Skip to content

Commit 5c5e7ce

Browse files
authored
test(core): new integration tests (#7229)
* test(core): new integration tests * test: formatting comments
1 parent 9c6a29e commit 5c5e7ce

File tree

7 files changed

+419
-8
lines changed

7 files changed

+419
-8
lines changed
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import { requireRequestsFrom } from "@aws-sdk/aws-util-test/src";
2+
import { DynamoDB } from "@aws-sdk/client-dynamodb";
3+
import type { AccountIdEndpointMode } from "@aws-sdk/core/account-id-endpoint";
4+
import type { AwsCredentialIdentity } from "@smithy/types";
5+
import { afterEach, beforeEach, describe, expect, test as it } from "vitest";
6+
7+
describe("account id endpoint", () => {
8+
const region = "us-west-2";
9+
10+
beforeEach(async () => {
11+
delete process.env.AWS_ACCOUNT_ID_ENDPOINT_MODE;
12+
});
13+
14+
afterEach(async () => {
15+
delete process.env.AWS_ACCOUNT_ID_ENDPOINT_MODE;
16+
});
17+
18+
describe("when credentials have account id", () => {
19+
const credentials: AwsCredentialIdentity = {
20+
accessKeyId: "INTEG_TEST",
21+
secretAccessKey: "INTEG_TEST",
22+
accountId: "123456789012",
23+
};
24+
25+
it("should default to resolving endpoint with account id when it is available in the client credentials", async () => {
26+
const ddb = new DynamoDB({
27+
region,
28+
credentials,
29+
});
30+
requireRequestsFrom(ddb).toMatch({
31+
hostname: /123456789012.ddb.us-west-2.amazonaws.com/,
32+
});
33+
await ddb.listTables();
34+
});
35+
36+
describe("config values", () => {
37+
it.each([
38+
["dynamodb", "disabled"],
39+
["123456789012.ddb", "preferred"],
40+
["123456789012.ddb", "required"],
41+
])(
42+
"should match prefix '%s' for when accountId endpoint mode is '%s' in config",
43+
async (expectedHostnamePrefix, mode) => {
44+
const ddb = new DynamoDB({
45+
region,
46+
credentials,
47+
accountIdEndpointMode: mode as AccountIdEndpointMode,
48+
});
49+
requireRequestsFrom(ddb).toMatch({
50+
hostname: `${expectedHostnamePrefix}.${region}.amazonaws.com`,
51+
});
52+
await ddb.listTables();
53+
}
54+
);
55+
});
56+
57+
describe("ENV values", () => {
58+
it.each([
59+
["dynamodb", "disabled"],
60+
["123456789012.ddb", "preferred"],
61+
["123456789012.ddb", "required"],
62+
])(
63+
"should match prefix '%s' for when accountId endpoint mode is '%s' in ENV",
64+
async (expectedHostnamePrefix, mode) => {
65+
process.env.AWS_ACCOUNT_ID_ENDPOINT_MODE = mode;
66+
const ddb = new DynamoDB({
67+
region,
68+
credentials,
69+
});
70+
requireRequestsFrom(ddb).toMatch({
71+
hostname: `${expectedHostnamePrefix}.${region}.amazonaws.com`,
72+
});
73+
await ddb.listTables();
74+
}
75+
);
76+
});
77+
});
78+
79+
describe("when credentials do not have account id", () => {
80+
const credentials = {
81+
accessKeyId: "INTEG_TEST",
82+
secretAccessKey: "INTEG_TEST",
83+
};
84+
85+
it("it follows that the hostname will not have it either", async () => {
86+
const ddb = new DynamoDB({
87+
region,
88+
credentials,
89+
});
90+
requireRequestsFrom(ddb).toMatch({
91+
hostname: /dynamodb.us-west-2.amazonaws.com/,
92+
});
93+
await ddb.listTables();
94+
});
95+
96+
it("will fail if required by ENV", async () => {
97+
process.env.AWS_ACCOUNT_ID_ENDPOINT_MODE = "required";
98+
const ddb = new DynamoDB({
99+
region,
100+
credentials,
101+
});
102+
const error = await ddb.listTables().catch((e) => e);
103+
expect(error.name).toEqual("EndpointError");
104+
});
105+
106+
it("will fail if required by config", async () => {
107+
const ddb = new DynamoDB({
108+
region,
109+
credentials,
110+
accountIdEndpointMode: "required",
111+
});
112+
const error = await ddb.listTables().catch((e) => e);
113+
expect(error.name).toEqual("EndpointError");
114+
});
115+
});
116+
});
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import { requireRequestsFrom } from "@aws-sdk/aws-util-test/src";
2+
import { DynamoDB, paginateScan, ScanCommandInput } from "@aws-sdk/client-dynamodb";
3+
import { HttpResponse } from "@smithy/protocol-http";
4+
import { describe, expect, test as it } from "vitest";
5+
6+
describe("pagination", () => {
7+
it("makes sequential requests using a pagination token", async () => {
8+
const ddb = new DynamoDB({
9+
credentials: {
10+
accessKeyId: "INTEG_TEST",
11+
secretAccessKey: "INTEG_TEST",
12+
},
13+
region: "us-west-2",
14+
});
15+
16+
requireRequestsFrom(ddb)
17+
.toMatch(
18+
{
19+
hostname: /dynamodb/,
20+
body(b) {
21+
expect(b).toContain("TableName");
22+
expect(b).not.toContain("ExclusiveStartKey");
23+
},
24+
},
25+
{
26+
hostname: /dynamodb/,
27+
body: /ExclusiveStartKey/,
28+
}
29+
)
30+
.respondWith(
31+
new HttpResponse({
32+
statusCode: 200,
33+
headers: {},
34+
body: Buffer.from(
35+
JSON.stringify({
36+
Items: [
37+
{
38+
id: { S: "1" },
39+
name: { S: "Item 1" },
40+
},
41+
{
42+
id: { S: "2" },
43+
name: { S: "Item 2" },
44+
},
45+
],
46+
Count: 2,
47+
ScannedCount: 2,
48+
LastEvaluatedKey: {
49+
id: { S: "2" },
50+
},
51+
})
52+
),
53+
}),
54+
new HttpResponse({
55+
statusCode: 200,
56+
headers: {},
57+
body: Buffer.from(
58+
JSON.stringify({
59+
Items: [
60+
{
61+
id: { S: "3" },
62+
name: { S: "Item 3" },
63+
},
64+
{
65+
id: { S: "4" },
66+
name: { S: "Item 4" },
67+
},
68+
],
69+
Count: 2,
70+
ScannedCount: 2,
71+
})
72+
),
73+
})
74+
);
75+
76+
const requestParams: ScanCommandInput = {
77+
TableName: "test",
78+
};
79+
80+
let pages = 0;
81+
for await (const page of paginateScan({ client: ddb }, requestParams)) {
82+
void page;
83+
pages += 1;
84+
}
85+
86+
expect(pages).toEqual(2);
87+
expect(requestParams.ExclusiveStartKey).toEqual({
88+
id: { S: "2" },
89+
});
90+
expect.assertions(7);
91+
});
92+
});
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { requireRequestsFrom } from "@aws-sdk/aws-util-test/src";
2+
import { Schemas } from "@aws-sdk/client-schemas";
3+
import { LazyJsonString } from "@smithy/core/serde";
4+
import { describe, expect, test as it } from "vitest";
5+
6+
describe(LazyJsonString.name, () => {
7+
it("should auto-serialize fields to JSON", async () => {
8+
const client = new Schemas({
9+
region: "us-west-2",
10+
});
11+
12+
let request = 0;
13+
14+
requireRequestsFrom(client).toMatch({
15+
body(b) {
16+
if (request === 0) {
17+
expect(b).toEqual(`{"Policy":"this is a plain string"}`);
18+
request += 1;
19+
} else if (request === 1) {
20+
expect(b).toEqual(`{"Policy":"{\\"this\\":\\"is a json string\\"}"}`);
21+
request += 1;
22+
} else if (request === 2) {
23+
expect(b).toEqual(`{"Policy":"{\\"message\\":\\"this is a js object\\"}"}`);
24+
request += 1;
25+
}
26+
},
27+
});
28+
29+
await client.putResourcePolicy({
30+
Policy: "this is a plain string",
31+
});
32+
await client.putResourcePolicy({
33+
Policy: `{"this":"is a json string"}`,
34+
});
35+
await client.putResourcePolicy({
36+
Policy: {
37+
message: "this is a js object",
38+
},
39+
});
40+
expect.assertions(3);
41+
});
42+
});
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
import { requireRequestsFrom } from "@aws-sdk/aws-util-test/src";
2+
import { type MetricDatum, CloudWatch } from "@aws-sdk/client-cloudwatch";
3+
import type { AwsCredentialIdentity } from "@smithy/types";
4+
import { describe, test as it } from "vitest";
5+
6+
describe("request compression", () => {
7+
const credentials: AwsCredentialIdentity = {
8+
accessKeyId: "INTEG_TEST",
9+
secretAccessKey: "INTEG_TEST",
10+
};
11+
12+
const smallMetricData: MetricDatum[] = [
13+
{
14+
MetricName: "TestMetric1",
15+
Value: 42,
16+
Unit: "Count",
17+
Timestamp: new Date(0),
18+
Dimensions: [
19+
{
20+
Name: "Environment",
21+
Value: "Test",
22+
},
23+
],
24+
},
25+
];
26+
27+
const largeMetricData = Array.from({ length: 1000 }).map(() => smallMetricData[0]);
28+
29+
it("should not compress small payloads", async () => {
30+
const cw = new CloudWatch({
31+
credentials,
32+
region: "us-west-2",
33+
});
34+
35+
requireRequestsFrom(cw).toMatch({
36+
headers: {
37+
"content-encoding": /undefined/,
38+
},
39+
});
40+
41+
await cw.putMetricData({
42+
Namespace: "TestMetrics",
43+
MetricData: smallMetricData,
44+
});
45+
});
46+
47+
it("should compress larger payloads", async () => {
48+
const cw = new CloudWatch({
49+
credentials,
50+
region: "us-west-2",
51+
});
52+
53+
requireRequestsFrom(cw).toMatch({
54+
headers: {
55+
"content-encoding": /^gzip$/,
56+
},
57+
});
58+
59+
await cw.putMetricData({
60+
Namespace: "TestMetrics",
61+
MetricData: largeMetricData,
62+
});
63+
});
64+
65+
describe("compression configuration", () => {
66+
it("can be shut off", async () => {
67+
const cw = new CloudWatch({
68+
credentials,
69+
disableRequestCompression: true,
70+
region: "us-west-2",
71+
});
72+
73+
requireRequestsFrom(cw).toMatch({
74+
headers: {
75+
"content-encoding": /undefined/,
76+
},
77+
});
78+
79+
await cw.putMetricData({
80+
Namespace: "TestMetrics",
81+
MetricData: largeMetricData,
82+
});
83+
});
84+
85+
it("should compress payloads barely beyond the specified limit", async () => {
86+
const cw = new CloudWatch({
87+
credentials,
88+
requestMinCompressionSizeBytes: 277_419,
89+
region: "us-west-2",
90+
});
91+
92+
requireRequestsFrom(cw).toMatch({
93+
headers: {
94+
"content-encoding": /^gzip$/,
95+
},
96+
});
97+
98+
await cw.putMetricData({
99+
Namespace: "TestMetrics",
100+
MetricData: largeMetricData,
101+
});
102+
});
103+
104+
it("should not compress payloads barely below the specified limit", async () => {
105+
const cw = new CloudWatch({
106+
credentials,
107+
requestMinCompressionSizeBytes: 277_420,
108+
region: "us-west-2",
109+
});
110+
111+
requireRequestsFrom(cw).toMatch({
112+
headers: {
113+
"content-encoding": /undefined/,
114+
},
115+
});
116+
117+
await cw.putMetricData({
118+
Namespace: "TestMetrics",
119+
MetricData: largeMetricData,
120+
});
121+
});
122+
});
123+
});

private/aws-util-test/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
"version": "3.848.0",
44
"private": true,
55
"scripts": {
6-
"build": "concurrently 'yarn:build:cjs' 'yarn:build:types'",
6+
"build": "concurrently 'yarn:build:cjs' 'yarn:build:es' 'yarn:build:types'",
7+
"build:es": "tsc -p tsconfig.es.json",
78
"build:cjs": "tsc -p tsconfig.cjs.json",
89
"build:include:deps": "lerna run --scope $npm_package_name --include-dependencies build",
910
"build:types": "tsc -p tsconfig.types.json",
@@ -14,6 +15,7 @@
1415
"test:integration:watch": "yarn g:vitest watch -c vitest.config.integ.js"
1516
},
1617
"main": "./dist-cjs/index.js",
18+
"module": "./dist-es/index.js",
1719
"types": "./dist-types/index.d.ts",
1820
"sideEffects": false,
1921
"dependencies": {

0 commit comments

Comments
 (0)