Skip to content

Commit 52125c4

Browse files
authored
Add port environment variables for Aspire integration (#1942)
1 parent 6c50e10 commit 52125c4

File tree

11 files changed

+103
-16
lines changed

11 files changed

+103
-16
lines changed

Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Amazon.Lambda.TestTool.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<Project Sdk="Microsoft.NET.Sdk.Web">
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
22

33
<PropertyGroup>
44
<Description>A tool to help debug and test your .NET AWS Lambda functions locally.</Description>
@@ -17,7 +17,7 @@
1717
<NoWarn>NU5100</NoWarn>
1818
</PropertyGroup>
1919

20-
<ItemGroup>
20+
<ItemGroup Condition="$(Configuration) == 'Release'">
2121
<None Include="$(OutputPath)\publish\wwwroot\" Pack="true" PackagePath="tools\net8.0\any\wwwroot" Visible="false" />
2222
</ItemGroup>
2323

Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Commands/RunCommand.cs

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using Amazon.Lambda.TestTool.Models;
88
using Amazon.Lambda.TestTool.Processes;
99
using Amazon.Lambda.TestTool.Services;
10+
using Amazon.Lambda.TestTool.Services.IO;
1011
using Spectre.Console.Cli;
1112

1213
namespace Amazon.Lambda.TestTool.Commands;
@@ -15,15 +16,20 @@ namespace Amazon.Lambda.TestTool.Commands;
1516
/// The default command of the application which is responsible for launching the Lambda Runtime API and the API Gateway Emulator.
1617
/// </summary>
1718
public sealed class RunCommand(
18-
IToolInteractiveService toolInteractiveService) : CancellableAsyncCommand<RunCommandSettings>
19+
IToolInteractiveService toolInteractiveService, IEnvironmentManager environmentManager) : CancellableAsyncCommand<RunCommandSettings>
1920
{
21+
public const string LAMBDA_RUNTIME_API_PORT = "LAMBDA_RUNTIME_API_PORT";
22+
public const string API_GATEWAY_EMULATOR_PORT = "API_GATEWAY_EMULATOR_PORT";
23+
2024
/// <summary>
2125
/// The method responsible for executing the <see cref="RunCommand"/>.
2226
/// </summary>
2327
public override async Task<int> ExecuteAsync(CommandContext context, RunCommandSettings settings, CancellationTokenSource cancellationTokenSource)
2428
{
2529
try
2630
{
31+
EvaluateEnvironmentVariables(settings);
32+
2733
var tasks = new List<Task>();
2834

2935
var testToolProcess = TestToolProcess.Startup(settings, cancellationTokenSource.Token);
@@ -80,4 +86,36 @@ public override async Task<int> ExecuteAsync(CommandContext context, RunCommandS
8086
await cancellationTokenSource.CancelAsync();
8187
}
8288
}
89+
90+
private void EvaluateEnvironmentVariables(RunCommandSettings settings)
91+
{
92+
var environmentVariables = environmentManager.GetEnvironmentVariables();
93+
if (environmentVariables == null)
94+
return;
95+
96+
if (environmentVariables.Contains(LAMBDA_RUNTIME_API_PORT))
97+
{
98+
var envValue = environmentVariables[LAMBDA_RUNTIME_API_PORT]?.ToString();
99+
if (int.TryParse(envValue, out var port))
100+
{
101+
settings.Port = port;
102+
}
103+
else
104+
{
105+
throw new ArgumentException($"Value for {LAMBDA_RUNTIME_API_PORT} environment variable was not a valid port number");
106+
}
107+
}
108+
if (environmentVariables.Contains(API_GATEWAY_EMULATOR_PORT))
109+
{
110+
var envValue = environmentVariables[API_GATEWAY_EMULATOR_PORT]?.ToString();
111+
if (int.TryParse(envValue, out var port))
112+
{
113+
settings.ApiGatewayEmulatorPort = port;
114+
}
115+
else
116+
{
117+
throw new ArgumentException($"Value for {API_GATEWAY_EMULATOR_PORT} environment variable was not a valid port number");
118+
}
119+
}
120+
}
83121
}

Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Extensions/HttpContextExtensions.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,9 +168,11 @@ public static async Task<APIGatewayProxyRequest> ToApiGatewayRequest(
168168

169169
if (emulatorMode == ApiGatewayEmulatorMode.Rest) // rest uses encoded value for the path params
170170
{
171+
#pragma warning disable SYSLIB0013 // Type or member is obsolete
171172
var encodedPathParameters = pathParameters.ToDictionary(
172173
kvp => kvp.Key,
173-
kvp => Uri.EscapeUriString(kvp.Value)); // intentionally using EscapeURiString over EscapeDataString since EscapeURiString correctly handles reserved characters :/?#[]@!$&'()*+,;= in this case
174+
kvp => Uri.EscapeUriString(kvp.Value)); // intentionally using EscapeUriString over EscapeDataString since EscapeUriString correctly handles reserved characters :/?#[]@!$&'()*+,;= in this case
175+
#pragma warning restore SYSLIB0013 // Type or member is obsolete
174176
pathParameters = encodedPathParameters;
175177
}
176178

Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Extensions/InvokeResponseExtensions.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public static APIGatewayProxyResponse ToApiGatewayProxyResponse(this InvokeRespo
3434
string responseJson = reader.ReadToEnd();
3535
try
3636
{
37-
return JsonSerializer.Deserialize<APIGatewayProxyResponse>(responseJson);
37+
return JsonSerializer.Deserialize<APIGatewayProxyResponse>(responseJson)!;
3838
}
3939
catch
4040
{
@@ -132,7 +132,7 @@ private static APIGatewayHttpApiV2ProxyResponse ToHttpApiV2Response(string respo
132132
// It has a statusCode property, so try to deserialize as full response
133133
try
134134
{
135-
return JsonSerializer.Deserialize<APIGatewayHttpApiV2ProxyResponse>(response);
135+
return JsonSerializer.Deserialize<APIGatewayHttpApiV2ProxyResponse>(response)!;
136136
}
137137
catch
138138
{
@@ -155,7 +155,7 @@ private static APIGatewayHttpApiV2ProxyResponse ToHttpApiV2Response(string respo
155155
// return "test", it actually comes as "\"test\"" to response. So we need to get the raw string which is what api gateway does.
156156
if (jsonElement.ValueKind == JsonValueKind.String)
157157
{
158-
response = jsonElement.GetString();
158+
response = jsonElement.GetString()!;
159159
}
160160

161161
}

Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Extensions/ServiceCollectionExtensions.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ public static void AddCustomServices(this IServiceCollection serviceCollection,
2020
{
2121
serviceCollection.TryAdd(new ServiceDescriptor(typeof(IToolInteractiveService), typeof(ConsoleInteractiveService), lifetime));
2222
serviceCollection.TryAdd(new ServiceDescriptor(typeof(IDirectoryManager), typeof(DirectoryManager), lifetime));
23+
serviceCollection.TryAdd(new ServiceDescriptor(typeof(IEnvironmentManager), typeof(EnvironmentManager), lifetime));
2324
}
2425

2526
/// <summary>

Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Services/ApiGatewayRouteConfigService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public class ApiGatewayRouteConfigService : IApiGatewayRouteConfigService
1414
{
1515
private readonly ILogger<ApiGatewayRouteConfigService> _logger;
1616
private readonly IEnvironmentManager _environmentManager;
17-
private List<ApiGatewayRouteConfig> _routeConfigs = new();
17+
private readonly List<ApiGatewayRouteConfig> _routeConfigs = new();
1818

1919
/// <summary>
2020
/// Constructs an instance of <see cref="ApiGatewayRouteConfigService"/>.

Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Utilities/HttpRequestUtility.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ public static (IDictionary<string, string>, IDictionary<string, IList<string>>)
107107
{
108108
var key = lowerCaseKeyName ? header.Key.ToLower() : header.Key;
109109
singleValueHeaders[key] = header.Value.Last() ?? "";
110-
multiValueHeaders[key] = [.. header.Value];
110+
multiValueHeaders[key] = [.. header.Value!];
111111
}
112112

113113
return (singleValueHeaders, multiValueHeaders);
@@ -133,7 +133,7 @@ public static (IDictionary<string, string>, IDictionary<string, IList<string>>)
133133
foreach (var param in query)
134134
{
135135
singleValueParams[param.Key] = param.Value.Last() ?? "";
136-
multiValueParams[param.Key] = [.. param.Value];
136+
multiValueParams[param.Key] = [.. param.Value!];
137137
}
138138

139139
return (singleValueParams, multiValueParams);
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
using System.Collections;
5+
using Amazon.Lambda.TestTool.Services.IO;
6+
7+
namespace Amazon.Lambda.TestTool.Utilities;
8+
9+
public class LocalEnvironmentManager(IDictionary environmentManager) : IEnvironmentManager
10+
{
11+
public IDictionary GetEnvironmentVariables() => environmentManager;
12+
}

Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Utilities/RouteTemplateUtility.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public static Dictionary<string, string> ExtractPathParameters(string routeTempl
4040

4141
foreach (var param in template.Parameters)
4242
{
43-
if (routeValues.TryGetValue(param.Name, out var value))
43+
if (routeValues.TryGetValue(param.Name!, out var value))
4444
{
4545
var stringValue = value?.ToString() ?? string.Empty;
4646

@@ -51,7 +51,7 @@ public static Dictionary<string, string> ExtractPathParameters(string routeTempl
5151
}
5252

5353
// Restore original parameter name
54-
var originalParamName = RestoreOriginalParamName(param.Name);
54+
var originalParamName = RestoreOriginalParamName(param.Name!);
5555
result[originalParamName] = stringValue;
5656
}
5757
}

Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.IntegrationTests/ApiGatewayEmulatorProcessTests.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using Amazon.Lambda.TestTool.Commands.Settings;
99
using Amazon.Lambda.TestTool.Models;
1010
using Amazon.Lambda.TestTool.Services;
11+
using Amazon.Lambda.TestTool.Services.IO;
1112
using Moq;
1213
using Spectre.Console.Cli;
1314
using Xunit;
@@ -17,6 +18,7 @@ namespace Amazon.Lambda.TestTool.IntegrationTests;
1718

1819
public class ApiGatewayEmulatorProcessTests : IAsyncDisposable
1920
{
21+
private readonly Mock<IEnvironmentManager> _mockEnvironmentManager = new Mock<IEnvironmentManager>();
2022
private readonly Mock<IToolInteractiveService> _mockInteractiveService = new Mock<IToolInteractiveService>();
2123
private readonly Mock<IRemainingArguments> _mockRemainingArgs = new Mock<IRemainingArguments>();
2224
private readonly ITestOutputHelper _testOutputHelper;
@@ -245,7 +247,7 @@ private void StartTestToolProcess(ApiGatewayEmulatorMode apiGatewayMode, TestCon
245247
}}");
246248
cancellationTokenSource.CancelAfter(5000);
247249
var settings = new RunCommandSettings { Port = lambdaPort, NoLaunchWindow = true, ApiGatewayEmulatorMode = apiGatewayMode,ApiGatewayEmulatorPort = apiGatewayPort};
248-
var command = new RunCommand(_mockInteractiveService.Object);
250+
var command = new RunCommand(_mockInteractiveService.Object, _mockEnvironmentManager.Object);
249251
var context = new CommandContext(new List<string>(), _mockRemainingArgs.Object, "run", null);
250252

251253
// Act

Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.UnitTests/Commands/RunCommandTests.cs

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
// SPDX-License-Identifier: Apache-2.0
33

44
using Amazon.Lambda.TestTool.Commands.Settings;
@@ -9,11 +9,14 @@
99
using Moq;
1010
using Amazon.Lambda.TestTool.UnitTests.Helpers;
1111
using Xunit;
12+
using Amazon.Lambda.TestTool.Services.IO;
13+
using Amazon.Lambda.TestTool.Utilities;
1214

1315
namespace Amazon.Lambda.TestTool.UnitTests.Commands;
1416

1517
public class RunCommandTests
1618
{
19+
private readonly Mock<IEnvironmentManager> _mockEnvironmentManager = new Mock<IEnvironmentManager>();
1720
private readonly Mock<IToolInteractiveService> _mockInteractiveService = new Mock<IToolInteractiveService>();
1821
private readonly Mock<IRemainingArguments> _mockRemainingArgs = new Mock<IRemainingArguments>();
1922

@@ -25,7 +28,7 @@ public async Task ExecuteAsync_LambdaRuntimeApi_SuccessfulLaunch()
2528
var cancellationSource = new CancellationTokenSource();
2629
cancellationSource.CancelAfter(5000);
2730
var settings = new RunCommandSettings { Port = 9001, NoLaunchWindow = true };
28-
var command = new RunCommand(_mockInteractiveService.Object);
31+
var command = new RunCommand(_mockInteractiveService.Object, _mockEnvironmentManager.Object);
2932
var context = new CommandContext(new List<string>(), _mockRemainingArgs.Object, "run", null);
3033
var apiUrl = $"http://{settings.Host}:{settings.Port}";
3134

@@ -48,7 +51,7 @@ public async Task ExecuteAsync_ApiGatewayEmulator_SuccessfulLaunch()
4851
var cancellationSource = new CancellationTokenSource();
4952
cancellationSource.CancelAfter(5000);
5053
var settings = new RunCommandSettings { Port = 9002, ApiGatewayEmulatorMode = ApiGatewayEmulatorMode.HttpV2, NoLaunchWindow = true};
51-
var command = new RunCommand(_mockInteractiveService.Object);
54+
var command = new RunCommand(_mockInteractiveService.Object, _mockEnvironmentManager.Object);
5255
var context = new CommandContext(new List<string>(), _mockRemainingArgs.Object, "run", null);
5356
var apiUrl = $"http://{settings.Host}:{settings.ApiGatewayEmulatorPort}/__lambda_test_tool_apigateway_health__";
5457

@@ -62,4 +65,33 @@ public async Task ExecuteAsync_ApiGatewayEmulator_SuccessfulLaunch()
6265
Assert.Equal(CommandReturnCodes.Success, result);
6366
Assert.True(isApiRunning);
6467
}
68+
69+
[Fact]
70+
public async Task ExecuteAsync_EnvPorts_SuccessfulLaunch()
71+
{
72+
var environmentManager = new LocalEnvironmentManager(new Dictionary<string, string>
73+
{
74+
{ RunCommand.LAMBDA_RUNTIME_API_PORT, "9432" },
75+
{ RunCommand.API_GATEWAY_EMULATOR_PORT, "9765" }
76+
});
77+
78+
// Arrange
79+
Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "Development");
80+
var cancellationSource = new CancellationTokenSource();
81+
cancellationSource.CancelAfter(5000);
82+
var settings = new RunCommandSettings { ApiGatewayEmulatorMode = ApiGatewayEmulatorMode.HttpV2, NoLaunchWindow = true };
83+
var command = new RunCommand(_mockInteractiveService.Object, environmentManager);
84+
var context = new CommandContext(new List<string>(), _mockRemainingArgs.Object, "run", null);
85+
var apiUrl = $"http://{settings.Host}:9765/__lambda_test_tool_apigateway_health__";
86+
87+
// Act
88+
var runningTask = command.ExecuteAsync(context, settings, cancellationSource);
89+
var isApiRunning = await TestHelpers.WaitForApiToStartAsync(apiUrl);
90+
await cancellationSource.CancelAsync();
91+
92+
// Assert
93+
var result = await runningTask;
94+
Assert.Equal(CommandReturnCodes.Success, result);
95+
Assert.True(isApiRunning);
96+
}
6597
}

0 commit comments

Comments
 (0)