Skip to content

Commit 642c3e8

Browse files
authored
Chore: Update move logic now to support non-HNS buckets (#2666)
* Chore: Update move logic to support non-HNS buckets The existing logic for file move operations was implicitly tied to features available only in Hierarchical Namespace (HNS) enabled buckets. This update refactors the underlying move implementation to correctly handle the different API requirements and constraints of **non-HNS buckets**. * refactor: system test * add more assert * bug fix * addressing comments
1 parent 254b6b2 commit 642c3e8

File tree

4 files changed

+53
-82
lines changed

4 files changed

+53
-82
lines changed

samples/moveFileAtomic.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ function main(
5959
},
6060
};
6161

62-
// Moves the file automatically within the HNS enabled bucket
62+
// Moves the file atomically within the bucket
6363
await storage
6464
.bucket(bucketName)
6565
.file(srcFileName)

samples/system-test/files.test.js

Lines changed: 19 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,6 @@ const storage = new Storage();
3030
const cwd = path.join(__dirname, '..');
3131
const bucketName = generateName();
3232
const bucket = storage.bucket(bucketName);
33-
const hnsBucketName = generateName();
34-
const hnsBucket = storage.bucket(hnsBucketName);
3533
const objectRetentionBucketName = generateName();
3634
const objectRetentionBucket = storage.bucket(objectRetentionBucketName);
3735
const fileContents = 'these-are-my-contents';
@@ -237,6 +235,25 @@ describe('file', () => {
237235
assert.strictEqual(exists, true);
238236
});
239237

238+
it('should atomically move a file', async () => {
239+
const movedFileName = 'test1.txt';
240+
const file = bucket.file(fileName);
241+
await file.save(fileName);
242+
const output = execSync(
243+
`node moveFileAtomic.js ${bucketName} ${fileName} ${movedFileName} ${doesNotExistPrecondition}`
244+
);
245+
assert.include(
246+
output,
247+
`gs://${bucketName}/${fileName} moved to gs://${bucketName}/${movedFileName}`
248+
);
249+
const [[destExists], [sourceExists]] = await Promise.all([
250+
bucket.file(movedFileName).exists(),
251+
bucket.file(fileName).exists(),
252+
]);
253+
assert.strictEqual(destExists, true);
254+
assert.strictEqual(sourceExists, false);
255+
});
256+
240257
it('should copy a file', async () => {
241258
const output = execSync(
242259
`node copyFile.js ${bucketName} ${movedFileName} ${bucketName} ${copiedFileName} ${doesNotExistPrecondition}`
@@ -599,33 +616,6 @@ describe('file', () => {
599616
assert(metadata.retention.mode.toUpperCase(), 'UNLOCKED');
600617
});
601618
});
602-
603-
describe('HNS Bucket Move Object', () => {
604-
before(async () => {
605-
await storage.createBucket(hnsBucketName, {
606-
hierarchicalNamespace: {enabled: true},
607-
iamConfiguration: {
608-
uniformBucketLevelAccess: {
609-
enabled: true,
610-
},
611-
},
612-
});
613-
});
614-
615-
it('should move a file', async () => {
616-
const file = hnsBucket.file(fileName);
617-
await file.save(fileName);
618-
const output = execSync(
619-
`node moveFileAtomic.js ${hnsBucketName} ${fileName} ${movedFileName} ${doesNotExistPrecondition}`
620-
);
621-
assert.include(
622-
output,
623-
`gs://${hnsBucketName}/${fileName} moved to gs://${hnsBucketName}/${movedFileName}`
624-
);
625-
const [exists] = await hnsBucket.file(movedFileName).exists();
626-
assert.strictEqual(exists, true);
627-
});
628-
});
629619
});
630620

631621
function generateName() {

src/file.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3485,7 +3485,7 @@ class File extends ServiceObject<File, FileMetadata> {
34853485
* @property {number} [preconditionOpts.ifGenerationMatch] Makes the operation conditional on whether the object's current generation matches the given value.
34863486
*/
34873487
/**
3488-
* Move this file within the same HNS-enabled bucket.
3488+
* Move this file within the same bucket.
34893489
* The source object must exist and be a live object.
34903490
* The source and destination object IDs must be different.
34913491
* Overwriting the destination object is allowed by default, but can be prevented
@@ -3507,17 +3507,17 @@ class File extends ServiceObject<File, FileMetadata> {
35073507
* const storage = new Storage();
35083508
*
35093509
* //-
3510-
* // Assume 'my-hns-bucket' is an HNS-enabled bucket.
3510+
* // Assume 'my-bucket' is a bucket.
35113511
* //-
3512-
* const bucket = storage.bucket('my-hns-bucket');
3512+
* const bucket = storage.bucket('my-bucket');
35133513
* const file = bucket.file('my-image.png');
35143514
*
35153515
* //-
35163516
* // If you pass in a string for the destination, the file is copied to its
35173517
* // current bucket, under the new name provided.
35183518
* //-
35193519
* file.moveFileAtomic('moved-image.png', function(err, movedFile, apiResponse) {
3520-
* // `my-hns-bucket` now contains:
3520+
* // `my-bucket` now contains:
35213521
* // - "moved-image.png"
35223522
*
35233523
* // `movedFile` is an instance of a File object that refers to your new
@@ -3528,7 +3528,7 @@ class File extends ServiceObject<File, FileMetadata> {
35283528
* // Move the file to a subdirectory, creating parent folders if necessary.
35293529
* //-
35303530
* file.moveFileAtomic('new-folder/subfolder/moved-image.png', function(err, movedFile, apiResponse) {
3531-
* // `my-hns-bucket` now contains:
3531+
* // `my-bucket` now contains:
35323532
* // - "new-folder/subfolder/moved-image.png"
35333533
* });
35343534
*
@@ -3557,7 +3557,7 @@ class File extends ServiceObject<File, FileMetadata> {
35573557
*
35583558
* ```
35593559
* @example <caption>include:samples/files.js</caption>
3560-
* region_tag:storage_move_file_hns
3560+
* region_tag:storage_move_file
35613561
* Another example:
35623562
*/
35633563
moveFileAtomic(

system-test/storage.ts

Lines changed: 27 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1693,52 +1693,6 @@ describe('storage', function () {
16931693
assert(metadata.hierarchicalNamespace);
16941694
assert.strictEqual(metadata.hierarchicalNamespace.enabled, true);
16951695
});
1696-
1697-
describe('file#moveFileAtomic', async () => {
1698-
let hnsBucket: Bucket;
1699-
1700-
afterEach(async () => {
1701-
try {
1702-
await hnsBucket.delete();
1703-
} catch {
1704-
//Ignore errors
1705-
}
1706-
});
1707-
1708-
it('Should move a file to a new name within the same HNS-enabled bucket.', async () => {
1709-
hnsBucket = storage.bucket(generateName());
1710-
await storage.createBucket(hnsBucket.name, {
1711-
hierarchicalNamespace: {enabled: true},
1712-
iamConfiguration: {
1713-
uniformBucketLevelAccess: {
1714-
enabled: true,
1715-
},
1716-
},
1717-
});
1718-
// Create a source file in the bucket and save some content.
1719-
const f1 = hnsBucket.file('move-src-obj');
1720-
await f1.save('move-src-obj');
1721-
assert(f1);
1722-
const [f1_metadata] = await f1.getMetadata();
1723-
1724-
// Move the source file to a new destination name within the same bucket.
1725-
await f1.moveFileAtomic('move-dst-obj');
1726-
const f2 = hnsBucket.file('move-dst-obj');
1727-
assert(f2);
1728-
const [f2_metadata] = await f2.getMetadata();
1729-
1730-
// Assert that the generation of the destination file is different from the source file,
1731-
// indicating a new file was created.
1732-
assert.notStrictEqual(f1_metadata.generation, f2_metadata.generation);
1733-
1734-
const [f1_exists] = await f1.exists();
1735-
const [f2_exists] = await f2.exists();
1736-
// Assert that the source file no longer exists after the move.
1737-
assert.strictEqual(f1_exists, false);
1738-
// Assert that the destination file exists after the move.
1739-
assert.strictEqual(f2_exists, true);
1740-
});
1741-
});
17421696
});
17431697

17441698
describe('bucket retention policies', () => {
@@ -3218,6 +3172,33 @@ describe('storage', function () {
32183172
});
32193173
});
32203174

3175+
describe('file#moveFileAtomic', async () => {
3176+
it('Should move a file to a new name within the bucket.', async () => {
3177+
// Create a source file in the bucket and save some content.
3178+
const f1 = bucket.file('move-src-obj');
3179+
await f1.save('move-src-obj');
3180+
assert(f1);
3181+
const [f1_metadata] = await f1.getMetadata();
3182+
3183+
// Move the source file to a new destination name within the same bucket.
3184+
await f1.moveFileAtomic('move-dst-obj');
3185+
const f2 = bucket.file('move-dst-obj');
3186+
assert(f2);
3187+
const [f2_metadata] = await f2.getMetadata();
3188+
3189+
// Assert that the generation of the destination file is different from the source file,
3190+
// indicating a new file was created.
3191+
assert.notStrictEqual(f1_metadata.generation, f2_metadata.generation);
3192+
3193+
const [f1_exists] = await f1.exists();
3194+
const [f2_exists] = await f2.exists();
3195+
// Assert that the source file no longer exists after the move.
3196+
assert.strictEqual(f1_exists, false);
3197+
// Assert that the destination file exists after the move.
3198+
assert.strictEqual(f2_exists, true);
3199+
});
3200+
});
3201+
32213202
describe('combine files', () => {
32223203
it('should combine multiple files into one', async () => {
32233204
const files = [

0 commit comments

Comments
 (0)