@@ -63,6 +63,374 @@ describe('backbeat routes for replication', () => {
6363 await dstS3 . deleteBucket ( { Bucket : bucketDestination } ) . promise ( ) ;
6464 } ) ;
6565
66+ it ( 'should successfully replicate a version' , done => {
67+ let objMD ;
68+ let versionId ;
69+
70+ async . series ( {
71+ enableVersioningSource : next => srcS3 . putBucketVersioning (
72+ { Bucket : bucketSource , VersioningConfiguration : { Status : 'Enabled' } } , next ) ,
73+ putObject : next => srcS3 . putObject (
74+ { Bucket : bucketSource , Key : keyName , Body : new Buffer ( testData ) } , ( err , data ) => {
75+ if ( err ) {
76+ return next ( err ) ;
77+ }
78+ versionId = data . VersionId ;
79+ return next ( ) ;
80+ } ) ,
81+ enableVersioningDestination : next => dstS3 . putBucketVersioning (
82+ { Bucket : bucketDestination , VersioningConfiguration : { Status : 'Enabled' } } , next ) ,
83+ getMetadata : next => makeBackbeatRequest ( {
84+ method : 'GET' ,
85+ resourceType : 'metadata' ,
86+ bucket : bucketSource ,
87+ objectKey : keyName ,
88+ queryObj : {
89+ versionId,
90+ } ,
91+ authCredentials : sourceAuthCredentials ,
92+ } , ( err , data ) => {
93+ if ( err ) {
94+ return next ( err ) ;
95+ }
96+ // Backbeat updates account info in metadata
97+ // to the destination account info
98+ objMD = objectMDFromRequestBody ( data )
99+ . setOwnerDisplayName ( dstAccountInfo . name )
100+ . setOwnerId ( dstAccountInfo . canonicalID )
101+ . getSerialized ( ) ;
102+ return next ( ) ;
103+ } ) ,
104+ replicateMetadata : next => makeBackbeatRequest ( {
105+ method : 'PUT' ,
106+ resourceType : 'metadata' ,
107+ bucket : bucketDestination ,
108+ objectKey : keyName ,
109+ queryObj : {
110+ versionId,
111+ } ,
112+ authCredentials : destinationAuthCredentials ,
113+ requestBody : objMD ,
114+ } , next ) ,
115+ headObject : next => dstS3 . headObject (
116+ { Bucket : bucketDestination , Key : keyName , VersionId : versionId } , next ) ,
117+ listObjectVersions : next => dstS3 . listObjectVersions ( { Bucket : bucketDestination } , next ) ,
118+ } , ( err , results ) => {
119+ if ( err ) {
120+ return done ( err ) ;
121+ }
122+
123+ const headObjectRes = results . headObject ;
124+ assert . strictEqual ( headObjectRes . VersionId , versionId ) ;
125+
126+ const listObjectVersionsRes = results . listObjectVersions ;
127+ const { Versions } = listObjectVersionsRes ;
128+ assert . strictEqual ( Versions . length , 1 ) ;
129+ assert . strictEqual ( Versions [ 0 ] . IsLatest , true ) ;
130+ assert . strictEqual ( Versions [ 0 ] . VersionId , versionId ) ;
131+
132+ return done ( ) ;
133+ } ) ;
134+ } ) ;
135+
136+ it ( 'should successfully replicate a version and update account info' , done => {
137+ let objMD ;
138+ let versionId ;
139+
140+ async . series ( {
141+ enableVersioningSource : next => srcS3 . putBucketVersioning (
142+ { Bucket : bucketSource , VersioningConfiguration : { Status : 'Enabled' } } , next ) ,
143+ putObject : next => srcS3 . putObject (
144+ { Bucket : bucketSource , Key : keyName , Body : new Buffer ( testData ) } , ( err , data ) => {
145+ if ( err ) {
146+ return next ( err ) ;
147+ }
148+ versionId = data . VersionId ;
149+ return next ( ) ;
150+ } ) ,
151+ enableVersioningDestination : next => dstS3 . putBucketVersioning (
152+ { Bucket : bucketDestination , VersioningConfiguration : { Status : 'Enabled' } } , next ) ,
153+ getMetadata : next => makeBackbeatRequest ( {
154+ method : 'GET' ,
155+ resourceType : 'metadata' ,
156+ bucket : bucketSource ,
157+ objectKey : keyName ,
158+ queryObj : {
159+ versionId,
160+ } ,
161+ authCredentials : sourceAuthCredentials ,
162+ } , ( err , data ) => {
163+ if ( err ) {
164+ return next ( err ) ;
165+ }
166+ objMD = objectMDFromRequestBody ( data )
167+ . getSerialized ( ) ;
168+ return next ( ) ;
169+ } ) ,
170+ replicateMetadata : next => makeBackbeatRequest ( {
171+ method : 'PUT' ,
172+ resourceType : 'metadata' ,
173+ bucket : bucketDestination ,
174+ objectKey : keyName ,
175+ queryObj : {
176+ versionId,
177+ // Specifying the account id in the query string
178+ // should make it update the account info in the
179+ // metadata to the destination account info
180+ accountId : dstAccountInfo . shortid ,
181+ } ,
182+ authCredentials : destinationAuthCredentials ,
183+ requestBody : objMD ,
184+ } , next ) ,
185+ getDestinationMetadata : next => makeBackbeatRequest ( {
186+ method : 'GET' ,
187+ resourceType : 'metadata' ,
188+ bucket : bucketDestination ,
189+ objectKey : keyName ,
190+ queryObj : {
191+ versionId,
192+ } ,
193+ authCredentials : destinationAuthCredentials ,
194+ } , ( err , data ) => {
195+ if ( err ) {
196+ return next ( err ) ;
197+ }
198+ return next ( null , objectMDFromRequestBody ( data ) ) ;
199+ } ) ,
200+ } , ( err , results ) => {
201+ if ( err ) {
202+ return done ( err ) ;
203+ }
204+ const dstObjMD = results . getDestinationMetadata ;
205+ assert . strictEqual ( dstObjMD . getOwnerDisplayName ( ) , dstAccountInfo . name ) ;
206+ assert . strictEqual ( dstObjMD . getOwnerId ( ) , dstAccountInfo . canonicalID ) ;
207+ return done ( ) ;
208+ } ) ;
209+ } ) ;
210+
211+ it ( 'should successfully replicate multiple versions and keep original order' , done => {
212+ let objMDCurrent , objMDNonCurrent ;
213+ let versionIdCurrent , versionIdNonCurrent ;
214+
215+ async . series ( {
216+ enableVersioningSource : next => srcS3 . putBucketVersioning (
217+ { Bucket : bucketSource , VersioningConfiguration : { Status : 'Enabled' } } , next ) ,
218+ putObjectNonCurrent : next => srcS3 . putObject (
219+ { Bucket : bucketSource , Key : keyName , Body : new Buffer ( testData ) } , ( err , data ) => {
220+ if ( err ) {
221+ return next ( err ) ;
222+ }
223+ versionIdNonCurrent = data . VersionId ;
224+ return next ( ) ;
225+ } ) ,
226+ putObjectCurrent : next => srcS3 . putObject (
227+ { Bucket : bucketSource , Key : keyName , Body : new Buffer ( testData ) } , ( err , data ) => {
228+ if ( err ) {
229+ return next ( err ) ;
230+ }
231+ versionIdCurrent = data . VersionId ;
232+ return next ( ) ;
233+ } ) ,
234+ enableVersioningDestination : next => dstS3 . putBucketVersioning (
235+ { Bucket : bucketDestination , VersioningConfiguration : { Status : 'Enabled' } } , next ) ,
236+ getMetadataNonCurrent : next => makeBackbeatRequest ( {
237+ method : 'GET' ,
238+ resourceType : 'metadata' ,
239+ bucket : bucketSource ,
240+ objectKey : keyName ,
241+ queryObj : {
242+ versionId : versionIdNonCurrent ,
243+ } ,
244+ authCredentials : sourceAuthCredentials ,
245+ } , ( err , data ) => {
246+ if ( err ) {
247+ return next ( err ) ;
248+ }
249+ // Backbeat updates account info in metadata
250+ // to the destination account info
251+ objMDNonCurrent = objectMDFromRequestBody ( data )
252+ . setOwnerDisplayName ( dstAccountInfo . name )
253+ . setOwnerId ( dstAccountInfo . canonicalID )
254+ . getSerialized ( ) ;
255+ return next ( ) ;
256+ } ) ,
257+ getMetadataCurrent : next => makeBackbeatRequest ( {
258+ method : 'GET' ,
259+ resourceType : 'metadata' ,
260+ bucket : bucketSource ,
261+ objectKey : keyName ,
262+ queryObj : {
263+ versionId : versionIdCurrent ,
264+ } ,
265+ authCredentials : sourceAuthCredentials ,
266+ } , ( err , data ) => {
267+ if ( err ) {
268+ return next ( err ) ;
269+ }
270+ // Backbeat updates account info in metadata
271+ // to the destination account info
272+ objMDCurrent = objectMDFromRequestBody ( data )
273+ . setOwnerDisplayName ( dstAccountInfo . name )
274+ . setOwnerId ( dstAccountInfo . canonicalID )
275+ . getSerialized ( ) ;
276+ return next ( ) ;
277+ } ) ,
278+ // replicating the objects in the reverse order
279+ replicateMetadataCurrent : next => makeBackbeatRequest ( {
280+ method : 'PUT' ,
281+ resourceType : 'metadata' ,
282+ bucket : bucketDestination ,
283+ objectKey : keyName ,
284+ queryObj : {
285+ versionId : versionIdCurrent ,
286+ } ,
287+ authCredentials : destinationAuthCredentials ,
288+ requestBody : objMDCurrent ,
289+ } , next ) ,
290+ replicateMetadataNonCurrent : next => makeBackbeatRequest ( {
291+ method : 'PUT' ,
292+ resourceType : 'metadata' ,
293+ bucket : bucketDestination ,
294+ objectKey : keyName ,
295+ queryObj : {
296+ versionId : versionIdNonCurrent ,
297+ } ,
298+ authCredentials : destinationAuthCredentials ,
299+ requestBody : objMDNonCurrent ,
300+ } , next ) ,
301+ listObjectVersions : next => dstS3 . listObjectVersions ( { Bucket : bucketDestination } , next ) ,
302+ } , ( err , results ) => {
303+ if ( err ) {
304+ return done ( err ) ;
305+ }
306+ const listObjectVersionsRes = results . listObjectVersions ;
307+ const { Versions } = listObjectVersionsRes ;
308+
309+ assert . strictEqual ( Versions . length , 2 ) ;
310+
311+ const [ currentVersion , nonCurrentVersion ] = Versions ;
312+
313+ assert . strictEqual ( currentVersion . IsLatest , true ) ;
314+ assert . strictEqual ( currentVersion . VersionId , versionIdCurrent ) ;
315+
316+ assert . strictEqual ( nonCurrentVersion . IsLatest , false ) ;
317+ assert . strictEqual ( nonCurrentVersion . VersionId , versionIdNonCurrent ) ;
318+
319+ return done ( ) ;
320+ } ) ;
321+ } ) ;
322+
323+ it ( 'should successfully replicate a delete marker' , done => {
324+ let objMDVersion , objMDDeleteMarker ;
325+ let versionIdVersion , versionIdDeleteMarker ;
326+
327+ async . series ( {
328+ enableVersioningSource : next => srcS3 . putBucketVersioning (
329+ { Bucket : bucketSource , VersioningConfiguration : { Status : 'Enabled' } } , next ) ,
330+ putObject : next => srcS3 . putObject (
331+ { Bucket : bucketSource , Key : keyName , Body : new Buffer ( testData ) } , ( err , data ) => {
332+ if ( err ) {
333+ return next ( err ) ;
334+ }
335+ versionIdVersion = data . VersionId ;
336+ return next ( ) ;
337+ } ) ,
338+ deleteObject : next => srcS3 . deleteObject (
339+ { Bucket : bucketSource , Key : keyName } , ( err , data ) => {
340+ if ( err ) {
341+ return next ( err ) ;
342+ }
343+ versionIdDeleteMarker = data . VersionId ;
344+ return next ( ) ;
345+ } ) ,
346+ enableVersioningDestination : next => dstS3 . putBucketVersioning (
347+ { Bucket : bucketDestination , VersioningConfiguration : { Status : 'Enabled' } } , next ) ,
348+ getMetadataVersion : next => makeBackbeatRequest ( {
349+ method : 'GET' ,
350+ resourceType : 'metadata' ,
351+ bucket : bucketSource ,
352+ objectKey : keyName ,
353+ queryObj : {
354+ versionId : versionIdVersion ,
355+ } ,
356+ authCredentials : sourceAuthCredentials ,
357+ } , ( err , data ) => {
358+ if ( err ) {
359+ return next ( err ) ;
360+ }
361+ // Backbeat updates account info in metadata
362+ // to the destination account info
363+ objMDVersion = objectMDFromRequestBody ( data )
364+ . setOwnerDisplayName ( dstAccountInfo . name )
365+ . setOwnerId ( dstAccountInfo . canonicalID )
366+ . getSerialized ( ) ;
367+ return next ( ) ;
368+ } ) ,
369+ replicateMetadataVersion : next => makeBackbeatRequest ( {
370+ method : 'PUT' ,
371+ resourceType : 'metadata' ,
372+ bucket : bucketDestination ,
373+ objectKey : keyName ,
374+ queryObj : {
375+ versionId : versionIdVersion ,
376+ } ,
377+ authCredentials : destinationAuthCredentials ,
378+ requestBody : objMDVersion ,
379+ } , next ) ,
380+ getMetadataDeleteMarker : next => makeBackbeatRequest ( {
381+ method : 'GET' ,
382+ resourceType : 'metadata' ,
383+ bucket : bucketSource ,
384+ objectKey : keyName ,
385+ queryObj : {
386+ versionId : versionIdDeleteMarker ,
387+ } ,
388+ authCredentials : sourceAuthCredentials ,
389+ } , ( err , data ) => {
390+ if ( err ) {
391+ return next ( err ) ;
392+ }
393+ // Backbeat updates account info in metadata
394+ // to the destination account info
395+ objMDDeleteMarker = objectMDFromRequestBody ( data )
396+ . setOwnerDisplayName ( dstAccountInfo . name )
397+ . setOwnerId ( dstAccountInfo . canonicalID )
398+ . getSerialized ( ) ;
399+ return next ( ) ;
400+ } ) ,
401+ replicateMetadataDeleteMarker : next => makeBackbeatRequest ( {
402+ method : 'PUT' ,
403+ resourceType : 'metadata' ,
404+ bucket : bucketDestination ,
405+ objectKey : keyName ,
406+ queryObj : {
407+ versionId : versionIdDeleteMarker ,
408+ } ,
409+ authCredentials : destinationAuthCredentials ,
410+ requestBody : objMDDeleteMarker ,
411+ } , next ) ,
412+ listObjectVersions : next => dstS3 . listObjectVersions ( { Bucket : bucketDestination } , next ) ,
413+ } , ( err , results ) => {
414+ if ( err ) {
415+ return done ( err ) ;
416+ }
417+
418+ const listObjectVersionsRes = results . listObjectVersions ;
419+ const { Versions, DeleteMarkers } = listObjectVersionsRes ;
420+
421+ assert . strictEqual ( Versions . length , 1 ) ;
422+ assert . strictEqual ( DeleteMarkers . length , 1 ) ;
423+
424+ assert . strictEqual ( Versions [ 0 ] . IsLatest , false ) ;
425+ assert . strictEqual ( Versions [ 0 ] . VersionId , versionIdVersion ) ;
426+
427+ assert . strictEqual ( DeleteMarkers [ 0 ] . IsLatest , true ) ;
428+ assert . strictEqual ( DeleteMarkers [ 0 ] . VersionId , versionIdDeleteMarker ) ;
429+
430+ return done ( ) ;
431+ } ) ;
432+ } ) ;
433+
66434 it ( 'should successfully replicate a null version' , done => {
67435 let objMD ;
68436
0 commit comments