diff options
| author | Erik Larkö <erik@mullvad.net> | 2017-10-13 11:31:57 +0200 |
|---|---|---|
| committer | Erik Larkö <erik@mullvad.net> | 2017-10-13 11:31:57 +0200 |
| commit | 992f7946dbe9004d88a331b97ea9e030701599ea (patch) | |
| tree | 858ef774e0751435f2b039af846cef4d29c37a0c /test | |
| parent | 8f5c5aa9a433a65d8a7f6f6d8e4211f5a82068f5 (diff) | |
| download | mullvadvpn-992f7946dbe9004d88a331b97ea9e030701599ea.tar.xz mullvadvpn-992f7946dbe9004d88a331b97ea9e030701599ea.zip | |
Move the auth flow into backend.js and write tests
Diffstat (limited to 'test')
| -rw-r--r-- | test/auth.spec.js | 56 | ||||
| -rw-r--r-- | test/connect.spec.js | 30 | ||||
| -rw-r--r-- | test/helpers/IpcChain.js | 19 | ||||
| -rw-r--r-- | test/helpers/ipc-helpers.js | 26 | ||||
| -rw-r--r-- | test/mocks/ipc.js | 16 |
5 files changed, 127 insertions, 20 deletions
diff --git a/test/auth.spec.js b/test/auth.spec.js new file mode 100644 index 0000000000..6bb23a7136 --- /dev/null +++ b/test/auth.spec.js @@ -0,0 +1,56 @@ +// @flow + +import { expect } from 'chai'; +import { setupIpcAndStore, setupBackendAndStore, failFast, checkNextTick } from './helpers/ipc-helpers'; +import { IpcChain } from './helpers/IpcChain'; +import { Backend } from '../app/lib/backend'; + +describe('authentication', () => { + + it('authenticates before ipc call if unauthenticated', (done) => { + const { store, mockIpc } = setupIpcAndStore(); + const credentials = { + sharedSecret: 'foo', + connectionString: '', + }; + + + const chain = new IpcChain(mockIpc); + chain.require('auth') + .withInputValidation( secret => { + expect(secret).to.equal(credentials.sharedSecret); + }) + .done(); + + chain.require('connect') + .done(); + + chain.onSuccessOrFailure(done); + + + const backend = new Backend(store, credentials, mockIpc); + backend.connect(); + }); + + it('reauthenticates on reconnect', (done) => { + const { mockIpc, backend } = setupBackendAndStore(); + + let authCount = 0; + mockIpc.auth = () => { + authCount++; + return Promise.resolve(); + }; + + + mockIpc.killWebSocket(); + failFast(() => { + expect(authCount).to.equal(0); + }, done); + + + backend.connect(); + checkNextTick(() => { + expect(authCount).to.equal(1); + }, done); + }); +}); diff --git a/test/connect.spec.js b/test/connect.spec.js index bb6ac41526..07e3091c6e 100644 --- a/test/connect.spec.js +++ b/test/connect.spec.js @@ -61,29 +61,35 @@ describe('connect', () => { }); }); - it('should correctly deduce \'connected\' from backend states', () => { + it('should correctly deduce \'connected\' from backend states', (done) => { const { store, mockIpc } = setupBackendAndStore(); - expect(store.getState().connection.status).not.to.equal('connected'); - mockIpc.sendNewState({ state: 'secured', target_state: 'secured' }); - expect(store.getState().connection.status).to.equal('connected'); + checkNextTick( () => { + expect(store.getState().connection.status).not.to.equal('connected'); + mockIpc.sendNewState({ state: 'secured', target_state: 'secured' }); + expect(store.getState().connection.status).to.equal('connected'); + }, done); }); - it('should correctly deduce \'connecting\' from backend states', () => { + it('should correctly deduce \'connecting\' from backend states', (done) => { const { store, mockIpc } = setupBackendAndStore(); - expect(store.getState().connection.status).not.to.equal('connecting'); - mockIpc.sendNewState({ state: 'unsecured', target_state: 'secured' }); - expect(store.getState().connection.status).to.equal('connecting'); + checkNextTick( () => { + expect(store.getState().connection.status).not.to.equal('connecting'); + mockIpc.sendNewState({ state: 'unsecured', target_state: 'secured' }); + expect(store.getState().connection.status).to.equal('connecting'); + }, done); }); - it('should correctly deduce \'disconnected\' from backend states', () => { + it('should correctly deduce \'disconnected\' from backend states', (done) => { const { store, mockIpc } = setupBackendAndStore(); store.dispatch(connectionActions.connected()); - expect(store.getState().connection.status).not.to.equal('disconnected'); - mockIpc.sendNewState({ state: 'unsecured', target_state: 'unsecured' }); - expect(store.getState().connection.status).to.equal('disconnected'); + checkNextTick( () => { + expect(store.getState().connection.status).not.to.equal('disconnected'); + mockIpc.sendNewState({ state: 'unsecured', target_state: 'unsecured' }); + expect(store.getState().connection.status).to.equal('disconnected'); + }, done); }); }); diff --git a/test/helpers/IpcChain.js b/test/helpers/IpcChain.js index a7916e1e9f..a62626a6a6 100644 --- a/test/helpers/IpcChain.js +++ b/test/helpers/IpcChain.js @@ -8,11 +8,13 @@ export class IpcChain { _recordedCalls: Array<string>; _mockIpc: {}; _done: (*) => void; + _aborted: boolean; constructor(mockIpc: {}) { this._expectedCalls = []; this._recordedCalls = []; this._mockIpc = mockIpc; + this._aborted = false; } require(ipcCall: string): StepBuilder { @@ -28,10 +30,21 @@ export class IpcChain { } _stepPromiseCallback(step, resolve, args) { + if (this._aborted) { + return; + } + this._registerCall(step.ipcCall); if (step.inputValidation) { - failFast(() => step.inputValidation(...args), this._done); + const failedInputValidation = failFast(() => { + step.inputValidation(...args); + }, this._done); + + if (failedInputValidation) { + this._abort(); + return; + } } if (this._isLastCall()) { @@ -41,6 +54,10 @@ export class IpcChain { resolve(step.returnValue); } + _abort() { + this._aborted = true; + } + _isLastCall(): boolean { return this._recordedCalls.length === this._expectedCalls.length; } diff --git a/test/helpers/ipc-helpers.js b/test/helpers/ipc-helpers.js index 5e4b2941d6..e2a578973b 100644 --- a/test/helpers/ipc-helpers.js +++ b/test/helpers/ipc-helpers.js @@ -9,14 +9,24 @@ import { mockState, mockStore } from '../mocks/redux'; type DoneCallback = (?mixed) => void; type Check = () => void; -export function setupBackendAndStore() { - +export function setupIpcAndStore() { const memoryHistory = createMemoryHistory(); const store = configureStore(null, memoryHistory); const mockIpc = newMockIpc(); - const backend = new Backend(store, mockIpc); + return { store, mockIpc }; +} + +export function setupBackendAndStore() { + + const { store, mockIpc } = setupIpcAndStore(); + + const credentials = { + sharedSecret: '', + connectionString: '', + }; + const backend = new Backend(store, credentials, mockIpc); return { store, mockIpc, backend }; } @@ -24,7 +34,11 @@ export function setupBackendAndStore() { export function setupBackendAndMockStore() { const store = mockStore(mockState()); const mockIpc = newMockIpc(); - const backend = new Backend(store, mockIpc); + const credentials = { + sharedSecret: '', + connectionString: '', + }; + const backend = new Backend(store, credentials, mockIpc); return { store, mockIpc, backend }; } @@ -54,11 +68,13 @@ export function checkNextTick(fn: Check, done: DoneCallback) { // In async tests where we want to test a chain of IPC messages // we can only invoke `done` for the last message. This function // is for the intermediate messages. -export function failFast(fn: Check, done: DoneCallback) { +export function failFast(fn: Check, done: DoneCallback): boolean { try { fn(); + return false; } catch(e) { done(e); + return true; } } export function failFastNextTick(fn: Check, done: DoneCallback) { diff --git a/test/mocks/ipc.js b/test/mocks/ipc.js index 8f0b82ba37..2672a431fd 100644 --- a/test/mocks/ipc.js +++ b/test/mocks/ipc.js @@ -1,20 +1,23 @@ // @flow -import type { IpcFacade, BackendState, IpcCredentials } from '../../app/lib/ipc-facade'; +import type { IpcFacade, BackendState } from '../../app/lib/ipc-facade'; interface MockIpc { sendNewState: (BackendState) => void; + killWebSocket: () => void; -getAccountData: *; -connect: *; -getAccount: *; + -auth: *; } export function newMockIpc() { const stateListeners = []; + const connectionCloseListeners = []; const mockIpc: IpcFacade & MockIpc = { - setCredentials: (_credentials: IpcCredentials) => {}, + setConnectionString: (_str: string) => {}, getAccountData: (accountToken) => { return new Promise(r => r({ accountToken: accountToken, @@ -60,6 +63,15 @@ export function newMockIpc() { l(state); } }, + auth: (_secret: string) => Promise.resolve(), + setCloseConnectionHandler: (listener: () => void) => { + connectionCloseListeners.push(listener); + }, + killWebSocket: () => { + for(const l of connectionCloseListeners) { + l(); + } + } }; return mockIpc; |
