]> git.proxmox.com Git - mirror_novnc.git/blame - tests/test.websock.js
Merge branch 'master' of https://github.com/josiah2009/noVNC
[mirror_novnc.git] / tests / test.websock.js
CommitLineData
2cccf753
SR
1/* jshint expr: true */
2var assert = chai.assert;
3var expect = chai.expect;
4
dfae3209
SR
5import Websock from '../core/websock.js';
6import FakeWebSocket from './fake.websocket.js';
7
0aaf59c2 8import sinon from '../vendor/sinon.js';
dfae3209 9
2cccf753
SR
10describe('Websock', function() {
11 "use strict";
12
13 describe('Queue methods', function () {
14 var sock;
38781d93 15 var RQ_TEMPLATE = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7]);
2cccf753
SR
16
17 beforeEach(function () {
18 sock = new Websock();
38781d93
SR
19 // skip init
20 sock._allocate_buffers();
21 sock._rQ.set(RQ_TEMPLATE);
22 sock._rQlen = RQ_TEMPLATE.length;
2cccf753
SR
23 });
24 describe('rQlen', function () {
25 it('should return the length of the receive queue', function () {
26 sock.set_rQi(0);
27
28 expect(sock.rQlen()).to.equal(RQ_TEMPLATE.length);
29 });
30
31 it("should return the proper length if we read some from the receive queue", function () {
32 sock.set_rQi(1);
33
34 expect(sock.rQlen()).to.equal(RQ_TEMPLATE.length - 1);
35 });
36 });
37
38 describe('rQpeek8', function () {
39 it('should peek at the next byte without poping it off the queue', function () {
40 var bef_len = sock.rQlen();
41 var peek = sock.rQpeek8();
42 expect(sock.rQpeek8()).to.equal(peek);
43 expect(sock.rQlen()).to.equal(bef_len);
44 });
45 });
46
47 describe('rQshift8', function () {
48 it('should pop a single byte from the receive queue', function () {
49 var peek = sock.rQpeek8();
50 var bef_len = sock.rQlen();
51 expect(sock.rQshift8()).to.equal(peek);
52 expect(sock.rQlen()).to.equal(bef_len - 1);
53 });
54 });
55
2cccf753
SR
56 describe('rQshift16', function () {
57 it('should pop two bytes from the receive queue and return a single number', function () {
58 var bef_len = sock.rQlen();
59 var expected = (RQ_TEMPLATE[0] << 8) + RQ_TEMPLATE[1];
60 expect(sock.rQshift16()).to.equal(expected);
61 expect(sock.rQlen()).to.equal(bef_len - 2);
62 });
63 });
64
65 describe('rQshift32', function () {
66 it('should pop four bytes from the receive queue and return a single number', function () {
67 var bef_len = sock.rQlen();
68 var expected = (RQ_TEMPLATE[0] << 24) +
69 (RQ_TEMPLATE[1] << 16) +
70 (RQ_TEMPLATE[2] << 8) +
71 RQ_TEMPLATE[3];
72 expect(sock.rQshift32()).to.equal(expected);
73 expect(sock.rQlen()).to.equal(bef_len - 4);
74 });
75 });
76
77 describe('rQshiftStr', function () {
78 it('should shift the given number of bytes off of the receive queue and return a string', function () {
79 var bef_len = sock.rQlen();
80 var bef_rQi = sock.get_rQi();
81 var shifted = sock.rQshiftStr(3);
82 expect(shifted).to.be.a('string');
38781d93 83 expect(shifted).to.equal(String.fromCharCode.apply(null, Array.prototype.slice.call(new Uint8Array(RQ_TEMPLATE.buffer, bef_rQi, 3))));
2cccf753
SR
84 expect(sock.rQlen()).to.equal(bef_len - 3);
85 });
86
87 it('should shift the entire rest of the queue off if no length is given', function () {
88 sock.rQshiftStr();
89 expect(sock.rQlen()).to.equal(0);
90 });
91 });
92
93 describe('rQshiftBytes', function () {
94 it('should shift the given number of bytes of the receive queue and return an array', function () {
95 var bef_len = sock.rQlen();
96 var bef_rQi = sock.get_rQi();
97 var shifted = sock.rQshiftBytes(3);
38781d93
SR
98 expect(shifted).to.be.an.instanceof(Uint8Array);
99 expect(shifted).to.array.equal(new Uint8Array(RQ_TEMPLATE.buffer, bef_rQi, 3));
2cccf753
SR
100 expect(sock.rQlen()).to.equal(bef_len - 3);
101 });
102
103 it('should shift the entire rest of the queue off if no length is given', function () {
104 sock.rQshiftBytes();
105 expect(sock.rQlen()).to.equal(0);
106 });
107 });
108
109 describe('rQslice', function () {
110 beforeEach(function () {
111 sock.set_rQi(0);
112 });
113
114 it('should not modify the receive queue', function () {
115 var bef_len = sock.rQlen();
116 sock.rQslice(0, 2);
117 expect(sock.rQlen()).to.equal(bef_len);
118 });
119
120 it('should return an array containing the given slice of the receive queue', function () {
121 var sl = sock.rQslice(0, 2);
38781d93
SR
122 expect(sl).to.be.an.instanceof(Uint8Array);
123 expect(sl).to.array.equal(new Uint8Array(RQ_TEMPLATE.buffer, 0, 2));
2cccf753
SR
124 });
125
126 it('should use the rest of the receive queue if no end is given', function () {
127 var sl = sock.rQslice(1);
128 expect(sl).to.have.length(RQ_TEMPLATE.length - 1);
38781d93 129 expect(sl).to.array.equal(new Uint8Array(RQ_TEMPLATE.buffer, 1));
2cccf753
SR
130 });
131
132 it('should take the current rQi in to account', function () {
133 sock.set_rQi(1);
38781d93 134 expect(sock.rQslice(0, 2)).to.array.equal(new Uint8Array(RQ_TEMPLATE.buffer, 1, 2));
2cccf753
SR
135 });
136 });
137
138 describe('rQwait', function () {
139 beforeEach(function () {
140 sock.set_rQi(0);
141 });
142
143 it('should return true if there are not enough bytes in the receive queue', function () {
144 expect(sock.rQwait('hi', RQ_TEMPLATE.length + 1)).to.be.true;
145 });
146
147 it('should return false if there are enough bytes in the receive queue', function () {
148 expect(sock.rQwait('hi', RQ_TEMPLATE.length)).to.be.false;
149 });
150
151 it('should return true and reduce rQi by "goback" if there are not enough bytes', function () {
152 sock.set_rQi(5);
153 expect(sock.rQwait('hi', RQ_TEMPLATE.length, 4)).to.be.true;
154 expect(sock.get_rQi()).to.equal(1);
155 });
156
157 it('should raise an error if we try to go back more than possible', function () {
158 sock.set_rQi(5);
159 expect(function () { sock.rQwait('hi', RQ_TEMPLATE.length, 6); }).to.throw(Error);
160 });
161
162 it('should not reduce rQi if there are enough bytes', function () {
163 sock.set_rQi(5);
164 sock.rQwait('hi', 1, 6);
165 expect(sock.get_rQi()).to.equal(5);
166 });
167 });
168
169 describe('flush', function () {
170 beforeEach(function () {
171 sock._websocket = {
172 send: sinon.spy()
173 };
174 });
175
c4482d2d 176 it('should actually send on the websocket', function () {
2cccf753 177 sock._websocket.bufferedAmount = 8;
cf0623ff 178 sock._websocket.readyState = WebSocket.OPEN
9ff86fb7
SR
179 sock._sQ = new Uint8Array([1, 2, 3]);
180 sock._sQlen = 3;
2cccf753
SR
181 var encoded = sock._encode_message();
182
183 sock.flush();
184 expect(sock._websocket.send).to.have.been.calledOnce;
185 expect(sock._websocket.send).to.have.been.calledWith(encoded);
186 });
187
2cccf753 188 it('should not call send if we do not have anything queued up', function () {
9ff86fb7 189 sock._sQlen = 0;
2cccf753
SR
190 sock._websocket.bufferedAmount = 8;
191
192 sock.flush();
193
194 expect(sock._websocket.send).not.to.have.been.called;
195 });
2cccf753
SR
196 });
197
198 describe('send', function () {
199 beforeEach(function () {
200 sock.flush = sinon.spy();
201 });
202
203 it('should add to the send queue', function () {
204 sock.send([1, 2, 3]);
205 var sq = sock.get_sQ();
9ff86fb7 206 expect(new Uint8Array(sq.buffer, sock._sQlen - 3, 3)).to.array.equal(new Uint8Array([1, 2, 3]));
2cccf753
SR
207 });
208
209 it('should call flush', function () {
210 sock.send([1, 2, 3]);
211 expect(sock.flush).to.have.been.calledOnce;
212 });
213 });
214
215 describe('send_string', function () {
216 beforeEach(function () {
217 sock.send = sinon.spy();
218 });
219
220 it('should call send after converting the string to an array', function () {
221 sock.send_string("\x01\x02\x03");
222 expect(sock.send).to.have.been.calledWith([1, 2, 3]);
223 });
224 });
225 });
226
227 describe('lifecycle methods', function () {
228 var old_WS;
229 before(function () {
230 old_WS = WebSocket;
231 });
232
233 var sock;
234 beforeEach(function () {
235 sock = new Websock();
236 WebSocket = sinon.spy();
237 WebSocket.OPEN = old_WS.OPEN;
238 WebSocket.CONNECTING = old_WS.CONNECTING;
239 WebSocket.CLOSING = old_WS.CLOSING;
240 WebSocket.CLOSED = old_WS.CLOSED;
38781d93
SR
241
242 WebSocket.prototype.binaryType = 'arraybuffer';
2cccf753
SR
243 });
244
245 describe('opening', function () {
246 it('should pick the correct protocols if none are given' , function () {
247
248 });
249
250 it('should open the actual websocket', function () {
38781d93
SR
251 sock.open('ws://localhost:8675', 'binary');
252 expect(WebSocket).to.have.been.calledWith('ws://localhost:8675', 'binary');
2cccf753
SR
253 });
254
2cccf753
SR
255 // it('should initialize the event handlers')?
256 });
257
258 describe('closing', function () {
259 beforeEach(function () {
260 sock.open('ws://');
261 sock._websocket.close = sinon.spy();
262 });
263
264 it('should close the actual websocket if it is open', function () {
265 sock._websocket.readyState = WebSocket.OPEN;
266 sock.close();
267 expect(sock._websocket.close).to.have.been.calledOnce;
268 });
269
270 it('should close the actual websocket if it is connecting', function () {
271 sock._websocket.readyState = WebSocket.CONNECTING;
272 sock.close();
273 expect(sock._websocket.close).to.have.been.calledOnce;
274 });
275
276 it('should not try to close the actual websocket if closing', function () {
277 sock._websocket.readyState = WebSocket.CLOSING;
278 sock.close();
279 expect(sock._websocket.close).not.to.have.been.called;
280 });
281
282 it('should not try to close the actual websocket if closed', function () {
283 sock._websocket.readyState = WebSocket.CLOSED;
284 sock.close();
285 expect(sock._websocket.close).not.to.have.been.called;
286 });
287
288 it('should reset onmessage to not call _recv_message', function () {
289 sinon.spy(sock, '_recv_message');
290 sock.close();
291 sock._websocket.onmessage(null);
292 try {
293 expect(sock._recv_message).not.to.have.been.called;
294 } finally {
295 sock._recv_message.restore();
296 }
297 });
298 });
299
300 describe('event handlers', function () {
301 beforeEach(function () {
302 sock._recv_message = sinon.spy();
303 sock.on('open', sinon.spy());
304 sock.on('close', sinon.spy());
305 sock.on('error', sinon.spy());
306 sock.open('ws://');
307 });
308
309 it('should call _recv_message on a message', function () {
310 sock._websocket.onmessage(null);
311 expect(sock._recv_message).to.have.been.calledOnce;
312 });
313
2cccf753
SR
314 it('should call the open event handler on opening', function () {
315 sock._websocket.onopen();
316 expect(sock._eventHandlers.open).to.have.been.calledOnce;
317 });
318
319 it('should call the close event handler on closing', function () {
320 sock._websocket.onclose();
321 expect(sock._eventHandlers.close).to.have.been.calledOnce;
322 });
323
324 it('should call the error event handler on error', function () {
325 sock._websocket.onerror();
326 expect(sock._eventHandlers.error).to.have.been.calledOnce;
327 });
328 });
329
330 after(function () {
331 WebSocket = old_WS;
332 });
333 });
334
335 describe('WebSocket Receiving', function () {
336 var sock;
337 beforeEach(function () {
338 sock = new Websock();
38781d93 339 sock._allocate_buffers();
2cccf753
SR
340 });
341
342 it('should support adding binary Uint8Array data to the receive queue', function () {
343 var msg = { data: new Uint8Array([1, 2, 3]) };
344 sock._mode = 'binary';
345 sock._recv_message(msg);
346 expect(sock.rQshiftStr(3)).to.equal('\x01\x02\x03');
347 });
348
349 it('should call the message event handler if present', function () {
350 sock._eventHandlers.message = sinon.spy();
38781d93
SR
351 var msg = { data: new Uint8Array([1, 2, 3]).buffer };
352 sock._mode = 'binary';
2cccf753
SR
353 sock._recv_message(msg);
354 expect(sock._eventHandlers.message).to.have.been.calledOnce;
355 });
356
357 it('should not call the message event handler if there is nothing in the receive queue', function () {
358 sock._eventHandlers.message = sinon.spy();
38781d93
SR
359 var msg = { data: new Uint8Array([]).buffer };
360 sock._mode = 'binary';
2cccf753
SR
361 sock._recv_message(msg);
362 expect(sock._eventHandlers.message).not.to.have.been.called;
363 });
364
365 it('should compact the receive queue', function () {
366 // NB(sross): while this is an internal implementation detail, it's important to
367 // test, otherwise the receive queue could become very large very quickly
38781d93
SR
368 sock._rQ = new Uint8Array([0, 1, 2, 3, 4, 5, 0, 0, 0, 0]);
369 sock._rQlen = 6;
2cccf753
SR
370 sock.set_rQi(6);
371 sock._rQmax = 3;
38781d93
SR
372 var msg = { data: new Uint8Array([1, 2, 3]).buffer };
373 sock._mode = 'binary';
2cccf753 374 sock._recv_message(msg);
38781d93 375 expect(sock._rQlen).to.equal(3);
2cccf753
SR
376 expect(sock.get_rQi()).to.equal(0);
377 });
378
40037b6a
SR
379 it('should automatically resize the receive queue if the incoming message is too large', function () {
380 sock._rQ = new Uint8Array(20);
381 sock._rQlen = 0;
382 sock.set_rQi(0);
383 sock._rQbufferSize = 20;
384 sock._rQmax = 2;
385 var msg = { data: new Uint8Array(30).buffer };
386 sock._mode = 'binary';
387 sock._recv_message(msg);
388 expect(sock._rQlen).to.equal(30);
389 expect(sock.get_rQi()).to.equal(0);
390 expect(sock._rQ.length).to.equal(240); // keep the invariant that rQbufferSize / 8 >= rQlen
391 });
2cccf753
SR
392 });
393
394 describe('Data encoding', function () {
395 before(function () { FakeWebSocket.replace(); });
396 after(function () { FakeWebSocket.restore(); });
397
398 describe('as binary data', function () {
399 var sock;
400 beforeEach(function () {
401 sock = new Websock();
402 sock.open('ws://', 'binary');
403 sock._websocket._open();
404 });
405
9ff86fb7
SR
406 it('should only send the send queue up to the send queue length', function () {
407 sock._sQ = new Uint8Array([1, 2, 3, 4, 5]);
408 sock._sQlen = 3;
409 var res = sock._encode_message();
410 expect(res).to.array.equal(new Uint8Array([1, 2, 3]));
2cccf753
SR
411 });
412
413 it('should properly pass the encoded data off to the actual WebSocket', function () {
414 sock.send([1, 2, 3]);
9ff86fb7 415 expect(sock._websocket._get_sent_data()).to.array.equal(new Uint8Array([1, 2, 3]));
2cccf753
SR
416 });
417 });
2cccf753
SR
418 });
419});