From 9efc09524d1499341e8e7cfe444fd8773d48904e Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Sun, 14 Dec 2025 11:07:47 -0500 Subject: [PATCH 1/7] refactor(tests): remove unused package references from unit test projects - Removed `System.Net.Http` and `System.Text.RegularExpressions` package references from test projects. - Streamlined dependencies to improve project maintainability. --- .../MinimalLambda.Envelopes.UnitTests.csproj | 2 -- .../MinimalLambda.OpenTelemetry.UnitTests.csproj | 2 -- tests/MinimalLambda.UnitTests/MinimalLambda.UnitTests.csproj | 2 -- 3 files changed, 6 deletions(-) diff --git a/tests/MinimalLambda.Envelopes.UnitTests/MinimalLambda.Envelopes.UnitTests.csproj b/tests/MinimalLambda.Envelopes.UnitTests/MinimalLambda.Envelopes.UnitTests.csproj index 0f54f85c..e6b4c2bf 100644 --- a/tests/MinimalLambda.Envelopes.UnitTests/MinimalLambda.Envelopes.UnitTests.csproj +++ b/tests/MinimalLambda.Envelopes.UnitTests/MinimalLambda.Envelopes.UnitTests.csproj @@ -17,8 +17,6 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - - all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/tests/MinimalLambda.OpenTelemetry.UnitTests/MinimalLambda.OpenTelemetry.UnitTests.csproj b/tests/MinimalLambda.OpenTelemetry.UnitTests/MinimalLambda.OpenTelemetry.UnitTests.csproj index 47ac57d3..4d2e6a12 100644 --- a/tests/MinimalLambda.OpenTelemetry.UnitTests/MinimalLambda.OpenTelemetry.UnitTests.csproj +++ b/tests/MinimalLambda.OpenTelemetry.UnitTests/MinimalLambda.OpenTelemetry.UnitTests.csproj @@ -22,8 +22,6 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - - all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/tests/MinimalLambda.UnitTests/MinimalLambda.UnitTests.csproj b/tests/MinimalLambda.UnitTests/MinimalLambda.UnitTests.csproj index bd37d950..caf6b611 100644 --- a/tests/MinimalLambda.UnitTests/MinimalLambda.UnitTests.csproj +++ b/tests/MinimalLambda.UnitTests/MinimalLambda.UnitTests.csproj @@ -23,8 +23,6 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - - all runtime; build; native; contentfiles; analyzers; buildtransitive From 3efeefe8cf7194d54ecbee3ff4807dc5b1de1c5d Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Sun, 14 Dec 2025 12:10:22 -0500 Subject: [PATCH 2/7] fix(tests): add delay handling to prevent disposal of DI container during test execution - Added delays in `DiLambdaTests` to prevent the DI container from being disposed prematurely. - Updated `CancellationToken` usage to use `TestContext.Current.CancellationToken`. - Improved test stability in scenarios where initialization fails or exits early. --- .../DiLambdaTests.cs | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) 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 7d1d0599..35fc54cf 100644 --- a/tests/MinimalLambda.Testing.UnitTests/Tests/MinimalLambda.Testing.UnitTests/DiLambdaTests.cs +++ b/tests/MinimalLambda.Testing.UnitTests/Tests/MinimalLambda.Testing.UnitTests/DiLambdaTests.cs @@ -43,7 +43,17 @@ internal async Task DiLambda_InitStopped() ) ); - lifecycleService.OnStart().Returns(false); + // due to how the dependencies are resolved within the test server, if we dont add a delay + // here, there is a small chance that the DI container will be disposed of before the test + // server can resolve the IHostedApplicationLifetime. This is only the issue if OnInit + // signals that the init phase should exit. + lifecycleService + .OnStart() + .Returns(false) + .AndDoes(_ => + Task.Delay(TimeSpan.FromMilliseconds(100), TestContext.Current.CancellationToken) + .Wait(TestContext.Current.CancellationToken) + ); var initResult = await factory.TestServer.StartAsync(TestContext.Current.CancellationToken); initResult.InitStatus.Should().Be(InitStatus.HostExited); @@ -52,15 +62,10 @@ internal async Task DiLambda_InitStopped() [Fact] internal async Task DiLambda_InitThrowsException() { - using var cts = CancellationTokenSource.CreateLinkedTokenSource( - TestContext.Current.CancellationToken - ); - cts.CancelAfter(TimeSpan.FromSeconds(5)); - var lifecycleService = Substitute.For(); await using var factory = new LambdaApplicationFactory() - .WithCancellationToken(cts.Token) + .WithCancellationToken(TestContext.Current.CancellationToken) .WithHostBuilder(builder => builder.ConfigureServices( (_, services) => @@ -71,9 +76,16 @@ internal async Task DiLambda_InitThrowsException() ) ); - lifecycleService.OnStart().Throws(new Exception("Test init error")); + // See DiLambda_InitStopped for why the delay is needed here + lifecycleService + .OnStart() + .Throws(new Exception("Test init error")) + .AndDoes(_ => + Task.Delay(TimeSpan.FromMilliseconds(100), TestContext.Current.CancellationToken) + .Wait(TestContext.Current.CancellationToken) + ); - var initResult = await factory.TestServer.StartAsync(cts.Token); + var initResult = await factory.TestServer.StartAsync(TestContext.Current.CancellationToken); initResult.InitStatus.Should().Be(InitStatus.InitError); initResult.Error.Should().NotBeNull(); initResult From 46d3c22c5a44b600575aeacbe186cb603fefdb84 Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Sun, 14 Dec 2025 12:25:59 -0500 Subject: [PATCH 3/7] refactor(config): update editor settings for code formatting and host resolver rules - Updated `.editorconfig` to apply formatting rules to all `HostFactoryResolver.cs` files. - Adjusted Rider settings to ensure consistent reformatting across multiple languages. - Enabled C# documentation comments formatting in Rider settings. --- .editorconfig | 2 +- MinimalLambda.sln.DotSettings | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.editorconfig b/.editorconfig index 1693a54e..14f699d3 100644 --- a/.editorconfig +++ b/.editorconfig @@ -15,6 +15,6 @@ trim_trailing_whitespace = true [*.xml] indent_size = 4 -[src/AwsLambda.Host.Testing/HostFactoryResolver.cs] +[*HostFactoryResolver.cs] ij_formatter_enabled = false resharper_disable_formatter = true \ No newline at end of file diff --git a/MinimalLambda.sln.DotSettings b/MinimalLambda.sln.DotSettings index 7c660687..e8728508 100644 --- a/MinimalLambda.sln.DotSettings +++ b/MinimalLambda.sln.DotSettings @@ -8,8 +8,8 @@ &lt;inspection_tool class="UnterminatedStatementJS" enabled="true" level="WARNING" enabled_by_default="true" /&gt; &lt;/profile&gt;</IDEA_SETTINGS><RIDER_SETTINGS>&lt;profile&gt; &lt;Language id="CSS"&gt; - &lt;Reformat&gt;true&lt;/Reformat&gt; &lt;Rearrange&gt;true&lt;/Rearrange&gt; + &lt;Reformat&gt;true&lt;/Reformat&gt; &lt;/Language&gt; &lt;Language id="EditorConfig"&gt; &lt;Reformat&gt;true&lt;/Reformat&gt; @@ -18,9 +18,9 @@ &lt;Reformat&gt;true&lt;/Reformat&gt; &lt;/Language&gt; &lt;Language id="HTML"&gt; - &lt;Reformat&gt;true&lt;/Reformat&gt; &lt;OptimizeImports&gt;true&lt;/OptimizeImports&gt; &lt;Rearrange&gt;true&lt;/Rearrange&gt; + &lt;Reformat&gt;true&lt;/Reformat&gt; &lt;/Language&gt; &lt;Language id="HTTP Request"&gt; &lt;Reformat&gt;true&lt;/Reformat&gt; @@ -38,9 +38,9 @@ &lt;Reformat&gt;true&lt;/Reformat&gt; &lt;/Language&gt; &lt;Language id="JavaScript"&gt; - &lt;Reformat&gt;true&lt;/Reformat&gt; &lt;OptimizeImports&gt;true&lt;/OptimizeImports&gt; &lt;Rearrange&gt;true&lt;/Rearrange&gt; + &lt;Reformat&gt;true&lt;/Reformat&gt; &lt;/Language&gt; &lt;Language id="Markdown"&gt; &lt;Reformat&gt;false&lt;/Reformat&gt; @@ -70,14 +70,14 @@ &lt;Reformat&gt;true&lt;/Reformat&gt; &lt;/Language&gt; &lt;Language id="XML"&gt; - &lt;Reformat&gt;true&lt;/Reformat&gt; &lt;OptimizeImports&gt;true&lt;/OptimizeImports&gt; &lt;Rearrange&gt;true&lt;/Rearrange&gt; + &lt;Reformat&gt;true&lt;/Reformat&gt; &lt;/Language&gt; &lt;Language id="yaml"&gt; &lt;Reformat&gt;true&lt;/Reformat&gt; &lt;/Language&gt; -&lt;/profile&gt;</RIDER_SETTINGS></Profile> +&lt;/profile&gt;</RIDER_SETTINGS><CSharpFormatDocComments>True</CSharpFormatDocComments></Profile> Built-in: Full Cleanup NotRequired NotRequired From b3b052c30625d9b9f96dac1ceb2a93bcfc474928 Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Sun, 14 Dec 2025 12:26:14 -0500 Subject: [PATCH 4/7] refactor(testing): adjust formatting and modify Lambda defaults - Updated formatting in `LambdaServerOptions` for consistent inline documentation. - Changed default `FunctionTimeout` from 15 minutes to 3 seconds with relevant documentation link. - Simplified exception handling logic in `DeferredHostBuilder`. --- .../DeferredHostBuilder.cs | 4 ---- .../Options/LambdaServerOptions.cs | 23 +++++++++---------- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/src/MinimalLambda.Testing/DeferredHostBuilder.cs b/src/MinimalLambda.Testing/DeferredHostBuilder.cs index 4b26d5aa..66228a8b 100644 --- a/src/MinimalLambda.Testing/DeferredHostBuilder.cs +++ b/src/MinimalLambda.Testing/DeferredHostBuilder.cs @@ -122,13 +122,9 @@ public void EntryPointCompleted(Exception? exception) // If the entry point completed we'll set the tcs just in case the application doesn't call // IHost.Start/StartAsync. if (exception is not null) - { _hostStartTcs.TrySetException(exception); - } else - { _hostStartTcs.TrySetResult(); - } _entryPointCompletionTcs.TrySetResult(exception); } diff --git a/src/MinimalLambda.Testing/Options/LambdaServerOptions.cs b/src/MinimalLambda.Testing/Options/LambdaServerOptions.cs index 7c977de0..12f1b8ad 100644 --- a/src/MinimalLambda.Testing/Options/LambdaServerOptions.cs +++ b/src/MinimalLambda.Testing/Options/LambdaServerOptions.cs @@ -1,28 +1,27 @@ namespace MinimalLambda.Testing; -/// -/// Configuration options for the Lambda test client. -/// +/// Configuration options for the Lambda test client. public class LambdaServerOptions { /// - /// Gets or sets additional custom headers to include in the Lambda invocation response. - /// Use this to add any additional headers beyond the standard Lambda runtime headers. + /// Gets or sets additional custom headers to include in the Lambda invocation response. Use + /// this to add any additional headers beyond the standard Lambda runtime headers. /// public Dictionary AdditionalHeaders { get; set; } = new(); /// - /// Gets or sets the ARN of the Lambda function being invoked. - /// Maps to the Lambda-Runtime-Invoked-Function-Arn header. + /// Gets or sets the ARN of the Lambda function being invoked. Maps to the + /// Lambda-Runtime-Invoked-Function-Arn header. /// public string FunctionArn { get; set; } = "arn:aws:lambda:us-west-2:123412341234:function:Function"; /// - /// Gets or sets the Lambda function timeout duration. - /// Maps to the Lambda-Runtime-Deadline-Ms header as Unix epoch milliseconds. - /// This determines when the Lambda function will timeout, calculated as the current time plus this duration. - /// Defaults to 15 minutes. + /// Gets or sets the Lambda function timeout duration. Maps to the + /// Lambda-Runtime-Deadline-Ms header as Unix epoch milliseconds. This determines when the + /// Lambda function will timeout, calculated as the current time plus this duration. Defaults to 3 + /// seconds, the default function + /// timeout. /// - public TimeSpan FunctionTimeout { get; set; } = TimeSpan.FromMinutes(15); + public TimeSpan FunctionTimeout { get; set; } = TimeSpan.FromMinutes(3); } From e7d35728f25b072f832424c04347e99d0f8e8152 Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Sun, 14 Dec 2025 12:28:19 -0500 Subject: [PATCH 5/7] refactor(docs): improve inline XML doc formatting across Lambda Testing models and extensions - Replaced multi-line XML documentation with consistent single-line descriptions for readability. - Simplified and formatted comments in `InvocationResponse`, `ErrorResponse`, `InitResponse`, and related models. - Standardized usage of `` inline references for improved clarity and consistency in codebase. - Adjusted extension method comments in `LambdaTestServerExtensions` to align with updated formatting style. --- .../Features/IEventFeatureProviderFactory.cs | 10 +- .../IResponseFeatureProviderFactory.cs | 6 +- .../DefaultLambdaJsonSerializerOptions.cs | 10 +- .../MiddlewareOpenTelemetryExtensions.cs | 8 +- .../LambdaApplicationFactory.cs | 176 ++++++------ ...aApplicationFactoryContentRootAttribute.cs | 71 ++--- .../LambdaHttpHandler.cs | 4 +- src/MinimalLambda.Testing/LambdaTestServer.cs | 256 ++++++++---------- .../LambdaTestServerExtensions.cs | 107 ++++---- .../Models/ErrorResponse.cs | 44 +-- .../Models/InitResponse.cs | 12 +- .../Models/InitStatus.cs | 20 +- .../Models/InvocationCompletion.cs | 4 +- .../Models/InvocationResponse.cs | 53 ++-- .../Models/InvocationResponseT.cs | 30 +- .../Models/LambdaHttpTransaction.cs | 24 +- .../Models/PendingInvocation.cs | 28 +- .../Models/ServerState.cs | 28 +- ...daHttpClientServiceCollectionExtensions.cs | 36 ++- .../Core/Options/LambdaHostOptions.cs | 1 - .../SimpleLambdaTests.cs | 2 +- ...dlewareLambdaApplicationExtensionsTests.cs | 2 +- .../Builder/LambdaApplicationTests.cs | 2 +- ...mattingLambdaApplicationExtensionsTests.cs | 2 +- 24 files changed, 439 insertions(+), 497 deletions(-) diff --git a/src/MinimalLambda.Abstractions/Features/IEventFeatureProviderFactory.cs b/src/MinimalLambda.Abstractions/Features/IEventFeatureProviderFactory.cs index 8f4a1c28..604e5dee 100644 --- a/src/MinimalLambda.Abstractions/Features/IEventFeatureProviderFactory.cs +++ b/src/MinimalLambda.Abstractions/Features/IEventFeatureProviderFactory.cs @@ -4,9 +4,9 @@ namespace MinimalLambda; /// /// /// creates -/// instances for specific event types during Lambda invocations. The factory enables -/// lazy registration of event feature providers. This factory is registered automatically -/// at startup. +/// instances for specific event types during Lambda invocations. The factory enables lazy +/// registration of event feature providers. This factory is registered automatically at +/// startup. /// /// public interface IEventFeatureProviderFactory @@ -14,8 +14,8 @@ public interface IEventFeatureProviderFactory /// Creates a feature provider for the specified event type. /// The type of event object to create a provider for. /// - /// An that can create - /// instances for the specified type. + /// An that can create instances + /// for the specified type. /// IFeatureProvider Create(); } diff --git a/src/MinimalLambda.Abstractions/Features/IResponseFeatureProviderFactory.cs b/src/MinimalLambda.Abstractions/Features/IResponseFeatureProviderFactory.cs index 6444d715..34294940 100644 --- a/src/MinimalLambda.Abstractions/Features/IResponseFeatureProviderFactory.cs +++ b/src/MinimalLambda.Abstractions/Features/IResponseFeatureProviderFactory.cs @@ -4,9 +4,9 @@ namespace MinimalLambda; /// /// /// creates -/// instances for specific response types during Lambda invocations. The factory enables -/// lazy registration of response feature providers. This factory is registered automatically -/// at startup. +/// instances for specific response types during Lambda invocations. The factory enables lazy +/// registration of response feature providers. This factory is registered automatically at +/// startup. /// /// public interface IResponseFeatureProviderFactory diff --git a/src/MinimalLambda.Abstractions/Options/DefaultLambdaJsonSerializerOptions.cs b/src/MinimalLambda.Abstractions/Options/DefaultLambdaJsonSerializerOptions.cs index b30c5b8f..1ac834e8 100644 --- a/src/MinimalLambda.Abstractions/Options/DefaultLambdaJsonSerializerOptions.cs +++ b/src/MinimalLambda.Abstractions/Options/DefaultLambdaJsonSerializerOptions.cs @@ -13,8 +13,14 @@ public static class DefaultLambdaJsonSerializerOptions /// . /// /// - /// Configures null-value ignoring, case-insensitive property names, and the AWS naming policy. - /// Adds the AWS-provided converters for dates, memory streams, constant classes, and byte arrays. + /// + /// Configures null-value ignoring, case-insensitive property names, and the AWS naming + /// policy. + /// + /// + /// Adds the AWS-provided converters for dates, memory streams, constant classes, and byte + /// arrays. + /// /// /// Configured JSON serializer options suitable for AWS Lambda payloads. public static JsonSerializerOptions Create() diff --git a/src/MinimalLambda.OpenTelemetry/MiddlewareOpenTelemetryExtensions.cs b/src/MinimalLambda.OpenTelemetry/MiddlewareOpenTelemetryExtensions.cs index 15e67768..5a6024a9 100644 --- a/src/MinimalLambda.OpenTelemetry/MiddlewareOpenTelemetryExtensions.cs +++ b/src/MinimalLambda.OpenTelemetry/MiddlewareOpenTelemetryExtensions.cs @@ -16,12 +16,12 @@ public static class MiddlewareOpenTelemetryExtensions /// /// /// Adds middleware that wraps each Lambda invocation with distributed tracing using the - /// from the OpenTelemetry AWS Lambda instrumentation - /// package. A root span is created for each invocation with Lambda context information. + /// from the OpenTelemetry AWS Lambda instrumentation package. + /// A root span is created for each invocation with Lambda context information. /// /// - /// Middleware Placement: Call this method early in the middleware pipeline to - /// capture the execution time of all subsequent middleware and handler logic. + /// Middleware Placement: Call this method early in the middleware pipeline to capture + /// the execution time of all subsequent middleware and handler logic. /// /// /// TracerProvider Registration Required: A must be diff --git a/src/MinimalLambda.Testing/LambdaApplicationFactory.cs b/src/MinimalLambda.Testing/LambdaApplicationFactory.cs index 79d7f337..a10e0b2c 100644 --- a/src/MinimalLambda.Testing/LambdaApplicationFactory.cs +++ b/src/MinimalLambda.Testing/LambdaApplicationFactory.cs @@ -17,11 +17,11 @@ namespace MinimalLambda.Testing; -/// -/// Factory for bootstrapping an application in memory for functional end to end tests. -/// -/// A type in the entry point assembly of the application. -/// Typically the Startup or Program classes can be used. +/// Factory for bootstrapping an application in memory for functional end to end tests. +/// +/// A type in the entry point assembly of the application. Typically the +/// Startup or Program classes can be used. +/// public class LambdaApplicationFactory : IDisposable, IAsyncDisposable where TEntryPoint : class { @@ -34,52 +34,58 @@ public class LambdaApplicationFactory : IDisposable, IAsyncDisposab private CancellationToken? _stoppingToken; /// - /// - /// Creates an instance of . This factory can be used to - /// create a instance for testing Lambda applications defined by - /// in-memory without deploying to AWS. - /// The will find the entry point class of - /// assembly and initialize the application by calling IHostBuilder CreateHostBuilder(string[] args) - /// on . - /// - /// - /// This constructor will infer the application content root path by searching for a - /// on the assembly containing the functional tests with - /// a key equal to the assembly . - /// In case an attribute with the right key can't be found, - /// will fall back to searching for a solution file (*.sln) and then appending assembly name - /// to the solution directory. The application root directory will be used to discover views and content files. - /// - /// - /// The application assemblies will be loaded from the dependency context of the assembly containing - /// . This means that project dependencies of the assembly containing - /// will be loaded as application assemblies. - /// + /// + /// Creates an instance of . This factory + /// can be used to create a instance for testing Lambda + /// applications defined by in-memory without deploying to + /// AWS. The will find the entry point + /// class of assembly and initialize the application by + /// calling IHostBuilder CreateHostBuilder(string[] args) on + /// . + /// + /// + /// This constructor will infer the application content root path by searching for a + /// on the assembly containing the + /// functional tests with a key equal to the assembly + /// . In case an attribute with the right key can't be found, + /// will fall back to searching for a + /// solution file (*.sln) and then appending assembly name + /// to the solution directory. The application root directory will be used to discover views + /// and content files. + /// + /// + /// The application assemblies will be loaded from the dependency context of the assembly + /// containing . This means that project dependencies of the + /// assembly containing will be loaded as application + /// assemblies. + /// /// public LambdaApplicationFactory() => _configuration = ConfigureWebHost; /// - /// Gets the of factories created from this factory - /// by further customizing the when calling - /// . + /// Gets the of factories created from + /// this factory by further customizing the when calling + /// . /// public IReadOnlyList> Factories => _derivedFactories.AsReadOnly(); /// - /// Gets the used to configure the . - /// These options control Lambda-specific testing behavior such as function timeout, ARN, and custom headers - /// included in Lambda runtime HTTP responses. + /// Gets the used to configure the + /// . These options control Lambda-specific testing behavior such as + /// function timeout, ARN, and custom headers included in Lambda runtime HTTP responses. /// public LambdaServerOptions ServerOptions { get; private init; } = new(); /// - /// Gets the created by the server associated with this . + /// Gets the created by the server associated with this + /// . /// public virtual IServiceProvider Services => TestServer.Services; /// - /// Gets the created by this . + /// Gets the created by this + /// . /// public LambdaTestServer TestServer { @@ -123,20 +129,23 @@ public void Dispose() } /// - /// Configures a cancellation token to propagate test cancellation signals to the Lambda test server - /// and its underlying components. + /// Configures a cancellation token to propagate test cancellation signals to the Lambda test + /// server and its underlying components. /// /// - /// A that will be propagated to the test server, allowing it to - /// respond more efficiently to cancellation signals during test execution. + /// A that will be propagated to the + /// test server, allowing it to respond more efficiently to cancellation signals during test + /// execution. /// /// - /// The current instance for method chaining. + /// The current instance for method + /// chaining. /// /// - /// This method allows test frameworks to signal cancellation to the Lambda test infrastructure, - /// enabling graceful shutdown and faster test cleanup when tests are cancelled or time out. - /// The cancellation token is passed to the during creation. + /// This method allows test frameworks to signal cancellation to the Lambda test + /// infrastructure, enabling graceful shutdown and faster test cleanup when tests are cancelled or + /// time out. The cancellation token is passed to the during + /// creation. /// public LambdaApplicationFactory WithCancellationToken( CancellationToken cancellationToken @@ -146,39 +155,42 @@ CancellationToken cancellationToken return this; } - /// - /// Finalizes an instance of the class. - /// + /// Finalizes an instance of the class. ~LambdaApplicationFactory() => Dispose(false); /// - /// Creates a new with a - /// that is further customized by . + /// Creates a new with a + /// that is further customized by . /// /// - /// An to configure the . + /// An to configure the + /// . /// - /// A new . + /// A new . public LambdaApplicationFactory WithHostBuilder( Action configuration ) => WithHostBuilderCore(configuration); /// - /// Core implementation of that creates a derived factory with additional configuration. - /// This method creates a that chains the parent factory's configuration - /// with the new configuration provided in . The derived factory is tracked in the - /// list for proper disposal. + /// Core implementation of that creates a derived factory with + /// additional configuration. This method creates a + /// that chains the parent factory's configuration + /// with the new configuration provided in . The derived factory + /// is tracked in the list for proper disposal. /// /// - /// An to configure the . - /// This configuration will be applied after the parent factory's configuration. + /// An to configure the + /// . This configuration will be applied after the parent factory's + /// configuration. /// /// - /// A new that applies both the parent factory's - /// configuration and the additional configuration specified in . + /// A new that applies both the parent + /// factory's configuration and the additional configuration specified in + /// . /// /// - /// This method is to allow derived classes to customize the factory creation behavior. + /// This method is to allow derived classes to customize the + /// factory creation behavior. /// protected virtual LambdaApplicationFactory WithHostBuilderCore( Action configuration @@ -379,12 +391,11 @@ string tEntryPointAssemblyName } /// - /// Gets the assemblies containing the functional tests. The - /// applied to these - /// assemblies defines the content root to use for the given - /// . + /// Gets the assemblies containing the functional tests. The + /// applied to these assemblies defines + /// the content root to use for the given . /// - /// The list of containing tests. + /// The list of containing tests. protected virtual IEnumerable GetTestAssemblies() { try @@ -445,28 +456,28 @@ private static void EnsureDepsFile() } /// - /// Creates the with the bootstrapped application in . - /// The host is built but not started. The will start the host - /// when is called. + /// Creates the with the bootstrapped application in + /// . The host is built but not started. The + /// will start the host when + /// is called. /// - /// The used to create the host. - /// The with the bootstrapped application. + /// The used to create the host. + /// The with the bootstrapped application. protected virtual IHost CreateHost(IHostBuilder builder) => // Build the host but DON'T start it - LambdaTestServer.StartAsync() will start it builder.Build(); - /// - /// Gives a fixture an opportunity to configure the application before it gets built. - /// - /// The for the application. + /// Gives a fixture an opportunity to configure the application before it gets built. + /// The for the application. protected virtual void ConfigureWebHost(IHostBuilder builder) { } /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// Performs application-defined tasks associated with freeing, releasing, or resetting + /// unmanaged resources. /// /// - /// to release both managed and unmanaged resources; - /// to release only unmanaged resources. + /// to release both managed and unmanaged resources; + /// to release only unmanaged resources. /// protected virtual void Dispose(bool disposing) { @@ -480,15 +491,16 @@ protected virtual void Dispose(bool disposing) } /// - /// Internal implementation of that delegates virtual method calls - /// to callbacks provided at construction. This class is used by to create derived - /// factories with customized behavior without creating additional subclasses. + /// Internal implementation of that + /// delegates virtual method calls to callbacks provided at construction. This class is used by + /// to create derived + /// factories with customized behavior without creating additional subclasses. /// /// - /// This class implements the delegation pattern to allow runtime customization of virtual methods. - /// Each virtual method (, , - /// and ) delegates to a callback function provided in the constructor, - /// enabling configuration chaining while reusing the base factory infrastructure. + /// This class implements the delegation pattern to allow runtime customization of virtual + /// methods. Each virtual method (, , and + /// ) delegates to a callback function provided in the constructor, + /// enabling configuration chaining while reusing the base factory infrastructure. /// private sealed class DelegatedLambdaApplicationFactory : LambdaApplicationFactory { diff --git a/src/MinimalLambda.Testing/LambdaApplicationFactoryContentRootAttribute.cs b/src/MinimalLambda.Testing/LambdaApplicationFactoryContentRootAttribute.cs index b79a883f..9cf33ae1 100644 --- a/src/MinimalLambda.Testing/LambdaApplicationFactoryContentRootAttribute.cs +++ b/src/MinimalLambda.Testing/LambdaApplicationFactoryContentRootAttribute.cs @@ -12,39 +12,45 @@ namespace MinimalLambda.Testing; /// -/// Metadata that uses to find out the content -/// root for the web application represented by TEntryPoint. -/// will iterate over all the instances of -/// , filter the instances whose -/// is equal to TEntryPoint , -/// order them by in ascending order. -/// will check for the existence of the marker -/// in Path.Combine(, Path.GetFileName())" -/// and if the file exists it will set the content root to . +/// Metadata that uses to find out the +/// content root for the web application represented by TEntryPoint. +/// will iterate over all the instances of +/// , filter the instances whose +/// is equal to TEntryPoint , order them +/// by in ascending order. +/// will check for the existence of the marker +/// in +/// +/// Path.Combine(, Path.GetFileName( +/// ))" +/// +/// and if the file exists it will set the content root to +/// . /// [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] public sealed class LambdaApplicationFactoryContentRootAttribute : Attribute { - /// - /// Initializes a new instance of . - /// + /// Initializes a new instance of . /// - /// The key of this . This - /// key is used by to determine what of the - /// instances on the test assembly should be used - /// to match a given TEntryPoint class. + /// The key of this . This + /// key is used by to determine what of the + /// instances on the test assembly + /// should be used to match a given TEntryPoint class. + /// + /// + /// The path to the content root. This path can be either relative or + /// absolute. In case the path is relative, the path will be combined with + /// /// - /// The path to the content root. This path can be either relative or absolute. - /// In case the path is relative, the path will be combined with - /// /// - /// A file that will be use as a marker to determine that the content root path for the given context is correct. + /// A file that will be use as a marker to determine that the content + /// root path for the given context is correct. /// /// - /// The priority of this content root attribute compared to other attributes. When - /// multiple instances are applied for the - /// same key, they are processed with , ordered in ascending order and applied - /// in priority until a match is found. + /// The priority of this content root attribute compared to other attributes. + /// When multiple instances are applied + /// for the same key, they are processed with , ordered in + /// ascending order and applied in priority until a match is found. /// public LambdaApplicationFactoryContentRootAttribute( string key, @@ -68,24 +74,25 @@ out var parsedPriority } /// - /// Gets the content root path for a given project. This content root can be relative or absolute. If it is a - /// relative path, it will be combined with . + /// Gets the content root path for a given project. This content root can be relative or + /// absolute. If it is a relative path, it will be combined with + /// . /// public string ContentRootPath { get; } - /// - /// A marker file used to ensure that the path the content root is being set to is correct. - /// + /// A marker file used to ensure that the path the content root is being set to is correct. public string ContentRootTest { get; } /// - /// Gets the key for the content root associated with this project. Typically . + /// Gets the key for the content root associated with this project. Typically + /// . /// public string Key { get; } /// - /// Gets a number for determining the probing order when multiple - /// instances with the same key are present on the test . + /// Gets a number for determining the probing order when multiple + /// instances with the same key are + /// present on the test . /// public int Priority { get; } } diff --git a/src/MinimalLambda.Testing/LambdaHttpHandler.cs b/src/MinimalLambda.Testing/LambdaHttpHandler.cs index b01b73c4..ec33b0df 100644 --- a/src/MinimalLambda.Testing/LambdaHttpHandler.cs +++ b/src/MinimalLambda.Testing/LambdaHttpHandler.cs @@ -3,8 +3,8 @@ namespace MinimalLambda.Testing; /// -/// HTTP message handler that intercepts Lambda Bootstrap HTTP calls and -/// routes them through the test server via transactions. +/// HTTP message handler that intercepts Lambda Bootstrap HTTP calls and routes them through +/// the test server via transactions. /// internal class LambdaTestingHttpHandler( Channel transactionChannel, diff --git a/src/MinimalLambda.Testing/LambdaTestServer.cs b/src/MinimalLambda.Testing/LambdaTestServer.cs index a6dec8fd..407622d5 100644 --- a/src/MinimalLambda.Testing/LambdaTestServer.cs +++ b/src/MinimalLambda.Testing/LambdaTestServer.cs @@ -12,95 +12,74 @@ namespace MinimalLambda.Testing; /// -/// Provides an in-memory test server that simulates the AWS Lambda runtime environment for testing Lambda functions -/// without deploying to AWS. This server intercepts HTTP requests from the Lambda bootstrap client, manages the -/// invocation lifecycle, and provides a public API for test scenarios. +/// Provides an in-memory test server that simulates the AWS Lambda runtime environment for +/// testing Lambda functions without deploying to AWS. This server intercepts HTTP requests from +/// the Lambda bootstrap client, manages the invocation lifecycle, and provides a public API for +/// test scenarios. /// /// -/// -/// The follows a strict state machine lifecycle: -/// Created → Starting → Running → Stopping → Stopped → Disposed. -/// -/// -/// This class is typically created and managed by -/// rather than being instantiated directly. The server handles invocation queuing, response handling, -/// timeout enforcement, and Lambda runtime API protocol compliance. -/// +/// +/// The follows a strict state machine lifecycle: Created → +/// Starting → Running → Stopping → Stopped → Disposed. +/// +/// +/// This class is typically created and managed by +/// rather than being instantiated +/// directly. The server handles invocation queuing, response handling, timeout enforcement, +/// and Lambda runtime API protocol compliance. +/// /// public class LambdaTestServer : IAsyncDisposable { - /// - /// Task that represents the running Host application that has been captured. - /// + /// Task that represents the running Host application that has been captured. private readonly Task _entryPointCompletion; - /// - /// TCS used to signal the startup has completed - /// + /// TCS used to signal the startup has completed private readonly TaskCompletionSource _initCompletionTcs = new( TaskCreationOptions.RunContinuationsAsynchronously ); - /// - /// JSON serializer options used to serialize/deserilize Lambda events and responses. - /// + /// JSON serializer options used to serialize/deserilize Lambda events and responses. private readonly JsonSerializerOptions _jsonSerializerOptions; - /// - /// Channel used to queue pending invocations in a FIFO manner. - /// + /// Channel used to queue pending invocations in a FIFO manner. private readonly Channel _pendingInvocationIds = Channel.CreateUnbounded( new UnboundedChannelOptions { SingleReader = true, SingleWriter = false } ); - /// - /// Dictionary to track all invocations that have been sent to Lambda. - /// + /// Dictionary to track all invocations that have been sent to Lambda. private readonly ConcurrentDictionary _pendingInvocations = new(); - /// - /// Options used to configure how the server interacts with the Lambda. - /// + /// Options used to configure how the server interacts with the Lambda. private readonly LambdaServerOptions _serverOptions; - /// - /// CTS used to signal shutdown of the server and cancellation of pending tasks. - /// + /// CTS used to signal shutdown of the server and cancellation of pending tasks. private readonly CancellationTokenSource _shutdownCts; private readonly SemaphoreSlim _startSemaphore = new(1, 1); - /// - /// Channel used to by the Lambda to send events to the server. - /// + /// Channel used to by the Lambda to send events to the server. private readonly Channel _transactionChannel = Channel.CreateUnbounded( new UnboundedChannelOptions { SingleReader = true, SingleWriter = false } ); - /// - /// Host application lifetime used to signal shutdown to the captioned Host. - /// + /// Host application lifetime used to signal shutdown to the captioned Host. private IHostApplicationLifetime? _applicationLifetime; - /// - /// Indicates whether the server has been disposed. - /// + /// Indicates whether the server has been disposed. private bool _disposed; - /// - /// The captured Host instance. - /// + /// The captured Host instance. private IHost? _host; /// - /// Task that is running the background processing loop to handle incoming requests from Lambda. + /// Task that is running the background processing loop to handle incoming requests from + /// Lambda. /// private Task? _processingTask; - /// - /// Counter used to generate unique request IDs. - /// + /// Counter used to generate unique request IDs. private int _requestCounter; internal LambdaTestServer( @@ -120,45 +99,38 @@ internal LambdaTestServer( } /// - /// Gets the from the underlying instance, - /// providing access to the dependency injection container for the Lambda application. + /// Gets the from the underlying + /// instance, providing access to the dependency injection container for the Lambda application. /// - /// - /// The service provider from the captured host instance. - /// + /// The service provider from the captured host instance. /// - /// This property allows tests to resolve services from the Lambda application's DI container - /// for setup, assertion, or inspection purposes. + /// This property allows tests to resolve services from the Lambda application's DI container + /// for setup, assertion, or inspection purposes. /// /// - /// Thrown if accessed before the host has been set via . + /// Thrown if accessed before the host has been set via + /// . /// public IServiceProvider Services => _host!.Services; - /// - /// Current state of the server used to enforce lifecycle rules. - /// + /// Current state of the server used to enforce lifecycle rules. public ServerState State { get; private set; } - /// - /// Asynchronously releases all resources used by the . - /// - /// A representing the asynchronous dispose operation. + /// Asynchronously releases all resources used by the . + /// A representing the asynchronous dispose operation. /// - /// - /// This method performs the following cleanup operations: - /// - /// - /// Stops the server if it is currently running - /// Completes the transaction channel to prevent new requests - /// Cancels the shutdown token to signal background tasks - /// Disposes the underlying instance - /// Transitions the server state to - /// - /// - /// This method is safe to call multiple times. Subsequent calls after the first will return immediately - /// without performing any operations. - /// + /// This method performs the following cleanup operations: + /// + /// Stops the server if it is currently running + /// Completes the transaction channel to prevent new requests + /// Cancels the shutdown token to signal background tasks + /// Disposes the underlying instance + /// Transitions the server state to + /// + /// + /// This method is safe to call multiple times. Subsequent calls after the first will return + /// immediately without performing any operations. + /// /// public async ValueTask DisposeAsync() { @@ -198,30 +170,32 @@ internal HttpMessageHandler CreateHandler() => // └──────────────────────────────────────────────────────────┘ /// - /// Initializes and starts the Lambda test server, beginning the application host and preparing - /// it to accept invocations. + /// Initializes and starts the Lambda test server, beginning the application host and + /// preparing it to accept invocations. /// /// - /// A to observe while waiting for the server to start. + /// A to observe while waiting for the + /// server to start. /// /// - /// A that completes with an indicating - /// whether initialization succeeded, failed with an error, or the host exited prematurely. + /// A that completes with an + /// indicating whether initialization succeeded, failed with an error, or the host exited + /// prematurely. /// /// - /// Thrown if the server has already been started, if the host is not set, or if initialization - /// fails without an error or completion signal. + /// Thrown if the server has already been started, if the + /// host is not set, or if initialization fails without an error or completion signal. /// /// - /// - /// This method can only be called once per server instance. The server must be in the - /// state when this method is called. - /// - /// - /// The method starts the underlying , begins background processing of - /// Lambda runtime HTTP transactions, and waits for the Lambda bootstrap to complete its - /// initialization phase by requesting the first invocation. - /// + /// + /// This method can only be called once per server instance. The server must be in the + /// state when this method is called. + /// + /// + /// The method starts the underlying , begins background processing of + /// Lambda runtime HTTP transactions, and waits for the Lambda bootstrap to complete its + /// initialization phase by requesting the first invocation. + /// /// public async Task StartAsync(CancellationToken cancellationToken = default) { @@ -284,50 +258,50 @@ await TaskHelpers } } - /// - /// Invokes the Lambda function with the specified event and waits for the response or error. - /// + /// Invokes the Lambda function with the specified event and waits for the response or error. /// The expected type of the Lambda function's response. /// The type of the Lambda event to send to the function. /// The event object to pass to the Lambda function. /// - /// Set to when the handler does not return a response body (for example, - /// stream writers) to skip reading/deserializing the response. + /// Set to when the handler does not return a response + /// body (for example, stream writers) to skip reading/deserializing the response. /// /// - /// The AWS X-Ray trace ID to use for this invocation. If , a new GUID will be generated and - /// surfaced on the `Lambda-Runtime-Trace-Id` header. + /// The AWS X-Ray trace ID to use for this invocation. If + /// , a new GUID will be generated and surfaced on the `Lambda-Runtime-Trace-Id` header. /// /// - /// A to observe while waiting for the invocation to complete. + /// A to observe while waiting for the + /// invocation to complete. /// /// - /// A that completes with an - /// containing either the successful response or error information from the Lambda function. + /// A that completes with an + /// containing either the successful response or error + /// information from the Lambda function. /// /// - /// Thrown if the server is not in the state, or if the - /// invocation cannot be enqueued. + /// Thrown if the server is not in the + /// state, or if the invocation cannot be enqueued. /// /// - /// Thrown if the invocation times out based on - /// or if the is cancelled. + /// Thrown if the invocation times out based on + /// or if the + /// is cancelled. /// /// - /// - /// This method simulates the AWS Lambda invocation protocol by: - /// - /// - /// Generating a unique request ID - /// Creating an HTTP response with Lambda runtime headers - /// Queuing the invocation for the Lambda bootstrap to retrieve - /// Waiting for the Lambda function to respond or report an error - /// Deserializing the response or error information - /// - /// - /// The invocation will timeout based on the setting, - /// which defaults to AWS Lambda's standard timeout behavior. - /// + /// This method simulates the AWS Lambda invocation protocol by: + /// + /// Generating a unique request ID + /// Creating an HTTP response with Lambda runtime headers + /// Queuing the invocation for the Lambda bootstrap to retrieve + /// Waiting for the Lambda function to respond or report an error + /// Deserializing the response or error information + /// + /// + /// The invocation will timeout based on the + /// setting, which defaults to AWS Lambda's + /// standard timeout behavior. + /// /// public async Task> InvokeAsync( TEvent? invokeEvent, @@ -407,31 +381,31 @@ is not (InitStatus.InitCompleted or InitStatus.InitAlreadyCompleted) } /// - /// Gracefully stops the running test server, shutting down the Lambda application host and - /// completing all background processing. + /// Gracefully stops the running test server, shutting down the Lambda application host and + /// completing all background processing. /// /// - /// A to observe while waiting for the server to stop. + /// A to observe while waiting for the + /// server to stop. /// - /// A representing the asynchronous stop operation. + /// A representing the asynchronous stop operation. /// - /// Thrown if the server is not currently in the state. + /// Thrown if the server is not currently in the + /// state. /// /// - /// - /// 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 - /// Waits for the entry point and processing tasks to complete - /// Transitions the server state to - /// - /// - /// After stopping, the server cannot be restarted. A new instance - /// must be created for subsequent test runs. - /// + /// 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 + /// Waits for the entry point and processing tasks to complete + /// Transitions the server state to + /// + /// + /// After stopping, the server cannot be restarted. A new + /// instance must be created for subsequent test runs. + /// /// public async Task StopAsync(CancellationToken cancellationToken = default) { diff --git a/src/MinimalLambda.Testing/LambdaTestServerExtensions.cs b/src/MinimalLambda.Testing/LambdaTestServerExtensions.cs index 37e31c26..55a8167c 100644 --- a/src/MinimalLambda.Testing/LambdaTestServerExtensions.cs +++ b/src/MinimalLambda.Testing/LambdaTestServerExtensions.cs @@ -1,41 +1,47 @@ namespace MinimalLambda.Testing; /// -/// Provides convenience extension methods for to simplify common invocation patterns. +/// Provides convenience extension methods for to simplify +/// common invocation patterns. /// /// -/// -/// These extension methods wrap the core method, -/// providing simplified overloads for common scenarios such as invocations without events or without response bodies. -/// +/// +/// These extension methods wrap the core +/// method, providing simplified +/// overloads for common scenarios such as invocations without events or without response +/// bodies. +/// /// public static class LambdaTestServerExtensions { extension(LambdaTestServer server) { - /// - /// Invokes the Lambda function with the specified event and waits for the response. - /// + /// Invokes the Lambda function with the specified event and waits for the response. /// The type of the Lambda event to send to the function. /// The expected type of the Lambda function's response. /// The event object to pass to the Lambda function. /// - /// A to observe while waiting for the invocation to complete. + /// A to observe while waiting for the + /// invocation to complete. /// /// - /// A that completes with an - /// containing either the successful response or error information from the Lambda function. + /// A that completes with an + /// containing either the successful response or error + /// information from the Lambda function. /// /// - /// Thrown if the server is not in a valid state to accept invocations. + /// Thrown if the server is not in a valid state to accept + /// invocations. /// /// - /// Thrown if the invocation times out or the is cancelled. + /// Thrown if the invocation times out or the + /// is cancelled. /// /// - /// This is a convenience method that invokes the Lambda function with an event and expects a response body. - /// It is equivalent to calling with - /// noResponse set to . + /// This is a convenience method that invokes the Lambda function with an event and expects a + /// response body. It is equivalent to calling + /// with noResponse set to + /// . /// public Task> InvokeAsync( TEvent invokeEvent, @@ -47,32 +53,35 @@ public Task> InvokeAsync( cancellationToken: cancellationToken ); - /// - /// Invokes the Lambda function without an event and waits for the response. - /// + /// Invokes the Lambda function without an event and waits for the response. /// The expected type of the Lambda function's response. /// - /// A to observe while waiting for the invocation to complete. + /// A to observe while waiting for the + /// invocation to complete. /// /// - /// A that completes with an - /// containing either the successful response or error information from the Lambda function. + /// A that completes with an + /// containing either the successful response or error + /// information from the Lambda function. /// /// - /// Thrown if the server is not in a valid state to accept invocations. + /// Thrown if the server is not in a valid state to accept + /// invocations. /// /// - /// Thrown if the invocation times out or the is cancelled. + /// Thrown if the invocation times out or the + /// is cancelled. /// /// - /// - /// This is a convenience method for invoking Lambda functions that do not require an event payload, - /// such as handlers that perform scheduled tasks or generate data without input. - /// - /// - /// It is equivalent to calling with - /// a event and noResponse set to . - /// + /// + /// This is a convenience method for invoking Lambda functions that do not require an event + /// payload, such as handlers that perform scheduled tasks or generate data without input. + /// + /// + /// It is equivalent to calling + /// with a + /// event and noResponse set to . + /// /// public Task> InvokeNoEventAsync( CancellationToken cancellationToken = default @@ -84,32 +93,38 @@ public Task> InvokeNoEventAsync( ); /// - /// Invokes the Lambda function with the specified event but does not expect or deserialize a response body. + /// Invokes the Lambda function with the specified event but does not expect or deserialize a + /// response body. /// /// The type of the Lambda event to send to the function. /// The event object to pass to the Lambda function. /// - /// A to observe while waiting for the invocation to complete. + /// A to observe while waiting for the + /// invocation to complete. /// /// - /// A that completes with an - /// containing either success status or error information from the Lambda function. + /// A that completes with an + /// containing either success status or error information from the Lambda function. /// /// - /// Thrown if the server is not in a valid state to accept invocations. + /// Thrown if the server is not in a valid state to accept + /// invocations. /// /// - /// Thrown if the invocation times out or the is cancelled. + /// Thrown if the invocation times out or the + /// is cancelled. /// /// - /// - /// This is a convenience method for invoking Lambda functions that do not return a response body, - /// such as handlers that write directly to streams or perform side effects without returning data. - /// - /// - /// It is equivalent to calling with - /// noResponse set to . - /// + /// + /// This is a convenience method for invoking Lambda functions that do not return a response + /// body, such as handlers that write directly to streams or perform side effects without + /// returning data. + /// + /// + /// It is equivalent to calling + /// with noResponse set + /// to . + /// /// public async Task InvokeNoResponseAsync( TEvent invokeEvent, diff --git a/src/MinimalLambda.Testing/Models/ErrorResponse.cs b/src/MinimalLambda.Testing/Models/ErrorResponse.cs index dd0c433d..a297c704 100644 --- a/src/MinimalLambda.Testing/Models/ErrorResponse.cs +++ b/src/MinimalLambda.Testing/Models/ErrorResponse.cs @@ -2,67 +2,45 @@ namespace MinimalLambda.Testing; -/// -/// Represents an error response with type, message, stack trace, and optional cause. -/// +/// Represents an error response with type, message, stack trace, and optional cause. public class ErrorResponse { - /// - /// The underlying cause of this error, if any. - /// + /// The underlying cause of this error, if any. [JsonPropertyName("cause")] public ErrorCause? Cause { get; set; } - /// - /// The underlying causes of this error, if any. - /// + /// The underlying causes of this error, if any. [JsonPropertyName("causes")] public List? Causes { get; set; } - /// - /// The error message describing what went wrong. - /// + /// The error message describing what went wrong. [JsonPropertyName("errorMessage")] public required string ErrorMessage { get; set; } - /// - /// The type of error that occurred. - /// + /// The type of error that occurred. [JsonPropertyName("errorType")] public required string ErrorType { get; set; } - /// - /// The stack trace showing where the error occurred. - /// + /// The stack trace showing where the error occurred. [JsonPropertyName("stackTrace")] public List StackTrace { get; set; } = []; - /// - /// Represents the cause of an error, which can have its own nested cause. - /// + /// Represents the cause of an error, which can have its own nested cause. public class ErrorCause { - /// - /// The underlying cause of this error, if any. - /// + /// The underlying cause of this error, if any. [JsonPropertyName("cause")] public ErrorCause? Cause { get; set; } - /// - /// The error message describing what went wrong. - /// + /// The error message describing what went wrong. [JsonPropertyName("errorMessage")] public required string ErrorMessage { get; set; } - /// - /// The type of error that occurred. - /// + /// The type of error that occurred. [JsonPropertyName("errorType")] public required string ErrorType { get; set; } - /// - /// The stack trace showing where the error occurred. - /// + /// The stack trace showing where the error occurred. [JsonPropertyName("stackTrace")] public List StackTrace { get; set; } = []; } diff --git a/src/MinimalLambda.Testing/Models/InitResponse.cs b/src/MinimalLambda.Testing/Models/InitResponse.cs index 823f9947..7fcdb1d8 100644 --- a/src/MinimalLambda.Testing/Models/InitResponse.cs +++ b/src/MinimalLambda.Testing/Models/InitResponse.cs @@ -1,17 +1,11 @@ namespace MinimalLambda.Testing; -/// -/// Represents the result of a Lambda function initialization attempt. -/// +/// Represents the result of a Lambda function initialization attempt. public class InitResponse { - /// - /// Gets the error information if initialization failed, or null if initialization succeeded. - /// + /// Gets the error information if initialization failed, or null if initialization succeeded. public ErrorResponse? Error { get; internal init; } - /// - /// Gets the status of the initialization attempt. - /// + /// Gets the status of the initialization attempt. public InitStatus InitStatus { get; internal init; } } diff --git a/src/MinimalLambda.Testing/Models/InitStatus.cs b/src/MinimalLambda.Testing/Models/InitStatus.cs index ae8f0f92..e8ba9cc6 100644 --- a/src/MinimalLambda.Testing/Models/InitStatus.cs +++ b/src/MinimalLambda.Testing/Models/InitStatus.cs @@ -1,27 +1,17 @@ namespace MinimalLambda.Testing; -/// -/// An enumeration of possible statuses for Lambda initialization. -/// +/// An enumeration of possible statuses for Lambda initialization. public enum InitStatus { - /// - /// Initialization of the Lambda completed successfully. - /// + /// Initialization of the Lambda completed successfully. InitCompleted, - /// - /// Initialization of the Lambda failed, and the Lambda returned an error. - /// + /// Initialization of the Lambda failed, and the Lambda returned an error. InitError, - /// - /// Initialization of the Lambda failed, and the Host process exited. - /// + /// Initialization of the Lambda failed, and the Host process exited. HostExited, - /// - /// Initialization has already been completed and cannot be repeated. - /// + /// Initialization has already been completed and cannot be repeated. InitAlreadyCompleted, } diff --git a/src/MinimalLambda.Testing/Models/InvocationCompletion.cs b/src/MinimalLambda.Testing/Models/InvocationCompletion.cs index 0737b98a..dadb1043 100644 --- a/src/MinimalLambda.Testing/Models/InvocationCompletion.cs +++ b/src/MinimalLambda.Testing/Models/InvocationCompletion.cs @@ -1,8 +1,6 @@ namespace MinimalLambda.Testing; -/// -/// Represents the completion of a Lambda invocation with metadata about the outcome. -/// +/// Represents the completion of a Lambda invocation with metadata about the outcome. internal class InvocationCompletion { internal required HttpRequestMessage Request { get; init; } diff --git a/src/MinimalLambda.Testing/Models/InvocationResponse.cs b/src/MinimalLambda.Testing/Models/InvocationResponse.cs index 354e2802..806d59c5 100644 --- a/src/MinimalLambda.Testing/Models/InvocationResponse.cs +++ b/src/MinimalLambda.Testing/Models/InvocationResponse.cs @@ -1,48 +1,49 @@ namespace MinimalLambda.Testing; /// -/// Represents the base result of a Lambda function invocation, containing success status and -/// error information. +/// Represents the base result of a Lambda function invocation, containing success status and +/// error information. /// /// -/// -/// This class serves as the non-generic base for , -/// providing common properties for all invocation results regardless of the response type. -/// It contains the flag and information that -/// are shared across all invocation responses. -/// -/// -/// For invocations that return typed response data, use the generic -/// class instead. -/// +/// +/// This class serves as the non-generic base for +/// , providing common properties for all +/// invocation results regardless of the response type. It contains the +/// flag and information that are shared across +/// all invocation responses. +/// +/// +/// For invocations that return typed response data, use the generic +/// class instead. +/// /// public class InvocationResponse { /// - /// Gets the error information if the Lambda function invocation failed, or - /// if the invocation succeeded. + /// Gets the error information if the Lambda function invocation failed, or + /// if the invocation succeeded. /// /// - /// An containing error details, or for successful invocations. + /// An containing error details, or for + /// successful invocations. /// /// - /// This property is populated when the Lambda function reports an error via the runtime API's - /// error endpoint, or when the invocation times out or encounters other failures. + /// This property is populated when the Lambda function reports an error via the runtime API's + /// error endpoint, or when the invocation times out or encounters other failures. /// public ErrorResponse? Error { get; internal init; } - /// - /// Gets a value indicating whether the Lambda function invocation completed successfully. - /// + /// Gets a value indicating whether the Lambda function invocation completed successfully. /// - /// if the invocation succeeded and response data is available (in - /// for generic invocations); - /// if the invocation failed and contains error information. + /// if the invocation succeeded and response data is available (in + /// for generic invocations); + /// if the invocation failed and contains error + /// information. /// /// - /// Use this property to determine whether the invocation succeeded or failed, which indicates - /// whether response data or information contains meaningful data for the - /// invocation result. + /// Use this property to determine whether the invocation succeeded or failed, which indicates + /// whether response data or information contains meaningful data for the + /// invocation result. /// public bool WasSuccess { get; internal init; } } diff --git a/src/MinimalLambda.Testing/Models/InvocationResponseT.cs b/src/MinimalLambda.Testing/Models/InvocationResponseT.cs index e4d1e58b..011eef91 100644 --- a/src/MinimalLambda.Testing/Models/InvocationResponseT.cs +++ b/src/MinimalLambda.Testing/Models/InvocationResponseT.cs @@ -1,31 +1,33 @@ namespace MinimalLambda.Testing; /// -/// Represents the result of a Lambda function invocation with a typed response, containing either -/// a successful response or error information. +/// Represents the result of a Lambda function invocation with a typed response, containing +/// either a successful response or error information. /// /// The expected type of the successful Lambda response. /// -/// -/// This generic class extends to provide strongly-typed access -/// to the Lambda function's response data. Use the -/// property to determine whether the invocation succeeded or failed. If successful, -/// will contain the deserialized response data. If failed, -/// will contain details about the error. -/// +/// +/// This generic class extends to provide strongly-typed +/// access to the Lambda function's response data. Use the +/// property to determine whether the invocation +/// succeeded or failed. If successful, will contain the deserialized +/// response data. If failed, will contain details +/// about the error. +/// /// public class InvocationResponse : InvocationResponse { /// - /// Gets the Lambda function's response data if the invocation succeeded, or the default value - /// of if the invocation failed. + /// Gets the Lambda function's response data if the invocation succeeded, or the default value + /// of if the invocation failed. /// /// - /// The deserialized response from the Lambda function, or for failed invocations. + /// The deserialized response from the Lambda function, or for failed + /// invocations. /// /// - /// This property is populated when the Lambda function successfully completes and returns a response - /// via the runtime API's response endpoint. + /// This property is populated when the Lambda function successfully completes and returns a + /// response via the runtime API's response endpoint. /// public TResponse? Response { get; internal init; } } diff --git a/src/MinimalLambda.Testing/Models/LambdaHttpTransaction.cs b/src/MinimalLambda.Testing/Models/LambdaHttpTransaction.cs index cb3a6015..d8ab6697 100644 --- a/src/MinimalLambda.Testing/Models/LambdaHttpTransaction.cs +++ b/src/MinimalLambda.Testing/Models/LambdaHttpTransaction.cs @@ -1,25 +1,21 @@ namespace MinimalLambda.Testing; /// -/// Represents a single HTTP transaction from the Lambda Bootstrap. -/// Bundles the request with its response completion mechanism for automatic correlation. +/// Represents a single HTTP transaction from the Lambda Bootstrap. Bundles the request with +/// its response completion mechanism for automatic correlation. /// internal class LambdaHttpTransaction { - /// - /// The HTTP request from Lambda Bootstrap. - /// + /// The HTTP request from Lambda Bootstrap. internal required HttpRequestMessage Request { get; init; } /// - /// Task completion source for the HTTP response. - /// Completing this sends the response back to Bootstrap. + /// Task completion source for the HTTP response. Completing this sends the response back to + /// Bootstrap. /// internal required TaskCompletionSource ResponseTcs { get; init; } - /// - /// Creates a new transaction with RunContinuationsAsynchronously to prevent deadlocks. - /// + /// Creates a new transaction with RunContinuationsAsynchronously to prevent deadlocks. internal static LambdaHttpTransaction Create(HttpRequestMessage request) => new() { @@ -29,13 +25,9 @@ internal static LambdaHttpTransaction Create(HttpRequestMessage request) => ), }; - /// - /// Completes the transaction with a successful HTTP response. - /// + /// Completes the transaction with a successful HTTP response. internal bool Respond(HttpResponseMessage response) => ResponseTcs.TrySetResult(response); - /// - /// Completes the transaction with cancellation. - /// + /// Completes the transaction with cancellation. internal bool Cancel() => ResponseTcs.TrySetCanceled(); } diff --git a/src/MinimalLambda.Testing/Models/PendingInvocation.cs b/src/MinimalLambda.Testing/Models/PendingInvocation.cs index 12eb63b9..54437ea6 100644 --- a/src/MinimalLambda.Testing/Models/PendingInvocation.cs +++ b/src/MinimalLambda.Testing/Models/PendingInvocation.cs @@ -1,40 +1,30 @@ namespace MinimalLambda.Testing; -/// -/// Represents a pending Lambda invocation waiting for Bootstrap to process and respond. -/// +/// Represents a pending Lambda invocation waiting for Bootstrap to process and respond. internal class PendingInvocation { - /// - /// Timestamp when this invocation was created (for timeout tracking). - /// + /// Timestamp when this invocation was created (for timeout tracking). internal DateTime CreatedAt { get; init; } = DateTime.UtcNow; - /// - /// Absolute time when this invocation should be considered expired. - /// + /// Absolute time when this invocation should be considered expired. internal required DateTimeOffset DeadlineUtc { get; init; } /// - /// The HTTP response containing the serialized event payload and Lambda headers - /// to send to Bootstrap when it polls for the next invocation. + /// The HTTP response containing the serialized event payload and Lambda headers to send to + /// Bootstrap when it polls for the next invocation. /// internal required HttpResponseMessage EventResponse { get; init; } - /// - /// Unique request ID for this invocation (will be in Lambda-Runtime-Aws-Request-Id header). - /// + /// Unique request ID for this invocation (will be in Lambda-Runtime-Aws-Request-Id header). internal required string RequestId { get; init; } /// - /// Task completion source for the invocation result. - /// Completed when Bootstrap posts response or error with the HTTP request containing the result payload. + /// Task completion source for the invocation result. Completed when Bootstrap posts response + /// or error with the HTTP request containing the result payload. /// internal required TaskCompletionSource ResponseTcs { get; init; } - /// - /// Creates a pending invocation with proper TCS configuration. - /// + /// Creates a pending invocation with proper TCS configuration. internal static PendingInvocation Create( string requestId, HttpResponseMessage eventResponse, diff --git a/src/MinimalLambda.Testing/Models/ServerState.cs b/src/MinimalLambda.Testing/Models/ServerState.cs index 164c3803..f7d48f29 100644 --- a/src/MinimalLambda.Testing/Models/ServerState.cs +++ b/src/MinimalLambda.Testing/Models/ServerState.cs @@ -1,37 +1,23 @@ namespace MinimalLambda.Testing; -/// -/// Represents the lifecycle state of a LambdaTestServer. -/// +/// Represents the lifecycle state of a LambdaTestServer. public enum ServerState { - /// - /// TestServer created but not started. - /// + /// TestServer created but not started. Created, - /// - /// TestServer is starting (building host). - /// + /// TestServer is starting (building host). Starting, - /// - /// TestServer is running and accepting invocations. - /// + /// TestServer is running and accepting invocations. Running, - /// - /// TestServer is stopping. - /// + /// TestServer is stopping. Stopping, - /// - /// TestServer has stopped cleanly. - /// + /// TestServer has stopped cleanly. Stopped, - /// - /// TestServer has been disposed. - /// + /// TestServer has been disposed. Disposed, } diff --git a/src/MinimalLambda/Builder/Extensions/LambdaHttpClientServiceCollectionExtensions.cs b/src/MinimalLambda/Builder/Extensions/LambdaHttpClientServiceCollectionExtensions.cs index 3c46b6aa..9fd120a6 100644 --- a/src/MinimalLambda/Builder/Extensions/LambdaHttpClientServiceCollectionExtensions.cs +++ b/src/MinimalLambda/Builder/Extensions/LambdaHttpClientServiceCollectionExtensions.cs @@ -4,8 +4,8 @@ namespace MinimalLambda.Builder.Extensions; /// -/// Extension methods for configuring the Lambda bootstrap HTTP client in an -/// . +/// Extension methods for configuring the Lambda bootstrap HTTP client in an +/// . /// public static class LambdaHttpClientServiceCollectionExtensions { @@ -30,20 +30,18 @@ public IServiceCollection AddLambdaBootstrapHttpClient(T client) return services; } - /// - /// Adds a factory for creating a custom HTTP client for the Lambda bootstrap runtime API. - /// + /// Adds a factory for creating a custom HTTP client for the Lambda bootstrap runtime API. /// - /// A factory function that creates the instance. The function - /// receives the and service key. + /// A factory function that creates the instance. The + /// function receives the and service key. /// /// The for chaining. /// /// /// Registers a keyed singleton factory that will be used by the - /// Lambda bootstrap to communicate with the Lambda runtime API. This overload provides - /// access to the dependency injection container, allowing you to resolve other services - /// when constructing the HTTP client. + /// Lambda bootstrap to communicate with the Lambda runtime API. This overload provides access + /// to the dependency injection container, allowing you to resolve other services when + /// constructing the HTTP client. /// /// public IServiceCollection AddLambdaBootstrapHttpClient( @@ -58,16 +56,16 @@ public IServiceCollection AddLambdaBootstrapHttpClient( } /// - /// Attempts to add a custom HTTP client instance for the Lambda bootstrap runtime API if one is - /// not already registered. + /// Attempts to add a custom HTTP client instance for the Lambda bootstrap runtime API if one + /// is not already registered. /// /// The type of to register. /// The pre-configured instance. /// /// Registers a keyed singleton that will be used by the Lambda - /// bootstrap to communicate with the Lambda runtime API, but only if a keyed HTTP client has - /// not already been registered. This overload is useful for testing scenarios where you want - /// to inject a mock or fake HTTP client without overwriting user-supplied configurations. + /// bootstrap to communicate with the Lambda runtime API, but only if a keyed HTTP client has not + /// already been registered. This overload is useful for testing scenarios where you want to inject + /// a mock or fake HTTP client without overwriting user-supplied configurations. /// public void TryAddLambdaBootstrapHttpClient(T client) where T : HttpClient @@ -78,12 +76,12 @@ public void TryAddLambdaBootstrapHttpClient(T client) } /// - /// Attempts to add a factory for creating a custom HTTP client for the Lambda bootstrap runtime - /// API if one is not already registered. + /// Attempts to add a factory for creating a custom HTTP client for the Lambda bootstrap + /// runtime API if one is not already registered. /// /// - /// A factory function that creates the instance. The function - /// receives the and service key. + /// A factory function that creates the instance. The + /// function receives the and service key. /// /// /// diff --git a/src/MinimalLambda/Core/Options/LambdaHostOptions.cs b/src/MinimalLambda/Core/Options/LambdaHostOptions.cs index c9d45807..1286c812 100644 --- a/src/MinimalLambda/Core/Options/LambdaHostOptions.cs +++ b/src/MinimalLambda/Core/Options/LambdaHostOptions.cs @@ -1,5 +1,4 @@ using Amazon.Lambda.RuntimeSupport.Bootstrap; -using MinimalLambda.Builder.Extensions; namespace MinimalLambda.Options; 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 48b30e1f..284253f2 100644 --- a/tests/MinimalLambda.Testing.UnitTests/Tests/MinimalLambda.Testing.UnitTests/SimpleLambdaTests.cs +++ b/tests/MinimalLambda.Testing.UnitTests/Tests/MinimalLambda.Testing.UnitTests/SimpleLambdaTests.cs @@ -17,7 +17,7 @@ public async Task SimpleLambda_ReturnsExpectedValue() var response = await factory.TestServer.InvokeAsync( "World", - cancellationToken: TestContext.Current.CancellationToken + TestContext.Current.CancellationToken ); response.WasSuccess.Should().BeTrue(); diff --git a/tests/MinimalLambda.UnitTests/Builder/Extensions/MiddlewareLambdaApplicationExtensionsTests.cs b/tests/MinimalLambda.UnitTests/Builder/Extensions/MiddlewareLambdaApplicationExtensionsTests.cs index e010c594..b886bc25 100644 --- a/tests/MinimalLambda.UnitTests/Builder/Extensions/MiddlewareLambdaApplicationExtensionsTests.cs +++ b/tests/MinimalLambda.UnitTests/Builder/Extensions/MiddlewareLambdaApplicationExtensionsTests.cs @@ -8,7 +8,7 @@ public class MiddlewareLambdaApplicationExtensionsTests { private static IHost CreateHostWithServices() { - var builder = Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder(); + var builder = Host.CreateDefaultBuilder(); builder.ConfigureServices(services => { services.ConfigureLambdaHostOptions(_ => { }); diff --git a/tests/MinimalLambda.UnitTests/Builder/LambdaApplicationTests.cs b/tests/MinimalLambda.UnitTests/Builder/LambdaApplicationTests.cs index a020fc85..6a5a5805 100644 --- a/tests/MinimalLambda.UnitTests/Builder/LambdaApplicationTests.cs +++ b/tests/MinimalLambda.UnitTests/Builder/LambdaApplicationTests.cs @@ -8,7 +8,7 @@ public class LambdaApplicationTests { private static IHost CreateHostWithServices() { - var builder = Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder(); + var builder = Host.CreateDefaultBuilder(); builder.ConfigureServices(services => { services.ConfigureLambdaHostOptions(_ => { }); diff --git a/tests/MinimalLambda.UnitTests/Builder/OnInit/OutputFormattingLambdaApplicationExtensionsTests.cs b/tests/MinimalLambda.UnitTests/Builder/OnInit/OutputFormattingLambdaApplicationExtensionsTests.cs index b9cafb50..7d387a1b 100644 --- a/tests/MinimalLambda.UnitTests/Builder/OnInit/OutputFormattingLambdaApplicationExtensionsTests.cs +++ b/tests/MinimalLambda.UnitTests/Builder/OnInit/OutputFormattingLambdaApplicationExtensionsTests.cs @@ -8,7 +8,7 @@ public class OutputFormattingLambdaApplicationExtensionsTests { private static IHost CreateHostWithServices() { - var builder = Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder(); + var builder = Host.CreateDefaultBuilder(); builder.ConfigureServices(services => { services.ConfigureLambdaHostOptions(_ => { }); From 79b346b3da46300fb686bbe9b3cea8cf110fe4ff Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Sun, 14 Dec 2025 12:28:39 -0500 Subject: [PATCH 6/7] refactor(testing): update Lambda default timeout value - Changed `FunctionTimeout` default in `LambdaServerOptions` from 3 minutes to 3 seconds. - Updated inline XML documentation link for better clarification. --- src/MinimalLambda.Testing/Options/LambdaServerOptions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MinimalLambda.Testing/Options/LambdaServerOptions.cs b/src/MinimalLambda.Testing/Options/LambdaServerOptions.cs index 12f1b8ad..b2404af4 100644 --- a/src/MinimalLambda.Testing/Options/LambdaServerOptions.cs +++ b/src/MinimalLambda.Testing/Options/LambdaServerOptions.cs @@ -23,5 +23,5 @@ public class LambdaServerOptions /// seconds, the default function /// timeout. /// - public TimeSpan FunctionTimeout { get; set; } = TimeSpan.FromMinutes(3); + public TimeSpan FunctionTimeout { get; set; } = TimeSpan.FromSeconds(3); } From 033ca224dae50e38616ae68b2518f6a2748599d2 Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Sun, 14 Dec 2025 12:29:23 -0500 Subject: [PATCH 7/7] chore(config): bump version to 2.0.0-beta.5 - Updated the version in `Directory.Build.props` to 2.0.0-beta.5. --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index f5952314..258f0801 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,6 +1,6 @@ - 2.0.0-beta.3 + 2.0.0-beta.5 MIT