Skip to content

Commit

Permalink
feat(sdk): add Bucket.copy() for tf-azure target (#4690)
Browse files Browse the repository at this point in the history
Closes #4397

## Checklist

- [x] Title matches [Winglang's style guide](https://www.winglang.io/contributing/start-here/pull_requests#how-are-pull-request-titles-formatted)
- [x] Description explains motivation and solution
- [x] Tests added (always)
- [ ] Docs updated (only required for features)
- [ ] Added `pr/e2e-full` label if this feature requires end-to-end testing

*By submitting this pull request, I confirm that my contribution is made under the terms of the [Wing Cloud Contribution License](https://github.com/winglang/wing/blob/main/CONTRIBUTION_LICENSE.md)*.
  • Loading branch information
garysassano authored Nov 20, 2023
1 parent 9251b9b commit bc272f5
Show file tree
Hide file tree
Showing 9 changed files with 74 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@
"copy": {
"sim": { "implemented": true },
"tf-aws": { "implemented": true },
"tf-azure": { "implemented": false, "issue": 4397 },
"tf-azure": { "implemented": true },
"tf-gcp": { "implemented": false, "issue": 4398 },
"awscdk": { "implemented": true }
},
Expand Down
2 changes: 1 addition & 1 deletion examples/tests/sdk_tests/bucket/copy.test.w
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ test "copy()" {
assert(error);
};
let UNEXISTING_KEY = "no-such-file.txt";
let OBJECT_DOES_NOT_EXIST_ERROR = "Unable to copy. Source object does not exist (srcKey=${UNEXISTING_KEY}).";
let OBJECT_DOES_NOT_EXIST_ERROR = "Source object does not exist (srcKey=${UNEXISTING_KEY}).";

let KEY1 = "file1.main.w";
let VALUE1 = "bring cloud;";
Expand Down
4 changes: 1 addition & 3 deletions libs/wingsdk/src/shared-aws/bucket.inflight.ts
Original file line number Diff line number Diff line change
Expand Up @@ -278,9 +278,7 @@ export class BucketClient implements IBucketClient {
await this.s3Client.send(command);
} catch (error) {
if (error instanceof NotFound) {
throw new Error(
`Unable to copy. Source object does not exist (srcKey=${srcKey}).`
);
throw new Error(`Source object does not exist (srcKey=${srcKey}).`);
}
throw error;
}
Expand Down
4 changes: 1 addition & 3 deletions libs/wingsdk/src/target-sim/bucket.inflight.ts
Original file line number Diff line number Diff line change
Expand Up @@ -256,9 +256,7 @@ export class Bucket implements IBucketClient, ISimulatorResourceInstance {
message: `Copy (srcKey=${srcKey} to dstKey=${dstKey}).`,
activity: async () => {
if (!this.objectKeys.has(srcKey)) {
throw new Error(
`Unable to copy. Source object does not exist (srcKey=${srcKey}).`
);
throw new Error(`Source object does not exist (srcKey=${srcKey}).`);
}

const dstValue = await this.get(srcKey);
Expand Down
13 changes: 9 additions & 4 deletions libs/wingsdk/src/target-tf-azure/bucket.inflight.ts
Original file line number Diff line number Diff line change
Expand Up @@ -264,16 +264,21 @@ export class BucketClient implements IBucketClient {
}

/**
* Copy object within the container
* Copy object within the bucket
*
* @param srcKey The key of the source object you wish to copy.
* @param dstKey The key of the destination object after copying.
* @throws if `srcKey` object doesn't exist.
*/
public async copy(srcKey: string, dstKey: string): Promise<void> {
return Promise.reject(
`copy is not implemented: (srcKey=${srcKey}, dstKey=${dstKey})`
);
const srcBlobUrl = this.containerClient.getBlobClient(srcKey).url;
const dstBlobClient = this.containerClient.getBlockBlobClient(dstKey);

try {
await dstBlobClient.syncCopyFromURL(srcBlobUrl);
} catch (error) {
throw new Error(`Source object does not exist (srcKey=${srcKey}).`);
}
}

/**
Expand Down
1 change: 1 addition & 0 deletions libs/wingsdk/src/target-tf-azure/bucket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ export class Bucket extends cloud.Bucket {
cloud.BucketInflightMethods.TRY_GET_JSON,
cloud.BucketInflightMethods.TRY_DELETE,
cloud.BucketInflightMethods.METADATA,
cloud.BucketInflightMethods.COPY,
];
}

Expand Down
2 changes: 1 addition & 1 deletion libs/wingsdk/test/shared-aws/bucket.inflight.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -727,6 +727,6 @@ test("copy a non-existent object within the bucket", async () => {

// THEN
await expect(() => client.copy(SRC_KEY, DST_KEY)).rejects.toThrowError(
`Unable to copy. Source object does not exist (srcKey=${SRC_KEY}).`
`Source object does not exist (srcKey=${SRC_KEY}).`
);
});
2 changes: 1 addition & 1 deletion libs/wingsdk/test/target-sim/bucket.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -769,7 +769,7 @@ test("copy non-existent object within the bucket", async () => {

// THEN
await expect(() => client.copy(SRC_KEY, DST_KEY)).rejects.toThrowError(
/Unable to copy. Source object does not exist/
/Source object does not exist/
);
await s.stop();
});
Expand Down
58 changes: 58 additions & 0 deletions libs/wingsdk/test/target-tf-azure/bucket.inflight.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ import { Readable } from "stream";
import { PagedAsyncIterableIterator, PageSettings } from "@azure/core-paging";
import {
BlobClient,
BlobCopyFromURLResponse,
BlobDeleteResponse,
BlobDownloadResponseParsed,
BlobExistsOptions,
BlobGetPropertiesOptions,
BlobGetPropertiesResponse,
BlobItem,
BlobServiceClient,
BlobSyncCopyFromURLOptions,
BlockBlobClient,
BlockBlobUploadResponse,
ContainerClient,
Expand Down Expand Up @@ -514,6 +516,52 @@ test("fetch metadata of an unexisting object from the bucket", async () => {
);
});

test("copy objects within the bucket", async () => {
// GIVEN
const BUCKET_NAME = "BUCKET_NAME";
const STORAGE_NAME = "STORAGE_NAME";
const SRC_KEY = "SRC/KEY";
const DST_KEY = "DST/KEY";

// WHEN
const client = new BucketClient(
BUCKET_NAME,
STORAGE_NAME,
false,
mockBlobServiceClient
);
TEST_PATH = "happy";

const response1 = await client.copy(SRC_KEY, SRC_KEY);
const response2 = await client.copy(SRC_KEY, DST_KEY);

// THEN
expect(response1).toEqual(undefined);
expect(response2).toEqual(undefined);
});

test("copy a non-existent object within the bucket", async () => {
// GIVEN
const BUCKET_NAME = "BUCKET_NAME";
const STORAGE_NAME = "STORAGE_NAME";
const SRC_KEY = "SRC/KEY";
const DST_KEY = "DST/KEY";

// WHEN
const client = new BucketClient(
BUCKET_NAME,
STORAGE_NAME,
false,
mockBlobServiceClient
);
TEST_PATH = "sad";

// THEN
await expect(() => client.copy(SRC_KEY, DST_KEY)).rejects.toThrowError(
`Source object does not exist (srcKey=${SRC_KEY}).`
);
});

// Mock Clients
class MockBlobClient extends BlobClient {
public download(): Promise<BlobDownloadResponseParsed> {
Expand Down Expand Up @@ -592,6 +640,16 @@ class MockBlockBlobClient extends BlockBlobClient {
public delete(): Promise<BlobDeleteResponse> {
return Promise.resolve({} as any);
}

public syncCopyFromURL(
copySource: string,
options?: BlobSyncCopyFromURLOptions
): Promise<BlobCopyFromURLResponse> {
if (TEST_PATH === "happy") {
return Promise.resolve({} as BlobCopyFromURLResponse);
}
return Promise.reject("some fake error");
}
}

class MockContainerClient extends ContainerClient {
Expand Down

0 comments on commit bc272f5

Please sign in to comment.