Skip to content

Commit d755389

Browse files
committed
lifecycle | unit test
Signed-off-by: naveenpaul1 <[email protected]>
1 parent dd419ed commit d755389

File tree

3 files changed

+208
-23
lines changed

3 files changed

+208
-23
lines changed

src/server/object_services/md_store.js

+9-7
Original file line numberDiff line numberDiff line change
@@ -431,11 +431,12 @@ class MDStore {
431431
WHERE ctid in (
432432
SELECT ctid
433433
FROM ${table_name} t1
434-
WHERE t1.data->>'bucket' = '${bucket_id}'
435-
AND t1.data->>'deleted' IS NULL
436-
AND t1.data->>'delete_marker' IS NOT NULL
437-
AND t1.data->>'version_past' IS NULL
438-
AND NOT EXISTS (
434+
WHERE ${sql_and_conditions(
435+
`t1.data->>'bucket' = '${bucket_id}'`,
436+
`t1.data->>'deleted' IS NULL`,
437+
`t1.data->>'delete_marker' IS NOT NULL`,
438+
`t1.data->>'version_past' IS NULL`,
439+
`NOT EXISTS (
439440
SELECT 1
440441
FROM ${table_name} t2
441442
WHERE t2.data->>'key' = t1.data->>'key'
@@ -444,8 +445,9 @@ class MDStore {
444445
t2.data->>'deleted' IS NULL -- is not deleted
445446
OR t2.data->>'delete_marker' IS NOT NULL -- is a delete marker
446447
)
447-
)
448-
${sql_and_conditions(sql_condition0, sql_condition1, sql_condition2, sql_condition3)}
448+
)`,
449+
sql_condition0, sql_condition1, sql_condition2, sql_condition3
450+
)}
449451
${sql_limit}
450452
);`;
451453

src/test/lifecycle/common.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ function marker_lifecycle_configuration(Bucket, Key) {
2727
},
2828
};
2929
}
30+
exports.marker_lifecycle_configuration = marker_lifecycle_configuration;
3031

3132
function empty_filter_marker_lifecycle_configuration(Bucket) {
3233
return {
@@ -390,7 +391,7 @@ function duplicate_id_lifecycle_configuration(Bucket, Key) {
390391
};
391392
}
392393

393-
function version_lifecycle_configuration(Bucket, Key, Days, ExpiredDeleteMarker, NewnonCurrentVersion, NonCurrentDays) {
394+
function version_lifecycle_configuration(Bucket, Key, Days, NewnonCurrentVersion, NonCurrentDays) {
394395
const ID = 'rule_id';
395396
return {
396397
Bucket,
@@ -402,7 +403,6 @@ function version_lifecycle_configuration(Bucket, Key, Days, ExpiredDeleteMarker,
402403
},
403404
Expiration: {
404405
Days: Days,
405-
ExpiredObjectDeleteMarker: ExpiredDeleteMarker,
406406
},
407407
NoncurrentVersionExpiration: {
408408
NewerNoncurrentVersions: NewnonCurrentVersion,
@@ -467,7 +467,7 @@ exports.test_multipart = async function(Bucket, Key, s3) {
467467
};
468468

469469
exports.test_version = async function(Bucket, Key, s3) {
470-
const putLifecycleParams = version_lifecycle_configuration(Bucket, Key, 10, true, 5, 10);
470+
const putLifecycleParams = version_lifecycle_configuration(Bucket, Key, 10, 5, 10);
471471
const getLifecycleResult = await put_get_lifecycle_configuration(Bucket, putLifecycleParams, s3);
472472

473473
const expirationDays = getLifecycleResult.Rules[0].Expiration.Days;

src/test/unit_tests/test_lifecycle.js

+196-13
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,15 @@ const TagValue2 = 'tagvalue2';
3737
const object_io = new ObjectIO();
3838
object_io.set_verification_mode();
3939

40-
40+
// eslint-disable-next-line max-lines-per-function
4141
mocha.describe('lifecycle', () => {
4242

4343
let s3;
4444
mocha.before(async function() {
4545
this.timeout(60000);
4646

47+
config.LIFECYCLE_SCHEDULE_MIN = 0;
48+
config.LIFECYCLE_INTERVAL = 0;
4749
const account_info = await rpc_client.account.read_account({ email: EMAIL, });
4850
s3 = new S3({
4951
endpoint: coretest.get_http_address(),
@@ -347,9 +349,6 @@ mocha.describe('lifecycle', () => {
347349
const size = num_parts * part_size;
348350
const data = generator.update(Buffer.alloc(size));
349351
const { obj_id } = await rpc_client.object.create_object_upload({ bucket, key, content_type });
350-
const mp_list_before = await rpc_client.object.list_multiparts({ obj_id, bucket, key });
351-
coretest.log('list_multiparts before', mp_list_before);
352-
assert.strictEqual(mp_list_before.multiparts.length, 0);
353352
const multiparts_ids = [];
354353

355354
const get_part_slice = i => data.slice(i * part_size, (i + 1) * part_size);
@@ -381,15 +380,65 @@ mocha.describe('lifecycle', () => {
381380
await MDStore.instance().update_object_by_id(obj_id, update);
382381

383382
const mp_list_after = await rpc_client.object.list_multiparts({ obj_id, bucket, key });
384-
coretest.log('mp_list_after after', mp_list_after);
385-
assert.strictEqual(mp_list_after.multiparts.length, num_parts);
383+
assert.strictEqual(mp_list_after.multiparts.length, num_parts,
384+
`list_multiparts actual ${mp_list_after.multiparts.length} !== ${num_parts}`);
386385

387386
return obj_id;
388387
}
389388

390-
mocha.it('lifecyle - listMultiPart verify', async () => {
391-
await create_mock_multipart_upload('test-lifecycle-multipart', multipart_bucket, 3, 45, 7);
389+
mocha.it('lifecycle - delete multipart after 30 days', async () => {
390+
const days = 30;
391+
const multi_bucket_key = 'test-lifecycle-multipart1';
392+
const obj_id = await create_mock_multipart_upload(multi_bucket_key, multipart_bucket, days, 45, 7);
393+
const putLifecycleParams = commonTests.multipart_lifecycle_configuration(multipart_bucket, multi_bucket_key, days);
394+
395+
await s3.putBucketLifecycleConfiguration(putLifecycleParams);
396+
await lifecycle.background_worker();
397+
await verify_multipart_deleted(obj_id, multi_bucket_key, 0);
398+
});
399+
400+
mocha.it('lifecycle - should not delete multipart after 30 days, before expiration', async () => {
401+
const days = 30;
402+
const multi_bucket_key = 'test-lifecycle-multipart2';
403+
// create_time updated to 29 days and expire is 30 days, do not delete any multipart
404+
const obj_id = await create_mock_multipart_upload(multi_bucket_key, multipart_bucket, days - 1, 45, 7);
405+
const putLifecycleParams = commonTests.multipart_lifecycle_configuration(multipart_bucket, multi_bucket_key, days);
406+
407+
await s3.putBucketLifecycleConfiguration(putLifecycleParams);
408+
await lifecycle.background_worker();
409+
await verify_multipart_deleted(obj_id, multi_bucket_key, 7);
392410
});
411+
412+
mocha.it('lifecycle - delete multipart after 30 days, with prfix', async () => {
413+
const days = 30;
414+
const multi_bucket_key_prefix = 'prefix-test-lifecycle-multipart3';
415+
const multi_bucket_key = 'test-lifecycle-multipart3';
416+
// create_time updated to days + 1(31 days) and expire is 30 days,
417+
const obj_id1 = await create_mock_multipart_upload(multi_bucket_key_prefix, multipart_bucket, days + 1, 45, 7);
418+
const obj_id2 = await create_mock_multipart_upload(multi_bucket_key, multipart_bucket, days + 1, 45, 7);
419+
const putLifecycleParams = commonTests.multipart_lifecycle_configuration(multipart_bucket, multi_bucket_key_prefix, days);
420+
421+
await s3.putBucketLifecycleConfiguration(putLifecycleParams);
422+
await lifecycle.background_worker();
423+
// delete only those multipart with prefix `prefix-test-lifecycle-multipart3` not others
424+
await verify_multipart_deleted(obj_id1, multi_bucket_key_prefix, 0);
425+
await verify_multipart_deleted(obj_id2, multi_bucket_key, 7);
426+
});
427+
428+
async function verify_multipart_deleted(obj_id, key, expected_length) {
429+
try {
430+
const mp_list = await rpc_client.object.list_multiparts({ obj_id, bucket: multipart_bucket, key });
431+
console.log('verify_multipart_deleted : multipart upload objects :', mp_list);
432+
const actual_length = mp_list.objects.length;
433+
console.log('list_objects_admin objects: ', util.inspect(mp_list.objects));
434+
assert.strictEqual(actual_length, expected_length, `listObjectResult actual ${actual_length} !== ${expected_length}`);
435+
} catch (err) {
436+
console.log('verify_multipart_deleted error is :', err);
437+
if (err.code === 'NO_SUCH_UPLOAD' && expected_length === 0) {
438+
assert.ok(true);
439+
}
440+
}
441+
}
393442
});
394443

395444
mocha.describe('bucket-lifecycle-version', function() {
@@ -553,16 +602,16 @@ mocha.describe('lifecycle', () => {
553602
const update = {
554603
create_time: moment().subtract(age, 'days').toDate(),
555604
};
556-
console.log('blow_version_objects: bucket', bucket, 'multiparts_ids', obj_upload_ids, " obj_upload_ids length: ", obj_upload_ids.length, "update :", update);
605+
console.log('create_mock_version: bucket', bucket, 'obj_upload_ids:', obj_upload_ids, " obj_upload_ids length: ", obj_upload_ids.length, "update :", update);
557606
const update_result = await MDStore.instance().update_objects_by_ids(obj_upload_ids, update);
558-
console.log('blow_version_objects: update_objects_by_ids', update_result);
607+
console.log('create_mock_version: update_objects_by_ids:', update_result);
559608
}
560609
}
561610

562611
mocha.it('lifecyle - version object expired', async () => {
563612
const age = 30;
564613
const version_count = 10;
565-
const version_bucket_key = 'test-lifecycle-version1';
614+
const version_bucket_key = 'test-lifecycle-version1-1';
566615
await create_mock_version(version_bucket_key, version_bucket, age, version_count, true);
567616
const putLifecycleParams = commonTests.days_lifecycle_configuration(version_bucket, version_bucket_key);
568617
await s3.putBucketLifecycleConfiguration(putLifecycleParams);
@@ -574,7 +623,7 @@ mocha.describe('lifecycle', () => {
574623
mocha.it('lifecyle - version object not expired', async () => {
575624
const age = 5;
576625
const version_count = 10;
577-
const version_bucket_key = 'test-lifecycle-version2';
626+
const version_bucket_key = 'test-lifecycle-version2-0';
578627
await create_mock_version(version_bucket_key, version_bucket, age, version_count, true);
579628
const putLifecycleParams = commonTests.days_lifecycle_configuration(version_bucket, version_bucket_key);
580629
await s3.putBucketLifecycleConfiguration(putLifecycleParams);
@@ -583,7 +632,141 @@ mocha.describe('lifecycle', () => {
583632
await verify_version_deleted(version_count, version_bucket_key);
584633
});
585634

586-
async function verify_version_deleted(expected_length, key) {
635+
mocha.it('lifecyle - version not expiration', async () => {
636+
const days = 30;
637+
const version_count = 10;
638+
const newnon_current_version = 1;
639+
const noncurrent_days = 15;
640+
const version_bucket_key = 'test-lifecycle-version2-1';
641+
// create_time updated to 29 days and expire is 30 days and noncurrent expire in 15
642+
await create_mock_version(version_bucket_key, version_bucket, days - 1, version_count);
643+
const putLifecycleParams = commonTests.version_lifecycle_configuration(version_bucket,
644+
version_bucket_key, days, newnon_current_version, noncurrent_days);
645+
646+
await s3.putBucketLifecycleConfiguration(putLifecycleParams);
647+
await lifecycle.background_worker();
648+
// remove all the noncurrent versions expect one( newnon_current_version = 1) once 15 days passed
649+
// current version has not expired. In that case, list will return 2 objects
650+
await verify_version_deleted(2, version_bucket_key);
651+
});
652+
653+
mocha.it('lifecyle - version expiration - only NewerNoncurrentVersions exceeded', async () => {
654+
const days = 35;
655+
const version_count = 10;
656+
const newnon_current_version = 5;
657+
const noncurrent_days = 30;
658+
const version_bucket_key = 'test-lifecycle-version1-1';
659+
// create_time updated to 36 days and expire is 35 days
660+
await create_mock_version(version_bucket_key, version_bucket, days + 1, version_count, true);
661+
const putLifecycleParams = commonTests.version_lifecycle_configuration(version_bucket,
662+
version_bucket_key, days, newnon_current_version, noncurrent_days);
663+
664+
await s3.putBucketLifecycleConfiguration(putLifecycleParams);
665+
await lifecycle.background_worker();
666+
// object will expire, noncurrent version count(5) + deleted current version(1) + delete marker(1)
667+
await verify_version_deleted(7, version_bucket_key);
668+
});
669+
670+
mocha.it('lifecyle - version expiration - only NoncurrentDays exceeded', async () => {
671+
const days = 45;
672+
const version_count = 10;
673+
const newnon_current_version = 100;
674+
const noncurrent_days = 30;
675+
const version_bucket_key = 'test-lifecycle-version3';
676+
// create_time updated to 45+30+1= 76 days and expire is 45 days
677+
await create_mock_version(version_bucket_key, version_bucket, days + noncurrent_days + 1, version_count, true);
678+
const putLifecycleParams = commonTests.version_lifecycle_configuration(version_bucket,
679+
version_bucket_key, days, newnon_current_version, noncurrent_days);
680+
681+
await s3.putBucketLifecycleConfiguration(putLifecycleParams);
682+
await lifecycle.background_worker();
683+
// dekete only current version, do not delete noncurrent version because newnon_current_version = 100
684+
// noncurrent version count + delete marker(1)
685+
await verify_version_deleted(11, version_bucket_key);
686+
});
687+
688+
mocha.it('lifecyle - version expiration - both NoncurrentDays and NewerNoncurrentVersions exceeded', async () => {
689+
const days = 30;
690+
const version_count = 10;
691+
const newnon_current_version = 1;
692+
const noncurrent_days = 15;
693+
const version_bucket_key = 'test-lifecycle-version4';
694+
// create_time updated to 46 days and expire is 30 days
695+
await create_mock_version(version_bucket_key, version_bucket, days + noncurrent_days + 1, version_count);
696+
const putLifecycleParams = commonTests.version_lifecycle_configuration(version_bucket,
697+
version_bucket_key, days, newnon_current_version, noncurrent_days);
698+
699+
await s3.putBucketLifecycleConfiguration(putLifecycleParams);
700+
await lifecycle.background_worker();
701+
// newnon_current_version count + current version
702+
await verify_version_deleted(2, version_bucket_key);
703+
});
704+
705+
mocha.it('lifecyle - version not expiration - delete marker true', async () => {
706+
const days = 30;
707+
const version_count = 10;
708+
const newnon_current_version = 0;
709+
const noncurrent_days = 15;
710+
const version_bucket_key = 'test-lifecycle-version5';
711+
// create_time updated to 29 days and expire is 30 days,
712+
await create_mock_version(version_bucket_key, version_bucket, days - 1, version_count, true);
713+
const putLifecycleParams = commonTests.version_lifecycle_configuration(version_bucket,
714+
version_bucket_key, days, newnon_current_version, noncurrent_days);
715+
716+
await s3.putBucketLifecycleConfiguration(putLifecycleParams);
717+
await lifecycle.background_worker();
718+
// remove all the noncurrent version because the noncurrent_days is 15(< 30) and
719+
// newnon_current_version is 0. Only current version exists
720+
await verify_version_deleted(1, version_bucket_key);
721+
});
722+
723+
mocha.it('lifecyle - version expiration all - delete marker true', async () => {
724+
const days = 30;
725+
const version_count = 10;
726+
const newnon_current_version = 0;
727+
const noncurrent_days = 15;
728+
const version_bucket_key = 'test-lifecycle-version6';
729+
await create_mock_version(version_bucket_key, version_bucket, days + noncurrent_days + 1, version_count, true);
730+
const putLifecycleParams = commonTests.version_lifecycle_configuration(version_bucket,
731+
version_bucket_key, days, newnon_current_version, noncurrent_days);
732+
await s3.putBucketLifecycleConfiguration(putLifecycleParams);
733+
await lifecycle.background_worker();
734+
await verify_version_deleted(2, version_bucket_key);
735+
// add a delay between two worker run
736+
await P.delay(100); // 0.1sec
737+
// Complete deletion will happen in two lifecycle run,
738+
// First delete all the noncurrent version and current version to noncurrent version
739+
// last noncurrent version( current in first step ) and delete marker
740+
await age_object(days + noncurrent_days + 1, version_bucket_key);
741+
await lifecycle.background_worker();
742+
await verify_version_deleted(1, version_bucket_key);
743+
744+
const putDeleteMarkerLifecycleParams = commonTests.marker_lifecycle_configuration(version_bucket, version_bucket_key);
745+
await s3.putBucketLifecycleConfiguration(putDeleteMarkerLifecycleParams);
746+
await lifecycle.background_worker();
747+
await verify_version_deleted(0, version_bucket_key);
748+
});
749+
750+
async function age_object(age, key = '') {
751+
const obj_params = {
752+
bucket: version_bucket,
753+
prefix: key,
754+
};
755+
const obj_ids = [];
756+
const {objects} = await rpc_client.object.list_object_versions(obj_params);
757+
for (const object of objects) {
758+
obj_ids.push(object.obj_id);
759+
}
760+
if (age > 0) {
761+
const update = {
762+
create_time: moment().subtract(age, 'days').toDate(),
763+
};
764+
console.log('age_object: bucket', version_bucket, 'obj_ids', obj_ids, " obj_upload_ids length: ", obj_ids.length, "update :", update);
765+
await MDStore.instance().update_objects_by_ids(obj_ids, update);
766+
}
767+
}
768+
769+
async function verify_version_deleted(expected_length, key = '') {
587770
const obj_params = {
588771
bucket: version_bucket,
589772
prefix: key,

0 commit comments

Comments
 (0)