Skip to content

Commit

Permalink
perf: improve RuntimeSupport integration test performance
Browse files Browse the repository at this point in the history
  • Loading branch information
philasmar committed Nov 11, 2024
1 parent eec92d1 commit 9b3eda9
Show file tree
Hide file tree
Showing 10 changed files with 233 additions and 29 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<DefineConstants Condition="'$(SkipRuntimeSupportIntegTests)'=='true'">SKIP_RUNTIME_SUPPORT_INTEG_TESTS</DefineConstants>
</PropertyGroup>

Expand All @@ -23,13 +23,13 @@
<PackageReference Include="AWSSDK.IdentityManagement" Version="3.7.402.7" />
<PackageReference Include="AWSSDK.Lambda" Version="3.7.402.3" />
<PackageReference Include="AWSSDK.S3" Version="3.7.103.34" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit" Version="2.9.2" />

<!-- This needs to be referenced to allow testing via AssumeRole credentials -->
<PackageReference Include="AWSSDK.SecurityToken" Version="3.7.400.13" />
Expand All @@ -39,24 +39,4 @@
<ProjectReference Include="..\..\..\src\Amazon.Lambda.APIGatewayEvents\Amazon.Lambda.APIGatewayEvents.csproj" />
</ItemGroup>

<Target Name="PackageTestFunction" BeforeTargets="BeforeBuild">
<Exec Command="dotnet tool install -g Amazon.Lambda.Tools" IgnoreExitCode="true" />

<Exec WorkingDirectory="..\CustomRuntimeFunctionTest" Command="dotnet restore" />
<Exec WorkingDirectory="..\CustomRuntimeFunctionTest" Condition="'$(Architecture)'=='' or '$(Architecture)'=='x86'" Command="dotnet lambda package -c Release --framework net6.0" />
<Exec WorkingDirectory="..\CustomRuntimeFunctionTest" Condition="'$(Architecture)'=='arm64'" Command="dotnet lambda package -c Release --framework net6.0 --function-architecture arm64" />

<Exec WorkingDirectory="..\CustomRuntimeFunctionTest" Command="dotnet restore" />
<Exec WorkingDirectory="..\CustomRuntimeFunctionTest" Condition="'$(Architecture)'=='' or '$(Architecture)'=='x86'" Command="dotnet lambda package -c Release --framework net8.0" />
<Exec WorkingDirectory="..\CustomRuntimeFunctionTest" Condition="'$(Architecture)'=='arm64'" Command="dotnet lambda package -c Release --framework net8.0 --function-architecture arm64" />

<Exec WorkingDirectory="..\CustomRuntimeAspNetCoreMinimalApiTest" Command="dotnet restore" />
<Exec WorkingDirectory="..\CustomRuntimeAspNetCoreMinimalApiTest" Condition="'$(Architecture)'=='' or '$(Architecture)'=='x86'" Command="dotnet lambda package -c Release --framework net6.0" />
<Exec WorkingDirectory="..\CustomRuntimeAspNetCoreMinimalApiTest" Condition="'$(Architecture)'=='arm64'" Command="dotnet lambda package -c Release --framework net6.0 --function-architecture arm64" />

<Exec WorkingDirectory="..\CustomRuntimeAspNetCoreMinimalApiCustomSerializerTest" Command="dotnet restore" />
<Exec WorkingDirectory="..\CustomRuntimeAspNetCoreMinimalApiCustomSerializerTest" Condition="'$(Architecture)'=='' or '$(Architecture)'=='x86'" Command="dotnet lambda package -c Release --framework net6.0" />
<Exec WorkingDirectory="..\CustomRuntimeAspNetCoreMinimalApiCustomSerializerTest" Condition="'$(Architecture)'=='arm64'" Command="dotnet lambda package -c Release --framework net6.0 --function-architecture arm64" />
</Target>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

namespace Amazon.Lambda.RuntimeSupport.IntegrationTests
{
[Collection("Integration Tests")]
public class CustomRuntimeAspNetCoreMinimalApiCustomSerializerTest : BaseCustomRuntimeTest
{
public CustomRuntimeAspNetCoreMinimalApiCustomSerializerTest()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

namespace Amazon.Lambda.RuntimeSupport.IntegrationTests
{
[Collection("Integration Tests")]
public class CustomRuntimeAspNetCoreMinimalApiTest : BaseCustomRuntimeTest
{
public CustomRuntimeAspNetCoreMinimalApiTest()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

namespace Amazon.Lambda.RuntimeSupport.IntegrationTests
{
[Collection("Integration Tests")]
public class CustomRuntimeNET6Tests : CustomRuntimeTests
{
public CustomRuntimeNET6Tests()
Expand All @@ -49,6 +50,7 @@ public async Task TestAllNET6HandlersAsync()
}
}

[Collection("Integration Tests")]
public class CustomRuntimeNET8Tests : CustomRuntimeTests
{
public CustomRuntimeNET8Tests()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Xunit;

namespace Amazon.Lambda.RuntimeSupport.IntegrationTests.Helpers;

public static class CommandLineWrapper
{
public static async Task Run(string command, string arguments, string workingDirectory, CancellationToken cancellationToken = default)
{
var processStartInfo = new ProcessStartInfo
{
FileName = command,
Arguments = arguments,
WorkingDirectory = workingDirectory,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true,
};

using (var process = new Process { StartInfo = processStartInfo, EnableRaisingEvents = true })
{
var tcs = new TaskCompletionSource<bool>();

// Handle process exit event
process.Exited += (sender, args) =>
{
tcs.TrySetResult(true);
};

try
{
// Attach event handlers
process.OutputDataReceived += (sender, args) =>
{
if (!string.IsNullOrEmpty(args.Data))
{
Console.WriteLine(args.Data);
}
};

process.ErrorDataReceived += (sender, args) =>
{
if (!string.IsNullOrEmpty(args.Data))
{
Console.WriteLine(args.Data);
}
};

// Start the process
process.Start();

// Begin asynchronous read operations
process.BeginOutputReadLine();
process.BeginErrorReadLine();

// Wait for the process to exit or cancellation
var completedTask = await Task.WhenAny(tcs.Task, Task.Delay(Timeout.Infinite, cancellationToken));

if (completedTask == tcs.Task)
{
// Process exited normally
await tcs.Task; // Just to propagate any exceptions
}
else
{
// Cancellation requested
if (!process.HasExited)
{
process.Kill();
}
throw new OperationCanceledException(cancellationToken);
}
}
catch (Exception ex)
{
Console.WriteLine("Exception: " + ex);
if (!process.HasExited)
{
process.Kill();
}
}

Assert.True(process.ExitCode == 0, $"Command '{command} {arguments}' failed.");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
using System.IO;
using System.Runtime.InteropServices;
using System.Threading.Tasks;

namespace Amazon.Lambda.RuntimeSupport.IntegrationTests.Helpers;

public static class LambdaToolsHelper
{
private static readonly string FunctionArchitecture = RuntimeInformation.OSArchitecture == System.Runtime.InteropServices.Architecture.Arm64 ? "arm64" : "x86_64";

public static string GetTempTestAppDirectory(string workingDirectory, string testAppPath)
{
var customTestAppPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
Directory.CreateDirectory(customTestAppPath);

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

return Path.Combine(customTestAppPath, testAppPath);
}

public static async Task<string> InstallLambdaTools()
{
var customToolPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
Directory.CreateDirectory(customToolPath);
await CommandLineWrapper.Run(
"dotnet",
$"tool install Amazon.Lambda.Tools --tool-path {customToolPath}",
Directory.GetCurrentDirectory());
return customToolPath;
}

public static async Task LambdaPackage(string toolPath, string framework, string workingDirectory)
{
string lambdaToolPath = Path.Combine(toolPath, "dotnet-lambda");
await CommandLineWrapper.Run(
lambdaToolPath,
$"package -c Release --framework {framework} --function-architecture {FunctionArchitecture}",
workingDirectory);
}

public static void CleanUp(string toolPath)
{
if (!string.IsNullOrEmpty(toolPath) && Directory.Exists(toolPath))
{
Directory.Delete(toolPath, 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);
}

foreach (var subdir in dirs)
{
var tempPath = Path.Combine(destDirName, subdir.Name);
var subDir = new DirectoryInfo(subdir.FullName);
CopyDirectory(subDir, tempPath);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using Xunit;

namespace Amazon.Lambda.RuntimeSupport.IntegrationTests;

[CollectionDefinition("Integration Tests")]
public class IntegrationTestCollection : ICollectionFixture<IntegrationTestFixture>
{

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Amazon.Lambda.RuntimeSupport.IntegrationTests.Helpers;
using Xunit;

namespace Amazon.Lambda.RuntimeSupport.IntegrationTests;

public class IntegrationTestFixture : IAsyncLifetime
{
private readonly List<string> _tempPaths = new();

public async Task InitializeAsync()
{
var testAppPath = LambdaToolsHelper.GetTempTestAppDirectory(
"../../../../../../..",
"Libraries/test/Amazon.Lambda.RuntimeSupport.Tests/CustomRuntimeFunctionTest");
var toolPath = await LambdaToolsHelper.InstallLambdaTools();
_tempPaths.AddRange([testAppPath, toolPath] );
await LambdaToolsHelper.LambdaPackage(toolPath, "net6.0", testAppPath);
await LambdaToolsHelper.LambdaPackage(toolPath, "net8.0", testAppPath);

testAppPath = LambdaToolsHelper.GetTempTestAppDirectory(
"../../../../../../..",
"Libraries/test/Amazon.Lambda.RuntimeSupport.Tests/CustomRuntimeAspNetCoreMinimalApiTest");
toolPath = await LambdaToolsHelper.InstallLambdaTools();
_tempPaths.AddRange([testAppPath, toolPath] );
await LambdaToolsHelper.LambdaPackage(toolPath, "net6.0", testAppPath);

testAppPath = LambdaToolsHelper.GetTempTestAppDirectory(
"../../../../../../..",
"Libraries/test/Amazon.Lambda.RuntimeSupport.Tests/CustomRuntimeAspNetCoreMinimalApiCustomSerializerTest");
toolPath = await LambdaToolsHelper.InstallLambdaTools();
_tempPaths.AddRange([testAppPath, toolPath] );
await LambdaToolsHelper.LambdaPackage(toolPath, "net6.0", testAppPath);
}

public Task DisposeAsync()
{
foreach (var tempPath in _tempPaths)
{
LambdaToolsHelper.CleanUp(tempPath);
}

return Task.CompletedTask;
}
}
4 changes: 2 additions & 2 deletions buildtools/build.proj
Original file line number Diff line number Diff line change
Expand Up @@ -198,8 +198,8 @@
<Exec Command="dotnet test -c $(Configuration)" WorkingDirectory="..\Libraries\test\Amazon.Lambda.Annotations.SourceGenerators.Tests"/>
</Target>
<Target Name="run-integ-tests">
<Exec Command="dotnet test -c $(Configuration)" WorkingDirectory="..\Libraries\test\Amazon.Lambda.RuntimeSupport.Tests\Amazon.Lambda.RuntimeSupport.IntegrationTests"/>
<Exec Command="dotnet test -c $(Configuration)" WorkingDirectory="..\Libraries\test\TestServerlessApp.IntegrationTests"/>
<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"/>
</Target>
<Target Name="create-nuget-packages-cicd" DependsOnTargets="build-project-packages">
<Exec Command="$(PackCommand)" WorkingDirectory="..\Libraries\src\%(LibraryName.FileName)"/>
Expand Down
3 changes: 0 additions & 3 deletions buildtools/ci.buildspec.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@ phases:
commands:
# The tests need .NET 3.1, 6 and 8. .NET6 is installed by default. .NET8 is added in the runtime-versions. .NET 3.1 is installed manually.
- curl -sSL https://dot.net/v1/dotnet-install.sh | bash /dev/stdin --channel 3.1
# Mono is needed to run the unit tests on Linux
- curl https://download.mono-project.com/repo/centos8-stable.repo | tee /etc/yum.repos.d/mono-stable.repo
- dnf install -y mono-complete mono-devel
build:
commands:
- dotnet msbuild buildtools/build.proj /t:unit-tests /p:Cicd=true
Expand Down

0 comments on commit 9b3eda9

Please sign in to comment.