diff --git a/.github/workflows/pr-build.yaml b/.github/workflows/pr-build.yaml
index 06c1aabd..249fe8f7 100644
--- a/.github/workflows/pr-build.yaml
+++ b/.github/workflows/pr-build.yaml
@@ -54,6 +54,7 @@ jobs:
dotnet test MinimalLambda.sln --configuration Release --no-build
--results-directory ./coverage --coverage
--coverage-output-format cobertura --no-progress --no-ansi
+ --max-parallel-test-modules 1 -p:TestTfmsInParallel=false
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v6
diff --git a/src/MinimalLambda.Testing/LambdaApplicationFactory.cs b/src/MinimalLambda.Testing/LambdaApplicationFactory.cs
index d7cf1c42..672461e0 100644
--- a/src/MinimalLambda.Testing/LambdaApplicationFactory.cs
+++ b/src/MinimalLambda.Testing/LambdaApplicationFactory.cs
@@ -105,20 +105,24 @@ public virtual async ValueTask DisposeAsync()
if (_disposedAsync)
return;
- foreach (var factory in _derivedFactories)
- await ((IAsyncDisposable)factory).DisposeAsync().ConfigureAwait(false);
-
- // TestServer handles disposing both processor and host
- if (_server != null)
- await _server.DisposeAsync().ConfigureAwait(false);
-
- _host?.Dispose();
+ try
+ {
+ foreach (var factory in _derivedFactories)
+ await ((IAsyncDisposable)factory).DisposeAsync().ConfigureAwait(false);
- _disposedAsync = true;
+ // TestServer handles disposing its processor.
+ if (_server != null)
+ await _server.DisposeAsync().ConfigureAwait(false);
+ }
+ finally
+ {
+ _host?.Dispose();
+ _disposedAsync = true;
- Dispose(true);
+ Dispose(true);
- GC.SuppressFinalize(this);
+ GC.SuppressFinalize(this);
+ }
}
///
diff --git a/src/MinimalLambda.Testing/LambdaTestServer.cs b/src/MinimalLambda.Testing/LambdaTestServer.cs
index 481685d7..1e1dbe38 100644
--- a/src/MinimalLambda.Testing/LambdaTestServer.cs
+++ b/src/MinimalLambda.Testing/LambdaTestServer.cs
@@ -132,6 +132,9 @@ public async ValueTask DisposeAsync()
if (_disposed)
return;
+ if (State == ServerState.Running)
+ await StopAsync().ConfigureAwait(false);
+
// Complete both channels to prevent new items
_transactionChannel.Writer.TryComplete();
_pendingInvocationIds.Writer.TryComplete();
@@ -139,9 +142,6 @@ public async ValueTask DisposeAsync()
// Cancel the shutdown token
await _shutdownCts.CancelAsync();
- if (State == ServerState.Running)
- await StopAsync().ConfigureAwait(false);
-
// Dispose the CancellationTokenSource
_shutdownCts.Dispose();
@@ -236,7 +236,10 @@ await TaskHelpers
if (_initCompletionTcs.Task.Result.InitStatus == InitStatus.InitCompleted)
State = ServerState.Running;
else
+ {
+ await _shutdownCts.CancelAsync();
await StopAsync(CancellationToken.None);
+ }
return _initCompletionTcs.Task.Result;
}
@@ -377,9 +380,8 @@ public async Task> InvokeAsync(
///
/// This method performs the following shutdown sequence:
///
- /// - Transitions the server state to
- /// - Cancels the internal shutdown token to signal background tasks
/// - Stops the application host via
+ /// - Cancels the internal shutdown token to stop transaction processing
/// - Waits for the entry point and processing tasks to complete
/// - Transitions the server state to
///
@@ -396,10 +398,10 @@ public async Task StopAsync(CancellationToken cancellationToken = default)
State = ServerState.Stopping;
- await _shutdownCts.CancelAsync();
-
_applicationLifetime?.StopApplication();
+ await _shutdownCts.CancelAsync();
+
await TaskHelpers
.WhenAll(_entryPointCompletion, _processingTask ?? Task.CompletedTask)
.UnwrapAndThrow("Exception(s) encountered while running StopAsync")
@@ -466,7 +468,7 @@ private async Task HandleGetNextInvocationAsync(LambdaHttpTransaction transactio
{
var requestId = await _pendingInvocationIds.Reader.ReadAsync(_shutdownCts.Token);
_pendingInvocations.GetRequired(requestId, out var pendingInvocation);
- transaction.ResponseTcs.SetResult(pendingInvocation.EventResponse);
+ transaction.Respond(pendingInvocation.EventResponse);
}
}
diff --git a/src/MinimalLambda/Runtime/LambdaHostedService.cs b/src/MinimalLambda/Runtime/LambdaHostedService.cs
index 55d09167..a0a26c0a 100644
--- a/src/MinimalLambda/Runtime/LambdaHostedService.cs
+++ b/src/MinimalLambda/Runtime/LambdaHostedService.cs
@@ -18,6 +18,7 @@ internal sealed class LambdaHostedService : IHostedService, IDisposable
private readonly LambdaHostedServiceOptions _options;
private bool _disposed;
+ private CancellationTokenRegistration _applicationStoppingRegistration;
private Task? _executeTask;
private Func? _shutdownHandler;
private CancellationTokenSource? _stoppingCts;
@@ -48,6 +49,7 @@ public LambdaHostedService(
///
public void Dispose()
{
+ _applicationStoppingRegistration.Dispose();
_stoppingCts?.Cancel();
if (_disposed)
@@ -69,6 +71,9 @@ public Task StartAsync(CancellationToken cancellationToken)
// Create a linked token to allow cancelling the executing task from the provided token
_stoppingCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
+ _applicationStoppingRegistration =
+ _lifetime.ApplicationStopping.Register(_stoppingCts.Cancel);
+
// Create a fully composed handler with middleware and request processing.
var requestHandler = _handlerFactory.CreateHandler(_stoppingCts.Token);
diff --git a/tests/MinimalLambda.Testing.UnitTests/Tests/MinimalLambda.Testing.UnitTests/DiLambdaTests.cs b/tests/MinimalLambda.Testing.UnitTests/Tests/MinimalLambda.Testing.UnitTests/DiLambdaTests.cs
index 11913673..97373e69 100644
--- a/tests/MinimalLambda.Testing.UnitTests/Tests/MinimalLambda.Testing.UnitTests/DiLambdaTests.cs
+++ b/tests/MinimalLambda.Testing.UnitTests/Tests/MinimalLambda.Testing.UnitTests/DiLambdaTests.cs
@@ -2,6 +2,7 @@
using Autofac.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
+using Microsoft.Extensions.Logging;
using MinimalLambda.UnitTests;
using NSubstitute.ExceptionExtensions;
@@ -13,8 +14,9 @@ public class DiLambdaTests
public async Task DiLambda_ReturnsExpectedValue()
{
await using var factory =
- new LambdaApplicationFactory().WithCancellationToken(
- TestContext.Current.CancellationToken);
+ LambdaTestFactory
+ .Create()
+ .WithCancellationToken(TestContext.Current.CancellationToken);
var response = await factory.TestServer.InvokeAsync(
new DiLambdaRequest("World"),
@@ -26,11 +28,26 @@ public async Task DiLambda_ReturnsExpectedValue()
response.Response.Message.Should().Be("Hello World!");
}
+ [Fact]
+ public async Task DiLambda_HostLoggingIsDisabled()
+ {
+ await using var factory =
+ LambdaTestFactory
+ .Create()
+ .WithCancellationToken(TestContext.Current.CancellationToken);
+
+ var logger = factory.Services.GetRequiredService>();
+
+ foreach (var level in Enum.GetValues())
+ logger.IsEnabled(level).Should().BeFalse();
+ }
+
[Fact]
internal async Task DiLambda_InitStopped()
{
var lifecycleService = Substitute.For();
- await using var factory = new LambdaApplicationFactory()
+ await using var factory = LambdaTestFactory
+ .Create()
.WithCancellationToken(TestContext.Current.CancellationToken)
.WithHostBuilder(builder => builder.ConfigureServices((_, services) =>
{
@@ -59,7 +76,8 @@ internal async Task DiLambda_InitThrowsException()
{
var lifecycleService = Substitute.For();
- await using var factory = new LambdaApplicationFactory()
+ await using var factory = LambdaTestFactory
+ .Create()
.WithCancellationToken(TestContext.Current.CancellationToken)
.WithHostBuilder(builder => builder.ConfigureServices((_, services) =>
{
@@ -90,7 +108,8 @@ internal async Task DiLambda_InitThrowsException()
[AutoNSubstituteData]
internal async Task DiLambda_ShutdownThrowsException(ILifecycleService lifecycleService)
{
- await using var factory = new LambdaApplicationFactory()
+ await using var factory = LambdaTestFactory
+ .Create()
.WithCancellationToken(TestContext.Current.CancellationToken)
.WithHostBuilder(builder => builder.ConfigureServices((_, services) =>
{
@@ -104,15 +123,16 @@ internal async Task DiLambda_ShutdownThrowsException(ILifecycleService lifecycle
var initResult = await factory.TestServer.StartAsync(TestContext.Current.CancellationToken);
initResult.InitStatus.Should().Be(InitStatus.InitCompleted);
- var act = async () =>
- // ReSharper disable once AccessToDisposedClosure
- await factory.TestServer.StopAsync(TestContext.Current.CancellationToken);
+ var act = async () => await factory.DisposeAsync();
(await act.Should().ThrowAsync())
.WithInnerException()
.WithInnerException()
.WithInnerException()
.WithMessage("Test init error");
+
+ var getService = () => factory.Services.GetRequiredService();
+ getService.Should().Throw();
}
[Theory]
@@ -121,7 +141,8 @@ internal async Task DiLambda_DiContainerCanBeReplaced(
ILifecycleService lifecycleService,
IService service)
{
- await using var factory = new LambdaApplicationFactory()
+ await using var factory = LambdaTestFactory
+ .Create()
.WithCancellationToken(TestContext.Current.CancellationToken)
.WithHostBuilder(builder => builder
.ConfigureContainer((_, containerBuilder) =>
@@ -149,7 +170,8 @@ internal async Task DiLambda_DiContainerCanBeReplacedWithFactory(
ILifecycleService lifecycleService,
IService service)
{
- await using var factory = new LambdaApplicationFactory()
+ await using var factory = LambdaTestFactory
+ .Create()
.WithCancellationToken(TestContext.Current.CancellationToken)
.WithHostBuilder(builder => builder
.ConfigureContainer((_, containerBuilder) =>
diff --git a/tests/MinimalLambda.Testing.UnitTests/Tests/MinimalLambda.Testing.UnitTests/DurableLambdaTests.cs b/tests/MinimalLambda.Testing.UnitTests/Tests/MinimalLambda.Testing.UnitTests/DurableLambdaTests.cs
index 6342764a..39df8310 100644
--- a/tests/MinimalLambda.Testing.UnitTests/Tests/MinimalLambda.Testing.UnitTests/DurableLambdaTests.cs
+++ b/tests/MinimalLambda.Testing.UnitTests/Tests/MinimalLambda.Testing.UnitTests/DurableLambdaTests.cs
@@ -14,8 +14,9 @@ public async Task DurableLambda_Success_RoundTripsGeneratedAdapterPipeline()
{
// Arrange
await using var factory =
- new LambdaApplicationFactory().WithCancellationToken(
- TestContext.Current.CancellationToken);
+ LambdaTestFactory
+ .Create()
+ .WithCancellationToken(TestContext.Current.CancellationToken);
var input = CreateInvocationInput(shouldFail: false);
// Act
@@ -45,8 +46,9 @@ public async Task DurableLambda_Failure_ReturnsFailedOuterEnvelope()
{
// Arrange
await using var factory =
- new LambdaApplicationFactory().WithCancellationToken(
- TestContext.Current.CancellationToken);
+ LambdaTestFactory
+ .Create()
+ .WithCancellationToken(TestContext.Current.CancellationToken);
var input = CreateInvocationInput(shouldFail: true);
// Act
diff --git a/tests/MinimalLambda.Testing.UnitTests/Tests/MinimalLambda.Testing.UnitTests/LambdaTestFactory.cs b/tests/MinimalLambda.Testing.UnitTests/Tests/MinimalLambda.Testing.UnitTests/LambdaTestFactory.cs
new file mode 100644
index 00000000..b5f5cb83
--- /dev/null
+++ b/tests/MinimalLambda.Testing.UnitTests/Tests/MinimalLambda.Testing.UnitTests/LambdaTestFactory.cs
@@ -0,0 +1,27 @@
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Hosting;
+
+namespace MinimalLambda.Testing.UnitTests;
+
+internal static class LambdaTestFactory
+{
+ private const string LambdaLogLevelEnvironmentVariable = "AWS_LAMBDA_LOG_LEVEL";
+
+ private static readonly KeyValuePair[] HostConfiguration =
+ [
+ new("Logging:LogLevel:Default", "None"),
+ ];
+
+ static LambdaTestFactory()
+ {
+ if (string.IsNullOrEmpty(
+ Environment.GetEnvironmentVariable(LambdaLogLevelEnvironmentVariable)))
+ Environment.SetEnvironmentVariable(LambdaLogLevelEnvironmentVariable, "Critical");
+ }
+
+ public static LambdaApplicationFactory Create()
+ where TEntryPoint : class =>
+ new LambdaApplicationFactory().WithHostBuilder(builder =>
+ builder.ConfigureAppConfiguration((_, configuration) =>
+ configuration.AddInMemoryCollection(HostConfiguration)));
+}
diff --git a/tests/MinimalLambda.Testing.UnitTests/Tests/MinimalLambda.Testing.UnitTests/NoEventLambdaTests.cs b/tests/MinimalLambda.Testing.UnitTests/Tests/MinimalLambda.Testing.UnitTests/NoEventLambdaTests.cs
index f8044c1a..bef667cf 100644
--- a/tests/MinimalLambda.Testing.UnitTests/Tests/MinimalLambda.Testing.UnitTests/NoEventLambdaTests.cs
+++ b/tests/MinimalLambda.Testing.UnitTests/Tests/MinimalLambda.Testing.UnitTests/NoEventLambdaTests.cs
@@ -8,8 +8,9 @@ public class NoEventLambdaTests
public async Task NoEvent_ReturnsExpectedValue()
{
await using var factory =
- new LambdaApplicationFactory().WithCancellationToken(
- TestContext.Current.CancellationToken);
+ LambdaTestFactory
+ .Create()
+ .WithCancellationToken(TestContext.Current.CancellationToken);
var response =
await factory.TestServer.InvokeNoEventAsync(
@@ -24,11 +25,13 @@ await factory.TestServer.InvokeNoEventAsync(
[Fact]
public async Task NoEvent_ConfigurationCanBeOverwritten()
{
- await using var factory = new LambdaApplicationFactory()
- .WithCancellationToken(TestContext.Current.CancellationToken)
- .WithHostBuilder(builder => builder.ConfigureAppConfiguration((_, config) =>
- config.AddInMemoryCollection(
- new Dictionary { ["MESSAGE"] = "Hello Mars!" }!)));
+ await using var factory =
+ LambdaTestFactory
+ .Create()
+ .WithCancellationToken(TestContext.Current.CancellationToken)
+ .WithHostBuilder(builder => builder.ConfigureAppConfiguration((_, config) =>
+ config.AddInMemoryCollection(
+ new Dictionary { ["MESSAGE"] = "Hello Mars!" }!)));
var response =
await factory.TestServer.InvokeNoEventAsync(
diff --git a/tests/MinimalLambda.Testing.UnitTests/Tests/MinimalLambda.Testing.UnitTests/NoResponseLambdaTests.cs b/tests/MinimalLambda.Testing.UnitTests/Tests/MinimalLambda.Testing.UnitTests/NoResponseLambdaTests.cs
index f92e58d0..8ba9ff1a 100644
--- a/tests/MinimalLambda.Testing.UnitTests/Tests/MinimalLambda.Testing.UnitTests/NoResponseLambdaTests.cs
+++ b/tests/MinimalLambda.Testing.UnitTests/Tests/MinimalLambda.Testing.UnitTests/NoResponseLambdaTests.cs
@@ -11,8 +11,9 @@ public class NoResponseLambdaTests
public async Task NoResponseLambda_ReturnsExpectedValue()
{
await using var factory =
- new LambdaApplicationFactory().WithCancellationToken(
- TestContext.Current.CancellationToken);
+ LambdaTestFactory
+ .Create()
+ .WithCancellationToken(TestContext.Current.CancellationToken);
var response = await factory.TestServer.InvokeNoResponseAsync(
new NoResponseLambdaRequest("World"),
@@ -26,8 +27,9 @@ public async Task NoResponseLambda_ReturnsExpectedValue()
public async Task NoResponseLambda_ServicesIsAccessible()
{
await using var factory =
- new LambdaApplicationFactory().WithCancellationToken(
- TestContext.Current.CancellationToken);
+ LambdaTestFactory
+ .Create()
+ .WithCancellationToken(TestContext.Current.CancellationToken);
var act = () => factory.TestServer.Services.GetRequiredService();
@@ -38,8 +40,9 @@ public async Task NoResponseLambda_ServicesIsAccessible()
public async Task NoResponseLambda_DisposeCanBeCalledMultipleTimes()
{
await using var factory =
- new LambdaApplicationFactory().WithCancellationToken(
- TestContext.Current.CancellationToken);
+ LambdaTestFactory
+ .Create()
+ .WithCancellationToken(TestContext.Current.CancellationToken);
var act = async () =>
{
diff --git a/tests/MinimalLambda.Testing.UnitTests/Tests/MinimalLambda.Testing.UnitTests/SimpleLambdaTests.cs b/tests/MinimalLambda.Testing.UnitTests/Tests/MinimalLambda.Testing.UnitTests/SimpleLambdaTests.cs
index 88143e92..aa377d46 100644
--- a/tests/MinimalLambda.Testing.UnitTests/Tests/MinimalLambda.Testing.UnitTests/SimpleLambdaTests.cs
+++ b/tests/MinimalLambda.Testing.UnitTests/Tests/MinimalLambda.Testing.UnitTests/SimpleLambdaTests.cs
@@ -9,8 +9,9 @@ public class SimpleLambdaTests
public async Task SimpleLambda_ReturnsExpectedValue()
{
await using var factory =
- new LambdaApplicationFactory().WithCancellationToken(
- TestContext.Current.CancellationToken);
+ LambdaTestFactory
+ .Create()
+ .WithCancellationToken(TestContext.Current.CancellationToken);
var setup = await factory.TestServer.StartAsync(TestContext.Current.CancellationToken);
setup.InitStatus.Should().Be(InitStatus.InitCompleted);
@@ -27,8 +28,9 @@ public async Task SimpleLambda_ReturnsExpectedValue()
public async Task SimpleLambda_WorksWhenStartIsNotCalled()
{
await using var factory =
- new LambdaApplicationFactory().WithCancellationToken(
- TestContext.Current.CancellationToken);
+ LambdaTestFactory
+ .Create()
+ .WithCancellationToken(TestContext.Current.CancellationToken);
var response = await factory.TestServer.InvokeAsync(
"World",
@@ -43,8 +45,9 @@ public async Task SimpleLambda_WorksWhenStartIsNotCalled()
public async Task SimpleLambda_WorksWhenInvokeCalledMultipleTimes()
{
await using var factory =
- new LambdaApplicationFactory().WithCancellationToken(
- TestContext.Current.CancellationToken);
+ LambdaTestFactory
+ .Create()
+ .WithCancellationToken(TestContext.Current.CancellationToken);
// Launch 5 concurrent invocations
var tasks = Enumerable
@@ -73,8 +76,9 @@ public async Task SimpleLambda_WorksWhenInvokeCalledMultipleTimes()
public async Task SimpleLambda_WorksWhenInvokeCalledMultipleTimes_WithoutStart()
{
await using var factory =
- new LambdaApplicationFactory().WithCancellationToken(
- TestContext.Current.CancellationToken);
+ LambdaTestFactory
+ .Create()
+ .WithCancellationToken(TestContext.Current.CancellationToken);
await factory.TestServer.StartAsync(TestContext.Current.CancellationToken);
// Launch 5 concurrent invocations
@@ -104,8 +108,9 @@ public async Task SimpleLambda_WorksWhenInvokeCalledMultipleTimes_WithoutStart()
public async Task SimpleLambda_ReturnsError()
{
await using var factory =
- new LambdaApplicationFactory().WithCancellationToken(
- TestContext.Current.CancellationToken);
+ LambdaTestFactory
+ .Create()
+ .WithCancellationToken(TestContext.Current.CancellationToken);
var response = await factory.TestServer.InvokeAsync(
"",
@@ -115,12 +120,15 @@ public async Task SimpleLambda_ReturnsError()
response.WasSuccess.Should().BeFalse();
response.Error.Should().NotBeNull();
response.Error.ErrorMessage.Should().Be("Name is required");
+
+ await factory.TestServer.DisposeAsync();
}
[Fact]
public async Task SimpleLambda_ErrorsArePropagated()
{
- await using var factory = new LambdaApplicationFactory()
+ await using var factory = LambdaTestFactory
+ .Create()
.WithCancellationToken(TestContext.Current.CancellationToken)
.WithHostBuilder(builder =>
{
@@ -148,8 +156,9 @@ await act
public async Task SimpleLambda_WithPreCanceledToken_CancelsInvocation()
{
await using var factory =
- new LambdaApplicationFactory().WithCancellationToken(
- TestContext.Current.CancellationToken);
+ LambdaTestFactory
+ .Create()
+ .WithCancellationToken(TestContext.Current.CancellationToken);
await factory.TestServer.StartAsync(TestContext.Current.CancellationToken);
using var cts = new CancellationTokenSource();
diff --git a/tests/MinimalLambda.UnitTests/Builder/LambdaApplicationTests.cs b/tests/MinimalLambda.UnitTests/Builder/LambdaApplicationTests.cs
index 5856b156..0a794d12 100644
--- a/tests/MinimalLambda.UnitTests/Builder/LambdaApplicationTests.cs
+++ b/tests/MinimalLambda.UnitTests/Builder/LambdaApplicationTests.cs
@@ -177,32 +177,38 @@ public void Logger_WithoutLoggerFactory_ReturnsNullLogger()
}
[Fact]
- public void StartAsync_ReturnsAwaitableTask()
+ public async Task StartAsync_DelegatesToHost()
{
// Arrange
- var host = CreateHostWithServices();
+ using var servicesHost = CreateHostWithServices();
+ var host = Substitute.For();
+ host.Services.Returns(servicesHost.Services);
+ host.StartAsync(TestContext.Current.CancellationToken).Returns(Task.CompletedTask);
var app = new LambdaApplication(host);
// Act
- var task = app.StartAsync(TestContext.Current.CancellationToken);
+ await app.StartAsync(TestContext.Current.CancellationToken);
// Assert
- task.Should().NotBeNull();
+ await host.Received(1).StartAsync(TestContext.Current.CancellationToken);
}
[Fact]
- public void StartAsync_WithCancellationToken_ReturnsAwaitableTask()
+ public async Task StartAsync_PassesCancellationTokenToHost()
{
// Arrange
- var host = CreateHostWithServices();
+ using var servicesHost = CreateHostWithServices();
+ var host = Substitute.For();
+ host.Services.Returns(servicesHost.Services);
+ using var cts = new CancellationTokenSource();
+ host.StartAsync(cts.Token).Returns(Task.CompletedTask);
var app = new LambdaApplication(host);
// Act
- using var cts = new CancellationTokenSource();
- var task = app.StartAsync(cts.Token);
+ await app.StartAsync(cts.Token);
// Assert
- task.Should().NotBeNull();
+ await host.Received(1).StartAsync(cts.Token);
}
[Fact]
diff --git a/tests/MinimalLambda.UnitTests/Builder/OnInit/OutputFormattingLambdaApplicationExtensionsTests.cs b/tests/MinimalLambda.UnitTests/Builder/OnInit/OutputFormattingLambdaApplicationExtensionsTests.cs
index 7c049064..c2058b14 100644
--- a/tests/MinimalLambda.UnitTests/Builder/OnInit/OutputFormattingLambdaApplicationExtensionsTests.cs
+++ b/tests/MinimalLambda.UnitTests/Builder/OnInit/OutputFormattingLambdaApplicationExtensionsTests.cs
@@ -1,12 +1,18 @@
using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
namespace MinimalLambda.UnitTests.Application.Extensions;
[TestSubject(typeof(OutputFormattingLambdaApplicationExtensions))]
public class OutputFormattingLambdaApplicationExtensionsTests
{
- private static IHost CreateHostWithServices() =>
- new LambdaApplicationBuilder(new LambdaApplicationOptions()).Build();
+ private static IHost CreateHostWithServices()
+ {
+ var builder = new LambdaApplicationBuilder(new LambdaApplicationOptions());
+ builder.Logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.None);
+
+ return builder.Build();
+ }
[Fact]
public void OnInitClearLambdaOutputFormatting_WithNullApplication_ThrowsArgumentNullException()
diff --git a/tests/MinimalLambda.UnitTests/Core/Runtime/LambdaHostedServiceTests.cs b/tests/MinimalLambda.UnitTests/Core/Runtime/LambdaHostedServiceTests.cs
index cfc2f0a7..aa2df0e8 100644
--- a/tests/MinimalLambda.UnitTests/Core/Runtime/LambdaHostedServiceTests.cs
+++ b/tests/MinimalLambda.UnitTests/Core/Runtime/LambdaHostedServiceTests.cs
@@ -78,6 +78,39 @@ await bootstrapOrchestrator
Arg.Any());
}
+ [Theory]
+ [AutoNSubstituteData]
+ internal async Task StartAsync_CancelsBootstrapWhenApplicationStops(
+ [Frozen] ILambdaBootstrapOrchestrator bootstrap,
+ [Frozen] IHostApplicationLifetime lifetime,
+ LambdaHostedService service)
+ {
+ // Arrange
+ using var applicationStoppingCts = new CancellationTokenSource();
+ var bootstrapToken = new TaskCompletionSource(
+ TaskCreationOptions.RunContinuationsAsynchronously);
+ lifetime.ApplicationStopping.Returns(applicationStoppingCts.Token);
+ bootstrap
+ .RunAsync(
+ Arg.Any>>(),
+ Arg.Any>>(),
+ Arg.Any())
+ .Returns(callInfo =>
+ {
+ var cancellationToken = callInfo.ArgAt(2);
+ bootstrapToken.SetResult(cancellationToken);
+ return Task.Delay(Timeout.InfiniteTimeSpan, cancellationToken);
+ });
+
+ // Act
+ await service.StartAsync(CancellationToken.None);
+ applicationStoppingCts.Cancel();
+
+ // Assert
+ (await bootstrapToken.Task).IsCancellationRequested.Should().BeTrue();
+ await service.StopAsync(CancellationToken.None);
+ }
+
[Theory]
[AutoNSubstituteData]
internal async Task StartAsync_CreatesRequestHandler(