From e2179d979c233d1da33ae94e42e4b77fa1bd5f18 Mon Sep 17 00:00:00 2001 From: Raghunandan Date: Thu, 21 May 2020 14:55:58 +0200 Subject: [PATCH] Add tests for providers/index, factories and google provider --- .../src/providers/factories.test.ts | 72 +++++++++++++++++++ .../auth-backend/src/providers/factories.ts | 18 ++++- .../src/providers/google/provider.test.ts | 42 +++++++++++ .../src/providers/google/provider.ts | 2 +- .../auth-backend/src/providers/index.test.ts | 71 ++++++++++++++---- plugins/auth-backend/src/providers/index.ts | 19 ++--- plugins/auth-backend/src/service/router.ts | 2 - 7 files changed, 193 insertions(+), 33 deletions(-) create mode 100644 plugins/auth-backend/src/providers/factories.test.ts create mode 100644 plugins/auth-backend/src/providers/google/provider.test.ts diff --git a/plugins/auth-backend/src/providers/factories.test.ts b/plugins/auth-backend/src/providers/factories.test.ts new file mode 100644 index 0000000000..ef9bb6256f --- /dev/null +++ b/plugins/auth-backend/src/providers/factories.test.ts @@ -0,0 +1,72 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import express from 'express'; +import passport from 'passport'; +import { AuthProvider, AuthProviderRouteHandlers } from './types'; +import { ProviderFactories } from './factories'; + +class MyAuthProvider implements AuthProvider, AuthProviderRouteHandlers { + strategy(): passport.Strategy { + return new passport.Strategy(); + } + start( + req: express.Request, + res: express.Response, + next: express.NextFunction, + ): Promise { + return new Promise(resolve => { + res.send('start'); + resolve(); + }); + } + frameHandler( + req: express.Request, + res: express.Response, + next: express.NextFunction, + ): Promise { + return new Promise(resolve => { + res.send('frameHandler'); + resolve(); + }); + } + logout( + req: express.Request, + res: express.Response, + next: express.NextFunction, + ): Promise { + return new Promise(resolve => { + res.send('logout'); + resolve(); + }); + } +} + +describe('getProviderFactory', () => { + it('makes a provider for MyAuthProvider', () => { + jest + .spyOn(ProviderFactories, 'getProviderFactory') + .mockReturnValueOnce(MyAuthProvider); + const provider = ProviderFactories.getProviderFactory('a'); + expect(provider).toBeDefined(); + }); + + it('throws an error when provider implementation does not exist', () => { + expect(() => { + ProviderFactories.getProviderFactory('b'); + }).toThrow('Provider Implementation missing for : b auth provider'); + }); +}); diff --git a/plugins/auth-backend/src/providers/factories.ts b/plugins/auth-backend/src/providers/factories.ts index 218f7995e1..6947f0ebd2 100644 --- a/plugins/auth-backend/src/providers/factories.ts +++ b/plugins/auth-backend/src/providers/factories.ts @@ -17,6 +17,18 @@ import { AuthProviderFactories } from './types'; import { GoogleAuthProvider } from './google/provider'; -export const providerFactories: AuthProviderFactories = { - google: GoogleAuthProvider, -}; +export class ProviderFactories { + private static readonly providerFactories: AuthProviderFactories = { + google: GoogleAuthProvider, + }; + + public static getProviderFactory(providerId: string) { + const ProviderImpl = ProviderFactories.providerFactories.providerId; + if (!ProviderImpl) { + throw Error( + `Provider Implementation missing for : ${providerId} auth provider`, + ); + } + return ProviderImpl; + } +} diff --git a/plugins/auth-backend/src/providers/google/provider.test.ts b/plugins/auth-backend/src/providers/google/provider.test.ts new file mode 100644 index 0000000000..bb35d0a47b --- /dev/null +++ b/plugins/auth-backend/src/providers/google/provider.test.ts @@ -0,0 +1,42 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { GoogleAuthProvider } from './provider'; +import passport from 'passport'; + +const googleAuthProviderConfig = { + provider: 'google', + options: {}, +}; + +const googleAuthProviderConfigInvalid = { + provider: 'google', +}; + +describe('GoogleAuthProvider', () => { + describe('create a new provider', () => { + it('should succeed with valid config', () => { + const googleAuthProvider = new GoogleAuthProvider( + googleAuthProviderConfig, + ); + expect(googleAuthProvider).toBeDefined(); + expect(googleAuthProvider.start).toBeDefined(); + expect(googleAuthProvider.logout).toBeDefined(); + expect(googleAuthProvider.frameHandler).toBeDefined(); + expect(googleAuthProvider.strategy).toBeDefined(); + }); + }); +}); diff --git a/plugins/auth-backend/src/providers/google/provider.ts b/plugins/auth-backend/src/providers/google/provider.ts index 5d715724bf..86a490df91 100644 --- a/plugins/auth-backend/src/providers/google/provider.ts +++ b/plugins/auth-backend/src/providers/google/provider.ts @@ -62,7 +62,7 @@ export class GoogleAuthProvider } logout(_req: express.Request, res: express.Response) { - return new Promise((resolve) => { + return new Promise(resolve => { res.send('logout!'); resolve(); }); diff --git a/plugins/auth-backend/src/providers/index.test.ts b/plugins/auth-backend/src/providers/index.test.ts index a6d6c221a9..97b40d07dd 100644 --- a/plugins/auth-backend/src/providers/index.test.ts +++ b/plugins/auth-backend/src/providers/index.test.ts @@ -16,10 +16,20 @@ import passport from 'passport'; import express from 'express'; -import { makeProvider } from '.'; -import { AuthProvider, AuthProviderRouteHandlers } from './types'; +import { makeProvider, defaultRouter } from '.'; +import { + AuthProvider, + AuthProviderRouteHandlers, + AuthProviderConfig, +} from './types'; +import { ProviderFactories } from './factories'; class MyAuthProvider implements AuthProvider, AuthProviderRouteHandlers { + private readonly providerConfig: AuthProviderConfig; + constructor(providerConfig: AuthProviderConfig) { + this.providerConfig = providerConfig; + } + strategy(): passport.Strategy { return new passport.Strategy(); } @@ -28,27 +38,45 @@ class MyAuthProvider implements AuthProvider, AuthProviderRouteHandlers { res: express.Response, next: express.NextFunction, ): Promise { - return new Promise((res, rej) => res()); + return new Promise(resolve => { + res.send('start'); + resolve(); + }); } frameHandler( req: express.Request, res: express.Response, next: express.NextFunction, - ): express.Response { - return res.send('frameHandler'); + ): Promise { + return new Promise(resolve => { + res.send('frameHandler'); + resolve(); + }); } logout( req: express.Request, res: express.Response, next: express.NextFunction, - ): express.Response { - return res.send('logout'); + ): Promise { + return new Promise(resolve => { + res.send('logout'); + resolve(); + }); } } -const providerFactories = { - a: MyAuthProvider, -}; +class MyAuthProviderWithRefresh extends MyAuthProvider { + refresh( + req: express.Request, + res: express.Response, + next: express.NextFunction, + ): Promise { + return new Promise(resolve => { + res.send('logout'); + resolve(); + }); + } +} const providerConfig = { provider: 'a', @@ -66,7 +94,10 @@ const providerConfigInvalid = { describe('makeProvider', () => { it('makes a provider for Myauthprovider', () => { - const provider = makeProvider(providerFactories, providerConfig); + jest + .spyOn(ProviderFactories, 'getProviderFactory') + .mockReturnValueOnce(MyAuthProvider); + const provider = makeProvider(providerConfig); expect(provider.providerId).toEqual('a'); expect(provider.strategy).toBeDefined(); expect(provider.providerRouter).toBeDefined(); @@ -74,7 +105,23 @@ describe('makeProvider', () => { it('throws an error when provider implementation does not exist', () => { expect(() => { - makeProvider(providerFactories, providerConfigInvalid); + makeProvider(providerConfigInvalid); }).toThrow('Provider Implementation missing for : b auth provider'); }); }); + +describe('defaultRouter', () => { + it('make router for auth provider without refresh', () => { + expect( + defaultRouter(new MyAuthProvider({ provider: 'a', options: {} })), + ).toBeDefined(); + }); + + it('make router for auth provider with refresh', () => { + expect( + defaultRouter( + new MyAuthProviderWithRefresh({ provider: 'b', options: {} }), + ), + ).toBeDefined(); + }); +}); diff --git a/plugins/auth-backend/src/providers/index.ts b/plugins/auth-backend/src/providers/index.ts index 433c7483b3..6658299033 100644 --- a/plugins/auth-backend/src/providers/index.ts +++ b/plugins/auth-backend/src/providers/index.ts @@ -15,11 +15,8 @@ */ import Router from 'express-promise-router'; -import { - AuthProviderRouteHandlers, - AuthProviderFactories, - AuthProviderConfig, -} from './types'; +import { AuthProviderRouteHandlers, AuthProviderConfig } from './types'; +import { ProviderFactories } from './factories'; export const defaultRouter = (provider: AuthProviderRouteHandlers) => { const router = Router(); @@ -32,17 +29,9 @@ export const defaultRouter = (provider: AuthProviderRouteHandlers) => { return router; }; -export const makeProvider = ( - providerFactories: AuthProviderFactories, - config: any, -) => { +export const makeProvider = (config: AuthProviderConfig) => { const providerId = config.provider; - const ProviderImpl = providerFactories[providerId]; - if (!ProviderImpl) { - throw Error( - `Provider Implementation missing for : ${providerId} auth provider`, - ); - } + const ProviderImpl = ProviderFactories.getProviderFactory(providerId); const providerInstance = new ProviderImpl(config); const strategy = providerInstance.strategy(); const providerRouter = defaultRouter(providerInstance); diff --git a/plugins/auth-backend/src/service/router.ts b/plugins/auth-backend/src/service/router.ts index 18ec5ad81d..cdde95d9d0 100644 --- a/plugins/auth-backend/src/service/router.ts +++ b/plugins/auth-backend/src/service/router.ts @@ -19,7 +19,6 @@ import Router from 'express-promise-router'; import passport from 'passport'; import { Logger } from 'winston'; import { providers } from './../providers/config'; -import { providerFactories } from './../providers/factories'; import { makeProvider } from '../providers'; export interface RouterOptions { @@ -36,7 +35,6 @@ export async function createRouter( // configure all the providers for (const providerConfig of providers) { const { providerId, strategy, providerRouter } = makeProvider( - providerFactories, providerConfig, ); logger.info(`Configuring provider: ${providerId}`);