From 6cad22b44375ed20118e7659a66d1489ca2b1ca2 Mon Sep 17 00:00:00 2001 From: George Fu Date: Mon, 10 Nov 2025 11:01:11 -0500 Subject: [PATCH 1/2] test(client-cloudwatch-logs): e2e test for protocol selection and event streams --- clients/client-cloudwatch-logs/package.json | 4 +- .../test/CloudWatchLogs.e2e.spec.ts | 73 +++++++++++++++++++ .../vitest.config.e2e.mts | 10 +++ 3 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 clients/client-cloudwatch-logs/test/CloudWatchLogs.e2e.spec.ts create mode 100644 clients/client-cloudwatch-logs/vitest.config.e2e.mts diff --git a/clients/client-cloudwatch-logs/package.json b/clients/client-cloudwatch-logs/package.json index 712a3df80a68..7d527dc79772 100644 --- a/clients/client-cloudwatch-logs/package.json +++ b/clients/client-cloudwatch-logs/package.json @@ -11,7 +11,9 @@ "build:types:downlevel": "downlevel-dts dist-types dist-types/ts3.4", "clean": "rimraf ./dist-* && rimraf *.tsbuildinfo", "extract:docs": "api-extractor run --local", - "generate:client": "node ../../scripts/generate-clients/single-service --solo cloudwatch-logs" + "generate:client": "node ../../scripts/generate-clients/single-service --solo cloudwatch-logs", + "test:e2e": "yarn g:vitest run -c vitest.config.e2e.mts", + "test:e2e:watch": "yarn g:vitest watch -c vitest.config.e2e.mts" }, "main": "./dist-cjs/index.js", "types": "./dist-types/index.d.ts", diff --git a/clients/client-cloudwatch-logs/test/CloudWatchLogs.e2e.spec.ts b/clients/client-cloudwatch-logs/test/CloudWatchLogs.e2e.spec.ts new file mode 100644 index 000000000000..9caa90257b1e --- /dev/null +++ b/clients/client-cloudwatch-logs/test/CloudWatchLogs.e2e.spec.ts @@ -0,0 +1,73 @@ +import { CloudWatchLogs } from "@aws-sdk/client-cloudwatch-logs"; +import { AwsJson1_1Protocol, AwsSmithyRpcV2CborProtocol } from "@aws-sdk/core/protocols"; +import type { IncomingMessage } from "node:http"; +import { describe, expect, test as it } from "vitest"; + +describe( + CloudWatchLogs.name, + () => { + const cwlDefault = new CloudWatchLogs({ + region: "us-west-2", + protocol: new AwsJson1_1Protocol({ + defaultNamespace: "com.amazonaws.cloudwatchlogs", + serviceTarget: "Logs_20140328", + awsQueryCompatible: false, + }), + }); + const cwlCustom = new CloudWatchLogs({ + region: "us-west-2", + protocol: new AwsSmithyRpcV2CborProtocol({ defaultNamespace: "com.amazonaws.cloudwatchlogs" }), + }); + + it("should be able to make requests with runtime protocol selection", async () => { + for (const cwl of [cwlDefault, cwlCustom]) { + const logGroups = await cwl.listLogGroups(); + + expect(logGroups).toMatchObject({ + $metadata: { + httpStatusCode: 200, + }, + logGroups: expect.any(Array), + }); + expect(logGroups.nextToken ?? "").toBeTypeOf("string"); + } + }); + + it("should be able to use an event stream to tail logs", async () => { + for (const cwl of [cwlDefault, cwlCustom]) { + const logGroups = await cwl.listLogGroups({ + limit: 1, + }); + + const groupArn = logGroups.logGroups?.[0].logGroupArn; + + if (groupArn) { + const liveTail = await cwl.startLiveTail({ + logGroupIdentifiers: [groupArn], + }); + + let pagesRead = 0; + + for await (const page of liveTail.responseStream ?? []) { + pagesRead += 1; + + if (pagesRead === 1) { + expect(page.sessionStart?.requestId).toBeTypeOf("string"); + expect(page.sessionStart?.sessionId).toBeTypeOf("string"); + expect(page.sessionStart?.logGroupIdentifiers).toEqual([groupArn]); + } else if (pagesRead === 2) { + expect(page.sessionUpdate?.sessionMetadata).toMatchObject({ + sampled: expect.any(Boolean), + }); + } else if (pagesRead > 2) { + break; + } + } + + cwl.destroy(); + } + } + }); + }, + 120_000 +); diff --git a/clients/client-cloudwatch-logs/vitest.config.e2e.mts b/clients/client-cloudwatch-logs/vitest.config.e2e.mts new file mode 100644 index 000000000000..ccea26a45905 --- /dev/null +++ b/clients/client-cloudwatch-logs/vitest.config.e2e.mts @@ -0,0 +1,10 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + exclude: ["**/*.browser.e2e.spec.ts"], + include: ["**/*.e2e.spec.ts"], + environment: "node", + }, + mode: "development", +}); From d1a700775f9fc97f85547cbf51cea6f9e4d903de Mon Sep 17 00:00:00 2001 From: George Fu Date: Mon, 10 Nov 2025 11:45:28 -0500 Subject: [PATCH 2/2] test: create log group if none exists --- .../test/CloudWatchLogs.e2e.spec.ts | 54 +++++++++---------- 1 file changed, 25 insertions(+), 29 deletions(-) diff --git a/clients/client-cloudwatch-logs/test/CloudWatchLogs.e2e.spec.ts b/clients/client-cloudwatch-logs/test/CloudWatchLogs.e2e.spec.ts index 9caa90257b1e..f28665cc968e 100644 --- a/clients/client-cloudwatch-logs/test/CloudWatchLogs.e2e.spec.ts +++ b/clients/client-cloudwatch-logs/test/CloudWatchLogs.e2e.spec.ts @@ -1,45 +1,42 @@ import { CloudWatchLogs } from "@aws-sdk/client-cloudwatch-logs"; -import { AwsJson1_1Protocol, AwsSmithyRpcV2CborProtocol } from "@aws-sdk/core/protocols"; -import type { IncomingMessage } from "node:http"; +import { GetCallerIdentityCommandOutput, STS } from "@aws-sdk/client-sts"; import { describe, expect, test as it } from "vitest"; describe( CloudWatchLogs.name, + { + timeout: 120_000, + retry: 4, + }, () => { const cwlDefault = new CloudWatchLogs({ region: "us-west-2", - protocol: new AwsJson1_1Protocol({ - defaultNamespace: "com.amazonaws.cloudwatchlogs", - serviceTarget: "Logs_20140328", - awsQueryCompatible: false, - }), - }); - const cwlCustom = new CloudWatchLogs({ - region: "us-west-2", - protocol: new AwsSmithyRpcV2CborProtocol({ defaultNamespace: "com.amazonaws.cloudwatchlogs" }), }); - it("should be able to make requests with runtime protocol selection", async () => { - for (const cwl of [cwlDefault, cwlCustom]) { - const logGroups = await cwl.listLogGroups(); + it("should be able to use an event stream to tail logs", async () => { + const sts = new STS({ region: "us-west-2" }); + const id: GetCallerIdentityCommandOutput = await sts.getCallerIdentity(); + const accountId = id.Account; - expect(logGroups).toMatchObject({ - $metadata: { - httpStatusCode: 200, - }, - logGroups: expect.any(Array), - }); - expect(logGroups.nextToken ?? "").toBeTypeOf("string"); - } - }); + for (const cwl of [cwlDefault]) { + const testLogGroupName = `/jsv3-e2e-${accountId}`; - it("should be able to use an event stream to tail logs", async () => { - for (const cwl of [cwlDefault, cwlCustom]) { - const logGroups = await cwl.listLogGroups({ + let logGroups = await cwl.listLogGroups({ + logGroupNamePattern: `^${testLogGroupName}`, limit: 1, }); - const groupArn = logGroups.logGroups?.[0].logGroupArn; + if (!logGroups.logGroups?.length) { + await cwl.createLogGroup({ + logGroupName: testLogGroupName, + }); + logGroups = await cwl.listLogGroups({ + logGroupNamePattern: `^${testLogGroupName}`, + limit: 1, + }); + } + + const groupArn = logGroups.logGroups?.[0]?.logGroupArn; if (groupArn) { const liveTail = await cwl.startLiveTail({ @@ -68,6 +65,5 @@ describe( } } }); - }, - 120_000 + } );