@webex/internal-plugin-mercury 3.7.0 → 3.8.0-next.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/mercury.js +43 -16
- package/dist/mercury.js.map +1 -1
- package/dist/socket/socket-base.js +54 -16
- package/dist/socket/socket-base.js.map +1 -1
- package/package.json +17 -17
- package/src/mercury.js +46 -10
- package/src/socket/socket-base.js +40 -22
- package/test/unit/spec/mercury.js +93 -32
- package/test/unit/spec/socket.js +126 -11
|
@@ -143,9 +143,9 @@ describe('plugin-mercury', () => {
|
|
|
143
143
|
const envelope = {
|
|
144
144
|
data: {
|
|
145
145
|
featureToggle: {
|
|
146
|
-
'feature-name': true
|
|
147
|
-
}
|
|
148
|
-
}
|
|
146
|
+
'feature-name': true,
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
149
|
};
|
|
150
150
|
|
|
151
151
|
assert.isFalse(mercury.connected, 'Mercury is not connected');
|
|
@@ -157,7 +157,10 @@ describe('plugin-mercury', () => {
|
|
|
157
157
|
assert.isFalse(mercury.connecting, 'Mercury is not connecting');
|
|
158
158
|
assert.calledWith(socketOpenStub, sinon.match(/ws:\/\/example.com/), sinon.match.any);
|
|
159
159
|
mercury._emit('event:featureToggle_update', envelope);
|
|
160
|
-
assert.calledOnceWithExactly(
|
|
160
|
+
assert.calledOnceWithExactly(
|
|
161
|
+
webex.internal.feature.updateFeature,
|
|
162
|
+
envelope.data.featureToggle
|
|
163
|
+
);
|
|
161
164
|
sinon.restore();
|
|
162
165
|
});
|
|
163
166
|
});
|
|
@@ -175,7 +178,6 @@ describe('plugin-mercury', () => {
|
|
|
175
178
|
});
|
|
176
179
|
|
|
177
180
|
describe('when `maxRetries` is set', () => {
|
|
178
|
-
|
|
179
181
|
const check = () => {
|
|
180
182
|
socketOpenStub.restore();
|
|
181
183
|
socketOpenStub = sinon.stub(Socket.prototype, 'open');
|
|
@@ -209,7 +211,7 @@ describe('plugin-mercury', () => {
|
|
|
209
211
|
.then(() => {
|
|
210
212
|
assert.calledThrice(Socket.prototype.open);
|
|
211
213
|
});
|
|
212
|
-
}
|
|
214
|
+
};
|
|
213
215
|
|
|
214
216
|
// skipping due to apparent bug with lolex in all browsers but Chrome.
|
|
215
217
|
// if initial retries is zero and mercury has never connected max retries is used
|
|
@@ -504,24 +506,33 @@ describe('plugin-mercury', () => {
|
|
|
504
506
|
});
|
|
505
507
|
|
|
506
508
|
describe('#logout()', () => {
|
|
507
|
-
it('calls disconnect', () => {
|
|
509
|
+
it('calls disconnect and logs', () => {
|
|
510
|
+
sinon.stub(mercury.logger, 'info');
|
|
508
511
|
sinon.stub(mercury, 'disconnect');
|
|
509
512
|
mercury.logout();
|
|
510
513
|
assert.called(mercury.disconnect);
|
|
514
|
+
assert.calledTwice(mercury.logger.info);
|
|
515
|
+
|
|
516
|
+
assert.calledWith(mercury.logger.info.getCall(0), 'Mercury: logout() called');
|
|
517
|
+
assert.isTrue(
|
|
518
|
+
mercury.logger.info
|
|
519
|
+
.getCall(1)
|
|
520
|
+
.args[0].startsWith('Mercury: debug_mercury_logging stack: ')
|
|
521
|
+
);
|
|
511
522
|
});
|
|
512
523
|
|
|
513
|
-
it('uses the config.beforeLogoutOptionsCloseReason to disconnect and will send code
|
|
524
|
+
it('uses the config.beforeLogoutOptionsCloseReason to disconnect and will send code 3050 for logout', () => {
|
|
514
525
|
sinon.stub(mercury, 'disconnect');
|
|
515
526
|
mercury.config.beforeLogoutOptionsCloseReason = 'done (permanent)';
|
|
516
527
|
mercury.logout();
|
|
517
|
-
assert.calledWith(mercury.disconnect, {code:
|
|
528
|
+
assert.calledWith(mercury.disconnect, {code: 3050, reason: 'done (permanent)'});
|
|
518
529
|
});
|
|
519
530
|
|
|
520
|
-
it('uses the config.beforeLogoutOptionsCloseReason to disconnect and will send code
|
|
531
|
+
it('uses the config.beforeLogoutOptionsCloseReason to disconnect and will send code 3050 for logout if the reason is different than standard', () => {
|
|
521
532
|
sinon.stub(mercury, 'disconnect');
|
|
522
533
|
mercury.config.beforeLogoutOptionsCloseReason = 'test';
|
|
523
534
|
mercury.logout();
|
|
524
|
-
assert.calledWith(mercury.disconnect, {code:
|
|
535
|
+
assert.calledWith(mercury.disconnect, {code: 3050, reason: 'test'});
|
|
525
536
|
});
|
|
526
537
|
|
|
527
538
|
it('uses the config.beforeLogoutOptionsCloseReason to disconnect and will send undefined for logout if the reason is same as standard', () => {
|
|
@@ -554,26 +565,26 @@ describe('plugin-mercury', () => {
|
|
|
554
565
|
assert.isUndefined(mercury.mockWebSocket, 'Mercury does not have a mockWebSocket');
|
|
555
566
|
}));
|
|
556
567
|
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
568
|
+
it('disconnects the WebSocket with code 3050', () =>
|
|
569
|
+
mercury
|
|
570
|
+
.connect()
|
|
571
|
+
.then(() => {
|
|
572
|
+
assert.isTrue(mercury.connected, 'Mercury is connected');
|
|
573
|
+
assert.isFalse(mercury.connecting, 'Mercury is not connecting');
|
|
574
|
+
const promise = mercury.disconnect();
|
|
575
|
+
|
|
576
|
+
mockWebSocket.emit('close', {
|
|
577
|
+
code: 3050,
|
|
578
|
+
reason: 'done (permanent)',
|
|
579
|
+
});
|
|
580
|
+
|
|
581
|
+
return promise;
|
|
582
|
+
})
|
|
583
|
+
.then(() => {
|
|
584
|
+
assert.isFalse(mercury.connected, 'Mercury is not connected');
|
|
585
|
+
assert.isFalse(mercury.connecting, 'Mercury is not connecting');
|
|
586
|
+
assert.isUndefined(mercury.mockWebSocket, 'Mercury does not have a mockWebSocket');
|
|
587
|
+
}));
|
|
577
588
|
|
|
578
589
|
it('stops emitting message events', () => {
|
|
579
590
|
const spy = sinon.spy();
|
|
@@ -687,7 +698,7 @@ describe('plugin-mercury', () => {
|
|
|
687
698
|
return assert.isRejected(promise).then((error) => {
|
|
688
699
|
const lastError = mercury.getLastError();
|
|
689
700
|
|
|
690
|
-
assert.equal(error.message,
|
|
701
|
+
assert.equal(error.message, 'Mercury Connection Aborted');
|
|
691
702
|
assert.isDefined(lastError);
|
|
692
703
|
assert.equal(lastError, realError);
|
|
693
704
|
});
|
|
@@ -716,6 +727,21 @@ describe('plugin-mercury', () => {
|
|
|
716
727
|
return res;
|
|
717
728
|
});
|
|
718
729
|
});
|
|
730
|
+
|
|
731
|
+
it('_onmessage without eventType', () => {
|
|
732
|
+
sinon.spy(mercury, '_getEventHandlers');
|
|
733
|
+
sinon.spy(mercury, '_emit');
|
|
734
|
+
const event = {data: {data: {eventType: undefined, mydata: 'some data'}}};
|
|
735
|
+
mercury.logger.error.restore();
|
|
736
|
+
sinon.stub(mercury.logger, 'error');
|
|
737
|
+
return Promise.resolve(mercury._onmessage(event)).then(() => {
|
|
738
|
+
assert.calledWith(mercury._getEventHandlers, undefined);
|
|
739
|
+
assert.calledWith(mercury._emit, 'event', event.data);
|
|
740
|
+
assert.notCalled(mercury.logger.error);
|
|
741
|
+
mercury._emit.restore();
|
|
742
|
+
mercury._getEventHandlers.restore();
|
|
743
|
+
});
|
|
744
|
+
});
|
|
719
745
|
});
|
|
720
746
|
|
|
721
747
|
describe('#_applyOverrides()', () => {
|
|
@@ -773,6 +799,41 @@ describe('plugin-mercury', () => {
|
|
|
773
799
|
});
|
|
774
800
|
});
|
|
775
801
|
|
|
802
|
+
describe('#_setTimeOffset', () => {
|
|
803
|
+
it('sets mercuryTimeOffset based on the difference between wsWriteTimestamp and now', () => {
|
|
804
|
+
const event = {
|
|
805
|
+
data: {
|
|
806
|
+
wsWriteTimestamp: Date.now() - 60000,
|
|
807
|
+
},
|
|
808
|
+
};
|
|
809
|
+
assert.isUndefined(mercury.mercuryTimeOffset);
|
|
810
|
+
mercury._setTimeOffset(event);
|
|
811
|
+
assert.isDefined(mercury.mercuryTimeOffset);
|
|
812
|
+
assert.isTrue(mercury.mercuryTimeOffset > 0);
|
|
813
|
+
});
|
|
814
|
+
it('handles negative offsets', () => {
|
|
815
|
+
const event = {
|
|
816
|
+
data: {
|
|
817
|
+
wsWriteTimestamp: Date.now() + 60000,
|
|
818
|
+
},
|
|
819
|
+
};
|
|
820
|
+
mercury._setTimeOffset(event);
|
|
821
|
+
assert.isTrue(mercury.mercuryTimeOffset < 0);
|
|
822
|
+
});
|
|
823
|
+
it('handles invalid wsWriteTimestamp', () => {
|
|
824
|
+
const invalidTimestamps = [null, -1, 'invalid', undefined];
|
|
825
|
+
invalidTimestamps.forEach((invalidTimestamp) => {
|
|
826
|
+
const event = {
|
|
827
|
+
data: {
|
|
828
|
+
wsWriteTimestamp: invalidTimestamp,
|
|
829
|
+
},
|
|
830
|
+
};
|
|
831
|
+
mercury._setTimeOffset(event);
|
|
832
|
+
assert.isUndefined(mercury.mercuryTimeOffset);
|
|
833
|
+
});
|
|
834
|
+
});
|
|
835
|
+
});
|
|
836
|
+
|
|
776
837
|
describe('#_prepareUrl()', () => {
|
|
777
838
|
beforeEach(() => {
|
|
778
839
|
webex.internal.device.webSocketUrl = 'ws://example.com';
|
package/test/unit/spec/socket.js
CHANGED
|
@@ -139,6 +139,7 @@ describe('plugin-mercury', () => {
|
|
|
139
139
|
));
|
|
140
140
|
|
|
141
141
|
it('accepts a logLevelToken option', () => {
|
|
142
|
+
const acknowledgeSpy = sinon.spy(socket, '_acknowledge');
|
|
142
143
|
const promise = socket.open('ws://example.com', {
|
|
143
144
|
forceCloseDelay: mockoptions.forceCloseDelay,
|
|
144
145
|
pingInterval: mockoptions.pingInterval,
|
|
@@ -147,6 +148,7 @@ describe('plugin-mercury', () => {
|
|
|
147
148
|
token: 'mocktoken',
|
|
148
149
|
trackingId: 'mocktrackingid',
|
|
149
150
|
logLevelToken: 'mocklogleveltoken',
|
|
151
|
+
acknowledgementRequired: true,
|
|
150
152
|
});
|
|
151
153
|
|
|
152
154
|
mockWebSocket.readyState = 1;
|
|
@@ -162,9 +164,83 @@ describe('plugin-mercury', () => {
|
|
|
162
164
|
});
|
|
163
165
|
|
|
164
166
|
return promise.then(() => {
|
|
167
|
+
assert.called(acknowledgeSpy);
|
|
165
168
|
assert.equal(socket.logLevelToken, 'mocklogleveltoken');
|
|
166
169
|
});
|
|
167
170
|
});
|
|
171
|
+
|
|
172
|
+
it('accepts acknowledgementRequired option as false and skip acknowledge', () => {
|
|
173
|
+
const acknowledgeSpy = sinon.spy(socket, '_acknowledge');
|
|
174
|
+
const promise = socket.open('ws://example.com', {
|
|
175
|
+
forceCloseDelay: mockoptions.forceCloseDelay,
|
|
176
|
+
pingInterval: mockoptions.pingInterval,
|
|
177
|
+
pongTimeout: mockoptions.pongTimeout,
|
|
178
|
+
logger: console,
|
|
179
|
+
token: 'mocktoken',
|
|
180
|
+
trackingId: 'mocktrackingid',
|
|
181
|
+
logLevelToken: 'mocklogleveltoken',
|
|
182
|
+
acknowledgementRequired: false,
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
mockWebSocket.readyState = 1;
|
|
186
|
+
mockWebSocket.emit('open');
|
|
187
|
+
|
|
188
|
+
mockWebSocket.emit('message', {
|
|
189
|
+
data: JSON.stringify({
|
|
190
|
+
id: uuid.v4(),
|
|
191
|
+
data: {
|
|
192
|
+
eventType: 'mercury.buffer_state',
|
|
193
|
+
},
|
|
194
|
+
}),
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
return promise.then(() => {
|
|
198
|
+
assert.notCalled(acknowledgeSpy);
|
|
199
|
+
assert.equal(socket.logLevelToken, 'mocklogleveltoken');
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it('accepts authorizationRequired option as false and skip authorize', () => {
|
|
204
|
+
const s = new Socket();
|
|
205
|
+
const authorizeSpy = sinon.spy(socket, '_authorize');
|
|
206
|
+
socket.open('ws://example.com', {
|
|
207
|
+
forceCloseDelay: mockoptions.forceCloseDelay,
|
|
208
|
+
pingInterval: mockoptions.pingInterval,
|
|
209
|
+
pongTimeout: mockoptions.pongTimeout,
|
|
210
|
+
logger: console,
|
|
211
|
+
token: 'mocktoken',
|
|
212
|
+
trackingId: 'mocktrackingid',
|
|
213
|
+
logLevelToken: 'mocklogleveltoken',
|
|
214
|
+
authorizationRequired: false,
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
mockWebSocket.readyState = 1;
|
|
218
|
+
mockWebSocket.emit('open');
|
|
219
|
+
|
|
220
|
+
assert.notCalled(authorizeSpy);
|
|
221
|
+
assert.called(socket._ping);
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
it('accepts authorizationRequired option as true and calles authorize', () => {
|
|
225
|
+
const s = new Socket();
|
|
226
|
+
const authorizeSpy = sinon.spy(socket, '_authorize');
|
|
227
|
+
socket.open('ws://example.com', {
|
|
228
|
+
forceCloseDelay: mockoptions.forceCloseDelay,
|
|
229
|
+
pingInterval: mockoptions.pingInterval,
|
|
230
|
+
pongTimeout: mockoptions.pongTimeout,
|
|
231
|
+
logger: console,
|
|
232
|
+
token: 'mocktoken',
|
|
233
|
+
trackingId: 'mocktrackingid',
|
|
234
|
+
logLevelToken: 'mocklogleveltoken',
|
|
235
|
+
authorizationRequired: true,
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
mockWebSocket.readyState = 1;
|
|
239
|
+
mockWebSocket.emit('open');
|
|
240
|
+
|
|
241
|
+
assert.called(authorizeSpy);
|
|
242
|
+
assert.called(socket._ping);
|
|
243
|
+
});
|
|
168
244
|
});
|
|
169
245
|
|
|
170
246
|
describe('#binaryType', () => {
|
|
@@ -452,7 +528,7 @@ describe('plugin-mercury', () => {
|
|
|
452
528
|
Promise.all([
|
|
453
529
|
assert.isRejected(
|
|
454
530
|
socket.close({code: 1001}),
|
|
455
|
-
/`options.code` must be 1000 or
|
|
531
|
+
/`options.code` must be 1000 or between 3000 and 4999 \(inclusive\)/
|
|
456
532
|
),
|
|
457
533
|
socket.close({code: 1000}),
|
|
458
534
|
]));
|
|
@@ -468,10 +544,10 @@ describe('plugin-mercury', () => {
|
|
|
468
544
|
it('accepts the logout reason', () =>
|
|
469
545
|
socket
|
|
470
546
|
.close({
|
|
471
|
-
code:
|
|
547
|
+
code: 3050,
|
|
472
548
|
reason: 'done (permanent)',
|
|
473
549
|
})
|
|
474
|
-
.then(() => assert.calledWith(mockWebSocket.close,
|
|
550
|
+
.then(() => assert.calledWith(mockWebSocket.close, 3050, 'done (permanent)')));
|
|
475
551
|
|
|
476
552
|
it('can safely be called called multiple times', () => {
|
|
477
553
|
const p1 = socket.close();
|
|
@@ -521,7 +597,7 @@ describe('plugin-mercury', () => {
|
|
|
521
597
|
});
|
|
522
598
|
});
|
|
523
599
|
|
|
524
|
-
it('signals closure if no close frame is received within the specified window, but uses the initial options as
|
|
600
|
+
it('signals closure if no close frame is received within the specified window, but uses the initial options as 3050 if specified by options call', () => {
|
|
525
601
|
const socket = new Socket();
|
|
526
602
|
const promise = socket.open('ws://example.com', mockoptions);
|
|
527
603
|
|
|
@@ -546,21 +622,21 @@ describe('plugin-mercury', () => {
|
|
|
546
622
|
});
|
|
547
623
|
mockWebSocket.removeAllListeners('close');
|
|
548
624
|
|
|
549
|
-
const promise = socket.close({code:
|
|
625
|
+
const promise = socket.close({code: 3050, reason: 'done (permanent)'});
|
|
550
626
|
|
|
551
627
|
clock.tick(mockoptions.forceCloseDelay);
|
|
552
628
|
|
|
553
629
|
return promise.then(() => {
|
|
554
630
|
assert.called(spy);
|
|
555
631
|
assert.calledWith(spy, {
|
|
556
|
-
code:
|
|
632
|
+
code: 3050,
|
|
557
633
|
reason: 'done (permanent)',
|
|
558
634
|
});
|
|
559
635
|
});
|
|
560
636
|
});
|
|
561
637
|
});
|
|
562
638
|
|
|
563
|
-
it('signals closure if no close frame is received within the specified window, and uses default options as 1000 if the code is not
|
|
639
|
+
it('signals closure if no close frame is received within the specified window, and uses default options as 1000 if the code is not 3050', () => {
|
|
564
640
|
const socket = new Socket();
|
|
565
641
|
const promise = socket.open('ws://example.com', mockoptions);
|
|
566
642
|
|
|
@@ -593,7 +669,46 @@ describe('plugin-mercury', () => {
|
|
|
593
669
|
assert.called(spy);
|
|
594
670
|
assert.calledWith(spy, {
|
|
595
671
|
code: 1000,
|
|
596
|
-
reason: '
|
|
672
|
+
reason: 'test',
|
|
673
|
+
});
|
|
674
|
+
});
|
|
675
|
+
});
|
|
676
|
+
});
|
|
677
|
+
|
|
678
|
+
it('signals closure if no close frame is received within the specified window, and uses default options as 1000 if the code is not 3050', () => {
|
|
679
|
+
const socket = new Socket();
|
|
680
|
+
const promise = socket.open('ws://example.com', mockoptions);
|
|
681
|
+
|
|
682
|
+
mockWebSocket.readyState = 1;
|
|
683
|
+
mockWebSocket.emit('open');
|
|
684
|
+
mockWebSocket.emit('message', {
|
|
685
|
+
data: JSON.stringify({
|
|
686
|
+
id: uuid.v4(),
|
|
687
|
+
data: {
|
|
688
|
+
eventType: 'mercury.buffer_state',
|
|
689
|
+
},
|
|
690
|
+
}),
|
|
691
|
+
});
|
|
692
|
+
|
|
693
|
+
return promise.then(() => {
|
|
694
|
+
const spy = sinon.spy();
|
|
695
|
+
|
|
696
|
+
socket.on('close', spy);
|
|
697
|
+
mockWebSocket.close = () =>
|
|
698
|
+
new Promise(() => {
|
|
699
|
+
/* eslint no-inline-comments: [0] */
|
|
700
|
+
});
|
|
701
|
+
mockWebSocket.removeAllListeners('close');
|
|
702
|
+
|
|
703
|
+
const promise = socket.close({code: 1000});
|
|
704
|
+
|
|
705
|
+
clock.tick(mockoptions.forceCloseDelay);
|
|
706
|
+
|
|
707
|
+
return promise.then(() => {
|
|
708
|
+
assert.called(spy);
|
|
709
|
+
assert.calledWith(spy, {
|
|
710
|
+
code: 1000,
|
|
711
|
+
reason: 'Done (unknown)',
|
|
597
712
|
});
|
|
598
713
|
});
|
|
599
714
|
});
|
|
@@ -705,9 +820,9 @@ describe('plugin-mercury', () => {
|
|
|
705
820
|
);
|
|
706
821
|
});
|
|
707
822
|
|
|
708
|
-
describe('when it receives close code
|
|
709
|
-
it(`emits code
|
|
710
|
-
const code =
|
|
823
|
+
describe('when it receives close code 3050', () => {
|
|
824
|
+
it(`emits code 3050 for code 3050`, () => {
|
|
825
|
+
const code = 3050;
|
|
711
826
|
const reason = 'done (permanent)';
|
|
712
827
|
const spy = sinon.spy();
|
|
713
828
|
|