Skip to content

Commit 133430c

Browse files
AllanZhengYPtrivikr
authored andcommitted
feat: add support for browser streaming (#721)
1 parent 97bbb9a commit 133430c

File tree

12 files changed

+82
-91
lines changed

12 files changed

+82
-91
lines changed

jest.config.js

+1-7
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,9 @@ const base = require("./jest.config.base.js");
33
module.exports = {
44
...base,
55
projects: ["<rootDir>/packages/*/jest.config.js"],
6-
testPathIgnorePatterns: [
7-
"<rootDir>/packages/add-glacier-checksum-headers-browser",
8-
"<rootDir>/clients/client-.*"
9-
],
6+
testPathIgnorePatterns: ["/node_modules/", "<rootDir>/clients/client-.*"],
107
coveragePathIgnorePatterns: [
118
"/node_modules/",
12-
"<rootDir>/packages/add-glacier-checksum-headers-browser",
13-
"<rootDir>/packages/crypto-sjcl-*",
14-
"<rootDir>/packages/xml-body-parser/vendor/",
159
"<rootDir>/clients/client-.*",
1610
"/__fixtures__/"
1711
]

package.json

+11-5
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
"build:smithy-client": "yarn build:crypto-dependencies && lerna run --scope '@aws-sdk/client-rds-data' --include-dependencies pretest",
1515
"build:all": "yarn build:crypto-dependencies && lerna run pretest --include-dependencies --include-dependents",
1616
"pretest:all": "yarn build:all",
17-
"test:all": "jest --coverage --passWithNoTests",
17+
"test:all": "jest --coverage --passWithNoTests && lerna run test --scope @aws-sdk/stream-collector-browser --scope @aws-sdk/hash-blob-browser",
1818
"test:functional": "jest --config tests/functional/jest.config.js --passWithNoTests",
1919
"test:integration": "cucumber.js"
2020
},
@@ -50,10 +50,16 @@
5050
"typescript": "^3.7.0",
5151
"yarn": "1.21.1"
5252
},
53-
"workspaces": [
54-
"packages/*",
55-
"clients/*"
56-
],
53+
"workspaces": {
54+
"packages": [
55+
"packages/*",
56+
"clients/*"
57+
],
58+
"nohoist": [
59+
"**/karma*",
60+
"**/karma*/**"
61+
]
62+
},
5763
"husky": {
5864
"hooks": {
5965
"pre-commit": "lint-staged",

packages/fetch-http-handler/src/fetch-http-handler.spec.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ describe("httpHandler", () => {
4040
["bizz", "bazz"]
4141
])
4242
},
43-
blob: jest.fn().mockResolvedValue("")
43+
body: "FOO" //should be a ReadableStream in real life.
4444
};
4545
const mockFetch = jest.fn().mockResolvedValue(mockResponse);
4646

@@ -50,7 +50,7 @@ describe("httpHandler", () => {
5050
let response = await fetchHttpHandler.handle({} as any, {});
5151

5252
expect(mockFetch.mock.calls.length).toBe(1);
53-
expect(mockResponse.blob.mock.calls.length).toBe(1);
53+
expect(response.response.body).toBe("FOO");
5454
});
5555

5656
it("properly constructs url", async () => {
@@ -61,7 +61,7 @@ describe("httpHandler", () => {
6161
["bizz", "bazz"]
6262
])
6363
},
64-
blob: jest.fn().mockResolvedValue("")
64+
body: ""
6565
};
6666
const mockFetch = jest.fn().mockResolvedValue(mockResponse);
6767

packages/fetch-http-handler/src/fetch-http-handler.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,13 @@ export class FetchHttpHandler implements HttpHandler {
7272
transformedHeaders[pair[0]] = pair[1];
7373
}
7474

75-
return response.blob().then<{ response: HttpResponse }>(body => ({
75+
return {
7676
response: new HttpResponse({
7777
headers: transformedHeaders,
7878
statusCode: response.status,
79-
body
79+
body: response.body
8080
})
81-
}));
81+
};
8282
}),
8383
requestTimeout(requestTimeoutInMs)
8484
];

packages/hash-blob-browser/karma.conf.js

+7-3
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,13 @@ module.exports = function(config) {
4848
// enable / disable watching file and executing tests whenever any file changes
4949
autoWatch: false,
5050

51-
// start these browsers
52-
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
53-
browsers: ["ChromeHeadless"],
51+
browsers: ["ChromeHeadlessNoSandbox"],
52+
customLaunchers: {
53+
ChromeHeadlessNoSandbox: {
54+
base: "ChromeHeadless",
55+
flags: ["--no-sandbox"]
56+
}
57+
},
5458

5559
// Continuous Integration mode
5660
// if true, Karma captures browsers, runs the tests and exits

packages/stream-collector-browser/jest.config.js

-5
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
process.env.CHROME_BIN = require("puppeteer").executablePath();
2+
module.exports = function(config) {
3+
config.set({
4+
frameworks: ["jasmine", "karma-typescript"],
5+
files: ["src/**/*.ts"],
6+
exclude: ["**/*.d.ts"],
7+
preprocessors: {
8+
"**/*.ts": "karma-typescript"
9+
},
10+
reporters: ["progress", "karma-typescript"],
11+
browsers: ["ChromeHeadlessNoSandbox"],
12+
customLaunchers: {
13+
ChromeHeadlessNoSandbox: {
14+
base: "ChromeHeadless",
15+
flags: ["--no-sandbox"]
16+
}
17+
},
18+
karmaTypescriptConfig: {
19+
tsconfig: "./tsconfig.json",
20+
bundlerOptions: {
21+
addNodeGlobals: false
22+
}
23+
},
24+
singleRun: true
25+
});
26+
};

packages/stream-collector-browser/package.json

+9-3
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
"description": "Provides a way to store the contents of a stream into a Uint8Array",
55
"scripts": {
66
"prepublishOnly": "tsc",
7-
"pretest": "tsc -p tsconfig.test.json",
8-
"test": "jest --coverage"
7+
"pretest": "tsc -p tsconfig.json",
8+
"test": "karma start karma.conf.js"
99
},
1010
"author": {
1111
"name": "AWS SDK for JavaScript Team",
@@ -20,7 +20,13 @@
2020
},
2121
"devDependencies": {
2222
"@types/jest": "^24.0.12",
23-
"jest": "^24.7.1",
23+
"jasmine-core": "^3.5.0",
24+
"karma": "^4.4.1",
25+
"karma-chrome-launcher": "^3.1.0",
26+
"karma-jasmine": "^2.0.1",
27+
"karma-typescript": "^4.1.1",
28+
"puppeteer": "^2.0.0",
29+
"source-map": "^0.7.3",
2430
"typescript": "~3.4.0"
2531
}
2632
}

packages/stream-collector-browser/src/index.spec.ts

+15-41
Original file line numberDiff line numberDiff line change
@@ -3,48 +3,22 @@ import { streamCollector } from "./index";
33
declare const global: any;
44

55
describe("streamCollector", () => {
6-
const ambientFileReader =
7-
typeof FileReader !== "undefined" ? FileReader : undefined;
8-
9-
beforeEach(() => {
10-
const mockFileReader: FileReader = {
11-
readAsArrayBuffer: jest.fn()
12-
} as any;
13-
global.FileReader = function() {
14-
return mockFileReader;
15-
} as any;
16-
});
17-
18-
afterEach(() => {
19-
global.FileReader = ambientFileReader as any;
20-
});
21-
22-
it("returns a Uint8Array from a blob", async () => {
23-
const dataPromise = streamCollector(new Blob());
24-
25-
const reader = new FileReader();
26-
(reader as any).result = Uint8Array.from([0xde, 0xad]).buffer;
27-
reader.onload!({} as any);
28-
29-
expect(await dataPromise).toEqual(Uint8Array.from([0xde, 0xad]));
6+
it("returns a Uint8Array from a blob", done => {
7+
const dataPromise = streamCollector(
8+
new Response(new Uint8Array([102, 111, 111]).buffer).body
9+
);
10+
dataPromise.then((data: any) => {
11+
expect(data).toEqual(Uint8Array.from([102, 111, 111]));
12+
done();
13+
});
3014
});
3115

32-
it("propagates errors encountered by the file reader", async () => {
33-
const dataPromise = streamCollector(new Blob());
34-
35-
const reader = new FileReader();
36-
(reader as any).error = new Error("PANIC");
37-
reader.onerror!({} as any);
38-
39-
await expect(dataPromise).rejects.toMatchObject(new Error("PANIC"));
40-
});
41-
42-
it("rejects the promise when the read is aborted", async () => {
43-
const dataPromise = streamCollector(new Blob());
44-
45-
const reader = new FileReader();
46-
reader.onabort!({} as any);
47-
48-
await expect(dataPromise).rejects.toMatchObject(new Error("Read aborted"));
16+
it("returns a Uint8Array when stream is empty", done => {
17+
const expected = new Uint8Array(0);
18+
const dataPromise = streamCollector(new Response(expected.buffer).body);
19+
dataPromise.then((data: any) => {
20+
expect(data).toEqual(expected);
21+
done();
22+
});
4923
});
5024
});
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11
import { StreamCollector } from "@aws-sdk/types";
22

33
export const streamCollector: StreamCollector = (
4-
stream: Blob
5-
): Promise<Uint8Array> =>
6-
new Promise<Uint8Array>((resolve, reject) => {
7-
const reader = new FileReader();
8-
reader.onload = () => resolve(new Uint8Array(reader.result as ArrayBuffer));
9-
reader.onabort = () => reject(new Error("Read aborted"));
10-
reader.onerror = () => reject(reader.error);
11-
reader.readAsArrayBuffer(stream);
12-
});
4+
stream: ReadableStream
5+
): Promise<Uint8Array> => {
6+
return new Response(stream)
7+
.arrayBuffer()
8+
.then(arrayBuffer => new Uint8Array(arrayBuffer));
9+
};

packages/stream-collector-browser/tsconfig.test.json

-11
This file was deleted.

packages/types/src/crypto.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export interface HashConstructor {
3737
* will consume the stream, so only replayable streams should be provided to an
3838
* implementation of this interface.
3939
*/
40-
export interface StreamHasher<StreamType> {
40+
export interface StreamHasher<StreamType = any> {
4141
(hashCtor: { new (): Hash }, stream: StreamType): Promise<Uint8Array>;
4242
}
4343

0 commit comments

Comments
 (0)