Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions solution/deps.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ backbeat:
dashboard: backbeat/backbeat-dashboards
image: backbeat
policy: backbeat/backbeat-policies
tag: 9.5.0-preview.1
tag: 9.5.0-preview.3
envsubst: BACKBEAT_TAG
busybox:
image: busybox
Expand All @@ -16,7 +16,7 @@ cloudserver:
sourceRegistry: ghcr.io/scality
dashboard: cloudserver/cloudserver-dashboards
image: cloudserver
tag: 9.4.0-preview.2
tag: 9.4.0-preview.4
envsubst: CLOUDSERVER_TAG
drctl:
sourceRegistry: ghcr.io/scality
Expand Down Expand Up @@ -80,7 +80,7 @@ mongodb-connector:
pensieve-api:
sourceRegistry: ghcr.io/scality
image: pensieve-api
tag: 1.10.1
tag: 1.11.0-preview.1
envsubst: PENSIEVE_API_TAG
rclone:
sourceRegistry: rclone
Expand Down
21 changes: 21 additions & 0 deletions tests/functional/ctst/features/lifecycleExpiration.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
Feature: Lifecycle expiration

@2.16.0
@PreMerge
@Expiration
@Lifecycle
Scenario: Days=0 expiration deletes all objects in a non-versioned bucket
Given a "Non versioned" bucket
And 5 objects "expire-obj" of size 100 bytes
When i set a lifecycle expiration of 0 days
Then the bucket should contain 0 objects within 120 seconds

@2.16.0
@PreMerge
@Expiration
@Lifecycle
Scenario: Days=0 expiration deletes all versions and delete markers in a versioned bucket
Given a "Versioned" bucket
And 5 objects "expire-ver-obj" of size 100 bytes
When i set a lifecycle expiration of 0 days including noncurrent versions
Then the bucket should contain 0 objects within 180 seconds
38 changes: 38 additions & 0 deletions tests/functional/ctst/steps/lifecycleExpiration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { Then, When } from '@cucumber/cucumber';
import { S3, Utils } from 'cli-testing';
import { ListObjectVersionsOutput } from '@aws-sdk/client-s3';
import assert from 'assert';
import Zenko from 'world/Zenko';
import { safeJsonParse } from 'common/utils';
import { addExpirationWorkflow } from './utils/utils';

When('i set a lifecycle expiration of {int} days', async function (this: Zenko, days: number) {
await addExpirationWorkflow.call(this, days);
});

When('i set a lifecycle expiration of {int} days including noncurrent versions',
async function (this: Zenko, days: number) {
await addExpirationWorkflow.call(this, days, true);
});

Then('the bucket should contain {int} objects within {int} seconds', { timeout: 6 * 60 * 1000 },
async function (this: Zenko, expectedCount: number, seconds: number) {
const bucketName = this.getSaved<string>('bucketName');
const deadline = Date.now() + seconds * 1000;
let count = -1;
do {
const res = await S3.listObjectVersions({ bucket: bucketName, maxItems: '1000' });
const parsed = safeJsonParse<ListObjectVersionsOutput>(res.stdout || '{}');
assert.ok(parsed.ok, `Failed to list versions in bucket ${bucketName}: ${parsed.error}`);
const versions = parsed.result?.Versions ?? [];
const deleteMarkers = parsed.result?.DeleteMarkers ?? [];
count = versions.length + deleteMarkers.length;
if (count === expectedCount) {
return;
}
await Utils.sleep(2000);
} while (Date.now() < deadline);
assert.fail(
`Bucket ${bucketName} has ${count} versions/delete markers, ` +
`expected ${expectedCount} after ${seconds}s`);
});
66 changes: 42 additions & 24 deletions tests/functional/ctst/steps/utils/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -378,35 +378,52 @@ async function emptyVersionedBucket(world: Zenko) {
}));
}

async function addTransitionWorkflow(this: Zenko, location: string, enabled = true) {
let conditionOk = false;
this.resetCommand();
this.addCommandParameter({ bucket: this.getSaved<string>('bucketName') });
const enabledStr = enabled ? 'Enabled' : 'Disabled';
const lifecycleConfiguration = JSON.stringify({
Rules: [
{
Status: enabledStr,
Prefix: '',
Transitions: [
{
Days: 0,
StorageClass: location,
},
],
},
],
});
this.addCommandParameter({
lifecycleConfiguration,
async function putBucketLifecycleConfigurationWithRetry(world: Zenko, rules: Record<string, unknown>[]) {
world.resetCommand();
world.addCommandParameter({ bucket: world.getSaved<string>('bucketName') });
world.addCommandParameter({
lifecycleConfiguration: JSON.stringify({ Rules: rules }),
});
const commandParameters = this.getCommandParameters();
const commandParameters = world.getCommandParameters();
let conditionOk = false;
while (!conditionOk) {
const res = await S3.putBucketLifecycleConfiguration(commandParameters);
conditionOk = res.err === null;
// Wait for the transition to be accepted because the deployment of the location's pods can take some time
await Utils.sleep(5000);
// Wait for the configuration to be accepted because the deployment of the location's pods can take some time
await Utils.sleep(5000);
}
}

async function addTransitionWorkflow(this: Zenko, location: string, enabled = true) {
const enabledStr = enabled ? 'Enabled' : 'Disabled';
await putBucketLifecycleConfigurationWithRetry(this, [
{
Status: enabledStr,
Prefix: '',
Transitions: [
{
Days: 0,
StorageClass: location,
},
],
},
]);
}

async function addExpirationWorkflow(this: Zenko, days: number, includeNoncurrentVersions = false) {
const rule: Record<string, unknown> = {
Status: 'Enabled',
Prefix: '',
Expiration: {
Days: days,
},
};
if (includeNoncurrentVersions) {
rule.NoncurrentVersionExpiration = {
NoncurrentDays: days,
};
}
await putBucketLifecycleConfigurationWithRetry(this, [rule]);
}

async function getReplicationLocationConfig(world: Zenko, location: string): Promise<{
Expand Down Expand Up @@ -601,6 +618,7 @@ export {
getObjectNameWithBackendFlakiness,
restoreObject,
addTransitionWorkflow,
addExpirationWorkflow,
getReplicationLocationConfig,
putBucketReplication,
};
Loading