@webex/internal-plugin-mercury 3.9.0-multi-llms.4 → 3.9.0-multi-llms.5
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 +321 -131
- package/dist/mercury.js.map +1 -1
- package/dist/socket/socket-base.js +15 -0
- package/dist/socket/socket-base.js.map +1 -1
- package/package.json +5 -5
- package/src/mercury.js +279 -105
- package/src/socket/socket-base.js +13 -0
- package/test/unit/spec/mercury-events.js +20 -2
- package/test/unit/spec/mercury.js +53 -22
|
@@ -33,6 +33,8 @@ export default class Socket extends EventEmitter {
|
|
|
33
33
|
this._domain = 'unknown-domain';
|
|
34
34
|
this.onmessage = this.onmessage.bind(this);
|
|
35
35
|
this.onclose = this.onclose.bind(this);
|
|
36
|
+
// Increase max listeners to avoid memory leak warning in tests
|
|
37
|
+
this.setMaxListeners(5);
|
|
36
38
|
}
|
|
37
39
|
|
|
38
40
|
/**
|
|
@@ -358,9 +360,20 @@ export default class Socket extends EventEmitter {
|
|
|
358
360
|
return Promise.reject(new Error('`event.data.id` is required'));
|
|
359
361
|
}
|
|
360
362
|
|
|
363
|
+
// Don't try to acknowledge if socket is not in open state
|
|
364
|
+
if (this.readyState !== 1) {
|
|
365
|
+
return Promise.resolve(); // Silently ignore acknowledgment for closed sockets
|
|
366
|
+
}
|
|
367
|
+
|
|
361
368
|
return this.send({
|
|
362
369
|
messageId: event.data.id,
|
|
363
370
|
type: 'ack',
|
|
371
|
+
}).catch((error) => {
|
|
372
|
+
// Gracefully handle send errors (like INVALID_STATE_ERROR) to prevent test issues
|
|
373
|
+
if (error.message === 'INVALID_STATE_ERROR') {
|
|
374
|
+
return Promise.resolve(); // Socket was closed, ignore the acknowledgment
|
|
375
|
+
}
|
|
376
|
+
throw error; // Re-throw other errors
|
|
364
377
|
});
|
|
365
378
|
}
|
|
366
379
|
|
|
@@ -38,14 +38,31 @@ describe('plugin-mercury', () => {
|
|
|
38
38
|
},
|
|
39
39
|
timestamp: Date.now(),
|
|
40
40
|
trackingId: `suffix_${uuid.v4()}_${Date.now()}`,
|
|
41
|
+
sessionId: 'mercury-default-session',
|
|
41
42
|
};
|
|
42
43
|
|
|
43
44
|
beforeEach(() => {
|
|
44
45
|
clock = FakeTimers.install({now: Date.now()});
|
|
45
46
|
});
|
|
46
47
|
|
|
47
|
-
afterEach(() => {
|
|
48
|
+
afterEach(async () => {
|
|
48
49
|
clock.uninstall();
|
|
50
|
+
// Clean up mercury socket and mockWebSocket
|
|
51
|
+
if (mercury && mercury.socket) {
|
|
52
|
+
try {
|
|
53
|
+
await mercury.socket.close();
|
|
54
|
+
} catch (e) {}
|
|
55
|
+
}
|
|
56
|
+
if (mockWebSocket && typeof mockWebSocket.close === 'function') {
|
|
57
|
+
mockWebSocket.close();
|
|
58
|
+
}
|
|
59
|
+
// Restore stubs
|
|
60
|
+
if (Socket.getWebSocketConstructor.restore) {
|
|
61
|
+
Socket.getWebSocketConstructor.restore();
|
|
62
|
+
}
|
|
63
|
+
if (socketOpenStub && socketOpenStub.restore) {
|
|
64
|
+
socketOpenStub.restore();
|
|
65
|
+
}
|
|
49
66
|
});
|
|
50
67
|
|
|
51
68
|
beforeEach(() => {
|
|
@@ -76,6 +93,7 @@ describe('plugin-mercury', () => {
|
|
|
76
93
|
});
|
|
77
94
|
|
|
78
95
|
mercury = webex.internal.mercury;
|
|
96
|
+
mercury.defaultSessionId = 'mercury-default-session';
|
|
79
97
|
});
|
|
80
98
|
|
|
81
99
|
afterEach(() => {
|
|
@@ -301,7 +319,7 @@ describe('plugin-mercury', () => {
|
|
|
301
319
|
})
|
|
302
320
|
.then(() => {
|
|
303
321
|
assert.called(offlineSpy);
|
|
304
|
-
assert.calledWith(offlineSpy, {code, reason});
|
|
322
|
+
assert.calledWith(offlineSpy, {code, reason, sessionId: 'mercury-default-session'});
|
|
305
323
|
switch (action) {
|
|
306
324
|
case 'close':
|
|
307
325
|
assert.called(permanentSpy);
|
|
@@ -99,9 +99,32 @@ describe('plugin-mercury', () => {
|
|
|
99
99
|
});
|
|
100
100
|
|
|
101
101
|
mercury = webex.internal.mercury;
|
|
102
|
+
mercury.defaultSessionId = 'mercury-default-session';
|
|
102
103
|
});
|
|
103
104
|
|
|
104
|
-
afterEach(() => {
|
|
105
|
+
afterEach(async () => {
|
|
106
|
+
// Clean up Mercury connections and internal state
|
|
107
|
+
if (mercury) {
|
|
108
|
+
try {
|
|
109
|
+
await mercury.disconnectAll();
|
|
110
|
+
} catch (e) {
|
|
111
|
+
// Ignore cleanup errors
|
|
112
|
+
}
|
|
113
|
+
// Clear any remaining connection promises
|
|
114
|
+
if (mercury._connectPromises) {
|
|
115
|
+
mercury._connectPromises.clear();
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Ensure mock socket is properly closed
|
|
120
|
+
if (mockWebSocket && typeof mockWebSocket.close === 'function') {
|
|
121
|
+
try {
|
|
122
|
+
mockWebSocket.close();
|
|
123
|
+
} catch (e) {
|
|
124
|
+
// Ignore cleanup errors
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
105
128
|
if (socketOpenStub) {
|
|
106
129
|
socketOpenStub.restore();
|
|
107
130
|
}
|
|
@@ -109,6 +132,9 @@ describe('plugin-mercury', () => {
|
|
|
109
132
|
if (Socket.getWebSocketConstructor.restore) {
|
|
110
133
|
Socket.getWebSocketConstructor.restore();
|
|
111
134
|
}
|
|
135
|
+
|
|
136
|
+
// Small delay to ensure all async operations complete
|
|
137
|
+
await new Promise(resolve => setTimeout(resolve, 10));
|
|
112
138
|
});
|
|
113
139
|
|
|
114
140
|
describe('#listen()', () => {
|
|
@@ -498,9 +524,13 @@ describe('plugin-mercury', () => {
|
|
|
498
524
|
|
|
499
525
|
// skipping due to apparent bug with lolex in all browsers but Chrome.
|
|
500
526
|
skipInBrowser(it)('does not continue attempting to connect', () => {
|
|
501
|
-
mercury.connect();
|
|
527
|
+
const promise = mercury.connect();
|
|
528
|
+
|
|
529
|
+
// Wait for the connection to be established before proceeding
|
|
530
|
+
mockWebSocket.open();
|
|
502
531
|
|
|
503
|
-
return
|
|
532
|
+
return promise.then(() =>
|
|
533
|
+
promiseTick(2)
|
|
504
534
|
.then(() => {
|
|
505
535
|
clock.tick(6 * webex.internal.mercury.config.backoffTimeReset);
|
|
506
536
|
|
|
@@ -508,7 +538,8 @@ describe('plugin-mercury', () => {
|
|
|
508
538
|
})
|
|
509
539
|
.then(() => {
|
|
510
540
|
assert.calledOnce(Socket.prototype.open);
|
|
511
|
-
|
|
541
|
+
})
|
|
542
|
+
);
|
|
512
543
|
});
|
|
513
544
|
});
|
|
514
545
|
|
|
@@ -583,11 +614,11 @@ describe('plugin-mercury', () => {
|
|
|
583
614
|
});
|
|
584
615
|
|
|
585
616
|
describe('#logout()', () => {
|
|
586
|
-
it('calls
|
|
617
|
+
it('calls disconnectAll and logs', () => {
|
|
587
618
|
sinon.stub(mercury.logger, 'info');
|
|
588
|
-
sinon.stub(mercury, '
|
|
619
|
+
sinon.stub(mercury, 'disconnectAll');
|
|
589
620
|
mercury.logout();
|
|
590
|
-
assert.called(mercury.
|
|
621
|
+
assert.called(mercury.disconnectAll);
|
|
591
622
|
assert.calledTwice(mercury.logger.info);
|
|
592
623
|
|
|
593
624
|
assert.calledWith(mercury.logger.info.getCall(0), 'Mercury: logout() called');
|
|
@@ -599,24 +630,24 @@ describe('plugin-mercury', () => {
|
|
|
599
630
|
});
|
|
600
631
|
|
|
601
632
|
it('uses the config.beforeLogoutOptionsCloseReason to disconnect and will send code 3050 for logout', () => {
|
|
602
|
-
sinon.stub(mercury, '
|
|
633
|
+
sinon.stub(mercury, 'disconnectAll');
|
|
603
634
|
mercury.config.beforeLogoutOptionsCloseReason = 'done (permanent)';
|
|
604
635
|
mercury.logout();
|
|
605
|
-
assert.calledWith(mercury.
|
|
636
|
+
assert.calledWith(mercury.disconnectAll, {code: 3050, reason: 'done (permanent)'});
|
|
606
637
|
});
|
|
607
638
|
|
|
608
639
|
it('uses the config.beforeLogoutOptionsCloseReason to disconnect and will send code 3050 for logout if the reason is different than standard', () => {
|
|
609
|
-
sinon.stub(mercury, '
|
|
640
|
+
sinon.stub(mercury, 'disconnectAll');
|
|
610
641
|
mercury.config.beforeLogoutOptionsCloseReason = 'test';
|
|
611
642
|
mercury.logout();
|
|
612
|
-
assert.calledWith(mercury.
|
|
643
|
+
assert.calledWith(mercury.disconnectAll, {code: 3050, reason: 'test'});
|
|
613
644
|
});
|
|
614
645
|
|
|
615
646
|
it('uses the config.beforeLogoutOptionsCloseReason to disconnect and will send undefined for logout if the reason is same as standard', () => {
|
|
616
|
-
sinon.stub(mercury, '
|
|
647
|
+
sinon.stub(mercury, 'disconnectAll');
|
|
617
648
|
mercury.config.beforeLogoutOptionsCloseReason = 'done (forced)';
|
|
618
649
|
mercury.logout();
|
|
619
|
-
assert.calledWith(mercury.
|
|
650
|
+
assert.calledWith(mercury.disconnectAll, undefined);
|
|
620
651
|
});
|
|
621
652
|
});
|
|
622
653
|
|
|
@@ -722,12 +753,12 @@ describe('plugin-mercury', () => {
|
|
|
722
753
|
return promiseTick(webex.internal.mercury.config.backoffTimeReset).then(() => {
|
|
723
754
|
// By this time backoffCall and mercury socket should be defined by the
|
|
724
755
|
// 'connect' call
|
|
725
|
-
assert.isDefined(mercury.
|
|
756
|
+
assert.isDefined(mercury.backoffCalls.get('mercury-default-session'), 'Mercury backoffCall is not defined');
|
|
726
757
|
assert.isDefined(mercury.socket, 'Mercury socket is not defined');
|
|
727
758
|
// Calling disconnect will abort the backoffCall, close the socket, and
|
|
728
759
|
// reject the connect
|
|
729
760
|
mercury.disconnect();
|
|
730
|
-
assert.isUndefined(mercury.
|
|
761
|
+
assert.isUndefined(mercury.backoffCalls.get('mercury-default-session'), 'Mercury backoffCall is still defined');
|
|
731
762
|
// The socket will never be unset (which seems bad)
|
|
732
763
|
assert.isDefined(mercury.socket, 'Mercury socket is not defined');
|
|
733
764
|
|
|
@@ -745,15 +776,15 @@ describe('plugin-mercury', () => {
|
|
|
745
776
|
|
|
746
777
|
let reason;
|
|
747
778
|
|
|
748
|
-
mercury.
|
|
749
|
-
mercury._attemptConnection('ws://example.com', (_reason) => {
|
|
779
|
+
mercury.backoffCalls.clear();
|
|
780
|
+
mercury._attemptConnection('ws://example.com', 'mercury-default-session',(_reason) => {
|
|
750
781
|
reason = _reason;
|
|
751
782
|
});
|
|
752
783
|
|
|
753
784
|
return promiseTick(webex.internal.mercury.config.backoffTimeReset).then(() => {
|
|
754
785
|
assert.equal(
|
|
755
786
|
reason.message,
|
|
756
|
-
|
|
787
|
+
`Mercury: prevent socket open when backoffCall no longer defined for ${mercury.defaultSessionId}`
|
|
757
788
|
);
|
|
758
789
|
});
|
|
759
790
|
});
|
|
@@ -775,7 +806,7 @@ describe('plugin-mercury', () => {
|
|
|
775
806
|
return assert.isRejected(promise).then((error) => {
|
|
776
807
|
const lastError = mercury.getLastError();
|
|
777
808
|
|
|
778
|
-
assert.equal(error.message,
|
|
809
|
+
assert.equal(error.message, `Mercury Connection Aborted for ${mercury.defaultSessionId}`);
|
|
779
810
|
assert.isDefined(lastError);
|
|
780
811
|
assert.equal(lastError, realError);
|
|
781
812
|
});
|
|
@@ -869,7 +900,7 @@ describe('plugin-mercury', () => {
|
|
|
869
900
|
},
|
|
870
901
|
};
|
|
871
902
|
assert.isUndefined(mercury.mercuryTimeOffset);
|
|
872
|
-
mercury._setTimeOffset(event);
|
|
903
|
+
mercury._setTimeOffset('mercury-default-session', event);
|
|
873
904
|
assert.isDefined(mercury.mercuryTimeOffset);
|
|
874
905
|
assert.isTrue(mercury.mercuryTimeOffset > 0);
|
|
875
906
|
});
|
|
@@ -879,7 +910,7 @@ describe('plugin-mercury', () => {
|
|
|
879
910
|
wsWriteTimestamp: Date.now() + 60000,
|
|
880
911
|
},
|
|
881
912
|
};
|
|
882
|
-
mercury._setTimeOffset(event);
|
|
913
|
+
mercury._setTimeOffset('mercury-default-session', event);
|
|
883
914
|
assert.isTrue(mercury.mercuryTimeOffset < 0);
|
|
884
915
|
});
|
|
885
916
|
it('handles invalid wsWriteTimestamp', () => {
|
|
@@ -890,7 +921,7 @@ describe('plugin-mercury', () => {
|
|
|
890
921
|
wsWriteTimestamp: invalidTimestamp,
|
|
891
922
|
},
|
|
892
923
|
};
|
|
893
|
-
mercury._setTimeOffset(event);
|
|
924
|
+
mercury._setTimeOffset('mercury-default-session', event);
|
|
894
925
|
assert.isUndefined(mercury.mercuryTimeOffset);
|
|
895
926
|
});
|
|
896
927
|
});
|