1
1
using System . Text . Json ;
2
+ using Amazon . DynamoDBv2 ;
3
+ using Amazon . DynamoDBv2 . Model ;
2
4
using Amazon . Lambda ;
3
5
using Amazon . Lambda . APIGatewayEvents ;
4
6
using Xunit ;
@@ -13,44 +15,52 @@ public class FunctionTests
13
15
{
14
16
private readonly ITestOutputHelper _testOutputHelper ;
15
17
private readonly AmazonLambdaClient _lambdaClient ;
18
+ private readonly AmazonDynamoDBClient _dynamoDbClient ;
19
+ private string _tableName = null ! ;
16
20
17
21
public FunctionTests ( ITestOutputHelper testOutputHelper )
18
22
{
19
23
_testOutputHelper = testOutputHelper ;
20
24
_lambdaClient = new AmazonLambdaClient ( ) ;
25
+ _dynamoDbClient = new AmazonDynamoDBClient ( ) ;
21
26
}
22
27
23
28
[ Trait ( "Category" , "AOT" ) ]
24
29
[ Theory ]
25
- [ InlineData ( "E2ETestLambda_X64_AOT_NET8_idempotency" ) ]
26
- [ InlineData ( "E2ETestLambda_ARM_AOT_NET8_idempotency" ) ]
27
- public async Task AotFunctionTest ( string functionName )
30
+ [ InlineData ( "E2ETestLambda_X64_AOT_NET8_idempotency" , "IdempotencyTable-AOT-x86_64" ) ]
31
+ [ InlineData ( "E2ETestLambda_ARM_AOT_NET8_idempotency" , "IdempotencyTable-AOT-arm64" ) ]
32
+ public async Task IdempotencyHandlerAotTest ( string functionName , string tableName )
28
33
{
29
- await TestFunction ( functionName ) ;
34
+ _tableName = tableName ;
35
+ await TestIdempotencyHandler ( functionName ) ;
30
36
}
31
37
32
38
[ Theory ]
33
- [ InlineData ( "E2ETestLambda_X64_NET6_idempotency" ) ]
34
- [ InlineData ( "E2ETestLambda_ARM_NET6_idempotency" ) ]
35
- [ InlineData ( "E2ETestLambda_X64_NET8_idempotency" ) ]
36
- [ InlineData ( "E2ETestLambda_ARM_NET8_idempotency" ) ]
37
- public async Task FunctionTest ( string functionName )
39
+ [ InlineData ( "E2ETestLambda_X64_NET6_idempotency" , "IdempotencyTable" ) ]
40
+ [ InlineData ( "E2ETestLambda_ARM_NET6_idempotency" , "IdempotencyTable" ) ]
41
+ [ InlineData ( "E2ETestLambda_X64_NET8_idempotency" , "IdempotencyTable" ) ]
42
+ [ InlineData ( "E2ETestLambda_ARM_NET8_idempotency" , "IdempotencyTable" ) ]
43
+ public async Task IdempotencyHandlerTest ( string functionName , string tableName )
38
44
{
39
- await TestFunction ( functionName ) ;
45
+ _tableName = tableName ;
46
+ await TestIdempotencyHandler ( functionName ) ;
40
47
}
41
48
42
- internal async Task TestFunction ( string functionName )
49
+ internal async Task TestIdempotencyHandler ( string functionName )
43
50
{
44
51
var request = new InvokeRequest
45
52
{
46
53
FunctionName = functionName ,
47
54
InvocationType = InvocationType . RequestResponse ,
48
55
Payload = await File . ReadAllTextAsync ( "../../../../../../../payload.json" ) ,
49
- LogType = LogType . Tail
56
+ LogType = LogType . Tail ,
50
57
} ;
51
58
52
- // run twice for cold and warm start
53
- for ( int i = 0 ; i < 2 ; i ++ )
59
+ var initialGuid = string . Empty ;
60
+ var initialRequestId = string . Empty ;
61
+
62
+ // run three times to test idempotency
63
+ for ( int i = 0 ; i < 3 ; i ++ )
54
64
{
55
65
var response = await _lambdaClient . InvokeAsync ( request ) ;
56
66
@@ -66,181 +76,81 @@ internal async Task TestFunction(string functionName)
66
76
{
67
77
Assert . Fail ( "Failed to parse payload." ) ;
68
78
}
69
-
79
+
70
80
Assert . Equal ( 200 , parsedPayload . StatusCode ) ;
71
- Assert . Equal ( "HELLO WORLD" , parsedPayload . Body ) ;
81
+
82
+ var parsedResponse = JsonSerializer . Deserialize < Response > ( parsedPayload . Body ) ;
72
83
73
- // Assert Output log from Lambda execution
74
- AssertOutputLog ( functionName , response ) ;
75
- }
76
- }
84
+ if ( parsedResponse == null )
85
+ {
86
+ Assert . Fail ( "Failed to parse response." ) ;
87
+ }
88
+
89
+ if ( i == 0 )
90
+ {
91
+ initialGuid = parsedResponse . MethodGuid ;
92
+ initialRequestId = parsedResponse . RequestId ;
93
+ }
77
94
78
- private void AssertOutputLog ( string functionName , InvokeResponse response )
79
- {
80
- // Extract and parse log
81
- var logResult = System . Text . Encoding . UTF8 . GetString ( Convert . FromBase64String ( response . LogResult ) ) ;
82
- _testOutputHelper . WriteLine ( logResult ) ;
83
- var output = OutputLogParser . ParseLogSegments ( logResult , out var report ) ;
84
- var isColdStart = report . initDuration != "N/A" ;
95
+ Assert . Equal ( initialGuid , parsedResponse . MethodGuid ) ;
96
+ Assert . Equal ( initialRequestId , parsedResponse . RequestId ) ;
97
+ }
85
98
86
- // Assert Logging utility
87
- // AssertEventLog(functionName, isColdStart, output[0]);
88
- // AssertInformationLog(functionName, isColdStart, output[1]);
89
- // AssertWarningLog(functionName, isColdStart, output[2]);
90
- // AssertExceptionLog(functionName, isColdStart, output[3]);
99
+ // Query DynamoDB and assert results
100
+ await AssertDynamoDbData ( functionName , initialGuid , initialRequestId ) ;
91
101
}
92
-
93
- private void AssertEventLog ( string functionName , bool isColdStart , string output )
102
+
103
+ private async Task AssertDynamoDbData ( string functionName , string initialGuid , string initialRequestId )
94
104
{
95
- using JsonDocument doc = JsonDocument . Parse ( output ) ;
96
- JsonElement root = doc . RootElement ;
105
+ var id = $ " { functionName } .FunctionHandler#35973cf447e6cc11008d603c791a232f" ;
106
+ _testOutputHelper . WriteLine ( $ "Querying DynamoDB with id: { id } " ) ;
97
107
98
- AssertDefaultLoggingProperties . ArePresent ( functionName , isColdStart , output ) ;
99
-
100
- if ( ! isColdStart )
108
+ var queryRequest = new QueryRequest
101
109
{
102
- Assert . True ( root . TryGetProperty ( "LookupInfo" , out JsonElement lookupInfoElement ) ) ;
103
- Assert . True ( lookupInfoElement . TryGetProperty ( "LookupId" , out JsonElement lookupIdElement ) ) ;
104
- Assert . Equal ( "c6af9ac6-7b61-11e6-9a41-93e8deadbeef" , lookupIdElement . GetString ( ) ) ;
105
- }
106
-
107
- Assert . True ( root . TryGetProperty ( "Level" , out JsonElement levelElement ) ) ;
108
- Assert . Equal ( "Information" , levelElement . GetString ( ) ) ;
109
-
110
- Assert . True ( root . TryGetProperty ( "Message" , out JsonElement messageElement ) ) ;
111
- Assert . True ( messageElement . TryGetProperty ( "Resource" , out JsonElement resourceElement ) ) ;
112
- Assert . Equal ( "/{proxy+}" , resourceElement . GetString ( ) ) ;
113
-
114
- Assert . True ( messageElement . TryGetProperty ( "Path" , out JsonElement pathElement ) ) ;
115
- Assert . Equal ( "/path/to/resource" , pathElement . GetString ( ) ) ;
116
-
117
- Assert . True ( messageElement . TryGetProperty ( "HttpMethod" , out JsonElement httpMethodElement ) ) ;
118
- Assert . Equal ( "POST" , httpMethodElement . GetString ( ) ) ;
119
-
120
- Assert . True ( messageElement . TryGetProperty ( "Headers" , out JsonElement headersElement ) ) ;
121
- Assert . True ( headersElement . TryGetProperty ( "Accept-Encoding" , out JsonElement acceptEncodingElement ) ) ;
122
- Assert . Equal ( "gzip, deflate, sdch" , acceptEncodingElement . GetString ( ) ) ;
123
-
124
- Assert . True ( headersElement . TryGetProperty ( "Accept-Language" , out JsonElement acceptLanguageElement ) ) ;
125
- Assert . Equal ( "en-US,en;q=0.8" , acceptLanguageElement . GetString ( ) ) ;
126
-
127
- Assert . True ( headersElement . TryGetProperty ( "Cache-Control" , out JsonElement cacheControlElement ) ) ;
128
- Assert . Equal ( "max-age=0" , cacheControlElement . GetString ( ) ) ;
129
-
130
- Assert . True (
131
- messageElement . TryGetProperty ( "QueryStringParameters" , out JsonElement queryStringParametersElement ) ) ;
132
- Assert . True ( queryStringParametersElement . TryGetProperty ( "Foo" , out JsonElement fooElement ) ) ;
133
- Assert . Equal ( "bar" , fooElement . GetString ( ) ) ;
134
-
135
- Assert . True ( messageElement . TryGetProperty ( "RequestContext" , out JsonElement requestContextElement ) ) ;
136
- Assert . True ( requestContextElement . TryGetProperty ( "Path" , out JsonElement requestContextPathElement ) ) ;
137
- Assert . Equal ( "/prod/path/to/resource" , requestContextPathElement . GetString ( ) ) ;
138
-
139
- Assert . True ( requestContextElement . TryGetProperty ( "AccountId" , out JsonElement accountIdElement ) ) ;
140
- Assert . Equal ( "123456789012" , accountIdElement . GetString ( ) ) ;
141
-
142
- Assert . True ( requestContextElement . TryGetProperty ( "ResourceId" , out JsonElement resourceIdElement ) ) ;
143
- Assert . Equal ( "123456" , resourceIdElement . GetString ( ) ) ;
144
-
145
- Assert . True ( requestContextElement . TryGetProperty ( "Stage" , out JsonElement stageElement ) ) ;
146
- Assert . Equal ( "prod" , stageElement . GetString ( ) ) ;
147
-
148
- Assert . True ( requestContextElement . TryGetProperty ( "RequestId" , out JsonElement requestIdElement ) ) ;
149
- Assert . Equal ( "c6af9ac6-7b61-11e6-9a41-93e8deadbeef" , requestIdElement . GetString ( ) ) ;
150
-
151
- Assert . True ( requestContextElement . TryGetProperty ( "ResourcePath" , out JsonElement resourcePathElement ) ) ;
152
- Assert . Equal ( "/{proxy+}" , resourcePathElement . GetString ( ) ) ;
153
-
154
- Assert . True (
155
- requestContextElement . TryGetProperty ( "HttpMethod" , out JsonElement requestContextHttpMethodElement ) ) ;
156
- Assert . Equal ( "POST" , requestContextHttpMethodElement . GetString ( ) ) ;
157
-
158
- Assert . True ( requestContextElement . TryGetProperty ( "ApiId" , out JsonElement apiIdElement ) ) ;
159
- Assert . Equal ( "1234567890" , apiIdElement . GetString ( ) ) ;
160
-
161
- Assert . True ( requestContextElement . TryGetProperty ( "RequestTime" , out JsonElement requestTimeElement ) ) ;
162
- Assert . Equal ( "09/Apr/2015:12:34:56 +0000" , requestTimeElement . GetString ( ) ) ;
163
-
164
- Assert . True ( requestContextElement . TryGetProperty ( "RequestTimeEpoch" , out JsonElement requestTimeEpochElement ) ) ;
165
- Assert . Equal ( 1428582896000 , requestTimeEpochElement . GetInt64 ( ) ) ;
166
-
167
- Assert . True ( messageElement . TryGetProperty ( "Body" , out JsonElement bodyElement ) ) ;
168
- Assert . Equal ( "hello world" , bodyElement . GetString ( ) ) ;
169
-
170
- Assert . True ( messageElement . TryGetProperty ( "IsBase64Encoded" , out JsonElement isBase64EncodedElement ) ) ;
171
- Assert . False ( isBase64EncodedElement . GetBoolean ( ) ) ;
172
- }
173
-
174
- private void AssertInformationLog ( string functionName , bool isColdStart , string output )
175
- {
176
- using JsonDocument doc = JsonDocument . Parse ( output ) ;
177
- JsonElement root = doc . RootElement ;
110
+ TableName = _tableName ,
111
+ KeyConditionExpression = "id = :v_id" ,
112
+ ExpressionAttributeValues = new Dictionary < string , AttributeValue >
113
+ {
114
+ { ":v_id" , new AttributeValue { S = id } }
115
+ }
116
+ } ;
117
+
118
+ _testOutputHelper . WriteLine ( $ "QueryRequest: { JsonSerializer . Serialize ( queryRequest ) } ") ;
178
119
179
- AssertDefaultLoggingProperties . ArePresent ( functionName , isColdStart , output ) ;
120
+ var queryResponse = await _dynamoDbClient . QueryAsync ( queryRequest ) ;
180
121
181
- if ( ! isColdStart )
122
+ _testOutputHelper . WriteLine ( $ "QueryResponse: { JsonSerializer . Serialize ( queryResponse ) } ") ;
123
+
124
+ if ( queryResponse . Items . Count == 0 )
182
125
{
183
- Assert . True ( root . TryGetProperty ( "LookupInfo" , out JsonElement lookupInfoElement ) ) ;
184
- Assert . True ( lookupInfoElement . TryGetProperty ( "LookupId" , out JsonElement lookupIdElement ) ) ;
185
- Assert . Equal ( "c6af9ac6-7b61-11e6-9a41-93e8deadbeef" , lookupIdElement . GetString ( ) ) ;
126
+ Assert . Fail ( "No items found in DynamoDB for the given id." ) ;
186
127
}
187
128
188
- Assert . True ( root . TryGetProperty ( "Level" , out JsonElement levelElement ) ) ;
189
- Assert . Equal ( "Information" , levelElement . GetString ( ) ) ;
190
-
191
- Assert . True ( root . TryGetProperty ( "Message" , out JsonElement messageElement ) ) ;
192
- Assert . Equal ( "Processing request started" , messageElement . GetString ( ) ) ;
193
- }
194
-
195
- private static void AssertWarningLog ( string functionName , bool isColdStart , string output )
196
- {
197
- using JsonDocument doc = JsonDocument . Parse ( output ) ;
198
- JsonElement root = doc . RootElement ;
199
-
200
- AssertDefaultLoggingProperties . ArePresent ( functionName , isColdStart , output ) ;
129
+ foreach ( var item in queryResponse . Items )
130
+ {
131
+ var data = item [ "data" ] . S ;
132
+ var status = item [ "status" ] . S ;
201
133
202
- Assert . True ( root . TryGetProperty ( "LookupInfo" , out JsonElement lookupInfoElement ) ) ;
203
- Assert . True ( lookupInfoElement . TryGetProperty ( "LookupId" , out JsonElement lookupIdElement ) ) ;
204
- Assert . Equal ( "c6af9ac6-7b61-11e6-9a41-93e8deadbeef" , lookupIdElement . GetString ( ) ) ;
134
+ Assert . Equal ( "COMPLETED" , status ) ;
205
135
206
- Assert . True ( root . TryGetProperty ( "Level" , out JsonElement levelElement ) ) ;
207
- Assert . Equal ( "Warning" , levelElement . GetString ( ) ) ;
136
+ var parsedData = JsonSerializer . Deserialize < APIGatewayProxyResponse > ( data ) ;
208
137
209
- Assert . True ( root . TryGetProperty ( "Test1" , out JsonElement test1Element ) ) ;
210
- Assert . Equal ( "value1" , test1Element . GetString ( ) ) ;
211
-
212
- Assert . True ( root . TryGetProperty ( "Test2" , out JsonElement test2Element ) ) ;
213
- Assert . Equal ( "value2" , test2Element . GetString ( ) ) ;
214
-
215
- Assert . True ( root . TryGetProperty ( "Message" , out JsonElement messageElement ) ) ;
216
- Assert . Equal ( "Warn with additional keys" , messageElement . GetString ( ) ) ;
138
+ if ( parsedData == null )
139
+ {
140
+ Assert . Fail ( "Failed to parse data field." ) ;
141
+ }
142
+
143
+ var parsedResponse = JsonSerializer . Deserialize < Response > ( parsedData . Body ) ;
144
+
145
+ if ( parsedResponse == null )
146
+ {
147
+ Assert . Fail ( "Failed to parse response." ) ;
148
+ }
149
+
150
+ Assert . Equal ( initialGuid , parsedResponse . MethodGuid ) ;
151
+ Assert . Equal ( initialRequestId , parsedResponse . RequestId ) ;
152
+ }
217
153
}
154
+ }
218
155
219
- private void AssertExceptionLog ( string functionName , bool isColdStart , string output )
220
- {
221
- using JsonDocument doc = JsonDocument . Parse ( output ) ;
222
- JsonElement root = doc . RootElement ;
223
-
224
- AssertDefaultLoggingProperties . ArePresent ( functionName , isColdStart , output ) ;
225
-
226
- Assert . True ( root . TryGetProperty ( "LookupInfo" , out JsonElement lookupInfoElement ) ) ;
227
- Assert . True ( lookupInfoElement . TryGetProperty ( "LookupId" , out JsonElement lookupIdElement ) ) ;
228
- Assert . Equal ( "c6af9ac6-7b61-11e6-9a41-93e8deadbeef" , lookupIdElement . GetString ( ) ) ;
229
-
230
- Assert . True ( root . TryGetProperty ( "Level" , out JsonElement levelElement ) ) ;
231
- Assert . Equal ( "Error" , levelElement . GetString ( ) ) ;
232
-
233
- Assert . True ( root . TryGetProperty ( "Message" , out JsonElement messageElement ) ) ;
234
- Assert . Equal ( "Oops something went wrong" , messageElement . GetString ( ) ) ;
235
-
236
- Assert . True ( root . TryGetProperty ( "Exception" , out JsonElement exceptionElement ) ) ;
237
- Assert . True ( exceptionElement . TryGetProperty ( "Type" , out JsonElement exceptionTypeElement ) ) ;
238
- Assert . Equal ( "System.InvalidOperationException" , exceptionTypeElement . GetString ( ) ) ;
239
-
240
- Assert . True ( exceptionElement . TryGetProperty ( "Message" , out JsonElement exceptionMessageElement ) ) ;
241
- Assert . Equal ( "Parent exception message" , exceptionMessageElement . GetString ( ) ) ;
242
-
243
- Assert . False ( root . TryGetProperty ( "Test1" , out JsonElement _ ) ) ;
244
- Assert . False ( root . TryGetProperty ( "Test2" , out JsonElement _ ) ) ;
245
- }
246
- }
156
+ public record Response ( string RequestId , string Greeting , string MethodGuid , string HandlerGuid ) ;
0 commit comments