summaryrefslogtreecommitdiffhomepage
path: root/test
diff options
context:
space:
mode:
authorAndrej Mihajlov <and@mullvad.net>2018-06-20 15:34:40 +0200
committerAndrej Mihajlov <and@mullvad.net>2018-07-03 13:37:54 +0200
commit73840e98952dd3f7c005fcec44c971455da179eb (patch)
tree15a887410858007a802450ad2870d8bf495dd16d /test
parent67e82627564f8e4a2d8da4bcf5f0fd00867876bc (diff)
downloadmullvadvpn-73840e98952dd3f7c005fcec44c971455da179eb.tar.xz
mullvadvpn-73840e98952dd3f7c005fcec44c971455da179eb.zip
Refactor IpcFacade to DaemonRpc and JsonRpcWs to JsonRpcTransport
Diffstat (limited to 'test')
-rw-r--r--test/auth.spec.js20
-rw-r--r--test/autologin.spec.js2
-rw-r--r--test/connect.spec.js4
-rw-r--r--test/helpers/IpcChain.js18
-rw-r--r--test/helpers/ipc-helpers.js14
-rw-r--r--test/ipc.spec.js134
-rw-r--r--test/jsonrpc-transport.spec.js144
-rw-r--r--test/login.spec.js2
-rw-r--r--test/logout.spec.js2
-rw-r--r--test/mocks/ipc.js58
10 files changed, 199 insertions, 199 deletions
diff --git a/test/auth.spec.js b/test/auth.spec.js
index e6b2c25486..4f919dff87 100644
--- a/test/auth.spec.js
+++ b/test/auth.spec.js
@@ -8,30 +8,34 @@ describe('authentication', () => {
it('authenticates before ipc call if unauthenticated', (done) => {
const { store, mockIpc } = setupIpcAndStore();
+ const credentials = {
+ connectionString: 'ws://localhost:1234/',
+ sharedSecret: '1234',
+ };
+
const chain = new IpcChain(mockIpc);
- chain.onSuccessOrFailure(done);
chain.expect('authenticate').withInputValidation((secret) => {
expect(secret).to.equal(credentials.sharedSecret);
});
chain.expect('connect');
+ chain.end(done);
- const credentials = {
- sharedSecret: '',
- connectionString: '',
- };
- const backend = new Backend(store, credentials, mockIpc);
- backend.connect();
+ const backend = new Backend(store, mockIpc);
+ backend.connect(credentials);
+
+ backend.connectTunnel();
});
it('reauthenticates on reconnect', async () => {
const { mockIpc, backend } = setupBackendAndStore();
mockIpc.authenticate = spy(mockIpc.authenticate);
+ await mockIpc.connectTunnel();
mockIpc.killWebSocket();
expect(mockIpc.authenticate).to.not.have.been.called();
- await backend.connect();
+ await backend.connectTunnel();
expect(mockIpc.authenticate).to.have.been.called.once;
});
});
diff --git a/test/autologin.spec.js b/test/autologin.spec.js
index 60c5cc5bde..505ad285c0 100644
--- a/test/autologin.spec.js
+++ b/test/autologin.spec.js
@@ -16,7 +16,7 @@ describe('autologin', () => {
expect(num).to.equal(randomAccountToken);
});
- chain.onSuccessOrFailure(done);
+ chain.end(done);
backend.autologin();
});
diff --git a/test/connect.spec.js b/test/connect.spec.js
index f1621dbeb6..409a04c0fb 100644
--- a/test/connect.spec.js
+++ b/test/connect.spec.js
@@ -7,7 +7,7 @@ describe('connect', () => {
it("should set the connection state to 'disconnected' on failed attempts", (done) => {
const { store, mockIpc, backend } = setupBackendAndStore();
- mockIpc.connect = () => new Promise((_, reject) => reject('Some error'));
+ mockIpc.connectTunnel = () => new Promise((_, reject) => reject('Some error'));
store.dispatch(connectionActions.connected());
@@ -23,7 +23,7 @@ describe('connect', () => {
it('should update the state with the server address', () => {
const { store, backend } = setupBackendAndStore();
- return backend.connect().then(() => {
+ return backend.connectTunnel().then(() => {
const state = store.getState().connection;
expect(state.status).to.equal('connecting');
});
diff --git a/test/helpers/IpcChain.js b/test/helpers/IpcChain.js
index 1505621cc0..547851fdcf 100644
--- a/test/helpers/IpcChain.js
+++ b/test/helpers/IpcChain.js
@@ -1,7 +1,5 @@
// @flow
-import { check, failFast } from './ipc-helpers';
-
export class IpcChain {
_expectedCalls: Array<string>;
_recordedCalls: Array<string>;
@@ -39,12 +37,11 @@ export class IpcChain {
const inputValidation = step.inputValidation;
if (inputValidation) {
- const failedInputValidation = failFast(() => {
+ try {
inputValidation(...args);
- }, this._done);
-
- if (failedInputValidation) {
+ } catch (error) {
this._abort();
+ this._done(error);
return;
}
}
@@ -65,16 +62,19 @@ export class IpcChain {
}
_ensureChainCalledCorrectly() {
- check(() => {
+ try {
expect(this._expectedCalls).to.deep.equal(this._recordedCalls);
- }, this._done);
+ this._done();
+ } catch (error) {
+ this._done(error);
+ }
}
_registerCall(ipcCall: string) {
this._recordedCalls.push(ipcCall);
}
- onSuccessOrFailure(done: (*) => void) {
+ end(done: (?Error) => void) {
this._done = done;
}
}
diff --git a/test/helpers/ipc-helpers.js b/test/helpers/ipc-helpers.js
index 4466c06eb2..5bfe1d0267 100644
--- a/test/helpers/ipc-helpers.js
+++ b/test/helpers/ipc-helpers.js
@@ -12,7 +12,6 @@ type Check = () => void;
export function setupIpcAndStore() {
const memoryHistory = createMemoryHistory();
const store = configureStore(null, memoryHistory);
-
const mockIpc = newMockIpc();
return { store, mockIpc };
@@ -20,12 +19,7 @@ export function setupIpcAndStore() {
export function setupBackendAndStore() {
const { store, mockIpc } = setupIpcAndStore();
-
- const credentials = {
- sharedSecret: '',
- connectionString: '',
- };
- const backend = new Backend(store, credentials, mockIpc);
+ const backend = new Backend(store, mockIpc);
return { store, mockIpc, backend };
}
@@ -33,11 +27,7 @@ export function setupBackendAndStore() {
export function setupBackendAndMockStore() {
const store = mockStore(_initialState());
const mockIpc = newMockIpc();
- const credentials = {
- sharedSecret: '',
- connectionString: '',
- };
- const backend = new Backend(store, credentials, mockIpc);
+ const backend = new Backend(store, mockIpc);
return { store, mockIpc, backend };
}
diff --git a/test/ipc.spec.js b/test/ipc.spec.js
deleted file mode 100644
index 1c8b19b5a6..0000000000
--- a/test/ipc.spec.js
+++ /dev/null
@@ -1,134 +0,0 @@
-// @flow
-
-import Ipc from '../app/lib/jsonrpc-ws-ipc';
-import jsonrpc from 'jsonrpc-lite';
-import type { JsonRpcMessage } from '../app/lib/jsonrpc-ws-ipc';
-
-describe('The IPC server', () => {
- it('should send as soon as the websocket connects', () => {
- const { ws, ipc } = setupIpc();
- ws.close();
-
- let sent = false;
- const p = ipc.send('hello').then(() => {
- expect(sent).to.be.true;
- });
-
- ws.on('hello', (msg) => {
- sent = true;
-
- ws.replyOk(msg.id);
- });
- ws.acceptConnection();
-
- return p;
- });
-
- it('should reject failed jsonrpc requests', () => {
- const { ws, ipc } = setupIpc();
- ws.on('WHAT_IS_THIS', (msg) => {
- ws.replyFail(msg.id, 'Method not found', -32601);
- });
-
- return ipc.send('WHAT_IS_THIS').catch((e) => {
- expect(e.code).to.equal(-32601);
- expect(e.message).to.contain('Method not found');
- });
- });
-
- it('should route reply to correct promise', () => {
- const { ws, ipc } = setupIpc();
-
- ws.on('a message', (msg) => ws.replyOk(msg.id, 'a reply'));
-
- const decoy = ipc
- .send('a decoy', [], 1)
- .then(() => {
- throw new Error('Should not be called');
- })
- .catch((e) => {
- if (e.name !== 'TimeOutError') {
- throw e;
- }
- });
- const message = ipc.send('a message', [], 1).then((reply) => expect(reply).to.equal('a reply'));
-
- return Promise.all([message, decoy]);
- });
-
- it('should timeout if no response is returned', () => {
- const { ipc } = setupIpc();
-
- return ipc.send('a message', [], 1).catch((e) => {
- expect(e.name).to.equal('TimeOutError');
- expect(e.message).to.contain('timed out');
- });
- });
-
- it('should route notifications', (done) => {
- const { ws, ipc } = setupIpc();
-
- const eventListener = (event) => {
- try {
- expect(event).to.equal('an event!');
- done();
- } catch (ex) {
- done(ex);
- }
- };
-
- ws.on('event_subscribe', (msg) => ws.replyOk(msg.id, 1));
- ipc
- .on('event', eventListener)
- .then(() => {
- ws.reply(jsonrpc.notification('event', { subscription: 1, result: 'an event!' }));
- })
- .catch((e) => done(e));
- });
-});
-
-function mockWebsocket() {
- const ws: any = {
- listeners: {},
- readyState: 1,
- };
-
- ws.on = (event, listener) => (ws.listeners[event] = listener);
- ws.send = (data) => {
- const listener = ws.listeners[data.method];
- if (listener) {
- listener(data);
- }
- };
-
- ws.factory = () => ws;
-
- ws.acceptConnection = () => {
- ws.readyState = 1;
- ws.onopen();
- };
- ws.close = () => {
- ws.readyState = 3;
- ws.onclose();
- };
-
- ws.reply = (msg: JsonRpcMessage) => {
- ws.onmessage({ data: JSON.stringify(msg) });
- };
- ws.replyOk = (id: string, msg) => {
- ws.reply(jsonrpc.success(id, msg || ''));
- };
- ws.replyFail = (id: string, msg: string, code: number) => {
- ws.reply(jsonrpc.error(id, new jsonrpc.JsonRpcError(msg, code)));
- };
-
- return ws;
-}
-
-function setupIpc() {
- const ws = mockWebsocket();
- return {
- ws: ws,
- ipc: new Ipc('1.2.3.4', ws.factory),
- };
-}
diff --git a/test/jsonrpc-transport.spec.js b/test/jsonrpc-transport.spec.js
new file mode 100644
index 0000000000..124bba8f00
--- /dev/null
+++ b/test/jsonrpc-transport.spec.js
@@ -0,0 +1,144 @@
+// @flow
+
+import JsonRpcTransport, {
+ TimeOutError as JsonRpcTransportTimeOutError,
+} from '../app/lib/jsonrpc-transport';
+import jsonrpc from 'jsonrpc-lite';
+import { Server, WebSocket as MockWebSocket } from 'mock-socket';
+
+describe('JSON RPC transport', () => {
+ const WEBSOCKET_URL = 'ws://localhost:8080';
+ let server: Server, transport: JsonRpcTransport;
+
+ beforeEach(() => {
+ server = new Server(WEBSOCKET_URL);
+ transport = new JsonRpcTransport((s) => new MockWebSocket(s));
+ });
+
+ afterEach(() => {
+ server.close();
+ });
+
+ it('should send as soon as the websocket connects', (done) => {
+ server.on('message', (msg) => {
+ const { payload } = jsonrpc.parse(msg);
+
+ if (payload.method === 'hello') {
+ server.send(JSON.stringify(jsonrpc.success(payload.id, 'ok')));
+ }
+ });
+
+ transport
+ .send('hello')
+ .then(() => {
+ done();
+ })
+ .catch((error) => {
+ done(error);
+ });
+
+ transport.connect(WEBSOCKET_URL);
+ });
+
+ it('should reject failed jsonrpc requests', (done) => {
+ server.on('message', (msg) => {
+ const { payload } = jsonrpc.parse(msg);
+
+ if (payload.method === 'invalid-method') {
+ server.send(
+ JSON.stringify(
+ jsonrpc.error(payload.id, new jsonrpc.JsonRpcError('Method not found', -32601)),
+ ),
+ );
+ }
+ });
+
+ transport.send('invalid-method').catch((error) => {
+ try {
+ expect(error.code).to.equal(-32601);
+ expect(error.message).to.contain('Method not found');
+ done();
+ } catch (error) {
+ done(error);
+ }
+ });
+
+ transport.connect(WEBSOCKET_URL);
+ });
+
+ it('should route reply to correct promise', () => {
+ server.on('message', (msg) => {
+ const { payload } = jsonrpc.parse(msg);
+
+ if (payload.method === 'a message') {
+ server.send(JSON.stringify(jsonrpc.success(payload.id, 'a reply')));
+ }
+ });
+
+ const decoy = transport
+ .send('a decoy', [], 100)
+ .then(() => {
+ throw new Error('Should not be called');
+ })
+ .catch((error) => {
+ expect(error).to.be.an.instanceof(JsonRpcTransportTimeOutError);
+ });
+
+ const message = transport.send('a message', [], 100).then((reply) => {
+ expect(reply).to.equal('a reply');
+ });
+
+ transport.connect(WEBSOCKET_URL);
+
+ return Promise.all([message, decoy]);
+ });
+
+ it('should timeout if no response is returned', (done) => {
+ transport
+ .send('timeout-message', {}, 1)
+ .then(() => {
+ done(new Error('Should not be called'));
+ })
+ .catch((error) => {
+ try {
+ expect(error).to.be.an.instanceof(JsonRpcTransportTimeOutError);
+ expect(error.message).to.contain('Request timed out');
+ done();
+ } catch (error) {
+ done(error);
+ }
+ });
+
+ transport.connect(WEBSOCKET_URL);
+ });
+
+ it('should route notifications', (done) => {
+ server.on('message', (msg) => {
+ const { payload } = jsonrpc.parse(msg);
+
+ if (payload.method === 'event_subscribe') {
+ server.send(JSON.stringify(jsonrpc.success(payload.id, 1)));
+ }
+ });
+
+ transport
+ .subscribe('event', (event) => {
+ try {
+ expect(event).to.equal('an event!');
+ done();
+ } catch (error) {
+ done(error);
+ }
+ })
+ .then(() => {
+ server.send(
+ JSON.stringify(jsonrpc.notification('event', { subscription: 1, result: 'an event!' })),
+ );
+ })
+ .catch((error) => {
+ done(error);
+ });
+
+ transport.connect(WEBSOCKET_URL);
+ });
+});
diff --git a/test/login.spec.js b/test/login.spec.js
index 68db14494b..a2390b5241 100644
--- a/test/login.spec.js
+++ b/test/login.spec.js
@@ -24,7 +24,7 @@ describe('Logging in', () => {
expect(an).to.equal('123');
});
- chain.onSuccessOrFailure(done);
+ chain.end(done);
store.dispatch(accountActions.login(backend, '123'));
});
diff --git a/test/logout.spec.js b/test/logout.spec.js
index 65bc3aba09..c973c6a81a 100644
--- a/test/logout.spec.js
+++ b/test/logout.spec.js
@@ -19,7 +19,7 @@ describe('logging out', () => {
expect(num).to.be.null;
});
chain.expect('disconnect');
- chain.onSuccessOrFailure(done);
+ chain.end(done);
backend.logout();
});
diff --git a/test/mocks/ipc.js b/test/mocks/ipc.js
index 590313ec13..b610244462 100644
--- a/test/mocks/ipc.js
+++ b/test/mocks/ipc.js
@@ -1,39 +1,39 @@
// @flow
-import type { IpcFacade, AccountToken, AccountData, BackendState } from '../../app/lib/ipc-facade';
+import type {
+ DaemonRpcProtocol,
+ AccountToken,
+ AccountData,
+ BackendState,
+} from '../../app/lib/daemon-rpc';
interface MockIpc {
sendNewState: (BackendState) => void;
killWebSocket: () => void;
-getAccountData: (AccountToken) => Promise<AccountData>;
- -connect: () => Promise<void>;
+ -connectTunnel: () => Promise<void>;
-getAccount: () => Promise<?AccountToken>;
-authenticate: (string) => Promise<void>;
}
export function newMockIpc() {
const stateListeners = [];
- const connectionCloseListeners = [];
+ let connectionOpenListener: ?() => void;
+ let connectionCloseListener: ?(error: ?Error) => void;
- const mockIpc: IpcFacade & MockIpc = {
+ const mockIpc: DaemonRpcProtocol & MockIpc = {
setConnectionString: (_str: string) => {},
-
getAccountData: (accountToken) =>
Promise.resolve({
accountToken: accountToken,
expiry: '',
}),
-
getRelayLocations: () =>
Promise.resolve({
countries: [],
}),
-
getAccount: () => Promise.resolve('1111'),
-
setAccount: () => Promise.resolve(),
-
updateRelaySettings: () => Promise.resolve(),
-
getRelaySettings: () =>
Promise.resolve({
custom_tunnel_endpoint: {
@@ -46,17 +46,16 @@ export function newMockIpc() {
},
},
}),
-
setAllowLan: (_allowLan: boolean) => Promise.resolve(),
-
getAllowLan: () => Promise.resolve(true),
-
- connect: () => Promise.resolve(),
-
- disconnect: () => Promise.resolve(),
-
- shutdown: () => Promise.resolve(),
-
+ connect: () => {
+ if (connectionOpenListener) {
+ connectionOpenListener();
+ }
+ },
+ disconnect: () => {},
+ connectTunnel: () => Promise.resolve(),
+ disconnectTunnel: () => Promise.resolve(),
getLocation: () =>
Promise.resolve({
ip: '',
@@ -66,36 +65,33 @@ export function newMockIpc() {
longitude: 0.0,
mullvad_exit_ip: false,
}),
-
getState: () =>
Promise.resolve({
state: 'unsecured',
target_state: 'unsecured',
}),
-
- registerStateListener: (listener: (BackendState) => void) => {
+ subscribeStateListener: (listener: (state: ?BackendState, error: ?Error) => void) => {
stateListeners.push(listener);
+ return Promise.resolve();
},
-
sendNewState: (state: BackendState) => {
for (const listener of stateListeners) {
listener(state);
}
},
-
- setCloseConnectionHandler: (listener: () => void) => {
- connectionCloseListeners.push(listener);
+ addOpenConnectionObserver: (listener: () => void) => {
+ connectionOpenListener = listener;
+ },
+ addCloseConnectionObserver: (listener: (error: ?Error) => void) => {
+ connectionCloseListener = listener;
},
-
authenticate: (_secret: string) => Promise.resolve(),
-
getAccountHistory: () => Promise.resolve([]),
-
removeAccountFromHistory: (_accountToken) => Promise.resolve(),
killWebSocket: () => {
- for (const listener of connectionCloseListeners) {
- listener();
+ if (connectionCloseListener) {
+ connectionCloseListener();
}
},
};