diff --git a/e2e-tests/payment-strands-bedrock.test.ts b/e2e-tests/payment-strands-bedrock.test.ts index 765dc8ef7..8c165fbbc 100644 --- a/e2e-tests/payment-strands-bedrock.test.ts +++ b/e2e-tests/payment-strands-bedrock.test.ts @@ -9,7 +9,7 @@ * - CDP_API_KEY_ID, CDP_API_KEY_SECRET, CDP_WALLET_SECRET (for connector creation) * - CDK_TARBALL (optional — path to payment-aware CDK constructs tgz) */ -import { hasAwsCredentials, parseJsonOutput, prereqs, retry } from '../src/test-utils/index.js'; +import { hasAwsCredentials, parseJsonOutput, prereqs, retry, uniqueRunName, uniqueRunSuffix } from '../src/test-utils/index.js'; import { installCdkTarball, runAgentCoreCLI, teardownE2EProject, writeAwsTargets } from './e2e-helper.js'; import { type Logger, getLogger } from './utils/logger.js'; import { randomUUID } from 'node:crypto'; @@ -27,8 +27,11 @@ describe.sequential('e2e: payments — create → add payment → deploy → sta let projectPath: string; let agentName: string; let logger: Logger; - const managerName = 'E2ePayMgr'; - const connectorName = 'E2ePayConn'; + // Payment credential-provider name is derived as `${manager}-${connector}-cdp` and is unique only per + // account+region. Randomize per run (like agentName/testDir below) so leftover providers from a crashed + // prior run or a concurrent CI pipeline don't collide on the static 'E2ePayMgr-E2ePayConn-cdp'. + let managerName: string; + let connectorName: string; beforeAll(async () => { logger = getLogger('payments-strands-bedrock'); @@ -39,7 +42,10 @@ describe.sequential('e2e: payments — create → add payment → deploy → sta testDir = join(tmpdir(), `agentcore-e2e-pay-${randomUUID()}`); await mkdir(testDir, { recursive: true }); - agentName = `E2ePay${String(Date.now()).slice(-8)}`; + const runSuffix = uniqueRunSuffix(); + agentName = `E2ePay${runSuffix}`; + managerName = uniqueRunName('E2ePayMgr', runSuffix); + connectorName = uniqueRunName('E2ePayConn', runSuffix); // Create project const createResult = await runAgentCoreCLI( diff --git a/src/test-utils/index.ts b/src/test-utils/index.ts index 2920b822a..0bba2bb2b 100644 --- a/src/test-utils/index.ts +++ b/src/test-utils/index.ts @@ -11,6 +11,7 @@ export { exists } from './fs-helpers.js'; export { hasCommand, hasAwsCredentials, prereqs } from './prereqs.js'; export { createTestProject, type TestProject, type CreateTestProjectOptions } from './project-factory.js'; export { readProjectConfig } from './config-reader.js'; +export { uniqueRunSuffix, uniqueRunName } from './run-naming.js'; export async function runSuccess(args: string[], cwd: string): Promise> { const result = await runCLIImpl(args, cwd); diff --git a/src/test-utils/run-naming.test.ts b/src/test-utils/run-naming.test.ts new file mode 100644 index 000000000..44ffdaded --- /dev/null +++ b/src/test-utils/run-naming.test.ts @@ -0,0 +1,29 @@ +import { uniqueRunName, uniqueRunSuffix } from './run-naming.js'; +import { describe, expect, it, vi } from 'vitest'; + +describe('uniqueRunSuffix / uniqueRunName', () => { + it('produces an 8-digit run suffix', () => { + expect(uniqueRunSuffix()).toMatch(/^\d{8}$/); + }); + + it('derives a per-run-unique payment credential-provider name (regression for #1559)', () => { + // PaymentConnectorPrimitive builds the credential name as `${manager}-${connector}-cdp` + // (PaymentConnectorPrimitive.ts). Derive it the same way from the e2e test's chosen names + // and assert it carries a per-run suffix instead of the static 'E2ePayMgr-E2ePayConn-cdp'. + const deriveCredentialName = (suffix: string): string => { + const manager = uniqueRunName('E2ePayMgr', suffix); + const connector = uniqueRunName('E2ePayConn', suffix); + return `${manager}-${connector}-cdp`; + }; + + vi.spyOn(Date, 'now').mockReturnValue(112233445566); + const first = deriveCredentialName(uniqueRunSuffix()); + vi.spyOn(Date, 'now').mockReturnValue(112233449999); + const second = deriveCredentialName(uniqueRunSuffix()); + vi.restoreAllMocks(); + + expect(first).toMatch(/^E2ePayMgr\d{8}-E2ePayConn\d{8}-cdp$/); + expect(first).not.toBe('E2ePayMgr-E2ePayConn-cdp'); + expect(first).not.toBe(second); + }); +}); diff --git a/src/test-utils/run-naming.ts b/src/test-utils/run-naming.ts new file mode 100644 index 000000000..1582ee837 --- /dev/null +++ b/src/test-utils/run-naming.ts @@ -0,0 +1,24 @@ +/** + * Per-run naming helpers for e2e tests. + * + * Some AWS resources (e.g. payment credential providers) are unique only per + * account+region with no project/run scoping. Tests must therefore derive + * resource names with a per-run suffix so a leftover resource from a crashed + * prior run or a concurrent CI pipeline sharing the account does not collide. + */ + +/** + * Returns an 8-character run suffix derived from the current time. Two calls + * made on different runs (or > ~100ms apart) produce different values. + */ +export function uniqueRunSuffix(): string { + return String(Date.now()).slice(-8); +} + +/** + * Returns `base` with a per-run unique suffix appended, e.g. + * `uniqueRunName('E2ePayMgr')` -> `E2ePayMgr12345678`. + */ +export function uniqueRunName(base: string, suffix: string = uniqueRunSuffix()): string { + return `${base}${suffix}`; +}