Skip to content

Commit

Permalink
Integration tests (smithy-lang#851)
Browse files Browse the repository at this point in the history
  • Loading branch information
srchase authored Aug 15, 2023
1 parent a6a1389 commit 1be3c4c
Show file tree
Hide file tree
Showing 33 changed files with 676 additions and 58 deletions.
9 changes: 9 additions & 0 deletions .changeset/twenty-bears-fry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@smithy/middleware-apply-body-checksum": patch
"@smithy/middleware-content-length": patch
"@smithy/middleware-retry": patch
"@smithy/middleware-serde": patch
"@smithy/util-stream": patch
---

Add integration tests
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"clean": "turbo run clean --force --parallel",
"build": "turbo run build",
"test": "turbo run test",
"test:integration": "turbo run test:integration",
"lint": "turbo run lint",
"format": "turbo run format --parallel",
"stage-release": "turbo run stage-release",
Expand Down Expand Up @@ -65,7 +66,8 @@
"packages/*",
"smithy-typescript-ssdk-libs/*",
"smithy-typescript-codegen-test/build/smithyprojections/smithy-typescript-codegen-test/source/typescript-codegen",
"smithy-typescript-codegen-test/build/smithyprojections/smithy-typescript-codegen-test/ssdk-test/typescript-ssdk-codegen"
"smithy-typescript-codegen-test/build/smithyprojections/smithy-typescript-codegen-test/ssdk-test/typescript-ssdk-codegen",
"private/*"
],
"packageManager": "[email protected]"
}
4 changes: 4 additions & 0 deletions packages/middleware-apply-body-checksum/jest.config.integ.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module.exports = {
preset: "ts-jest",
testMatch: ["**/*.integ.spec.ts"],
};
4 changes: 3 additions & 1 deletion packages/middleware-apply-body-checksum/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
"clean": "rimraf ./dist-* && rimraf *.tsbuildinfo",
"lint": "eslint -c ../../.eslintrc.js \"src/**/*.ts\"",
"format": "prettier --config ../../prettier.config.js --ignore-path ../.prettierignore --write \"**/*.{ts,md,json}\"",
"test": "jest --coverage"
"test": "jest --coverage",
"test:integration": "jest --config jest.config.integ.js"
},
"main": "./dist-cjs/index.js",
"module": "./dist-es/index.js",
Expand Down Expand Up @@ -47,6 +48,7 @@
"directory": "packages/middleware-apply-body-checksum"
},
"devDependencies": {
"@smithy/util-test": "workspace:^",
"@tsconfig/recommended": "1.0.1",
"concurrently": "7.0.0",
"downlevel-dts": "0.10.1",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { requireRequestsFrom } from "@smithy/util-test";
import { Weather } from "weather";

describe("middleware-apply-body-checksum", () => {
describe(Weather.name, () => {
it("should add body-checksum", async () => {
const client = new Weather({ endpoint: "https://foo.bar" });
requireRequestsFrom(client).toMatch({
headers: {
"content-md5": /^.{22}(==)?$/i,
},
});

await client.getCity({
cityId: "my-city",
});

expect.assertions(1);
});
});
});
4 changes: 4 additions & 0 deletions packages/middleware-content-length/jest.config.integ.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module.exports = {
preset: "ts-jest",
testMatch: ["**/*.integ.spec.ts"],
};
4 changes: 3 additions & 1 deletion packages/middleware-content-length/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
"clean": "rimraf ./dist-* && rimraf *.tsbuildinfo",
"lint": "eslint -c ../../.eslintrc.js \"src/**/*.ts\"",
"format": "prettier --config ../../prettier.config.js --ignore-path ../.prettierignore --write \"**/*.{ts,md,json}\"",
"test": "exit 0"
"test": "exit 0",
"test:integration": "jest --config jest.config.integ.js"
},
"main": "./dist-cjs/index.js",
"module": "./dist-es/index.js",
Expand Down Expand Up @@ -46,6 +47,7 @@
"directory": "packages/middleware-content-length"
},
"devDependencies": {
"@smithy/util-test": "workspace:^",
"@tsconfig/recommended": "1.0.1",
"concurrently": "7.0.0",
"downlevel-dts": "0.10.1",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { requireRequestsFrom } from "@smithy/util-test";
import { Weather } from "weather";

describe("middleware-content-length", () => {
describe(Weather.name, () => {
it("should not add content-length if no body", async () => {
const client = new Weather({ endpoint: "https://foo.bar" });
requireRequestsFrom(client).toMatch({
headers: {
"content-length": /undefined/,
},
});

await client.getCity({
cityId: "my-city",
});

expect.assertions(1);
});

// Weather uses TestProtocolGenerator, which serializes all bodies as `{}`.
// This tests that content-length gets set to `2`, only where bodies are
// sent in the request.
it("should add content-length if body present", async () => {
const client = new Weather({ endpoint: "https://foo.bar" });
requireRequestsFrom(client).toMatch({
headers: {
"content-length": /2/,
},
});

console.log(client.middlewareStack);

await client.createCity({
name: "MyCity",
coordinates: {
latitude: 0,
longitude: 0,
},
});

expect.assertions(1);
});
});
});
4 changes: 4 additions & 0 deletions packages/middleware-retry/jest.config.integ.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module.exports = {
preset: "ts-jest",
testMatch: ["**/*.integ.spec.ts"],
};
4 changes: 3 additions & 1 deletion packages/middleware-retry/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
"lint": "eslint -c ../../.eslintrc.js \"src/**/*.ts\"",
"format": "prettier --config ../../prettier.config.js --ignore-path ../.prettierignore --write \"**/*.{ts,md,json}\"",
"extract:docs": "api-extractor run --local",
"test": "jest"
"test": "jest",
"test:integration": "jest --config jest.config.integ.js"
},
"main": "./dist-cjs/index.js",
"module": "./dist-es/index.js",
Expand All @@ -33,6 +34,7 @@
},
"devDependencies": {
"@smithy/node-config-provider": "workspace:^",
"@smithy/util-test": "workspace:^",
"@tsconfig/recommended": "1.0.1",
"@types/uuid": "^8.3.0",
"concurrently": "7.0.0",
Expand Down
24 changes: 24 additions & 0 deletions packages/middleware-retry/src/middleware-retry.integ.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { requireRequestsFrom } from "@smithy/util-test";
import { Weather } from "weather";

describe("middleware-retry", () => {
describe(Weather.name, () => {
it("should set retry headers", async () => {
const client = new Weather({ endpoint: "https://foo.bar" });

requireRequestsFrom(client).toMatch({
hostname: "foo.bar",
headers: {
"amz-sdk-invocation-id": /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/,
"amz-sdk-request": "attempt=1; max=3",
},
});

await client.getCity({
cityId: "my-city",
});

expect.hasAssertions();
});
});
});
4 changes: 4 additions & 0 deletions packages/middleware-serde/jest.config.integ.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module.exports = {
preset: "ts-jest",
testMatch: ["**/*.integ.spec.ts"],
};
4 changes: 3 additions & 1 deletion packages/middleware-serde/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
"clean": "rimraf ./dist-* && rimraf *.tsbuildinfo",
"lint": "eslint -c ../../.eslintrc.js \"src/**/*.ts\"",
"format": "prettier --config ../../prettier.config.js --ignore-path ../.prettierignore --write \"**/*.{ts,md,json}\"",
"test": "jest"
"test": "jest",
"test:integration": "jest --config jest.config.integ.js"
},
"main": "./dist-cjs/index.js",
"module": "./dist-es/index.js",
Expand Down Expand Up @@ -45,6 +46,7 @@
"directory": "packages/middleware-serde"
},
"devDependencies": {
"@smithy/util-test": "workspace:^",
"@tsconfig/recommended": "1.0.1",
"concurrently": "7.0.0",
"downlevel-dts": "0.10.1",
Expand Down
24 changes: 24 additions & 0 deletions packages/middleware-serde/src/middleware-serde.integ.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { requireRequestsFrom } from "@smithy/util-test";
import { Weather } from "weather";

describe("middleware-serde", () => {
describe(Weather.name, () => {
it("should serialize TestProtocol", async () => {
const client = new Weather({ endpoint: "https://foo.bar" });
requireRequestsFrom(client).toMatch({
method: "PUT",
hostname: "foo.bar",
body: "{}",
protocol: "https:",
path: "/city",
});
await client.createCity({
name: "MyCity",
coordinates: {
latitude: 0,
longitude: 0,
},
});
});
});
});
4 changes: 4 additions & 0 deletions packages/util-stream/jest.config.integ.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module.exports = {
preset: "ts-jest",
testMatch: ["**/*.integ.spec.ts"],
};
4 changes: 3 additions & 1 deletion packages/util-stream/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
"clean": "rimraf ./dist-* && rimraf *.tsbuildinfo",
"lint": "eslint -c ../../.eslintrc.js \"src/**/*.ts\"",
"format": "prettier --config ../../prettier.config.js --ignore-path ../.prettierignore --write \"**/*.{ts,md,json}\"",
"test": "jest && karma start karma.conf.js"
"test": "jest && karma start karma.conf.js",
"test:integration": "jest --config jest.config.integ.js"
},
"main": "./dist-cjs/index.js",
"module": "./dist-es/index.js",
Expand All @@ -32,6 +33,7 @@
"tslib": "^2.5.0"
},
"devDependencies": {
"@smithy/util-test": "workspace:^",
"@types/chai-as-promised": "^7.1.2",
"@types/node": "^14.14.31",
"chai": "^4.2.0",
Expand Down
112 changes: 112 additions & 0 deletions packages/util-stream/src/util-stream.integ.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import { HttpResponse } from "@smithy/protocol-http";
import { HttpRequest as IHttpRequest } from "@smithy/types";
import { Uint8ArrayBlobAdapter } from "@smithy/util-stream";
import { requireRequestsFrom } from "@smithy/util-test";
import { fromUtf8 } from "@smithy/util-utf8";
import { Readable } from "stream";
import { Weather } from "weather";

describe("util-stream", () => {
describe(Weather.name, () => {
it("should be uniform between string and Uint8Array payloads", async () => {
const client = new Weather({ endpoint: "https://foo.bar" });
requireRequestsFrom(client).toMatch({
method: "POST",
hostname: "foo.bar",
query: {},
headers: {
"content-type": "application/octet-stream",
"content-length": "17",
},
body(raw) {
expect(raw.toString("utf-8")).toEqual('{"hello":"world"}');
},
protocol: "https:",
path: "/invoke",
});

// string
await client.invoke({
payload: JSON.stringify({
hello: "world",
}),
});

// Uint8Array
await client.invoke({
payload: Buffer.from(
JSON.stringify({
hello: "world",
})
),
});
});
});

describe("blob helper integration", () => {
const FunctionName = "echo";

const client = new Weather({ endpoint: "https://foo.bar" });

requireRequestsFrom(client).toMatch({
method: "POST",
hostname: "foo.bar",
query: {},
headers: {
"content-type": "application/octet-stream",
},
protocol: "https:",
path: "/invoke",
});

client.config.requestHandler = new (class {
async handle(request: IHttpRequest) {
return {
response: new HttpResponse({
statusCode: 200,
body: typeof request.body === "string" ? fromUtf8(request.body) : Uint8Array.from(request.body),
}),
};
}
})();

it("should allow string as payload blob and allow conversion of output payload blob to string", async () => {
const payload = JSON.stringify({ hello: "world" });
const invoke = await client.invoke({ payload: payload });
expect(JSON.parse(invoke?.payload?.transformToString() ?? "{}")).toEqual({ hello: "world" });
});

it("should allow Uint8Array as payload blob", async () => {
const payload = Uint8ArrayBlobAdapter.fromString(JSON.stringify({ hello: "world" }));
const invoke = await client.invoke({ payload: payload });
expect(JSON.parse(invoke?.payload?.transformToString() ?? "{}")).toEqual({ hello: "world" });
});

it("should allow buffer as payload blob", async () => {
// note: Buffer extends Uint8Array
const payload = Buffer.from(Uint8ArrayBlobAdapter.fromString(JSON.stringify({ hello: "world" })));
const invoke = await client.invoke({ payload: payload });
expect(JSON.parse(invoke?.payload?.transformToString() ?? "{}")).toEqual({ hello: "world" });
});

it("should allow stream as payload blob but not be able to sign it", async () => {
const payload = Readable.from(Buffer.from(Uint8ArrayBlobAdapter.fromString(JSON.stringify({ hello: "world" }))), {
encoding: "utf-8",
});
expect(JSON.parse(await streamToString(payload))).toEqual({ hello: "world" });
await client.invoke({ payload: payload }).catch((e) => {
expect(e.toString()).toContain("InvalidSignatureException");
});
expect.hasAssertions();
});
});

function streamToString(stream: Readable): Promise<string> {
const chunks: any[] = [];
return new Promise((resolve, reject) => {
stream.on("data", (chunk) => chunks.push(Buffer.from(chunk)));
stream.on("error", (err) => reject(err));
stream.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
});
}
});
8 changes: 8 additions & 0 deletions private/util-test/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/node_modules/
/build/
/coverage/
/docs/
*.tsbuildinfo
*.tgz
*.log
package-lock.json
Loading

0 comments on commit 1be3c4c

Please sign in to comment.