@@ -4,98 +4,212 @@ import {
4
4
S3ObjectLambdaEventSchema ,
5
5
S3Schema ,
6
6
S3SqsEventNotificationSchema ,
7
- } from '../../../src/schemas/' ;
8
- import { TestEvents } from './utils.js' ;
7
+ } from '../../../src/schemas/s3.js' ;
8
+ import type {
9
+ S3Event ,
10
+ S3EventNotificationEventBridge ,
11
+ S3ObjectLambdaEvent ,
12
+ S3SqsEventNotification ,
13
+ } from '../../../src/types/schema.js' ;
14
+ import { getTestEvent , omit } from './utils.js' ;
9
15
10
- describe ( 'S3 ' , ( ) => {
11
- it ( 'should parse s3 event' , ( ) => {
12
- const s3Event = TestEvents . s3Event ;
16
+ describe ( 'Schema: S3' , ( ) => {
17
+ const eventsPath = 's3' ;
18
+ const baseEvent = getTestEvent < S3Event > ( {
19
+ eventsPath,
20
+ filename : 'base' ,
21
+ } ) ;
22
+ const baseLambdaEvent = getTestEvent < S3ObjectLambdaEvent > ( {
23
+ eventsPath,
24
+ filename : 'object-iam-user' ,
25
+ } ) ;
26
+
27
+ it ( 'parses an S3 event' , ( ) => {
28
+ // Prepare
29
+ const event = structuredClone ( baseEvent ) ;
13
30
14
- expect ( S3Schema . parse ( s3Event ) ) . toEqual ( s3Event ) ;
31
+ // Act
32
+ const result = S3Schema . parse ( event ) ;
33
+
34
+ // Assess
35
+ expect ( result ) . toStrictEqual ( event ) ;
15
36
} ) ;
16
37
17
- it ( 'should parse s3 event bridge notification event created' , ( ) => {
18
- const s3EventBridgeNotificationObjectCreatedEvent =
19
- TestEvents . s3EventBridgeNotificationObjectCreatedEvent ;
38
+ it ( 'throws if the event is not an S3 event' , ( ) => {
39
+ // Prepare
40
+ const event = {
41
+ Records : [ ] ,
42
+ } ;
20
43
21
- expect (
22
- S3EventNotificationEventBridgeSchema . parse (
23
- s3EventBridgeNotificationObjectCreatedEvent
24
- )
25
- ) . toEqual ( s3EventBridgeNotificationObjectCreatedEvent ) ;
44
+ // Act & Assess
45
+ expect ( ( ) => S3Schema . parse ( event ) ) . toThrow ( ) ;
26
46
} ) ;
27
47
28
- it ( 'should parse s3 event bridge notification event detelted' , ( ) => {
29
- const s3EventBridgeNotificationObjectDeletedEvent =
30
- TestEvents . s3EventBridgeNotificationObjectDeletedEvent ;
48
+ it ( 'throws if the event is missing required fields' , ( ) => {
49
+ // Prepare
50
+ const event = structuredClone ( baseEvent ) ;
51
+ // @ts -expect-error - Intentionally remove required field
52
+ event . Records [ 0 ] . s3 . bucket . name = undefined ;
31
53
32
- expect (
33
- S3EventNotificationEventBridgeSchema . parse (
34
- s3EventBridgeNotificationObjectDeletedEvent
35
- )
36
- ) . toEqual ( s3EventBridgeNotificationObjectDeletedEvent ) ;
54
+ // Act & Assess
55
+ expect ( ( ) => S3Schema . parse ( event ) ) . toThrow ( ) ;
37
56
} ) ;
38
- it ( 'should parse s3 event bridge notification event expired' , ( ) => {
39
- const s3EventBridgeNotificationObjectExpiredEvent =
40
- TestEvents . s3EventBridgeNotificationObjectExpiredEvent ;
41
57
42
- expect (
43
- S3EventNotificationEventBridgeSchema . parse (
44
- s3EventBridgeNotificationObjectExpiredEvent
45
- )
46
- ) . toEqual ( s3EventBridgeNotificationObjectExpiredEvent ) ;
58
+ it ( 'parses an S3 Glacier event' , ( ) => {
59
+ // Prepare
60
+ const event = getTestEvent < S3Event > ( {
61
+ eventsPath,
62
+ filename : 'glacier' ,
63
+ } ) ;
64
+
65
+ // Act
66
+ const result = S3Schema . parse ( event ) ;
67
+
68
+ // Assess
69
+ expect ( result ) . toStrictEqual ( event ) ;
70
+ } ) ;
71
+
72
+ it ( 'parses an S3 event with a decoded key' , ( ) => {
73
+ // Prepare
74
+ const event = getTestEvent < S3Event > ( {
75
+ eventsPath,
76
+ filename : 'decoded-key' ,
77
+ } ) ;
78
+
79
+ // Act
80
+ const result = S3Schema . parse ( event ) ;
81
+
82
+ // Assess
83
+ expect ( result ) . toStrictEqual ( event ) ;
47
84
} ) ;
48
85
49
- it ( 'should parse s3 sqs notification event' , ( ) => {
50
- const s3SqsEvent = TestEvents . s3SqsEvent ;
51
- expect ( S3SqsEventNotificationSchema . parse ( s3SqsEvent ) ) . toEqual ( s3SqsEvent ) ;
86
+ it ( 'parses an S3 event with a deleted object' , ( ) => {
87
+ // Prepare
88
+ const event = getTestEvent < S3Event > ( {
89
+ eventsPath,
90
+ filename : 'delete-object' ,
91
+ } ) ;
92
+
93
+ // Act
94
+ const result = S3Schema . parse ( event ) ;
95
+
96
+ // Assess
97
+ expect ( result ) . toStrictEqual ( event ) ;
52
98
} ) ;
53
99
54
- it ( 'should parse s3 event with decoded key' , ( ) => {
55
- const s3EventDecodedKey = TestEvents . s3EventDecodedKey ;
56
- expect ( S3Schema . parse ( s3EventDecodedKey ) ) . toEqual ( s3EventDecodedKey ) ;
100
+ it ( 'parses an S3 Object Lambda with an IAM user' , ( ) => {
101
+ // Prepare
102
+ const event = structuredClone ( baseLambdaEvent ) ;
103
+
104
+ // Act
105
+ const result = S3ObjectLambdaEventSchema . parse ( event ) ;
106
+
107
+ // Assess
108
+ expect ( result ) . toStrictEqual ( event ) ;
57
109
} ) ;
58
110
59
- it ( 'should parse s3 event delete object' , ( ) => {
60
- const s3EventDeleteObject = TestEvents . s3EventDeleteObject ;
61
- expect ( S3Schema . parse ( s3EventDeleteObject ) ) . toEqual ( s3EventDeleteObject ) ;
111
+ it ( 'throws if the S3 Object Lambda event is missing required fields' , ( ) => {
112
+ // Prepare
113
+ const event = omit ( [ 'getObjectContext' ] , structuredClone ( baseLambdaEvent ) ) ;
114
+
115
+ // Act & Assess
116
+ expect ( ( ) => S3ObjectLambdaEventSchema . parse ( event ) ) . toThrow ( ) ;
62
117
} ) ;
63
118
64
- it ( 'should parse s3 event glacier' , ( ) => {
65
- const s3EventGlacier = TestEvents . s3EventGlacier ;
66
- expect ( S3Schema . parse ( s3EventGlacier ) ) . toEqual ( s3EventGlacier ) ;
119
+ it ( 'parses an S3 Object Lambda with temporary credentials' , ( ) => {
120
+ // Prepare
121
+ const event = getTestEvent < S3ObjectLambdaEvent > ( {
122
+ eventsPath,
123
+ filename : 'object-temp-credentials' ,
124
+ } ) ;
125
+ const expected = structuredClone ( event ) ;
126
+ // @ts -expect-error - Modifying the expected result to account for type coercion
127
+ expected . userIdentity . sessionContext . attributes . mfaAuthenticated = false ;
128
+
129
+ // Act
130
+ const result = S3ObjectLambdaEventSchema . parse ( event ) ;
131
+
132
+ // Assess
133
+ expect ( result ) . toStrictEqual ( expected ) ;
67
134
} ) ;
68
135
69
- it ( 'should parse s3 object event iam user' , ( ) => {
70
- const s3ObjectEventIAMUser = TestEvents . s3ObjectEventIAMUser ;
71
- expect ( S3ObjectLambdaEventSchema . parse ( s3ObjectEventIAMUser ) ) . toEqual (
72
- s3ObjectEventIAMUser
73
- ) ;
136
+ it ( 'parses an S3 Object Notification EventBridge event' , ( ) => {
137
+ // Prepare
138
+ const event = getTestEvent < S3EventNotificationEventBridge > ( {
139
+ eventsPath,
140
+ filename : 'eventbridge-object-created' ,
141
+ } ) ;
142
+
143
+ // Act
144
+ const result = S3EventNotificationEventBridgeSchema . parse ( event ) ;
145
+
146
+ // Assess
147
+ expect ( result ) . toStrictEqual ( event ) ;
148
+ } ) ;
149
+
150
+ it ( 'parses an S3 Object Notification EventBridge event for an object deleted' , ( ) => {
151
+ // Prepare
152
+ const event = getTestEvent < S3EventNotificationEventBridge > ( {
153
+ eventsPath,
154
+ filename : 'eventbridge-object-deleted' ,
155
+ } ) ;
156
+
157
+ // Act
158
+ const result = S3EventNotificationEventBridgeSchema . parse ( event ) ;
159
+
160
+ // Assess
161
+ expect ( result ) . toStrictEqual ( event ) ;
162
+ } ) ;
163
+
164
+ it ( 'parses an S3 Object Notification EventBridge event for an object expired' , ( ) => {
165
+ // Prepare
166
+ const event = getTestEvent < S3EventNotificationEventBridge > ( {
167
+ eventsPath,
168
+ filename : 'eventbridge-object-expired' ,
169
+ } ) ;
170
+
171
+ // Act
172
+ const result = S3EventNotificationEventBridgeSchema . parse ( event ) ;
173
+
174
+ // Assess
175
+ expect ( result ) . toStrictEqual ( event ) ;
176
+ } ) ;
177
+
178
+ it ( 'parses an S3 Object Notification EventBridge event for an object restored' , ( ) => {
179
+ // Prepare
180
+ const event = getTestEvent < S3EventNotificationEventBridge > ( {
181
+ eventsPath,
182
+ filename : 'eventbridge-object-restored' ,
183
+ } ) ;
184
+
185
+ // Act
186
+ const result = S3EventNotificationEventBridgeSchema . parse ( event ) ;
187
+
188
+ // Assess
189
+ expect ( result ) . toStrictEqual ( event ) ;
190
+ } ) ;
191
+
192
+ it ( 'parses an S3 event notification SQS event' , ( ) => {
193
+ // Prepare
194
+ const event = getTestEvent < S3SqsEventNotification > ( {
195
+ eventsPath,
196
+ filename : 'sqs-event' ,
197
+ } ) ;
198
+
199
+ // Prepare
200
+ const result = S3SqsEventNotificationSchema . parse ( event ) ;
201
+
202
+ // Assess
203
+ expect ( result ) . toStrictEqual ( event ) ;
74
204
} ) ;
75
205
76
- it ( 'should parse s3 object event temp credentials' , ( ) => {
77
- // ignore any because we don't want typed json
78
- const s3ObjectEventTempCredentials =
79
- // biome-ignore lint/suspicious/noExplicitAny: no specific typing needed
80
- TestEvents . s3ObjectEventTempCredentials as any ;
81
- const parsed = S3ObjectLambdaEventSchema . parse (
82
- s3ObjectEventTempCredentials
83
- ) ;
206
+ it ( 'throws if the S3 event notification SQS event is not valid' , ( ) => {
207
+ // Prepare
208
+ const event = {
209
+ Records : [ ] ,
210
+ } ;
84
211
85
- expect ( parsed . userRequest ) . toEqual (
86
- s3ObjectEventTempCredentials . userRequest
87
- ) ;
88
- expect ( parsed . getObjectContext ) . toEqual (
89
- s3ObjectEventTempCredentials . getObjectContext
90
- ) ;
91
- expect ( parsed . configuration ) . toEqual (
92
- s3ObjectEventTempCredentials . configuration
93
- ) ;
94
- expect ( parsed . userRequest ) . toEqual (
95
- s3ObjectEventTempCredentials . userRequest
96
- ) ;
97
- expect (
98
- parsed . userIdentity ?. sessionContext ?. attributes . mfaAuthenticated
99
- ) . toEqual ( false ) ;
212
+ // Act & Assess
213
+ expect ( ( ) => S3SqsEventNotificationSchema . parse ( event ) ) . toThrow ( ) ;
100
214
} ) ;
101
215
} ) ;
0 commit comments