Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import { requireRequestsFrom } from "@aws-sdk/aws-util-test/src";
import { DynamoDB } from "@aws-sdk/client-dynamodb";
import type { AccountIdEndpointMode } from "@aws-sdk/core/account-id-endpoint";
import type { AwsCredentialIdentity } from "@smithy/types";
import { afterEach, beforeEach, describe, expect, test as it } from "vitest";

describe("account id endpoint", () => {
const region = "us-west-2";

beforeEach(async () => {
delete process.env.AWS_ACCOUNT_ID_ENDPOINT_MODE;
});

afterEach(async () => {
delete process.env.AWS_ACCOUNT_ID_ENDPOINT_MODE;
});

describe("when credentials have account id", () => {
const credentials: AwsCredentialIdentity = {
accessKeyId: "INTEG_TEST",
secretAccessKey: "INTEG_TEST",
accountId: "123456789012",
};

it("should default to resolving endpoint with account id when it is available in the client credentials", async () => {
const ddb = new DynamoDB({
region,
credentials,
});
requireRequestsFrom(ddb).toMatch({
hostname: /123456789012.ddb.us-west-2.amazonaws.com/,
});
await ddb.listTables();
});

describe("config values", () => {
it.each([
["dynamodb", "disabled"],
["123456789012.ddb", "preferred"],
["123456789012.ddb", "required"],
])(
"should match prefix '%s' for when accountId endpoint mode is '%s' in config",
async (expectedHostnamePrefix, mode) => {
const ddb = new DynamoDB({
region,
credentials,
accountIdEndpointMode: mode as AccountIdEndpointMode,
});
requireRequestsFrom(ddb).toMatch({
hostname: `${expectedHostnamePrefix}.${region}.amazonaws.com`,
});
await ddb.listTables();
}
);
});

describe("ENV values", () => {
it.each([
["dynamodb", "disabled"],
["123456789012.ddb", "preferred"],
["123456789012.ddb", "required"],
])(
"should match prefix '%s' for when accountId endpoint mode is '%s' in ENV",
async (expectedHostnamePrefix, mode) => {
process.env.AWS_ACCOUNT_ID_ENDPOINT_MODE = mode;
const ddb = new DynamoDB({
region,
credentials,
});
requireRequestsFrom(ddb).toMatch({
hostname: `${expectedHostnamePrefix}.${region}.amazonaws.com`,
});
await ddb.listTables();
}
);
});
});

describe("when credentials do not have account id", () => {
const credentials = {
accessKeyId: "INTEG_TEST",
secretAccessKey: "INTEG_TEST",
};

it("it follows that the hostname will not have it either", async () => {
const ddb = new DynamoDB({
region,
credentials,
});
requireRequestsFrom(ddb).toMatch({
hostname: /dynamodb.us-west-2.amazonaws.com/,
});
await ddb.listTables();
});

it("will fail if required by ENV", async () => {
process.env.AWS_ACCOUNT_ID_ENDPOINT_MODE = "required";
const ddb = new DynamoDB({
region,
credentials,
});
const error = await ddb.listTables().catch((e) => e);
expect(error.name).toEqual("EndpointError");
});

it("will fail if required by config", async () => {
const ddb = new DynamoDB({
region,
credentials,
accountIdEndpointMode: "required",
});
const error = await ddb.listTables().catch((e) => e);
expect(error.name).toEqual("EndpointError");
});
});
});
92 changes: 92 additions & 0 deletions packages/core/src/submodules/client/pagination.integ.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { requireRequestsFrom } from "@aws-sdk/aws-util-test/src";
import { DynamoDB, paginateScan, ScanCommandInput } from "@aws-sdk/client-dynamodb";
import { HttpResponse } from "@smithy/protocol-http";
import { describe, expect, test as it } from "vitest";

describe("pagination", () => {
it("makes sequential requests using a pagination token", async () => {
const ddb = new DynamoDB({
credentials: {
accessKeyId: "INTEG_TEST",
secretAccessKey: "INTEG_TEST",
},
region: "us-west-2",
});

requireRequestsFrom(ddb)
.toMatch(
{
hostname: /dynamodb/,
body(b) {
expect(b).toContain("TableName");
expect(b).not.toContain("ExclusiveStartKey");
},
},
{
hostname: /dynamodb/,
body: /ExclusiveStartKey/,
}
)
.respondWith(
new HttpResponse({
statusCode: 200,
headers: {},
body: Buffer.from(
JSON.stringify({
Items: [
{
id: { S: "1" },
name: { S: "Item 1" },
},
{
id: { S: "2" },
name: { S: "Item 2" },
},
],
Count: 2,
ScannedCount: 2,
LastEvaluatedKey: {
id: { S: "2" },
},
})
),
}),
new HttpResponse({
statusCode: 200,
headers: {},
body: Buffer.from(
JSON.stringify({
Items: [
{
id: { S: "3" },
name: { S: "Item 3" },
},
{
id: { S: "4" },
name: { S: "Item 4" },
},
],
Count: 2,
ScannedCount: 2,
})
),
})
);

const requestParams: ScanCommandInput = {
TableName: "test",
};

let pages = 0;
for await (const page of paginateScan({ client: ddb }, requestParams)) {
void page;
pages += 1;
}

expect(pages).toEqual(2);
expect(requestParams.ExclusiveStartKey).toEqual({
id: { S: "2" },
});
expect.assertions(7);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { requireRequestsFrom } from "@aws-sdk/aws-util-test/src";
import { Schemas } from "@aws-sdk/client-schemas";
import { LazyJsonString } from "@smithy/core/serde";
import { describe, expect, test as it } from "vitest";

describe(LazyJsonString.name, () => {
it("should auto-serialize fields to JSON", async () => {
const client = new Schemas({
region: "us-west-2",
});

let request = 0;

requireRequestsFrom(client).toMatch({
body(b) {
if (request === 0) {
expect(b).toEqual(`{"Policy":"this is a plain string"}`);
request += 1;
} else if (request === 1) {
expect(b).toEqual(`{"Policy":"{\\"this\\":\\"is a json string\\"}"}`);
request += 1;
} else if (request === 2) {
expect(b).toEqual(`{"Policy":"{\\"message\\":\\"this is a js object\\"}"}`);
request += 1;
}
},
});

await client.putResourcePolicy({
Policy: "this is a plain string",
});
await client.putResourcePolicy({
Policy: `{"this":"is a json string"}`,
});
await client.putResourcePolicy({
Policy: {
message: "this is a js object",
},
});
expect.assertions(3);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import { requireRequestsFrom } from "@aws-sdk/aws-util-test/src";
import { type MetricDatum, CloudWatch } from "@aws-sdk/client-cloudwatch";
import type { AwsCredentialIdentity } from "@smithy/types";
import { describe, test as it } from "vitest";

describe("request compression", () => {
const credentials: AwsCredentialIdentity = {
accessKeyId: "INTEG_TEST",
secretAccessKey: "INTEG_TEST",
};

const smallMetricData: MetricDatum[] = [
{
MetricName: "TestMetric1",
Value: 42,
Unit: "Count",
Timestamp: new Date(0),
Dimensions: [
{
Name: "Environment",
Value: "Test",
},
],
},
];

const largeMetricData = Array.from({ length: 1000 }).map(() => smallMetricData[0]);

it("should not compress small payloads", async () => {
const cw = new CloudWatch({
credentials,
region: "us-west-2",
});

requireRequestsFrom(cw).toMatch({
headers: {
"content-encoding": /undefined/,
},
});

await cw.putMetricData({
Namespace: "TestMetrics",
MetricData: smallMetricData,
});
});

it("should compress larger payloads", async () => {
const cw = new CloudWatch({
credentials,
region: "us-west-2",
});

requireRequestsFrom(cw).toMatch({
headers: {
"content-encoding": /^gzip$/,
},
});

await cw.putMetricData({
Namespace: "TestMetrics",
MetricData: largeMetricData,
});
});

describe("compression configuration", () => {
it("can be shut off", async () => {
const cw = new CloudWatch({
credentials,
disableRequestCompression: true,
region: "us-west-2",
});

requireRequestsFrom(cw).toMatch({
headers: {
"content-encoding": /undefined/,
},
});

await cw.putMetricData({
Namespace: "TestMetrics",
MetricData: largeMetricData,
});
});

it("should compress payloads barely beyond the specified limit", async () => {
const cw = new CloudWatch({
credentials,
requestMinCompressionSizeBytes: 277_419,
region: "us-west-2",
});

requireRequestsFrom(cw).toMatch({
headers: {
"content-encoding": /^gzip$/,
},
});

await cw.putMetricData({
Namespace: "TestMetrics",
MetricData: largeMetricData,
});
});

it("should not compress payloads barely below the specified limit", async () => {
const cw = new CloudWatch({
credentials,
requestMinCompressionSizeBytes: 277_420,
region: "us-west-2",
});

requireRequestsFrom(cw).toMatch({
headers: {
"content-encoding": /undefined/,
},
});

await cw.putMetricData({
Namespace: "TestMetrics",
MetricData: largeMetricData,
});
});
});
});
4 changes: 3 additions & 1 deletion private/aws-util-test/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
"version": "3.848.0",
"private": true,
"scripts": {
"build": "concurrently 'yarn:build:cjs' 'yarn:build:types'",
"build": "concurrently 'yarn:build:cjs' 'yarn:build:es' 'yarn:build:types'",
"build:es": "tsc -p tsconfig.es.json",
"build:cjs": "tsc -p tsconfig.cjs.json",
"build:include:deps": "lerna run --scope $npm_package_name --include-dependencies build",
"build:types": "tsc -p tsconfig.types.json",
Expand All @@ -14,6 +15,7 @@
"test:integration:watch": "yarn g:vitest watch -c vitest.config.integ.js"
},
"main": "./dist-cjs/index.js",
"module": "./dist-es/index.js",
"types": "./dist-types/index.d.ts",
"sideEffects": false,
"dependencies": {
Expand Down
Loading
Loading