diff --git a/.changeset/eleven-lamps-mix.md b/.changeset/eleven-lamps-mix.md new file mode 100644 index 00000000000..18af1495fd9 --- /dev/null +++ b/.changeset/eleven-lamps-mix.md @@ -0,0 +1,5 @@ +--- +"@smithy/experimental-identity-and-auth": patch +--- + +Add `@httpBearerAuth` integration tests. diff --git a/packages/experimental-identity-and-auth/src/integration/httpBearerAuth.integ.spec.ts b/packages/experimental-identity-and-auth/src/integration/httpBearerAuth.integ.spec.ts new file mode 100644 index 00000000000..e0c04010ee0 --- /dev/null +++ b/packages/experimental-identity-and-auth/src/integration/httpBearerAuth.integ.spec.ts @@ -0,0 +1,213 @@ +import { + HttpBearerAuthServiceClient, + OnlyHttpBearerAuthCommand, + OnlyHttpBearerAuthOptionalCommand, + SameAsServiceCommand, +} from "@smithy/identity-and-auth-http-bearer-auth-service"; +import { requireRequestsFrom } from "@smithy/util-test"; + +describe("@httpBearerAuth integration tests", () => { + // Arbitrary mock token + const MOCK_TOKEN = "TOKEN_123"; + + // Arbitrary mock endpoint (`requireRequestsFrom()` intercepts network requests) + const MOCK_ENDPOINT = "https://foo.bar"; + + describe("Operation requires `@httpBearerAuth`", () => { + it("Request is thrown when `token` is not configured", async () => { + const client = new HttpBearerAuthServiceClient({ + endpoint: MOCK_ENDPOINT, + }); + requireRequestsFrom(client).toMatch({}); + await expect(client.send(new OnlyHttpBearerAuthCommand({}))).rejects.toThrow( + "HttpAuthScheme `smithy.api#httpBearerAuth` did not have an IdentityProvider configured." + ); + }); + + it("Request is thrown when `token` is configured incorrectly", async () => { + const client = new HttpBearerAuthServiceClient({ + endpoint: MOCK_ENDPOINT, + token: {} as any, + }); + requireRequestsFrom(client).toMatch({}); + await expect(client.send(new OnlyHttpBearerAuthCommand({}))).rejects.toThrow( + "request could not be signed with `token` since the `token` is not defined" + ); + }); + + it("Request is thrown given configured `token` identity provider throws", async () => { + const client = new HttpBearerAuthServiceClient({ + endpoint: MOCK_ENDPOINT, + token: async () => { + throw new Error("IdentityProvider throws this error"); + }, + }); + requireRequestsFrom(client).toMatch({}); + await expect(client.send(new OnlyHttpBearerAuthCommand({}))).rejects.toThrow( + "IdentityProvider throws this error" + ); + }); + + it("Request is signed given configured `token` identity provider", async () => { + const client = new HttpBearerAuthServiceClient({ + endpoint: MOCK_ENDPOINT, + token: async () => ({ + token: MOCK_TOKEN, + }), + }); + requireRequestsFrom(client).toMatch({ + headers: { + Authorization: `Bearer ${MOCK_TOKEN}`, + }, + }); + await client.send(new OnlyHttpBearerAuthCommand({})); + }); + + it("Request is signed given configured `token` identity", async () => { + const client = new HttpBearerAuthServiceClient({ + endpoint: MOCK_ENDPOINT, + token: { + token: MOCK_TOKEN, + }, + }); + requireRequestsFrom(client).toMatch({ + headers: { + Authorization: `Bearer ${MOCK_TOKEN}`, + }, + }); + await client.send(new OnlyHttpBearerAuthCommand({})); + }); + }); + + describe("Operation has `@httpBearerAuth` and `@optionalAuth`", () => { + it("Request is NOT thrown and NOT signed when `token` is not configured", async () => { + const client = new HttpBearerAuthServiceClient({ + endpoint: MOCK_ENDPOINT, + }); + requireRequestsFrom(client).toMatch({ + headers: { + Authorization: (value) => expect(value).toBeUndefined(), + }, + }); + await client.send(new OnlyHttpBearerAuthOptionalCommand({})); + }); + + it("Request is thrown when `token` is configured incorrectly", async () => { + const client = new HttpBearerAuthServiceClient({ + endpoint: MOCK_ENDPOINT, + token: {} as any, + }); + requireRequestsFrom(client).toMatch({}); + await expect(client.send(new OnlyHttpBearerAuthOptionalCommand({}))).rejects.toThrow( + "request could not be signed with `token` since the `token` is not defined" + ); + }); + + it("Request is thrown given configured `token` identity provider throws", async () => { + const client = new HttpBearerAuthServiceClient({ + endpoint: MOCK_ENDPOINT, + token: async () => { + throw new Error("IdentityProvider throws this error"); + }, + }); + requireRequestsFrom(client).toMatch({}); + await expect(client.send(new OnlyHttpBearerAuthOptionalCommand({}))).rejects.toThrow( + "IdentityProvider throws this error" + ); + }); + + it("Request is signed given configured `token` identity provider", async () => { + const client = new HttpBearerAuthServiceClient({ + endpoint: MOCK_ENDPOINT, + token: async () => ({ + token: MOCK_TOKEN, + }), + }); + requireRequestsFrom(client).toMatch({ + headers: { + Authorization: `Bearer ${MOCK_TOKEN}`, + }, + }); + await client.send(new OnlyHttpBearerAuthOptionalCommand({})); + }); + + it("Request is signed given configured `token` identity", async () => { + const client = new HttpBearerAuthServiceClient({ + endpoint: MOCK_ENDPOINT, + token: { + token: MOCK_TOKEN, + }, + }); + requireRequestsFrom(client).toMatch({ + headers: { + Authorization: `Bearer ${MOCK_TOKEN}`, + }, + }); + await client.send(new OnlyHttpBearerAuthOptionalCommand({})); + }); + }); + + describe("Service has `@httpBearerAuth`", () => { + it("Request is thrown when `token` is not configured", async () => { + const client = new HttpBearerAuthServiceClient({ + endpoint: MOCK_ENDPOINT, + }); + requireRequestsFrom(client).toMatch({}); + await expect(client.send(new SameAsServiceCommand({}))).rejects.toThrow( + "HttpAuthScheme `smithy.api#httpBearerAuth` did not have an IdentityProvider configured." + ); + }); + + it("Request is thrown when `token` is configured incorrectly", async () => { + const client = new HttpBearerAuthServiceClient({ + endpoint: MOCK_ENDPOINT, + token: {} as any, + }); + requireRequestsFrom(client).toMatch({}); + await expect(client.send(new SameAsServiceCommand({}))).rejects.toThrow( + "request could not be signed with `token` since the `token` is not defined" + ); + }); + + it("Request is thrown given configured `token` identity provider throws", async () => { + const client = new HttpBearerAuthServiceClient({ + endpoint: MOCK_ENDPOINT, + token: async () => { + throw new Error("IdentityProvider throws this error"); + }, + }); + requireRequestsFrom(client).toMatch({}); + await expect(client.send(new SameAsServiceCommand({}))).rejects.toThrow("IdentityProvider throws this error"); + }); + + it("Request is signed given configured `token` identity provider", async () => { + const client = new HttpBearerAuthServiceClient({ + endpoint: MOCK_ENDPOINT, + token: async () => ({ + token: MOCK_TOKEN, + }), + }); + requireRequestsFrom(client).toMatch({ + headers: { + Authorization: `Bearer ${MOCK_TOKEN}`, + }, + }); + await client.send(new SameAsServiceCommand({})); + }); + + it("Request is signed given configured `token` identity", async () => { + const client = new HttpBearerAuthServiceClient({ + endpoint: MOCK_ENDPOINT, + token: { + token: MOCK_TOKEN, + }, + }); + requireRequestsFrom(client).toMatch({ + headers: { + Authorization: `Bearer ${MOCK_TOKEN}`, + }, + }); + await client.send(new SameAsServiceCommand({})); + }); + }); +}); diff --git a/scripts/build-generated-test-packages.js b/scripts/build-generated-test-packages.js index 0bee4f96d65..3d8834f0c25 100644 --- a/scripts/build-generated-test-packages.js +++ b/scripts/build-generated-test-packages.js @@ -43,6 +43,13 @@ const httpApiKeyAuthClientDir = path.join( "typescript-codegen" ); +// TODO(experimentalIdentityAndAuth): add `@httpBearerAuth` client for integration tests +const httpBearerAuthClientDir = path.join( + codegenTestDir, + "identity-and-auth-http-bearer-auth", + "typescript-codegen" +); + const nodeModulesDir = path.join(root, "node_modules"); const buildAndCopyToNodeModules = async (packageName, codegenDir, nodeModulesDir) => { @@ -70,6 +77,8 @@ const buildAndCopyToNodeModules = async (packageName, codegenDir, nodeModulesDir await buildAndCopyToNodeModules("@smithy/weather-experimental-identity-and-auth", weatherExperimentalIdentityAndAuthClientDir, nodeModulesDir); // TODO(experimentalIdentityAndAuth): add `@httpApiKeyAuth` client for integration tests await buildAndCopyToNodeModules("@smithy/identity-and-auth-http-api-key-auth-service", httpApiKeyAuthClientDir, nodeModulesDir); + // TODO(experimentalIdentityAndAuth): add `@httpBearerAuth` client for integration tests + await buildAndCopyToNodeModules("@smithy/identity-and-auth-http-bearer-auth-service", httpBearerAuthClientDir, nodeModulesDir); } catch (e) { console.log(e); process.exit(1); diff --git a/smithy-typescript-codegen-test/model/identity-and-auth/httpBearerAuth/HttpBearerAuthService.smithy b/smithy-typescript-codegen-test/model/identity-and-auth/httpBearerAuth/HttpBearerAuthService.smithy new file mode 100644 index 00000000000..c7c4949b8dc --- /dev/null +++ b/smithy-typescript-codegen-test/model/identity-and-auth/httpBearerAuth/HttpBearerAuthService.smithy @@ -0,0 +1,27 @@ +$version: "2.0" + +namespace identity.auth.httpBearerAuth + +use common#fakeProtocol + +@fakeProtocol +@httpBearerAuth +service HttpBearerAuthService { + operations: [ + OnlyHttpBearerAuth + OnlyHttpBearerAuthOptional + SameAsService + ] +} + +@http(method: "GET", uri: "/OnlyHttpBearerAuth") +@auth([httpBearerAuth]) +operation OnlyHttpBearerAuth {} + +@http(method: "GET", uri: "/OnlyHttpBearerAuthOptional") +@auth([httpBearerAuth]) +@optionalAuth +operation OnlyHttpBearerAuthOptional {} + +@http(method: "GET", uri: "/SameAsService") +operation SameAsService {} diff --git a/smithy-typescript-codegen-test/smithy-build.json b/smithy-typescript-codegen-test/smithy-build.json index 021ea3ff6c8..1e3fd0f710d 100644 --- a/smithy-typescript-codegen-test/smithy-build.json +++ b/smithy-typescript-codegen-test/smithy-build.json @@ -97,6 +97,29 @@ "experimentalIdentityAndAuth": true } } + }, + "identity-and-auth-http-bearer-auth": { + "transforms": [ + { + "name": "includeServices", + "args": { + "services": ["identity.auth.httpBearerAuth#HttpBearerAuthService"] + } + } + ], + "plugins": { + "typescript-codegen": { + "service": "identity.auth.httpBearerAuth#HttpBearerAuthService", + "targetNamespace": "HttpBearerAuthService", + "package": "@smithy/identity-and-auth-http-bearer-auth-service", + "packageVersion": "0.0.1", + "packageJson": { + "license": "Apache-2.0", + "private": true + }, + "experimentalIdentityAndAuth": true + } + } } }, "plugins": {