@@ -23,12 +23,12 @@ def setUp(self):
23
23
24
24
def test_invalid_request (self ):
25
25
resp = invoke_handler ("Create" , {}, expected_status = "FAILED" )
26
- self .assertEqual (resp ["Reason" ], "missing request resource property 'SourceBucketName '. props: {}" )
26
+ self .assertEqual (resp ["Reason" ], "missing request resource property 'SourceBucketNames '. props: {}" )
27
27
28
28
def test_create_update (self ):
29
29
invoke_handler ("Create" , {
30
- "SourceBucketName " : "<source-bucket>" ,
31
- "SourceObjectKey " : "<source-object-key>" ,
30
+ "SourceBucketNames " : [ "<source-bucket>" ] ,
31
+ "SourceObjectKeys " : [ "<source-object-key>" ] ,
32
32
"DestinationBucketName" : "<dest-bucket-name>"
33
33
})
34
34
@@ -37,10 +37,25 @@ def test_create_update(self):
37
37
"s3 sync --delete contents.zip s3://<dest-bucket-name>/"
38
38
)
39
39
40
+ def test_create_update_multiple_sources (self ):
41
+ invoke_handler ("Create" , {
42
+ "SourceBucketNames" : ["<source-bucket1>" , "<source-bucket2>" ],
43
+ "SourceObjectKeys" : ["<source-object-key1>" , "<source-object-key2>" ],
44
+ "DestinationBucketName" : "<dest-bucket-name>"
45
+ })
46
+
47
+ # Note: these are different files in real-life. For testing purposes, we hijack
48
+ # the command to output a static filename, archive.zip
49
+ self .assertAwsCommands (
50
+ "s3 cp s3://<source-bucket1>/<source-object-key1> archive.zip" ,
51
+ "s3 cp s3://<source-bucket2>/<source-object-key2> archive.zip" ,
52
+ "s3 sync --delete contents.zip s3://<dest-bucket-name>/"
53
+ )
54
+
40
55
def test_create_with_backslash_prefix_same_as_no_prefix (self ):
41
56
invoke_handler ("Create" , {
42
- "SourceBucketName " : "<source-bucket>" ,
43
- "SourceObjectKey " : "<source-object-key>" ,
57
+ "SourceBucketNames " : [ "<source-bucket>" ] ,
58
+ "SourceObjectKeys " : [ "<source-object-key>" ] ,
44
59
"DestinationBucketName" : "<dest-bucket-name>" ,
45
60
"DestinationBucketKeyPrefix" : "/"
46
61
})
@@ -53,8 +68,8 @@ def test_create_with_backslash_prefix_same_as_no_prefix(self):
53
68
54
69
def test_create_update_with_dest_key (self ):
55
70
invoke_handler ("Create" , {
56
- "SourceBucketName " : "<source-bucket>" ,
57
- "SourceObjectKey " : "<source-object-key>" ,
71
+ "SourceBucketNames " : [ "<source-bucket>" ] ,
72
+ "SourceObjectKeys " : [ "<source-object-key>" ] ,
58
73
"DestinationBucketName" : "<dest-bucket-name>" ,
59
74
"DestinationBucketKeyPrefix" : "<dest-key-prefix>"
60
75
})
@@ -66,8 +81,8 @@ def test_create_update_with_dest_key(self):
66
81
67
82
def test_delete_no_retain (self ):
68
83
invoke_handler ("Delete" , {
69
- "SourceBucketName " : "<source-bucket>" ,
70
- "SourceObjectKey " : "<source-object-key>" ,
84
+ "SourceBucketNames " : [ "<source-bucket>" ] ,
85
+ "SourceObjectKeys " : [ "<source-object-key>" ] ,
71
86
"DestinationBucketName" : "<dest-bucket-name>" ,
72
87
"RetainOnDelete" : "false"
73
88
}, physical_id = "<physicalid>" )
@@ -76,8 +91,8 @@ def test_delete_no_retain(self):
76
91
77
92
def test_delete_with_dest_key (self ):
78
93
invoke_handler ("Delete" , {
79
- "SourceBucketName " : "<source-bucket>" ,
80
- "SourceObjectKey " : "<source-object-key>" ,
94
+ "SourceBucketNames " : [ "<source-bucket>" ] ,
95
+ "SourceObjectKeys " : [ "<source-object-key>" ] ,
81
96
"DestinationBucketName" : "<dest-bucket-name>" ,
82
97
"DestinationBucketKeyPrefix" : "<dest-key-prefix>" ,
83
98
"RetainOnDelete" : "false"
@@ -87,8 +102,8 @@ def test_delete_with_dest_key(self):
87
102
88
103
def test_delete_with_retain_explicit (self ):
89
104
invoke_handler ("Delete" , {
90
- "SourceBucketName " : "<source-bucket>" ,
91
- "SourceObjectKey " : "<source-object-key>" ,
105
+ "SourceBucketNames " : [ "<source-bucket>" ] ,
106
+ "SourceObjectKeys " : [ "<source-object-key>" ] ,
92
107
"DestinationBucketName" : "<dest-bucket-name>" ,
93
108
"RetainOnDelete" : "true"
94
109
}, physical_id = "<physicalid>" )
@@ -99,8 +114,8 @@ def test_delete_with_retain_explicit(self):
99
114
# RetainOnDelete=true is the default
100
115
def test_delete_with_retain_implicit_default (self ):
101
116
invoke_handler ("Delete" , {
102
- "SourceBucketName " : "<source-bucket>" ,
103
- "SourceObjectKey " : "<source-object-key>" ,
117
+ "SourceBucketNames " : [ "<source-bucket>" ] ,
118
+ "SourceObjectKeys " : [ "<source-object-key>" ] ,
104
119
"DestinationBucketName" : "<dest-bucket-name>"
105
120
}, physical_id = "<physicalid>" )
106
121
@@ -109,8 +124,8 @@ def test_delete_with_retain_implicit_default(self):
109
124
110
125
def test_delete_with_retain_explicitly_false (self ):
111
126
invoke_handler ("Delete" , {
112
- "SourceBucketName " : "<source-bucket>" ,
113
- "SourceObjectKey " : "<source-object-key>" ,
127
+ "SourceBucketNames " : [ "<source-bucket>" ] ,
128
+ "SourceObjectKeys " : [ "<source-object-key>" ] ,
114
129
"DestinationBucketName" : "<dest-bucket-name>" ,
115
130
"RetainOnDelete" : "false"
116
131
}, physical_id = "<physicalid>" )
@@ -125,8 +140,8 @@ def test_delete_with_retain_explicitly_false(self):
125
140
126
141
def test_update_same_dest (self ):
127
142
invoke_handler ("Update" , {
128
- "SourceBucketName " : "<source-bucket>" ,
129
- "SourceObjectKey " : "<source-object-key>" ,
143
+ "SourceBucketNames " : [ "<source-bucket>" ] ,
144
+ "SourceObjectKeys " : [ "<source-object-key>" ] ,
130
145
"DestinationBucketName" : "<dest-bucket-name>" ,
131
146
}, old_resource_props = {
132
147
"DestinationBucketName" : "<dest-bucket-name>" ,
@@ -150,8 +165,8 @@ def mock_make_api_call(self, operation_name, kwarg):
150
165
151
166
with patch ('botocore.client.BaseClient._make_api_call' , new = mock_make_api_call ):
152
167
invoke_handler ("Update" , {
153
- "SourceBucketName " : "<source-bucket>" ,
154
- "SourceObjectKey " : "<source-object-key>" ,
168
+ "SourceBucketNames " : [ "<source-bucket>" ] ,
169
+ "SourceObjectKeys " : [ "<source-object-key>" ] ,
155
170
"DestinationBucketName" : "<dest-bucket-name>" ,
156
171
"DistributionId" : "<cf-dist-id>"
157
172
}, old_resource_props = {
@@ -171,8 +186,8 @@ def mock_make_api_call(self, operation_name, kwarg):
171
186
172
187
with patch ('botocore.client.BaseClient._make_api_call' , new = mock_make_api_call ):
173
188
invoke_handler ("Update" , {
174
- "SourceBucketName " : "<source-bucket>" ,
175
- "SourceObjectKey " : "<source-object-key>" ,
189
+ "SourceBucketNames " : [ "<source-bucket>" ] ,
190
+ "SourceObjectKeys " : [ "<source-object-key>" ] ,
176
191
"DestinationBucketName" : "<dest-bucket-name>" ,
177
192
"DestinationBucketKeyPrefix" : "<dest-prefix>" ,
178
193
"DistributionId" : "<cf-dist-id>"
@@ -194,8 +209,8 @@ def mock_make_api_call(self, operation_name, kwarg):
194
209
195
210
with patch ('botocore.client.BaseClient._make_api_call' , new = mock_make_api_call ):
196
211
invoke_handler ("Update" , {
197
- "SourceBucketName " : "<source-bucket>" ,
198
- "SourceObjectKey " : "<source-object-key>" ,
212
+ "SourceBucketNames " : [ "<source-bucket>" ] ,
213
+ "SourceObjectKeys " : [ "<source-object-key>" ] ,
199
214
"DestinationBucketName" : "<dest-bucket-name>" ,
200
215
"DistributionId" : "<cf-dist-id>" ,
201
216
"DistributionPaths" : ["/path1/*" , "/path2/*" ]
@@ -205,8 +220,8 @@ def mock_make_api_call(self, operation_name, kwarg):
205
220
206
221
def test_update_new_dest_retain (self ):
207
222
invoke_handler ("Update" , {
208
- "SourceBucketName " : "<source-bucket>" ,
209
- "SourceObjectKey " : "<source-object-key>" ,
223
+ "SourceBucketNames " : [ "<source-bucket>" ] ,
224
+ "SourceObjectKeys " : [ "<source-object-key>" ] ,
210
225
"DestinationBucketName" : "<dest-bucket-name>" ,
211
226
}, old_resource_props = {
212
227
"DestinationBucketName" : "<dest-bucket-name>" ,
@@ -220,8 +235,8 @@ def test_update_new_dest_retain(self):
220
235
221
236
def test_update_new_dest_no_retain (self ):
222
237
invoke_handler ("Update" , {
223
- "SourceBucketName " : "<source-bucket>" ,
224
- "SourceObjectKey " : "<source-object-key>" ,
238
+ "SourceBucketNames " : [ "<source-bucket>" ] ,
239
+ "SourceObjectKeys " : [ "<source-object-key>" ] ,
225
240
"DestinationBucketName" : "<new-dest-bucket-name>" ,
226
241
"RetainOnDelete" : "false"
227
242
}, old_resource_props = {
@@ -238,8 +253,8 @@ def test_update_new_dest_no_retain(self):
238
253
239
254
def test_update_new_dest_retain_implicit (self ):
240
255
invoke_handler ("Update" , {
241
- "SourceBucketName " : "<source-bucket>" ,
242
- "SourceObjectKey " : "<source-object-key>" ,
256
+ "SourceBucketNames " : [ "<source-bucket>" ] ,
257
+ "SourceObjectKeys " : [ "<source-object-key>" ] ,
243
258
"DestinationBucketName" : "<new-dest-bucket-name>" ,
244
259
}, old_resource_props = {
245
260
"DestinationBucketName" : "<old-dest-bucket-name>" ,
@@ -253,8 +268,8 @@ def test_update_new_dest_retain_implicit(self):
253
268
254
269
def test_update_new_dest_prefix_no_retain (self ):
255
270
invoke_handler ("Update" , {
256
- "SourceBucketName " : "<source-bucket>" ,
257
- "SourceObjectKey " : "<source-object-key>" ,
271
+ "SourceBucketNames " : [ "<source-bucket>" ] ,
272
+ "SourceObjectKeys " : [ "<source-object-key>" ] ,
258
273
"DestinationBucketName" : "<dest-bucket-name>" ,
259
274
"DestinationBucketKeyPrefix" : "<new-dest-prefix>" ,
260
275
"RetainOnDelete" : "false"
@@ -271,8 +286,8 @@ def test_update_new_dest_prefix_no_retain(self):
271
286
272
287
def test_update_new_dest_prefix_retain_implicit (self ):
273
288
invoke_handler ("Update" , {
274
- "SourceBucketName " : "<source-bucket>" ,
275
- "SourceObjectKey " : "<source-object-key>" ,
289
+ "SourceBucketNames " : [ "<source-bucket>" ] ,
290
+ "SourceObjectKeys " : [ "<source-object-key>" ] ,
276
291
"DestinationBucketName" : "<dest-bucket-name>" ,
277
292
"DestinationBucketKeyPrefix" : "<new-dest-prefix>"
278
293
}, old_resource_props = {
@@ -290,8 +305,8 @@ def test_update_new_dest_prefix_retain_implicit(self):
290
305
291
306
def test_physical_id_allocated_on_create_and_reused_afterwards (self ):
292
307
create_resp = invoke_handler ("Create" , {
293
- "SourceBucketName " : "<source-bucket>" ,
294
- "SourceObjectKey " : "<source-object-key>" ,
308
+ "SourceBucketNames " : [ "<source-bucket>" ] ,
309
+ "SourceObjectKeys " : [ "<source-object-key>" ] ,
295
310
"DestinationBucketName" : "<dest-bucket-name>" ,
296
311
})
297
312
@@ -301,8 +316,8 @@ def test_physical_id_allocated_on_create_and_reused_afterwards(self):
301
316
# now issue an update and pass in the physical id. expect the same
302
317
# one to be returned back
303
318
update_resp = invoke_handler ("Update" , {
304
- "SourceBucketName " : "<source-bucket>" ,
305
- "SourceObjectKey " : "<source-object-key>" ,
319
+ "SourceBucketNames " : [ "<source-bucket>" ] ,
320
+ "SourceObjectKeys " : [ "<source-object-key>" ] ,
306
321
"DestinationBucketName" : "<new-dest-bucket-name>" ,
307
322
}, old_resource_props = {
308
323
"DestinationBucketName" : "<dest-bucket-name>" ,
@@ -311,17 +326,17 @@ def test_physical_id_allocated_on_create_and_reused_afterwards(self):
311
326
312
327
# now issue a delete, and make sure this also applies
313
328
delete_resp = invoke_handler ("Delete" , {
314
- "SourceBucketName " : "<source-bucket>" ,
315
- "SourceObjectKey " : "<source-object-key>" ,
329
+ "SourceBucketNames " : [ "<source-bucket>" ] ,
330
+ "SourceObjectKeys " : [ "<source-object-key>" ] ,
316
331
"DestinationBucketName" : "<dest-bucket-name>" ,
317
332
"RetainOnDelete" : "false"
318
333
}, physical_id = phid )
319
334
self .assertEqual (delete_resp ['PhysicalResourceId' ], phid )
320
335
321
336
def test_fails_when_physical_id_not_present_in_update (self ):
322
337
update_resp = invoke_handler ("Update" , {
323
- "SourceBucketName " : "<source-bucket>" ,
324
- "SourceObjectKey " : "<source-object-key>" ,
338
+ "SourceBucketNames " : [ "<source-bucket>" ] ,
339
+ "SourceObjectKeys " : [ "<source-object-key>" ] ,
325
340
"DestinationBucketName" : "<new-dest-bucket-name>" ,
326
341
}, old_resource_props = {
327
342
"DestinationBucketName" : "<dest-bucket-name>" ,
@@ -331,8 +346,8 @@ def test_fails_when_physical_id_not_present_in_update(self):
331
346
332
347
def test_fails_when_physical_id_not_present_in_delete (self ):
333
348
update_resp = invoke_handler ("Delete" , {
334
- "SourceBucketName " : "<source-bucket>" ,
335
- "SourceObjectKey " : "<source-object-key>" ,
349
+ "SourceBucketNames " : [ "<source-bucket>" ] ,
350
+ "SourceObjectKeys " : [ "<source-object-key>" ] ,
336
351
"DestinationBucketName" : "<new-dest-bucket-name>" ,
337
352
}, old_resource_props = {
338
353
"DestinationBucketName" : "<dest-bucket-name>" ,
0 commit comments