Skip to content

Commit

Permalink
chore: Add tests for node public oauth (#1053)
Browse files Browse the repository at this point in the history
  • Loading branch information
tiwarishubham635 authored Dec 10, 2024
1 parent 1299c58 commit df591f4
Show file tree
Hide file tree
Showing 10 changed files with 507 additions and 0 deletions.
6 changes: 6 additions & 0 deletions .github/workflows/test-and-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ jobs:
TWILIO_API_SECRET: ${{ secrets.TWILIO_CLUSTER_TEST_API_KEY_SECRET }}
TWILIO_FROM_NUMBER: ${{ secrets.TWILIO_FROM_NUMBER }}
TWILIO_TO_NUMBER: ${{ secrets.TWILIO_TO_NUMBER }}
TWILIO_ORGS_CLIENT_ID: ${{ secrets.TWILIO_ORGS_CLIENT_ID }}
TWILIO_ORGS_CLIENT_SECRET: ${{ secrets.TWILIO_ORGS_CLIENT_SECRET }}
TWILIO_ORG_SID: ${{ secrets.TWILIO_ORG_SID }}
TWILIO_CLIENT_ID: ${{ secrets.TWILIO_CLIENT_ID }}
TWILIO_CLIENT_SECRET: ${{ secrets.TWILIO_CLIENT_SECRET }}
TWILIO_MESSAGE_SID: ${{ secrets.TWILIO_MESSAGE_SID }}
run: |
npm pack
tar -xzf twilio*.tgz
Expand Down
28 changes: 28 additions & 0 deletions spec/cluster/public_oauth.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
jest.setTimeout(15000);

import twilio from "twilio";

const clientId = process.env.TWILIO_CLIENT_ID;
const clientSecret = process.env.TWILIO_CLIENT_SECRET;
const accountSid = process.env.TWILIO_ACCOUNT_SID;

const clientCredentialProvider = new twilio.ClientCredentialProviderBuilder()
.setClientId(clientId)
.setClientSecret(clientSecret)
.build();

const client = twilio();
client.setCredentialProvider(clientCredentialProvider);
client.setAccountSid(accountSid);

test("Should fetch message", () => {
const messageId = process.env.TWILIO_MESSAGE_SID;
return client
.messages(messageId)
.fetch()
.then((message) => {
expect(message).not.toBeNull();
expect(message).not.toBeUndefined();
expect(message.sid).toEqual(messageId);
});
});
23 changes: 23 additions & 0 deletions spec/unit/auth_strategy/BasicAuthStrategy.spec.ts
Original file line number Diff line number Diff line change
@@ -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);
});
});
20 changes: 20 additions & 0 deletions spec/unit/auth_strategy/NoAuthStrategy.spec.ts
Original file line number Diff line number Diff line change
@@ -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);
});
});
126 changes: 126 additions & 0 deletions spec/unit/auth_strategy/TokenAuthStrategy.spec.ts
Original file line number Diff line number Diff line change
@@ -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<any>) {
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<any>;
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: "[email protected]",
});
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<any>;
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"
);
});
});
22 changes: 22 additions & 0 deletions spec/unit/credential_provider/ClientCredentialProvider.spec.ts
Original file line number Diff line number Diff line change
@@ -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
);
});
});
18 changes: 18 additions & 0 deletions spec/unit/credential_provider/NoAuthCredentialProvider.spec.ts
Original file line number Diff line number Diff line change
@@ -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
);
});
});
20 changes: 20 additions & 0 deletions spec/unit/credential_provider/OrgsCredentialProvider.spec.ts
Original file line number Diff line number Diff line change
@@ -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
);
});
});
122 changes: 122 additions & 0 deletions spec/unit/http/bearer_token/ApiTokenManager.spec.ts
Original file line number Diff line number Diff line change
@@ -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<any>) {
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<any>;
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<any>;
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`
);
});
});
Loading

0 comments on commit df591f4

Please sign in to comment.