@@ -151,6 +151,8 @@ mocha.describe('nsfs_glacier', function() {
151
151
mocha . describe ( 'nsfs_glacier_tapecloud' , async function ( ) {
152
152
const upload_key = 'upload_key_1' ;
153
153
const restore_key = 'restore_key_1' ;
154
+ const restore_key_spcl_char_1 = 'restore_key_2_\n' ;
155
+ const restore_key_spcl_char_2 = 'restore_key_2_\n_2' ;
154
156
const xattr = { key : 'value' , key2 : 'value2' } ;
155
157
xattr [ s3_utils . XATTR_SORT_SYMBOL ] = true ;
156
158
@@ -267,10 +269,140 @@ mocha.describe('nsfs_glacier', function() {
267
269
failure_backend . _process_expired = async ( ) => { /**noop*/ } ;
268
270
failure_backend . _recall = async ( _file , failure_recorder , success_recorder ) => {
269
271
// This unintentionally also replicates duplicate entries in WAL
270
- await failure_recorder ( failed_file_path ) ;
272
+ await failure_recorder ( failure_backend . encode_log ( failed_file_path ) ) ;
271
273
272
274
// This unintentionally also replicates duplicate entries in WAL
273
- await success_recorder ( success_file_path ) ;
275
+ await success_recorder ( failure_backend . encode_log ( success_file_path ) ) ;
276
+
277
+ return false ;
278
+ } ;
279
+
280
+ const upload_res_1 = await glacier_ns . upload_object ( failed_params , dummy_object_sdk ) ;
281
+ console . log ( 'upload_object response' , inspect ( upload_res_1 ) ) ;
282
+
283
+ const upload_res_2 = await glacier_ns . upload_object ( success_params , dummy_object_sdk ) ;
284
+ console . log ( 'upload_object response' , inspect ( upload_res_2 ) ) ;
285
+
286
+ const restore_res_1 = await glacier_ns . restore_object ( failed_params , dummy_object_sdk ) ;
287
+ assert ( restore_res_1 ) ;
288
+
289
+ const restore_res_2 = await glacier_ns . restore_object ( success_params , dummy_object_sdk ) ;
290
+ assert ( restore_res_2 ) ;
291
+
292
+ const fs_context = glacier_ns . prepare_fs_context ( dummy_object_sdk ) ;
293
+
294
+ // Issue restore
295
+ await NamespaceFS . restore_wal . _process ( async file => {
296
+ await failure_backend . restore ( fs_context , file , async ( ) => { /*noop*/ } ) ;
297
+
298
+ // Don't delete the file
299
+ return false ;
300
+ } ) ;
301
+
302
+ // Ensure success object is restored
303
+ const success_md = await glacier_ns . read_object_md ( success_params , dummy_object_sdk ) ;
304
+
305
+ assert ( ! success_md . restore_status . ongoing ) ;
306
+
307
+ const expected_expiry = Glacier . generate_expiry ( new Date ( ) , success_params . days , '' , config . NSFS_GLACIER_EXPIRY_TZ ) ;
308
+ assert ( expected_expiry . getTime ( ) >= success_md . restore_status . expiry_time . getTime ( ) ) ;
309
+ assert ( now <= success_md . restore_status . expiry_time . getTime ( ) ) ;
310
+
311
+ // Ensure failed object is NOT restored
312
+ const failure_stats = await nb_native ( ) . fs . stat (
313
+ fs_context ,
314
+ failed_file_path ,
315
+ ) ;
316
+
317
+ assert ( ! failure_stats . xattr [ Glacier . XATTR_RESTORE_EXPIRY ] || failure_stats . xattr [ Glacier . XATTR_RESTORE_EXPIRY ] === '' ) ;
318
+ assert ( failure_stats . xattr [ Glacier . XATTR_RESTORE_REQUEST ] ) ;
319
+ } ) ;
320
+
321
+ mocha . it ( 'restore-object should successfully restore objects with special characters' , async function ( ) {
322
+ const now = Date . now ( ) ;
323
+ const data = crypto . randomBytes ( 100 ) ;
324
+ const all_params = [
325
+ {
326
+ bucket : upload_bkt ,
327
+ key : restore_key_spcl_char_1 ,
328
+ storage_class : s3_utils . STORAGE_CLASS_GLACIER ,
329
+ xattr,
330
+ days : 1 ,
331
+ source_stream : buffer_utils . buffer_to_read_stream ( data )
332
+ } ,
333
+ {
334
+ bucket : upload_bkt ,
335
+ key : restore_key_spcl_char_2 ,
336
+ storage_class : s3_utils . STORAGE_CLASS_GLACIER ,
337
+ xattr,
338
+ days : 1 ,
339
+ source_stream : buffer_utils . buffer_to_read_stream ( data )
340
+ }
341
+ ] ;
342
+
343
+ for ( const params of all_params ) {
344
+ const upload_res = await glacier_ns . upload_object ( params , dummy_object_sdk ) ;
345
+ console . log ( 'upload_object response' , inspect ( upload_res ) ) ;
346
+
347
+ const restore_res = await glacier_ns . restore_object ( params , dummy_object_sdk ) ;
348
+ assert ( restore_res ) ;
349
+
350
+ // Issue restore
351
+ await NamespaceFS . restore_wal . _process ( async file => {
352
+ const fs_context = glacier_ns . prepare_fs_context ( dummy_object_sdk ) ;
353
+ await backend . restore ( fs_context , file ) ;
354
+
355
+ // Don't delete the file
356
+ return false ;
357
+ } ) ;
358
+
359
+ // Ensure object is restored
360
+ const md = await glacier_ns . read_object_md ( params , dummy_object_sdk ) ;
361
+
362
+ assert ( ! md . restore_status . ongoing ) ;
363
+
364
+ const expected_expiry = Glacier . generate_expiry ( new Date ( ) , params . days , '' , config . NSFS_GLACIER_EXPIRY_TZ ) ;
365
+ assert ( expected_expiry . getTime ( ) >= md . restore_status . expiry_time . getTime ( ) ) ;
366
+ assert ( now <= md . restore_status . expiry_time . getTime ( ) ) ;
367
+ }
368
+ } ) ;
369
+
370
+ mocha . it ( 'restore-object should not restore failed item with special characters' , async function ( ) {
371
+ const now = Date . now ( ) ;
372
+ const data = crypto . randomBytes ( 100 ) ;
373
+ const failed_restore_key = `${ restore_key_spcl_char_1 } _failured` ;
374
+ const success_restore_key = `${ restore_key_spcl_char_1 } _success` ;
375
+
376
+ const failed_params = {
377
+ bucket : upload_bkt ,
378
+ key : failed_restore_key ,
379
+ storage_class : s3_utils . STORAGE_CLASS_GLACIER ,
380
+ xattr,
381
+ days : 1 ,
382
+ source_stream : buffer_utils . buffer_to_read_stream ( data )
383
+ } ;
384
+
385
+ const success_params = {
386
+ bucket : upload_bkt ,
387
+ key : success_restore_key ,
388
+ storage_class : s3_utils . STORAGE_CLASS_GLACIER ,
389
+ xattr,
390
+ days : 1 ,
391
+ source_stream : buffer_utils . buffer_to_read_stream ( data )
392
+ } ;
393
+
394
+ const failed_file_path = glacier_ns . _get_file_path ( failed_params ) ;
395
+ const success_file_path = glacier_ns . _get_file_path ( success_params ) ;
396
+
397
+ const failure_backend = new TapeCloudGlacier ( ) ;
398
+ failure_backend . _migrate = async ( ) => true ;
399
+ failure_backend . _process_expired = async ( ) => { /**noop*/ } ;
400
+ failure_backend . _recall = async ( _file , failure_recorder , success_recorder ) => {
401
+ // This unintentionally also replicates duplicate entries in WAL
402
+ await failure_recorder ( failure_backend . encode_log ( failed_file_path ) ) ;
403
+
404
+ // This unintentionally also replicates duplicate entries in WAL
405
+ await success_recorder ( failure_backend . encode_log ( success_file_path ) ) ;
274
406
275
407
return false ;
276
408
} ;
0 commit comments