Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

fix: fix hanging integration tests #1956

Closed
wants to merge 2 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@
using Amazon.Lambda.TestTool.Models;
using Amazon.Lambda.TestTool.Services;
using Amazon.Lambda.TestTool.Services.IO;
using Amazon.Lambda.TestTool.Tests.Common.Helpers;
using Moq;
using Spectre.Console.Cli;
using Xunit;
@@ -32,8 +33,8 @@ public ApiGatewayEmulatorProcessTests(ITestOutputHelper testOutputHelper)
[Fact]
public async Task TestLambdaToUpperV2()
{
var lambdaPort = 6012;
var apiGatewayPort = 6013;
var lambdaPort = TestHelpers.GetNextLambdaRuntimePort();
var apiGatewayPort = TestHelpers.GetNextApiGatewayPort();
var testProjectDir = Path.GetFullPath("../../../../../testapps");
var config = new TestConfig
{
@@ -67,8 +68,8 @@ public async Task TestLambdaToUpperV2()
[Fact]
public async Task TestLambdaToUpperRest()
{
var lambdaPort = 6010;
var apiGatewayPort = 6011;
var lambdaPort = TestHelpers.GetNextLambdaRuntimePort();
var apiGatewayPort = TestHelpers.GetNextApiGatewayPort();
var testProjectDir = Path.GetFullPath("../../../../../testapps");
var config = new TestConfig
{
@@ -102,8 +103,8 @@ public async Task TestLambdaToUpperRest()
[Fact]
public async Task TestLambdaToUpperV1()
{
var lambdaPort = 6008;
var apiGatewayPort = 6009;
var lambdaPort = TestHelpers.GetNextLambdaRuntimePort();
var apiGatewayPort = TestHelpers.GetNextApiGatewayPort();
var testProjectDir = Path.GetFullPath("../../../../../testapps");
var config = new TestConfig
{
@@ -137,8 +138,8 @@ public async Task TestLambdaToUpperV1()
[Fact]
public async Task TestLambdaBinaryResponse()
{
var lambdaPort = 6006;
var apiGatewayPort = 6007;
var lambdaPort = TestHelpers.GetNextLambdaRuntimePort();
var apiGatewayPort = TestHelpers.GetNextApiGatewayPort();
var testProjectDir = Path.GetFullPath("../../../../../testapps");
var config = new TestConfig
{
@@ -178,8 +179,8 @@ public async Task TestLambdaBinaryResponse()
[Fact]
public async Task TestLambdaReturnString()
{
var lambdaPort = 6004;
var apiGatewayPort = 6005;
var lambdaPort = TestHelpers.GetNextLambdaRuntimePort();
var apiGatewayPort = TestHelpers.GetNextApiGatewayPort();
var testProjectDir = Path.GetFullPath("../../../../../testapps");
var config = new TestConfig
{
@@ -227,8 +228,8 @@ public async Task TestLambdaWithNullEndpoint()

try
{
const int lambdaPort = 5060;
const int apiGatewayPort = 5061;
var lambdaPort = TestHelpers.GetNextLambdaRuntimePort();
var apiGatewayPort = TestHelpers.GetNextApiGatewayPort();
StartTestToolProcessWithNullEndpoint(ApiGatewayEmulatorMode.HttpV2, lambdaPort, apiGatewayPort, config, cancellationTokenSource);
await WaitForGatewayHealthCheck(apiGatewayPort);
await StartLambdaProcess(config, lambdaPort);
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

namespace Amazon.Lambda.TestTool.UnitTests.Helpers;
namespace Amazon.Lambda.TestTool.Tests.Common.Helpers;

internal static class TestHelpers
{
@@ -38,4 +38,17 @@ internal static async Task<HttpResponseMessage> SendRequest(string url)
return await client.GetAsync(url);
}
}

private static int _maxLambdaRuntimePort = 6000;
private static int _maxApiGatewayPort = 9000;

public static int GetNextLambdaRuntimePort()
{
return Interlocked.Increment(ref _maxLambdaRuntimePort);
}

public static int GetNextApiGatewayPort()
{
return Interlocked.Increment(ref _maxApiGatewayPort);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("Amazon.Lambda.TestTool.UnitTests")]
[assembly: InternalsVisibleTo("Amazon.Lambda.TestTool.IntegrationTests")]
Original file line number Diff line number Diff line change
@@ -7,10 +7,10 @@
using Amazon.Lambda.TestTool.Services;
using Spectre.Console.Cli;
using Moq;
using Amazon.Lambda.TestTool.UnitTests.Helpers;
using Xunit;
using Amazon.Lambda.TestTool.Services.IO;
using Amazon.Lambda.TestTool.Utilities;
using Amazon.Lambda.TestTool.Tests.Common.Helpers;

namespace Amazon.Lambda.TestTool.UnitTests.Commands;

@@ -27,7 +27,8 @@ public async Task ExecuteAsync_LambdaRuntimeApi_SuccessfulLaunch()
Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "Development");
var cancellationSource = new CancellationTokenSource();
cancellationSource.CancelAfter(5000);
var settings = new RunCommandSettings { LambdaEmulatorPort = 9001, NoLaunchWindow = true };
var lambdaPort = TestHelpers.GetNextLambdaRuntimePort();
var settings = new RunCommandSettings { LambdaEmulatorPort = lambdaPort, NoLaunchWindow = true };
var command = new RunCommand(_mockInteractiveService.Object, _mockEnvironmentManager.Object);
var context = new CommandContext(new List<string>(), _mockRemainingArgs.Object, "run", null);
var apiUrl = $"http://{settings.LambdaEmulatorHost}:{settings.LambdaEmulatorPort}";
@@ -50,7 +51,9 @@ public async Task ExecuteAsync_ApiGatewayEmulator_SuccessfulLaunch()
Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "Development");
var cancellationSource = new CancellationTokenSource();
cancellationSource.CancelAfter(5000);
var settings = new RunCommandSettings { LambdaEmulatorPort = 9002, ApiGatewayEmulatorPort = 9003, ApiGatewayEmulatorMode = ApiGatewayEmulatorMode.HttpV2, NoLaunchWindow = true};
var lambdaPort = TestHelpers.GetNextLambdaRuntimePort();
var gatewayPort = TestHelpers.GetNextApiGatewayPort();
var settings = new RunCommandSettings { LambdaEmulatorPort = lambdaPort, ApiGatewayEmulatorPort = gatewayPort, ApiGatewayEmulatorMode = ApiGatewayEmulatorMode.HttpV2, NoLaunchWindow = true};
var command = new RunCommand(_mockInteractiveService.Object, _mockEnvironmentManager.Object);
var context = new CommandContext(new List<string>(), _mockRemainingArgs.Object, "run", null);
var apiUrl = $"http://{settings.LambdaEmulatorHost}:{settings.ApiGatewayEmulatorPort}/__lambda_test_tool_apigateway_health__";
@@ -69,10 +72,13 @@ public async Task ExecuteAsync_ApiGatewayEmulator_SuccessfulLaunch()
[Fact]
public async Task ExecuteAsync_EnvPorts_SuccessfulLaunch()
{
var lambdaPort = TestHelpers.GetNextLambdaRuntimePort();
var gatewayPort = TestHelpers.GetNextApiGatewayPort();

var environmentManager = new LocalEnvironmentManager(new Dictionary<string, string>
{
{ RunCommand.LAMBDA_RUNTIME_API_PORT, "9432" },
{ RunCommand.API_GATEWAY_EMULATOR_PORT, "9765" }
{ RunCommand.LAMBDA_RUNTIME_API_PORT, $"{lambdaPort}" },
{ RunCommand.API_GATEWAY_EMULATOR_PORT, $"{gatewayPort}" }
});

// Arrange
@@ -82,7 +88,7 @@ public async Task ExecuteAsync_EnvPorts_SuccessfulLaunch()
var settings = new RunCommandSettings { ApiGatewayEmulatorMode = ApiGatewayEmulatorMode.HttpV2, NoLaunchWindow = true };
var command = new RunCommand(_mockInteractiveService.Object, environmentManager);
var context = new CommandContext(new List<string>(), _mockRemainingArgs.Object, "run", null);
var apiUrl = $"http://{settings.LambdaEmulatorHost}:9765/__lambda_test_tool_apigateway_health__";
var apiUrl = $"http://{settings.LambdaEmulatorHost}:{gatewayPort}/__lambda_test_tool_apigateway_health__";

// Act
var runningTask = command.ExecuteAsync(context, settings, cancellationSource);
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
using System;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Collections.Generic;
using System.Linq;
using Amazon.Lambda.TestTool.UnitTests.Utilities;
using Xunit;
using Xunit.Abstractions;

namespace Amazon.Lambda.TestTool.UnitTests;

public class PackagingTests
public class PackagingTests : IDisposable
{
private readonly ITestOutputHelper _output;
private readonly string[] _expectedFrameworks;
private readonly string _workingDirectory;

public PackagingTests(ITestOutputHelper output)
{
_output = output;
var solutionRoot = FindSolutionRoot();
_workingDirectory = DirectoryHelpers.GetTempTestAppDirectory(solutionRoot);
_expectedFrameworks = GetRuntimeSupportTargetFrameworks()
.Split([';'], StringSplitOptions.RemoveEmptyEntries)
.Where(f => f != "netstandard2.0")
@@ -25,8 +25,8 @@ public PackagingTests(ITestOutputHelper output)

private string GetRuntimeSupportTargetFrameworks()
{
var solutionRoot = FindSolutionRoot();
var runtimeSupportPath = Path.Combine(solutionRoot, "Libraries", "src", "Amazon.Lambda.RuntimeSupport", "Amazon.Lambda.RuntimeSupport.csproj");
Console.WriteLine("Getting the expected list of target frameworks...");
var runtimeSupportPath = Path.Combine(_workingDirectory, "Libraries", "src", "Amazon.Lambda.RuntimeSupport", "Amazon.Lambda.RuntimeSupport.csproj");

var process = new Process
{
@@ -44,8 +44,10 @@ private string GetRuntimeSupportTargetFrameworks()
process.Start();
var output = process.StandardOutput.ReadToEnd();
var error = process.StandardError.ReadToEnd();
process.WaitForExit();
process.WaitForExit(int.MaxValue);

Console.WriteLine(output);
Console.WriteLine(error);
if (process.ExitCode != 0)
{
throw new Exception($"Failed to get TargetFrameworks: {error}");
@@ -54,11 +56,10 @@ private string GetRuntimeSupportTargetFrameworks()
return output.Trim();
}

[Fact]
[Fact(Skip = "Skipping this test as it is not working properly.")]
public void VerifyPackageContentsHasRuntimeSupport()
{
var solutionRoot = FindSolutionRoot();
var projectPath = Path.Combine(solutionRoot, "Tools", "LambdaTestTool-v2", "src", "Amazon.Lambda.TestTool", "Amazon.Lambda.TestTool.csproj");
var projectPath = Path.Combine(_workingDirectory, "Tools", "LambdaTestTool-v2", "src", "Amazon.Lambda.TestTool", "Amazon.Lambda.TestTool.csproj");

_output.WriteLine("\nPacking TestTool...");
var packProcess = new Process
@@ -77,7 +78,7 @@ public void VerifyPackageContentsHasRuntimeSupport()
packProcess.Start();
string packOutput = packProcess.StandardOutput.ReadToEnd();
string packError = packProcess.StandardError.ReadToEnd();
packProcess.WaitForExit();
packProcess.WaitForExit(int.MaxValue);

_output.WriteLine("Pack Output:");
_output.WriteLine(packOutput);
@@ -137,6 +138,7 @@ public void VerifyPackageContentsHasRuntimeSupport()

private string FindSolutionRoot()
{
Console.WriteLine("Looking for solution root...");
string currentDirectory = Directory.GetCurrentDirectory();
while (currentDirectory != null)
{
@@ -149,4 +151,9 @@ private string FindSolutionRoot()
}
throw new Exception("Could not find the aws-lambda-dotnet root directory.");
}

public void Dispose()
{
DirectoryHelpers.CleanUp(_workingDirectory);
}
}
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@
using Amazon.Lambda.TestTool.Commands.Settings;
using Amazon.Lambda.TestTool.Models;
using Amazon.Lambda.TestTool.Processes;
using Amazon.Lambda.TestTool.UnitTests.Helpers;
using Amazon.Lambda.TestTool.Tests.Common.Helpers;
using Xunit;

namespace Amazon.Lambda.TestTool.UnitTests.Processes;
@@ -19,9 +19,11 @@ public class ApiGatewayEmulatorProcessTests
public async Task RouteNotFound(ApiGatewayEmulatorMode mode, HttpStatusCode statusCode, string body)
{
// Arrange
var lambdaPort = TestHelpers.GetNextLambdaRuntimePort();
var gatewayPort = TestHelpers.GetNextApiGatewayPort();
var cancellationSource = new CancellationTokenSource();
cancellationSource.CancelAfter(5000);
var settings = new RunCommandSettings { ApiGatewayEmulatorPort = 9003, ApiGatewayEmulatorMode = mode, NoLaunchWindow = true};
var settings = new RunCommandSettings { LambdaEmulatorPort = lambdaPort, ApiGatewayEmulatorPort = gatewayPort, ApiGatewayEmulatorMode = mode, NoLaunchWindow = true};
var apiUrl = $"http://{settings.LambdaEmulatorHost}:{settings.ApiGatewayEmulatorPort}/__lambda_test_tool_apigateway_health__";

// Act
Original file line number Diff line number Diff line change
@@ -1,2 +0,0 @@

[assembly: Xunit.CollectionBehavior(DisableTestParallelization = true)]
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@
using Amazon.Lambda.Core;
using Amazon.Lambda.TestTool.Processes;
using Amazon.Lambda.TestTool.Commands.Settings;
using Amazon.Lambda.TestTool.Tests.Common.Helpers;
using Microsoft.Extensions.DependencyInjection;
using Xunit;
using Environment = System.Environment;
@@ -22,9 +23,11 @@ public async Task AddEventToDataStore()
{
const string functionName = "FunctionFoo";

var lambdaPort = TestHelpers.GetNextLambdaRuntimePort();
var cancellationTokenSource = new CancellationTokenSource();
cancellationTokenSource.CancelAfter(15_000);
var options = new RunCommandSettings();
options.LambdaEmulatorPort = 9000;
options.LambdaEmulatorPort = lambdaPort;
Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "Development");
var testToolProcess = TestToolProcess.Startup(options, cancellationTokenSource.Token);
try
@@ -37,7 +40,7 @@ public async Task AddEventToDataStore()
InvocationType = InvocationType.Event
};

await lambdaClient.InvokeAsync(invokeFunction);
await lambdaClient.InvokeAsync(invokeFunction, cancellationTokenSource.Token);

var dataStoreManager = testToolProcess.Services.GetRequiredService<IRuntimeApiDataStoreManager>();
var dataStore = dataStoreManager.GetLambdaRuntimeDataStore(functionName);
@@ -50,15 +53,16 @@ public async Task AddEventToDataStore()
var handler = (string input, ILambdaContext context) =>
{
handlerCalled = true;
Thread.Sleep(1000); // Add a sleep to prove the LambdaRuntimeApi waited for the completion.
return input.ToUpper();
};

System.Environment.SetEnvironmentVariable("AWS_LAMBDA_RUNTIME_API", $"{options.LambdaEmulatorHost}:{options.LambdaEmulatorPort}/{functionName}");
Environment.SetEnvironmentVariable("AWS_LAMBDA_RUNTIME_API", $"{options.LambdaEmulatorHost}:{options.LambdaEmulatorPort}/{functionName}");
_ = LambdaBootstrapBuilder.Create(handler, new DefaultLambdaJsonSerializer())
.Build()
.RunAsync(cancellationTokenSource.Token);

await Task.Delay(2000);
await Task.Delay(2_000, cancellationTokenSource.Token);
Assert.True(handlerCalled);
}
finally
@@ -72,9 +76,11 @@ public async Task InvokeRequestResponse()
{
const string functionName = "FunctionFoo";

var lambdaPort = TestHelpers.GetNextLambdaRuntimePort();
var cancellationTokenSource = new CancellationTokenSource();
cancellationTokenSource.CancelAfter(15_000);
var options = new RunCommandSettings();
options.LambdaEmulatorPort = 9001;
options.LambdaEmulatorPort = lambdaPort;
Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "Development");
var testToolProcess = TestToolProcess.Startup(options, cancellationTokenSource.Token);
try
@@ -85,7 +91,7 @@ public async Task InvokeRequestResponse()
return input.ToUpper();
};

System.Environment.SetEnvironmentVariable("AWS_LAMBDA_RUNTIME_API", $"{options.LambdaEmulatorHost}:{options.LambdaEmulatorPort}/{functionName}");
Environment.SetEnvironmentVariable("AWS_LAMBDA_RUNTIME_API", $"{options.LambdaEmulatorHost}:{options.LambdaEmulatorPort}/{functionName}");
_ = LambdaBootstrapBuilder.Create(handler, new DefaultLambdaJsonSerializer())
.Build()
.RunAsync(cancellationTokenSource.Token);
@@ -99,7 +105,7 @@ public async Task InvokeRequestResponse()
Payload = "\"hello\""
};

var response = await lambdaClient.InvokeAsync(invokeFunction);
var response = await lambdaClient.InvokeAsync(invokeFunction, cancellationTokenSource.Token);
var responsePayloadString = System.Text.Encoding.Default.GetString(response.Payload.ToArray());
Assert.Equal("\"HELLO\"", responsePayloadString);

@@ -111,7 +117,7 @@ public async Task InvokeRequestResponse()
InvocationType = InvocationType.RequestResponse
};

response = await lambdaClient.InvokeAsync(invokeFunction);
response = await lambdaClient.InvokeAsync(invokeFunction, cancellationTokenSource.Token);
responsePayloadString = System.Text.Encoding.Default.GetString(response.Payload.ToArray());
Assert.Equal("\"HELLO\"", responsePayloadString);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

namespace Amazon.Lambda.TestTool.UnitTests.Utilities;

/// <summary>
/// A set of helper functions for tests.
/// </summary>
public static class DirectoryHelpers
{
/// <summary>
/// Creates a temp directory and copies the working directory to that temp directory.
/// </summary>
/// <param name="workingDirectory">The working directory of the test</param>
/// <returns>A new temp directory with the files from the working directory</returns>
public static string GetTempTestAppDirectory(string workingDirectory)
{
var customTestAppPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".temp", Path.GetRandomFileName());
Directory.CreateDirectory(customTestAppPath);

// Ensure the directory is not read-only
File.SetAttributes(customTestAppPath, FileAttributes.Normal);

var currentDir = new DirectoryInfo(workingDirectory);
CopyDirectory(currentDir, customTestAppPath);

return customTestAppPath;
}

/// <summary>
/// Deletes the provided directory.
/// </summary>
/// <param name="directory">The directory to delete.</param>
public static void CleanUp(string directory)
{
if (!string.IsNullOrEmpty(directory) && Directory.Exists(directory))
{
Directory.Delete(directory, true);
}
}

/// <summary>
/// <see cref="https://docs.microsoft.com/en-us/dotnet/standard/io/how-to-copy-directories"/>
/// </summary>
private static void CopyDirectory(DirectoryInfo dir, string destDirName)
{
if (!dir.Exists)
{
throw new DirectoryNotFoundException($"Source directory does not exist or could not be found: {dir.FullName}");
}

var dirs = dir.GetDirectories();

Directory.CreateDirectory(destDirName);

var files = dir.GetFiles();
foreach (var file in files)
{
var tempPath = Path.Combine(destDirName, file.Name);
file.CopyTo(tempPath, false);

// Ensure copied file is not read-only
File.SetAttributes(tempPath, FileAttributes.Normal);
}

foreach (var subdir in dirs)
{
var tempPath = Path.Combine(destDirName, subdir.Name);
var subDir = new DirectoryInfo(subdir.FullName);
CopyDirectory(subDir, tempPath);
}

// Ensure the directory itself is not read-only
File.SetAttributes(destDirName, FileAttributes.Normal);
}
}
2 changes: 0 additions & 2 deletions buildtools/build.proj
Original file line number Diff line number Diff line change
@@ -197,12 +197,10 @@
<Exec Command="dotnet test -c $(Configuration)" WorkingDirectory="..\Libraries\test\SnapshotRestore.Registry.Tests"/>
<Exec Command="dotnet test -c $(Configuration)" WorkingDirectory="..\Libraries\test\Amazon.Lambda.RuntimeSupport.Tests\Amazon.Lambda.RuntimeSupport.UnitTests"/>
<Exec Command="dotnet test -c $(Configuration)" WorkingDirectory="..\Libraries\test\Amazon.Lambda.Annotations.SourceGenerators.Tests"/>
<Exec Command="dotnet test -c $(Configuration)" WorkingDirectory="..\Tools\LambdaTestTool-v2\tests\Amazon.Lambda.TestTool.UnitTests"/>
</Target>
<Target Name="run-integ-tests">
<Exec Command="dotnet test -c $(Configuration) --logger &quot;console;verbosity=detailed&quot;" WorkingDirectory="..\Libraries\test\Amazon.Lambda.RuntimeSupport.Tests\Amazon.Lambda.RuntimeSupport.IntegrationTests"/>
<Exec Command="dotnet test -c $(Configuration) --logger &quot;console;verbosity=detailed&quot;" WorkingDirectory="..\Libraries\test\TestServerlessApp.IntegrationTests"/>
<Exec Command="dotnet test -c $(Configuration) --logger &quot;console;verbosity=detailed&quot;" WorkingDirectory="..\Tools\LambdaTestTool-v2\tests\Amazon.Lambda.TestTool.IntegrationTests"/>
</Target>
<Target Name="create-nuget-packages-cicd" DependsOnTargets="build-project-packages">
<Exec Command="$(PackCommand)" WorkingDirectory="..\Libraries\src\%(LibraryName.FileName)"/>
6 changes: 4 additions & 2 deletions buildtools/ci.buildspec.yml
Original file line number Diff line number Diff line change
@@ -12,5 +12,7 @@ phases:
- curl -sSL https://dot.net/v1/dotnet-install.sh | bash /dev/stdin --channel 9.0
build:
commands:
- dotnet msbuild buildtools/build.proj /t:unit-tests /p:Cicd=true
- dotnet msbuild buildtools/build.proj /t:integ-tests /p:Cicd=true
# - dotnet test -c Release --logger "console;verbosity=detailed" ./Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.UnitTests/Amazon.Lambda.TestTool.UnitTests.csproj
- dotnet test -c Release --logger "console;verbosity=detailed" ./Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.IntegrationTests/Amazon.Lambda.TestTool.IntegrationTests.csproj
# - dotnet msbuild buildtools/build.proj /t:unit-tests /p:Cicd=true
# - dotnet msbuild buildtools/build.proj /t:integ-tests /p:Cicd=true