Skip to content

Commit 5d2080f

Browse files
committed
test cases for events with nullish behavior
Following CR feedback on #1130 . The selected cases cover booleans, dynamodb items, maps, and the GroupConfiguration data structure, so we have at least one instance of each nullish use case. I added a utility function for basic serde verification. I retrofitted it to existing tests for the data structures that got new cases, just so the code is consistent for them. There are a very large number of other similar cases that I left alone to keep the review reasonable.
1 parent 36d211b commit 5d2080f

12 files changed

Lines changed: 437 additions & 37 deletions

lambda-events/src/event/activemq/mod.rs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,14 +87,24 @@ pub struct ActiveMqDestination {
8787
#[cfg(test)]
8888
mod test {
8989
use super::*;
90+
use crate::fixtures::verify_serde_roundtrip;
9091

9192
#[test]
9293
#[cfg(feature = "activemq")]
9394
fn example_activemq_event() {
94-
let data = include_bytes!("../../fixtures/example-activemq-event.json");
95-
let parsed: ActiveMqEvent = serde_json::from_slice(data).unwrap();
96-
let output: String = serde_json::to_string(&parsed).unwrap();
97-
let reparsed: ActiveMqEvent = serde_json::from_slice(output.as_bytes()).unwrap();
98-
assert_eq!(parsed, reparsed);
95+
verify_serde_roundtrip::<ActiveMqEvent>(include_bytes!("../../fixtures/example-activemq-event.json"));
96+
}
97+
98+
#[test]
99+
#[cfg(feature = "activemq")]
100+
fn example_activemq_event_null_properties() {
101+
let event: ActiveMqEvent = verify_serde_roundtrip(include_bytes!(
102+
"../../fixtures/example-activemq-event-null-properties.json"
103+
));
104+
assert_eq!(
105+
0,
106+
event.messages[0].properties.len(),
107+
"null properties should deserialize to empty map"
108+
)
99109
}
100110
}

lambda-events/src/event/apigw/mod.rs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1147,6 +1147,7 @@ pub fn serialize_authorizer_fields<S: Serializer>(
11471147
#[cfg(test)]
11481148
mod test {
11491149
use super::*;
1150+
use crate::fixtures::verify_serde_roundtrip;
11501151

11511152
#[test]
11521153
#[cfg(feature = "apigw")]
@@ -1396,31 +1397,32 @@ mod test {
13961397
#[cfg(feature = "apigw")]
13971398
fn example_apigw_v2_custom_authorizer_v2_request() {
13981399
let data = include_bytes!("../../fixtures/example-apigw-v2-custom-authorizer-v2-request.json");
1399-
let parsed: ApiGatewayV2CustomAuthorizerV2Request = serde_json::from_slice(data).unwrap();
1400-
let output: String = serde_json::to_string(&parsed).unwrap();
1401-
let reparsed: ApiGatewayV2CustomAuthorizerV2Request = serde_json::from_slice(output.as_bytes()).unwrap();
1402-
assert_eq!(parsed, reparsed);
1400+
verify_serde_roundtrip::<ApiGatewayV2CustomAuthorizerV2Request>(data);
1401+
}
1402+
1403+
#[test]
1404+
#[cfg(feature = "apigw")]
1405+
fn example_apigw_v2_custom_authorizer_v2_request_null_maps() {
1406+
let data = include_bytes!("../../fixtures/example-apigw-v2-custom-authorizer-v2-request-null-maps.json");
1407+
let parsed: ApiGatewayV2CustomAuthorizerV2Request = verify_serde_roundtrip(data);
1408+
assert_eq!(0, parsed.path_parameters.len());
1409+
assert_eq!(0, parsed.query_string_parameters.len());
1410+
assert_eq!(0, parsed.stage_variables.len());
14031411
}
14041412

14051413
#[test]
14061414
#[cfg(feature = "apigw")]
14071415
fn example_apigw_v2_custom_authorizer_v2_request_without_cookies() {
14081416
let data = include_bytes!("../../fixtures/example-apigw-v2-custom-authorizer-v2-request-without-cookies.json");
1409-
let parsed: ApiGatewayV2CustomAuthorizerV2Request = serde_json::from_slice(data).unwrap();
1410-
let output: String = serde_json::to_string(&parsed).unwrap();
1411-
let reparsed: ApiGatewayV2CustomAuthorizerV2Request = serde_json::from_slice(output.as_bytes()).unwrap();
1412-
assert_eq!(parsed, reparsed);
1417+
verify_serde_roundtrip::<ApiGatewayV2CustomAuthorizerV2Request>(data);
14131418
}
14141419

14151420
#[test]
14161421
#[cfg(feature = "apigw")]
14171422
fn example_apigw_v2_custom_authorizer_v2_request_without_identity_source() {
14181423
let data =
14191424
include_bytes!("../../fixtures/example-apigw-v2-custom-authorizer-v2-request-without-identity-source.json");
1420-
let parsed: ApiGatewayV2CustomAuthorizerV2Request = serde_json::from_slice(data).unwrap();
1421-
let output: String = serde_json::to_string(&parsed).unwrap();
1422-
let reparsed: ApiGatewayV2CustomAuthorizerV2Request = serde_json::from_slice(output.as_bytes()).unwrap();
1423-
assert_eq!(parsed, reparsed);
1425+
verify_serde_roundtrip::<ApiGatewayV2CustomAuthorizerV2Request>(data);
14241426
}
14251427

14261428
#[test]

lambda-events/src/event/cognito/mod.rs

Lines changed: 50 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1077,6 +1077,7 @@ pub struct CognitoEventUserPoolsCustomMessageResponse {
10771077
#[cfg(test)]
10781078
mod test {
10791079
use super::*;
1080+
use crate::fixtures::verify_serde_roundtrip;
10801081

10811082
#[test]
10821083
#[cfg(feature = "cognito")]
@@ -1166,10 +1167,27 @@ mod test {
11661167
#[cfg(feature = "cognito")]
11671168
fn example_cognito_event_userpools_migrateuser() {
11681169
let data = include_bytes!("../../fixtures/example-cognito-event-userpools-migrateuser.json");
1169-
let parsed: CognitoEventUserPoolsMigrateUser = serde_json::from_slice(data).unwrap();
1170-
let output: String = serde_json::to_string(&parsed).unwrap();
1171-
let reparsed: CognitoEventUserPoolsMigrateUser = serde_json::from_slice(output.as_bytes()).unwrap();
1172-
assert_eq!(parsed, reparsed);
1170+
verify_serde_roundtrip::<CognitoEventUserPoolsMigrateUser>(data);
1171+
}
1172+
1173+
#[test]
1174+
#[cfg(feature = "cognito")]
1175+
fn example_cognito_event_userpools_migrateuser_null_fields() {
1176+
let data = include_bytes!("../../fixtures/example-cognito-event-userpools-migrateuser-null-fields.json");
1177+
let event: CognitoEventUserPoolsMigrateUser = verify_serde_roundtrip(data);
1178+
// verify correct values substituted for nulls.
1179+
assert_eq!(
1180+
0,
1181+
event
1182+
.cognito_event_user_pools_migrate_user_response
1183+
.user_attributes
1184+
.len()
1185+
);
1186+
assert!(
1187+
!event
1188+
.cognito_event_user_pools_migrate_user_response
1189+
.force_alias_creation
1190+
);
11731191
}
11741192

11751193
#[test]
@@ -1216,40 +1234,52 @@ mod test {
12161234
#[cfg(feature = "cognito")]
12171235
fn example_cognito_event_userpools_pretokengen_incoming() {
12181236
let data = include_bytes!("../../fixtures/example-cognito-event-userpools-pretokengen-incoming.json");
1219-
let parsed: CognitoEventUserPoolsPreTokenGen = serde_json::from_slice(data).unwrap();
1220-
let output: String = serde_json::to_string(&parsed).unwrap();
1221-
let reparsed: CognitoEventUserPoolsPreTokenGen = serde_json::from_slice(output.as_bytes()).unwrap();
1222-
assert_eq!(parsed, reparsed);
1237+
verify_serde_roundtrip::<CognitoEventUserPoolsPreTokenGen>(data);
12231238
}
12241239

12251240
#[test]
12261241
#[cfg(feature = "cognito")]
12271242
fn example_cognito_event_userpools_pretokengen_v2_incoming() {
12281243
let data = include_bytes!("../../fixtures/example-cognito-event-userpools-pretokengen-v2-incoming.json");
1229-
let parsed: CognitoEventUserPoolsPreTokenGenV2 = serde_json::from_slice(data).unwrap();
1230-
let output: String = serde_json::to_string(&parsed).unwrap();
1231-
let reparsed: CognitoEventUserPoolsPreTokenGenV2 = serde_json::from_slice(output.as_bytes()).unwrap();
1232-
assert_eq!(parsed, reparsed);
1244+
verify_serde_roundtrip::<CognitoEventUserPoolsPreTokenGenV2>(data);
12331245
}
12341246

12351247
#[test]
12361248
#[cfg(feature = "cognito")]
12371249
fn example_cognito_event_userpools_pretokengen() {
12381250
let data = include_bytes!("../../fixtures/example-cognito-event-userpools-pretokengen.json");
1239-
let parsed: CognitoEventUserPoolsPreTokenGen = serde_json::from_slice(data).unwrap();
1240-
let output: String = serde_json::to_string(&parsed).unwrap();
1241-
let reparsed: CognitoEventUserPoolsPreTokenGen = serde_json::from_slice(output.as_bytes()).unwrap();
1242-
assert_eq!(parsed, reparsed);
1251+
verify_serde_roundtrip::<CognitoEventUserPoolsPreTokenGen>(data);
1252+
}
1253+
1254+
#[test]
1255+
#[cfg(feature = "cognito")]
1256+
fn example_cognito_event_userpools_pretokengen_null_group_configuration() {
1257+
let data =
1258+
include_bytes!("../../fixtures/example-cognito-event-userpools-pretokengen-null-group-configuration.json");
1259+
verify_serde_roundtrip::<CognitoEventUserPoolsPreTokenGen>(data);
12431260
}
12441261

12451262
#[test]
12461263
#[cfg(feature = "cognito")]
12471264
fn example_cognito_event_userpools_v2_pretokengen() {
12481265
let data = include_bytes!("../../fixtures/example-cognito-event-userpools-pretokengen-v2.json");
1249-
let parsed: CognitoEventUserPoolsPreTokenGenV2 = serde_json::from_slice(data).unwrap();
1250-
let output: String = serde_json::to_string(&parsed).unwrap();
1251-
let reparsed: CognitoEventUserPoolsPreTokenGenV2 = serde_json::from_slice(output.as_bytes()).unwrap();
1252-
assert_eq!(parsed, reparsed);
1266+
verify_serde_roundtrip::<CognitoEventUserPoolsPreTokenGenV2>(data);
1267+
}
1268+
1269+
#[test]
1270+
#[cfg(feature = "cognito")]
1271+
fn example_cognito_event_userpools_v2_pretokengen_null_group_configuration() {
1272+
let data = include_bytes!(
1273+
"../../fixtures/example-cognito-event-userpools-pretokengen-v2-null-group-configuration.json"
1274+
);
1275+
let event: CognitoEventUserPoolsPreTokenGenV2 = verify_serde_roundtrip(data);
1276+
// fail if there are any breaking changes to GroupConfiguration::default().
1277+
assert_eq!(0, event.request.group_configuration.groups_to_override.len());
1278+
assert_eq!(0, event.request.group_configuration.iam_roles_to_override.len());
1279+
assert!(event.request.group_configuration.preferred_role.is_none());
1280+
1281+
#[cfg(feature = "catch-all-fields")]
1282+
assert_eq!(0, event.request.group_configuration.other.len());
12531283
}
12541284

12551285
#[test]

lambda-events/src/event/dynamodb/mod.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,7 @@ pub struct StreamRecord {
328328
#[allow(deprecated)]
329329
mod test {
330330
use super::*;
331+
use crate::fixtures::verify_serde_roundtrip;
331332
use chrono::TimeZone;
332333

333334
#[test]
@@ -344,6 +345,16 @@ mod test {
344345
assert_eq!(date, event.change.approximate_creation_date_time);
345346
}
346347

348+
#[test]
349+
#[cfg(feature = "dynamodb")]
350+
fn example_dynamodb_event_null_items() {
351+
let data = include_bytes!("../../fixtures/example-dynamodb-event-null-items.json");
352+
let event = verify_serde_roundtrip::<Event>(data);
353+
assert_eq!(0, event.records[0].change.keys.len());
354+
assert_eq!(0, event.records[0].change.new_image.len());
355+
assert_eq!(0, event.records[0].change.old_image.len());
356+
}
357+
347358
#[test]
348359
#[cfg(feature = "dynamodb")]
349360
fn example_dynamodb_event_with_optional_fields() {
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"eventSource": "aws:mq",
3+
"eventSourceArn": "arn:aws:mq:us-west-2:533019413397:broker:shask-test:b-0f5b7522-2b41-4f85-a615-735a4e6d96b5",
4+
"messages": [
5+
{
6+
"messageID": "ID:b-0f5b7522-2b41-4f85-a615-735a4e6d96b5-2.mq.us-west-2.amazonaws.com-34859-1598944546501-4:12:1:1:3",
7+
"messageType": "jms/text-message",
8+
"timestamp": 1599863938941,
9+
"deliveryMode": 1,
10+
"correlationID": "",
11+
"replyTo": "null",
12+
"destination": {
13+
"physicalName": "testQueue"
14+
},
15+
"redelivered": false,
16+
"type": "",
17+
"expiration": 0,
18+
"priority": 0,
19+
"data": "RW50ZXIgc29tZSB0ZXh0IGhlcmUgZm9yIHRoZSBtZXNzYWdlIGJvZHkuLi4=",
20+
"brokerInTime": 1599863938943,
21+
"brokerOutTime": 1599863938944,
22+
"properties": null
23+
}
24+
]
25+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
{
2+
"version": "2.0",
3+
"type": "REQUEST",
4+
"routeArn": "arn:aws:execute-api:us-east-1:123456789012:abcdef123/test/GET/request",
5+
"identitySource": ["user1", "123"],
6+
"routeKey": "$default",
7+
"rawPath": "/my/path",
8+
"rawQueryString": "parameter1=value1&parameter1=value2&parameter2=value",
9+
"cookies": ["cookie1", "cookie2"],
10+
"headers": {
11+
"Header1": "value1",
12+
"Header2": "value2"
13+
},
14+
"queryStringParameters": null,
15+
"requestContext": {
16+
"accountId": "123456789012",
17+
"apiId": "api-id",
18+
"authentication": {
19+
"clientCert": {
20+
"clientCertPem": "CERT_CONTENT",
21+
"subjectDN": "www.example.com",
22+
"issuerDN": "Example issuer",
23+
"serialNumber": "a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1",
24+
"validity": {
25+
"notBefore": "May 28 12:30:02 2019 GMT",
26+
"notAfter": "Aug 5 09:36:04 2021 GMT"
27+
}
28+
}
29+
},
30+
"domainName": "id.execute-api.us-east-1.amazonaws.com",
31+
"domainPrefix": "id",
32+
"http": {
33+
"method": "POST",
34+
"path": "/my/path",
35+
"protocol": "HTTP/1.1",
36+
"sourceIp": "IP",
37+
"userAgent": "agent"
38+
},
39+
"requestId": "id",
40+
"routeKey": "$default",
41+
"stage": "$default",
42+
"time": "12/Mar/2020:19:03:58 +0000",
43+
"timeEpoch": 1583348638390
44+
},
45+
"pathParameters": null,
46+
"stageVariables": null
47+
}
48+
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"version": "1",
3+
"triggerSource": "UserMigration_Authentication",
4+
"region": "<region>",
5+
"userPoolId": "<userPoolId>",
6+
"userName": "<userName>",
7+
"callerContext": {
8+
"awsSdkVersion": "<calling aws sdk with version>",
9+
"clientId": "<apps client id>"
10+
},
11+
"request": {
12+
"password": "<password>",
13+
"validationData": {
14+
"exampleMetadataKey": "example metadata value"
15+
},
16+
"clientMetadata": {
17+
"exampleMetadataKey": "example metadata value"
18+
}
19+
},
20+
"response": {
21+
"userAttributes": null,
22+
"finalUserStatus": "<final_user_status>",
23+
"messageAction": "<message-action>",
24+
"desiredDeliveryMediums": [
25+
"<desired-delivery-mediums-1>",
26+
"<desired-delivery-mediums-2>"
27+
],
28+
"forceAliasCreation": null
29+
}
30+
}
31+
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
{
2+
"version": "1",
3+
"triggerSource": "TokenGeneration_HostedAuth",
4+
"region": "region",
5+
"userPoolId": "userPoolId",
6+
"userName": "userName",
7+
"callerContext": {
8+
"awsSdkVersion": "calling aws sdk with version",
9+
"clientId": "apps client id"
10+
},
11+
"request": {
12+
"userAttributes": {
13+
"email": "email",
14+
"phone_number": "phone_number"
15+
},
16+
"groupConfiguration": null,
17+
"clientMetadata": {
18+
"exampleMetadataKey": "example metadata value"
19+
}
20+
},
21+
"response": {
22+
"claimsOverrideDetails": {
23+
"claimsToAddOrOverride": {
24+
"attribute_key2": "attribute_value2",
25+
"attribute_key": "attribute_value"
26+
},
27+
"claimsToSuppress": ["email"],
28+
"groupOverrideDetails": {
29+
"groupsToOverride": ["group-A", "group-B", "group-C"],
30+
"iamRolesToOverride": [
31+
"arn:aws:iam::XXXXXXXXXXXX:role/sns_callerA",
32+
"arn:aws:iam::XXXXXXXXX:role/sns_callerB",
33+
"arn:aws:iam::XXXXXXXXXX:role/sns_callerC"
34+
],
35+
"preferredRole": "arn:aws:iam::XXXXXXXXXXX:role/sns_caller"
36+
}
37+
}
38+
}
39+
}

0 commit comments

Comments
 (0)