diff --git a/spec/unit/auth_strategy/BasicAuthStrategy.spec.ts b/spec/unit/auth_strategy/BasicAuthStrategy.spec.ts new file mode 100644 index 000000000..bb66d2f5d --- /dev/null +++ b/spec/unit/auth_strategy/BasicAuthStrategy.spec.ts @@ -0,0 +1,23 @@ +import BasicAuthStrategy from "../../../src/auth_strategy/BasicAuthStrategy"; + +describe("BasicAuthStrategy constructor", function () { + const username = "username"; + const password = "password"; + const basicAuthStrategy = new BasicAuthStrategy(username, password); + + it("Should have basic as its authType", function () { + expect(basicAuthStrategy.getAuthType()).toEqual("basic"); + }); + + it("Should return basic auth string", function (done) { + const auth = Buffer.from(username + ":" + password).toString("base64"); + basicAuthStrategy.getAuthString().then(function (authString) { + expect(authString).toEqual(`Basic ${auth}`); + done(); + }); + }); + + it("Should return true for requiresAuthentication", function () { + expect(basicAuthStrategy.requiresAuthentication()).toBe(true); + }); +}); diff --git a/spec/unit/auth_strategy/NoAuthStrategy.spec.ts b/spec/unit/auth_strategy/NoAuthStrategy.spec.ts new file mode 100644 index 000000000..08a31da11 --- /dev/null +++ b/spec/unit/auth_strategy/NoAuthStrategy.spec.ts @@ -0,0 +1,20 @@ +import NoAuthStrategy from "../../../src/auth_strategy/NoAuthStrategy"; + +describe("NoAuthStrategy constructor", function () { + const noAuthStrategy = new NoAuthStrategy(); + + it("Should have noauth as its authType", function () { + expect(noAuthStrategy.getAuthType()).toEqual("noauth"); + }); + + it("Should return an empty string for getAuthString", function (done) { + noAuthStrategy.getAuthString().then(function (authString) { + expect(authString).toEqual(""); + done(); + }); + }); + + it("Should return false for requiresAuthentication", function () { + expect(noAuthStrategy.requiresAuthentication()).toBe(false); + }); +}); diff --git a/spec/unit/auth_strategy/TokenAuthStrategy.spec.ts b/spec/unit/auth_strategy/TokenAuthStrategy.spec.ts new file mode 100644 index 000000000..909a1bcf9 --- /dev/null +++ b/spec/unit/auth_strategy/TokenAuthStrategy.spec.ts @@ -0,0 +1,126 @@ +import TokenAuthStrategy from "../../../src/auth_strategy/TokenAuthStrategy"; +import ApiTokenManager from "../../../src/http/bearer_token/ApiTokenManager"; +import { jest } from "@jest/globals"; +import axios from "axios"; +import twilio from "../../../src"; + +function createMockAxios(promiseHandler: Promise) { + const instance = () => promiseHandler; + instance.defaults = { + headers: { + post: {}, + }, + }; + return instance; +} + +describe("TokenAuthStrategy constructor", function () { + const clientId = "clientId"; + const clientSecret = "clientSecret"; + const grantType = "client_credentials"; + + const tokenManager = new ApiTokenManager({ + grantType: grantType, + clientId: clientId, + clientSecret: clientSecret, + }); + const tokenAuthStrategy = new TokenAuthStrategy(tokenManager); + + let createSpy: jest.Spied; + const initialHttpProxyValue = process.env.HTTP_PROXY; + + beforeEach(() => { + createSpy = jest.spyOn(axios, "create"); + createSpy.mockReturnValue( + createMockAxios( + Promise.resolve({ + status: 200, + data: { + access_token: "accessTokenValue", + token_type: "Bearer", + }, + }) + ) + ); + }); + + afterEach(() => { + createSpy.mockRestore(); + + if (initialHttpProxyValue) { + process.env.HTTP_PROXY = initialHttpProxyValue; + } else { + delete process.env.HTTP_PROXY; + } + }); + + it("Should have token as its authType", function () { + expect(tokenAuthStrategy.getAuthType()).toEqual("token"); + }); + + it("Should check token expiry", function () { + const accountSid = "ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; + const keySid = "SKb5aed9ca12bf5890f37930e63cad6d38"; + const token = new twilio.jwt.AccessToken(accountSid, keySid, "secret", { + identity: "ID@example.com", + }); + expect(tokenAuthStrategy.isTokenExpired(token.toJwt())).toBe(false); + }); + + it("Should return token auth string", function (done) { + tokenAuthStrategy.getAuthString().then(function (authString) { + expect(authString).toEqual(`Bearer accessTokenValue`); + done(); + }); + }); + + it("Should return true for requiresAuthentication", function () { + expect(tokenAuthStrategy.requiresAuthentication()).toBe(true); + }); +}); + +describe("TokenAuthStrategy error response", function () { + const clientId = "clientId"; + const clientSecret = "clientSecret"; + const grantType = "client_credentials"; + + const tokenManager = new ApiTokenManager({ + grantType: grantType, + clientId: clientId, + clientSecret: clientSecret, + }); + const tokenAuthStrategy = new TokenAuthStrategy(tokenManager); + + let createSpy: jest.Spied; + const initialHttpProxyValue = process.env.HTTP_PROXY; + + beforeEach(() => { + createSpy = jest.spyOn(axios, "create"); + createSpy.mockReturnValue( + createMockAxios( + Promise.resolve({ + status: 403, + data: { + message: "Invalid Credentials", + }, + }) + ) + ); + }); + + afterEach(() => { + createSpy.mockRestore(); + + if (initialHttpProxyValue) { + process.env.HTTP_PROXY = initialHttpProxyValue; + } else { + delete process.env.HTTP_PROXY; + } + }); + + it("Should return error", async function () { + await expect(tokenAuthStrategy.getAuthString()).rejects.toThrow( + "Failed to fetch access token: Invalid Credentials" + ); + }); +}); diff --git a/spec/unit/credential_provider/ClientCredentialProvider.spec.ts b/spec/unit/credential_provider/ClientCredentialProvider.spec.ts new file mode 100644 index 000000000..ad2a7e154 --- /dev/null +++ b/spec/unit/credential_provider/ClientCredentialProvider.spec.ts @@ -0,0 +1,22 @@ +import ClientCredentialProvider from "../../../src/credential_provider/ClientCredentialProvider"; +import TokenAuthStrategy from "../../../src/auth_strategy/TokenAuthStrategy"; + +describe("ClientCredentialProvider Constructor", () => { + const clientCredentialProvider = + new ClientCredentialProvider.ClientCredentialProviderBuilder() + .setClientId("clientId") + .setClientSecret("clientSecret") + .build(); + + it("Should have client-credentials as its authType", () => { + expect(clientCredentialProvider.getAuthType()).toEqual( + "client-credentials" + ); + }); + + it("Should return NoAuthStrategy as its auth strategy", () => { + expect(clientCredentialProvider.toAuthStrategy()).toBeInstanceOf( + TokenAuthStrategy + ); + }); +}); diff --git a/spec/unit/credential_provider/NoAuthCredentialProvider.spec.ts b/spec/unit/credential_provider/NoAuthCredentialProvider.spec.ts new file mode 100644 index 000000000..8c2c5d4f6 --- /dev/null +++ b/spec/unit/credential_provider/NoAuthCredentialProvider.spec.ts @@ -0,0 +1,18 @@ +import NoAuthCredentialProvider from "../../../src/credential_provider/NoAuthCredentialProvider"; +import NoAuthStrategy from "../../../src/auth_strategy/NoAuthStrategy"; +import Twilio from "../../../src"; + +describe("NoAuthCredentialProvider Constructor", () => { + const noAuthCredentialProvider = + new NoAuthCredentialProvider.NoAuthCredentialProvider(); + + it("Should have client-credentials as its authType", () => { + expect(noAuthCredentialProvider.getAuthType()).toEqual("noauth"); + }); + + it("Should return NoAuthStrategy as its auth strategy", () => { + expect(noAuthCredentialProvider.toAuthStrategy()).toBeInstanceOf( + NoAuthStrategy + ); + }); +}); diff --git a/spec/unit/credential_provider/OrgsCredentialProvider.spec.ts b/spec/unit/credential_provider/OrgsCredentialProvider.spec.ts new file mode 100644 index 000000000..4c0ca203e --- /dev/null +++ b/spec/unit/credential_provider/OrgsCredentialProvider.spec.ts @@ -0,0 +1,20 @@ +import OrgsCredentialProvider from "../../../src/credential_provider/OrgsCredentialProvider"; +import TokenAuthStrategy from "../../../src/auth_strategy/TokenAuthStrategy"; + +describe("OrgsCredentialProvider Constructor", () => { + const orgsCredentialProvider = + new OrgsCredentialProvider.OrgsCredentialProviderBuilder() + .setClientId("clientId") + .setClientSecret("clientSecret") + .build(); + + it("Should have client-credentials as its authType", () => { + expect(orgsCredentialProvider.getAuthType()).toEqual("client-credentials"); + }); + + it("Should return NoAuthStrategy as its auth strategy", () => { + expect(orgsCredentialProvider.toAuthStrategy()).toBeInstanceOf( + TokenAuthStrategy + ); + }); +}); diff --git a/spec/unit/http/bearer_token/ApiTokenManager.spec.ts b/spec/unit/http/bearer_token/ApiTokenManager.spec.ts new file mode 100644 index 000000000..f470f2637 --- /dev/null +++ b/spec/unit/http/bearer_token/ApiTokenManager.spec.ts @@ -0,0 +1,122 @@ +import ApiTokenManager from "../../../../src/http/bearer_token/ApiTokenManager"; +import axios from "axios"; +import { jest } from "@jest/globals"; + +function createMockAxios(promiseHandler: Promise) { + const instance = () => promiseHandler; + instance.defaults = { + headers: { + post: {}, + }, + }; + return instance; +} + +describe("ApiTokenManager constructor", function () { + const clientId = "clientId"; + const clientSecret = "clientSecret"; + const grantType = "client_credentials"; + + const apiTokenManager = new ApiTokenManager({ + grantType: grantType, + clientId: clientId, + clientSecret: clientSecret, + }); + + const params = apiTokenManager.getParams(); + + let createSpy: jest.Spied; + const initialHttpProxyValue = process.env.HTTP_PROXY; + + beforeEach(() => { + createSpy = jest.spyOn(axios, "create"); + createSpy.mockReturnValue( + createMockAxios( + Promise.resolve({ + status: 200, + data: { + access_token: "accessTokenValue", + expires_in: 86400, + id_token: null, + refresh_token: null, + token_type: "Bearer", + }, + }) + ) + ); + }); + + afterEach(() => { + createSpy.mockRestore(); + + if (initialHttpProxyValue) { + process.env.HTTP_PROXY = initialHttpProxyValue; + } else { + delete process.env.HTTP_PROXY; + } + }); + + it("Should have client-credentials as its grantType", function () { + expect(params.grantType).toEqual(grantType); + }); + + it("Should have clientId as its clientId", function () { + expect(params.clientId).toEqual(clientId); + }); + + it("Should have clientSecret as its clientSecret", function () { + expect(params.clientSecret).toEqual(clientSecret); + }); + + it("Should return an access token", async function () { + const token = await apiTokenManager.fetchToken(); + expect(token).toEqual("accessTokenValue"); + }); +}); + +describe("ApiTokenManager with error response", function () { + const clientId = "clientId"; + const clientSecret = "clientSecret"; + const grantType = "client_credentials"; + + const apiTokenManager = new ApiTokenManager({ + grantType: grantType, + clientId: clientId, + clientSecret: clientSecret, + }); + + const params = apiTokenManager.getParams(); + + let createSpy: jest.Spied; + const initialHttpProxyValue = process.env.HTTP_PROXY; + + beforeEach(() => { + createSpy = jest.spyOn(axios, "create"); + createSpy.mockReturnValue( + createMockAxios( + Promise.resolve({ + status: 400, + data: { + message: "Token error", + }, + }) + ) + ); + }); + + afterEach(() => { + createSpy.mockRestore(); + + if (initialHttpProxyValue) { + process.env.HTTP_PROXY = initialHttpProxyValue; + } else { + delete process.env.HTTP_PROXY; + } + }); + + it("Should return error message", async function () { + await expect(apiTokenManager.fetchToken()).rejects.toThrow( + `Error Status Code: 400\nFailed to fetch access token: Token error` + ); + }); +}); diff --git a/spec/unit/http/bearer_token/OrgsTokenManager.spec.ts b/spec/unit/http/bearer_token/OrgsTokenManager.spec.ts new file mode 100644 index 000000000..c353d4402 --- /dev/null +++ b/spec/unit/http/bearer_token/OrgsTokenManager.spec.ts @@ -0,0 +1,122 @@ +import OrgsTokenManager from "../../../../src/http/bearer_token/OrgsTokenManager"; +import axios from "axios"; +import { jest } from "@jest/globals"; + +function createMockAxios(promiseHandler: Promise) { + const instance = () => promiseHandler; + instance.defaults = { + headers: { + post: {}, + }, + }; + return instance; +} + +describe("OrgsTokenManager constructor", function () { + const clientId = "clientId"; + const clientSecret = "clientSecret"; + const grantType = "client_credentials"; + + const orgsTokenManager = new OrgsTokenManager({ + grantType: grantType, + clientId: clientId, + clientSecret: clientSecret, + }); + + const params = orgsTokenManager.getParams(); + + let createSpy: jest.Spied; + const initialHttpProxyValue = process.env.HTTP_PROXY; + + beforeEach(() => { + createSpy = jest.spyOn(axios, "create"); + createSpy.mockReturnValue( + createMockAxios( + Promise.resolve({ + status: 200, + data: { + access_token: "accessTokenValue", + expires_in: 86400, + id_token: null, + refresh_token: null, + token_type: "Bearer", + }, + }) + ) + ); + }); + + afterEach(() => { + createSpy.mockRestore(); + + if (initialHttpProxyValue) { + process.env.HTTP_PROXY = initialHttpProxyValue; + } else { + delete process.env.HTTP_PROXY; + } + }); + + it("Should have client-credentials as its grantType", function () { + expect(params.grantType).toEqual(grantType); + }); + + it("Should have clientId as its clientId", function () { + expect(params.clientId).toEqual(clientId); + }); + + it("Should have clientSecret as its clientSecret", function () { + expect(params.clientSecret).toEqual(clientSecret); + }); + + it("Should return an access token", async function () { + const token = await orgsTokenManager.fetchToken(); + expect(token).toEqual("accessTokenValue"); + }); +}); + +describe("OrgsTokenManager with error response", function () { + const clientId = "clientId"; + const clientSecret = "clientSecret"; + const grantType = "client_credentials"; + + const orgsTokenManager = new OrgsTokenManager({ + grantType: grantType, + clientId: clientId, + clientSecret: clientSecret, + }); + + const params = orgsTokenManager.getParams(); + + let createSpy: jest.Spied; + const initialHttpProxyValue = process.env.HTTP_PROXY; + + beforeEach(() => { + createSpy = jest.spyOn(axios, "create"); + createSpy.mockReturnValue( + createMockAxios( + Promise.resolve({ + status: 400, + data: { + message: "Token error", + }, + }) + ) + ); + }); + + afterEach(() => { + createSpy.mockRestore(); + + if (initialHttpProxyValue) { + process.env.HTTP_PROXY = initialHttpProxyValue; + } else { + delete process.env.HTTP_PROXY; + } + }); + + it("Should return error message", async function () { + await expect(orgsTokenManager.fetchToken()).rejects.toThrow( + `Error Status Code: 400\nFailed to fetch access token: Token error` + ); + }); +});