Skip to content

Commit

Permalink
fix(lib-storage): add missing return keys (#2700)
Browse files Browse the repository at this point in the history
* fix(lib-storage): add missing return keys

* feat: assert putResponse is defined

* feat: add encodeURIComponent to Bucket and Key

* refactor: move extra key insertion

* fix: correct wrong line being deleted

* chore: change to ternary operator

* chore: remove done from tests
  • Loading branch information
samchungy authored May 6, 2022
1 parent c0ed833 commit cbab94e
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 5 deletions.
44 changes: 43 additions & 1 deletion lib/lib-storage/src/Upload.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,27 @@ const putObjectTaggingMock = jest.fn().mockResolvedValue({
Success: "Tags have been applied!",
});

const endpointMock = jest.fn().mockResolvedValue({
hostname: "s3.region.amazonaws.com",
port: undefined,
protocol: "https:",
path: "/",
query: undefined,
});

jest.mock("@aws-sdk/client-s3", () => ({
...(jest.requireActual("@aws-sdk/client-s3") as {}),
S3: jest.fn().mockReturnValue({
send: sendMock,
config: {
endpoint: endpointMock,
},
}),
S3Client: jest.fn().mockReturnValue({
send: sendMock,
config: {
endpoint: endpointMock,
},
}),
CreateMultipartUploadCommand: createMultipartMock,
UploadPartCommand: uploadPartMock,
Expand All @@ -36,7 +50,7 @@ jest.mock("@aws-sdk/client-s3", () => ({
PutObjectCommand: putObjectMock,
}));

import { S3 } from "@aws-sdk/client-s3";
import { CompleteMultipartUploadCommandOutput, S3 } from "@aws-sdk/client-s3";
import { Readable } from "stream";

import { Progress, Upload } from "./index";
Expand Down Expand Up @@ -184,6 +198,34 @@ describe(Upload.name, () => {
expect(putObjectTaggingMock).toHaveBeenCalledTimes(0);
});

it("should return a Bucket, Key and Location fields when upload uses a PUT", async () => {
const buffer = Buffer.from("");
const actionParams = { ...params, Body: buffer };
const upload = new Upload({
params: actionParams,
client: new S3({}),
});

const result = (await upload.done()) as CompleteMultipartUploadCommandOutput;
expect(result.Key).toEqual("example-key");
expect(result.Bucket).toEqual("example-bucket");
expect(result.Location).toEqual("https://example-bucket.s3.region.amazonaws.com/example-key");
});

it("should return a Location field formatted in path style when forcePathStyle is true", async () => {
const buffer = Buffer.from("");
const actionParams = { ...params, Body: buffer };
const s3Client = new S3({});
s3Client.config.forcePathStyle = true;
const upload = new Upload({
params: actionParams,
client: s3Client,
});

const result = (await upload.done()) as CompleteMultipartUploadCommandOutput;
expect(result.Location).toEqual("https://s3.region.amazonaws.com/example-bucket/example-key");
});

it("should upload using multi-part when parts are larger than part size", async () => {
// create a string that's larger than 5MB.
const partSize = 1024 * 1024 * 5;
Expand Down
28 changes: 24 additions & 4 deletions lib/lib-storage/src/Upload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@ import { AbortController, AbortSignal } from "@aws-sdk/abort-controller";
import {
CompletedPart,
CompleteMultipartUploadCommand,
CompleteMultipartUploadCommandOutput,
CreateMultipartUploadCommand,
CreateMultipartUploadCommandOutput,
PutObjectCommand,
PutObjectCommandInput,
PutObjectCommandOutput,
PutObjectTaggingCommand,
ServiceOutputTypes,
Tag,
UploadPartCommand,
} from "@aws-sdk/client-s3";
import { extendedEncodeURIComponent } from "@aws-sdk/smithy-client";
import { EventEmitter } from "events";

import { byteLength } from "./bytelength";
Expand Down Expand Up @@ -55,7 +56,7 @@ export class Upload extends EventEmitter {
uploadEvent?: string;

private isMultiPart = true;
private putResponse?: PutObjectCommandOutput;
private putResponse?: CompleteMultipartUploadCommandOutput;

constructor(options: Options) {
super();
Expand Down Expand Up @@ -97,8 +98,27 @@ export class Upload extends EventEmitter {
async __uploadUsingPut(dataPart: RawDataPart) {
this.isMultiPart = false;
const params = { ...this.params, Body: dataPart.data };
const putResult = await this.client.send(new PutObjectCommand(params));
this.putResponse = putResult;
const [putResult, endpoint] = await Promise.all([
this.client.send(new PutObjectCommand(params)),
this.client.config.endpoint(),
]);

const locationKey = this.params
.Key!.split("/")
.map((segment) => extendedEncodeURIComponent(segment))
.join("/");
const locationBucket = extendedEncodeURIComponent(this.params.Bucket!);

const Location: string = this.client.config.forcePathStyle
? `${endpoint.protocol}//${endpoint.hostname}/${locationBucket}/${locationKey}`
: `${endpoint.protocol}//${locationBucket}.${endpoint.hostname}/${locationKey}`;

this.putResponse = {
...putResult,
Bucket: this.params.Bucket,
Key: this.params.Key,
Location,
};
const totalSize = byteLength(dataPart.data);
this.__notifyProgress({
loaded: totalSize,
Expand Down

0 comments on commit cbab94e

Please sign in to comment.