Skip to content

Commit d1c1ccf

Browse files
committed
Add S3Event annotation tests
- ValidS3Events.cs.txt test source with 3 test functions - S3EventsTests.cs CloudFormation writer tests (attribute application + property sync) - S3Events project references in TestServerlessApp.csproj and test project
1 parent 9446774 commit d1c1ccf

4 files changed

Lines changed: 203 additions & 0 deletions

File tree

Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Amazon.Lambda.Annotations.SourceGenerators.Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@
208208
<ProjectReference Include="..\..\src\Amazon.Lambda.Annotations\Amazon.Lambda.Annotations.csproj" />
209209
<ProjectReference Include="..\..\src\Amazon.Lambda.APIGatewayEvents\Amazon.Lambda.APIGatewayEvents.csproj" />
210210
<ProjectReference Include="..\..\src\Amazon.Lambda.SQSEvents\Amazon.Lambda.SQSEvents.csproj" />
211+
<ProjectReference Include="..\..\src\Amazon.Lambda.S3Events\Amazon.Lambda.S3Events.csproj" />
211212
<!--
212213
We need to force using the .NET Standard 2.0 version because the source generator test framework will complain
213214
about using newer versions of System.Runtime then it can handle. This is not an issue in a end user scenario.
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
using Amazon.Lambda.Annotations.SourceGenerator;
2+
using Amazon.Lambda.Annotations.SourceGenerator.Models;
3+
using Amazon.Lambda.Annotations.SourceGenerator.Models.Attributes;
4+
using Amazon.Lambda.Annotations.SourceGenerator.Writers;
5+
using Amazon.Lambda.Annotations.S3;
6+
using System.Collections.Generic;
7+
using System.Linq;
8+
using Xunit;
9+
10+
namespace Amazon.Lambda.Annotations.SourceGenerators.Tests.WriterTests
11+
{
12+
public partial class CloudFormationWriterTests
13+
{
14+
[Theory]
15+
[ClassData(typeof(S3EventsTestData))]
16+
public void VerifyS3EventAttributes_AreCorrectlyApplied(CloudFormationTemplateFormat templateFormat, S3EventAttribute s3EventAttribute)
17+
{
18+
// ARRANGE
19+
var mockFileManager = GetMockFileManager(string.Empty);
20+
var lambdaFunctionModel = GetLambdaFunctionModel();
21+
lambdaFunctionModel.PackageType = LambdaPackageType.Zip;
22+
lambdaFunctionModel.Attributes.Add(new AttributeModel<S3EventAttribute> { Data = s3EventAttribute });
23+
var cloudFormationWriter = GetCloudFormationWriter(mockFileManager, _directoryManager, templateFormat, _diagnosticReporter);
24+
var report = GetAnnotationReport([lambdaFunctionModel]);
25+
26+
// ACT
27+
cloudFormationWriter.ApplyReport(report);
28+
29+
// ASSERT
30+
ITemplateWriter templateWriter = templateFormat == CloudFormationTemplateFormat.Json ? new JsonWriter() : new YamlWriter();
31+
templateWriter.Parse(mockFileManager.ReadAllText(ServerlessTemplateFilePath));
32+
33+
var eventName = s3EventAttribute.ResourceName;
34+
var eventPath = $"Resources.{lambdaFunctionModel.ResourceName}.Properties.Events.{eventName}";
35+
var eventPropertiesPath = $"{eventPath}.Properties";
36+
37+
Assert.True(templateWriter.Exists(eventPath));
38+
Assert.Equal("S3", templateWriter.GetToken<string>($"{eventPath}.Type"));
39+
40+
// Bucket is always a Ref
41+
var bucketName = s3EventAttribute.Bucket.StartsWith("@") ? s3EventAttribute.Bucket.Substring(1) : s3EventAttribute.Bucket;
42+
Assert.Equal(bucketName, templateWriter.GetToken<string>($"{eventPropertiesPath}.Bucket.Ref"));
43+
44+
// Events
45+
if (s3EventAttribute.IsEventsSet)
46+
{
47+
var expectedEvents = s3EventAttribute.Events.Split(';').Select(x => x.Trim()).ToList();
48+
Assert.Equal(expectedEvents, templateWriter.GetToken<List<string>>($"{eventPropertiesPath}.Events"));
49+
}
50+
51+
// Filter
52+
if (s3EventAttribute.IsFilterPrefixSet || s3EventAttribute.IsFilterSuffixSet)
53+
{
54+
Assert.True(templateWriter.Exists($"{eventPropertiesPath}.Filter.S3Key.Rules"));
55+
var rules = templateWriter.GetToken<List<Dictionary<string, string>>>($"{eventPropertiesPath}.Filter.S3Key.Rules");
56+
if (s3EventAttribute.IsFilterPrefixSet)
57+
{
58+
Assert.Contains(rules, r => r["Name"] == "prefix" && r["Value"] == s3EventAttribute.FilterPrefix);
59+
}
60+
if (s3EventAttribute.IsFilterSuffixSet)
61+
{
62+
Assert.Contains(rules, r => r["Name"] == "suffix" && r["Value"] == s3EventAttribute.FilterSuffix);
63+
}
64+
}
65+
else
66+
{
67+
Assert.False(templateWriter.Exists($"{eventPropertiesPath}.Filter"));
68+
}
69+
70+
// Enabled
71+
Assert.Equal(s3EventAttribute.IsEnabledSet, templateWriter.Exists($"{eventPropertiesPath}.Enabled"));
72+
if (s3EventAttribute.IsEnabledSet)
73+
{
74+
Assert.Equal(s3EventAttribute.Enabled, templateWriter.GetToken<bool>($"{eventPropertiesPath}.Enabled"));
75+
}
76+
}
77+
78+
[Theory]
79+
[InlineData(CloudFormationTemplateFormat.Json)]
80+
[InlineData(CloudFormationTemplateFormat.Yaml)]
81+
public void VerifyS3EventProperties_AreSyncedCorrectly(CloudFormationTemplateFormat templateFormat)
82+
{
83+
// ARRANGE
84+
var mockFileManager = GetMockFileManager(string.Empty);
85+
var lambdaFunctionModel = GetLambdaFunctionModel();
86+
lambdaFunctionModel.PackageType = LambdaPackageType.Zip;
87+
var eventResourceName = "MyBucket";
88+
var eventPropertiesPath = $"Resources.{lambdaFunctionModel.ResourceName}.Properties.Events.{eventResourceName}.Properties";
89+
var syncedEventPropertiesPath = $"Resources.{lambdaFunctionModel.ResourceName}.Metadata.SyncedEventProperties";
90+
91+
// Initial attribute with filters
92+
var initialAttribute = new S3EventAttribute("@MyBucket")
93+
{
94+
FilterPrefix = "uploads/",
95+
FilterSuffix = ".jpg"
96+
};
97+
lambdaFunctionModel.Attributes = [new AttributeModel<S3EventAttribute> { Data = initialAttribute }];
98+
var cloudFormationWriter = GetCloudFormationWriter(mockFileManager, _directoryManager, templateFormat, _diagnosticReporter);
99+
var report = GetAnnotationReport([lambdaFunctionModel]);
100+
101+
// ACT
102+
cloudFormationWriter.ApplyReport(report);
103+
104+
// Assert initial properties
105+
ITemplateWriter templateWriter = templateFormat == CloudFormationTemplateFormat.Json ? new JsonWriter() : new YamlWriter();
106+
templateWriter.Parse(mockFileManager.ReadAllText(ServerlessTemplateFilePath));
107+
108+
Assert.Equal("MyBucket", templateWriter.GetToken<string>($"{eventPropertiesPath}.Bucket.Ref"));
109+
Assert.True(templateWriter.Exists($"{eventPropertiesPath}.Filter.S3Key.Rules"));
110+
Assert.True(templateWriter.Exists($"{eventPropertiesPath}.Events"));
111+
112+
// Update attribute - remove filters, add Enabled=false
113+
var updatedAttribute = new S3EventAttribute("@MyBucket")
114+
{
115+
Enabled = false
116+
};
117+
lambdaFunctionModel.Attributes = [new AttributeModel<S3EventAttribute> { Data = updatedAttribute }];
118+
report = GetAnnotationReport([lambdaFunctionModel]);
119+
120+
cloudFormationWriter.ApplyReport(report);
121+
122+
// Assert updated properties
123+
templateWriter.Parse(mockFileManager.ReadAllText(ServerlessTemplateFilePath));
124+
Assert.Equal("MyBucket", templateWriter.GetToken<string>($"{eventPropertiesPath}.Bucket.Ref"));
125+
Assert.False(templateWriter.Exists($"{eventPropertiesPath}.Filter"));
126+
Assert.False(templateWriter.GetToken<bool>($"{eventPropertiesPath}.Enabled"));
127+
}
128+
129+
public class S3EventsTestData : TheoryData<CloudFormationTemplateFormat, S3EventAttribute>
130+
{
131+
public S3EventsTestData()
132+
{
133+
foreach (var templateFormat in new List<CloudFormationTemplateFormat> { CloudFormationTemplateFormat.Json, CloudFormationTemplateFormat.Yaml })
134+
{
135+
// Simple - default events
136+
Add(templateFormat, new S3EventAttribute("@MyBucket"));
137+
138+
// With custom events
139+
Add(templateFormat, new S3EventAttribute("@MyBucket") { Events = "s3:ObjectCreated:*;s3:ObjectRemoved:*" });
140+
141+
// With filters
142+
Add(templateFormat, new S3EventAttribute("@MyBucket") { FilterPrefix = "uploads/", FilterSuffix = ".jpg" });
143+
144+
// With prefix only
145+
Add(templateFormat, new S3EventAttribute("@MyBucket") { FilterPrefix = "logs/" });
146+
147+
// With suffix only
148+
Add(templateFormat, new S3EventAttribute("@MyBucket") { FilterSuffix = ".png" });
149+
150+
// With custom resource name and disabled
151+
Add(templateFormat, new S3EventAttribute("@ImageBucket") { ResourceName = "ImageBucketEvent", Enabled = false });
152+
153+
// All properties
154+
Add(templateFormat, new S3EventAttribute("@MyBucket")
155+
{
156+
ResourceName = "FullS3Event",
157+
Events = "s3:ObjectCreated:Put",
158+
FilterPrefix = "data/",
159+
FilterSuffix = ".csv",
160+
Enabled = true
161+
});
162+
}
163+
}
164+
}
165+
}
166+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using Amazon.Lambda.Annotations;
2+
using Amazon.Lambda.Annotations.S3;
3+
using Amazon.Lambda.S3Events;
4+
using System;
5+
using System.Threading.Tasks;
6+
7+
namespace TestServerlessApp.S3EventExamples
8+
{
9+
// This file represents valid usage of the S3EventAttribute. This is added as .txt file since we do not want to deploy these functions during our integration tests.
10+
// This file is only sent as input to the source generator unit tests.
11+
12+
public class ValidS3Events
13+
{
14+
[LambdaFunction(PackageType = LambdaPackageType.Image)]
15+
[S3Event("@MyBucket")]
16+
public void ProcessS3Event(S3Event evnt)
17+
{
18+
Console.WriteLine($"Event processed: {evnt}");
19+
}
20+
21+
[LambdaFunction(PackageType = LambdaPackageType.Image)]
22+
[S3Event("@MyBucket", Events = "s3:ObjectCreated:*;s3:ObjectRemoved:*", FilterPrefix = "uploads/", FilterSuffix = ".jpg")]
23+
public async Task ProcessS3EventWithFilters(S3Event evnt)
24+
{
25+
await Console.Out.WriteLineAsync($"Event processed: {evnt}");
26+
}
27+
28+
[LambdaFunction(PackageType = LambdaPackageType.Image)]
29+
[S3Event("@ImageBucket", ResourceName = "ImageBucketEvent", Enabled = false)]
30+
public void ProcessS3EventDisabled(S3Event evnt)
31+
{
32+
Console.WriteLine($"Event processed: {evnt}");
33+
}
34+
}
35+
}

Libraries/test/TestServerlessApp/TestServerlessApp.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
<ProjectReference Include="..\..\src\Amazon.Lambda.Annotations\Amazon.Lambda.Annotations.csproj" />
2828
<ProjectReference Include="..\..\src\Amazon.Lambda.APIGatewayEvents\Amazon.Lambda.APIGatewayEvents.csproj" />
2929
<ProjectReference Include="..\..\src\Amazon.Lambda.SQSEvents\Amazon.Lambda.SQSEvents.csproj" />
30+
<ProjectReference Include="..\..\src\Amazon.Lambda.S3Events\Amazon.Lambda.S3Events.csproj" />
3031
<ProjectReference Include="..\..\src\Amazon.Lambda.Core\Amazon.Lambda.Core.csproj" />
3132
<ProjectReference Include="..\..\src\Amazon.Lambda.Serialization.SystemTextJson\Amazon.Lambda.Serialization.SystemTextJson.csproj" />
3233
</ItemGroup>

0 commit comments

Comments
 (0)