diff --git a/clients/client-cognito-identity/test/e2e/CognitoIdentity.e2e.spec.ts b/clients/client-cognito-identity/test/e2e/CognitoIdentity.e2e.spec.ts index 836bb76119f0..ca83bfccff90 100644 --- a/clients/client-cognito-identity/test/e2e/CognitoIdentity.e2e.spec.ts +++ b/clients/client-cognito-identity/test/e2e/CognitoIdentity.e2e.spec.ts @@ -1,6 +1,6 @@ import { beforeAll, describe, expect, test as it } from "vitest"; -import { getIntegTestResources } from "../../../../tests/e2e/get-integ-test-resources"; +import { getE2eTestResources } from "@aws-sdk/aws-util-test/src"; import { CognitoIdentity } from "../../src/index"; describe("@aws-sdk/client-cognito-identity", () => { @@ -9,8 +9,8 @@ describe("@aws-sdk/client-cognito-identity", () => { let IdentityPoolId: string; beforeAll(async () => { - const integTestResourcesEnv = await getIntegTestResources(); - Object.assign(process.env, integTestResourcesEnv); + const e2eTestResourcesEnv = await getE2eTestResources(); + Object.assign(process.env, e2eTestResourcesEnv); region = process?.env?.AWS_SMOKE_TEST_REGION as string; IdentityPoolId = @@ -38,4 +38,4 @@ describe("@aws-sdk/client-cognito-identity", () => { expect(typeof getCredentialsResult.Credentials?.AccessKeyId).to.equal("string"); expect(typeof getCredentialsResult.Credentials?.SecretKey).to.equal("string"); }); -}); +}, 60_000); diff --git a/clients/client-s3/test/e2e/S3.browser.e2e.spec.ts b/clients/client-s3/test/e2e/S3.browser.e2e.spec.ts index 156d26239b54..9c49a5cb1a6b 100644 --- a/clients/client-s3/test/e2e/S3.browser.e2e.spec.ts +++ b/clients/client-s3/test/e2e/S3.browser.e2e.spec.ts @@ -4,10 +4,10 @@ import { FetchHttpHandler } from "@smithy/fetch-http-handler"; import { Browser } from "happy-dom"; import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, onTestFailed, test as it } from "vitest"; -import { getIntegTestResources } from "../../../../tests/e2e/get-integ-test-resources"; import { getRuntimeConfig } from "../../src/runtimeConfig.browser"; import { S3 as S3Impl, waitUntilObjectExists as waitUntilObjectExistsImpl } from "../browser-build/browser-s3-bundle"; import { createBuffer } from "./helpers"; +import { getE2eTestResources } from "@aws-sdk/aws-util-test/src"; describe("@aws-sdk/client-s3", () => { let client: S3; @@ -25,8 +25,8 @@ describe("@aws-sdk/client-s3", () => { const browser = new Browser(); browser.settings.fetch.disableSameOriginPolicy = true; - const integTestResourcesEnv = await getIntegTestResources(); - Object.assign(process.env, integTestResourcesEnv); + const e2eTestResourcesEnv = await getE2eTestResources(); + Object.assign(process.env, e2eTestResourcesEnv); region = process?.env?.AWS_SMOKE_TEST_REGION as string; Bucket = process?.env?.AWS_SMOKE_TEST_BUCKET as string; diff --git a/clients/client-s3/test/e2e/S3.e2e.spec.ts b/clients/client-s3/test/e2e/S3.e2e.spec.ts index b212bf9a4c6f..db4a733f0037 100644 --- a/clients/client-s3/test/e2e/S3.e2e.spec.ts +++ b/clients/client-s3/test/e2e/S3.e2e.spec.ts @@ -3,8 +3,8 @@ import "@aws-sdk/signature-v4-crt"; import { ChecksumAlgorithm, S3 } from "@aws-sdk/client-s3"; import { afterAll, afterEach, beforeAll, describe, expect, test as it } from "vitest"; -import { getIntegTestResources } from "../../../../tests/e2e/get-integ-test-resources"; import { createBuffer } from "./helpers"; +import { getE2eTestResources } from "@aws-sdk/aws-util-test/src"; let Key = `${Date.now()}`; @@ -15,8 +15,8 @@ describe("@aws-sdk/client-s3", () => { let mrapArn: string; beforeAll(async () => { - const integTestResourcesEnv = await getIntegTestResources(); - Object.assign(process.env, integTestResourcesEnv); + const e2eTestResourcesEnv = await getE2eTestResources(); + Object.assign(process.env, e2eTestResourcesEnv); region = process?.env?.AWS_SMOKE_TEST_REGION as string; Bucket = process?.env?.AWS_SMOKE_TEST_BUCKET as string; @@ -247,4 +247,4 @@ describe("@aws-sdk/client-s3", () => { expect(result.Contents).toBeInstanceOf(Array); }); }); -}); +}, 60_000); diff --git a/clients/client-s3/test/e2e/s3-object-features.e2e.spec.ts b/clients/client-s3/test/e2e/s3-object-features.e2e.spec.ts index 6ca3452138db..f93160405fd6 100644 --- a/clients/client-s3/test/e2e/s3-object-features.e2e.spec.ts +++ b/clients/client-s3/test/e2e/s3-object-features.e2e.spec.ts @@ -5,7 +5,7 @@ import { GetObjectCommand, PutObjectCommand, S3 } from "@aws-sdk/client-s3"; import { getSignedUrl } from "@aws-sdk/s3-request-presigner"; import { afterAll, beforeAll, describe, expect, test as it } from "vitest"; -import { getIntegTestResources } from "../../../../tests/e2e/get-integ-test-resources"; +import { getE2eTestResources } from "@aws-sdk/aws-util-test/src"; describe("@aws-sdk/client-s3", () => { let client: S3; @@ -13,8 +13,8 @@ describe("@aws-sdk/client-s3", () => { let region: string; beforeAll(async () => { - const integTestResourcesEnv = await getIntegTestResources(); - Object.assign(process.env, integTestResourcesEnv); + const e2eTestResourcesEnv = await getE2eTestResources(); + Object.assign(process.env, e2eTestResourcesEnv); region = process?.env?.AWS_SMOKE_TEST_REGION as string; Bucket = process?.env?.AWS_SMOKE_TEST_BUCKET as string; diff --git a/lib/lib-storage/src/lib-storage.e2e.spec.ts b/lib/lib-storage/src/lib-storage.e2e.spec.ts index 98723fd03f5c..d3c6fb089d51 100644 --- a/lib/lib-storage/src/lib-storage.e2e.spec.ts +++ b/lib/lib-storage/src/lib-storage.e2e.spec.ts @@ -1,11 +1,10 @@ +import { getE2eTestResources } from "@aws-sdk/aws-util-test/src"; import { ChecksumAlgorithm, S3 } from "@aws-sdk/client-s3"; import { Upload } from "@aws-sdk/lib-storage"; import { randomBytes } from "crypto"; import { Readable } from "stream"; import { afterAll, beforeAll, describe, expect, test as it } from "vitest"; -import { getIntegTestResources } from "../../../tests/e2e/get-integ-test-resources"; - describe("@aws-sdk/lib-storage", () => { describe.each([undefined, "WHEN_REQUIRED", "WHEN_SUPPORTED"])( "requestChecksumCalculation: %s", @@ -23,12 +22,11 @@ describe("@aws-sdk/lib-storage", () => { let dataString: string; let Bucket: string; let region: string; - let resourcesAvailable = false; beforeAll(async () => { try { - const integTestResourcesEnv = await getIntegTestResources(); - Object.assign(process.env, integTestResourcesEnv); + const e2eTestResourcesEnv = await getE2eTestResources(); + Object.assign(process.env, e2eTestResourcesEnv); region = process?.env?.AWS_SMOKE_TEST_REGION as string; Bucket = process?.env?.AWS_SMOKE_TEST_BUCKET as string; @@ -43,7 +41,6 @@ describe("@aws-sdk/lib-storage", () => { requestChecksumCalculation, }); Key = `multi-part-file-${requestChecksumCalculation}-${ChecksumAlgorithm}-${Date.now()}`; - resourcesAvailable = true; } catch (error) { console.warn("Failed to set up test resources:", error); } diff --git a/packages/middleware-flexible-checksums/src/middleware-flexible-checksums.e2e.spec.ts b/packages/middleware-flexible-checksums/src/middleware-flexible-checksums.e2e.spec.ts index 75c10b60a7dc..e5b9b4e814fc 100644 --- a/packages/middleware-flexible-checksums/src/middleware-flexible-checksums.e2e.spec.ts +++ b/packages/middleware-flexible-checksums/src/middleware-flexible-checksums.e2e.spec.ts @@ -1,3 +1,4 @@ +import { getE2eTestResources } from "@aws-sdk/aws-util-test/src"; import { S3, UploadPartCommandOutput } from "@aws-sdk/client-s3"; import { Upload } from "@aws-sdk/lib-storage"; import { FetchHttpHandler } from "@smithy/fetch-http-handler"; @@ -6,8 +7,6 @@ import { ChecksumStream, headStream } from "@smithy/util-stream"; import { Readable } from "node:stream"; import { beforeAll, describe, expect, test as it, vi } from "vitest"; -import { getIntegTestResources } from "../../../tests/e2e/get-integ-test-resources"; - describe("S3 checksums", () => { let s3: S3; let s3_noChecksum: S3; @@ -38,8 +37,8 @@ describe("S3 checksums", () => { } beforeAll(async () => { - const integTestResourcesEnv = await getIntegTestResources(); - Object.assign(process.env, integTestResourcesEnv); + const e2eTestResourcesEnv = await getE2eTestResources(); + Object.assign(process.env, e2eTestResourcesEnv); region = process?.env?.AWS_SMOKE_TEST_REGION as string; Bucket = process?.env?.AWS_SMOKE_TEST_BUCKET as string; @@ -252,4 +251,4 @@ describe("S3 checksums", () => { await expect(checksumStream.getReader().closed).resolves.toBe(undefined); }); }); -}); +}, 60_000); diff --git a/packages/s3-presigned-post/src/createPresignedPost.e2e.spec.ts b/packages/s3-presigned-post/src/createPresignedPost.e2e.spec.ts index 60caeb7167c2..1f6a5389c246 100644 --- a/packages/s3-presigned-post/src/createPresignedPost.e2e.spec.ts +++ b/packages/s3-presigned-post/src/createPresignedPost.e2e.spec.ts @@ -3,98 +3,102 @@ import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, test as i const FormData = require("form-data"); +import { getE2eTestResources } from "@aws-sdk/aws-util-test/src"; import { createReadStream, existsSync, rmSync, writeFileSync } from "fs"; import { join } from "path"; -import { getIntegTestResources } from "../../../tests/e2e/get-integ-test-resources"; import { createPresignedPost } from "./createPresignedPost"; -describe(createPresignedPost.name, () => { - let Bucket: string; - let region: string; - - beforeAll(async () => { - const integTestResourcesEnv = await getIntegTestResources(); - Object.assign(process.env, integTestResourcesEnv); - - region = process?.env?.AWS_SMOKE_TEST_REGION as string; - Bucket = process?.env?.AWS_SMOKE_TEST_BUCKET as string; - }); - - it("should allow custom endpoints to be modified by endpoint resolution options", async () => { - const Key = "test-key"; - { - const client = new S3({ - region, - forcePathStyle: true, - endpoint: `https://s3.dualstack.${region}.amazonaws.com`, - }); - const { url } = await createPresignedPost(client, { Bucket, Key }); - expect(url).toBe(`https://s3.dualstack.${region}.amazonaws.com/${Bucket}`); - } - { - const client = new S3({ region, endpoint: `https://s3.dualstack.${region}.amazonaws.com` }); - const { url } = await createPresignedPost(client, { Bucket, Key }); - expect(url).toBe(`https://${Bucket}.s3.dualstack.${region}.amazonaws.com/`); - } - }); - - describe("test with real bucket", () => { - let Key: string; - let client: S3; - let contents: string; - let fileLocation: string; +describe( + createPresignedPost.name, + () => { + let Bucket: string; + let region: string; beforeAll(async () => { - Key = `aws-sdk-js-integration-test-s3-presigned-post-${Date.now()}.txt`; - contents = "Hello, world!"; - fileLocation = join(__dirname, Key); - client = new S3({ region, endpoint: `https://s3.dualstack.${region}.amazonaws.com` }); + const e2eTestResourcesEnv = await getE2eTestResources(); + Object.assign(process.env, e2eTestResourcesEnv); - await client.headBucket({ Bucket }); - writeFileSync(fileLocation, contents, "utf-8"); + region = process?.env?.AWS_SMOKE_TEST_REGION as string; + Bucket = process?.env?.AWS_SMOKE_TEST_BUCKET as string; }); - afterAll(async () => { - if (existsSync(fileLocation)) { - rmSync(fileLocation); + it("should allow custom endpoints to be modified by endpoint resolution options", async () => { + const Key = "test-key"; + { + const client = new S3({ + region, + forcePathStyle: true, + endpoint: `https://s3.dualstack.${region}.amazonaws.com`, + }); + const { url } = await createPresignedPost(client, { Bucket, Key }); + expect(url).toBe(`https://s3.dualstack.${region}.amazonaws.com/${Bucket}`); + } + { + const client = new S3({ region, endpoint: `https://s3.dualstack.${region}.amazonaws.com` }); + const { url } = await createPresignedPost(client, { Bucket, Key }); + expect(url).toBe(`https://${Bucket}.s3.dualstack.${region}.amazonaws.com/`); } }); - beforeEach(async () => { - await client.deleteObject({ Bucket, Key }); - }); + describe("test with real bucket", () => { + let Key: string; + let client: S3; + let contents: string; + let fileLocation: string; - afterEach(async () => { - await client.deleteObject({ Bucket, Key }); - }); + beforeAll(async () => { + Key = `aws-sdk-js-integration-test-s3-presigned-post-${Date.now()}.txt`; + contents = "Hello, world!"; + fileLocation = join(__dirname, Key); + client = new S3({ region, endpoint: `https://s3.dualstack.${region}.amazonaws.com` }); - it("should put an object using a presigned post w/ custom endpoint", async () => { - const { url, fields } = await createPresignedPost(client, { Bucket, Key }); + await client.headBucket({ Bucket }); + writeFileSync(fileLocation, contents, "utf-8"); + }); - expect(url).toBe(`https://${Bucket}.s3.dualstack.${region}.amazonaws.com/`); + afterAll(async () => { + if (existsSync(fileLocation)) { + rmSync(fileLocation); + } + }); - const form = new FormData(); - Object.entries(fields).forEach(([field, value]) => { - form.append(field, value); + beforeEach(async () => { + await client.deleteObject({ Bucket, Key }); }); - form.append("file", createReadStream(fileLocation)); - const precheck = await client.getObject({ Bucket, Key }).catch((err) => err); - expect(precheck).toBeInstanceOf(NoSuchKey); + afterEach(async () => { + await client.deleteObject({ Bucket, Key }); + }); - const submit: { statusCode: number } = await new Promise((resolve, reject) => { - form.submit(url, (err: any, res: any) => { - if (err) reject(err); - resolve(res); + it("should put an object using a presigned post w/ custom endpoint", async () => { + const { url, fields } = await createPresignedPost(client, { Bucket, Key }); + + expect(url).toBe(`https://${Bucket}.s3.dualstack.${region}.amazonaws.com/`); + + const form = new FormData(); + Object.entries(fields).forEach(([field, value]) => { + form.append(field, value); }); - }); + form.append("file", createReadStream(fileLocation)); - expect(submit.statusCode).toBe(204); + const precheck = await client.getObject({ Bucket, Key }).catch((err) => err); + expect(precheck).toBeInstanceOf(NoSuchKey); - const check = await client.getObject({ Bucket, Key }); + const submit: { statusCode: number } = await new Promise((resolve, reject) => { + form.submit(url, (err: any, res: any) => { + if (err) reject(err); + resolve(res); + }); + }); - expect(await check.Body?.transformToString()).toEqual(contents); + expect(submit.statusCode).toBe(204); + + const check = await client.getObject({ Bucket, Key }); + + expect(await check.Body?.transformToString()).toEqual(contents); + }); }); - }); -}); + }, + 60_000 +); diff --git a/private/aws-util-test/package.json b/private/aws-util-test/package.json index a26167d77942..3aab4b805cfe 100644 --- a/private/aws-util-test/package.json +++ b/private/aws-util-test/package.json @@ -20,6 +20,10 @@ "sideEffects": false, "dependencies": { "@aws-sdk/aws-protocoltests-json": "*", + "@aws-sdk/client-cognito-identity": "*", + "@aws-sdk/client-s3": "*", + "@aws-sdk/client-s3-control": "*", + "@aws-sdk/client-sts": "*", "@smithy/protocol-http": "^5.2.1", "@smithy/shared-ini-file-loader": "^4.2.0", "@smithy/types": "^4.5.0", diff --git a/private/aws-util-test/src/e2e/getE2eTestResources.ts b/private/aws-util-test/src/e2e/getE2eTestResources.ts new file mode 100644 index 000000000000..22d177de8f25 --- /dev/null +++ b/private/aws-util-test/src/e2e/getE2eTestResources.ts @@ -0,0 +1,130 @@ +import { STS } from "@aws-sdk/client-sts"; +import { paginateListMultiRegionAccessPoints, S3Control } from "@aws-sdk/client-s3-control"; +import { CognitoIdentity, paginateListIdentityPools } from "@aws-sdk/client-cognito-identity"; +import { paginateListBuckets, S3 } from "@aws-sdk/client-s3"; + +const region = "us-west-2"; + +const s3 = new S3({ region }); +const s3Control = new S3Control({ region }); +const sts = new STS({ region }); +const cognito = new CognitoIdentity({ + region, +}); + +let identityPoolId: string = ""; +let bucketName: string = ""; +let mrapAlias = ""; + +/** + * @returns cacheable idPool, Bucket, and MRAP used in e2e tests without calling changesets API from cloudformation. + */ +export async function getE2eTestResources() { + const caller = await sts.getCallerIdentity(); + + if (!identityPoolId) { + for await (const page of paginateListIdentityPools( + { client: cognito }, + { + MaxResults: 60, + } + )) { + for (const pool of page.IdentityPools ?? []) { + if (pool.IdentityPoolName === "IntegTestIdentityPool") { + identityPoolId = pool.IdentityPoolId!; + break; + } + } + if (identityPoolId) { + break; + } + } + } + + if (!identityPoolId) { + throw new Error("Could not find identity pool id"); + } + + if (!bucketName) { + for await (const page of paginateListBuckets( + { client: s3 }, + { + Prefix: "sdkreleasev3integtest", + BucketRegion: region, + } + )) { + for (const bucket of page.Buckets ?? []) { + if (bucket.Name?.includes("v3integtest")) { + const bucketMetadata = await s3 + .getBucketTagging({ + Bucket: bucket.Name, + }) + .catch((e) => { + if (e.name === "NoSuchTagSet") { + return { + TagSet: [], + }; + } + throw e; + }); + + if ( + (bucketMetadata.TagSet ?? []).find( + (tag) => tag.Key === "aws:cloudformation:logical-id" && tag.Value?.includes("IntegTestBucket") + ) + ) { + bucketName = bucket.Name; + break; + } + } + } + if (bucketName) { + break; + } + } + } + if (!bucketName) { + throw new Error("Could not find e2e test bucket."); + } + + if (!mrapAlias) { + for await (const page of paginateListMultiRegionAccessPoints( + { client: s3Control }, + { AccountId: caller.Account } + )) { + for (const mrap of page.AccessPoints ?? []) { + if (mrap.Name?.includes("v3-sdk-integration-test")) { + mrapAlias = mrap.Alias!; + break; + } + } + if (mrapAlias) { + break; + } + } + } + if (!mrapAlias) { + throw new Error("Could not find MRAP."); + } + + await s3.putBucketCors({ + Bucket: bucketName, + CORSConfiguration: { + CORSRules: [ + { + AllowedOrigins: ["*"], + AllowedMethods: ["GET", "PUT", "POST", "DELETE", "HEAD"], + AllowedHeaders: ["*"], + ExposeHeaders: ["ETag"], + }, + ], + }, + }); + + return { + AWS_SMOKE_TEST_REGION: region, + AWS_SMOKE_TEST_IDENTITY_POOL_ID: identityPoolId, + AWS_SMOKE_TEST_BUCKET: bucketName, + AWS_SMOKE_TEST_MRAP_ARN: `arn:aws:s3::${caller.Account}:accesspoint/${mrapAlias}`, + }; +} diff --git a/private/aws-util-test/src/index.ts b/private/aws-util-test/src/index.ts index b85d6584258a..25a50d05ff49 100644 --- a/private/aws-util-test/src/index.ts +++ b/private/aws-util-test/src/index.ts @@ -1 +1,2 @@ export * from "./requests/test-http-handler"; +export { getE2eTestResources } from "./e2e/getE2eTestResources"; diff --git a/yarn.lock b/yarn.lock index cc01822f3712..f16bffcaa159 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1434,6 +1434,10 @@ __metadata: resolution: "@aws-sdk/aws-util-test@workspace:private/aws-util-test" dependencies: "@aws-sdk/aws-protocoltests-json": "npm:*" + "@aws-sdk/client-cognito-identity": "npm:*" + "@aws-sdk/client-s3": "npm:*" + "@aws-sdk/client-s3-control": "npm:*" + "@aws-sdk/client-sts": "npm:*" "@smithy/protocol-http": "npm:^5.2.1" "@smithy/shared-ini-file-loader": "npm:^4.2.0" "@smithy/types": "npm:^4.5.0"