Skip to content

Commit

Permalink
feat: add support for restore token (#2548)
Browse files Browse the repository at this point in the history
* Adds support for the restore token feature

* description fix

* lint fix
  • Loading branch information
thiyaguk09 authored Oct 29, 2024
1 parent 5cdc4cb commit 8241e91
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 1 deletion.
9 changes: 9 additions & 0 deletions src/file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ export interface GetFileMetadataCallback {
export interface GetFileOptions extends GetConfig {
userProject?: string;
generation?: number;
restoreToken?: string;
softDeleted?: boolean;
}

Expand Down Expand Up @@ -354,6 +355,7 @@ export interface FileOptions {
crc32cGenerator?: CRC32CValidatorGenerator;
encryptionKey?: string | Buffer;
generation?: number | string;
restoreToken?: string;
kmsKeyName?: string;
preconditionOpts?: PreconditionOptions;
userProject?: string;
Expand Down Expand Up @@ -450,6 +452,7 @@ export interface SetStorageClassCallback {

export interface RestoreOptions extends PreconditionOptions {
generation: number;
restoreToken?: string;
projection?: 'full' | 'noAcl';
}

Expand All @@ -471,6 +474,7 @@ export interface FileMetadata extends BaseMetadata {
eventBasedHold?: boolean | null;
readonly eventBasedHoldReleaseTime?: string;
generation?: string | number;
restoreToken?: string;
hardDeleteTime?: string;
kmsKeyName?: string;
md5Hash?: string;
Expand Down Expand Up @@ -547,6 +551,7 @@ class File extends ServiceObject<File, FileMetadata> {
name: string;

generation?: number;
restoreToken?: string;
parent!: Bucket;

private encryptionKey?: string | Buffer;
Expand Down Expand Up @@ -844,6 +849,8 @@ class File extends ServiceObject<File, FileMetadata> {
* @param {string} [options.userProject] The ID of the project which will be
* billed for the request.
* @param {number} [options.generation] The generation number to get
* @param {string} [options.restoreToken] If this is a soft-deleted object in an HNS-enabled bucket, returns the restore token which will
* be necessary to restore it if there's a name conflict with another object.
* @param {boolean} [options.softDeleted] If true, returns the soft-deleted object.
Object `generation` is required if `softDeleted` is set to True.
* @param {GetFileCallback} [callback] Callback function.
Expand Down Expand Up @@ -3707,6 +3714,8 @@ class File extends ServiceObject<File, FileMetadata> {
* @param {string} [userProject] The ID of the project which will be
* billed for the request.
* @param {number} [generation] If present, selects a specific revision of this object.
* @param {string} [restoreToken] Returns an option that must be specified when getting a soft-deleted object from an HNS-enabled
* bucket that has a naming and generation conflict with another object in the same bucket.
* @param {string} [projection] Specifies the set of properties to return. If used, must be 'full' or 'noAcl'.
* @param {string | number} [ifGenerationMatch] Request proceeds if the generation of the target resource
* matches the value used in the precondition.
Expand Down
73 changes: 73 additions & 0 deletions system-test/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -792,6 +792,7 @@ describe('storage', function () {

describe('soft-delete', () => {
let bucket: Bucket;
let hnsBucket: Bucket;
const SOFT_DELETE_RETENTION_SECONDS = 7 * 24 * 60 * 60; //7 days in seconds;

beforeEach(async () => {
Expand All @@ -802,11 +803,26 @@ describe('storage', function () {
retentionDurationSeconds: SOFT_DELETE_RETENTION_SECONDS,
},
});

hnsBucket = storage.bucket(generateName());
await storage.createBucket(hnsBucket.name, {
hierarchicalNamespace: {enabled: true},
iamConfiguration: {
uniformBucketLevelAccess: {
enabled: true,
},
},
softDeletePolicy: {
retentionDurationSeconds: SOFT_DELETE_RETENTION_SECONDS,
},
});
});

afterEach(async () => {
await bucket.deleteFiles({force: true, versions: true});
await bucket.delete();
await hnsBucket.deleteFiles({force: true, versions: true});
await hnsBucket.delete();
});

it('should set softDeletePolicy correctly', async () => {
Expand Down Expand Up @@ -862,6 +878,63 @@ describe('storage', function () {
[files] = await bucket.getFiles();
assert.strictEqual(files.length, 1);
});

it('should LIST soft-deleted files with restore token', async () => {
const f1 = hnsBucket.file('file5a');
const f2 = hnsBucket.file('file5b');
await f1.save('file5a');
await f2.save('file5b');
await f1.delete();
await f2.delete();
const [notSoftDeletedFiles] = await hnsBucket.getFiles();
assert.strictEqual(notSoftDeletedFiles.length, 0);
const [softDeletedFiles] = await hnsBucket.getFiles({softDeleted: true});
assert.strictEqual(softDeletedFiles.length, 2);
assert.notStrictEqual(
softDeletedFiles![0].metadata.restoreToken,
undefined
);
});

it('should GET a soft-deleted file with restore token', async () => {
const f1 = hnsBucket.file('file6');
await f1.save('file6');
const [metadata] = await f1.getMetadata();
await f1.delete();
const [softDeletedFile] = await f1.get({
softDeleted: true,
generation: parseInt(metadata.generation?.toString() || '0'),
});
assert(softDeletedFile);
assert.strictEqual(
softDeletedFile.metadata.generation,
metadata.generation
);
assert.notStrictEqual(softDeletedFile.metadata.restoreToken, undefined);
});

it('should restore a soft-deleted file using restoreToken', async () => {
const f1 = hnsBucket.file('file7');
await f1.save('file7');
const [metadata] = await f1.getMetadata();
await f1.delete();
let [files] = await hnsBucket.getFiles();
assert.strictEqual(files.length, 0);
const [softDeletedFile] = await f1.get({
softDeleted: true,
generation: parseInt(metadata.generation?.toString() || '0'),
});
assert(softDeletedFile);
const restoredFile = await f1.restore({
generation: parseInt(
softDeletedFile.metadata.generation?.toString() || '0'
),
restoreToken: softDeletedFile.metadata.restoreToken,
});
assert(restoredFile);
[files] = await hnsBucket.getFiles();
assert.strictEqual(files.length, 1);
});
});

describe('dual-region', () => {
Expand Down
1 change: 0 additions & 1 deletion test/transfer-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import {
MultiPartUploadError,
MultiPartUploadHelper,
UploadOptions,
UploadManyFilesOptions,
TransferManager,
Storage,
DownloadResponse,
Expand Down

0 comments on commit 8241e91

Please sign in to comment.