Skip to content

Commit 8d43ff9

Browse files
committed
fix: Lambda test tool debugs the correct assembly when the Lambda project depends on other executable projects
1 parent 7a516b8 commit 8d43ff9

File tree

9 files changed

+488
-9
lines changed

9 files changed

+488
-9
lines changed

Tools/LambdaTestTool/src/Amazon.Lambda.TestTool/Runtime/LocalLambdaRuntime.cs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,20 +53,15 @@ public static ILocalLambdaRuntime Initialize(string directory, IAWSService awsSe
5353
throw new DirectoryNotFoundException($"Directory containing built Lambda project does not exist {directory}");
5454
}
5555

56-
var depsFile = Directory.GetFiles(directory, "*.deps.json").FirstOrDefault();
57-
if (depsFile == null)
58-
{
59-
throw new Exception($"Failed to find a deps.json file in the specified directory ({directory})");
60-
}
56+
var lambdaAssemblyPath = Utils.FindLambdaAssemblyPath(directory);
6157

62-
var fileName = depsFile.Substring(0, depsFile.Length - ".deps.json".Length) + ".dll";
63-
if (!File.Exists(fileName))
58+
if (string.IsNullOrEmpty(lambdaAssemblyPath) || !File.Exists(lambdaAssemblyPath))
6459
{
6560
throw new Exception($"Failed to find Lambda project entry assembly in the specified directory ({directory})");
6661
}
6762

6863
// The resolver provides the ability to load the assemblies containing the select Lambda function.
69-
var resolver = new LambdaAssemblyLoadContext(fileName);
64+
var resolver = new LambdaAssemblyLoadContext(lambdaAssemblyPath);
7065

7166
var runtime = new LocalLambdaRuntime(resolver, directory, awsService);
7267
return runtime;

Tools/LambdaTestTool/src/Amazon.Lambda.TestTool/Utils.cs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using System.Text;
1010
using System.Text.Json;
1111
using Amazon.Lambda.TestTool.Runtime;
12+
using Newtonsoft.Json.Linq;
1213

1314
namespace Amazon.Lambda.TestTool
1415
{
@@ -241,5 +242,66 @@ public static string SearchLatestCompilationDirectory(string debugDirectory)
241242

242243
return depsFile[0].Directory.FullName;
243244
}
245+
246+
/// <summary>
247+
/// Returns the Lambda assembly file path that will debugged by the test tool.
248+
/// It returns an empty string if no Lambda assembly path is found.
249+
/// </summary>
250+
/// <param name="debugDirectory">This points to the .../bin/{CONFIGURATION}/{TARGET_FRAMEWORK} directory</param>
251+
public static string FindLambdaAssemblyPath(string debugDirectory)
252+
{
253+
var depsFiles = Directory.GetFiles(debugDirectory, "*.deps.json");
254+
if (!depsFiles.Any())
255+
{
256+
return string.Empty;
257+
}
258+
259+
if (depsFiles.Length == 1)
260+
{
261+
var depsFilePath = depsFiles.First();
262+
var lambdaAssemblyPath = depsFilePath.Substring(0, depsFilePath.Length - ".deps.json".Length) + ".dll";
263+
return lambdaAssemblyPath;
264+
}
265+
266+
var dependencies = new HashSet<string>();
267+
foreach (var depsFilePath in depsFiles)
268+
{
269+
var depsFileContent = File.ReadAllText(depsFilePath);
270+
ExtractDependenciesFromDepsJson(JsonDocument.Parse(depsFileContent).RootElement, dependencies);
271+
}
272+
273+
foreach (var depsFilePath in depsFiles)
274+
{
275+
var depsFileName = Path.GetFileName(depsFilePath);
276+
var projectName = depsFileName.Substring(0, depsFileName.Length - ".deps.json".Length);
277+
if (!dependencies.Contains(projectName))
278+
{
279+
var lambdaAssemblyPath = depsFilePath.Substring(0, depsFilePath.Length - ".deps.json".Length) + ".dll";
280+
return lambdaAssemblyPath;
281+
}
282+
}
283+
284+
return string.Empty;
285+
}
286+
287+
private static void ExtractDependenciesFromDepsJson(JsonElement node, HashSet<string> dependencies)
288+
{
289+
if (node.ValueKind != JsonValueKind.Object)
290+
return;
291+
292+
if (node.TryGetProperty("dependencies", out var depenciesBlob))
293+
{
294+
foreach (var dependency in depenciesBlob.EnumerateObject())
295+
{
296+
dependencies.Add(dependency.Name);
297+
}
298+
return;
299+
}
300+
301+
foreach (var childNode in node.EnumerateObject())
302+
{
303+
ExtractDependenciesFromDepsJson(childNode.Value, dependencies);
304+
}
305+
}
244306
}
245307
}

Tools/LambdaTestTool/tests/Amazon.Lambda.TestTool.Tests.NET6/Amazon.Lambda.TestTool.Tests.NET6.csproj

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

33
<PropertyGroup>
44
<TargetFramework>net6.0</TargetFramework>
@@ -26,4 +26,10 @@
2626
<ProjectReference Include="..\LambdaFunctions\net6\SourceGeneratorExample\SourceGeneratorExample.csproj" />
2727
</ItemGroup>
2828

29+
<ItemGroup>
30+
<Content Include="TestFiles\**">
31+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
32+
</Content>
33+
</ItemGroup>
34+
2935
</Project>
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
namespace Amazon.Lambda.TestTool.Tests.NET6
2+
{
3+
public class LambdaAssemblyPathTests
4+
{
5+
6+
[Fact]
7+
public void SingleDepsJsonFile()
8+
{
9+
var lambdaAssemblyPath = Utils.FindLambdaAssemblyPath(Path.Combine("TestFiles", "SingleDepsJsonFile"));
10+
Assert.Equal(Path.Combine("TestFiles", "SingleDepsJsonFile", "LambdaDemo.dll"), lambdaAssemblyPath);
11+
}
12+
13+
[Fact]
14+
public void MultipleDepsJsonFile()
15+
{
16+
var lambdaAssemblyPath = Utils.FindLambdaAssemblyPath(Path.Combine("TestFiles", "MultipleDepsJsonFile"));
17+
Assert.Equal(Path.Combine("TestFiles", "MultipleDepsJsonFile", "LambdaDemo.dll"), lambdaAssemblyPath);
18+
}
19+
}
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
The dependency graph is as follows:
2+
1. LambdaDemo depends on LambdaDemo.Api1 and LambdaDemo.Api2
3+
2. LambdaDemo.Api1 depends on LambdaDemo.Api2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
{
2+
"runtimeTarget": {
3+
"name": ".NETCoreApp,Version=v6.0",
4+
"signature": ""
5+
},
6+
"compilationOptions": {},
7+
"targets": {
8+
".NETCoreApp,Version=v6.0": {
9+
"LambdaDemo.Api1/1.0.0": {
10+
"dependencies": {
11+
"LambdaDemo.Api2": "1.0.0",
12+
"Swashbuckle.AspNetCore": "6.5.0"
13+
},
14+
"runtime": {
15+
"LambdaDemo.Api1.dll": {}
16+
}
17+
},
18+
"LambdaDemo.Api2/1.0.0": {
19+
"dependencies": {
20+
"Swashbuckle.AspNetCore": "6.5.0"
21+
},
22+
"runtime": {
23+
"LambdaDemo.Api2.dll": {}
24+
}
25+
},
26+
"Microsoft.Extensions.ApiDescription.Server/6.0.5": {},
27+
"Microsoft.OpenApi/1.2.3": {
28+
"runtime": {
29+
"lib/netstandard2.0/Microsoft.OpenApi.dll": {
30+
"assemblyVersion": "1.2.3.0",
31+
"fileVersion": "1.2.3.0"
32+
}
33+
}
34+
},
35+
"Swashbuckle.AspNetCore/6.5.0": {
36+
"dependencies": {
37+
"Microsoft.Extensions.ApiDescription.Server": "6.0.5",
38+
"Swashbuckle.AspNetCore.Swagger": "6.5.0",
39+
"Swashbuckle.AspNetCore.SwaggerGen": "6.5.0",
40+
"Swashbuckle.AspNetCore.SwaggerUI": "6.5.0"
41+
}
42+
},
43+
"Swashbuckle.AspNetCore.Swagger/6.5.0": {
44+
"dependencies": {
45+
"Microsoft.OpenApi": "1.2.3"
46+
},
47+
"runtime": {
48+
"lib/net6.0/Swashbuckle.AspNetCore.Swagger.dll": {
49+
"assemblyVersion": "6.5.0.0",
50+
"fileVersion": "6.5.0.0"
51+
}
52+
}
53+
},
54+
"Swashbuckle.AspNetCore.SwaggerGen/6.5.0": {
55+
"dependencies": {
56+
"Swashbuckle.AspNetCore.Swagger": "6.5.0"
57+
},
58+
"runtime": {
59+
"lib/net6.0/Swashbuckle.AspNetCore.SwaggerGen.dll": {
60+
"assemblyVersion": "6.5.0.0",
61+
"fileVersion": "6.5.0.0"
62+
}
63+
}
64+
},
65+
"Swashbuckle.AspNetCore.SwaggerUI/6.5.0": {
66+
"runtime": {
67+
"lib/net6.0/Swashbuckle.AspNetCore.SwaggerUI.dll": {
68+
"assemblyVersion": "6.5.0.0",
69+
"fileVersion": "6.5.0.0"
70+
}
71+
}
72+
}
73+
}
74+
},
75+
"libraries": {
76+
"LambdaDemo.Api1/1.0.0": {
77+
"type": "project",
78+
"serviceable": false,
79+
"sha512": ""
80+
},
81+
"LambdaDemo.Api2/1.0.0": {
82+
"type": "project",
83+
"serviceable": false,
84+
"sha512": ""
85+
},
86+
"Microsoft.Extensions.ApiDescription.Server/6.0.5": {
87+
"type": "package",
88+
"serviceable": true,
89+
"sha512": "sha512-Ckb5EDBUNJdFWyajfXzUIMRkhf52fHZOQuuZg/oiu8y7zDCVwD0iHhew6MnThjHmevanpxL3f5ci2TtHQEN6bw==",
90+
"path": "microsoft.extensions.apidescription.server/6.0.5",
91+
"hashPath": "microsoft.extensions.apidescription.server.6.0.5.nupkg.sha512"
92+
},
93+
"Microsoft.OpenApi/1.2.3": {
94+
"type": "package",
95+
"serviceable": true,
96+
"sha512": "sha512-Nug3rO+7Kl5/SBAadzSMAVgqDlfGjJZ0GenQrLywJ84XGKO0uRqkunz5Wyl0SDwcR71bAATXvSdbdzPrYRYKGw==",
97+
"path": "microsoft.openapi/1.2.3",
98+
"hashPath": "microsoft.openapi.1.2.3.nupkg.sha512"
99+
},
100+
"Swashbuckle.AspNetCore/6.5.0": {
101+
"type": "package",
102+
"serviceable": true,
103+
"sha512": "sha512-FK05XokgjgwlCI6wCT+D4/abtQkL1X1/B9Oas6uIwHFmYrIO9WUD5aLC9IzMs9GnHfUXOtXZ2S43gN1mhs5+aA==",
104+
"path": "swashbuckle.aspnetcore/6.5.0",
105+
"hashPath": "swashbuckle.aspnetcore.6.5.0.nupkg.sha512"
106+
},
107+
"Swashbuckle.AspNetCore.Swagger/6.5.0": {
108+
"type": "package",
109+
"serviceable": true,
110+
"sha512": "sha512-XWmCmqyFmoItXKFsQSwQbEAsjDKcxlNf1l+/Ki42hcb6LjKL8m5Db69OTvz5vLonMSRntYO1XLqz0OP+n3vKnA==",
111+
"path": "swashbuckle.aspnetcore.swagger/6.5.0",
112+
"hashPath": "swashbuckle.aspnetcore.swagger.6.5.0.nupkg.sha512"
113+
},
114+
"Swashbuckle.AspNetCore.SwaggerGen/6.5.0": {
115+
"type": "package",
116+
"serviceable": true,
117+
"sha512": "sha512-Y/qW8Qdg9OEs7V013tt+94OdPxbRdbhcEbw4NiwGvf4YBcfhL/y7qp/Mjv/cENsQ2L3NqJ2AOu94weBy/h4KvA==",
118+
"path": "swashbuckle.aspnetcore.swaggergen/6.5.0",
119+
"hashPath": "swashbuckle.aspnetcore.swaggergen.6.5.0.nupkg.sha512"
120+
},
121+
"Swashbuckle.AspNetCore.SwaggerUI/6.5.0": {
122+
"type": "package",
123+
"serviceable": true,
124+
"sha512": "sha512-OvbvxX+wL8skxTBttcBsVxdh73Fag4xwqEU2edh4JMn7Ws/xJHnY/JB1e9RoCb6XpDxUF3hD9A0Z1lEUx40Pfw==",
125+
"path": "swashbuckle.aspnetcore.swaggerui/6.5.0",
126+
"hashPath": "swashbuckle.aspnetcore.swaggerui.6.5.0.nupkg.sha512"
127+
}
128+
}
129+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
{
2+
"runtimeTarget": {
3+
"name": ".NETCoreApp,Version=v6.0",
4+
"signature": ""
5+
},
6+
"compilationOptions": {},
7+
"targets": {
8+
".NETCoreApp,Version=v6.0": {
9+
"LambdaDemo.Api2/1.0.0": {
10+
"dependencies": {
11+
"Swashbuckle.AspNetCore": "6.5.0"
12+
},
13+
"runtime": {
14+
"LambdaDemo.Api2.dll": {}
15+
}
16+
},
17+
"Microsoft.Extensions.ApiDescription.Server/6.0.5": {},
18+
"Microsoft.OpenApi/1.2.3": {
19+
"runtime": {
20+
"lib/netstandard2.0/Microsoft.OpenApi.dll": {
21+
"assemblyVersion": "1.2.3.0",
22+
"fileVersion": "1.2.3.0"
23+
}
24+
}
25+
},
26+
"Swashbuckle.AspNetCore/6.5.0": {
27+
"dependencies": {
28+
"Microsoft.Extensions.ApiDescription.Server": "6.0.5",
29+
"Swashbuckle.AspNetCore.Swagger": "6.5.0",
30+
"Swashbuckle.AspNetCore.SwaggerGen": "6.5.0",
31+
"Swashbuckle.AspNetCore.SwaggerUI": "6.5.0"
32+
}
33+
},
34+
"Swashbuckle.AspNetCore.Swagger/6.5.0": {
35+
"dependencies": {
36+
"Microsoft.OpenApi": "1.2.3"
37+
},
38+
"runtime": {
39+
"lib/net6.0/Swashbuckle.AspNetCore.Swagger.dll": {
40+
"assemblyVersion": "6.5.0.0",
41+
"fileVersion": "6.5.0.0"
42+
}
43+
}
44+
},
45+
"Swashbuckle.AspNetCore.SwaggerGen/6.5.0": {
46+
"dependencies": {
47+
"Swashbuckle.AspNetCore.Swagger": "6.5.0"
48+
},
49+
"runtime": {
50+
"lib/net6.0/Swashbuckle.AspNetCore.SwaggerGen.dll": {
51+
"assemblyVersion": "6.5.0.0",
52+
"fileVersion": "6.5.0.0"
53+
}
54+
}
55+
},
56+
"Swashbuckle.AspNetCore.SwaggerUI/6.5.0": {
57+
"runtime": {
58+
"lib/net6.0/Swashbuckle.AspNetCore.SwaggerUI.dll": {
59+
"assemblyVersion": "6.5.0.0",
60+
"fileVersion": "6.5.0.0"
61+
}
62+
}
63+
}
64+
}
65+
},
66+
"libraries": {
67+
"LambdaDemo.Api2/1.0.0": {
68+
"type": "project",
69+
"serviceable": false,
70+
"sha512": ""
71+
},
72+
"Microsoft.Extensions.ApiDescription.Server/6.0.5": {
73+
"type": "package",
74+
"serviceable": true,
75+
"sha512": "sha512-Ckb5EDBUNJdFWyajfXzUIMRkhf52fHZOQuuZg/oiu8y7zDCVwD0iHhew6MnThjHmevanpxL3f5ci2TtHQEN6bw==",
76+
"path": "microsoft.extensions.apidescription.server/6.0.5",
77+
"hashPath": "microsoft.extensions.apidescription.server.6.0.5.nupkg.sha512"
78+
},
79+
"Microsoft.OpenApi/1.2.3": {
80+
"type": "package",
81+
"serviceable": true,
82+
"sha512": "sha512-Nug3rO+7Kl5/SBAadzSMAVgqDlfGjJZ0GenQrLywJ84XGKO0uRqkunz5Wyl0SDwcR71bAATXvSdbdzPrYRYKGw==",
83+
"path": "microsoft.openapi/1.2.3",
84+
"hashPath": "microsoft.openapi.1.2.3.nupkg.sha512"
85+
},
86+
"Swashbuckle.AspNetCore/6.5.0": {
87+
"type": "package",
88+
"serviceable": true,
89+
"sha512": "sha512-FK05XokgjgwlCI6wCT+D4/abtQkL1X1/B9Oas6uIwHFmYrIO9WUD5aLC9IzMs9GnHfUXOtXZ2S43gN1mhs5+aA==",
90+
"path": "swashbuckle.aspnetcore/6.5.0",
91+
"hashPath": "swashbuckle.aspnetcore.6.5.0.nupkg.sha512"
92+
},
93+
"Swashbuckle.AspNetCore.Swagger/6.5.0": {
94+
"type": "package",
95+
"serviceable": true,
96+
"sha512": "sha512-XWmCmqyFmoItXKFsQSwQbEAsjDKcxlNf1l+/Ki42hcb6LjKL8m5Db69OTvz5vLonMSRntYO1XLqz0OP+n3vKnA==",
97+
"path": "swashbuckle.aspnetcore.swagger/6.5.0",
98+
"hashPath": "swashbuckle.aspnetcore.swagger.6.5.0.nupkg.sha512"
99+
},
100+
"Swashbuckle.AspNetCore.SwaggerGen/6.5.0": {
101+
"type": "package",
102+
"serviceable": true,
103+
"sha512": "sha512-Y/qW8Qdg9OEs7V013tt+94OdPxbRdbhcEbw4NiwGvf4YBcfhL/y7qp/Mjv/cENsQ2L3NqJ2AOu94weBy/h4KvA==",
104+
"path": "swashbuckle.aspnetcore.swaggergen/6.5.0",
105+
"hashPath": "swashbuckle.aspnetcore.swaggergen.6.5.0.nupkg.sha512"
106+
},
107+
"Swashbuckle.AspNetCore.SwaggerUI/6.5.0": {
108+
"type": "package",
109+
"serviceable": true,
110+
"sha512": "sha512-OvbvxX+wL8skxTBttcBsVxdh73Fag4xwqEU2edh4JMn7Ws/xJHnY/JB1e9RoCb6XpDxUF3hD9A0Z1lEUx40Pfw==",
111+
"path": "swashbuckle.aspnetcore.swaggerui/6.5.0",
112+
"hashPath": "swashbuckle.aspnetcore.swaggerui.6.5.0.nupkg.sha512"
113+
}
114+
}
115+
}

0 commit comments

Comments
 (0)