Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: remove .NET Core 3.1 from skwas.MockHttp.Server (EOL) #122

Merged
merged 2 commits into from
Oct 2, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/MockHttp.Server/MockHttp.Server.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net8.0;net6.0;netcoreapp3.1</TargetFrameworks>
<TargetFrameworks>net8.0;net6.0</TargetFrameworks>
<PackageId>skwas.MockHttp.Server</PackageId>
<AssemblyName>skwas.MockHttp.Server</AssemblyName>
<RootNamespace>MockHttp</RootNamespace>
8 changes: 2 additions & 6 deletions src/MockHttp.Server/Server/HttpResponseMessageExtensions.cs
Original file line number Diff line number Diff line change
@@ -19,15 +19,11 @@ internal static async Task MapToFeatureAsync
responseFeature.ReasonPhrase = response.ReasonPhrase;

CopyHeaders(response.Headers, responseFeature.Headers);
// ReSharper disable once ConditionIsAlwaysTrueOrFalse
// ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
if (response.Content is not null)
{
CopyHeaders(response.Content.Headers, responseFeature.Headers);
Stream contentStream = await response.Content.ReadAsStreamAsync(
#if NET6_0_OR_GREATER
cancellationToken
#endif
).ConfigureAwait(false);
Stream contentStream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
await using ConfiguredAsyncDisposable _ = contentStream.ConfigureAwait(false);
await contentStream.CopyToAsync(responseBodyFeature.Writer.AsStream(), 4096, cancellationToken).ConfigureAwait(false);
}
15 changes: 9 additions & 6 deletions src/MockHttp.Server/Server/Log.cs
Original file line number Diff line number Diff line change
@@ -7,15 +7,18 @@ internal static partial class Log
{
internal const string LogRequestMessageTemplate = "Connection id \"{ConnectionId}\", Request id \"{RequestId}\": {Message}";

#if NET6_0_OR_GREATER
[LoggerMessage(
EventId = 0,
Level = LogLevel.Debug,
Message = LogRequestMessageTemplate)]
private static partial void LogDebugRequestMessage(ILogger logger, string connectionId, string requestId, string message, Exception? exception);
#else
private static readonly Action<ILogger, string, string, string, Exception?> LogDebugRequestMessage = LoggerMessage.Define<string, string, string>(LogLevel.Debug, new EventId(0), LogRequestMessageTemplate);
#endif
Message = LogRequestMessageTemplate
)]
private static partial void LogDebugRequestMessage(
ILogger logger,
string connectionId,
string requestId,
string message,
Exception? exception
);

public static void LogRequestMessage(this ILogger logger, HttpContext httpContext, string message, Exception? exception = null)
{
2 changes: 1 addition & 1 deletion src/MockHttp.Server/Server/WrappedHttpRequest.cs
Original file line number Diff line number Diff line change
@@ -21,7 +21,7 @@ public WrappedHttpRequest(HttpRequest request)

RequestUri = uriBuilder.Uri;

// ReSharper disable once ConditionIsAlwaysTrueOrFalse
// ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
if (request.Body is not null)
{
Content = new StreamContent(request.Body)
230 changes: 0 additions & 230 deletions test/MockHttp.Server.Tests/Fixtures/CapturingLoggerFactoryFixture.cs

This file was deleted.

53 changes: 53 additions & 0 deletions test/MockHttp.Server.Tests/Fixtures/FakeLogRecordSerialization.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using System.Text;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Testing;

namespace MockHttp.Fixtures;

internal static class FakeLogRecordSerialization
{
internal static string Serialize(FakeLogRecord e)
{
var sb = new StringBuilder();
const int len = 4;
string indent = new(' ', len + 2);

sb.AppendLine($"{GetLogLevelString(e.Level)}: {e.Category}[{e.Id.Id}]");
foreach (IEnumerable<KeyValuePair<string, object?>> scope in e.Scopes.OfType<IEnumerable<KeyValuePair<string, object?>>>())
{
sb.Append(indent);
// ReSharper disable once UsageOfDefaultStructEquality
foreach (KeyValuePair<string, object?> kvp in scope)
{
sb.Append($"=> {kvp} ");
}

sb.AppendLine();
}

sb.Append(indent);
sb.AppendLine(e.Message);

if (e.Exception is not null)
{
sb.Append(indent);
sb.AppendLine(e.Exception.ToString());
}

return sb.ToString();
}

private static string GetLogLevelString(LogLevel logLevel)
{
return logLevel switch
{
LogLevel.Trace => "trce",
LogLevel.Debug => "dbug",
LogLevel.Information => "info",
LogLevel.Warning => "warn",
LogLevel.Error => "fail",
LogLevel.Critical => "crit",
_ => throw new ArgumentOutOfRangeException(nameof(logLevel))
};
}
}
48 changes: 20 additions & 28 deletions test/MockHttp.Server.Tests/Fixtures/LoggerFactoryFixture.cs
Original file line number Diff line number Diff line change
@@ -1,52 +1,44 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Testing;

namespace MockHttp.Fixtures;

public abstract class LoggerFactoryFixture : IAsyncLifetime, IAsyncDisposable
internal sealed class LoggerFactoryFixture : IAsyncDisposable, IDisposable
{
private readonly ServiceProvider _services;

protected LoggerFactoryFixture(Action<ILoggingBuilder>? configure = null)
public LoggerFactoryFixture(Action<ILoggingBuilder>? configure = null)
{
_services = new ServiceCollection()
.AddLogging(builder =>
{
builder.SetMinimumLevel(LogLevel.Trace);

builder
.AddDebug()
#if NET6_0_OR_GREATER
.AddSimpleConsole(opts => opts.IncludeScopes = true)
#endif
;

configure?.Invoke(builder);
})
.AddLogging(
builder =>
{
builder.SetMinimumLevel(LogLevel.Trace);

builder
.AddFakeLogging()
.AddDebug();

configure?.Invoke(builder);
}
)
.BuildServiceProvider();

Factory = _services.GetRequiredService<ILoggerFactory>();
FakeLogCollector = _services.GetRequiredService<FakeLogCollector>();
}

public ILoggerFactory Factory { get; }

public async ValueTask DisposeAsync()
{
await DisposeAsyncCore();
GC.SuppressFinalize(this);
}
public FakeLogCollector FakeLogCollector { get; }

Task IAsyncLifetime.InitializeAsync()
public void Dispose()
{
return Task.CompletedTask;
_services.Dispose();
}

Task IAsyncLifetime.DisposeAsync()
{
return DisposeAsync().AsTask();
}

protected virtual async ValueTask DisposeAsyncCore()
public async ValueTask DisposeAsync()
{
await _services.DisposeAsync();
}
53 changes: 32 additions & 21 deletions test/MockHttp.Server.Tests/Fixtures/MockHttpServerFixture.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
using System.Net.NetworkInformation;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Xunit.Abstractions;

namespace MockHttp.Fixtures;

public class MockHttpServerFixture : IDisposable, IAsyncLifetime
{
private readonly CapturingLoggerFactoryFixture _loggerFactoryFixture;
private CapturingLoggerFactoryFixture.LogContext? _loggerCtx;
private readonly Guid _logRequestScope = Guid.NewGuid();
private readonly LoggerFactoryFixture _loggerFactoryFixture;

public MockHttpServerFixture()
: this("http")
@@ -16,7 +18,7 @@ public MockHttpServerFixture()

protected MockHttpServerFixture(string scheme)
{
_loggerFactoryFixture = new CapturingLoggerFactoryFixture();
_loggerFactoryFixture = new LoggerFactoryFixture();
Handler = new MockHttpHandler();
Server = new MockHttpServer(
Handler,
@@ -28,12 +30,16 @@ protected MockHttpServerFixture(string scheme)
)
);
Server
.Configure(builder => builder
.Use((_, next) =>
{
_loggerCtx ??= CapturingLoggerFactoryFixture.CreateContext();
return next();
})
.Configure(
builder => builder.Use(
async (context, func) =>
{
ILogger<MockHttpServerFixture>
logger = context.RequestServices.GetRequiredService<ILogger<MockHttpServerFixture>>();
using IDisposable? scope = logger.BeginScope(_logRequestScope);
await func(context);
}
)
);
}

@@ -48,33 +54,38 @@ public Task InitializeAsync()

public async Task DisposeAsync()
{
await _loggerFactoryFixture.DisposeAsync();
await Server.DisposeAsync();
Handler.Dispose();
await _loggerFactoryFixture.DisposeAsync();
}

public void Dispose()
{
_loggerCtx?.Dispose();
Server.Dispose();
Handler.Dispose();
Dispose(true);
GC.SuppressFinalize(this);
}

protected virtual void Dispose(bool disposing)
{
if (disposing)
{
Server.Dispose();
Handler.Dispose();
_loggerFactoryFixture.Dispose();
}
}

private static bool SupportsIpv6()
{
NetworkInterface[] networkInterfaces = NetworkInterface.GetAllNetworkInterfaces();
return networkInterfaces.Any(ni => ni.Supports(NetworkInterfaceComponent.IPv6));
}

// ReSharper disable once MemberCanBeMadeStatic.Global
public void LogServerTrace(ITestOutputHelper testOutputHelper)
{
if (_loggerCtx is null)
{
return;
}

foreach (string msg in _loggerCtx.Events)
foreach (string msg in _loggerFactoryFixture.FakeLogCollector.GetSnapshot()
.Where(e => e.Scopes.Contains(_logRequestScope))
.Select(FakeLogRecordSerialization.Serialize))
{
testOutputHelper.WriteLine(msg);
}
@@ -83,6 +94,6 @@ public void LogServerTrace(ITestOutputHelper testOutputHelper)
public void Reset()
{
Handler.Reset();
_loggerCtx = null;
_loggerFactoryFixture.FakeLogCollector.Clear();
}
}
4 changes: 2 additions & 2 deletions test/MockHttp.Server.Tests/MockHttp.Server.Tests.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net8.0;net6.0;netcoreapp3.1</TargetFrameworks>
<TargetFrameworks>net8.0;net6.0</TargetFrameworks>

<IsTestProject>true</IsTestProject>

@@ -13,7 +13,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.Testing" Version="8.9.1" />
</ItemGroup>

<ItemGroup>
2 changes: 1 addition & 1 deletion test/MockHttp.Server.Tests/MockHttpServerTests.cs
Original file line number Diff line number Diff line change
@@ -177,7 +177,7 @@ public async Task When_using_other_API_like_webRequest_it_should_respond_correct
request.ContentType = MediaTypes.PlainText;
await using (Stream requestStream = await request.GetRequestStreamAsync())
{
requestStream.Write(Encoding.ASCII.GetBytes("request-content"));
await requestStream.WriteAsync(Encoding.ASCII.GetBytes("request-content"));
}

// Assert
25 changes: 0 additions & 25 deletions test/MockHttp.Server.Tests/PublicApi/.NET_Core_3.1.verified.txt

This file was deleted.


Unchanged files with check annotations Beta

/// <summary>
/// Represents a collection of invoked HTTP requests.
/// </summary>
public interface IInvokedHttpRequestCollection : IConcurrentReadOnlyCollection<IInvokedHttpRequest>

Check warning on line 8 in src/MockHttp/IInvokedHttpRequestCollection.cs

GitHub Actions / Analyze (csharp)

'IConcurrentReadOnlyCollection<IInvokedHttpRequest>' is obsolete: 'Will be removed in next version.'

Check warning on line 8 in src/MockHttp/IInvokedHttpRequestCollection.cs

GitHub Actions / Analyze (csharp)

'IConcurrentReadOnlyCollection<IInvokedHttpRequest>' is obsolete: 'Will be removed in next version.'

Check warning on line 8 in src/MockHttp/IInvokedHttpRequestCollection.cs

GitHub Actions / Analyze (csharp)

'IConcurrentReadOnlyCollection<IInvokedHttpRequest>' is obsolete: 'Will be removed in next version.'

Check warning on line 8 in src/MockHttp/IInvokedHttpRequestCollection.cs

GitHub Actions / analysis

'IConcurrentReadOnlyCollection<IInvokedHttpRequest>' is obsolete: 'Will be removed in next version.'

Check warning on line 8 in src/MockHttp/IInvokedHttpRequestCollection.cs

GitHub Actions / analysis

'IConcurrentReadOnlyCollection<IInvokedHttpRequest>' is obsolete: 'Will be removed in next version.'

Check warning on line 8 in src/MockHttp/IInvokedHttpRequestCollection.cs

GitHub Actions / analysis

'IConcurrentReadOnlyCollection<IInvokedHttpRequest>' is obsolete: 'Will be removed in next version.'

Check warning on line 8 in src/MockHttp/IInvokedHttpRequestCollection.cs

GitHub Actions / build (v4.4.1-pr122.23)

'IConcurrentReadOnlyCollection<IInvokedHttpRequest>' is obsolete: 'Will be removed in next version.'

Check warning on line 8 in src/MockHttp/IInvokedHttpRequestCollection.cs

GitHub Actions / build (v4.4.1-pr122.23)

'IConcurrentReadOnlyCollection<IInvokedHttpRequest>' is obsolete: 'Will be removed in next version.'

Check warning on line 8 in src/MockHttp/IInvokedHttpRequestCollection.cs

GitHub Actions / build (v4.4.1-pr122.23)

'IConcurrentReadOnlyCollection<IInvokedHttpRequest>' is obsolete: 'Will be removed in next version.'
{
/// <summary>
/// Clears the invoked requests collection.
namespace MockHttp.Threading;
internal class ConcurrentCollection<T> : IConcurrentReadOnlyCollection<T>

Check warning on line 6 in src/MockHttp/Internal/Threading/ConcurrentCollection.cs

GitHub Actions / Analyze (csharp)

'IConcurrentReadOnlyCollection<T>' is obsolete: 'Will be removed in next version.'

Check warning on line 6 in src/MockHttp/Internal/Threading/ConcurrentCollection.cs

GitHub Actions / Analyze (csharp)

'IConcurrentReadOnlyCollection<T>' is obsolete: 'Will be removed in next version.'

Check warning on line 6 in src/MockHttp/Internal/Threading/ConcurrentCollection.cs

GitHub Actions / Analyze (csharp)

'IConcurrentReadOnlyCollection<T>' is obsolete: 'Will be removed in next version.'

Check warning on line 6 in src/MockHttp/Internal/Threading/ConcurrentCollection.cs

GitHub Actions / analysis

'IConcurrentReadOnlyCollection<T>' is obsolete: 'Will be removed in next version.'

Check warning on line 6 in src/MockHttp/Internal/Threading/ConcurrentCollection.cs

GitHub Actions / analysis

'IConcurrentReadOnlyCollection<T>' is obsolete: 'Will be removed in next version.'

Check warning on line 6 in src/MockHttp/Internal/Threading/ConcurrentCollection.cs

GitHub Actions / analysis

'IConcurrentReadOnlyCollection<T>' is obsolete: 'Will be removed in next version.'

Check warning on line 6 in src/MockHttp/Internal/Threading/ConcurrentCollection.cs

GitHub Actions / build (v4.4.1-pr122.23)

'IConcurrentReadOnlyCollection<T>' is obsolete: 'Will be removed in next version.'

Check warning on line 6 in src/MockHttp/Internal/Threading/ConcurrentCollection.cs

GitHub Actions / build (v4.4.1-pr122.23)

'IConcurrentReadOnlyCollection<T>' is obsolete: 'Will be removed in next version.'

Check warning on line 6 in src/MockHttp/Internal/Threading/ConcurrentCollection.cs

GitHub Actions / build (v4.4.1-pr122.23)

'IConcurrentReadOnlyCollection<T>' is obsolete: 'Will be removed in next version.'
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private readonly object _syncLock = new();
/// A delegate which when executed returns a configured HTTP response.
/// </summary>
/// <returns></returns>
public delegate Task ResponseHandlerDelegate(MockHttpRequestContext requestContext, HttpResponseMessage responseMessage, CancellationToken cancellationToken);

Check warning on line 7 in src/MockHttp/Responses/IResponseBehavior.cs

GitHub Actions / Analyze (csharp)

Rename type name ResponseHandlerDelegate so that it does not end in 'Delegate' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1711)

Check warning on line 7 in src/MockHttp/Responses/IResponseBehavior.cs

GitHub Actions / Analyze (csharp)

Rename type name ResponseHandlerDelegate so that it does not end in 'Delegate' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1711)

Check warning on line 7 in src/MockHttp/Responses/IResponseBehavior.cs

GitHub Actions / analysis

Rename type name ResponseHandlerDelegate so that it does not end in 'Delegate' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1711)

Check warning on line 7 in src/MockHttp/Responses/IResponseBehavior.cs

GitHub Actions / analysis

Rename type name ResponseHandlerDelegate so that it does not end in 'Delegate' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1711)

Check warning on line 7 in src/MockHttp/Responses/IResponseBehavior.cs

GitHub Actions / build (v4.4.1-pr122.23)

Rename type name ResponseHandlerDelegate so that it does not end in 'Delegate' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1711)

Check warning on line 7 in src/MockHttp/Responses/IResponseBehavior.cs

GitHub Actions / build (v4.4.1-pr122.23)

Rename type name ResponseHandlerDelegate so that it does not end in 'Delegate' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1711)
/// <summary>
/// Describes a way to apply a response behavior in a response builder pipeline.
/// <param name="next">The next behavior.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>An awaitable that upon completion returns the HTTP response message.</returns>
Task HandleAsync(MockHttpRequestContext requestContext, HttpResponseMessage responseMessage, ResponseHandlerDelegate next, CancellationToken cancellationToken);

Check warning on line 22 in src/MockHttp/Responses/IResponseBehavior.cs

GitHub Actions / Analyze (csharp)

In virtual/interface member IResponseBehavior.HandleAsync(MockHttpRequestContext, HttpResponseMessage, ResponseHandlerDelegate, CancellationToken), rename parameter next so that it no longer conflicts with the reserved language keyword 'Next'. Using a reserved keyword as the name of a parameter on a virtual/interface member makes it harder for consumers in other languages to override/implement the member. (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1716)

Check warning on line 22 in src/MockHttp/Responses/IResponseBehavior.cs

GitHub Actions / Analyze (csharp)

In virtual/interface member IResponseBehavior.HandleAsync(MockHttpRequestContext, HttpResponseMessage, ResponseHandlerDelegate, CancellationToken), rename parameter next so that it no longer conflicts with the reserved language keyword 'Next'. Using a reserved keyword as the name of a parameter on a virtual/interface member makes it harder for consumers in other languages to override/implement the member. (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1716)

Check warning on line 22 in src/MockHttp/Responses/IResponseBehavior.cs

GitHub Actions / analysis

In virtual/interface member IResponseBehavior.HandleAsync(MockHttpRequestContext, HttpResponseMessage, ResponseHandlerDelegate, CancellationToken), rename parameter next so that it no longer conflicts with the reserved language keyword 'Next'. Using a reserved keyword as the name of a parameter on a virtual/interface member makes it harder for consumers in other languages to override/implement the member. (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1716)

Check warning on line 22 in src/MockHttp/Responses/IResponseBehavior.cs

GitHub Actions / analysis

In virtual/interface member IResponseBehavior.HandleAsync(MockHttpRequestContext, HttpResponseMessage, ResponseHandlerDelegate, CancellationToken), rename parameter next so that it no longer conflicts with the reserved language keyword 'Next'. Using a reserved keyword as the name of a parameter on a virtual/interface member makes it harder for consumers in other languages to override/implement the member. (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1716)

Check warning on line 22 in src/MockHttp/Responses/IResponseBehavior.cs

GitHub Actions / build (v4.4.1-pr122.23)

In virtual/interface member IResponseBehavior.HandleAsync(MockHttpRequestContext, HttpResponseMessage, ResponseHandlerDelegate, CancellationToken), rename parameter next so that it no longer conflicts with the reserved language keyword 'Next'. Using a reserved keyword as the name of a parameter on a virtual/interface member makes it harder for consumers in other languages to override/implement the member. (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1716)

Check warning on line 22 in src/MockHttp/Responses/IResponseBehavior.cs

GitHub Actions / build (v4.4.1-pr122.23)

In virtual/interface member IResponseBehavior.HandleAsync(MockHttpRequestContext, HttpResponseMessage, ResponseHandlerDelegate, CancellationToken), rename parameter next so that it no longer conflicts with the reserved language keyword 'Next'. Using a reserved keyword as the name of a parameter on a virtual/interface member makes it harder for consumers in other languages to override/implement the member. (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1716)
}