@webex/plugin-meetings 3.6.0-next.9 → 3.7.0-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.
- package/README.md +2 -1
- package/dist/breakouts/breakout.js +1 -1
- package/dist/breakouts/index.js +1 -1
- package/dist/config.js +2 -1
- package/dist/config.js.map +1 -1
- package/dist/constants.js +24 -2
- package/dist/constants.js.map +1 -1
- package/dist/controls-options-manager/enums.js +1 -0
- package/dist/controls-options-manager/enums.js.map +1 -1
- package/dist/controls-options-manager/index.js +10 -3
- package/dist/controls-options-manager/index.js.map +1 -1
- package/dist/controls-options-manager/types.js.map +1 -1
- package/dist/controls-options-manager/util.js +12 -0
- package/dist/controls-options-manager/util.js.map +1 -1
- package/dist/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/locus-info/controlsUtils.js +28 -4
- package/dist/locus-info/controlsUtils.js.map +1 -1
- package/dist/locus-info/fullState.js +2 -1
- package/dist/locus-info/fullState.js.map +1 -1
- package/dist/locus-info/index.js +61 -3
- package/dist/locus-info/index.js.map +1 -1
- package/dist/meeting/in-meeting-actions.js +19 -1
- package/dist/meeting/in-meeting-actions.js.map +1 -1
- package/dist/meeting/index.js +564 -441
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/locusMediaRequest.js +2 -6
- package/dist/meeting/locusMediaRequest.js.map +1 -1
- package/dist/meeting/request.js +21 -29
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting/util.js +94 -59
- package/dist/meeting/util.js.map +1 -1
- package/dist/meetings/index.js +2 -0
- package/dist/meetings/index.js.map +1 -1
- package/dist/members/index.js +3 -2
- package/dist/members/index.js.map +1 -1
- package/dist/members/util.js +9 -5
- package/dist/members/util.js.map +1 -1
- package/dist/reachability/clusterReachability.js +0 -4
- package/dist/reachability/clusterReachability.js.map +1 -1
- package/dist/reachability/index.js +433 -136
- package/dist/reachability/index.js.map +1 -1
- package/dist/reachability/reachability.types.js +7 -0
- package/dist/reachability/reachability.types.js.map +1 -0
- package/dist/reachability/request.js +23 -9
- package/dist/reachability/request.js.map +1 -1
- package/dist/roap/index.js +5 -7
- package/dist/roap/index.js.map +1 -1
- package/dist/roap/request.js +45 -79
- package/dist/roap/request.js.map +1 -1
- package/dist/roap/turnDiscovery.js +3 -6
- package/dist/roap/turnDiscovery.js.map +1 -1
- package/dist/types/config.d.ts +1 -0
- package/dist/types/constants.d.ts +19 -0
- package/dist/types/controls-options-manager/enums.d.ts +2 -1
- package/dist/types/controls-options-manager/index.d.ts +2 -1
- package/dist/types/controls-options-manager/types.d.ts +2 -0
- package/dist/types/locus-info/index.d.ts +9 -0
- package/dist/types/meeting/in-meeting-actions.d.ts +18 -0
- package/dist/types/meeting/index.d.ts +14 -3
- package/dist/types/meeting/locusMediaRequest.d.ts +2 -3
- package/dist/types/meeting/request.d.ts +2 -2
- package/dist/types/meeting/util.d.ts +2 -2
- package/dist/types/meetings/index.d.ts +1 -1
- package/dist/types/members/index.d.ts +2 -1
- package/dist/types/members/util.d.ts +3 -1
- package/dist/types/reachability/clusterReachability.d.ts +1 -10
- package/dist/types/reachability/index.d.ts +74 -35
- package/dist/types/reachability/reachability.types.d.ts +64 -0
- package/dist/types/reachability/request.d.ts +5 -1
- package/dist/types/roap/request.d.ts +1 -13
- package/dist/webinar/index.js +32 -19
- package/dist/webinar/index.js.map +1 -1
- package/package.json +22 -22
- package/src/config.ts +1 -0
- package/src/constants.ts +25 -0
- package/src/controls-options-manager/enums.ts +1 -0
- package/src/controls-options-manager/index.ts +19 -2
- package/src/controls-options-manager/types.ts +2 -0
- package/src/controls-options-manager/util.ts +12 -0
- package/src/locus-info/controlsUtils.ts +46 -2
- package/src/locus-info/fullState.ts +1 -0
- package/src/locus-info/index.ts +60 -0
- package/src/meeting/in-meeting-actions.ts +37 -0
- package/src/meeting/index.ts +114 -11
- package/src/meeting/locusMediaRequest.ts +4 -8
- package/src/meeting/request.ts +4 -11
- package/src/meeting/util.ts +24 -4
- package/src/meetings/index.ts +46 -39
- package/src/members/index.ts +4 -2
- package/src/members/util.ts +3 -1
- package/src/reachability/clusterReachability.ts +1 -14
- package/src/reachability/index.ts +285 -77
- package/src/reachability/reachability.types.ts +85 -0
- package/src/reachability/request.ts +55 -30
- package/src/roap/index.ts +4 -5
- package/src/roap/request.ts +30 -44
- package/src/roap/turnDiscovery.ts +2 -4
- package/src/webinar/index.ts +31 -17
- package/test/unit/spec/controls-options-manager/index.js +56 -32
- package/test/unit/spec/controls-options-manager/util.js +44 -0
- package/test/unit/spec/locus-info/controlsUtils.js +80 -4
- package/test/unit/spec/locus-info/index.js +59 -2
- package/test/unit/spec/meeting/in-meeting-actions.ts +18 -0
- package/test/unit/spec/meeting/index.js +231 -100
- package/test/unit/spec/meeting/locusMediaRequest.ts +18 -11
- package/test/unit/spec/meeting/request.js +3 -26
- package/test/unit/spec/meeting/utils.js +53 -13
- package/test/unit/spec/meetings/index.js +16 -1
- package/test/unit/spec/members/index.js +25 -2
- package/test/unit/spec/members/request.js +37 -3
- package/test/unit/spec/members/utils.js +15 -1
- package/test/unit/spec/reachability/index.ts +265 -1
- package/test/unit/spec/reachability/request.js +56 -15
- package/test/unit/spec/roap/index.ts +1 -1
- package/test/unit/spec/roap/request.ts +51 -109
- package/test/unit/spec/roap/turnDiscovery.ts +202 -147
- package/test/unit/spec/webinar/index.ts +82 -16
|
@@ -196,6 +196,7 @@ describe('plugin-meetings', () => {
|
|
|
196
196
|
const permissionToken = 'permission-token';
|
|
197
197
|
const installationId = 'installationId';
|
|
198
198
|
const reachability = 'reachability';
|
|
199
|
+
const clientMediaPreferences = 'clientMediaPreferences';
|
|
199
200
|
|
|
200
201
|
await meetingsRequest.joinMeeting({
|
|
201
202
|
locusUrl,
|
|
@@ -204,6 +205,7 @@ describe('plugin-meetings', () => {
|
|
|
204
205
|
roapMessage,
|
|
205
206
|
reachability,
|
|
206
207
|
permissionToken,
|
|
208
|
+
clientMediaPreferences
|
|
207
209
|
});
|
|
208
210
|
const requestParams = meetingsRequest.request.getCall(0).args[0];
|
|
209
211
|
|
|
@@ -214,6 +216,7 @@ describe('plugin-meetings', () => {
|
|
|
214
216
|
assert.equal(requestParams.body.device.countryCode, 'US');
|
|
215
217
|
assert.equal(requestParams.body.permissionToken, 'permission-token');
|
|
216
218
|
assert.equal(requestParams.body.device.regionCode, 'WEST-COAST');
|
|
219
|
+
assert.equal(requestParams.body.clientMediaPreferences, 'clientMediaPreferences');
|
|
217
220
|
assert.include(requestParams.body.device.localIp, '127.0.0');
|
|
218
221
|
assert.deepEqual(requestParams.body.localMedias, [
|
|
219
222
|
{localSdp: '{"roapMessage":"roap-message","reachability":"reachability"}'},
|
|
@@ -386,32 +389,6 @@ describe('plugin-meetings', () => {
|
|
|
386
389
|
|
|
387
390
|
assert.deepEqual(requestParams.body.alias, undefined);
|
|
388
391
|
});
|
|
389
|
-
|
|
390
|
-
it('includes joinCookie and ipver correctly', async () => {
|
|
391
|
-
const locusUrl = 'locusURL';
|
|
392
|
-
const deviceUrl = 'deviceUrl';
|
|
393
|
-
const correlationId = 'random-uuid';
|
|
394
|
-
const roapMessage = 'roap-message';
|
|
395
|
-
const permissionToken = 'permission-token';
|
|
396
|
-
|
|
397
|
-
await meetingsRequest.joinMeeting({
|
|
398
|
-
locusUrl,
|
|
399
|
-
deviceUrl,
|
|
400
|
-
correlationId,
|
|
401
|
-
roapMessage,
|
|
402
|
-
permissionToken,
|
|
403
|
-
ipVersion: IP_VERSION.ipv4_and_ipv6,
|
|
404
|
-
});
|
|
405
|
-
const requestParams = meetingsRequest.request.getCall(0).args[0];
|
|
406
|
-
|
|
407
|
-
assert.equal(requestParams.method, 'POST');
|
|
408
|
-
assert.equal(requestParams.uri, `${locusUrl}/participant?alternateRedirect=true`);
|
|
409
|
-
assert.deepEqual(requestParams.body.clientMediaPreferences, {
|
|
410
|
-
joinCookie: {anycastEntryPoint: 'aws-eu-west-1'},
|
|
411
|
-
preferTranscoding: true,
|
|
412
|
-
ipver: 1,
|
|
413
|
-
});
|
|
414
|
-
});
|
|
415
392
|
});
|
|
416
393
|
|
|
417
394
|
describe('#pstn', () => {
|
|
@@ -22,6 +22,12 @@ describe('plugin-meetings', () => {
|
|
|
22
22
|
meetings: Meetings,
|
|
23
23
|
},
|
|
24
24
|
});
|
|
25
|
+
|
|
26
|
+
webex.meetings.reachability = {
|
|
27
|
+
getReachabilityReportToAttachToRoap: sinon.stub().resolves({}),
|
|
28
|
+
getClientMediaPreferences: sinon.stub().resolves({}),
|
|
29
|
+
};
|
|
30
|
+
|
|
25
31
|
const logger = {
|
|
26
32
|
info: sandbox.stub(),
|
|
27
33
|
log: sandbox.stub(),
|
|
@@ -408,17 +414,39 @@ describe('plugin-meetings', () => {
|
|
|
408
414
|
});
|
|
409
415
|
|
|
410
416
|
it('#Should call `meetingRequest.joinMeeting', async () => {
|
|
417
|
+
meeting.isMultistream = true;
|
|
418
|
+
|
|
419
|
+
const FAKE_REACHABILITY_REPORT = {
|
|
420
|
+
id: 'fake reachability report',
|
|
421
|
+
};
|
|
422
|
+
const FAKE_CLIENT_MEDIA_PREFERENCES = {
|
|
423
|
+
id: 'fake client media preferences',
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
webex.meetings.reachability.getReachabilityReportToAttachToRoap.resolves(FAKE_REACHABILITY_REPORT);
|
|
427
|
+
webex.meetings.reachability.getClientMediaPreferences.resolves(FAKE_CLIENT_MEDIA_PREFERENCES);
|
|
428
|
+
|
|
429
|
+
sinon
|
|
430
|
+
.stub(webex.internal.device.ipNetworkDetector, 'supportsIpV4')
|
|
431
|
+
.get(() => true);
|
|
432
|
+
sinon
|
|
433
|
+
.stub(webex.internal.device.ipNetworkDetector, 'supportsIpV6')
|
|
434
|
+
.get(() => true);
|
|
435
|
+
|
|
411
436
|
await MeetingUtil.joinMeeting(meeting, {
|
|
412
437
|
reachability: 'reachability',
|
|
413
438
|
roapMessage: 'roapMessage',
|
|
414
439
|
});
|
|
415
440
|
|
|
441
|
+
assert.calledOnceWithExactly(webex.meetings.reachability.getReachabilityReportToAttachToRoap);
|
|
442
|
+
assert.calledOnceWithExactly(webex.meetings.reachability.getClientMediaPreferences, meeting.isMultistream, IP_VERSION.ipv4_and_ipv6);
|
|
443
|
+
|
|
416
444
|
assert.calledOnce(meeting.meetingRequest.joinMeeting);
|
|
417
445
|
const parameter = meeting.meetingRequest.joinMeeting.getCall(0).args[0];
|
|
418
446
|
|
|
419
447
|
assert.equal(parameter.inviteeAddress, 'meetingJoinUrl');
|
|
420
|
-
assert.equal(parameter.
|
|
421
|
-
assert.equal(parameter.
|
|
448
|
+
assert.equal(parameter.reachability, FAKE_REACHABILITY_REPORT);
|
|
449
|
+
assert.equal(parameter.clientMediaPreferences, FAKE_CLIENT_MEDIA_PREFERENCES);
|
|
422
450
|
assert.equal(parameter.roapMessage, 'roapMessage');
|
|
423
451
|
|
|
424
452
|
assert.calledOnce(meeting.setLocus)
|
|
@@ -445,6 +473,29 @@ describe('plugin-meetings', () => {
|
|
|
445
473
|
});
|
|
446
474
|
});
|
|
447
475
|
|
|
476
|
+
it('should handle failed reachability report retrieval', async () => {
|
|
477
|
+
webex.meetings.reachability.getReachabilityReportToAttachToRoap.rejects(
|
|
478
|
+
new Error('fake error')
|
|
479
|
+
);
|
|
480
|
+
await MeetingUtil.joinMeeting(meeting, {});
|
|
481
|
+
// Verify meeting join still proceeds
|
|
482
|
+
assert.calledOnce(meeting.meetingRequest.joinMeeting);
|
|
483
|
+
});
|
|
484
|
+
|
|
485
|
+
it('should handle failed clientMediaPreferences retrieval', async () => {
|
|
486
|
+
webex.meetings.reachability.getClientMediaPreferences.rejects(new Error('fake error'));
|
|
487
|
+
meeting.isMultistream = true;
|
|
488
|
+
await MeetingUtil.joinMeeting(meeting, {});
|
|
489
|
+
// Verify meeting join still proceeds
|
|
490
|
+
assert.calledOnce(meeting.meetingRequest.joinMeeting);
|
|
491
|
+
const parameter = meeting.meetingRequest.joinMeeting.getCall(0).args[0];
|
|
492
|
+
assert.deepEqual(parameter.clientMediaPreferences, {
|
|
493
|
+
preferTranscoding: false,
|
|
494
|
+
ipver: 0,
|
|
495
|
+
joinCookie: undefined,
|
|
496
|
+
});
|
|
497
|
+
});
|
|
498
|
+
|
|
448
499
|
it('#Should call meetingRequest.joinMeeting with breakoutsSupported=true when passed in as true', async () => {
|
|
449
500
|
await MeetingUtil.joinMeeting(meeting, {
|
|
450
501
|
breakoutsSupported: true,
|
|
@@ -480,17 +531,6 @@ describe('plugin-meetings', () => {
|
|
|
480
531
|
assert.deepEqual(parameter.deviceCapabilities, ['TEST']);
|
|
481
532
|
});
|
|
482
533
|
|
|
483
|
-
it('#Should call meetingRequest.joinMeeting with preferTranscoding=false when multistream is enabled', async () => {
|
|
484
|
-
meeting.isMultistream = true;
|
|
485
|
-
await MeetingUtil.joinMeeting(meeting, {});
|
|
486
|
-
|
|
487
|
-
assert.calledOnce(meeting.meetingRequest.joinMeeting);
|
|
488
|
-
const parameter = meeting.meetingRequest.joinMeeting.getCall(0).args[0];
|
|
489
|
-
|
|
490
|
-
assert.equal(parameter.inviteeAddress, 'meetingJoinUrl');
|
|
491
|
-
assert.equal(parameter.preferTranscoding, false);
|
|
492
|
-
});
|
|
493
|
-
|
|
494
534
|
it('#Should fallback sipUrl if meetingJoinUrl does not exists', async () => {
|
|
495
535
|
meeting.meetingJoinUrl = undefined;
|
|
496
536
|
meeting.sipUri = 'sipUri';
|
|
@@ -2077,6 +2077,21 @@ describe('plugin-meetings', () => {
|
|
|
2077
2077
|
]);
|
|
2078
2078
|
});
|
|
2079
2079
|
|
|
2080
|
+
it('should handle failure to get user information if scopes are insufficient', async () => {
|
|
2081
|
+
loggerProxySpy = sinon.spy(LoggerProxy.logger, 'error');
|
|
2082
|
+
Object.assign(webex.people, {
|
|
2083
|
+
_getMe: sinon.stub().returns(Promise.reject()),
|
|
2084
|
+
});
|
|
2085
|
+
|
|
2086
|
+
await webex.meetings.fetchUserPreferredWebexSite();
|
|
2087
|
+
|
|
2088
|
+
assert.equal(webex.meetings.preferredWebexSite, '');
|
|
2089
|
+
assert.calledOnceWithExactly(
|
|
2090
|
+
loggerProxySpy,
|
|
2091
|
+
'Failed to retrieve user information. No preferredWebexSite will be set'
|
|
2092
|
+
);
|
|
2093
|
+
});
|
|
2094
|
+
|
|
2080
2095
|
const setup = ({me = { type: 'validuser'}, user} = {}) => {
|
|
2081
2096
|
loggerProxySpy = sinon.spy(LoggerProxy.logger, 'error');
|
|
2082
2097
|
assert.deepEqual(webex.internal.services._getCatalog().getAllowedDomains(), []);
|
|
@@ -2093,7 +2108,7 @@ describe('plugin-meetings', () => {
|
|
|
2093
2108
|
|
|
2094
2109
|
Object.assign(webex.people, {
|
|
2095
2110
|
_getMe: sinon.stub().returns(Promise.resolve(me)),
|
|
2096
|
-
|
|
2111
|
+
});
|
|
2097
2112
|
};
|
|
2098
2113
|
|
|
2099
2114
|
it('should not call request.getMeetingPreferences if user is a guest', async () => {
|
|
@@ -660,17 +660,20 @@ describe('plugin-meetings', () => {
|
|
|
660
660
|
resultPromise,
|
|
661
661
|
spies,
|
|
662
662
|
expectedRequestingMemberId,
|
|
663
|
-
expectedLocusUrl
|
|
663
|
+
expectedLocusUrl,
|
|
664
|
+
expectedRoles,
|
|
664
665
|
) => {
|
|
665
666
|
await assert.isFulfilled(resultPromise);
|
|
666
667
|
assert.calledOnceWithExactly(
|
|
667
668
|
spies.generateLowerAllHandsMemberOptions,
|
|
668
669
|
expectedRequestingMemberId,
|
|
669
|
-
expectedLocusUrl
|
|
670
|
+
expectedLocusUrl,
|
|
671
|
+
expectedRoles,
|
|
670
672
|
);
|
|
671
673
|
assert.calledOnceWithExactly(spies.lowerAllHandsMember, {
|
|
672
674
|
requestingParticipantId: expectedRequestingMemberId,
|
|
673
675
|
locusUrl: expectedLocusUrl,
|
|
676
|
+
...(expectedRoles !== undefined && { roles: expectedRoles })
|
|
674
677
|
});
|
|
675
678
|
assert.strictEqual(resultPromise, spies.lowerAllHandsMember.getCall(0).returnValue);
|
|
676
679
|
};
|
|
@@ -707,6 +710,26 @@ describe('plugin-meetings', () => {
|
|
|
707
710
|
|
|
708
711
|
await checkValid(resultPromise, spies, requestingMemberId, url1);
|
|
709
712
|
});
|
|
713
|
+
|
|
714
|
+
it('should make the correct request when called with valid requestingMemberId and roles', async () => {
|
|
715
|
+
const requestingMemberId = 'test-member-id';
|
|
716
|
+
const roles = ['panelist', 'attendee'];
|
|
717
|
+
const { members, spies } = setup('test-locus-url');
|
|
718
|
+
|
|
719
|
+
const resultPromise = members.lowerAllHands(requestingMemberId, roles);
|
|
720
|
+
|
|
721
|
+
await checkValid(resultPromise, spies, requestingMemberId, 'test-locus-url', roles);
|
|
722
|
+
});
|
|
723
|
+
|
|
724
|
+
it('should handle an empty roles array correctly', async () => {
|
|
725
|
+
const requestingMemberId = 'test-member-id';
|
|
726
|
+
const roles = [];
|
|
727
|
+
const { members, spies } = setup('test-locus-url');
|
|
728
|
+
|
|
729
|
+
const resultPromise = members.lowerAllHands(requestingMemberId, roles);
|
|
730
|
+
|
|
731
|
+
await checkValid(resultPromise, spies, requestingMemberId, 'test-locus-url', roles);
|
|
732
|
+
});
|
|
710
733
|
});
|
|
711
734
|
|
|
712
735
|
describe('#editDisplayName', () => {
|
|
@@ -225,7 +225,7 @@ describe('plugin-meetings', () => {
|
|
|
225
225
|
});
|
|
226
226
|
|
|
227
227
|
describe('#assignRolesMember', () => {
|
|
228
|
-
it('sends a PATCH to the locus endpoint', async () => {
|
|
228
|
+
it('sends a assignRolesMember PATCH to the locus endpoint', async () => {
|
|
229
229
|
const locusUrl = url1;
|
|
230
230
|
const memberId = 'test1';
|
|
231
231
|
const roles = [
|
|
@@ -255,7 +255,7 @@ describe('plugin-meetings', () => {
|
|
|
255
255
|
});
|
|
256
256
|
|
|
257
257
|
describe('#raiseHand', () => {
|
|
258
|
-
it('sends a PATCH to the locus endpoint', async () => {
|
|
258
|
+
it('sends a raiseOrLowerHandMember PATCH to the locus endpoint', async () => {
|
|
259
259
|
const locusUrl = url1;
|
|
260
260
|
const memberId = 'test1';
|
|
261
261
|
|
|
@@ -319,7 +319,7 @@ describe('plugin-meetings', () => {
|
|
|
319
319
|
assert.strictEqual(result, requestResponse);
|
|
320
320
|
});
|
|
321
321
|
|
|
322
|
-
it('sends a PATCH to the locus endpoint', async () => {
|
|
322
|
+
it('sends a lowerAllHandsMember PATCH to the locus endpoint', async () => {
|
|
323
323
|
const locusUrl = url1;
|
|
324
324
|
const memberId = 'test1';
|
|
325
325
|
|
|
@@ -348,6 +348,40 @@ describe('plugin-meetings', () => {
|
|
|
348
348
|
},
|
|
349
349
|
});
|
|
350
350
|
});
|
|
351
|
+
|
|
352
|
+
it('sends a lowerAllHandsMember PATCH to the locus endpoint with roles', async () => {
|
|
353
|
+
const locusUrl = url1;
|
|
354
|
+
const memberId = 'test1';
|
|
355
|
+
const roles = ['attendee'];
|
|
356
|
+
|
|
357
|
+
const options = {
|
|
358
|
+
requestingParticipantId: memberId,
|
|
359
|
+
locusUrl,
|
|
360
|
+
roles,
|
|
361
|
+
};
|
|
362
|
+
|
|
363
|
+
const getRequestParamsSpy = sandbox.spy(membersUtil, 'getLowerAllHandsMemberRequestParams');
|
|
364
|
+
|
|
365
|
+
await membersRequest.lowerAllHandsMember(options);
|
|
366
|
+
|
|
367
|
+
assert.calledOnceWithExactly(getRequestParamsSpy, {
|
|
368
|
+
requestingParticipantId: memberId,
|
|
369
|
+
locusUrl: url1,
|
|
370
|
+
roles: ['attendee'],
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
checkRequest({
|
|
374
|
+
method: 'PATCH',
|
|
375
|
+
uri: `${locusUrl}/controls`,
|
|
376
|
+
body: {
|
|
377
|
+
hand: {
|
|
378
|
+
raised: false,
|
|
379
|
+
roles: ['attendee'],
|
|
380
|
+
},
|
|
381
|
+
requestingParticipantId: memberId,
|
|
382
|
+
},
|
|
383
|
+
});
|
|
384
|
+
});
|
|
351
385
|
});
|
|
352
386
|
|
|
353
387
|
describe('#editDisplayName', () => {
|
|
@@ -101,7 +101,7 @@ describe('plugin-meetings', () => {
|
|
|
101
101
|
});
|
|
102
102
|
});
|
|
103
103
|
describe('#generateLowerAllHandsMemberOptions', () => {
|
|
104
|
-
it('returns the correct options', () => {
|
|
104
|
+
it('returns the correct options without roles', () => {
|
|
105
105
|
const requestingParticipantId = 'test';
|
|
106
106
|
const locusUrl = 'urlTest1';
|
|
107
107
|
|
|
@@ -113,6 +113,20 @@ describe('plugin-meetings', () => {
|
|
|
113
113
|
}
|
|
114
114
|
);
|
|
115
115
|
});
|
|
116
|
+
it('returns the correct options with roles', () => {
|
|
117
|
+
const requestingParticipantId = 'test';
|
|
118
|
+
const locusUrl = 'urlTest1';
|
|
119
|
+
const roles = ['panelist'];
|
|
120
|
+
|
|
121
|
+
assert.deepEqual(
|
|
122
|
+
MembersUtil.generateLowerAllHandsMemberOptions(requestingParticipantId, locusUrl, roles),
|
|
123
|
+
{
|
|
124
|
+
requestingParticipantId,
|
|
125
|
+
locusUrl,
|
|
126
|
+
roles,
|
|
127
|
+
}
|
|
128
|
+
);
|
|
129
|
+
});
|
|
116
130
|
});
|
|
117
131
|
describe('#generateEditDisplayNameMemberOptions', () => {
|
|
118
132
|
it('returns the correct options', () => {
|
|
@@ -1234,7 +1234,7 @@ describe('gatherReachability', () => {
|
|
|
1234
1234
|
assert.equal(receivedEvents['done'], 1);
|
|
1235
1235
|
|
|
1236
1236
|
// and that ip network detection was started
|
|
1237
|
-
assert.calledOnceWithExactly(webex.internal.device.ipNetworkDetector.detect);
|
|
1237
|
+
assert.calledOnceWithExactly(webex.internal.device.ipNetworkDetector.detect, true);
|
|
1238
1238
|
|
|
1239
1239
|
// finally, check the metrics - they should contain values from ipNetworkDetector
|
|
1240
1240
|
assert.calledWith(Metrics.sendBehavioralMetric, 'js_sdk_reachability_completed', {
|
|
@@ -1664,6 +1664,270 @@ describe('gatherReachability', () => {
|
|
|
1664
1664
|
|
|
1665
1665
|
assert.neverCalledWith(clusterReachabilityCtorStub);
|
|
1666
1666
|
});
|
|
1667
|
+
|
|
1668
|
+
describe('fallback mechanism and multiple calls to getClusters', () => {
|
|
1669
|
+
let receivedEvents;
|
|
1670
|
+
|
|
1671
|
+
const mockGetClustersEmptyResult = {
|
|
1672
|
+
discoveryOptions: {
|
|
1673
|
+
['early-call-min-clusters']: 0,
|
|
1674
|
+
['report-version']: 1,
|
|
1675
|
+
},
|
|
1676
|
+
clusters: {}, // empty cluster list
|
|
1677
|
+
joinCookie: {id: 'cookie'},
|
|
1678
|
+
};
|
|
1679
|
+
|
|
1680
|
+
beforeEach(() => {
|
|
1681
|
+
webex.config.meetings.experimental = {
|
|
1682
|
+
enableTcpReachability: true,
|
|
1683
|
+
enableTlsReachability: true,
|
|
1684
|
+
};
|
|
1685
|
+
|
|
1686
|
+
receivedEvents = {
|
|
1687
|
+
done: 0,
|
|
1688
|
+
};
|
|
1689
|
+
});
|
|
1690
|
+
|
|
1691
|
+
it('keeps retrying if minimum required clusters are not reached', async () => {
|
|
1692
|
+
const reachability = new Reachability(webex);
|
|
1693
|
+
|
|
1694
|
+
reachability.on('reachability:done', () => {
|
|
1695
|
+
receivedEvents.done += 1;
|
|
1696
|
+
});
|
|
1697
|
+
|
|
1698
|
+
const mockGetClustersResult1 = {
|
|
1699
|
+
discoveryOptions: {
|
|
1700
|
+
['early-call-min-clusters']: 2,
|
|
1701
|
+
['report-version']: 1,
|
|
1702
|
+
},
|
|
1703
|
+
clusters: {
|
|
1704
|
+
clusterA0: {
|
|
1705
|
+
udp: ['udp-urlA'],
|
|
1706
|
+
tcp: ['tcp-urlA'],
|
|
1707
|
+
xtls: ['xtls-urlA'],
|
|
1708
|
+
isVideoMesh: false,
|
|
1709
|
+
},
|
|
1710
|
+
clusterB0: {
|
|
1711
|
+
udp: ['udp-urlB'],
|
|
1712
|
+
tcp: ['tcp-urlB'],
|
|
1713
|
+
xtls: ['xtls-urlB'],
|
|
1714
|
+
isVideoMesh: false,
|
|
1715
|
+
},
|
|
1716
|
+
},
|
|
1717
|
+
joinCookie: {id: 'cookie1'},
|
|
1718
|
+
};
|
|
1719
|
+
const mockGetClustersResult2 = {
|
|
1720
|
+
discoveryOptions: {
|
|
1721
|
+
['early-call-min-clusters']: 2,
|
|
1722
|
+
['report-version']: 1,
|
|
1723
|
+
},
|
|
1724
|
+
clusters: {
|
|
1725
|
+
clusterA1: {
|
|
1726
|
+
udp: ['udp-urlA'],
|
|
1727
|
+
tcp: ['tcp-urlA'],
|
|
1728
|
+
xtls: ['xtls-urlA'],
|
|
1729
|
+
isVideoMesh: false,
|
|
1730
|
+
},
|
|
1731
|
+
clusterB1: {
|
|
1732
|
+
udp: ['udp-urlB'],
|
|
1733
|
+
tcp: ['tcp-urlB'],
|
|
1734
|
+
xtls: ['xtls-urlB'],
|
|
1735
|
+
isVideoMesh: false,
|
|
1736
|
+
},
|
|
1737
|
+
},
|
|
1738
|
+
joinCookie: {id: 'cookie2'},
|
|
1739
|
+
};
|
|
1740
|
+
const mockGetClustersResult3 = {
|
|
1741
|
+
discoveryOptions: {
|
|
1742
|
+
['early-call-min-clusters']: 1,
|
|
1743
|
+
['report-version']: 1,
|
|
1744
|
+
},
|
|
1745
|
+
clusters: {
|
|
1746
|
+
clusterA2: {
|
|
1747
|
+
udp: ['udp-urlA'],
|
|
1748
|
+
tcp: ['tcp-urlA'],
|
|
1749
|
+
xtls: ['xtls-urlA'],
|
|
1750
|
+
isVideoMesh: false,
|
|
1751
|
+
},
|
|
1752
|
+
clusterB2: {
|
|
1753
|
+
udp: ['udp-urlB'],
|
|
1754
|
+
tcp: ['tcp-urlB'],
|
|
1755
|
+
xtls: ['xtls-urlB'],
|
|
1756
|
+
isVideoMesh: false,
|
|
1757
|
+
},
|
|
1758
|
+
},
|
|
1759
|
+
joinCookie: {id: 'cookie3'},
|
|
1760
|
+
};
|
|
1761
|
+
|
|
1762
|
+
reachability.reachabilityRequest.getClusters = sinon.stub();
|
|
1763
|
+
reachability.reachabilityRequest.getClusters.onCall(0).returns(mockGetClustersResult1);
|
|
1764
|
+
reachability.reachabilityRequest.getClusters.onCall(1).returns(mockGetClustersResult2);
|
|
1765
|
+
|
|
1766
|
+
reachability.reachabilityRequest.getClusters.onCall(2).returns(mockGetClustersResult3);
|
|
1767
|
+
|
|
1768
|
+
const resultPromise = reachability.gatherReachability('test');
|
|
1769
|
+
|
|
1770
|
+
await testUtils.flushPromises();
|
|
1771
|
+
|
|
1772
|
+
// trigger some mock result events from ClusterReachability instances,
|
|
1773
|
+
// but only from 1 cluster, so not enough to reach the minimum required
|
|
1774
|
+
mockClusterReachabilityInstances['clusterA0'].emitFakeResult('udp', {
|
|
1775
|
+
result: 'reachable',
|
|
1776
|
+
clientMediaIPs: ['1.2.3.4'],
|
|
1777
|
+
latencyInMilliseconds: 11,
|
|
1778
|
+
});
|
|
1779
|
+
|
|
1780
|
+
clock.tick(3000);
|
|
1781
|
+
await resultPromise;
|
|
1782
|
+
await testUtils.flushPromises();
|
|
1783
|
+
|
|
1784
|
+
// because the minimum was not reached, another call to getClusters should be made
|
|
1785
|
+
assert.calledTwice(reachability.reachabilityRequest.getClusters);
|
|
1786
|
+
|
|
1787
|
+
// simulate no results this time
|
|
1788
|
+
|
|
1789
|
+
// check that while the 2nd attempt is in progress, the join cookie is already available from the 2nd call to getClusters
|
|
1790
|
+
const clientMediaPreferences = await reachability.getClientMediaPreferences(
|
|
1791
|
+
true,
|
|
1792
|
+
IP_VERSION.unknown
|
|
1793
|
+
);
|
|
1794
|
+
|
|
1795
|
+
assert.deepEqual(clientMediaPreferences.joinCookie, mockGetClustersResult2.joinCookie);
|
|
1796
|
+
|
|
1797
|
+
clock.tick(3000);
|
|
1798
|
+
await testUtils.flushPromises();
|
|
1799
|
+
|
|
1800
|
+
assert.calledThrice(reachability.reachabilityRequest.getClusters);
|
|
1801
|
+
|
|
1802
|
+
await testUtils.flushPromises();
|
|
1803
|
+
|
|
1804
|
+
// this time 1 result will be enough to reach the minimum
|
|
1805
|
+
mockClusterReachabilityInstances['clusterA2'].emitFakeResult('udp', {
|
|
1806
|
+
result: 'reachable',
|
|
1807
|
+
clientMediaIPs: ['1.2.3.4'],
|
|
1808
|
+
latencyInMilliseconds: 11,
|
|
1809
|
+
});
|
|
1810
|
+
clock.tick(3000);
|
|
1811
|
+
|
|
1812
|
+
// the reachability results should include only results from the last attempt
|
|
1813
|
+
await checkResults(
|
|
1814
|
+
{
|
|
1815
|
+
clusterA2: {
|
|
1816
|
+
udp: {result: 'reachable', clientMediaIPs: ['1.2.3.4'], latencyInMilliseconds: 11},
|
|
1817
|
+
tcp: {result: 'unreachable'},
|
|
1818
|
+
xtls: {result: 'unreachable'},
|
|
1819
|
+
isVideoMesh: false,
|
|
1820
|
+
},
|
|
1821
|
+
clusterB2: {
|
|
1822
|
+
udp: {result: 'unreachable'},
|
|
1823
|
+
tcp: {result: 'unreachable'},
|
|
1824
|
+
xtls: {result: 'unreachable'},
|
|
1825
|
+
isVideoMesh: false,
|
|
1826
|
+
},
|
|
1827
|
+
},
|
|
1828
|
+
mockGetClustersResult3.joinCookie
|
|
1829
|
+
);
|
|
1830
|
+
|
|
1831
|
+
// wait some more time to make sure that there are no timers that fire from one of the previous checks
|
|
1832
|
+
clock.tick(20000);
|
|
1833
|
+
|
|
1834
|
+
// as the first 2 attempts failed and didn't reach the overall timeout, there should be only 1 done event emitted
|
|
1835
|
+
assert.equal(receivedEvents.done, 1);
|
|
1836
|
+
});
|
|
1837
|
+
|
|
1838
|
+
it('handles getClusters() returning empty list on 1st call', async () => {
|
|
1839
|
+
const reachability = new Reachability(webex);
|
|
1840
|
+
|
|
1841
|
+
reachability.on('reachability:done', () => {
|
|
1842
|
+
receivedEvents.done += 1;
|
|
1843
|
+
});
|
|
1844
|
+
|
|
1845
|
+
reachability.reachabilityRequest.getClusters = sinon
|
|
1846
|
+
.stub()
|
|
1847
|
+
.resolves(mockGetClustersEmptyResult);
|
|
1848
|
+
|
|
1849
|
+
const resultPromise = reachability.gatherReachability('test');
|
|
1850
|
+
|
|
1851
|
+
await testUtils.flushPromises();
|
|
1852
|
+
|
|
1853
|
+
clock.tick(3000);
|
|
1854
|
+
await resultPromise;
|
|
1855
|
+
await testUtils.flushPromises();
|
|
1856
|
+
|
|
1857
|
+
assert.calledOnce(reachability.reachabilityRequest.getClusters);
|
|
1858
|
+
reachability.reachabilityRequest.getClusters.resetHistory();
|
|
1859
|
+
|
|
1860
|
+
assert.equal(receivedEvents.done, 1);
|
|
1861
|
+
await checkResults({}, mockGetClustersEmptyResult.joinCookie);
|
|
1862
|
+
|
|
1863
|
+
// because we didn't actually test anything (we got empty cluster list from getClusters()), we should
|
|
1864
|
+
// not say that webex backend is unreachable
|
|
1865
|
+
assert.equal(await reachability.isWebexMediaBackendUnreachable(), false);
|
|
1866
|
+
|
|
1867
|
+
// wait to check that there are no other things happening
|
|
1868
|
+
clock.tick(20000);
|
|
1869
|
+
await testUtils.flushPromises();
|
|
1870
|
+
|
|
1871
|
+
assert.notCalled(reachability.reachabilityRequest.getClusters);
|
|
1872
|
+
assert.equal(receivedEvents.done, 1);
|
|
1873
|
+
});
|
|
1874
|
+
|
|
1875
|
+
it('handles getClusters() returning empty list on 2nd call', async () => {
|
|
1876
|
+
const reachability = new Reachability(webex);
|
|
1877
|
+
|
|
1878
|
+
reachability.on('reachability:done', () => {
|
|
1879
|
+
receivedEvents.done += 1;
|
|
1880
|
+
});
|
|
1881
|
+
|
|
1882
|
+
const mockGetClustersResult1 = {
|
|
1883
|
+
discoveryOptions: {
|
|
1884
|
+
['early-call-min-clusters']: 2,
|
|
1885
|
+
['report-version']: 1,
|
|
1886
|
+
},
|
|
1887
|
+
clusters: {
|
|
1888
|
+
clusterA0: {
|
|
1889
|
+
udp: ['udp-urlA'],
|
|
1890
|
+
tcp: ['tcp-urlA'],
|
|
1891
|
+
xtls: ['xtls-urlA'],
|
|
1892
|
+
isVideoMesh: false,
|
|
1893
|
+
},
|
|
1894
|
+
clusterB0: {
|
|
1895
|
+
udp: ['udp-urlB'],
|
|
1896
|
+
tcp: ['tcp-urlB'],
|
|
1897
|
+
xtls: ['xtls-urlB'],
|
|
1898
|
+
isVideoMesh: false,
|
|
1899
|
+
},
|
|
1900
|
+
},
|
|
1901
|
+
joinCookie: {id: 'cookie1'},
|
|
1902
|
+
};
|
|
1903
|
+
|
|
1904
|
+
reachability.reachabilityRequest.getClusters = sinon.stub();
|
|
1905
|
+
reachability.reachabilityRequest.getClusters.onCall(0).returns(mockGetClustersResult1);
|
|
1906
|
+
reachability.reachabilityRequest.getClusters.onCall(1).returns(mockGetClustersEmptyResult);
|
|
1907
|
+
|
|
1908
|
+
const resultPromise = reachability.gatherReachability('test');
|
|
1909
|
+
|
|
1910
|
+
await testUtils.flushPromises();
|
|
1911
|
+
|
|
1912
|
+
clock.tick(3000);
|
|
1913
|
+
await resultPromise;
|
|
1914
|
+
await testUtils.flushPromises();
|
|
1915
|
+
|
|
1916
|
+
// because the minimum was not reached, another call to getClusters should be made
|
|
1917
|
+
assert.calledTwice(reachability.reachabilityRequest.getClusters);
|
|
1918
|
+
|
|
1919
|
+
// the reachability results should include only results from the last attempt
|
|
1920
|
+
await checkResults({}, mockGetClustersEmptyResult.joinCookie);
|
|
1921
|
+
|
|
1922
|
+
// as the first 2 attempts failed and didn't reach the overall timeout, there should be only 1 done event emitted
|
|
1923
|
+
assert.equal(receivedEvents.done, 1);
|
|
1924
|
+
// because we didn't actually test anything (we got empty cluster list from getClusters()), we should
|
|
1925
|
+
// not say that webex backend is unreachable
|
|
1926
|
+
assert.equal(await reachability.isWebexMediaBackendUnreachable(), false);
|
|
1927
|
+
});
|
|
1928
|
+
});
|
|
1929
|
+
|
|
1930
|
+
|
|
1667
1931
|
});
|
|
1668
1932
|
|
|
1669
1933
|
describe('getReachabilityResults', () => {
|