Skip to content

Commit 0511aae

Browse files
committed
test(signature-v4-multi-region): use long-lived resources for sigv4a events test
1 parent 594c19c commit 0511aae

File tree

1 file changed

+55
-129
lines changed

1 file changed

+55
-129
lines changed

packages/signature-v4-multi-region/src/eventbridge-sigv4a-put-api.e2e.spec.ts

Lines changed: 55 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ import { Sha256 } from "@aws-crypto/sha256-js";
55
import {
66
CreateEndpointCommand,
77
CreateEventBusCommand,
8-
DeleteEndpointCommand,
9-
DeleteEventBusCommand,
108
DescribeEndpointCommand,
119
EndpointState,
1210
EventBridgeClient,
@@ -15,27 +13,26 @@ import {
1513
PutEventsCommandOutput,
1614
ReplicationState,
1715
} from "@aws-sdk/client-eventbridge";
18-
import { CreateHealthCheckCommand, DeleteHealthCheckCommand, Route53Client } from "@aws-sdk/client-route-53";
19-
import { GetCallerIdentityCommand, STSClient } from "@aws-sdk/client-sts";
16+
import { CreateHealthCheckCommand, Route53Client } from "@aws-sdk/client-route-53";
2017
import { defaultProvider } from "@aws-sdk/credential-provider-node";
2118
import { SignatureV4MultiRegion } from "@aws-sdk/signature-v4-multi-region";
2219
import { HttpRequest } from "@smithy/protocol-http";
23-
import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
20+
import { beforeAll, describe, expect, it, vi } from "vitest";
2421

2522
const LONG_TIMEOUT = 5 * 60 * 1000;
2623
const POLLING_DELAY = 5000;
2724
const MAX_POLLING_ATTEMPTS = 40;
2825

26+
// long-lived resources
27+
const RESOURCE_PREFIX = "jsv3-e2e-global";
28+
2929
const wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
3030

3131
const getSubdomainFromUrl = (url: string | undefined): string | undefined => {
3232
if (!url) return undefined;
3333
try {
3434
const parsedUrl = new URL(url);
35-
// Hostname will be like abcde.xyz.endpoint.events.amazonaws.com
3635
const hostnameParts = parsedUrl.hostname.split(".");
37-
// We can expect at least 5 parts: subdomain[0].subdomain[1].endpoint.events.amazonaws.com
38-
// Check if the 3rd part from the end is 'events'
3936
if (hostnameParts.length >= 5 && hostnameParts[hostnameParts.length - 3] === "events") {
4037
return `${hostnameParts[0]}.${hostnameParts[1]}`;
4138
}
@@ -46,71 +43,25 @@ const getSubdomainFromUrl = (url: string | undefined): string | undefined => {
4643
};
4744

4845
describe("EventBridge Client with SignatureV4a", () => {
49-
let stsClient: STSClient;
5046
let primaryEbClient: EventBridgeClient;
5147
let secondaryEbClient: EventBridgeClient;
5248
let route53Client: Route53Client;
5349
let signer: SignatureV4MultiRegion;
5450
let globalEbClient: EventBridgeClient;
55-
56-
let accountId: string;
57-
let timestamp: number;
5851
let primaryRegion: string;
5952
let secondaryRegion: string;
6053
let eventBusName: string;
54+
let endpointName: string;
6155
let primaryEventBusArn: string | undefined;
6256
let secondaryEventBusArn: string | undefined;
6357
let healthCheckId: string | undefined;
64-
let endpointName: string;
65-
let endpointArn: string | undefined;
66-
67-
const cleanupResources = async () => {
68-
try {
69-
if (endpointArn) {
70-
const managementClient = new EventBridgeClient({ region: primaryRegion });
71-
await managementClient.send(new DeleteEndpointCommand({ Name: endpointName }));
72-
managementClient.destroy();
73-
endpointArn = undefined; // Mark as deleted
74-
}
75-
} catch (error) {
76-
console.error(`Error deleting endpoint ${endpointName}:`, error);
77-
}
78-
79-
try {
80-
if (healthCheckId) {
81-
await route53Client.send(new DeleteHealthCheckCommand({ HealthCheckId: healthCheckId }));
82-
healthCheckId = undefined;
83-
}
84-
} catch (error) {
85-
console.error(`Error deleting health check ${healthCheckId}:`, error);
86-
}
87-
88-
try {
89-
if (primaryEventBusArn) {
90-
await primaryEbClient.send(new DeleteEventBusCommand({ Name: eventBusName }));
91-
primaryEventBusArn = undefined;
92-
}
93-
} catch (error) {
94-
console.error(`Error deleting event bus ${eventBusName} from ${primaryRegion}:`, error);
95-
}
96-
97-
try {
98-
if (secondaryEventBusArn) {
99-
await secondaryEbClient.send(new DeleteEventBusCommand({ Name: eventBusName }));
100-
secondaryEventBusArn = undefined;
101-
}
102-
} catch (error) {
103-
console.error(`Error deleting event bus ${eventBusName} from ${secondaryRegion}:`, error);
104-
}
105-
};
10658

10759
beforeAll(async () => {
10860
vi.setConfig({ hookTimeout: LONG_TIMEOUT });
10961

11062
primaryRegion = "us-west-2";
11163
secondaryRegion = "us-east-1";
11264

113-
stsClient = new STSClient({ region: primaryRegion });
11465
primaryEbClient = new EventBridgeClient({ region: primaryRegion });
11566
secondaryEbClient = new EventBridgeClient({ region: secondaryRegion });
11667
route53Client = new Route53Client({ region: "us-west-2" });
@@ -127,87 +78,69 @@ describe("EventBridge Client with SignatureV4a", () => {
12778
signer,
12879
});
12980

130-
// Account ID & Timestamp for Unique Names
13181
try {
132-
const identity = await stsClient.send(new GetCallerIdentityCommand({}));
133-
accountId = identity.Account!;
134-
timestamp = Date.now();
135-
136-
eventBusName = `test-global-bus-${accountId}-${timestamp}`;
137-
endpointName = `test-global-endpoint-${accountId}-${timestamp}`;
138-
139-
const primaryBus = await primaryEbClient.send(new CreateEventBusCommand({ Name: eventBusName }));
140-
primaryEventBusArn = primaryBus.EventBusArn;
141-
expect(primaryEventBusArn).toBeDefined();
142-
143-
const secondaryBus = await secondaryEbClient.send(new CreateEventBusCommand({ Name: eventBusName }));
144-
secondaryEventBusArn = secondaryBus.EventBusArn;
145-
expect(secondaryEventBusArn).toBeDefined();
146-
147-
// Create Route 53 Health Check: a basic one against a dummy target.
148-
const healthCheckCallerReference = `eb-putevents-test-${timestamp}`;
149-
const healthCheck = await route53Client.send(
150-
new CreateHealthCheckCommand({
151-
CallerReference: healthCheckCallerReference,
152-
HealthCheckConfig: {
153-
Type: "HTTP",
154-
FullyQualifiedDomainName: "example.com",
155-
Port: 80,
156-
ResourcePath: "/",
157-
RequestInterval: 30,
158-
FailureThreshold: 3,
159-
},
160-
})
161-
);
162-
healthCheckId = healthCheck.HealthCheck?.Id;
163-
expect(healthCheckId).toBeDefined();
164-
await wait(10000);
82+
eventBusName = `${RESOURCE_PREFIX}-bus`;
83+
endpointName = `${RESOURCE_PREFIX}-endpoint`;
16584

166-
let managementClient: EventBridgeClient | undefined;
85+
const managementClient = new EventBridgeClient({ region: primaryRegion });
16786
try {
168-
managementClient = new EventBridgeClient({ region: primaryRegion });
169-
const createInput = {
170-
Name: endpointName,
171-
RoutingConfig: {
172-
FailoverConfig: {
173-
Primary: { HealthCheck: `arn:aws:route53:::healthcheck/${healthCheckId}` },
174-
Secondary: { Route: secondaryRegion },
175-
},
176-
},
177-
ReplicationConfig: { State: ReplicationState.DISABLED },
178-
EventBuses: [{ EventBusArn: primaryEventBusArn }, { EventBusArn: secondaryEventBusArn }],
179-
};
180-
const createResponse = await managementClient.send(new CreateEndpointCommand(createInput));
181-
182-
expect(createResponse.$metadata.httpStatusCode).toBe(200);
183-
expect(createResponse.Name).toBe(endpointName);
184-
expect(createResponse.Arn).toBeDefined();
185-
186-
endpointArn = createResponse.Arn!;
187-
} catch (error) {
188-
console.error("Error during prerequisite resource creation:", error);
189-
await cleanupResources();
190-
throw error;
87+
await managementClient.send(new DescribeEndpointCommand({ Name: endpointName }));
88+
} catch (error: any) {
89+
if (error.name === "ResourceNotFoundException") {
90+
// Create resources if they don't exist
91+
const primaryBus = await primaryEbClient.send(new CreateEventBusCommand({ Name: eventBusName }));
92+
primaryEventBusArn = primaryBus.EventBusArn;
93+
94+
const secondaryBus = await secondaryEbClient.send(new CreateEventBusCommand({ Name: eventBusName }));
95+
secondaryEventBusArn = secondaryBus.EventBusArn;
96+
97+
const healthCheck = await route53Client.send(
98+
new CreateHealthCheckCommand({
99+
CallerReference: `${RESOURCE_PREFIX}-${Date.now()}`,
100+
HealthCheckConfig: {
101+
Type: "HTTP",
102+
FullyQualifiedDomainName: "example.com",
103+
Port: 80,
104+
ResourcePath: "/",
105+
RequestInterval: 30,
106+
FailureThreshold: 3,
107+
},
108+
})
109+
);
110+
healthCheckId = healthCheck.HealthCheck?.Id;
111+
await wait(10000);
112+
113+
const createEndpointResponse = await managementClient.send(
114+
new CreateEndpointCommand({
115+
Name: endpointName,
116+
RoutingConfig: {
117+
FailoverConfig: {
118+
Primary: { HealthCheck: `arn:aws:route53:::healthcheck/${healthCheckId}` },
119+
Secondary: { Route: secondaryRegion },
120+
},
121+
},
122+
ReplicationConfig: { State: ReplicationState.DISABLED },
123+
EventBuses: [{ EventBusArn: primaryEventBusArn }, { EventBusArn: secondaryEventBusArn }],
124+
})
125+
);
126+
} else {
127+
throw error;
128+
}
191129
} finally {
192-
managementClient?.destroy();
130+
managementClient.destroy();
193131
}
194132
} catch (error) {
195-
console.error("Error during prerequisite resource creation:", error);
196-
await cleanupResources();
133+
console.error("Error during setup:", error);
197134
throw error;
198135
}
199136
}, LONG_TIMEOUT);
200137

201-
afterAll(async () => {
202-
vi.setConfig({ hookTimeout: LONG_TIMEOUT });
203-
await cleanupResources();
204-
// Clean up SDK clients
205-
stsClient?.destroy();
138+
beforeAll(async () => {
206139
primaryEbClient?.destroy();
207140
secondaryEbClient?.destroy();
208141
route53Client?.destroy();
209142
globalEbClient?.destroy();
210-
}, LONG_TIMEOUT);
143+
});
211144

212145
it("should add SigV4a headers when signing an EventBridge request (mocked)", async () => {
213146
expect(signer).toBeDefined();
@@ -251,8 +184,6 @@ describe("EventBridge Client with SignatureV4a", () => {
251184
it(
252185
"should send an event to an EventBridge Global Endpoint using SignatureV4a",
253186
async () => {
254-
expect(endpointArn).toBeDefined();
255-
256187
let attempts = 0;
257188
let currentState: EndpointState | string | undefined;
258189
let endpointUrl: string | undefined;
@@ -272,7 +203,6 @@ describe("EventBridge Client with SignatureV4a", () => {
272203
}
273204
} catch (error) {
274205
console.warn(`DescribeEndpoint failed (attempt ${attempts}):`, error);
275-
// Continue polling unless it's a definitive failure state
276206
}
277207
await wait(POLLING_DELAY);
278208
}
@@ -306,10 +236,6 @@ describe("EventBridge Client with SignatureV4a", () => {
306236
expect(putEventsResponse.FailedEntryCount).toBe(0);
307237
expect(putEventsResponse.Entries).toHaveLength(1);
308238
expect(putEventsResponse.Entries?.[0]?.EventId).toBeDefined();
309-
310-
// Note: Verifying the event *arrived* in the target bus (primary or secondary)
311-
// would require additional setup and is omitted
312-
// here to focus on the PutEvents call itself succeeding with SigV4a.
313239
},
314240
LONG_TIMEOUT
315241
);

0 commit comments

Comments
 (0)