summaryrefslogtreecommitdiffhomepage
path: root/test/ipc.spec.js
blob: ae9c5ab81596b8ac710dd8ad1d4821ab01058744 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// @flow

import Ipc from '../app/lib/jsonrpc-ws-ipc.js';
import jsonrpc from 'jsonrpc-lite';
import { expect } from 'chai';
import assert from 'assert';
import type { JsonRpcMessage } from '../app/lib/jsonrpc-ws-ipc.js';

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')
      .then(() => assert(false, 'Should not be called'))
      .catch(e => {
        if (e.name !== 'TimeOutError') {
          throw e;
        }
      });
    const message = ipc.send('a message')
      .then((reply) => expect(reply).to.equal('a reply'));

    return Promise.all([message, decoy]);
  });

  it('should timeout if no response is returned', () => {
    const { ipc } = setupIpc();

    ipc.setSendTimeout(1);
    return ipc.send('a message')
      .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),
  };
}