From 03afc8ee663c8db854d14dde66c5a4f236690079 Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Sun, 7 Dec 2025 15:42:38 -0500 Subject: [PATCH 1/7] refactor(testing): remove unused client configuration and streamline server creation - Deleted `ConfigureClient(HttpClient client)` method and related XML documentation. - Removed commented-out and redundant `_createServer` and `ConfigureClient` references. - Introduced `CreateServer` for internal use in `LambdaApplicationFactory`. - Updated `DelegatedLambdaApplicationFactory` to simplify server initialization logic. --- .../LambdaApplicationFactory.cs | 34 ++++++------------- 1 file changed, 10 insertions(+), 24 deletions(-) diff --git a/src/AwsLambda.Host.Testing/LambdaApplicationFactory.cs b/src/AwsLambda.Host.Testing/LambdaApplicationFactory.cs index ae4fca38..ea8c78d6 100644 --- a/src/AwsLambda.Host.Testing/LambdaApplicationFactory.cs +++ b/src/AwsLambda.Host.Testing/LambdaApplicationFactory.cs @@ -27,7 +27,6 @@ namespace AwsLambda.Host.Testing; public partial class LambdaApplicationFactory : IDisposable, IAsyncDisposable where TEntryPoint : class { - // private readonly List _clients = []; private readonly List> _derivedFactories = []; private Action _configuration; private bool _disposed; @@ -159,17 +158,18 @@ public LambdaApplicationFactory WithWebHostBuilder( Action configuration ) => WithWebHostBuilderCore(configuration); + internal virtual LambdaTestServer CreateServer() => new(); + internal virtual LambdaApplicationFactory WithWebHostBuilderCore( Action configuration ) { var factory = new DelegatedLambdaApplicationFactory( ClientOptions, - // CreateServer, + CreateServer, CreateHost, CreateHostBuilder, GetTestAssemblies, - ConfigureClient, builder => { _configuration(builder); @@ -479,17 +479,6 @@ protected virtual IHost CreateHost(IHostBuilder builder) /// The for the application. protected virtual void ConfigureWebHost(IHostBuilder builder) { } - /// - /// Configures instances created by this . - /// - /// The instance getting configured. - protected virtual void ConfigureClient(HttpClient client) - { - ArgumentNullException.ThrowIfNull(client); - - client.BaseAddress = new Uri("http://localhost"); - } - /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// @@ -514,52 +503,49 @@ private sealed partial class CustomJsonSerializerContext : JsonSerializerContext private sealed class DelegatedLambdaApplicationFactory : LambdaApplicationFactory { - private readonly Action _configureClient; - - // private readonly Func _createServer; + private readonly Func _createServer; private readonly Func _createHost; private readonly Func _createHostBuilder; private readonly Func> _getTestAssemblies; public DelegatedLambdaApplicationFactory( LambdaApplicationFactoryClientOptions options, + // Func createServer, // Func createServer, + Func createServer, Func createHost, Func createHostBuilder, Func> getTestAssemblies, - Action configureClient, Action configureWebHost ) { ClientOptions = options; - // _createServer = createServer; + _createServer = createServer; _createHost = createHost; _createHostBuilder = createHostBuilder; _getTestAssemblies = getTestAssemblies; - _configureClient = configureClient; _configuration = configureWebHost; } protected override IHost CreateHost(IHostBuilder builder) => _createHost(builder); + internal override LambdaTestServer CreateServer() => _createServer(); + protected override IHostBuilder? CreateHostBuilder() => _createHostBuilder(); protected override IEnumerable GetTestAssemblies() => _getTestAssemblies(); protected override void ConfigureWebHost(IHostBuilder builder) => _configuration(builder); - protected override void ConfigureClient(HttpClient client) => _configureClient(client); - internal override LambdaApplicationFactory WithWebHostBuilderCore( Action configuration ) => new DelegatedLambdaApplicationFactory( ClientOptions, - // _createServer, + _createServer, _createHost, _createHostBuilder, _getTestAssemblies, - _configureClient, builder => { _configuration(builder); From 312594a82ce3b37f6533d13d5dac45e86404fa64 Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Sun, 7 Dec 2025 15:47:16 -0500 Subject: [PATCH 2/7] refactor(testing): update default RuntimeApiEndpoint value in LambdaHostOptions - Changed default `RuntimeApiEndpoint` from `localhost:3002` to `localhost` in `LambdaApplicationFactory`. --- src/AwsLambda.Host.Testing/LambdaApplicationFactory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AwsLambda.Host.Testing/LambdaApplicationFactory.cs b/src/AwsLambda.Host.Testing/LambdaApplicationFactory.cs index ea8c78d6..a30be00a 100644 --- a/src/AwsLambda.Host.Testing/LambdaApplicationFactory.cs +++ b/src/AwsLambda.Host.Testing/LambdaApplicationFactory.cs @@ -250,7 +250,7 @@ private void ConfigureHostBuilder(IHostBuilder hostBuilder) services.PostConfigure(options => { if (string.IsNullOrEmpty(options.BootstrapOptions.RuntimeApiEndpoint)) - options.BootstrapOptions.RuntimeApiEndpoint = "localhost:3002"; + options.BootstrapOptions.RuntimeApiEndpoint = "localhost"; }); }); From 9c95711957a942bc0ddddd1b93abd7e881c25fcc Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Sun, 7 Dec 2025 15:51:00 -0500 Subject: [PATCH 3/7] refactor(testing): remove redundant logic and commented-out code in LambdaApplicationFactory - Deleted unused and commented-out `EnsureServer` and `Return Services` logic. - Simplified `SetContentRoot` by removing conditional file checks. - Updated `GetContentRoot` to always use `GetContentRootFromAssembly`. --- src/AwsLambda.Host.Testing/LambdaApplicationFactory.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/AwsLambda.Host.Testing/LambdaApplicationFactory.cs b/src/AwsLambda.Host.Testing/LambdaApplicationFactory.cs index a30be00a..9ea9a8bd 100644 --- a/src/AwsLambda.Host.Testing/LambdaApplicationFactory.cs +++ b/src/AwsLambda.Host.Testing/LambdaApplicationFactory.cs @@ -92,7 +92,6 @@ public virtual IServiceProvider Services get { EnsureServer(); - // return _host?.Services ?? _server.Host.Services; return _host!.Services; } } @@ -262,10 +261,7 @@ private void ConfigureHostBuilder(IHostBuilder hostBuilder) private void SetContentRoot(IHostBuilder builder) { - var fromFile = File.Exists("MvcTestingAppManifest.json"); - var contentRoot = fromFile - ? GetContentRootFromFile("MvcTestingAppManifest.json") - : GetContentRootFromAssembly(); + var contentRoot = GetContentRootFromAssembly(); if (contentRoot != null) builder.UseContentRoot(contentRoot); From 1c23862dd0c60bcf74fc20753575e9cdee2f7987 Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Sun, 7 Dec 2025 15:54:54 -0500 Subject: [PATCH 4/7] refactor(testing): remove unused methods and simplify logic in LambdaApplicationFactory - Deleted `GetContentRootFromFile` and replaced all usage with `GetContentRootFromAssembly`. - Updated `GetContentRootFromAssembly` to use a `foreach` loop for clarity. - Returned `[]` instead of `Array.Empty` to simplify empty array initialization. - Rearranged fields in `DelegatedLambdaApplicationFactory` for consistent ordering. - Added comments to ignored exceptions for better readability. --- .../LambdaApplicationFactory.cs | 28 +++++-------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/src/AwsLambda.Host.Testing/LambdaApplicationFactory.cs b/src/AwsLambda.Host.Testing/LambdaApplicationFactory.cs index 9ea9a8bd..478471c9 100644 --- a/src/AwsLambda.Host.Testing/LambdaApplicationFactory.cs +++ b/src/AwsLambda.Host.Testing/LambdaApplicationFactory.cs @@ -304,22 +304,6 @@ string solutionRelativePath ); } - private static string? GetContentRootFromFile(string file) - { - var data = JsonSerializer.Deserialize( - File.ReadAllBytes(file), - CustomJsonSerializerContext.Default.IDictionaryStringString - )!; - var key = typeof(TEntryPoint).Assembly.GetName().FullName; - - // If the `ContentRoot` is not provided in the app manifest, then return null - // and fallback to setting the content root relative to the entrypoint's assembly. - if (!data.TryGetValue(key, out var contentRoot)) - return null; - - return contentRoot == "~" ? AppContext.BaseDirectory : contentRoot; - } - private string? GetContentRootFromAssembly() { var metadataAttributes = GetContentRootMetadataAttributes( @@ -328,9 +312,8 @@ string solutionRelativePath ); string? contentRoot = null; - for (var i = 0; i < metadataAttributes.Length; i++) + foreach (var contentRootAttribute in metadataAttributes) { - var contentRootAttribute = metadataAttributes[i]; var contentRootCandidate = Path.Combine( AppContext.BaseDirectory, contentRootAttribute.ContentRootPath @@ -418,9 +401,12 @@ protected virtual IEnumerable GetTestAssemblies() return testAssemblies; } - catch (Exception) { } + catch (Exception) + { + // Ignore + } - return Array.Empty(); + return []; } private static void EnsureDepsFile() @@ -499,9 +485,9 @@ private sealed partial class CustomJsonSerializerContext : JsonSerializerContext private sealed class DelegatedLambdaApplicationFactory : LambdaApplicationFactory { - private readonly Func _createServer; private readonly Func _createHost; private readonly Func _createHostBuilder; + private readonly Func _createServer; private readonly Func> _getTestAssemblies; public DelegatedLambdaApplicationFactory( From 4744f6c48fcd908fd5f0d3114b6789d1fb605ac9 Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Sun, 7 Dec 2025 15:56:35 -0500 Subject: [PATCH 5/7] refactor(testing): rename WithWebHostBuilder to WithHostBuilder in LambdaApplicationFactory - Renamed `WithWebHostBuilder` and `WithWebHostBuilderCore` to `WithHostBuilder` and `WithHostBuilderCore`. - Updated XML documentation comments to reflect the new method names. - Removed unused and commented-out server creation code in `DelegatedLambdaApplicationFactory`. - Updated example tests in `LambdaHostTest` to use the renamed `WithHostBuilder` method. --- .../Tests/LambdaHostTest.cs | 24 +++++++++---------- .../LambdaApplicationFactory.cs | 12 ++++------ 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/examples/AwsLambda.Host.Example.Testing/Tests/LambdaHostTest.cs b/examples/AwsLambda.Host.Example.Testing/Tests/LambdaHostTest.cs index 9d736874..bcab7c64 100644 --- a/examples/AwsLambda.Host.Example.Testing/Tests/LambdaHostTest.cs +++ b/examples/AwsLambda.Host.Example.Testing/Tests/LambdaHostTest.cs @@ -28,20 +28,18 @@ public async Task LambdaHost_CanStartWithoutError() [Fact] public async Task LambdaHost_CrashesWithBadConfiguration_ThrowsException() { - await using var factory = new LambdaApplicationFactory().WithWebHostBuilder( - builder => - { - builder.ConfigureServices( - (_, services) => + await using var factory = new LambdaApplicationFactory().WithHostBuilder(builder => + { + builder.ConfigureServices( + (_, services) => + { + services.Configure(options => { - services.Configure(options => - { - options.BootstrapOptions.RuntimeApiEndpoint = "http://localhost:3002"; - }); - } - ); - } - ); + options.BootstrapOptions.RuntimeApiEndpoint = "http://localhost:3002"; + }); + } + ); + }); var client = factory.CreateClient(); // No need to wait for next request - server handles this automatically diff --git a/src/AwsLambda.Host.Testing/LambdaApplicationFactory.cs b/src/AwsLambda.Host.Testing/LambdaApplicationFactory.cs index 478471c9..e679f906 100644 --- a/src/AwsLambda.Host.Testing/LambdaApplicationFactory.cs +++ b/src/AwsLambda.Host.Testing/LambdaApplicationFactory.cs @@ -67,7 +67,7 @@ public partial class LambdaApplicationFactory : IDisposable, IAsync /// /// Gets the of factories created from this factory /// by further customizing the when calling - /// . + /// . /// public IReadOnlyList> Factories => _derivedFactories.AsReadOnly(); @@ -153,13 +153,13 @@ public LambdaClient CreateClient() /// An to configure the . /// /// A new . - public LambdaApplicationFactory WithWebHostBuilder( + public LambdaApplicationFactory WithHostBuilder( Action configuration - ) => WithWebHostBuilderCore(configuration); + ) => WithHostBuilderCore(configuration); internal virtual LambdaTestServer CreateServer() => new(); - internal virtual LambdaApplicationFactory WithWebHostBuilderCore( + internal virtual LambdaApplicationFactory WithHostBuilderCore( Action configuration ) { @@ -492,8 +492,6 @@ private sealed class DelegatedLambdaApplicationFactory : LambdaApplicationFactor public DelegatedLambdaApplicationFactory( LambdaApplicationFactoryClientOptions options, - // Func createServer, - // Func createServer, Func createServer, Func createHost, Func createHostBuilder, @@ -519,7 +517,7 @@ Action configureWebHost protected override void ConfigureWebHost(IHostBuilder builder) => _configuration(builder); - internal override LambdaApplicationFactory WithWebHostBuilderCore( + internal override LambdaApplicationFactory WithHostBuilderCore( Action configuration ) => new DelegatedLambdaApplicationFactory( From 826dabf1a5aa3bca176289927c258aa21c03712f Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Sun, 7 Dec 2025 16:03:34 -0500 Subject: [PATCH 6/7] refactor(testing): simplify server initialization in LambdaApplicationFactory - Replaced inline server creation logic with a call to `CreateServer`. - Removed unused variables `serializerOptions` and `routeManager` during initialization. --- src/AwsLambda.Host.Testing/LambdaApplicationFactory.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/AwsLambda.Host.Testing/LambdaApplicationFactory.cs b/src/AwsLambda.Host.Testing/LambdaApplicationFactory.cs index e679f906..12bf9abd 100644 --- a/src/AwsLambda.Host.Testing/LambdaApplicationFactory.cs +++ b/src/AwsLambda.Host.Testing/LambdaApplicationFactory.cs @@ -8,7 +8,6 @@ using System.Diagnostics.CodeAnalysis; using System.Reflection; -using System.Text.Json; using System.Text.Json.Serialization; using AwsLambda.Host.Builder.Extensions; using AwsLambda.Host.Options; @@ -236,10 +235,7 @@ private void ConfigureHostBuilder(IHostBuilder hostBuilder) SetContentRoot(hostBuilder); _configuration(hostBuilder); - var serializerOptions = new JsonSerializerOptions(); - var routeManager = new LambdaRuntimeRouteManager(); - - _server = new LambdaTestServer(serializerOptions, routeManager); + _server = CreateServer(); // set Lambda Bootstrap Http Client hostBuilder.ConfigureServices(services => From 1c928c9fb3fcf0c8ed6d80dc81060157c7761fdf Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Sun, 7 Dec 2025 16:08:00 -0500 Subject: [PATCH 7/7] refactor(testing): clean up and simplify LambdaApplicationFactory - Removed commented-out and unused code, including `_clients` disposal and `CustomJsonSerializerContext`. - Dropped `partial` keyword from `LambdaApplicationFactory` class declaration. - Replaced `?.Name ?? string.Empty` with `.Name` for assembly name retrieval. - Updated array initialization to use brackets instead of `new[]`. - Simplified disposal logic for `Dispose` and `DisposeAsync` methods. --- .../LambdaApplicationFactory.cs | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/src/AwsLambda.Host.Testing/LambdaApplicationFactory.cs b/src/AwsLambda.Host.Testing/LambdaApplicationFactory.cs index 12bf9abd..440371dc 100644 --- a/src/AwsLambda.Host.Testing/LambdaApplicationFactory.cs +++ b/src/AwsLambda.Host.Testing/LambdaApplicationFactory.cs @@ -8,7 +8,6 @@ using System.Diagnostics.CodeAnalysis; using System.Reflection; -using System.Text.Json.Serialization; using AwsLambda.Host.Builder.Extensions; using AwsLambda.Host.Options; using Microsoft.Extensions.Configuration; @@ -23,7 +22,7 @@ namespace AwsLambda.Host.Testing; /// /// A type in the entry point assembly of the application. /// Typically the Startup or Program classes can be used. -public partial class LambdaApplicationFactory : IDisposable, IAsyncDisposable +public class LambdaApplicationFactory : IDisposable, IAsyncDisposable where TEntryPoint : class { private readonly List> _derivedFactories = []; @@ -104,9 +103,6 @@ public virtual async ValueTask DisposeAsync() if (_disposedAsync) return; - // foreach (var client in _clients) - // client.Dispose(); - foreach (var factory in _derivedFactories) await ((IAsyncDisposable)factory).DisposeAsync().ConfigureAwait(false); @@ -200,7 +196,7 @@ private void EnsureServer() { { HostDefaults.ApplicationKey, - typeof(TEntryPoint).Assembly.GetName()?.Name ?? string.Empty + typeof(TEntryPoint).Assembly.GetName().Name ?? string.Empty }, } ); @@ -367,7 +363,7 @@ protected virtual IEnumerable GetTestAssemblies() var context = DependencyContext.Default; if (context == null || context.CompileLibraries.Count == 0) // The app domain friendly name will be populated in full framework. - return new[] { Assembly.Load(AppDomain.CurrentDomain.FriendlyName) }; + return [Assembly.Load(AppDomain.CurrentDomain.FriendlyName)]; var runtimeProjectLibraries = context.RuntimeLibraries.ToDictionary( r => r.Name, @@ -469,16 +465,12 @@ protected virtual void Dispose(bool disposing) if (_disposed) return; - if (disposing) - if (!_disposedAsync) - DisposeAsync().AsTask().ConfigureAwait(false).GetAwaiter().GetResult(); + if (disposing && !_disposedAsync) + DisposeAsync().AsTask().ConfigureAwait(false).GetAwaiter().GetResult(); _disposed = true; } - [JsonSerializable(typeof(IDictionary))] - private sealed partial class CustomJsonSerializerContext : JsonSerializerContext; - private sealed class DelegatedLambdaApplicationFactory : LambdaApplicationFactory { private readonly Func _createHost;