@webex/plugin-meetings 3.8.0-next.6 → 3.8.0-next.61

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 (156) hide show
  1. package/dist/breakouts/breakout.js +1 -1
  2. package/dist/breakouts/index.js +1 -1
  3. package/dist/common/errors/webex-errors.js +12 -2
  4. package/dist/common/errors/webex-errors.js.map +1 -1
  5. package/dist/config.js +1 -0
  6. package/dist/config.js.map +1 -1
  7. package/dist/constants.js +17 -121
  8. package/dist/constants.js.map +1 -1
  9. package/dist/controls-options-manager/enums.js +2 -0
  10. package/dist/controls-options-manager/enums.js.map +1 -1
  11. package/dist/controls-options-manager/types.js.map +1 -1
  12. package/dist/controls-options-manager/util.js +52 -0
  13. package/dist/controls-options-manager/util.js.map +1 -1
  14. package/dist/interpretation/index.js +1 -1
  15. package/dist/interpretation/siLanguage.js +1 -1
  16. package/dist/locus-info/controlsUtils.js +28 -10
  17. package/dist/locus-info/controlsUtils.js.map +1 -1
  18. package/dist/locus-info/index.js +20 -1
  19. package/dist/locus-info/index.js.map +1 -1
  20. package/dist/locus-info/selfUtils.js +405 -418
  21. package/dist/locus-info/selfUtils.js.map +1 -1
  22. package/dist/media/index.js +8 -16
  23. package/dist/media/index.js.map +1 -1
  24. package/dist/meeting/in-meeting-actions.js +17 -1
  25. package/dist/meeting/in-meeting-actions.js.map +1 -1
  26. package/dist/meeting/index.js +556 -288
  27. package/dist/meeting/index.js.map +1 -1
  28. package/dist/meeting/locusMediaRequest.js +0 -17
  29. package/dist/meeting/locusMediaRequest.js.map +1 -1
  30. package/dist/meeting/muteState.js +0 -2
  31. package/dist/meeting/muteState.js.map +1 -1
  32. package/dist/meeting/request.js +30 -0
  33. package/dist/meeting/request.js.map +1 -1
  34. package/dist/meeting/request.type.js.map +1 -1
  35. package/dist/meeting/util.js +13 -2
  36. package/dist/meeting/util.js.map +1 -1
  37. package/dist/meeting-info/meeting-info-v2.js +359 -60
  38. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  39. package/dist/meetings/index.js +91 -1
  40. package/dist/meetings/index.js.map +1 -1
  41. package/dist/meetings/util.js +14 -0
  42. package/dist/meetings/util.js.map +1 -1
  43. package/dist/member/index.js +10 -0
  44. package/dist/member/index.js.map +1 -1
  45. package/dist/member/util.js +3 -0
  46. package/dist/member/util.js.map +1 -1
  47. package/dist/members/index.js +23 -0
  48. package/dist/members/index.js.map +1 -1
  49. package/dist/members/request.js +21 -0
  50. package/dist/members/request.js.map +1 -1
  51. package/dist/members/util.js +15 -0
  52. package/dist/members/util.js.map +1 -1
  53. package/dist/metrics/constants.js +9 -0
  54. package/dist/metrics/constants.js.map +1 -1
  55. package/dist/reachability/clusterReachability.js +63 -27
  56. package/dist/reachability/clusterReachability.js.map +1 -1
  57. package/dist/reachability/index.js +112 -47
  58. package/dist/reachability/index.js.map +1 -1
  59. package/dist/reachability/reachability.types.js +14 -0
  60. package/dist/reachability/reachability.types.js.map +1 -1
  61. package/dist/reachability/request.js +19 -3
  62. package/dist/reachability/request.js.map +1 -1
  63. package/dist/reconnection-manager/index.js +2 -2
  64. package/dist/reconnection-manager/index.js.map +1 -1
  65. package/dist/recording-controller/util.js +5 -5
  66. package/dist/recording-controller/util.js.map +1 -1
  67. package/dist/roap/index.js.map +1 -1
  68. package/dist/roap/turnDiscovery.js +45 -27
  69. package/dist/roap/turnDiscovery.js.map +1 -1
  70. package/dist/roap/types.js +17 -0
  71. package/dist/roap/types.js.map +1 -0
  72. package/dist/types/common/errors/webex-errors.d.ts +7 -1
  73. package/dist/types/config.d.ts +1 -0
  74. package/dist/types/constants.d.ts +12 -85
  75. package/dist/types/controls-options-manager/enums.d.ts +3 -1
  76. package/dist/types/controls-options-manager/types.d.ts +7 -1
  77. package/dist/types/locus-info/index.d.ts +1 -0
  78. package/dist/types/locus-info/selfUtils.d.ts +247 -1
  79. package/dist/types/meeting/in-meeting-actions.d.ts +16 -0
  80. package/dist/types/meeting/index.d.ts +54 -1
  81. package/dist/types/meeting/muteState.d.ts +0 -1
  82. package/dist/types/meeting/request.d.ts +12 -1
  83. package/dist/types/meeting/request.type.d.ts +6 -0
  84. package/dist/types/meeting/util.d.ts +3 -1
  85. package/dist/types/meeting-info/meeting-info-v2.d.ts +80 -0
  86. package/dist/types/meetings/index.d.ts +38 -0
  87. package/dist/types/member/index.d.ts +1 -0
  88. package/dist/types/members/index.d.ts +8 -0
  89. package/dist/types/members/request.d.ts +19 -0
  90. package/dist/types/members/util.d.ts +13 -0
  91. package/dist/types/metrics/constants.d.ts +9 -0
  92. package/dist/types/reachability/clusterReachability.d.ts +15 -7
  93. package/dist/types/reachability/index.d.ts +10 -1
  94. package/dist/types/reachability/reachability.types.d.ts +5 -0
  95. package/dist/types/roap/index.d.ts +3 -2
  96. package/dist/types/roap/turnDiscovery.d.ts +5 -17
  97. package/dist/types/roap/types.d.ts +16 -0
  98. package/dist/webinar/index.js +1 -1
  99. package/package.json +23 -23
  100. package/src/common/errors/webex-errors.ts +8 -1
  101. package/src/config.ts +1 -0
  102. package/src/constants.ts +19 -90
  103. package/src/controls-options-manager/enums.ts +2 -0
  104. package/src/controls-options-manager/types.ts +11 -1
  105. package/src/controls-options-manager/util.ts +62 -0
  106. package/src/locus-info/controlsUtils.ts +44 -14
  107. package/src/locus-info/index.ts +23 -1
  108. package/src/locus-info/selfUtils.ts +451 -447
  109. package/src/media/index.ts +11 -21
  110. package/src/meeting/in-meeting-actions.ts +32 -0
  111. package/src/meeting/index.ts +372 -92
  112. package/src/meeting/locusMediaRequest.ts +0 -18
  113. package/src/meeting/muteState.ts +0 -2
  114. package/src/meeting/request.ts +36 -1
  115. package/src/meeting/request.type.ts +7 -0
  116. package/src/meeting/util.ts +11 -2
  117. package/src/meeting-info/meeting-info-v2.ts +247 -6
  118. package/src/meetings/index.ts +107 -1
  119. package/src/meetings/util.ts +18 -0
  120. package/src/member/index.ts +11 -0
  121. package/src/member/util.ts +3 -0
  122. package/src/members/index.ts +25 -0
  123. package/src/members/request.ts +26 -0
  124. package/src/members/util.ts +16 -0
  125. package/src/metrics/constants.ts +9 -0
  126. package/src/reachability/clusterReachability.ts +73 -26
  127. package/src/reachability/index.ts +70 -1
  128. package/src/reachability/reachability.types.ts +6 -0
  129. package/src/reachability/request.ts +7 -0
  130. package/src/reconnection-manager/index.ts +2 -2
  131. package/src/recording-controller/util.ts +17 -13
  132. package/src/roap/index.ts +3 -7
  133. package/src/roap/turnDiscovery.ts +34 -39
  134. package/src/roap/types.ts +23 -0
  135. package/test/unit/spec/controls-options-manager/util.js +120 -0
  136. package/test/unit/spec/locus-info/controlsUtils.js +103 -9
  137. package/test/unit/spec/locus-info/index.js +28 -0
  138. package/test/unit/spec/media/index.ts +36 -16
  139. package/test/unit/spec/meeting/in-meeting-actions.ts +19 -4
  140. package/test/unit/spec/meeting/index.js +528 -34
  141. package/test/unit/spec/meeting/locusMediaRequest.ts +0 -30
  142. package/test/unit/spec/meeting/muteState.js +0 -2
  143. package/test/unit/spec/meeting/request.js +32 -1
  144. package/test/unit/spec/meeting/utils.js +119 -18
  145. package/test/unit/spec/meeting-info/meetinginfov2.js +443 -114
  146. package/test/unit/spec/meetings/index.js +120 -2
  147. package/test/unit/spec/member/index.js +7 -0
  148. package/test/unit/spec/member/util.js +24 -0
  149. package/test/unit/spec/members/index.js +103 -26
  150. package/test/unit/spec/members/request.js +45 -22
  151. package/test/unit/spec/members/utils.js +33 -0
  152. package/test/unit/spec/reachability/clusterReachability.ts +88 -56
  153. package/test/unit/spec/reachability/index.ts +101 -0
  154. package/test/unit/spec/reachability/request.js +47 -2
  155. package/test/unit/spec/reconnection-manager/index.js +4 -4
  156. package/test/unit/spec/roap/turnDiscovery.ts +110 -28
@@ -9,7 +9,9 @@ import {
9
9
  ResultEventData,
10
10
  Events,
11
11
  ClientMediaIpsUpdatedEventData,
12
+ NatTypeUpdatedEventData,
12
13
  } from '@webex/plugin-meetings/src/reachability/clusterReachability'; // replace with actual path
14
+ import { NatType } from 'packages/@webex/plugin-meetings/dist/reachability/reachability.types';
13
15
 
14
16
  describe('ClusterReachability', () => {
15
17
  let previousRTCPeerConnection;
@@ -17,15 +19,17 @@ describe('ClusterReachability', () => {
17
19
  let fakePeerConnection;
18
20
  let gatherIceCandidatesSpy;
19
21
 
20
- const emittedEvents: Record<Events, (ResultEventData | ClientMediaIpsUpdatedEventData)[]> = {
22
+ const emittedEvents: Record<Events, (ResultEventData | ClientMediaIpsUpdatedEventData | NatTypeUpdatedEventData)[]> = {
21
23
  [Events.resultReady]: [],
22
24
  [Events.clientMediaIpsUpdated]: [],
25
+ [Events.natTypeUpdated]: [],
23
26
  };
24
27
  const FAKE_OFFER = {type: 'offer', sdp: 'fake sdp'};
25
28
 
26
29
  const resetEmittedEvents = () => {
27
30
  emittedEvents[Events.resultReady].length = 0;
28
31
  emittedEvents[Events.clientMediaIpsUpdated].length = 0;
32
+ emittedEvents[Events.natTypeUpdated].length = 0;
29
33
  };
30
34
  beforeEach(() => {
31
35
  fakePeerConnection = {
@@ -56,6 +60,10 @@ describe('ClusterReachability', () => {
56
60
  clusterReachability.on(Events.clientMediaIpsUpdated, (data: ClientMediaIpsUpdatedEventData) => {
57
61
  emittedEvents[Events.clientMediaIpsUpdated].push(data);
58
62
  });
63
+
64
+ clusterReachability.on(Events.natTypeUpdated, (data: NatTypeUpdatedEventData) => {
65
+ emittedEvents[Events.natTypeUpdated].push(data);
66
+ });
59
67
  });
60
68
 
61
69
  afterEach(() => {
@@ -166,59 +174,6 @@ describe('ClusterReachability', () => {
166
174
  assert.deepEqual(emittedEvents[Events.clientMediaIpsUpdated], []);
167
175
  });
168
176
 
169
- it('resolves and has correct result as soon as it finds that all udp, tcp and tls are reachable', async () => {
170
- const promise = clusterReachability.start();
171
-
172
- await clock.tickAsync(100);
173
- fakePeerConnection.onicecandidate({candidate: {type: 'srflx', address: 'somePublicIp'}});
174
-
175
- // check the right events were emitted
176
- assert.equal(emittedEvents[Events.resultReady].length, 1);
177
- assert.deepEqual(emittedEvents[Events.resultReady][0], {
178
- protocol: 'udp',
179
- result: 'reachable',
180
- latencyInMilliseconds: 100,
181
- clientMediaIPs: ['somePublicIp'],
182
- });
183
-
184
- // clientMediaIpsUpdated shouldn't be emitted, because the IP is already passed in the resultReady event
185
- assert.equal(emittedEvents[Events.clientMediaIpsUpdated].length, 0);
186
-
187
- await clock.tickAsync(100);
188
- fakePeerConnection.onicecandidate({candidate: {type: 'relay', address: 'someTurnRelayIp'}});
189
-
190
- // check the right event was emitted
191
- assert.equal(emittedEvents[Events.resultReady].length, 2);
192
- assert.deepEqual(emittedEvents[Events.resultReady][1], {
193
- protocol: 'tcp',
194
- result: 'reachable',
195
- latencyInMilliseconds: 200,
196
- });
197
- assert.equal(emittedEvents[Events.clientMediaIpsUpdated].length, 0);
198
-
199
- await clock.tickAsync(100);
200
- fakePeerConnection.onicecandidate({
201
- candidate: {type: 'relay', address: 'someTurnRelayIp', port: 443},
202
- });
203
-
204
- // check the right event was emitted
205
- assert.equal(emittedEvents[Events.resultReady].length, 3);
206
- assert.deepEqual(emittedEvents[Events.resultReady][2], {
207
- protocol: 'xtls',
208
- result: 'reachable',
209
- latencyInMilliseconds: 300,
210
- });
211
- assert.equal(emittedEvents[Events.clientMediaIpsUpdated].length, 0);
212
-
213
- await promise;
214
-
215
- assert.deepEqual(clusterReachability.getResult(), {
216
- udp: {result: 'reachable', latencyInMilliseconds: 100, clientMediaIPs: ['somePublicIp']},
217
- tcp: {result: 'reachable', latencyInMilliseconds: 200},
218
- xtls: {result: 'reachable', latencyInMilliseconds: 300},
219
- });
220
- });
221
-
222
177
  it('resolves and returns correct results when aborted before it gets any candidates', async () => {
223
178
  const promise = clusterReachability.start();
224
179
 
@@ -267,7 +222,7 @@ describe('ClusterReachability', () => {
267
222
 
268
223
  await testUtils.flushPromises();
269
224
 
270
- fakePeerConnection.iceConnectionState = 'complete';
225
+ fakePeerConnection.iceGatheringState = 'complete';
271
226
  fakePeerConnection.onicegatheringstatechange();
272
227
  await promise;
273
228
 
@@ -285,7 +240,7 @@ describe('ClusterReachability', () => {
285
240
  await clock.tickAsync(30);
286
241
  fakePeerConnection.onicecandidate({candidate: {type: 'srflx', address: 'somePublicIp1'}});
287
242
 
288
- fakePeerConnection.iceConnectionState = 'complete';
243
+ fakePeerConnection.iceGatheringState = 'complete';
289
244
  fakePeerConnection.onicegatheringstatechange();
290
245
  await promise;
291
246
 
@@ -428,6 +383,9 @@ describe('ClusterReachability', () => {
428
383
  candidate: {type: 'relay', address: 'someTurnRelayIp', port: 443},
429
384
  });
430
385
 
386
+ fakePeerConnection.iceGatheringState = 'complete';
387
+ fakePeerConnection.onicegatheringstatechange();
388
+
431
389
  await promise;
432
390
 
433
391
  assert.deepEqual(clusterReachability.getResult(), {
@@ -440,5 +398,79 @@ describe('ClusterReachability', () => {
440
398
  xtls: {result: 'reachable', latencyInMilliseconds: 40},
441
399
  });
442
400
  });
401
+
402
+ it('determines correctly if symmetric-nat is detected', async () => {
403
+ const promise = clusterReachability.start();
404
+
405
+ // generate candidates with duplicate addresses
406
+ await clock.tickAsync(10);
407
+ fakePeerConnection.onicecandidate({candidate: {type: 'srflx', address: 'somePublicIp1', relatedPort: 3478, port: 1000}});
408
+
409
+ // check events emitted: there shouldn't be any natTypeUpdated emitted
410
+ assert.equal(emittedEvents[Events.natTypeUpdated].length, 0);
411
+
412
+ await clock.tickAsync(10);
413
+ fakePeerConnection.onicecandidate({candidate: {type: 'srflx', address: 'somePublicIp1', relatedPort: 3478, port: 2000}});
414
+
415
+ // should emit natTypeUpdated event
416
+ assert.equal(emittedEvents[Events.natTypeUpdated].length, 1);
417
+ assert.deepEqual(emittedEvents[Events.natTypeUpdated][0], {
418
+ natType: 'symmetric-nat',
419
+ });
420
+
421
+ // send also a relay candidate so that the reachability check finishes
422
+ fakePeerConnection.onicecandidate({candidate: {type: 'relay', address: 'someTurnRelayIp'}});
423
+ fakePeerConnection.onicecandidate({
424
+ candidate: {type: 'relay', address: 'someTurnRelayIp', port: 443},
425
+ });
426
+
427
+ fakePeerConnection.iceGatheringState = 'complete';
428
+ fakePeerConnection.onicegatheringstatechange();
429
+ await clock.tickAsync(10);
430
+
431
+ await promise;
432
+
433
+ assert.deepEqual(clusterReachability.getResult(), {
434
+ udp: {
435
+ result: 'reachable',
436
+ latencyInMilliseconds: 10,
437
+ clientMediaIPs: ['somePublicIp1'],
438
+ },
439
+ tcp: {result: 'reachable', latencyInMilliseconds: 20},
440
+ xtls: {result: 'reachable', latencyInMilliseconds: 20},
441
+ });
442
+ });
443
+
444
+ it('should gather correctly reached subnets', async () => {
445
+ const promise = clusterReachability.start();
446
+
447
+ await clock.tickAsync(10);
448
+ fakePeerConnection.onicecandidate({candidate: {type: 'srflx', url: 'stun:1.2.3.4:5004'}});
449
+ fakePeerConnection.onicecandidate({candidate: {type: 'srflx', url: 'stun:4.3.2.1:5004'}});
450
+ fakePeerConnection.onicecandidate({candidate: {type: 'relay', address: 'someTurnRelayIp'}});
451
+
452
+ clusterReachability.abort();
453
+ await promise;
454
+
455
+ assert.deepEqual(Array.from(clusterReachability.reachedSubnets), [
456
+ '1.2.3.4',
457
+ '4.3.2.1',
458
+ 'someTurnRelayIp'
459
+ ]);
460
+ });
461
+
462
+ it('should store only unique subnet address', async () => {
463
+ const promise = clusterReachability.start();
464
+
465
+ await clock.tickAsync(10);
466
+ fakePeerConnection.onicecandidate({candidate: {type: 'srflx', url: 'stun:1.2.3.4:5004'}});
467
+ fakePeerConnection.onicecandidate({candidate: {type: 'srflx', url: 'stun:1.2.3.4:9000'}});
468
+ fakePeerConnection.onicecandidate({candidate: {type: 'relay', address: '1.2.3.4'}});
469
+
470
+ clusterReachability.abort();
471
+ await promise;
472
+
473
+ assert.deepEqual(Array.from(clusterReachability.reachedSubnets), ['1.2.3.4']);
474
+ });
443
475
  });
444
476
  });
@@ -538,6 +538,14 @@ describe('gatherReachability', () => {
538
538
  assert.equal(storedResultForJoinCookie, JSON.stringify(expectedJoinCookie));
539
539
  };
540
540
 
541
+ it('rejects if reachability is disabled in config', async () => {
542
+ webex.config.meetings.enableReachabilityChecks = false;
543
+
544
+ const reachability = new Reachability(webex);
545
+
546
+ await assert.isRejected(reachability.gatherReachability('test'), 'enableReachabilityChecks is disabled in config');
547
+ });
548
+
541
549
  [
542
550
  // ========================================================================
543
551
  {
@@ -1947,6 +1955,7 @@ describe('gatherReachability', () => {
1947
1955
  receivedEvents[event] = receivedEvents[event] + 1 || 1;
1948
1956
  });
1949
1957
  };
1958
+
1950
1959
  it('works as expected', async () => {
1951
1960
  setListener('reachability:stopped');
1952
1961
  setListener('reachability:done');
@@ -2008,6 +2017,59 @@ describe('gatherReachability', () => {
2008
2017
  assert.equal(receivedEvents['reachability:done'], undefined);
2009
2018
  assert.equal(receivedEvents['reachability:firstResultAvailable'], undefined);
2010
2019
  });
2020
+
2021
+ it('does not fallback when no clusters were reached and min clusters were specified', async () => {
2022
+ setListener('reachability:stopped');
2023
+ setListener('reachability:done');
2024
+ setListener('reachability:firstResultAvailable');
2025
+
2026
+ const mockGetClustersResult = {
2027
+ discoveryOptions: {
2028
+ ['early-call-min-clusters']: 1,
2029
+ },
2030
+ clusters: {
2031
+ clusterA: {
2032
+ udp: [],
2033
+ tcp: [],
2034
+ xtls: [],
2035
+ isVideoMesh: false,
2036
+ },
2037
+ clusterB: {
2038
+ udp: [],
2039
+ tcp: [],
2040
+ xtls: [],
2041
+ isVideoMesh: false,
2042
+ },
2043
+ },
2044
+ joinCookie: {id: 'id'},
2045
+ };
2046
+
2047
+ reachability.reachabilityRequest.getClusters = sinon.stub().returns(mockGetClustersResult);
2048
+
2049
+ const gatherReachabilityFallbackSpy = sinon.spy(reachability, 'gatherReachabilityFallback');
2050
+
2051
+ const resultPromise = reachability.gatherReachability('test');
2052
+
2053
+ await testUtils.flushPromises();
2054
+
2055
+ reachability.stopReachability();
2056
+
2057
+ await resultPromise;
2058
+
2059
+ // simulate a lot of time passing to check that all timers were stopped and nothing else happens
2060
+ clock.tick(99000);
2061
+
2062
+ assert.calledOnceWithExactly(mockClusterReachabilityInstances['clusterA'].abort);
2063
+ assert.calledOnceWithExactly(mockClusterReachabilityInstances['clusterB'].abort);
2064
+
2065
+ assert.calledOnceWithExactly(sendMetricSpy, true);
2066
+
2067
+ assert.equal(receivedEvents['reachability:stopped'], 1);
2068
+ assert.equal(receivedEvents['reachability:done'], undefined);
2069
+ assert.equal(receivedEvents['reachability:firstResultAvailable'], undefined);
2070
+
2071
+ assert.notCalled(gatherReachabilityFallbackSpy);
2072
+ });
2011
2073
  });
2012
2074
  });
2013
2075
 
@@ -2148,6 +2210,7 @@ describe('getReachabilityMetrics', () => {
2148
2210
  reachability_vmn_tcp_failed: 0,
2149
2211
  reachability_vmn_xtls_success: 0,
2150
2212
  reachability_vmn_xtls_failed: 0,
2213
+ natType: 'unknown'
2151
2214
  });
2152
2215
  });
2153
2216
 
@@ -2215,6 +2278,7 @@ describe('getReachabilityMetrics', () => {
2215
2278
  reachability_vmn_tcp_failed: 1,
2216
2279
  reachability_vmn_xtls_success: 0,
2217
2280
  reachability_vmn_xtls_failed: 0,
2281
+ natType: 'unknown'
2218
2282
  }
2219
2283
  );
2220
2284
  });
@@ -2276,6 +2340,7 @@ describe('getReachabilityMetrics', () => {
2276
2340
  reachability_vmn_tcp_failed: 0,
2277
2341
  reachability_vmn_xtls_success: 0,
2278
2342
  reachability_vmn_xtls_failed: 0,
2343
+ natType: 'unknown'
2279
2344
  }
2280
2345
  );
2281
2346
  });
@@ -2337,6 +2402,7 @@ describe('getReachabilityMetrics', () => {
2337
2402
  reachability_vmn_tcp_failed: 3,
2338
2403
  reachability_vmn_xtls_success: 1,
2339
2404
  reachability_vmn_xtls_failed: 1,
2405
+ natType: 'unknown'
2340
2406
  }
2341
2407
  );
2342
2408
  });
@@ -2674,3 +2740,38 @@ describe('sendMetric', () => {
2674
2740
  });
2675
2741
  });
2676
2742
  });
2743
+
2744
+ describe('isSubnetReachable', () => {
2745
+ let webex;
2746
+ let reachability;
2747
+
2748
+ beforeEach(() => {
2749
+ webex = new MockWebex();
2750
+ reachability = new TestReachability(webex);
2751
+
2752
+ reachability.setFakeClusterReachability({
2753
+ cluster1: {
2754
+ reachedSubnets: new Set(['1.2.3.4', '2.3.4.5']),
2755
+ },
2756
+ cluster2: {
2757
+ reachedSubnets: new Set(['3.4.5.6', '4.5.6.7']),
2758
+ },
2759
+ });
2760
+ });
2761
+
2762
+ afterEach(() => {
2763
+ sinon.restore();
2764
+ });
2765
+
2766
+ it('returns true if the subnet is reachable', () => {
2767
+ assert(reachability.isSubnetReachable('1.2.3.4'));
2768
+ });
2769
+
2770
+ it(`returns false if the subnet is unreachable`, () => {
2771
+ assert(!reachability.isSubnetReachable('11.2.3.4'));
2772
+ });
2773
+
2774
+ it('returns null if the subnet is not provided', () => {
2775
+ assert.isNull(reachability.isSubnetReachable(undefined));
2776
+ });
2777
+ });
@@ -12,6 +12,9 @@ describe('plugin-meetings/reachability', () => {
12
12
  let reachabilityRequest;
13
13
  let webex;
14
14
 
15
+ let appType;
16
+ let appVersion;
17
+
15
18
  beforeEach(() => {
16
19
  webex = new MockWebex({
17
20
  children: {
@@ -20,6 +23,14 @@ describe('plugin-meetings/reachability', () => {
20
23
  },
21
24
  });
22
25
 
26
+ webex.config.support = {
27
+ 'appType': 'NetworkChecker',
28
+ 'appVersion': '43.3.0.1',
29
+ }
30
+
31
+ appType = webex?.config?.support?.appType;
32
+ appVersion = webex?.config?.support?.appVersion;
33
+
23
34
  webex.meetings.clientRegion = {
24
35
  countryCode: 'US',
25
36
  regionCode: 'WEST-COAST',
@@ -56,7 +67,9 @@ describe('plugin-meetings/reachability', () => {
56
67
 
57
68
  previousReport = {
58
69
  id: 'fake previous report',
59
- }
70
+ };
71
+
72
+
60
73
  });
61
74
 
62
75
  afterEach(() => {
@@ -79,6 +92,7 @@ describe('plugin-meetings/reachability', () => {
79
92
  'report-version': 1,
80
93
  'early-call-min-clusters': true,
81
94
  },
95
+ 'client-environment': { components: { [appType]: appVersion } },
82
96
  'previous-report': previousReport,
83
97
  trigger: 'startup',
84
98
  },
@@ -105,6 +119,7 @@ describe('plugin-meetings/reachability', () => {
105
119
  'report-version': 1,
106
120
  'early-call-min-clusters': true,
107
121
  },
122
+ 'client-environment': { components: { [appType]: appVersion } },
108
123
  'previous-report': previousReport,
109
124
  trigger: 'early-call/no-min-reached',
110
125
  },
@@ -114,5 +129,35 @@ describe('plugin-meetings/reachability', () => {
114
129
  assert.deepEqual(res.joinCookie, {anycastEntryPoint: "aws-eu-west-1"})
115
130
  assert.notCalled(webex.internal.newMetrics.callDiagnosticLatencies.measureLatency);
116
131
  });
132
+
133
+ it('sends a POST request with the correct params when appVersion is undefined', async () => {
134
+ // Setting appType & appVersion to undefined
135
+ webex.config.support.appType = undefined;
136
+ webex.config.support.appVersion = undefined;
137
+
138
+ const res = await reachabilityRequest.getClusters('startup', IP_VERSION.only_ipv4, previousReport);
139
+ const requestParams = webex.request.getCall(0).args[0];
140
+
141
+ assert.deepEqual(requestParams, {
142
+ method: 'POST',
143
+ resource: `clusters`,
144
+ api: 'calliopeDiscovery',
145
+ shouldRefreshAccessToken: false,
146
+ timeout: 3000,
147
+ body: {
148
+ ipver: IP_VERSION.only_ipv4,
149
+ 'supported-options': {
150
+ 'report-version': 1,
151
+ 'early-call-min-clusters': true,
152
+ },
153
+ 'previous-report': previousReport,
154
+ trigger: 'startup',
155
+ },
156
+ });
157
+
158
+ assert.deepEqual(res.clusters.clusterId, {udp: "testUDP", isVideoMesh: true});
159
+ assert.deepEqual(res.joinCookie, {anycastEntryPoint: "aws-eu-west-1"});
160
+ assert.calledOnceWithExactly(webex.internal.newMetrics.callDiagnosticLatencies.measureLatency, sinon.match.func, 'internal.get.cluster.time');
161
+ });
117
162
  });
118
- });
163
+ });
@@ -60,7 +60,7 @@ describe('plugin-meetings', () => {
60
60
  roap: {
61
61
  doTurnDiscovery: sinon.stub().resolves({
62
62
  turnServerInfo: {
63
- url: 'fake_turn_url',
63
+ urls: ['fake_turn_url1', 'fake_turn_url2'],
64
64
  username: 'fake_turn_username',
65
65
  password: 'fake_turn_password',
66
66
  },
@@ -137,7 +137,7 @@ describe('plugin-meetings', () => {
137
137
  assert.calledOnce(fakeMediaConnection.reconnect);
138
138
  assert.calledWith(fakeMediaConnection.reconnect, [
139
139
  {
140
- urls: 'fake_turn_url',
140
+ urls: ['fake_turn_url1', 'fake_turn_url2'],
141
141
  username: 'fake_turn_username',
142
142
  credential: 'fake_turn_password',
143
143
  },
@@ -152,12 +152,12 @@ describe('plugin-meetings', () => {
152
152
  });
153
153
 
154
154
  // this can happen when we land on a video mesh node
155
- it('does not use TURN server if TURN url is an empty string', async () => {
155
+ it('does not use TURN server if TURN urls is an empty array', async () => {
156
156
  const rm = new ReconnectionManager(fakeMeeting);
157
157
 
158
158
  fakeMeeting.roap.doTurnDiscovery.resolves({
159
159
  turnServerInfo: {
160
- url: '',
160
+ urls: [],
161
161
  username: 'whatever',
162
162
  password: 'whatever',
163
163
  },