@webex/plugin-meetings 2.60.0-next.9 → 2.60.1-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.
Files changed (55) hide show
  1. package/dist/breakouts/breakout.js +1 -1
  2. package/dist/breakouts/index.js +1 -1
  3. package/dist/config.d.ts +1 -0
  4. package/dist/config.js +2 -1
  5. package/dist/config.js.map +1 -1
  6. package/dist/index.js +5 -1
  7. package/dist/index.js.map +1 -1
  8. package/dist/interceptors/index.d.ts +2 -0
  9. package/dist/interceptors/index.js +15 -0
  10. package/dist/interceptors/index.js.map +1 -0
  11. package/dist/interceptors/locusRetry.d.ts +27 -0
  12. package/dist/interceptors/locusRetry.js +94 -0
  13. package/dist/interceptors/locusRetry.js.map +1 -0
  14. package/dist/interpretation/index.js +1 -1
  15. package/dist/interpretation/siLanguage.js +1 -1
  16. package/dist/meeting/index.js +6 -2
  17. package/dist/meeting/index.js.map +1 -1
  18. package/dist/meetings/index.d.ts +1 -11
  19. package/dist/meetings/index.js +4 -3
  20. package/dist/meetings/index.js.map +1 -1
  21. package/dist/reachability/clusterReachability.d.ts +109 -0
  22. package/dist/reachability/clusterReachability.js +357 -0
  23. package/dist/reachability/clusterReachability.js.map +1 -0
  24. package/dist/reachability/index.d.ts +32 -121
  25. package/dist/reachability/index.js +173 -459
  26. package/dist/reachability/index.js.map +1 -1
  27. package/dist/reachability/util.d.ts +8 -0
  28. package/dist/reachability/util.js +29 -0
  29. package/dist/reachability/util.js.map +1 -0
  30. package/dist/statsAnalyzer/index.d.ts +22 -0
  31. package/dist/statsAnalyzer/index.js +60 -0
  32. package/dist/statsAnalyzer/index.js.map +1 -1
  33. package/dist/statsAnalyzer/mqaUtil.js +4 -0
  34. package/dist/statsAnalyzer/mqaUtil.js.map +1 -1
  35. package/dist/webinar/index.js +1 -1
  36. package/package.json +25 -22
  37. package/src/config.ts +1 -0
  38. package/src/index.ts +4 -0
  39. package/src/interceptors/index.ts +3 -0
  40. package/src/interceptors/locusRetry.ts +67 -0
  41. package/src/meeting/index.ts +10 -2
  42. package/src/meetings/index.ts +4 -3
  43. package/src/reachability/clusterReachability.ts +320 -0
  44. package/src/reachability/index.ts +124 -421
  45. package/src/reachability/util.ts +24 -0
  46. package/src/statsAnalyzer/index.ts +64 -1
  47. package/src/statsAnalyzer/mqaUtil.ts +4 -0
  48. package/test/unit/spec/interceptors/locusRetry.ts +131 -0
  49. package/test/unit/spec/meeting/index.js +8 -1
  50. package/test/unit/spec/meetings/index.js +28 -25
  51. package/test/unit/spec/reachability/clusterReachability.ts +279 -0
  52. package/test/unit/spec/reachability/index.ts +159 -226
  53. package/test/unit/spec/reachability/util.ts +40 -0
  54. package/test/unit/spec/roap/request.ts +26 -3
  55. package/test/unit/spec/stats-analyzer/index.js +100 -20
@@ -1,8 +1,9 @@
1
1
  import {assert} from '@webex/test-helper-chai';
2
2
  import MockWebex from '@webex/test-helper-mock-webex';
3
3
  import sinon from 'sinon';
4
- import Reachability, {ICECandidateResult, ReachabilityResults} from '@webex/plugin-meetings/src/reachability/';
4
+ import Reachability, {ReachabilityResults, ReachabilityResultsForBackend} from '@webex/plugin-meetings/src/reachability/';
5
5
  import MeetingUtil from '@webex/plugin-meetings/src/meeting/util';
6
+ import * as ClusterReachabilityModule from '@webex/plugin-meetings/src/reachability/clusterReachability';
6
7
 
7
8
  import { IP_VERSION } from '@webex/plugin-meetings/src/constants';
8
9
 
@@ -35,19 +36,19 @@ describe('isAnyPublicClusterReachable', () => {
35
36
  };
36
37
 
37
38
  it('returns true when udp is reachable', async () => {
38
- await checkIsClusterReachable({x: {udp: {reachable: 'true'}, tcp: {reachable: 'false'}}}, true);
39
+ await checkIsClusterReachable({x: {udp: {result: 'reachable'}, tcp: {result: 'unreachable'}}}, true);
39
40
  });
40
41
 
41
42
  it('returns true when tcp is reachable', async () => {
42
- await checkIsClusterReachable({x: {udp: {reachable: 'false'}, tcp: {reachable: 'true'}}}, true);
43
+ await checkIsClusterReachable({x: {udp: {result: 'unreachable'}, tcp: {result: 'reachable'}}}, true);
43
44
  });
44
45
 
45
46
  it('returns true when both tcp and udp are reachable', async () => {
46
- await checkIsClusterReachable({x: {udp: {reachable: 'true'}, tcp: {reachable: 'true'}}}, true);
47
+ await checkIsClusterReachable({x: {udp: {result: 'reachable'}, tcp: {result: 'reachable'}}}, true);
47
48
  });
48
49
 
49
50
  it('returns false when both tcp and udp are unreachable', async () => {
50
- await checkIsClusterReachable({x: {udp: {reachable: 'false'}, tcp: {reachable: 'false'}}}, false);
51
+ await checkIsClusterReachable({x: {udp: {result: 'unreachable'}, tcp: {result: 'unreachable'}}}, false);
51
52
  });
52
53
 
53
54
  it('returns false when reachability result is empty', async () => {
@@ -62,13 +63,13 @@ describe('isAnyPublicClusterReachable', () => {
62
63
  it('returns false if there are no public cluster results, only video mesh', async () => {
63
64
  await checkIsClusterReachable({
64
65
  x: {
65
- udp: {reachable: 'true'},
66
- tcp: {reachable: 'true'},
66
+ udp: {result: 'reachable'},
67
+ tcp: {result: 'reachable'},
67
68
  isVideoMesh: true,
68
69
  },
69
70
  y: {
70
- udp: {reachable: 'false'},
71
- tcp: {reachable: 'true'},
71
+ udp: {result: 'unreachable'},
72
+ tcp: {result: 'reachable'},
72
73
  isVideoMesh: true,
73
74
  }
74
75
  }, false);
@@ -77,18 +78,18 @@ describe('isAnyPublicClusterReachable', () => {
77
78
  it('returns false if there public cluster reachability failed, only video mesh succeeded', async () => {
78
79
  await checkIsClusterReachable({
79
80
  x: {
80
- udp: {reachable: 'false'},
81
- tcp: {reachable: 'true'},
81
+ udp: {result: 'unreachable'},
82
+ tcp: {result: 'reachable'},
82
83
  isVideoMesh: true,
83
84
  },
84
85
  y: {
85
- udp: {reachable: 'true'},
86
- tcp: {reachable: 'false'},
86
+ udp: {result: 'reachable'},
87
+ tcp: {result: 'unreachable'},
87
88
  isVideoMesh: true,
88
89
  },
89
90
  publicOne: {
90
- udp: {reachable: 'false'},
91
- tcp: {reachable: 'false'},
91
+ udp: {result: 'unreachable'},
92
+ tcp: {result: 'unreachable'},
92
93
  isVideoMesh: false,
93
94
  }
94
95
  }, false);
@@ -97,18 +98,18 @@ describe('isAnyPublicClusterReachable', () => {
97
98
  it('returns true if there is at least 1 public cluster result, while video mesh is not reachable', async () => {
98
99
  await checkIsClusterReachable({
99
100
  x: {
100
- udp: {reachable: 'true'},
101
- tcp: {reachable: 'true'},
101
+ udp: {result: 'reachable'},
102
+ tcp: {result: 'reachable'},
102
103
  isVideoMesh: true,
103
104
  },
104
105
  y: {
105
- udp: {reachable: 'false'},
106
- tcp: {reachable: 'true'},
106
+ udp: {result: 'unreachable'},
107
+ tcp: {result: 'reachable'},
107
108
  isVideoMesh: true,
108
109
  },
109
110
  publicOne: {
110
- udp: {reachable: 'false'},
111
- tcp: {reachable: 'true'},
111
+ udp: {result: 'unreachable'},
112
+ tcp: {result: 'reachable'},
112
113
  isVideoMesh: false,
113
114
  }
114
115
  }, true);
@@ -129,6 +130,10 @@ describe('gatherReachability', () => {
129
130
  );
130
131
  });
131
132
 
133
+ afterEach(() => {
134
+ sinon.restore();
135
+ });
136
+
132
137
  it('stores the reachability', async () => {
133
138
  const reachability = new Reachability(webex);
134
139
 
@@ -145,7 +150,7 @@ describe('gatherReachability', () => {
145
150
  };
146
151
 
147
152
  reachability.reachabilityRequest.getClusters = sinon.stub().returns(getClustersResult);
148
- (reachability as any).performReachabilityCheck = sinon.stub().returns(reachabilityResults);
153
+ (reachability as any).performReachabilityChecks = sinon.stub().returns(reachabilityResults);
149
154
 
150
155
  const result = await reachability.gatherReachability();
151
156
 
@@ -164,161 +169,89 @@ describe('gatherReachability', () => {
164
169
  assert.equal(JSON.stringify(getClustersResult.joinCookie), storedResultForJoinCookie);
165
170
  });
166
171
 
167
- it('does reachability only on udp', async () => {
168
- const reachability = new Reachability(webex);
172
+ it('starts ClusterReachability on each media cluster', async () => {
173
+ webex.config.meetings.experimental = {enableTcpReachability: true};
169
174
 
170
175
  const getClustersResult = {
171
- clusters: {clusterId: {
172
- tcp: [
173
- 'stun:170.72.164.1:5004',
174
- 'stun:170.72.165.2:5004'
175
- ],
176
- udp: [
177
- 'stun:170.72.164.3:5004',
178
- 'stun:170.72.164.3:9000',
179
- ],
180
- xtls: [
181
- 'stun:external-media101.public.wjfkm-a-4.prod.infra.webex.com:443',
182
- 'stun:external-media94.public.wjfkm-a-8.prod.infra.webex.com:443'
183
- ]
184
- }},
176
+ clusters: {
177
+ 'cluster 1': {
178
+ udp: ['udp1.1', 'udp1.2'],
179
+ tcp: ['tcp1.1', 'tcp1.2'],
180
+ xtls: ['xtls1.1', 'xtls1.2'],
181
+ isVideoMesh: false,
182
+ },
183
+ 'cluster 2': {
184
+ udp: ['udp2.1', 'udp2.2'],
185
+ tcp: ['tcp2.1', 'tcp2.2'],
186
+ xtls: ['xtls2.1', 'xtls2.2'],
187
+ isVideoMesh: true,
188
+ },
189
+ },
185
190
  joinCookie: {id: 'id'},
186
191
  };
187
192
 
188
- sinon.stub(reachability.reachabilityRequest, 'getClusters').returns(getClustersResult);
189
-
190
- const createPeerConnectionStub = sinon.stub(reachability, 'createPeerConnection');
193
+ const reachability = new Reachability(webex);
191
194
 
192
- await reachability.gatherReachability();
195
+ reachability.reachabilityRequest.getClusters = sinon.stub().returns(getClustersResult);
193
196
 
194
- // check that a peer connection was created with only the udp urls
195
- assert.calledOnceWithExactly(createPeerConnectionStub, {
196
- key: 'clusterId',
197
- config: {
198
- iceServers: [
199
- {
200
- username: '',
201
- credential: '',
202
- urls: ['stun:170.72.164.3:5004'],
203
- },
204
- {
205
- username: '',
206
- credential: '',
207
- urls: ['stun:170.72.164.3:9000'],
208
- }
209
- ],
210
- iceCandidatePoolSize: '0',
211
- iceTransportPolicy: 'all'
212
- }
213
- })
214
- });
197
+ const startStub = sinon.stub().resolves({});
198
+ const clusterReachabilityCtorStub = sinon
199
+ .stub(ClusterReachabilityModule, 'ClusterReachability')
200
+ .callsFake(() => ({
201
+ start: startStub,
202
+ }));
215
203
 
216
- describe('clientMediaIPs', () => {
217
- let testingClass: TestReachability;
204
+ await reachability.gatherReachability();
218
205
 
219
- class TestReachability extends Reachability {
220
- public testParseIceResultsToInternalReachabilityResults(iceResults: Array<ICECandidateResult>) {
221
- return this.parseIceResultsToInternalReachabilityResults(iceResults);
222
- }
223
- public testAddPublicIP(peerConnection: RTCPeerConnection, publicIP?: string | null) {
224
- return this.addPublicIP(peerConnection, publicIP);
225
- }
226
- }
227
- beforeEach(() => {
228
- testingClass = new TestReachability({webex});
206
+ assert.calledTwice(clusterReachabilityCtorStub);
207
+ assert.calledWith(clusterReachabilityCtorStub, 'cluster 1', {
208
+ udp: ['udp1.1', 'udp1.2'],
209
+ tcp: ['tcp1.1', 'tcp1.2'],
210
+ xtls: ['xtls1.1', 'xtls1.2'],
211
+ isVideoMesh: false,
229
212
  });
230
-
231
- it('calls parseIceResultsToInternalReachabilityResults correctly', () => {
232
- const res = testingClass.testParseIceResultsToInternalReachabilityResults([
233
- {
234
- clusterId: 'id1',
235
- elapsed: '12312',
236
- publicIPs: ['1.1.1.1'],
237
- isVideoMesh: true,
238
- },
239
- {
240
- clusterId: 'id2',
241
- elapsed: null,
242
- publicIPs: ['1.1.1.1'],
243
- isVideoMesh: false,
244
- },
245
- {
246
- clusterId: 'id2',
247
- elapsed: '14123',
248
- publicIPs: undefined,
249
- isVideoMesh: false,
250
- },
251
- ]);
252
-
253
- assert.deepEqual(res, {
254
- id1: {
255
- tcp: {
256
- untested: 'true',
257
- },
258
- xtls: {
259
- untested: 'true',
260
- },
261
- udp: {
262
- clientMediaIPs: ['1.1.1.1'],
263
- latencyInMilliseconds: '12312',
264
- reachable: 'true',
265
- },
266
- isVideoMesh: true,
267
- },
268
- id2: {
269
- xtls: {
270
- untested: 'true',
271
- },
272
- tcp: {
273
- untested: 'true',
274
- },
275
- udp: {
276
- latencyInMilliseconds: '14123',
277
- reachable: 'true',
278
- },
279
- isVideoMesh: false,
280
- },
281
- });
213
+ assert.calledWith(clusterReachabilityCtorStub, 'cluster 2', {
214
+ udp: ['udp2.1', 'udp2.2'],
215
+ tcp: ['tcp2.1', 'tcp2.2'],
216
+ xtls: ['xtls2.1', 'xtls2.2'],
217
+ isVideoMesh: true,
282
218
  });
283
219
 
284
- it('calls addPublicIP correctly with no existing public APIs', () => {
285
- const peerConnection = {
286
- connectionState: 'not_closed',
287
- };
288
-
289
- testingClass.testAddPublicIP(peerConnection as RTCPeerConnection, '1.1.1.1');
220
+ assert.calledTwice(startStub);
221
+ });
290
222
 
291
- assert.deepEqual(peerConnection, {
292
- connectionState: 'not_closed',
293
- publicIPs: ['1.1.1.1'],
294
- });
295
- });
223
+ it('does not do TCP reachability if it is disabled in config', async () => {
224
+ webex.config.meetings.experimental = {enableTcpReachability: false};
296
225
 
297
- it('calls addPublicIP correctly with existing public APIs', () => {
298
- const peerConnection = {
299
- connectionState: 'not_closed',
300
- publicIPs: ['2.2.2.2'],
301
- };
226
+ const getClustersResult = {
227
+ clusters: {
228
+ 'cluster name': {
229
+ udp: ['testUDP1', 'testUDP2'],
230
+ tcp: ['testTCP1', 'testTCP2'],
231
+ xtls: ['testXTLS1', 'testXTLS2'],
232
+ isVideoMesh: false,
233
+ },
234
+ },
235
+ joinCookie: {id: 'id'},
236
+ };
302
237
 
303
- testingClass.testAddPublicIP(peerConnection as any, '1.1.1.1');
238
+ const reachability = new Reachability(webex);
304
239
 
305
- assert.deepEqual(peerConnection, {
306
- connectionState: 'not_closed',
307
- publicIPs: ['2.2.2.2', '1.1.1.1'],
308
- });
309
- });
240
+ reachability.reachabilityRequest.getClusters = sinon.stub().returns(getClustersResult);
310
241
 
311
- it('calls addPublicIP correctly null publicAPI', () => {
312
- const peerConnection = {
313
- connectionState: 'not_closed',
314
- };
242
+ const clusterReachabilityCtorStub = sinon
243
+ .stub(ClusterReachabilityModule, 'ClusterReachability')
244
+ .callsFake(() => ({
245
+ start: sinon.stub().resolves({}),
246
+ }));
315
247
 
316
- testingClass.testAddPublicIP(peerConnection as RTCPeerConnection, null);
248
+ await reachability.gatherReachability();
317
249
 
318
- assert.deepEqual(peerConnection, {
319
- connectionState: 'not_closed',
320
- publicIPs: null,
321
- });
250
+ assert.calledOnceWithExactly(clusterReachabilityCtorStub, 'cluster name', {
251
+ isVideoMesh: false,
252
+ udp: ['testUDP1', 'testUDP2'],
253
+ tcp: [], // empty list because TCP is disabled in config
254
+ xtls: ['testXTLS1', 'testXTLS2'],
322
255
  });
323
256
  });
324
257
  });
@@ -334,7 +267,7 @@ describe('getReachabilityResults', () => {
334
267
  sinon.restore();
335
268
  });
336
269
 
337
- const runCheck = async (mockStorage: any, expectedResult: ReachabilityResults) => {
270
+ const runCheck = async (mockStorage: any, expectedResult: ReachabilityResultsForBackend) => {
338
271
  if (mockStorage) {
339
272
  await webex.boundedStorage.put(
340
273
  'Reachability',
@@ -359,36 +292,36 @@ describe('getReachabilityResults', () => {
359
292
  assert.isUndefined(result);
360
293
  });
361
294
 
362
- it('returns results from local storage, stripping any internal data', async () => {
295
+ it('returns results from local storage, converted to the backend data format', async () => {
363
296
  await runCheck(
364
297
  // mock storage:
365
298
  {
366
299
  cluster1: {
367
- udp: {reachable: 'true', latencyInMilliseconds: '100'},
368
- tcp: {reachable: 'false'},
369
- xtls: {untested: 'true'},
300
+ udp: {result: 'reachable', latencyInMilliseconds: 100},
301
+ tcp: {result: 'unreachable'},
302
+ xtls: {result: 'untested'},
370
303
  },
371
304
  cluster2: {
372
- udp: {reachable: 'true', latencyInMilliseconds: '200'},
373
- tcp: {reachable: 'false'},
374
- xtls: {untested: 'true'},
305
+ udp: {result: 'reachable', latencyInMilliseconds: 200},
306
+ tcp: {result: 'unreachable'},
307
+ xtls: {result: 'untested'},
375
308
  isVideoMesh: true,
376
309
  },
377
310
  cluster3: {
378
- udp: {reachable: 'false'},
379
- tcp: {reachable: 'true', latencyInMilliseconds: '100', clientMediaIPs: ['10.10.10.10']},
380
- xtls: {untested: 'true'},
311
+ udp: {result: 'unreachable'},
312
+ tcp: {result: 'reachable', latencyInMilliseconds: 100, clientMediaIPs: ['10.10.10.10']},
313
+ xtls: {result: 'untested'},
381
314
  isVideoMesh: true,
382
315
  someOtherField: 'any value',
383
316
  },
384
317
  cluster4: {
385
- udp: {reachable: 'false', latencyInMilliseconds: '300'},
386
- tcp: {reachable: 'false', untested: 'true'},
387
- xtls: {untested: 'true'},
318
+ udp: {result: 'reachable', latencyInMilliseconds: 300},
319
+ tcp: {result: 'untested'},
320
+ xtls: {result: 'untested'},
388
321
  someOtherField: 'any value',
389
322
  },
390
323
  },
391
- // expected result (same as above, but with isVideoMesh and someOtherField stripped out):
324
+ // expected result (same as above, but with values converted and isVideoMesh and someOtherField stripped out):
392
325
  {
393
326
  cluster1: {
394
327
  udp: {reachable: 'true', latencyInMilliseconds: '100'},
@@ -406,8 +339,8 @@ describe('getReachabilityResults', () => {
406
339
  xtls: {untested: 'true'},
407
340
  },
408
341
  cluster4: {
409
- udp: {reachable: 'false', latencyInMilliseconds: '300'},
410
- tcp: {reachable: 'false', untested: 'true'},
342
+ udp: {reachable: 'true', latencyInMilliseconds: '300'},
343
+ tcp: {untested: 'true'},
411
344
  xtls: {untested: 'true'},
412
345
  },
413
346
  }
@@ -464,47 +397,47 @@ describe('getReachabilityMetrics', () => {
464
397
  // mock storage:
465
398
  {
466
399
  public1: {
467
- udp: {reachable: 'true', latencyInMilliseconds: '100'},
468
- tcp: {untested: 'true'},
469
- xtls: {untested: 'true'},
400
+ udp: {result: 'reachable', latencyInMilliseconds: 100},
401
+ tcp: {result: 'untested'},
402
+ xtls: {result: 'untested'},
470
403
  },
471
404
  vmn1: {
472
- udp: {reachable: 'true', latencyInMilliseconds: '200'},
473
- tcp: {reachable: 'false'},
474
- xtls: {untested: 'true'},
405
+ udp: {result: 'reachable', latencyInMilliseconds: 200},
406
+ tcp: {result: 'unreachable'},
407
+ xtls: {result: 'untested'},
475
408
  isVideoMesh: true,
476
409
  },
477
410
  vmn2: {
478
- udp: {untested: 'true'},
479
- tcp: {reachable: 'true', latencyInMilliseconds: '100', clientMediaIPs: ['10.10.10.10']},
480
- xtls: {untested: 'true'},
411
+ udp: {result: 'untested'},
412
+ tcp: {result: 'reachable', latencyInMilliseconds: 100, clientMediaIPs: ['10.10.10.10']},
413
+ xtls: {result: 'untested'},
481
414
  isVideoMesh: true,
482
415
  someOtherField: 'any value',
483
416
  },
484
417
  public2: {
485
- udp: {reachable: 'false', latencyInMilliseconds: '300'},
486
- tcp: {reachable: 'false', untested: 'true'},
487
- xtls: {untested: 'true'},
418
+ udp: {result: 'unreachable'},
419
+ tcp: {result: 'unreachable'},
420
+ xtls: {result: 'untested'},
488
421
  someOtherField: 'any value',
489
422
  },
490
423
  public3: {
491
- udp: {reachable: 'true', latencyInMilliseconds: '400', clientMediaIPs: ['10.10.10.10']},
492
- tcp: {reachable: 'true', latencyInMilliseconds: '100', clientMediaIPs: ['10.10.10.10']},
493
- xtls: {untested: 'true'},
424
+ udp: {result: 'reachable', latencyInMilliseconds: 400, clientMediaIPs: ['10.10.10.10']},
425
+ tcp: {result: 'reachable', latencyInMilliseconds: 100, clientMediaIPs: ['10.10.10.10']},
426
+ xtls: {result: 'untested'},
494
427
  isVideoMesh: false,
495
428
  someOtherField: 'any value',
496
429
  },
497
430
  public4: {
498
- udp: {reachable: 'true', latencyInMilliseconds: '40', clientMediaIPs: ['10.10.10.11']},
499
- tcp: {reachable: 'true', latencyInMilliseconds: '100', clientMediaIPs: ['10.10.10.11']},
500
- xtls: {untested: 'true'},
431
+ udp: {result: 'reachable', latencyInMilliseconds: 40, clientMediaIPs: ['10.10.10.11']},
432
+ tcp: {result: 'reachable', latencyInMilliseconds: 100, clientMediaIPs: ['10.10.10.11']},
433
+ xtls: {result: 'untested'},
501
434
  isVideoMesh: false,
502
435
  someOtherField: 'any value',
503
436
  },
504
437
  public5: {
505
- udp: {reachable: 'false'},
506
- tcp: {untested: 'true'},
507
- xtls: {untested: 'true'},
438
+ udp: {result: 'unreachable'},
439
+ tcp: {result: 'untested'},
440
+ xtls: {result: 'untested'},
508
441
  isVideoMesh: false,
509
442
  someOtherField: 'any value',
510
443
  },
@@ -528,33 +461,33 @@ describe('getReachabilityMetrics', () => {
528
461
  // mock storage:
529
462
  {
530
463
  public1: {
531
- udp: {reachable: 'true', latencyInMilliseconds: '400', clientMediaIPs: ['10.10.10.10']},
532
- tcp: {reachable: 'true', latencyInMilliseconds: '100', clientMediaIPs: ['10.10.10.10']},
533
- xtls: {untested: 'true'},
464
+ udp: {result: 'reachable', latencyInMilliseconds: 400, clientMediaIPs: ['10.10.10.10']},
465
+ tcp: {result: 'reachable', latencyInMilliseconds: 100, clientMediaIPs: ['10.10.10.10']},
466
+ xtls: {result: 'untested'},
534
467
  isVideoMesh: false,
535
468
  },
536
469
  public2: {
537
- udp: {reachable: 'true', latencyInMilliseconds: '100'},
538
- tcp: {untested: 'true'},
539
- xtls: {untested: 'true'},
470
+ udp: {result: 'reachable', latencyInMilliseconds: 100},
471
+ tcp: {result: 'untested'},
472
+ xtls: {result: 'untested'},
540
473
  },
541
474
  public3: {
542
- udp: {reachable: 'false', latencyInMilliseconds: '300'},
543
- tcp: {reachable: 'false', untested: 'true'},
544
- xtls: {untested: 'true'},
475
+ udp: {result: 'unreachable'},
476
+ tcp: {result: 'unreachable'},
477
+ xtls: {result: 'untested'},
545
478
  someOtherField: 'any value',
546
479
  },
547
480
  public4: {
548
- udp: {untested: 'true'},
549
- tcp: {reachable: 'false'},
550
- xtls: {untested: 'true'},
481
+ udp: {result: 'untested'},
482
+ tcp: {result: 'unreachable'},
483
+ xtls: {result: 'untested'},
551
484
  isVideoMesh: false,
552
485
  someOtherField: 'any value',
553
486
  },
554
487
  public5: {
555
- udp: {reachable: 'true', latencyInMilliseconds: '400', clientMediaIPs: ['10.10.10.10']},
556
- tcp: {untested: 'true'},
557
- xtls: {untested: 'true'},
488
+ udp: {result: 'reachable', latencyInMilliseconds: '400', clientMediaIPs: ['10.10.10.10']},
489
+ tcp: {result: 'untested'},
490
+ xtls: {result: 'untested'},
558
491
  },
559
492
  },
560
493
  // expected result:
@@ -576,34 +509,34 @@ describe('getReachabilityMetrics', () => {
576
509
  // mock storage:
577
510
  {
578
511
  vmn1: {
579
- udp: {reachable: 'false'},
580
- tcp: {reachable: 'true', latencyInMilliseconds: '100', clientMediaIPs: ['10.10.10.10']},
581
- xtls: {untested: 'true'},
512
+ udp: {result: 'unreachable'},
513
+ tcp: {result: 'reachable', latencyInMilliseconds: 100, clientMediaIPs: ['10.10.10.10']},
514
+ xtls: {result: 'untested'},
582
515
  isVideoMesh: true,
583
516
  },
584
517
  vmn2: {
585
- udp: {reachable: 'true', latencyInMilliseconds: '200', clientMediaIPs: ['10.10.10.10']},
586
- tcp: {untested: 'true'},
587
- xtls: {untested: 'true'},
518
+ udp: {result: 'reachable', latencyInMilliseconds: 200, clientMediaIPs: ['10.10.10.10']},
519
+ tcp: {result: 'untested'},
520
+ xtls: {result: 'untested'},
588
521
  isVideoMesh: true,
589
522
  },
590
523
  vmn3: {
591
- udp: {reachable: 'true', latencyInMilliseconds: '300', clientMediaIPs: ['10.10.10.10']},
592
- tcp: {reachable: 'false', untested: 'true'},
593
- xtls: {untested: 'true'},
524
+ udp: {result: 'reachable', latencyInMilliseconds: 300, clientMediaIPs: ['10.10.10.10']},
525
+ tcp: {result: 'unreachable'},
526
+ xtls: {result: 'untested'},
594
527
  isVideoMesh: true,
595
528
  },
596
529
  vmn4: {
597
- udp: {untested: 'true'},
598
- tcp: {reachable: 'false'},
599
- xtls: {untested: 'true'},
530
+ udp: {result: 'untested'},
531
+ tcp: {result: 'unreachable'},
532
+ xtls: {result: 'untested'},
600
533
  isVideoMesh: true,
601
534
  someOtherField: 'any value',
602
535
  },
603
536
  vmn5: {
604
- udp: {reachable: 'true', latencyInMilliseconds: '200', clientMediaIPs: ['10.10.10.10']},
605
- tcp: {reachable: 'false'},
606
- xtls: {untested: 'true'},
537
+ udp: {result: 'reachable', latencyInMilliseconds: 200, clientMediaIPs: ['10.10.10.10']},
538
+ tcp: {result: 'unreachable'},
539
+ xtls: {result: 'untested'},
607
540
  isVideoMesh: true,
608
541
  someOtherField: 'any value',
609
542
  },
@@ -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
+ });