Skip to content

Commit 9b3eda9

Browse files
committed
perf: improve RuntimeSupport integration test performance
1 parent eec92d1 commit 9b3eda9

10 files changed

+233
-29
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFramework>net6.0</TargetFramework>
4+
<TargetFramework>net8.0</TargetFramework>
55
<DefineConstants Condition="'$(SkipRuntimeSupportIntegTests)'=='true'">SKIP_RUNTIME_SUPPORT_INTEG_TESTS</DefineConstants>
66
</PropertyGroup>
77

@@ -23,13 +23,13 @@
2323
<PackageReference Include="AWSSDK.IdentityManagement" Version="3.7.402.7" />
2424
<PackageReference Include="AWSSDK.Lambda" Version="3.7.402.3" />
2525
<PackageReference Include="AWSSDK.S3" Version="3.7.103.34" />
26-
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
26+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
2727
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
28-
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
28+
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
2929
<PrivateAssets>all</PrivateAssets>
3030
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
3131
</PackageReference>
32-
<PackageReference Include="xunit" Version="2.4.2" />
32+
<PackageReference Include="xunit" Version="2.9.2" />
3333

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

42-
<Target Name="PackageTestFunction" BeforeTargets="BeforeBuild">
43-
<Exec Command="dotnet tool install -g Amazon.Lambda.Tools" IgnoreExitCode="true" />
44-
45-
<Exec WorkingDirectory="..\CustomRuntimeFunctionTest" Command="dotnet restore" />
46-
<Exec WorkingDirectory="..\CustomRuntimeFunctionTest" Condition="'$(Architecture)'=='' or '$(Architecture)'=='x86'" Command="dotnet lambda package -c Release --framework net6.0" />
47-
<Exec WorkingDirectory="..\CustomRuntimeFunctionTest" Condition="'$(Architecture)'=='arm64'" Command="dotnet lambda package -c Release --framework net6.0 --function-architecture arm64" />
48-
49-
<Exec WorkingDirectory="..\CustomRuntimeFunctionTest" Command="dotnet restore" />
50-
<Exec WorkingDirectory="..\CustomRuntimeFunctionTest" Condition="'$(Architecture)'=='' or '$(Architecture)'=='x86'" Command="dotnet lambda package -c Release --framework net8.0" />
51-
<Exec WorkingDirectory="..\CustomRuntimeFunctionTest" Condition="'$(Architecture)'=='arm64'" Command="dotnet lambda package -c Release --framework net8.0 --function-architecture arm64" />
52-
53-
<Exec WorkingDirectory="..\CustomRuntimeAspNetCoreMinimalApiTest" Command="dotnet restore" />
54-
<Exec WorkingDirectory="..\CustomRuntimeAspNetCoreMinimalApiTest" Condition="'$(Architecture)'=='' or '$(Architecture)'=='x86'" Command="dotnet lambda package -c Release --framework net6.0" />
55-
<Exec WorkingDirectory="..\CustomRuntimeAspNetCoreMinimalApiTest" Condition="'$(Architecture)'=='arm64'" Command="dotnet lambda package -c Release --framework net6.0 --function-architecture arm64" />
56-
57-
<Exec WorkingDirectory="..\CustomRuntimeAspNetCoreMinimalApiCustomSerializerTest" Command="dotnet restore" />
58-
<Exec WorkingDirectory="..\CustomRuntimeAspNetCoreMinimalApiCustomSerializerTest" Condition="'$(Architecture)'=='' or '$(Architecture)'=='x86'" Command="dotnet lambda package -c Release --framework net6.0" />
59-
<Exec WorkingDirectory="..\CustomRuntimeAspNetCoreMinimalApiCustomSerializerTest" Condition="'$(Architecture)'=='arm64'" Command="dotnet lambda package -c Release --framework net6.0 --function-architecture arm64" />
60-
</Target>
61-
6242
</Project>

Libraries/test/Amazon.Lambda.RuntimeSupport.Tests/Amazon.Lambda.RuntimeSupport.IntegrationTests/CustomRuntimeAspNetCoreMinimalApiCustomSerializerTest.cs

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
namespace Amazon.Lambda.RuntimeSupport.IntegrationTests
2020
{
21+
[Collection("Integration Tests")]
2122
public class CustomRuntimeAspNetCoreMinimalApiCustomSerializerTest : BaseCustomRuntimeTest
2223
{
2324
public CustomRuntimeAspNetCoreMinimalApiCustomSerializerTest()

Libraries/test/Amazon.Lambda.RuntimeSupport.Tests/Amazon.Lambda.RuntimeSupport.IntegrationTests/CustomRuntimeAspNetCoreMinimalApiTest.cs

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
namespace Amazon.Lambda.RuntimeSupport.IntegrationTests
2020
{
21+
[Collection("Integration Tests")]
2122
public class CustomRuntimeAspNetCoreMinimalApiTest : BaseCustomRuntimeTest
2223
{
2324
public CustomRuntimeAspNetCoreMinimalApiTest()

Libraries/test/Amazon.Lambda.RuntimeSupport.Tests/Amazon.Lambda.RuntimeSupport.IntegrationTests/CustomRuntimeTests.cs

+2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131

3232
namespace Amazon.Lambda.RuntimeSupport.IntegrationTests
3333
{
34+
[Collection("Integration Tests")]
3435
public class CustomRuntimeNET6Tests : CustomRuntimeTests
3536
{
3637
public CustomRuntimeNET6Tests()
@@ -49,6 +50,7 @@ public async Task TestAllNET6HandlersAsync()
4950
}
5051
}
5152

53+
[Collection("Integration Tests")]
5254
public class CustomRuntimeNET8Tests : CustomRuntimeTests
5355
{
5456
public CustomRuntimeNET8Tests()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
using System;
2+
using System.Diagnostics;
3+
using System.Threading;
4+
using System.Threading.Tasks;
5+
using Xunit;
6+
7+
namespace Amazon.Lambda.RuntimeSupport.IntegrationTests.Helpers;
8+
9+
public static class CommandLineWrapper
10+
{
11+
public static async Task Run(string command, string arguments, string workingDirectory, CancellationToken cancellationToken = default)
12+
{
13+
var processStartInfo = new ProcessStartInfo
14+
{
15+
FileName = command,
16+
Arguments = arguments,
17+
WorkingDirectory = workingDirectory,
18+
RedirectStandardOutput = true,
19+
RedirectStandardError = true,
20+
UseShellExecute = false,
21+
CreateNoWindow = true,
22+
};
23+
24+
using (var process = new Process { StartInfo = processStartInfo, EnableRaisingEvents = true })
25+
{
26+
var tcs = new TaskCompletionSource<bool>();
27+
28+
// Handle process exit event
29+
process.Exited += (sender, args) =>
30+
{
31+
tcs.TrySetResult(true);
32+
};
33+
34+
try
35+
{
36+
// Attach event handlers
37+
process.OutputDataReceived += (sender, args) =>
38+
{
39+
if (!string.IsNullOrEmpty(args.Data))
40+
{
41+
Console.WriteLine(args.Data);
42+
}
43+
};
44+
45+
process.ErrorDataReceived += (sender, args) =>
46+
{
47+
if (!string.IsNullOrEmpty(args.Data))
48+
{
49+
Console.WriteLine(args.Data);
50+
}
51+
};
52+
53+
// Start the process
54+
process.Start();
55+
56+
// Begin asynchronous read operations
57+
process.BeginOutputReadLine();
58+
process.BeginErrorReadLine();
59+
60+
// Wait for the process to exit or cancellation
61+
var completedTask = await Task.WhenAny(tcs.Task, Task.Delay(Timeout.Infinite, cancellationToken));
62+
63+
if (completedTask == tcs.Task)
64+
{
65+
// Process exited normally
66+
await tcs.Task; // Just to propagate any exceptions
67+
}
68+
else
69+
{
70+
// Cancellation requested
71+
if (!process.HasExited)
72+
{
73+
process.Kill();
74+
}
75+
throw new OperationCanceledException(cancellationToken);
76+
}
77+
}
78+
catch (Exception ex)
79+
{
80+
Console.WriteLine("Exception: " + ex);
81+
if (!process.HasExited)
82+
{
83+
process.Kill();
84+
}
85+
}
86+
87+
Assert.True(process.ExitCode == 0, $"Command '{command} {arguments}' failed.");
88+
}
89+
}
90+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
using System.IO;
2+
using System.Runtime.InteropServices;
3+
using System.Threading.Tasks;
4+
5+
namespace Amazon.Lambda.RuntimeSupport.IntegrationTests.Helpers;
6+
7+
public static class LambdaToolsHelper
8+
{
9+
private static readonly string FunctionArchitecture = RuntimeInformation.OSArchitecture == System.Runtime.InteropServices.Architecture.Arm64 ? "arm64" : "x86_64";
10+
11+
public static string GetTempTestAppDirectory(string workingDirectory, string testAppPath)
12+
{
13+
var customTestAppPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
14+
Directory.CreateDirectory(customTestAppPath);
15+
16+
var currentDir = new DirectoryInfo(workingDirectory);
17+
CopyDirectory(currentDir, customTestAppPath);
18+
19+
return Path.Combine(customTestAppPath, testAppPath);
20+
}
21+
22+
public static async Task<string> InstallLambdaTools()
23+
{
24+
var customToolPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
25+
Directory.CreateDirectory(customToolPath);
26+
await CommandLineWrapper.Run(
27+
"dotnet",
28+
$"tool install Amazon.Lambda.Tools --tool-path {customToolPath}",
29+
Directory.GetCurrentDirectory());
30+
return customToolPath;
31+
}
32+
33+
public static async Task LambdaPackage(string toolPath, string framework, string workingDirectory)
34+
{
35+
string lambdaToolPath = Path.Combine(toolPath, "dotnet-lambda");
36+
await CommandLineWrapper.Run(
37+
lambdaToolPath,
38+
$"package -c Release --framework {framework} --function-architecture {FunctionArchitecture}",
39+
workingDirectory);
40+
}
41+
42+
public static void CleanUp(string toolPath)
43+
{
44+
if (!string.IsNullOrEmpty(toolPath) && Directory.Exists(toolPath))
45+
{
46+
Directory.Delete(toolPath, true);
47+
}
48+
}
49+
50+
/// <summary>
51+
/// <see cref="https://docs.microsoft.com/en-us/dotnet/standard/io/how-to-copy-directories"/>
52+
/// </summary>
53+
private static void CopyDirectory(DirectoryInfo dir, string destDirName)
54+
{
55+
if (!dir.Exists)
56+
{
57+
throw new DirectoryNotFoundException($"Source directory does not exist or could not be found: {dir.FullName}");
58+
}
59+
60+
var dirs = dir.GetDirectories();
61+
62+
Directory.CreateDirectory(destDirName);
63+
64+
var files = dir.GetFiles();
65+
foreach (var file in files)
66+
{
67+
var tempPath = Path.Combine(destDirName, file.Name);
68+
file.CopyTo(tempPath, false);
69+
}
70+
71+
foreach (var subdir in dirs)
72+
{
73+
var tempPath = Path.Combine(destDirName, subdir.Name);
74+
var subDir = new DirectoryInfo(subdir.FullName);
75+
CopyDirectory(subDir, tempPath);
76+
}
77+
}
78+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using Xunit;
2+
3+
namespace Amazon.Lambda.RuntimeSupport.IntegrationTests;
4+
5+
[CollectionDefinition("Integration Tests")]
6+
public class IntegrationTestCollection : ICollectionFixture<IntegrationTestFixture>
7+
{
8+
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
using System.Collections.Generic;
2+
using System.Threading.Tasks;
3+
using Amazon.Lambda.RuntimeSupport.IntegrationTests.Helpers;
4+
using Xunit;
5+
6+
namespace Amazon.Lambda.RuntimeSupport.IntegrationTests;
7+
8+
public class IntegrationTestFixture : IAsyncLifetime
9+
{
10+
private readonly List<string> _tempPaths = new();
11+
12+
public async Task InitializeAsync()
13+
{
14+
var testAppPath = LambdaToolsHelper.GetTempTestAppDirectory(
15+
"../../../../../../..",
16+
"Libraries/test/Amazon.Lambda.RuntimeSupport.Tests/CustomRuntimeFunctionTest");
17+
var toolPath = await LambdaToolsHelper.InstallLambdaTools();
18+
_tempPaths.AddRange([testAppPath, toolPath] );
19+
await LambdaToolsHelper.LambdaPackage(toolPath, "net6.0", testAppPath);
20+
await LambdaToolsHelper.LambdaPackage(toolPath, "net8.0", testAppPath);
21+
22+
testAppPath = LambdaToolsHelper.GetTempTestAppDirectory(
23+
"../../../../../../..",
24+
"Libraries/test/Amazon.Lambda.RuntimeSupport.Tests/CustomRuntimeAspNetCoreMinimalApiTest");
25+
toolPath = await LambdaToolsHelper.InstallLambdaTools();
26+
_tempPaths.AddRange([testAppPath, toolPath] );
27+
await LambdaToolsHelper.LambdaPackage(toolPath, "net6.0", testAppPath);
28+
29+
testAppPath = LambdaToolsHelper.GetTempTestAppDirectory(
30+
"../../../../../../..",
31+
"Libraries/test/Amazon.Lambda.RuntimeSupport.Tests/CustomRuntimeAspNetCoreMinimalApiCustomSerializerTest");
32+
toolPath = await LambdaToolsHelper.InstallLambdaTools();
33+
_tempPaths.AddRange([testAppPath, toolPath] );
34+
await LambdaToolsHelper.LambdaPackage(toolPath, "net6.0", testAppPath);
35+
}
36+
37+
public Task DisposeAsync()
38+
{
39+
foreach (var tempPath in _tempPaths)
40+
{
41+
LambdaToolsHelper.CleanUp(tempPath);
42+
}
43+
44+
return Task.CompletedTask;
45+
}
46+
}

buildtools/build.proj

+2-2
Original file line numberDiff line numberDiff line change
@@ -198,8 +198,8 @@
198198
<Exec Command="dotnet test -c $(Configuration)" WorkingDirectory="..\Libraries\test\Amazon.Lambda.Annotations.SourceGenerators.Tests"/>
199199
</Target>
200200
<Target Name="run-integ-tests">
201-
<Exec Command="dotnet test -c $(Configuration)" WorkingDirectory="..\Libraries\test\Amazon.Lambda.RuntimeSupport.Tests\Amazon.Lambda.RuntimeSupport.IntegrationTests"/>
202-
<Exec Command="dotnet test -c $(Configuration)" WorkingDirectory="..\Libraries\test\TestServerlessApp.IntegrationTests"/>
201+
<Exec Command="dotnet test -c $(Configuration) --logger &quot;console;verbosity=detailed&quot;" WorkingDirectory="..\Libraries\test\Amazon.Lambda.RuntimeSupport.Tests\Amazon.Lambda.RuntimeSupport.IntegrationTests"/>
202+
<Exec Command="dotnet test -c $(Configuration) --logger &quot;console;verbosity=detailed&quot;" WorkingDirectory="..\Libraries\test\TestServerlessApp.IntegrationTests"/>
203203
</Target>
204204
<Target Name="create-nuget-packages-cicd" DependsOnTargets="build-project-packages">
205205
<Exec Command="$(PackCommand)" WorkingDirectory="..\Libraries\src\%(LibraryName.FileName)"/>

buildtools/ci.buildspec.yml

-3
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,6 @@ phases:
77
commands:
88
# 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.
99
- curl -sSL https://dot.net/v1/dotnet-install.sh | bash /dev/stdin --channel 3.1
10-
# Mono is needed to run the unit tests on Linux
11-
- curl https://download.mono-project.com/repo/centos8-stable.repo | tee /etc/yum.repos.d/mono-stable.repo
12-
- dnf install -y mono-complete mono-devel
1310
build:
1411
commands:
1512
- dotnet msbuild buildtools/build.proj /t:unit-tests /p:Cicd=true

0 commit comments

Comments
 (0)