Skip to content

Commit 53ef260

Browse files
committed
feat: cr revisions
1 parent 2559e6a commit 53ef260

File tree

7 files changed

+75
-394
lines changed

7 files changed

+75
-394
lines changed

lib/lib-storage/package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@
1515
"clean": "rimraf ./dist-* && rimraf *.tsbuildinfo",
1616
"extract:docs": "api-extractor run --local",
1717
"test": "yarn g:vitest run",
18-
"test:e2e": "yarn g:vitest run -c vitest.config.e2e.ts --mode development",
1918
"test:watch": "yarn g:vitest watch",
2019
"test:browser": "yarn g:vitest run -c vitest.config.browser.ts",
2120
"test:browser:watch": "yarn g:vitest watch -c vitest.config.browser.ts",
21+
"test:e2e": "yarn g:vitest run -c vitest.config.e2e.ts --mode development",
2222
"test:e2e:watch": "yarn g:vitest watch -c vitest.config.e2e.ts"
2323
},
2424
"engines": {
@@ -48,7 +48,6 @@
4848
"@types/node": "^18.19.69",
4949
"concurrently": "7.0.0",
5050
"downlevel-dts": "0.10.1",
51-
"jsdom": "^26.1.0",
5251
"rimraf": "3.0.2",
5352
"typescript": "~5.8.3",
5453
"web-streams-polyfill": "3.2.1"

lib/lib-storage/src/s3-transfer-manager/S3TransferManager.e2e.spec.ts

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,10 @@
1-
import {
2-
GetObjectCommandOutput,
3-
ListBucketInventoryConfigurationsOutputFilterSensitiveLog,
4-
PutObjectCommand,
5-
S3,
6-
} from "@aws-sdk/client-s3";
7-
import internal from "stream";
8-
import { getHeapSnapshot } from "v8";
1+
import { GetObjectCommandOutput, S3 } from "@aws-sdk/client-s3";
92
import { beforeAll, describe, expect, test as it } from "vitest";
103

114
import { getIntegTestResources } from "../../../../tests/e2e/get-integ-test-resources";
125
import { Upload } from "../Upload";
136
import { internalEventHandler, S3TransferManager } from "./S3TransferManager";
14-
import type { IS3TransferManager, S3TransferManagerConfig } from "./types";
7+
import type { S3TransferManagerConfig } from "./types";
158

169
describe(S3TransferManager.name, () => {
1710
const chunk = "01234567";
@@ -231,10 +224,36 @@ describe(S3TransferManager.name, () => {
231224
}
232225
});
233226

234-
// TODO: Write abortController tests
235-
describe.skip("Download must cancel on timed abortController", () => {});
227+
describe("download with abortController ", () => {
228+
const modes = ["PART"] as S3TransferManagerConfig["multipartDownloadType"][];
229+
for (const mode of modes) {
230+
it(`should cancel ${mode} download on abort()`, async () => {
231+
const totalSizeMB = 10 * 1024 * 1024;
232+
const Body = data(totalSizeMB);
233+
const Key = `${mode}-size`;
234+
await new Upload({
235+
client,
236+
params: { Bucket, Key, Body },
237+
}).done();
238+
const tm: S3TransferManager = mode === "PART" ? tmPart : tmRange;
239+
const controller = new AbortController();
240+
setTimeout(() => controller.abort(), 100);
241+
try {
242+
await tm.download(
243+
{ Bucket, Key },
244+
{
245+
abortSignal: controller.signal,
246+
}
247+
);
248+
expect.fail("Download should have been aborted");
249+
} catch (error) {
250+
expect(error.name).toEqual("AbortError");
251+
}
252+
}, 60_000);
253+
}
254+
});
236255

237-
describe.skip("(SEP) download single object tests", () => {
256+
describe("(SEP) download single object tests", () => {
238257
async function sepTests(
239258
objectType: "single" | "multipart",
240259
multipartType: "PART" | "RANGE",
@@ -286,13 +305,6 @@ describe(S3TransferManager.name, () => {
286305
it("multipart object: multipartDownloadType = RANGE, range = 0-12MB, partNumber = null", async () => {
287306
await sepTests("multipart", "RANGE", `bytes=0-${12 * 1024 * 1024}`, undefined);
288307
}, 60_000);
289-
// skipped because TM no longer supports partNumber
290-
it.skip("single object: multipartDownloadType = PART, range = null, partNumber = 2", async () => {
291-
await sepTests("single", "PART", undefined, 2);
292-
}, 60_000);
293-
it.skip("single object: multipartDownloadType = RANGE, range = null, partNumber = 2", async () => {
294-
await sepTests("single", "RANGE", undefined, 2);
295-
}, 60_000);
296308
it("single object: multipartDownloadType = PART, range = null, partNumber = null", async () => {
297309
await sepTests("single", "PART", undefined, undefined);
298310
}, 60_000);

lib/lib-storage/src/s3-transfer-manager/S3TransferManager.spec.ts

Lines changed: 1 addition & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
import { S3, S3Client } from "@aws-sdk/client-s3";
2-
import { GetObjectCommand, PutObjectCommand } from "@aws-sdk/client-s3";
32
import { TransferCompleteEvent, TransferEvent } from "@aws-sdk/lib-storage/dist-types/s3-transfer-manager/types";
43
import { StreamingBlobPayloadOutputTypes } from "@smithy/types";
5-
import { mockClient } from "aws-sdk-client-mock";
64
import { Readable } from "stream";
75
import { beforeAll, beforeEach, describe, expect, test as it, vi } from "vitest";
86

97
import { getIntegTestResources } from "../../../../tests/e2e/get-integ-test-resources";
10-
import { iterateStreams, joinStreams } from "./join-streams";
8+
import { joinStreams } from "./join-streams";
119
import { S3TransferManager } from "./S3TransferManager";
1210

1311
describe("S3TransferManager Unit Tests", () => {
@@ -29,72 +27,6 @@ describe("S3TransferManager Unit Tests", () => {
2927
});
3028
});
3129

32-
// TODO: This test uses mock from public library aws-sdk-mock. May remove
33-
describe("ETag Unit tests", () => {
34-
const s3Mock = mockClient(S3Client);
35-
36-
beforeEach(() => {
37-
s3Mock.reset();
38-
});
39-
40-
it("Should throw precondition error when ETag changes mid-download", async () => {
41-
const bucket = "test-bucket";
42-
const key = "test-key";
43-
const originalData = Buffer.alloc(20 * 1024 * 1024, "a"); // 20MB
44-
45-
let getCallCount = 0;
46-
47-
s3Mock.on(GetObjectCommand).callsFake((input) => {
48-
getCallCount++;
49-
50-
if (getCallCount === 1) {
51-
// First call - return original object with PartsCount > 1 to trigger concurrent requests
52-
return {
53-
Body: Readable.from([originalData.slice(0, 8 * 1024 * 1024)]),
54-
ETag: '"original-etag"',
55-
ContentLength: 8 * 1024 * 1024,
56-
ContentRange: "bytes 0-8388607/20971520", // Part 1 of 3 parts
57-
PartsCount: 3,
58-
};
59-
} else {
60-
// Subsequent calls with IfMatch should fail with 412 Precondition Failed
61-
if (input.IfMatch === '"original-etag"') {
62-
const error = new Error("The condition specified using HTTP conditional header(s) is not met.");
63-
error.name = "PreconditionFailed";
64-
(error as any).$metadata = {
65-
httpStatusCode: 412,
66-
};
67-
throw error;
68-
}
69-
70-
// Fallback for any other calls
71-
return {
72-
Body: Readable.from([originalData.slice(0, 8 * 1024 * 1024)]),
73-
ETag: '"original-etag"',
74-
ContentLength: 8 * 1024 * 1024,
75-
};
76-
}
77-
});
78-
79-
const tm = new S3TransferManager({
80-
s3ClientInstance: new S3Client({}),
81-
targetPartSizeBytes: 8 * 1024 * 1024,
82-
multipartDownloadType: "PART", // Use PART mode to trigger the concurrent requests
83-
});
84-
85-
await expect(
86-
tm.download({
87-
Bucket: bucket,
88-
Key: key,
89-
})
90-
).rejects.toThrowError(
91-
expect.objectContaining({
92-
name: "PreconditionFailed",
93-
})
94-
);
95-
});
96-
});
97-
9830
describe("S3TransferManager Constructor", () => {
9931
it("Should create an instance of S3TransferManager with defaults given no parameters", () => {
10032
const tm = new S3TransferManager() as any;

lib/lib-storage/src/s3-transfer-manager/S3TransferManager.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,7 @@ import type {
55
PutObjectCommandInput,
66
} from "@aws-sdk/client-s3";
77
import { GetObjectCommand, HeadObjectCommand, S3Client } from "@aws-sdk/client-s3";
8-
import { CONFIG_RESPONSE_CHECKSUM_VALIDATION } from "@aws-sdk/middleware-flexible-checksums/dist-types";
9-
import { getChecksum } from "@aws-sdk/middleware-flexible-checksums/dist-types/getChecksum";
10-
import { copySnapshotPresignedUrlMiddlewareOptions } from "@aws-sdk/middleware-sdk-ec2/dist-types";
11-
import { type StreamingBlobPayloadOutputTypes, Checksum, ChecksumConstructor } from "@smithy/types";
8+
import { type StreamingBlobPayloadOutputTypes } from "@smithy/types";
129

1310
import type { AddEventListenerOptions, EventListener, RemoveEventListenerOptions } from "./event-listener-types";
1411
import { joinStreams } from "./join-streams";

lib/lib-storage/vitest.config.browser.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@ import { defineConfig } from "vitest/config";
33
export default defineConfig({
44
test: {
55
include: ["**/*.browser.spec.ts"],
6-
environment: "jsdom",
6+
environment: "happy-dom",
77
},
88
});

package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@
7979
"@typescript-eslint/eslint-plugin": "5.55.0",
8080
"@typescript-eslint/parser": "5.55.0",
8181
"async": "3.2.4",
82-
"aws-sdk-client-mock": "^4.1.0",
8382
"concurrently": "7.0.0",
8483
"decomment": "0.9.5",
8584
"downlevel-dts": "0.10.1",
@@ -96,7 +95,7 @@
9695
"fs-extra": "^9.0.0",
9796
"generate-changelog": "^1.7.1",
9897
"glob": "7.1.6",
99-
"happy-dom": "16.3.0",
98+
"happy-dom": "^18.0.1",
10099
"husky": "^4.2.3",
101100
"jest": "29.7.0",
102101
"jmespath": "^0.15.0",

0 commit comments

Comments
 (0)