@webex/plugin-meetings 3.4.0 → 3.5.0-next.2

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 (63) hide show
  1. package/dist/breakouts/breakout.js +1 -1
  2. package/dist/breakouts/index.js +1 -1
  3. package/dist/interpretation/index.js +1 -1
  4. package/dist/interpretation/siLanguage.js +1 -1
  5. package/dist/media/index.js +6 -9
  6. package/dist/media/index.js.map +1 -1
  7. package/dist/meeting/index.js +151 -50
  8. package/dist/meeting/index.js.map +1 -1
  9. package/dist/meeting/util.js +1 -0
  10. package/dist/meeting/util.js.map +1 -1
  11. package/dist/meetings/index.js +11 -2
  12. package/dist/meetings/index.js.map +1 -1
  13. package/dist/reachability/index.js +175 -103
  14. package/dist/reachability/index.js.map +1 -1
  15. package/dist/reconnection-manager/index.js +1 -1
  16. package/dist/reconnection-manager/index.js.map +1 -1
  17. package/dist/rtcMetrics/index.js +26 -6
  18. package/dist/rtcMetrics/index.js.map +1 -1
  19. package/dist/types/meeting/index.d.ts +22 -2
  20. package/dist/types/meetings/index.d.ts +4 -2
  21. package/dist/types/reachability/index.d.ts +14 -2
  22. package/dist/types/rtcMetrics/index.d.ts +11 -1
  23. package/dist/webinar/index.js +1 -1
  24. package/package.json +22 -22
  25. package/src/media/index.ts +5 -9
  26. package/src/meeting/index.ts +88 -10
  27. package/src/meeting/util.ts +2 -0
  28. package/src/meetings/index.ts +11 -4
  29. package/src/reachability/index.ts +49 -4
  30. package/src/reconnection-manager/index.ts +1 -1
  31. package/src/rtcMetrics/index.ts +25 -5
  32. package/test/integration/spec/converged-space-meetings.js +1 -1
  33. package/test/unit/spec/breakouts/index.ts +1 -0
  34. package/test/unit/spec/interceptors/locusRetry.ts +11 -10
  35. package/test/unit/spec/media/MediaConnectionAwaiter.ts +1 -0
  36. package/test/unit/spec/media/index.ts +34 -7
  37. package/test/unit/spec/media/properties.ts +1 -1
  38. package/test/unit/spec/meeting/connectionStateHandler.ts +1 -0
  39. package/test/unit/spec/meeting/index.js +116 -12
  40. package/test/unit/spec/meeting/locusMediaRequest.ts +3 -2
  41. package/test/unit/spec/meeting/request.js +1 -0
  42. package/test/unit/spec/meeting/utils.js +4 -0
  43. package/test/unit/spec/meeting-info/meetinginfov2.js +10 -11
  44. package/test/unit/spec/meeting-info/request.js +1 -1
  45. package/test/unit/spec/meetings/index.js +40 -5
  46. package/test/unit/spec/members/request.js +2 -1
  47. package/test/unit/spec/multistream/mediaRequestManager.ts +1 -0
  48. package/test/unit/spec/multistream/receiveSlot.ts +1 -0
  49. package/test/unit/spec/multistream/receiveSlotManager.ts +1 -0
  50. package/test/unit/spec/multistream/remoteMedia.ts +1 -0
  51. package/test/unit/spec/multistream/remoteMediaGroup.ts +1 -0
  52. package/test/unit/spec/multistream/remoteMediaManager.ts +1 -0
  53. package/test/unit/spec/multistream/sendSlotManager.ts +1 -0
  54. package/test/unit/spec/personal-meeting-room/personal-meeting-room.js +0 -1
  55. package/test/unit/spec/reachability/index.ts +211 -13
  56. package/test/unit/spec/reachability/request.js +1 -0
  57. package/test/unit/spec/roap/request.ts +1 -0
  58. package/test/unit/spec/rtcMetrics/index.ts +31 -0
  59. package/dist/networkQualityMonitor/index.js +0 -227
  60. package/dist/networkQualityMonitor/index.js.map +0 -1
  61. package/dist/types/networkQualityMonitor/index.d.ts +0 -70
  62. package/src/networkQualityMonitor/index.ts +0 -211
  63. package/test/unit/spec/networkQualityMonitor/index.js +0 -99
@@ -1,3 +1,4 @@
1
+ import 'jsdom-global/register';
1
2
  import sinon from 'sinon';
2
3
  import {assert} from '@webex/test-helper-chai';
3
4
  import MockWebex from '@webex/test-helper-mock-webex';
@@ -1,3 +1,4 @@
1
+ import 'jsdom-global/register';
1
2
  import sinon from 'sinon';
2
3
  import {assert} from '@webex/test-helper-chai';
3
4
  import Meetings from '@webex/plugin-meetings';
@@ -71,6 +72,7 @@ describe('plugin-meetings', () => {
71
72
  assert.calledOnce(meeting.updateLLMConnection);
72
73
  assert.calledOnce(meeting.breakouts.cleanUp);
73
74
  assert.calledOnce(meeting.simultaneousInterpretation.cleanUp);
75
+ assert.calledOnce(webex.internal.device.meetingEnded);
74
76
  });
75
77
 
76
78
  it('do clean up on meeting object with LLM disabled', async () => {
@@ -87,6 +89,7 @@ describe('plugin-meetings', () => {
87
89
  assert.notCalled(meeting.updateLLMConnection);
88
90
  assert.calledOnce(meeting.breakouts.cleanUp);
89
91
  assert.calledOnce(meeting.simultaneousInterpretation.cleanUp);
92
+ assert.calledOnce(webex.internal.device.meetingEnded);
90
93
  });
91
94
 
92
95
  it('do clean up on meeting object with no config', async () => {
@@ -102,6 +105,7 @@ describe('plugin-meetings', () => {
102
105
  assert.notCalled(meeting.updateLLMConnection);
103
106
  assert.calledOnce(meeting.breakouts.cleanUp);
104
107
  assert.calledOnce(meeting.simultaneousInterpretation.cleanUp);
108
+ assert.calledOnce(webex.internal.device.meetingEnded);
105
109
  });
106
110
  });
107
111
 
@@ -1,7 +1,7 @@
1
1
  /*!
2
2
  * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
3
  */
4
-
4
+ import 'jsdom-global/register';
5
5
  import {assert} from '@webex/test-helper-chai';
6
6
  import sinon from 'sinon';
7
7
  import MockWebex from '@webex/test-helper-mock-webex';
@@ -23,7 +23,6 @@ import MeetingInfoUtil from '@webex/plugin-meetings/src/meeting-info/utilv2';
23
23
  import Metrics from '@webex/plugin-meetings/src/metrics';
24
24
  import BEHAVIORAL_METRICS from '@webex/plugin-meetings/src/metrics/constants';
25
25
  import {forEach} from 'lodash';
26
- import { request } from 'express';
27
26
 
28
27
  describe('plugin-meetings', () => {
29
28
  const conversation = {
@@ -433,7 +432,7 @@ describe('plugin-meetings', () => {
433
432
  assert.deepEqual(submitInternalEventCalls[1].args[0], {
434
433
  name: 'internal.client.meetinginfo.response',
435
434
  });
436
-
435
+
437
436
  assert.deepEqual(submitClientEventCalls[1].args[0], {
438
437
  name: 'client.meetinginfo.response',
439
438
  payload: {
@@ -484,9 +483,9 @@ describe('plugin-meetings', () => {
484
483
  requestResponse.body.confIdStr = confIdStr;
485
484
  }
486
485
  const extraParams = {mtid: 'm9fe0afd8c435e892afcce9ea25b97046', joinTXId: 'TSmrX61wNF'}
487
-
486
+
488
487
  webex.request.resolves(requestResponse);
489
-
488
+
490
489
  const result = await meetingInfo.fetchMeetingInfo(
491
490
  '1234323',
492
491
  DESTINATION_TYPE.MEETING_ID,
@@ -497,7 +496,7 @@ describe('plugin-meetings', () => {
497
496
  extraParams,
498
497
  {meetingId, sendCAevents}
499
498
  );
500
-
499
+
501
500
  assert.calledWith(webex.request, {
502
501
  method: 'POST',
503
502
  service: WBXAPPAPI_SERVICE,
@@ -515,7 +514,7 @@ describe('plugin-meetings', () => {
515
514
  Metrics.sendBehavioralMetric,
516
515
  BEHAVIORAL_METRICS.FETCH_MEETING_INFO_V1_SUCCESS
517
516
  );
518
-
517
+
519
518
  const submitInternalEventCalls = webex.internal.newMetrics.submitInternalEvent.getCalls();
520
519
  const submitClientEventCalls = webex.internal.newMetrics.submitClientEvent.getCalls();
521
520
 
@@ -529,7 +528,7 @@ describe('plugin-meetings', () => {
529
528
  meetingId,
530
529
  }
531
530
  });
532
-
531
+
533
532
  assert.deepEqual(submitInternalEventCalls[1].args[0], {
534
533
  name: 'internal.client.meetinginfo.response',
535
534
  });
@@ -591,7 +590,7 @@ describe('plugin-meetings', () => {
591
590
 
592
591
  const submitInternalEventCalls = webex.internal.newMetrics.submitInternalEvent.getCalls();
593
592
  const submitClientEventCalls = webex.internal.newMetrics.submitClientEvent.getCalls();
594
-
593
+
595
594
  assert.deepEqual(submitInternalEventCalls[0].args[0], {
596
595
  name: 'internal.client.meetinginfo.request',
597
596
  });
@@ -601,7 +600,7 @@ describe('plugin-meetings', () => {
601
600
  meetingId: 'meetingId',
602
601
  }
603
602
  });
604
-
603
+
605
604
  assert.deepEqual(submitInternalEventCalls[1].args[0], {
606
605
  name: 'internal.client.meetinginfo.response',
607
606
  });
@@ -629,7 +628,7 @@ describe('plugin-meetings', () => {
629
628
  it(`should not send CA metric if meetingId is not provided disregarding if sendCAevents is ${sendCAevents}`, async () => {
630
629
  const message = 'a message';
631
630
  const meetingInfoData = 'meeting info';
632
-
631
+
633
632
  webex.request = sinon.stub().rejects({
634
633
  statusCode: 403,
635
634
  body: {message, code: 403102, data: {meetingInfo: meetingInfoData}},
@@ -1,7 +1,7 @@
1
1
  /*!
2
2
  * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
3
  */
4
-
4
+ import 'jsdom-global/register';
5
5
  import {assert} from '@webex/test-helper-chai';
6
6
  import sinon from 'sinon';
7
7
  import MockWebex from '@webex/test-helper-mock-webex';
@@ -79,6 +79,7 @@ describe('plugin-meetings', () => {
79
79
  let locusInfo;
80
80
  let services;
81
81
  let catalog;
82
+ let startReachabilityStub;
82
83
 
83
84
  describe('meetings index', () => {
84
85
  beforeEach(() => {
@@ -129,9 +130,7 @@ describe('plugin-meetings', () => {
129
130
  logger,
130
131
  });
131
132
 
132
- Object.assign(webex.meetings, {
133
- startReachability: sinon.stub().returns(Promise.resolve()),
134
- });
133
+ startReachabilityStub = sinon.stub(webex.meetings, 'startReachability').resolves();
135
134
 
136
135
  Object.assign(webex.internal, {
137
136
  llm: {on: sinon.stub()},
@@ -197,6 +196,34 @@ describe('plugin-meetings', () => {
197
196
  assert.calledOnce(MeetingsUtil.checkH264Support);
198
197
  });
199
198
 
199
+ describe('#startReachability', () => {
200
+ let gatherReachabilitySpy;
201
+ let fakeResult = {id: 'fake-result'};
202
+
203
+ beforeEach(() => {
204
+ startReachabilityStub.restore();
205
+ gatherReachabilitySpy = sinon
206
+ .stub(webex.meetings.getReachability(), 'gatherReachability')
207
+ .resolves(fakeResult);
208
+ });
209
+
210
+ it('should gather reachability with default trigger value', async () => {
211
+ const result = await webex.meetings.startReachability();
212
+
213
+ assert.calledOnceWithExactly(gatherReachabilitySpy, 'client');
214
+ assert.equal(result, fakeResult);
215
+ });
216
+
217
+ it('should gather reachability and pass custom trigger value', async () => {
218
+ const trigger = 'custom-trigger';
219
+
220
+ const result = await webex.meetings.startReachability(trigger);
221
+
222
+ assert.calledOnceWithExactly(gatherReachabilitySpy, trigger);
223
+ assert.equal(result, fakeResult);
224
+ });
225
+ });
226
+
200
227
  describe('#_toggleUnifiedMeetings', () => {
201
228
  it('should have toggleUnifiedMeetings', () => {
202
229
  assert.equal(typeof webex.meetings._toggleUnifiedMeetings, 'function');
@@ -726,7 +753,9 @@ describe('plugin-meetings', () => {
726
753
 
727
754
  const FAKE_USE_RANDOM_DELAY = true;
728
755
  const correlationId = 'my-correlationId';
756
+ const sessionCorrelationId = 'my-session-correlationId';
729
757
  const callStateForMetrics = {
758
+ sessionCorrelationId: 'my-session-correlationId2',
730
759
  correlationId: 'my-correlationId2',
731
760
  joinTrigger: 'my-join-trigger',
732
761
  loginType: 'my-login-type',
@@ -742,11 +771,15 @@ describe('plugin-meetings', () => {
742
771
  {},
743
772
  correlationId,
744
773
  true,
745
- callStateForMetrics
774
+ callStateForMetrics,
775
+ undefined,
776
+ undefined,
777
+ sessionCorrelationId
746
778
  );
747
779
  assert.calledOnceWithExactly(fakeMeeting.setCallStateForMetrics, {
748
780
  ...callStateForMetrics,
749
781
  correlationId,
782
+ sessionCorrelationId,
750
783
  });
751
784
  });
752
785
 
@@ -787,13 +820,14 @@ describe('plugin-meetings', () => {
787
820
  undefined,
788
821
  meetingInfo,
789
822
  'meetingLookupURL',
823
+ sessionCorrelationId
790
824
  ],
791
825
  [
792
826
  test1,
793
827
  test2,
794
828
  FAKE_USE_RANDOM_DELAY,
795
829
  {},
796
- {correlationId},
830
+ {correlationId, sessionCorrelationId},
797
831
  true,
798
832
  meetingInfo,
799
833
  'meetingLookupURL',
@@ -1692,6 +1726,7 @@ describe('plugin-meetings', () => {
1692
1726
  const expectedMeetingData = {
1693
1727
  correlationId: 'my-correlationId',
1694
1728
  callStateForMetrics: {
1729
+ sessionCorrelationId: '',
1695
1730
  correlationId: 'my-correlationId',
1696
1731
  joinTrigger: 'my-join-trigger',
1697
1732
  loginType: 'my-login-type',
@@ -1,3 +1,4 @@
1
+ import 'jsdom-global/register';
1
2
  import sinon from 'sinon';
2
3
  import chai from 'chai';
3
4
  import uuid from 'uuid';
@@ -131,7 +132,7 @@ describe('plugin-meetings', () => {
131
132
  locusUrl: url1,
132
133
  memberIds: ['1', '2'],
133
134
  };
134
-
135
+
135
136
  await membersRequest.admitMember(options)
136
137
 
137
138
  checkRequest({
@@ -1,3 +1,4 @@
1
+ import 'jsdom-global/register';
1
2
  import {MediaRequestManager} from '@webex/plugin-meetings/src/multistream/mediaRequestManager';
2
3
  import {ReceiveSlot} from '@webex/plugin-meetings/src/multistream/receiveSlot';
3
4
  import sinon from 'sinon';
@@ -1,4 +1,5 @@
1
1
  /* eslint-disable require-jsdoc */
2
+ import 'jsdom-global/register';
2
3
  import EventEmitter from 'events';
3
4
 
4
5
  import {MediaType, ReceiveSlotEvents as WcmeReceiveSlotEvents} from '@webex/internal-media-core';
@@ -1,3 +1,4 @@
1
+ import 'jsdom-global/register';
1
2
  import sinon from 'sinon';
2
3
  import {assert} from '@webex/test-helper-chai';
3
4
  import {MediaType} from '@webex/internal-media-core';
@@ -1,4 +1,5 @@
1
1
  /* eslint-disable require-jsdoc */
2
+ import 'jsdom-global/register';
2
3
  import EventEmitter from 'events';
3
4
 
4
5
  import {MediaType} from '@webex/internal-media-core';
@@ -1,3 +1,4 @@
1
+ import 'jsdom-global/register';
1
2
  import EventEmitter from 'events';
2
3
 
3
4
  import {MediaType} from '@webex/internal-media-core';
@@ -1,4 +1,5 @@
1
1
  /* eslint-disable require-jsdoc */
2
+ import 'jsdom-global/register';
2
3
  import EventEmitter from 'events';
3
4
 
4
5
  import {MediaType} from '@webex/internal-media-core';
@@ -1,3 +1,4 @@
1
+ import 'jsdom-global/register';
1
2
  import SendSlotManager from '@webex/plugin-meetings/src/multistream/sendSlotManager';
2
3
  import { LocalStream, MediaType, MultistreamRoapMediaConnection } from "@webex/internal-media-core";
3
4
  import {expect} from '@webex/test-helper-chai';
@@ -1,7 +1,6 @@
1
1
  /*!
2
2
  * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
3
  */
4
-
5
4
  import 'jsdom-global/register';
6
5
  import {assert} from '@webex/test-helper-chai';
7
6
  import sinon from 'sinon';
@@ -4,10 +4,9 @@ import sinon from 'sinon';
4
4
  import EventEmitter from 'events';
5
5
  import testUtils from '../../../utils/testUtils';
6
6
  import Reachability, {
7
- ReachabilityResults,
8
7
  ReachabilityResultsForBackend,
9
8
  } from '@webex/plugin-meetings/src/reachability/';
10
- import { ClusterNode } from '../../../../src/reachability/request';
9
+ import {ClusterNode} from '../../../../src/reachability/request';
11
10
  import MeetingUtil from '@webex/plugin-meetings/src/meeting/util';
12
11
  import * as ClusterReachabilityModule from '@webex/plugin-meetings/src/reachability/clusterReachability';
13
12
  import Metrics from '@webex/plugin-meetings/src/metrics';
@@ -145,7 +144,6 @@ describe('isAnyPublicClusterReachable', () => {
145
144
  });
146
145
  });
147
146
 
148
-
149
147
  describe('isWebexMediaBackendUnreachable', () => {
150
148
  let webex;
151
149
 
@@ -486,6 +484,16 @@ describe('gatherReachability', () => {
486
484
  JSON.stringify({old: 'joinCookie'})
487
485
  );
488
486
 
487
+ webex.internal.device.ipNetworkDetector = {
488
+ supportsIpV4: false,
489
+ supportsIpV6: false,
490
+ firstIpV4: -1,
491
+ firstIpV6: -1,
492
+ firstMdns: -1,
493
+ totalTime: -1,
494
+ detect: sinon.stub().resolves(),
495
+ };
496
+
489
497
  clock = sinon.useFakeTimers();
490
498
 
491
499
  mockClusterReachabilityInstances = {};
@@ -498,6 +506,11 @@ describe('gatherReachability', () => {
498
506
  mockClusterReachabilityInstances[id] = mockInstance;
499
507
  return mockInstance;
500
508
  });
509
+
510
+ webex.config.meetings.experimental = {
511
+ enableTcpReachability: false,
512
+ enableTlsReachability: false,
513
+ };
501
514
  });
502
515
 
503
516
  afterEach(() => {
@@ -1035,6 +1048,16 @@ describe('gatherReachability', () => {
1035
1048
  enableTlsReachability: true,
1036
1049
  };
1037
1050
 
1051
+ // the metrics related to ipver and trigger are not tested in these tests and are all the same, so setting them up here
1052
+ const expectedMetricsFull = {
1053
+ ...expectedMetrics,
1054
+ ipver_firstIpV4: -1,
1055
+ ipver_firstIpV6: -1,
1056
+ ipver_firstMdns: -1,
1057
+ ipver_totalTime: -1,
1058
+ trigger: 'test',
1059
+ };
1060
+
1038
1061
  const receivedEvents = {
1039
1062
  done: 0,
1040
1063
  firstResultAvailable: {
@@ -1064,7 +1087,7 @@ describe('gatherReachability', () => {
1064
1087
 
1065
1088
  reachability.reachabilityRequest.getClusters = sinon.stub().returns(mockGetClustersResult);
1066
1089
 
1067
- const resultPromise = reachability.gatherReachability();
1090
+ const resultPromise = reachability.gatherReachability('test');
1068
1091
 
1069
1092
  await testUtils.flushPromises();
1070
1093
 
@@ -1119,11 +1142,122 @@ describe('gatherReachability', () => {
1119
1142
  assert.calledWith(
1120
1143
  Metrics.sendBehavioralMetric,
1121
1144
  'js_sdk_reachability_completed',
1122
- expectedMetrics
1145
+ expectedMetricsFull
1123
1146
  );
1124
1147
  })
1125
1148
  );
1126
1149
 
1150
+ it('sends the trigger parameter in the metrics', async () => {
1151
+ const reachability = new TestReachability(webex);
1152
+
1153
+ const mockGetClustersResult = {
1154
+ clusters: {
1155
+ clusterA: {
1156
+ udp: ['udp-url'],
1157
+ tcp: [],
1158
+ xtls: [],
1159
+ isVideoMesh: false,
1160
+ },
1161
+ },
1162
+ joinCookie: {id: 'id'},
1163
+ };
1164
+
1165
+ reachability.reachabilityRequest.getClusters = sinon.stub().returns(mockGetClustersResult);
1166
+
1167
+ const resultPromise = reachability.gatherReachability('some trigger');
1168
+
1169
+ // let it time out
1170
+ await testUtils.flushPromises();
1171
+ clock.tick(15000);
1172
+ await resultPromise;
1173
+
1174
+ // check the metric contains the right trigger value
1175
+ assert.calledWith(
1176
+ Metrics.sendBehavioralMetric,
1177
+ 'js_sdk_reachability_completed',
1178
+ sinon.match({trigger: 'some trigger'})
1179
+ );
1180
+ });
1181
+
1182
+ it(`starts ip network version detection and includes the results in the metrics`, async () => {
1183
+ webex.config.meetings.experimental = {
1184
+ enableTcpReachability: true,
1185
+ enableTlsReachability: true,
1186
+ };
1187
+ webex.internal.device.ipNetworkDetector = {
1188
+ supportsIpV4: true,
1189
+ supportsIpV6: true,
1190
+ firstIpV4: 10,
1191
+ firstIpV6: 20,
1192
+ firstMdns: 30,
1193
+ totalTime: 40,
1194
+ detect: sinon.stub().resolves(),
1195
+ };
1196
+
1197
+ const receivedEvents = {
1198
+ done: 0,
1199
+ };
1200
+
1201
+ const reachability = new Reachability(webex);
1202
+
1203
+ reachability.on('reachability:done', () => {
1204
+ receivedEvents.done += 1;
1205
+ });
1206
+
1207
+ // simulate having just 1 cluster, we don't need more for this test
1208
+ reachability.reachabilityRequest.getClusters = sinon.stub().returns({
1209
+ clusters: {
1210
+ publicCluster: {
1211
+ udp: ['udp-url'],
1212
+ tcp: [],
1213
+ xtls: [],
1214
+ isVideoMesh: false,
1215
+ },
1216
+ },
1217
+ joinCookie: {id: 'id'},
1218
+ });
1219
+
1220
+ const resultPromise = reachability.gatherReachability('test');
1221
+
1222
+ await testUtils.flushPromises();
1223
+
1224
+ // trigger mock result events from ClusterReachability instance
1225
+ mockClusterReachabilityInstances['publicCluster'].emitFakeResult('udp', {
1226
+ result: 'reachable',
1227
+ clientMediaIPs: ['1.2.3.4'],
1228
+ latencyInMilliseconds: 100,
1229
+ });
1230
+
1231
+ await resultPromise;
1232
+
1233
+ // check events emitted by Reachability class
1234
+ assert.equal(receivedEvents['done'], 1);
1235
+
1236
+ // and that ip network detection was started
1237
+ assert.calledOnceWithExactly(webex.internal.device.ipNetworkDetector.detect);
1238
+
1239
+ // finally, check the metrics - they should contain values from ipNetworkDetector
1240
+ assert.calledWith(Metrics.sendBehavioralMetric, 'js_sdk_reachability_completed', {
1241
+ vmn_udp_min: -1,
1242
+ vmn_udp_max: -1,
1243
+ vmn_udp_average: -1,
1244
+ public_udp_min: 100,
1245
+ public_udp_max: 100,
1246
+ public_udp_average: 100,
1247
+ public_tcp_min: -1,
1248
+ public_tcp_max: -1,
1249
+ public_tcp_average: -1,
1250
+ public_xtls_min: -1,
1251
+ public_xtls_max: -1,
1252
+ public_xtls_average: -1,
1253
+ ipver_firstIpV4: webex.internal.device.ipNetworkDetector.firstIpV4,
1254
+ ipver_firstIpV6: webex.internal.device.ipNetworkDetector.firstIpV6,
1255
+ ipver_firstMdns: webex.internal.device.ipNetworkDetector.firstMdns,
1256
+ ipver_totalTime: webex.internal.device.ipNetworkDetector.totalTime,
1257
+ trigger: 'test',
1258
+ });
1259
+ });
1260
+
1127
1261
  it('keeps updating reachability results after the 3s public cloud timeout expires', async () => {
1128
1262
  webex.config.meetings.experimental = {
1129
1263
  enableTcpReachability: true,
@@ -1152,7 +1286,7 @@ describe('gatherReachability', () => {
1152
1286
 
1153
1287
  reachability.reachabilityRequest.getClusters = sinon.stub().returns(mockGetClustersResult);
1154
1288
 
1155
- const resultPromise = reachability.gatherReachability();
1289
+ const resultPromise = reachability.gatherReachability('test');
1156
1290
 
1157
1291
  await testUtils.flushPromises();
1158
1292
 
@@ -1245,7 +1379,7 @@ describe('gatherReachability', () => {
1245
1379
 
1246
1380
  reachability.reachabilityRequest.getClusters = sinon.stub().returns(mockGetClustersResult);
1247
1381
 
1248
- const resultPromise = reachability.gatherReachability();
1382
+ const resultPromise = reachability.gatherReachability('test');
1249
1383
 
1250
1384
  await testUtils.flushPromises();
1251
1385
 
@@ -1286,7 +1420,7 @@ describe('gatherReachability', () => {
1286
1420
 
1287
1421
  reachability.reachabilityRequest.getClusters = sinon.stub().throws();
1288
1422
 
1289
- const result = await reachability.gatherReachability();
1423
+ const result = await reachability.gatherReachability('test');
1290
1424
 
1291
1425
  assert.empty(result);
1292
1426
 
@@ -1304,7 +1438,7 @@ describe('gatherReachability', () => {
1304
1438
  reachability.reachabilityRequest.getClusters = sinon.stub().returns(getClustersResult);
1305
1439
  (reachability as any).performReachabilityChecks = sinon.stub().throws();
1306
1440
 
1307
- const result = await reachability.gatherReachability();
1441
+ const result = await reachability.gatherReachability('test');
1308
1442
 
1309
1443
  assert.empty(result);
1310
1444
 
@@ -1339,7 +1473,7 @@ describe('gatherReachability', () => {
1339
1473
 
1340
1474
  reachability.reachabilityRequest.getClusters = sinon.stub().returns(getClustersResult);
1341
1475
 
1342
- const promise = reachability.gatherReachability();
1476
+ const promise = reachability.gatherReachability('test');
1343
1477
 
1344
1478
  await simulateTimeout();
1345
1479
  await promise;
@@ -1385,7 +1519,7 @@ describe('gatherReachability', () => {
1385
1519
 
1386
1520
  reachability.reachabilityRequest.getClusters = sinon.stub().returns(getClustersResult);
1387
1521
 
1388
- const promise = reachability.gatherReachability();
1522
+ const promise = reachability.gatherReachability('test');
1389
1523
  await simulateTimeout();
1390
1524
  await promise;
1391
1525
 
@@ -1419,7 +1553,7 @@ describe('gatherReachability', () => {
1419
1553
 
1420
1554
  reachability.reachabilityRequest.getClusters = sinon.stub().returns(getClustersResult);
1421
1555
 
1422
- const promise = reachability.gatherReachability();
1556
+ const promise = reachability.gatherReachability('test');
1423
1557
 
1424
1558
  await simulateTimeout();
1425
1559
  await promise;
@@ -1454,7 +1588,7 @@ describe('gatherReachability', () => {
1454
1588
 
1455
1589
  reachability.reachabilityRequest.getClusters = sinon.stub().returns(getClustersResult);
1456
1590
 
1457
- const promise = reachability.gatherReachability();
1591
+ const promise = reachability.gatherReachability('test');
1458
1592
 
1459
1593
  await simulateTimeout();
1460
1594
  await promise;
@@ -1466,6 +1600,70 @@ describe('gatherReachability', () => {
1466
1600
  xtls: [], // empty list because TLS is disabled in config
1467
1601
  });
1468
1602
  });
1603
+
1604
+ it('retry of getClusters is succesfull', async () => {
1605
+ webex.config.meetings.experimental = {
1606
+ enableTcpReachability: true,
1607
+ enableTlsReachability: false,
1608
+ };
1609
+
1610
+ const getClustersResult = {
1611
+ clusters: {
1612
+ 'cluster name': {
1613
+ udp: ['testUDP1', 'testUDP2'],
1614
+ tcp: ['testTCP1', 'testTCP2'],
1615
+ xtls: ['testXTLS1', 'testXTLS2'],
1616
+ isVideoMesh: false,
1617
+ },
1618
+ },
1619
+ joinCookie: {id: 'id'},
1620
+ };
1621
+
1622
+ const reachability = new Reachability(webex);
1623
+
1624
+ let getClustersCallCount = 0;
1625
+
1626
+ reachability.reachabilityRequest.getClusters = sinon.stub().callsFake(() => {
1627
+ getClustersCallCount++;
1628
+
1629
+ if (getClustersCallCount == 1) {
1630
+ throw new Error('fake error');
1631
+ }
1632
+
1633
+ return getClustersResult;
1634
+ });
1635
+
1636
+ const promise = reachability.gatherReachability('test');
1637
+
1638
+ await simulateTimeout();
1639
+ await promise;
1640
+
1641
+ assert.equal(getClustersCallCount, 2);
1642
+
1643
+ assert.calledOnce(clusterReachabilityCtorStub);
1644
+ });
1645
+
1646
+ it('two failed calls to getClusters', async () => {
1647
+ const reachability = new Reachability(webex);
1648
+
1649
+ let getClustersCallCount = 0;
1650
+
1651
+ reachability.reachabilityRequest.getClusters = sinon.stub().callsFake(() => {
1652
+ getClustersCallCount++;
1653
+
1654
+ throw new Error('fake error');
1655
+ });
1656
+
1657
+ const promise = reachability.gatherReachability('test');
1658
+
1659
+ await simulateTimeout();
1660
+
1661
+ await promise;
1662
+
1663
+ assert.equal(getClustersCallCount, 2);
1664
+
1665
+ assert.neverCalledWith(clusterReachabilityCtorStub);
1666
+ });
1469
1667
  });
1470
1668
 
1471
1669
  describe('getReachabilityResults', () => {
@@ -1,3 +1,4 @@
1
+ import 'jsdom-global/register';
1
2
  import sinon from 'sinon';
2
3
  import {assert} from '@webex/test-helper-chai';
3
4
  import MockWebex from '@webex/test-helper-mock-webex';
@@ -1,3 +1,4 @@
1
+ import 'jsdom-global/register';
1
2
  import sinon from 'sinon';
2
3
  import {assert} from '@webex/test-helper-chai';
3
4
  import MockWebex from '@webex/test-helper-mock-webex';