@webex/plugin-meetings 3.0.0-stream-classes.4 → 3.0.0-test.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/README.md +12 -0
- package/dist/breakouts/breakout.js +1 -1
- package/dist/breakouts/index.js +1 -1
- package/dist/common/errors/no-meeting-info.js +51 -0
- package/dist/common/errors/no-meeting-info.js.map +1 -0
- package/dist/common/errors/reclaim-host-role-errors.js +158 -0
- package/dist/common/errors/reclaim-host-role-errors.js.map +1 -0
- package/dist/common/errors/webex-errors.js +23 -3
- package/dist/common/errors/webex-errors.js.map +1 -1
- package/dist/common/logs/request.js +5 -1
- package/dist/common/logs/request.js.map +1 -1
- package/dist/config.js +1 -1
- package/dist/config.js.map +1 -1
- package/dist/constants.js +69 -9
- package/dist/constants.js.map +1 -1
- package/dist/index.js +11 -1
- package/dist/index.js.map +1 -1
- package/dist/interceptors/index.js +15 -0
- package/dist/interceptors/index.js.map +1 -0
- package/dist/interceptors/locusRetry.js +93 -0
- package/dist/interceptors/locusRetry.js.map +1 -0
- package/dist/interpretation/index.js +16 -2
- package/dist/interpretation/index.js.map +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/locus-info/index.js +40 -11
- package/dist/locus-info/index.js.map +1 -1
- package/dist/locus-info/mediaSharesUtils.js +15 -1
- package/dist/locus-info/mediaSharesUtils.js.map +1 -1
- package/dist/locus-info/parser.js +42 -21
- package/dist/locus-info/parser.js.map +1 -1
- package/dist/media/index.js +10 -6
- package/dist/media/index.js.map +1 -1
- package/dist/media/properties.js +13 -3
- package/dist/media/properties.js.map +1 -1
- package/dist/mediaQualityMetrics/config.js +135 -330
- package/dist/mediaQualityMetrics/config.js.map +1 -1
- package/dist/meeting/in-meeting-actions.js +4 -0
- package/dist/meeting/in-meeting-actions.js.map +1 -1
- package/dist/meeting/index.js +2187 -1074
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/muteState.js +37 -25
- package/dist/meeting/muteState.js.map +1 -1
- package/dist/meeting/request.js +34 -19
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting/util.js +71 -0
- package/dist/meeting/util.js.map +1 -1
- package/dist/meeting-info/index.js +48 -23
- package/dist/meeting-info/index.js.map +1 -1
- package/dist/meeting-info/meeting-info-v2.js +25 -4
- package/dist/meeting-info/meeting-info-v2.js.map +1 -1
- package/dist/meeting-info/utilv2.js +1 -1
- package/dist/meeting-info/utilv2.js.map +1 -1
- package/dist/meetings/collection.js +17 -0
- package/dist/meetings/collection.js.map +1 -1
- package/dist/meetings/index.js +142 -57
- package/dist/meetings/index.js.map +1 -1
- package/dist/meetings/util.js +2 -6
- package/dist/meetings/util.js.map +1 -1
- package/dist/member/index.js +9 -0
- package/dist/member/index.js.map +1 -1
- package/dist/member/util.js +11 -0
- package/dist/member/util.js.map +1 -1
- package/dist/members/index.js +17 -1
- package/dist/members/index.js.map +1 -1
- package/dist/members/types.js.map +1 -1
- package/dist/members/util.js +15 -4
- package/dist/members/util.js.map +1 -1
- package/dist/metrics/constants.js +15 -1
- package/dist/metrics/constants.js.map +1 -1
- package/dist/multistream/mediaRequestManager.js +1 -1
- package/dist/multistream/mediaRequestManager.js.map +1 -1
- package/dist/multistream/remoteMediaGroup.js +16 -2
- package/dist/multistream/remoteMediaGroup.js.map +1 -1
- package/dist/multistream/remoteMediaManager.js +222 -73
- package/dist/multistream/remoteMediaManager.js.map +1 -1
- package/dist/multistream/sendSlotManager.js +22 -0
- package/dist/multistream/sendSlotManager.js.map +1 -1
- package/dist/reachability/clusterReachability.js +356 -0
- package/dist/reachability/clusterReachability.js.map +1 -0
- package/dist/reachability/index.js +262 -432
- package/dist/reachability/index.js.map +1 -1
- package/dist/reachability/request.js +1 -1
- package/dist/reachability/request.js.map +1 -1
- package/dist/reachability/util.js +29 -0
- package/dist/reachability/util.js.map +1 -0
- package/dist/reconnection-manager/index.js +113 -96
- package/dist/reconnection-manager/index.js.map +1 -1
- package/dist/roap/index.js +57 -25
- package/dist/roap/index.js.map +1 -1
- package/dist/roap/request.js +5 -13
- package/dist/roap/request.js.map +1 -1
- package/dist/roap/turnDiscovery.js +173 -81
- package/dist/roap/turnDiscovery.js.map +1 -1
- package/dist/rtcMetrics/index.js +68 -6
- package/dist/rtcMetrics/index.js.map +1 -1
- package/dist/statsAnalyzer/index.js +338 -289
- package/dist/statsAnalyzer/index.js.map +1 -1
- package/dist/statsAnalyzer/mqaUtil.js +296 -156
- package/dist/statsAnalyzer/mqaUtil.js.map +1 -1
- package/dist/types/common/errors/no-meeting-info.d.ts +14 -0
- package/dist/types/common/errors/reclaim-host-role-errors.d.ts +60 -0
- package/dist/types/common/errors/webex-errors.d.ts +13 -1
- package/dist/types/common/logs/request.d.ts +2 -0
- package/dist/types/config.d.ts +1 -1
- package/dist/types/constants.d.ts +66 -13
- package/dist/types/index.d.ts +1 -1
- package/dist/types/interceptors/index.d.ts +2 -0
- package/dist/types/interceptors/locusRetry.d.ts +27 -0
- package/dist/types/locus-info/index.d.ts +1 -1
- package/dist/types/locus-info/parser.d.ts +3 -2
- package/dist/types/mediaQualityMetrics/config.d.ts +99 -223
- package/dist/types/meeting/in-meeting-actions.d.ts +4 -0
- package/dist/types/meeting/index.d.ts +285 -34
- package/dist/types/meeting/locusMediaRequest.d.ts +1 -2
- package/dist/types/meeting/muteState.d.ts +2 -8
- package/dist/types/meeting/request.d.ts +4 -1
- package/dist/types/meeting/util.d.ts +25 -1
- package/dist/types/meeting-info/index.d.ts +7 -0
- package/dist/types/meeting-info/meeting-info-v2.d.ts +1 -0
- package/dist/types/meetings/collection.d.ts +9 -0
- package/dist/types/meetings/index.d.ts +42 -14
- package/dist/types/member/index.d.ts +1 -0
- package/dist/types/members/types.d.ts +1 -0
- package/dist/types/members/util.d.ts +5 -0
- package/dist/types/metrics/constants.d.ts +15 -0
- package/dist/types/multistream/mediaRequestManager.d.ts +2 -0
- package/dist/types/multistream/remoteMediaGroup.d.ts +2 -0
- package/dist/types/multistream/remoteMediaManager.d.ts +25 -1
- package/dist/types/multistream/sendSlotManager.d.ts +9 -0
- package/dist/types/reachability/clusterReachability.d.ts +109 -0
- package/dist/types/reachability/index.d.ts +59 -112
- package/dist/types/reachability/request.d.ts +1 -1
- package/dist/types/reachability/util.d.ts +8 -0
- package/dist/types/reconnection-manager/index.d.ts +10 -0
- package/dist/types/roap/index.d.ts +2 -1
- package/dist/types/roap/request.d.ts +2 -1
- package/dist/types/roap/turnDiscovery.d.ts +21 -4
- package/dist/types/rtcMetrics/index.d.ts +15 -1
- package/dist/types/statsAnalyzer/index.d.ts +28 -11
- package/dist/types/statsAnalyzer/mqaUtil.d.ts +28 -4
- package/dist/types/webinar/collection.d.ts +16 -0
- package/dist/types/webinar/index.d.ts +5 -0
- package/dist/webinar/collection.js +44 -0
- package/dist/webinar/collection.js.map +1 -0
- package/dist/webinar/index.js +69 -0
- package/dist/webinar/index.js.map +1 -0
- package/package.json +3 -2
- package/src/common/errors/no-meeting-info.ts +24 -0
- package/src/common/errors/reclaim-host-role-errors.ts +134 -0
- package/src/common/errors/webex-errors.ts +19 -2
- package/src/common/logs/request.ts +5 -1
- package/src/config.ts +1 -1
- package/src/constants.ts +71 -6
- package/src/index.ts +5 -0
- package/src/interceptors/index.ts +3 -0
- package/src/interceptors/locusRetry.ts +67 -0
- package/src/interpretation/index.ts +18 -1
- package/src/locus-info/index.ts +52 -16
- package/src/locus-info/mediaSharesUtils.ts +16 -0
- package/src/locus-info/parser.ts +47 -21
- package/src/media/index.ts +8 -6
- package/src/media/properties.ts +17 -2
- package/src/mediaQualityMetrics/config.ts +103 -238
- package/src/meeting/in-meeting-actions.ts +8 -0
- package/src/meeting/index.ts +1510 -529
- package/src/meeting/muteState.ts +34 -20
- package/src/meeting/request.ts +19 -1
- package/src/meeting/util.ts +97 -0
- package/src/meeting-info/index.ts +47 -20
- package/src/meeting-info/meeting-info-v2.ts +27 -5
- package/src/meeting-info/utilv2.ts +1 -1
- package/src/meetings/collection.ts +13 -0
- package/src/meetings/index.ts +112 -31
- package/src/meetings/util.ts +2 -8
- package/src/member/index.ts +9 -0
- package/src/member/util.ts +14 -0
- package/src/members/index.ts +29 -2
- package/src/members/types.ts +1 -0
- package/src/members/util.ts +15 -1
- package/src/metrics/constants.ts +14 -0
- package/src/multistream/mediaRequestManager.ts +4 -1
- package/src/multistream/remoteMediaGroup.ts +19 -0
- package/src/multistream/remoteMediaManager.ts +141 -18
- package/src/multistream/sendSlotManager.ts +29 -0
- package/src/reachability/clusterReachability.ts +320 -0
- package/src/reachability/index.ts +221 -382
- package/src/reachability/request.ts +1 -1
- package/src/reachability/util.ts +24 -0
- package/src/reconnection-manager/index.ts +87 -83
- package/src/roap/index.ts +60 -24
- package/src/roap/request.ts +3 -16
- package/src/roap/turnDiscovery.ts +112 -39
- package/src/rtcMetrics/index.ts +71 -5
- package/src/statsAnalyzer/index.ts +430 -427
- package/src/statsAnalyzer/mqaUtil.ts +317 -168
- package/src/webinar/collection.ts +31 -0
- package/src/webinar/index.ts +62 -0
- package/test/integration/spec/converged-space-meetings.js +7 -7
- package/test/integration/spec/journey.js +86 -104
- package/test/integration/spec/space-meeting.js +9 -9
- package/test/unit/spec/interceptors/locusRetry.ts +131 -0
- package/test/unit/spec/interpretation/index.ts +36 -3
- package/test/unit/spec/locus-info/index.js +205 -12
- package/test/unit/spec/locus-info/lib/SeqCmp.json +16 -0
- package/test/unit/spec/locus-info/mediaSharesUtils.ts +10 -0
- package/test/unit/spec/locus-info/parser.js +54 -13
- package/test/unit/spec/media/index.ts +20 -4
- package/test/unit/spec/media/properties.ts +2 -2
- package/test/unit/spec/meeting/in-meeting-actions.ts +4 -0
- package/test/unit/spec/meeting/index.js +4027 -1075
- package/test/unit/spec/meeting/muteState.js +219 -67
- package/test/unit/spec/meeting/request.js +63 -12
- package/test/unit/spec/meeting/utils.js +93 -0
- package/test/unit/spec/meeting-info/index.js +180 -61
- package/test/unit/spec/meeting-info/meetinginfov2.js +196 -53
- package/test/unit/spec/meetings/collection.js +12 -0
- package/test/unit/spec/meetings/index.js +619 -206
- package/test/unit/spec/meetings/utils.js +35 -12
- package/test/unit/spec/member/index.js +8 -7
- package/test/unit/spec/member/util.js +32 -0
- package/test/unit/spec/members/index.js +130 -17
- package/test/unit/spec/members/utils.js +26 -0
- package/test/unit/spec/multistream/mediaRequestManager.ts +20 -2
- package/test/unit/spec/multistream/remoteMediaGroup.ts +80 -1
- package/test/unit/spec/multistream/remoteMediaManager.ts +210 -3
- package/test/unit/spec/multistream/sendSlotManager.ts +50 -18
- package/test/unit/spec/reachability/clusterReachability.ts +279 -0
- package/test/unit/spec/reachability/index.ts +505 -135
- package/test/unit/spec/reachability/util.ts +40 -0
- package/test/unit/spec/reconnection-manager/index.js +74 -17
- package/test/unit/spec/roap/index.ts +181 -61
- package/test/unit/spec/roap/request.ts +27 -3
- package/test/unit/spec/roap/turnDiscovery.ts +362 -101
- package/test/unit/spec/rtcMetrics/index.ts +57 -3
- package/test/unit/spec/stats-analyzer/index.js +1225 -12
- package/test/unit/spec/webinar/collection.ts +13 -0
- package/test/unit/spec/webinar/index.ts +60 -0
- package/test/utils/integrationTestUtils.js +4 -4
- package/test/utils/webex-test-users.js +12 -4
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import {assert} from '@webex/test-helper-chai';
|
|
2
|
+
|
|
3
|
+
import {convertStunUrlToTurn} from '@webex/plugin-meetings/src/reachability/util';
|
|
4
|
+
|
|
5
|
+
describe('plugin-meetings/src/reachability/util', () => {
|
|
6
|
+
describe('#convertStunUrlToTurn()', () => {
|
|
7
|
+
[
|
|
8
|
+
{
|
|
9
|
+
title: 'a stun url with port',
|
|
10
|
+
stunUrl: 'stun:external-media91.public.wjfkm-a-10.prod.infra.webex.com:5004',
|
|
11
|
+
expectedUrlPart: 'external-media91.public.wjfkm-a-10.prod.infra.webex.com:5004',
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
title: 'a stun url without port',
|
|
15
|
+
stunUrl: 'stun:something.somewhere.com',
|
|
16
|
+
expectedUrlPart: 'something.somewhere.com',
|
|
17
|
+
},
|
|
18
|
+
].forEach(({title, stunUrl, expectedUrlPart}) => {
|
|
19
|
+
it(`should convert ${title} to a TCP turn url`, () => {
|
|
20
|
+
const turnUrl = convertStunUrlToTurn(stunUrl, 'tcp');
|
|
21
|
+
|
|
22
|
+
assert.equal(turnUrl, `turn:${expectedUrlPart}?transport=tcp`);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it(`should convert ${title} to a UDP turn url`, () => {
|
|
26
|
+
const turnUrl = convertStunUrlToTurn(stunUrl, 'udp');
|
|
27
|
+
|
|
28
|
+
assert.equal(turnUrl, `turn:${expectedUrlPart}`);
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('show fail if stunUrl is not a valid url', () => {
|
|
33
|
+
assert.throws(() => convertStunUrlToTurn('not a url', 'tcp'), 'Invalid URL: not a url');
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('show fail if stunUrl is not a STUN url', () => {
|
|
37
|
+
assert.throws(() => convertStunUrlToTurn('http://webex.com', 'tcp'), 'Not a STUN URL: http://webex.com');
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
});
|
|
@@ -3,6 +3,9 @@ import chai from 'chai';
|
|
|
3
3
|
import chaiAsPromised from 'chai-as-promised';
|
|
4
4
|
import sinon from 'sinon';
|
|
5
5
|
import ReconnectionManager from '@webex/plugin-meetings/src/reconnection-manager';
|
|
6
|
+
import { RECONNECTION } from '../../../../src/constants';
|
|
7
|
+
import LoggerProxy from '../../../../src/common/logs/logger-proxy';
|
|
8
|
+
import LoggerConfig from '../../../../src/common/logs/logger-config';
|
|
6
9
|
|
|
7
10
|
const {assert} = chai;
|
|
8
11
|
|
|
@@ -11,8 +14,16 @@ sinon.assert.expose(chai.assert, {prefix: ''});
|
|
|
11
14
|
|
|
12
15
|
describe('plugin-meetings', () => {
|
|
13
16
|
describe('ReconnectionManager.reconnect', () => {
|
|
17
|
+
const sandbox = sinon.createSandbox();
|
|
14
18
|
let fakeMediaConnection;
|
|
15
19
|
let fakeMeeting;
|
|
20
|
+
let loggerSpy;
|
|
21
|
+
|
|
22
|
+
before(() => {
|
|
23
|
+
LoggerConfig.set({ enable: false });
|
|
24
|
+
LoggerProxy.set();
|
|
25
|
+
loggerSpy = sandbox.spy(LoggerProxy.logger, 'info');
|
|
26
|
+
});
|
|
16
27
|
|
|
17
28
|
beforeEach(() => {
|
|
18
29
|
fakeMediaConnection = {
|
|
@@ -64,6 +75,7 @@ describe('plugin-meetings', () => {
|
|
|
64
75
|
meetings: {
|
|
65
76
|
getMeetingByType: sinon.stub().returns(true),
|
|
66
77
|
syncMeetings: sinon.stub().resolves({}),
|
|
78
|
+
startReachability: sinon.stub().resolves({}),
|
|
67
79
|
},
|
|
68
80
|
internal: {
|
|
69
81
|
newMetrics: {
|
|
@@ -74,22 +86,38 @@ describe('plugin-meetings', () => {
|
|
|
74
86
|
};
|
|
75
87
|
});
|
|
76
88
|
|
|
77
|
-
|
|
89
|
+
afterEach(() => {
|
|
90
|
+
sandbox.reset();
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('calls syncMeetings', async () => {
|
|
78
94
|
const rm = new ReconnectionManager(fakeMeeting);
|
|
79
95
|
|
|
80
96
|
await rm.reconnect();
|
|
81
97
|
|
|
82
98
|
assert.calledOnce(rm.webex.meetings.syncMeetings);
|
|
99
|
+
assert.calledWith(rm.webex.meetings.syncMeetings, {keepOnlyLocusMeetings: false});
|
|
83
100
|
});
|
|
84
101
|
|
|
85
|
-
it('
|
|
102
|
+
it('calls startReachability on reconnect', async () => {
|
|
86
103
|
const rm = new ReconnectionManager(fakeMeeting);
|
|
87
104
|
|
|
88
|
-
rm.
|
|
105
|
+
await rm.reconnect();
|
|
106
|
+
|
|
107
|
+
assert.calledOnce(rm.webex.meetings.startReachability);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('continues with reconnection attempt if startReachability throws an error', async () => {
|
|
111
|
+
const reachabilityError = new Error();
|
|
112
|
+
fakeMeeting.webex.meetings.startReachability = sinon.stub().throws(reachabilityError);
|
|
113
|
+
|
|
114
|
+
const rm = new ReconnectionManager(fakeMeeting);
|
|
89
115
|
|
|
90
116
|
await rm.reconnect();
|
|
91
117
|
|
|
92
|
-
assert.
|
|
118
|
+
assert.calledOnce(rm.webex.meetings.startReachability);
|
|
119
|
+
assert.calledWith(loggerSpy, 'ReconnectionManager:index#reconnect --> Reachability failed, continuing with reconnection attempt, err: ', reachabilityError);
|
|
120
|
+
assert.calledWith(loggerSpy, 'ReconnectionManager:index#executeReconnection --> Attempting to reconnect to meeting.');
|
|
93
121
|
});
|
|
94
122
|
|
|
95
123
|
it('uses correct TURN TLS information on the reconnection', async () => {
|
|
@@ -98,6 +126,7 @@ describe('plugin-meetings', () => {
|
|
|
98
126
|
await rm.reconnect();
|
|
99
127
|
|
|
100
128
|
assert.calledOnce(fakeMeeting.roap.doTurnDiscovery);
|
|
129
|
+
assert.calledWith(fakeMeeting.roap.doTurnDiscovery, fakeMeeting, true, true);
|
|
101
130
|
assert.calledOnce(fakeMediaConnection.reconnect);
|
|
102
131
|
assert.calledWith(fakeMediaConnection.reconnect, [
|
|
103
132
|
{
|
|
@@ -113,16 +142,6 @@ describe('plugin-meetings', () => {
|
|
|
113
142
|
meetingId: rm.meeting.id,
|
|
114
143
|
},
|
|
115
144
|
});
|
|
116
|
-
|
|
117
|
-
assert.calledWith(fakeMeeting.webex.internal.newMetrics.submitClientEvent, {
|
|
118
|
-
name: 'client.media.recovered',
|
|
119
|
-
payload: {
|
|
120
|
-
recoveredBy: 'new',
|
|
121
|
-
},
|
|
122
|
-
options: {
|
|
123
|
-
meetingId: rm.meeting.id,
|
|
124
|
-
},
|
|
125
|
-
});
|
|
126
145
|
});
|
|
127
146
|
|
|
128
147
|
it('does not clear previous requests and re-request media for non-multistream meetings', async () => {
|
|
@@ -149,7 +168,6 @@ describe('plugin-meetings', () => {
|
|
|
149
168
|
assert.calledOnce(fakeMeeting.mediaRequestManagers.video.commit);
|
|
150
169
|
});
|
|
151
170
|
|
|
152
|
-
|
|
153
171
|
it('sends the correct client event when reconnection fails', async () => {
|
|
154
172
|
sinon.stub(ReconnectionManager.prototype, 'executeReconnection').rejects();
|
|
155
173
|
fakeMeeting.isMultistream = true;
|
|
@@ -186,9 +204,10 @@ describe('plugin-meetings', () => {
|
|
|
186
204
|
*/
|
|
187
205
|
describe('ReconnectionManager', () => {
|
|
188
206
|
let reconnectionManager;
|
|
207
|
+
let fakeMeeting;
|
|
189
208
|
|
|
190
209
|
beforeEach(() => {
|
|
191
|
-
|
|
210
|
+
fakeMeeting = {
|
|
192
211
|
config: {
|
|
193
212
|
reconnection: {
|
|
194
213
|
enabled: true,
|
|
@@ -203,7 +222,9 @@ describe('plugin-meetings', () => {
|
|
|
203
222
|
},
|
|
204
223
|
},
|
|
205
224
|
},
|
|
206
|
-
}
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
reconnectionManager = new ReconnectionManager(fakeMeeting);
|
|
207
228
|
});
|
|
208
229
|
|
|
209
230
|
describe('iceReconnected()', () => {
|
|
@@ -309,5 +330,41 @@ describe('plugin-meetings', () => {
|
|
|
309
330
|
});
|
|
310
331
|
});
|
|
311
332
|
});
|
|
333
|
+
|
|
334
|
+
describe('setStatus()', () => {
|
|
335
|
+
beforeEach(() => {
|
|
336
|
+
reconnectionManager.status = RECONNECTION.STATE.DEFAULT_STATUS;
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
it('should correctly change status to in progress', () => {
|
|
340
|
+
reconnectionManager.setStatus(RECONNECTION.STATE.IN_PROGRESS);
|
|
341
|
+
|
|
342
|
+
assert.equal(reconnectionManager.status, RECONNECTION.STATE.IN_PROGRESS);
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
it('should correctly change status to complete', () => {
|
|
346
|
+
reconnectionManager.setStatus(RECONNECTION.STATE.COMPLETE);
|
|
347
|
+
|
|
348
|
+
assert.equal(reconnectionManager.status, RECONNECTION.STATE.COMPLETE);
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
it('should correctly change status to failure', () => {
|
|
352
|
+
reconnectionManager.setStatus(RECONNECTION.STATE.FAILURE);
|
|
353
|
+
|
|
354
|
+
assert.equal(reconnectionManager.status, RECONNECTION.STATE.FAILURE);
|
|
355
|
+
});
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
describe('cleanUp()', () => {
|
|
359
|
+
it('should call reset and keep reference to meeting object', () => {
|
|
360
|
+
const resetSpy = sinon.spy(reconnectionManager, 'reset');
|
|
361
|
+
assert.equal(reconnectionManager.meeting, fakeMeeting);
|
|
362
|
+
|
|
363
|
+
reconnectionManager.cleanUp();
|
|
364
|
+
|
|
365
|
+
assert.equal(reconnectionManager.meeting, fakeMeeting);
|
|
366
|
+
assert.calledOnce(reconnectionManager.reset);
|
|
367
|
+
});
|
|
368
|
+
});
|
|
312
369
|
});
|
|
313
370
|
});
|
|
@@ -7,38 +7,35 @@ import RoapRequest from '@webex/plugin-meetings/src/roap/request';
|
|
|
7
7
|
import Roap from '@webex/plugin-meetings/src/roap/';
|
|
8
8
|
import Meeting from '@webex/plugin-meetings/src/meeting';
|
|
9
9
|
import MeetingUtil from '@webex/plugin-meetings/src/meeting/util';
|
|
10
|
+
import Metrics from '@webex/plugin-meetings/src/metrics';
|
|
11
|
+
import BEHAVIORAL_METRICS from '@webex/plugin-meetings/src/metrics/constants';
|
|
10
12
|
|
|
11
13
|
import { IP_VERSION } from '../../../../src/constants';
|
|
12
14
|
|
|
13
15
|
describe('Roap', () => {
|
|
14
16
|
describe('doTurnDiscovery', () => {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
+
[false, true].forEach(function (isReconnecting) {
|
|
18
|
+
[false, true, undefined].forEach(function (isForced) {
|
|
19
|
+
it(`calls this.turnDiscovery.doTurnDiscovery() and forwards all the arguments when isReconnecting = ${isReconnecting} and isForced = ${isForced}`, async () => {
|
|
20
|
+
const webex = new MockWebex({});
|
|
17
21
|
|
|
18
|
-
|
|
19
|
-
|
|
22
|
+
const RESULT = {something: 'some value'};
|
|
23
|
+
const meeting = {id: 'some meeting id'} as Meeting;
|
|
20
24
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
25
|
+
const doTurnDiscoveryStub = sinon
|
|
26
|
+
.stub(TurnDiscovery.prototype, 'doTurnDiscovery')
|
|
27
|
+
.resolves(RESULT);
|
|
24
28
|
|
|
25
|
-
|
|
29
|
+
const roap = new Roap({}, {parent: webex});
|
|
26
30
|
|
|
27
|
-
|
|
28
|
-
const result = await roap.doTurnDiscovery(meeting, true);
|
|
31
|
+
const result = await roap.doTurnDiscovery(meeting, isReconnecting, isForced);
|
|
29
32
|
|
|
30
|
-
|
|
31
|
-
|
|
33
|
+
assert.calledOnceWithExactly(doTurnDiscoveryStub, meeting, isReconnecting, isForced);
|
|
34
|
+
assert.deepEqual(result, RESULT);
|
|
32
35
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const result2 = await roap.doTurnDiscovery(meeting, false);
|
|
37
|
-
|
|
38
|
-
assert.calledOnceWithExactly(doTurnDiscoveryStub, meeting, false);
|
|
39
|
-
assert.deepEqual(result2, RESULT);
|
|
40
|
-
|
|
41
|
-
sinon.restore();
|
|
36
|
+
sinon.restore();
|
|
37
|
+
});
|
|
38
|
+
});
|
|
42
39
|
});
|
|
43
40
|
});
|
|
44
41
|
|
|
@@ -47,6 +44,9 @@ describe('Roap', () => {
|
|
|
47
44
|
let meeting;
|
|
48
45
|
|
|
49
46
|
let webex;
|
|
47
|
+
let roap;
|
|
48
|
+
|
|
49
|
+
const fakeLocus = {id: 'fake locus'};
|
|
50
50
|
|
|
51
51
|
beforeEach(() => {
|
|
52
52
|
webex = new MockWebex({});
|
|
@@ -55,68 +55,188 @@ describe('Roap', () => {
|
|
|
55
55
|
correlationId: 'correlation id',
|
|
56
56
|
selfUrl: 'self url',
|
|
57
57
|
mediaId: 'media id',
|
|
58
|
-
audio:{
|
|
58
|
+
audio: {
|
|
59
59
|
isLocallyMuted: () => true,
|
|
60
60
|
},
|
|
61
|
-
video:{
|
|
61
|
+
video: {
|
|
62
62
|
isLocallyMuted: () => false,
|
|
63
63
|
},
|
|
64
|
+
isMultistream: true,
|
|
64
65
|
setRoapSeq: sinon.stub(),
|
|
65
|
-
config: {experimental: {enableTurnDiscovery: false}},
|
|
66
66
|
locusMediaRequest: {fake: true},
|
|
67
|
-
webex: {
|
|
67
|
+
webex: {meetings: {reachability: {isAnyPublicClusterReachable: () => true}}},
|
|
68
|
+
updateMediaConnections: sinon.stub(),
|
|
68
69
|
};
|
|
69
70
|
|
|
70
71
|
sinon.stub(MeetingUtil, 'getIpVersion').returns(IP_VERSION.unknown);
|
|
72
|
+
sinon.stub(Metrics, 'sendBehavioralMetric');
|
|
71
73
|
|
|
72
74
|
sendRoapStub = sinon.stub(RoapRequest.prototype, 'sendRoap').resolves({});
|
|
73
75
|
meeting.setRoapSeq.resetHistory();
|
|
76
|
+
|
|
77
|
+
roap = new Roap({}, {parent: webex});
|
|
78
|
+
sinon.stub(roap.turnDiscovery, 'isSkipped').resolves(false);
|
|
74
79
|
});
|
|
75
80
|
|
|
76
81
|
afterEach(() => {
|
|
77
82
|
sinon.restore();
|
|
78
83
|
});
|
|
79
84
|
|
|
80
|
-
|
|
81
|
-
{
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
meeting,
|
|
97
|
-
sdp: 'sdp',
|
|
98
|
-
reconnect,
|
|
99
|
-
seq: 2,
|
|
100
|
-
tieBreaker: 4294967294,
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
const expectedRoapMessage = {
|
|
104
|
-
messageType: 'OFFER',
|
|
105
|
-
sdps: ['sdp'],
|
|
106
|
-
version: '2',
|
|
107
|
-
seq: 2,
|
|
108
|
-
tieBreaker: 4294967294,
|
|
109
|
-
};
|
|
85
|
+
it(`sends roap OFFER`, async () => {
|
|
86
|
+
await roap.sendRoapMediaRequest({
|
|
87
|
+
meeting,
|
|
88
|
+
sdp: 'sdp',
|
|
89
|
+
seq: 2,
|
|
90
|
+
tieBreaker: 4294967294,
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const expectedRoapMessage = {
|
|
94
|
+
messageType: 'OFFER',
|
|
95
|
+
sdps: ['sdp'],
|
|
96
|
+
version: '2',
|
|
97
|
+
seq: 2,
|
|
98
|
+
tieBreaker: 4294967294,
|
|
99
|
+
headers: ['includeAnswerInHttpResponse', 'noOkInTransaction'],
|
|
100
|
+
};
|
|
110
101
|
|
|
111
|
-
|
|
112
|
-
|
|
102
|
+
assert.calledOnce(sendRoapStub);
|
|
103
|
+
assert.calledWith(
|
|
104
|
+
sendRoapStub,
|
|
105
|
+
sinon.match({
|
|
113
106
|
roapMessage: expectedRoapMessage,
|
|
114
107
|
locusSelfUrl: meeting.selfUrl,
|
|
115
|
-
mediaId:
|
|
108
|
+
mediaId: meeting.mediaId,
|
|
116
109
|
meetingId: meeting.id,
|
|
117
110
|
locusMediaRequest: meeting.locusMediaRequest,
|
|
118
|
-
})
|
|
119
|
-
|
|
120
|
-
);
|
|
111
|
+
})
|
|
112
|
+
);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('reads SDP answer from the http response', async () => {
|
|
116
|
+
const roapAnswer = {
|
|
117
|
+
seq: 5,
|
|
118
|
+
messageType: 'ANSWER',
|
|
119
|
+
sdps: ['sdp answer'],
|
|
120
|
+
errorType: 'error type', // normally ANSWER would not have errorType or errorCause (only error messages have these)
|
|
121
|
+
errorCause: 'error cause', // but we're just testing here that all the fields are forwarded to the caller of sendRoapMediaRequest()
|
|
122
|
+
headers: ['header1', 'header2'],
|
|
123
|
+
};
|
|
124
|
+
const fakeMediaConnections = [
|
|
125
|
+
{
|
|
126
|
+
remoteSdp: JSON.stringify({
|
|
127
|
+
roapMessage: roapAnswer,
|
|
128
|
+
}),
|
|
129
|
+
},
|
|
130
|
+
];
|
|
131
|
+
|
|
132
|
+
sendRoapStub.resolves({
|
|
133
|
+
mediaConnections: fakeMediaConnections,
|
|
134
|
+
locus: fakeLocus,
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
const result = await roap.sendRoapMediaRequest({
|
|
138
|
+
meeting,
|
|
139
|
+
sdp: 'sdp',
|
|
140
|
+
reconnect: false,
|
|
141
|
+
seq: 1,
|
|
142
|
+
tieBreaker: 4294967294,
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
assert.calledOnce(sendRoapStub);
|
|
146
|
+
assert.calledOnceWithExactly(meeting.updateMediaConnections, fakeMediaConnections);
|
|
147
|
+
assert.deepEqual(result, {
|
|
148
|
+
locus: fakeLocus,
|
|
149
|
+
roapAnswer: {
|
|
150
|
+
seq: 5,
|
|
151
|
+
messageType: 'ANSWER',
|
|
152
|
+
sdp: 'sdp answer',
|
|
153
|
+
errorType: 'error type',
|
|
154
|
+
errorCause: 'error cause',
|
|
155
|
+
headers: ['header1', 'header2'],
|
|
156
|
+
},
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it('handles the case when there is no answer in the http response', async () => {
|
|
161
|
+
const fakeMediaConnections = [
|
|
162
|
+
{
|
|
163
|
+
// this is the actual value Locus returns to us when they don't send Roap ANSWER in the http response
|
|
164
|
+
remoteSdp:
|
|
165
|
+
'{"audioMuted":false,"videoMuted":false,"csis":[],"dtmfReceiveSupported":true,"type":"SDP"}',
|
|
166
|
+
},
|
|
167
|
+
];
|
|
168
|
+
|
|
169
|
+
sendRoapStub.resolves({
|
|
170
|
+
mediaConnections: fakeMediaConnections,
|
|
171
|
+
locus: fakeLocus,
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
const result = await roap.sendRoapMediaRequest({
|
|
175
|
+
meeting,
|
|
176
|
+
sdp: 'sdp',
|
|
177
|
+
reconnect: false,
|
|
178
|
+
seq: 1,
|
|
179
|
+
tieBreaker: 4294967294,
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
assert.calledOnce(sendRoapStub);
|
|
183
|
+
assert.calledOnceWithExactly(meeting.updateMediaConnections, fakeMediaConnections);
|
|
184
|
+
assert.deepEqual(result, {
|
|
185
|
+
locus: fakeLocus,
|
|
186
|
+
roapAnswer: undefined,
|
|
187
|
+
});
|
|
188
|
+
assert.calledOnceWithExactly(
|
|
189
|
+
Metrics.sendBehavioralMetric,
|
|
190
|
+
BEHAVIORAL_METRICS.ROAP_HTTP_RESPONSE_MISSING,
|
|
191
|
+
{
|
|
192
|
+
correlationId: meeting.correlationId,
|
|
193
|
+
messageType: 'ANSWER',
|
|
194
|
+
isMultistream: meeting.isMultistream,
|
|
195
|
+
}
|
|
196
|
+
);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
describe('does not crash when http response is missing things', () => {
|
|
200
|
+
[
|
|
201
|
+
{mediaConnections: undefined, title: 'mediaConnections are undefined'},
|
|
202
|
+
{mediaConnections: [], title: 'mediaConnections are empty array'},
|
|
203
|
+
{mediaConnections: [{}], title: 'mediaConnections[0] has no remoteSdp'},
|
|
204
|
+
{
|
|
205
|
+
mediaConnections: [{remoteSdp: '{}'}],
|
|
206
|
+
title: 'mediaConnections[0].remoteSdp is an empty json',
|
|
207
|
+
},
|
|
208
|
+
].forEach(({mediaConnections, title}) =>
|
|
209
|
+
it(title, async () => {
|
|
210
|
+
sendRoapStub.resolves({
|
|
211
|
+
mediaConnections,
|
|
212
|
+
locus: fakeLocus,
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
const result = await roap.sendRoapMediaRequest({
|
|
216
|
+
meeting,
|
|
217
|
+
sdp: 'sdp',
|
|
218
|
+
reconnect: false,
|
|
219
|
+
seq: 1,
|
|
220
|
+
tieBreaker: 4294967294,
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
assert.calledOnce(sendRoapStub);
|
|
224
|
+
assert.deepEqual(result, {
|
|
225
|
+
locus: fakeLocus,
|
|
226
|
+
roapAnswer: undefined,
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
assert.calledOnceWithExactly(
|
|
230
|
+
Metrics.sendBehavioralMetric,
|
|
231
|
+
BEHAVIORAL_METRICS.ROAP_HTTP_RESPONSE_MISSING,
|
|
232
|
+
{
|
|
233
|
+
correlationId: meeting.correlationId,
|
|
234
|
+
messageType: 'ANSWER',
|
|
235
|
+
isMultistream: meeting.isMultistream,
|
|
236
|
+
}
|
|
237
|
+
);
|
|
238
|
+
})
|
|
239
|
+
);
|
|
240
|
+
});
|
|
121
241
|
});
|
|
122
242
|
});
|
|
@@ -65,7 +65,9 @@ describe('plugin-meetings/roap', () => {
|
|
|
65
65
|
REACHABILITY.localStorageResult,
|
|
66
66
|
JSON.stringify({
|
|
67
67
|
clusterId: {
|
|
68
|
-
udp: '
|
|
68
|
+
udp: { result: 'reachable', latencyInMilliseconds: 10 },
|
|
69
|
+
tcp: { result: 'unreachable' },
|
|
70
|
+
isVideoMesh: false,
|
|
69
71
|
},
|
|
70
72
|
})
|
|
71
73
|
);
|
|
@@ -78,7 +80,16 @@ describe('plugin-meetings/roap', () => {
|
|
|
78
80
|
assert.deepEqual(res.localSdp, {
|
|
79
81
|
reachability: {
|
|
80
82
|
clusterId: {
|
|
81
|
-
udp:
|
|
83
|
+
udp: {
|
|
84
|
+
reachable: 'true',
|
|
85
|
+
latencyInMilliseconds: '10',
|
|
86
|
+
},
|
|
87
|
+
tcp: {
|
|
88
|
+
reachable: 'false',
|
|
89
|
+
},
|
|
90
|
+
xtls: {
|
|
91
|
+
untested: 'true',
|
|
92
|
+
}
|
|
82
93
|
},
|
|
83
94
|
},
|
|
84
95
|
});
|
|
@@ -148,7 +159,20 @@ describe('plugin-meetings/roap', () => {
|
|
|
148
159
|
roapMessage: {
|
|
149
160
|
seq: 'seq',
|
|
150
161
|
},
|
|
151
|
-
reachability: {
|
|
162
|
+
reachability: {
|
|
163
|
+
clusterId: {
|
|
164
|
+
tcp: {
|
|
165
|
+
reachable: 'false',
|
|
166
|
+
},
|
|
167
|
+
udp: {
|
|
168
|
+
latencyInMilliseconds: '10',
|
|
169
|
+
reachable: 'true',
|
|
170
|
+
},
|
|
171
|
+
xtls: {
|
|
172
|
+
untested: 'true',
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
},
|
|
152
176
|
});
|
|
153
177
|
});
|
|
154
178
|
|