@webex/plugin-meetings 3.12.0-next.9 → 3.12.0-next.91
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/AGENTS.md +9 -0
- package/dist/aiEnableRequest/index.js +15 -2
- package/dist/aiEnableRequest/index.js.map +1 -1
- package/dist/breakouts/breakout.js +8 -3
- package/dist/breakouts/breakout.js.map +1 -1
- package/dist/breakouts/index.js +26 -2
- package/dist/breakouts/index.js.map +1 -1
- package/dist/config.js +2 -2
- package/dist/config.js.map +1 -1
- package/dist/constants.js +35 -9
- package/dist/constants.js.map +1 -1
- package/dist/controls-options-manager/constants.js +11 -1
- package/dist/controls-options-manager/constants.js.map +1 -1
- package/dist/controls-options-manager/index.js +67 -29
- package/dist/controls-options-manager/index.js.map +1 -1
- package/dist/controls-options-manager/util.js +91 -0
- package/dist/controls-options-manager/util.js.map +1 -1
- package/dist/hashTree/constants.js +13 -1
- package/dist/hashTree/constants.js.map +1 -1
- package/dist/hashTree/hashTreeParser.js +880 -382
- package/dist/hashTree/hashTreeParser.js.map +1 -1
- package/dist/hashTree/utils.js +42 -0
- package/dist/hashTree/utils.js.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/interceptors/dataChannelAuthToken.js +75 -15
- package/dist/interceptors/dataChannelAuthToken.js.map +1 -1
- package/dist/interceptors/locusRetry.js +23 -8
- package/dist/interceptors/locusRetry.js.map +1 -1
- package/dist/interpretation/index.js +10 -1
- package/dist/interpretation/index.js.map +1 -1
- package/dist/interpretation/interpretation.types.js +7 -0
- package/dist/interpretation/interpretation.types.js.map +1 -0
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/locus-info/controlsUtils.js +4 -1
- package/dist/locus-info/controlsUtils.js.map +1 -1
- package/dist/locus-info/index.js +303 -88
- package/dist/locus-info/index.js.map +1 -1
- package/dist/locus-info/infoUtils.js +36 -5
- package/dist/locus-info/infoUtils.js.map +1 -1
- package/dist/locus-info/types.js +19 -0
- package/dist/locus-info/types.js.map +1 -1
- package/dist/media/index.js +3 -1
- package/dist/media/index.js.map +1 -1
- package/dist/media/properties.js +1 -0
- package/dist/media/properties.js.map +1 -1
- package/dist/meeting/in-meeting-actions.js +5 -1
- package/dist/meeting/in-meeting-actions.js.map +1 -1
- package/dist/meeting/index.js +1233 -793
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/locusMediaRequest.js +229 -82
- package/dist/meeting/locusMediaRequest.js.map +1 -1
- package/dist/meeting/muteState.js +10 -1
- package/dist/meeting/muteState.js.map +1 -1
- package/dist/meeting/request.js +5 -2
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting/util.js +35 -2
- package/dist/meeting/util.js.map +1 -1
- package/dist/meeting-info/meeting-info-v2.js +2 -2
- package/dist/meeting-info/meeting-info-v2.js.map +1 -1
- package/dist/meetings/index.js +231 -118
- package/dist/meetings/index.js.map +1 -1
- package/dist/meetings/meetings.types.js +6 -1
- package/dist/meetings/meetings.types.js.map +1 -1
- package/dist/meetings/request.js +39 -0
- package/dist/meetings/request.js.map +1 -1
- package/dist/meetings/util.js +79 -5
- package/dist/meetings/util.js.map +1 -1
- package/dist/member/index.js +10 -0
- package/dist/member/index.js.map +1 -1
- package/dist/member/types.js.map +1 -1
- package/dist/member/util.js +30 -0
- package/dist/member/util.js.map +1 -1
- package/dist/members/index.js +101 -43
- package/dist/members/index.js.map +1 -1
- package/dist/members/util.js +8 -1
- package/dist/members/util.js.map +1 -1
- package/dist/metrics/constants.js +5 -1
- package/dist/metrics/constants.js.map +1 -1
- package/dist/multistream/codec/constants.js +63 -0
- package/dist/multistream/codec/constants.js.map +1 -0
- package/dist/multistream/mediaRequestManager.js +62 -15
- package/dist/multistream/mediaRequestManager.js.map +1 -1
- package/dist/multistream/receiveSlot.js +9 -0
- package/dist/multistream/receiveSlot.js.map +1 -1
- package/dist/reachability/index.js +10 -13
- package/dist/reachability/index.js.map +1 -1
- package/dist/reachability/reachability.types.js +2 -0
- package/dist/reachability/reachability.types.js.map +1 -1
- package/dist/reachability/util.js +45 -0
- package/dist/reachability/util.js.map +1 -1
- package/dist/reactions/reactions.type.js.map +1 -1
- package/dist/recording-controller/index.js +1 -3
- package/dist/recording-controller/index.js.map +1 -1
- package/dist/types/config.d.ts +2 -2
- package/dist/types/constants.d.ts +12 -1
- package/dist/types/controls-options-manager/constants.d.ts +6 -1
- package/dist/types/controls-options-manager/index.d.ts +16 -0
- package/dist/types/hashTree/constants.d.ts +2 -0
- package/dist/types/hashTree/hashTreeParser.d.ts +146 -17
- package/dist/types/hashTree/utils.d.ts +18 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/interceptors/locusRetry.d.ts +4 -4
- package/dist/types/interpretation/interpretation.types.d.ts +10 -0
- package/dist/types/locus-info/index.d.ts +50 -6
- package/dist/types/locus-info/infoUtils.d.ts +8 -0
- package/dist/types/locus-info/types.d.ts +21 -1
- package/dist/types/media/properties.d.ts +1 -0
- package/dist/types/meeting/in-meeting-actions.d.ts +4 -0
- package/dist/types/meeting/index.d.ts +94 -7
- package/dist/types/meeting/locusMediaRequest.d.ts +12 -0
- package/dist/types/meeting/request.d.ts +1 -0
- package/dist/types/meeting/util.d.ts +9 -0
- package/dist/types/meetings/index.d.ts +30 -18
- package/dist/types/meetings/meetings.types.d.ts +15 -0
- package/dist/types/meetings/request.d.ts +14 -0
- package/dist/types/member/index.d.ts +1 -0
- package/dist/types/member/types.d.ts +1 -0
- package/dist/types/member/util.d.ts +9 -0
- package/dist/types/members/index.d.ts +15 -2
- package/dist/types/members/util.d.ts +1 -5
- package/dist/types/metrics/constants.d.ts +4 -0
- package/dist/types/multistream/codec/constants.d.ts +7 -0
- package/dist/types/multistream/mediaRequestManager.d.ts +22 -5
- package/dist/types/reachability/index.d.ts +1 -1
- package/dist/types/reachability/reachability.types.d.ts +7 -0
- package/dist/types/reachability/util.d.ts +17 -0
- package/dist/types/reactions/reactions.type.d.ts +3 -0
- package/dist/webinar/index.js +305 -159
- package/dist/webinar/index.js.map +1 -1
- package/package.json +22 -22
- package/src/aiEnableRequest/index.ts +16 -0
- package/src/breakouts/breakout.ts +3 -1
- package/src/breakouts/index.ts +31 -0
- package/src/config.ts +2 -2
- package/src/constants.ts +20 -3
- package/src/controls-options-manager/constants.ts +14 -1
- package/src/controls-options-manager/index.ts +87 -28
- package/src/controls-options-manager/util.ts +81 -1
- package/src/hashTree/constants.ts +16 -0
- package/src/hashTree/hashTreeParser.ts +580 -196
- package/src/hashTree/utils.ts +36 -0
- package/src/index.ts +6 -0
- package/src/interceptors/dataChannelAuthToken.ts +88 -12
- package/src/interceptors/locusRetry.ts +25 -4
- package/src/interpretation/index.ts +27 -9
- package/src/interpretation/interpretation.types.ts +11 -0
- package/src/locus-info/controlsUtils.ts +3 -1
- package/src/locus-info/index.ts +304 -100
- package/src/locus-info/infoUtils.ts +41 -6
- package/src/locus-info/types.ts +25 -1
- package/src/media/index.ts +3 -0
- package/src/media/properties.ts +1 -0
- package/src/meeting/in-meeting-actions.ts +8 -0
- package/src/meeting/index.ts +494 -67
- package/src/meeting/locusMediaRequest.ts +106 -6
- package/src/meeting/muteState.ts +10 -1
- package/src/meeting/request.ts +11 -0
- package/src/meeting/util.ts +47 -5
- package/src/meeting-info/meeting-info-v2.ts +4 -2
- package/src/meetings/index.ts +133 -78
- package/src/meetings/meetings.types.ts +19 -0
- package/src/meetings/request.ts +43 -0
- package/src/meetings/util.ts +97 -1
- package/src/member/index.ts +10 -0
- package/src/member/types.ts +1 -0
- package/src/member/util.ts +29 -0
- package/src/members/index.ts +70 -7
- package/src/members/util.ts +12 -4
- package/src/metrics/constants.ts +4 -0
- package/src/multistream/codec/constants.ts +58 -0
- package/src/multistream/mediaRequestManager.ts +119 -28
- package/src/multistream/receiveSlot.ts +18 -0
- package/src/reachability/index.ts +19 -15
- package/src/reachability/reachability.types.ts +11 -0
- package/src/reachability/util.ts +36 -0
- package/src/reactions/reactions.type.ts +3 -0
- package/src/recording-controller/index.ts +1 -2
- package/src/webinar/index.ts +214 -36
- package/test/unit/spec/aiEnableRequest/index.ts +86 -0
- package/test/unit/spec/breakouts/breakout.ts +9 -3
- package/test/unit/spec/breakouts/index.ts +49 -0
- package/test/unit/spec/controls-options-manager/index.js +244 -29
- package/test/unit/spec/controls-options-manager/util.js +165 -0
- package/test/unit/spec/hashTree/hashTreeParser.ts +1838 -180
- package/test/unit/spec/hashTree/utils.ts +125 -1
- package/test/unit/spec/interceptors/dataChannelAuthToken.ts +196 -0
- package/test/unit/spec/interceptors/locusRetry.ts +205 -4
- package/test/unit/spec/interpretation/index.ts +26 -4
- package/test/unit/spec/locus-info/controlsUtils.js +172 -57
- package/test/unit/spec/locus-info/index.js +499 -81
- package/test/unit/spec/locus-info/infoUtils.js +184 -1
- package/test/unit/spec/media/index.ts +31 -0
- package/test/unit/spec/meeting/in-meeting-actions.ts +4 -0
- package/test/unit/spec/meeting/index.js +1615 -42
- package/test/unit/spec/meeting/locusMediaRequest.ts +302 -4
- package/test/unit/spec/meeting/muteState.js +81 -0
- package/test/unit/spec/meeting/request.js +12 -0
- package/test/unit/spec/meeting/utils.js +157 -1
- package/test/unit/spec/meeting-info/meetinginfov2.js +19 -10
- package/test/unit/spec/meetings/index.js +363 -36
- package/test/unit/spec/meetings/request.js +141 -0
- package/test/unit/spec/meetings/utils.js +189 -0
- package/test/unit/spec/member/index.js +7 -0
- package/test/unit/spec/member/util.js +89 -0
- package/test/unit/spec/members/index.js +216 -0
- package/test/unit/spec/members/request.js +37 -1
- package/test/unit/spec/members/utils.js +63 -0
- package/test/unit/spec/multistream/mediaRequestManager.ts +501 -37
- package/test/unit/spec/reachability/index.ts +59 -46
- package/test/unit/spec/reachability/util.ts +31 -0
- package/test/unit/spec/recording-controller/index.js +9 -8
- package/test/unit/spec/webinar/index.ts +329 -28
|
@@ -14,12 +14,14 @@ import StaticConfig from '@webex/plugin-meetings/src/common/config';
|
|
|
14
14
|
import TriggerProxy from '@webex/plugin-meetings/src/common/events/trigger-proxy';
|
|
15
15
|
import LoggerProxy from '@webex/plugin-meetings/src/common/logs/logger-proxy';
|
|
16
16
|
import LoggerConfig from '@webex/plugin-meetings/src/common/logs/logger-config';
|
|
17
|
+
import ParameterError from '@webex/plugin-meetings/src/common/errors/parameter';
|
|
17
18
|
import Meeting, {CallStateForMetrics} from '@webex/plugin-meetings/src/meeting';
|
|
18
19
|
import {Services} from '@webex/webex-core';
|
|
19
20
|
import MeetingUtil from '@webex/plugin-meetings/src/meeting/util';
|
|
20
21
|
import Meetings from '@webex/plugin-meetings/src/meetings';
|
|
21
22
|
import MeetingCollection from '@webex/plugin-meetings/src/meetings/collection';
|
|
22
23
|
import MeetingsUtil from '@webex/plugin-meetings/src/meetings/util';
|
|
24
|
+
import {SitePreferenceSelectOption} from '@webex/plugin-meetings/src/meetings/meetings.types';
|
|
23
25
|
import PersonalMeetingRoom from '@webex/plugin-meetings/src/personal-meeting-room';
|
|
24
26
|
import Reachability from '@webex/plugin-meetings/src/reachability';
|
|
25
27
|
import Metrics from '@webex/plugin-meetings/src/metrics';
|
|
@@ -91,6 +93,7 @@ describe('plugin-meetings', () => {
|
|
|
91
93
|
locusInfo = {
|
|
92
94
|
parse: sinon.stub().returns(true),
|
|
93
95
|
updateMainSessionLocusCache: sinon.stub(),
|
|
96
|
+
syncAllHashTreeDatasets: sinon.stub(),
|
|
94
97
|
};
|
|
95
98
|
webex = new MockWebex({
|
|
96
99
|
children: {
|
|
@@ -355,32 +358,6 @@ describe('plugin-meetings', () => {
|
|
|
355
358
|
});
|
|
356
359
|
});
|
|
357
360
|
|
|
358
|
-
describe('#_toggleTcpReachability', () => {
|
|
359
|
-
it('should have _toggleTcpReachability', () => {
|
|
360
|
-
assert.equal(typeof webex.meetings._toggleTcpReachability, 'function');
|
|
361
|
-
});
|
|
362
|
-
|
|
363
|
-
describe('success', () => {
|
|
364
|
-
it('should update meetings to do TCP reachability', () => {
|
|
365
|
-
webex.meetings._toggleTcpReachability(true);
|
|
366
|
-
assert.equal(webex.meetings.config.experimental.enableTcpReachability, true);
|
|
367
|
-
});
|
|
368
|
-
});
|
|
369
|
-
});
|
|
370
|
-
|
|
371
|
-
describe('#_toggleTlsReachability', () => {
|
|
372
|
-
it('should have _toggleTlsReachability', () => {
|
|
373
|
-
assert.equal(typeof webex.meetings._toggleTlsReachability, 'function');
|
|
374
|
-
});
|
|
375
|
-
|
|
376
|
-
describe('success', () => {
|
|
377
|
-
it('should update meetings to do TLS reachability', () => {
|
|
378
|
-
webex.meetings._toggleTlsReachability(true);
|
|
379
|
-
assert.equal(webex.meetings.config.experimental.enableTlsReachability, true);
|
|
380
|
-
});
|
|
381
|
-
});
|
|
382
|
-
});
|
|
383
|
-
|
|
384
361
|
describe('#_toggleIpv6BackendNativeSupport', () => {
|
|
385
362
|
it('should have _toggleIpv6BackendNativeSupport', () => {
|
|
386
363
|
assert.equal(typeof webex.meetings._toggleIpv6BackendNativeSupport, 'function');
|
|
@@ -423,6 +400,33 @@ describe('plugin-meetings', () => {
|
|
|
423
400
|
});
|
|
424
401
|
});
|
|
425
402
|
|
|
403
|
+
describe('#_toggleEnableAv1SlidesSupport', () => {
|
|
404
|
+
it('should have _toggleEnableAv1SlidesSupport', () => {
|
|
405
|
+
assert.equal(typeof webex.meetings._toggleEnableAv1SlidesSupport, 'function');
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
describe('success', () => {
|
|
409
|
+
it('should update meetings config to enable AV1 slides support', () => {
|
|
410
|
+
webex.meetings._toggleEnableAv1SlidesSupport(true);
|
|
411
|
+
assert.equal(webex.meetings.config.enableAv1SlidesSupport, true);
|
|
412
|
+
|
|
413
|
+
webex.meetings._toggleEnableAv1SlidesSupport(false);
|
|
414
|
+
assert.equal(webex.meetings.config.enableAv1SlidesSupport, false);
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
it('should not update config when called with a non-boolean value', () => {
|
|
418
|
+
webex.meetings._toggleEnableAv1SlidesSupport(true);
|
|
419
|
+
assert.equal(webex.meetings.config.enableAv1SlidesSupport, true);
|
|
420
|
+
|
|
421
|
+
webex.meetings._toggleEnableAv1SlidesSupport('invalid');
|
|
422
|
+
assert.equal(webex.meetings.config.enableAv1SlidesSupport, true);
|
|
423
|
+
|
|
424
|
+
webex.meetings._toggleEnableAv1SlidesSupport(undefined);
|
|
425
|
+
assert.equal(webex.meetings.config.enableAv1SlidesSupport, true);
|
|
426
|
+
});
|
|
427
|
+
});
|
|
428
|
+
});
|
|
429
|
+
|
|
426
430
|
describe('#_toggleStopIceGatheringAfterFirstRelayCandidate', () => {
|
|
427
431
|
it('should have _toggleStopIceGatheringAfterFirstRelayCandidate', () => {
|
|
428
432
|
assert.equal(
|
|
@@ -1355,6 +1359,87 @@ describe('plugin-meetings', () => {
|
|
|
1355
1359
|
);
|
|
1356
1360
|
});
|
|
1357
1361
|
});
|
|
1362
|
+
describe('#fetchSitePreferencesMeViaSite', () => {
|
|
1363
|
+
const sitePreferencesResponse = {
|
|
1364
|
+
scheduling: {
|
|
1365
|
+
supportScheduleWebinar: true,
|
|
1366
|
+
webinarWebLink: 'https://go.webex.com/webappng/sites/go/webinar/scheduler',
|
|
1367
|
+
},
|
|
1368
|
+
};
|
|
1369
|
+
|
|
1370
|
+
beforeEach(() => {
|
|
1371
|
+
webex.meetings.request.fetchSitePreferencesMeViaSite = sinon
|
|
1372
|
+
.stub()
|
|
1373
|
+
.resolves(sitePreferencesResponse);
|
|
1374
|
+
});
|
|
1375
|
+
|
|
1376
|
+
it('should have #fetchSitePreferencesMeViaSite', () => {
|
|
1377
|
+
assert.exists(webex.meetings.fetchSitePreferencesMeViaSite);
|
|
1378
|
+
});
|
|
1379
|
+
|
|
1380
|
+
it('fetches scheduling preferences for the preferred Webex site by default', async () => {
|
|
1381
|
+
webex.meetings.preferredWebexSite = 'go.webex.com';
|
|
1382
|
+
|
|
1383
|
+
const result = await webex.meetings.fetchSitePreferencesMeViaSite();
|
|
1384
|
+
|
|
1385
|
+
assert.deepEqual(result, sitePreferencesResponse);
|
|
1386
|
+
assert.calledOnceWithExactly(
|
|
1387
|
+
webex.meetings.request.fetchSitePreferencesMeViaSite,
|
|
1388
|
+
{
|
|
1389
|
+
siteUrl: 'go.webex.com',
|
|
1390
|
+
}
|
|
1391
|
+
);
|
|
1392
|
+
});
|
|
1393
|
+
|
|
1394
|
+
it('uses the provided Webex site instead of the preferred Webex site', async () => {
|
|
1395
|
+
webex.meetings.preferredWebexSite = 'preferred.webex.com';
|
|
1396
|
+
|
|
1397
|
+
await webex.meetings.fetchSitePreferencesMeViaSite({siteUrl: 'go.webex.com'});
|
|
1398
|
+
|
|
1399
|
+
assert.calledOnceWithExactly(
|
|
1400
|
+
webex.meetings.request.fetchSitePreferencesMeViaSite,
|
|
1401
|
+
{
|
|
1402
|
+
siteUrl: 'go.webex.com',
|
|
1403
|
+
}
|
|
1404
|
+
);
|
|
1405
|
+
});
|
|
1406
|
+
|
|
1407
|
+
it('forwards custom site name and preference sections to the request helper', async () => {
|
|
1408
|
+
webex.meetings.preferredWebexSite = 'go.webex.com';
|
|
1409
|
+
|
|
1410
|
+
await webex.meetings.fetchSitePreferencesMeViaSite({
|
|
1411
|
+
siteName: 'custom-site',
|
|
1412
|
+
selectOptions: [SitePreferenceSelectOption.SCHEDULING],
|
|
1413
|
+
});
|
|
1414
|
+
|
|
1415
|
+
assert.calledOnceWithExactly(
|
|
1416
|
+
webex.meetings.request.fetchSitePreferencesMeViaSite,
|
|
1417
|
+
{
|
|
1418
|
+
siteUrl: 'go.webex.com',
|
|
1419
|
+
siteName: 'custom-site',
|
|
1420
|
+
selectOptions: [SitePreferenceSelectOption.SCHEDULING],
|
|
1421
|
+
}
|
|
1422
|
+
);
|
|
1423
|
+
});
|
|
1424
|
+
|
|
1425
|
+
it('throws when no Webex site is available', () => {
|
|
1426
|
+
webex.meetings.preferredWebexSite = '';
|
|
1427
|
+
webex.meetings.request.fetchSitePreferencesMeViaSite.throws(
|
|
1428
|
+
new ParameterError(
|
|
1429
|
+
'No siteUrl available. Call register() before fetching site preferences or provide options.siteUrl.'
|
|
1430
|
+
)
|
|
1431
|
+
);
|
|
1432
|
+
|
|
1433
|
+
assert.throws(
|
|
1434
|
+
() => webex.meetings.fetchSitePreferencesMeViaSite(),
|
|
1435
|
+
ParameterError,
|
|
1436
|
+
'No siteUrl available. Call register() before fetching site preferences or provide options.siteUrl.'
|
|
1437
|
+
);
|
|
1438
|
+
assert.calledOnceWithExactly(webex.meetings.request.fetchSitePreferencesMeViaSite, {
|
|
1439
|
+
siteUrl: '',
|
|
1440
|
+
});
|
|
1441
|
+
});
|
|
1442
|
+
});
|
|
1358
1443
|
describe('Static shortcut proxy methods', () => {
|
|
1359
1444
|
describe('MeetingCollection getByKey proxies', () => {
|
|
1360
1445
|
beforeEach(() => {
|
|
@@ -1391,7 +1476,7 @@ describe('plugin-meetings', () => {
|
|
|
1391
1476
|
it('should have #syncMeetings', () => {
|
|
1392
1477
|
assert.exists(webex.meetings.syncMeetings);
|
|
1393
1478
|
});
|
|
1394
|
-
it('should
|
|
1479
|
+
it('should skip getActiveMeetings but still call syncAllHashTreeDatasets if unverified guest', async () => {
|
|
1395
1480
|
webex.meetings.request.getActiveMeetings = sinon.stub().returns(
|
|
1396
1481
|
Promise.resolve({
|
|
1397
1482
|
loci: [
|
|
@@ -1404,13 +1489,23 @@ describe('plugin-meetings', () => {
|
|
|
1404
1489
|
webex.credentials.isUnverifiedGuest = true;
|
|
1405
1490
|
LoggerProxy.logger.info = sinon.stub();
|
|
1406
1491
|
|
|
1492
|
+
const mockLocusInfo = {
|
|
1493
|
+
syncAllHashTreeDatasets: sinon.stub().resolves(),
|
|
1494
|
+
};
|
|
1495
|
+
webex.meetings.meetingCollection.getAll = sinon.stub().returns({
|
|
1496
|
+
meeting1: {locusInfo: mockLocusInfo},
|
|
1497
|
+
meeting2: {locusInfo: undefined},
|
|
1498
|
+
meeting3: {},
|
|
1499
|
+
});
|
|
1500
|
+
|
|
1407
1501
|
await webex.meetings.syncMeetings();
|
|
1408
1502
|
|
|
1409
1503
|
assert.notCalled(webex.meetings.request.getActiveMeetings);
|
|
1410
1504
|
assert.calledWith(
|
|
1411
1505
|
LoggerProxy.logger.info,
|
|
1412
|
-
'Meetings:index#syncMeetings --> skipping
|
|
1506
|
+
'Meetings:index#syncMeetings --> user is unverified guest, skipping calling Locus for meeting sync'
|
|
1413
1507
|
);
|
|
1508
|
+
assert.calledOnce(mockLocusInfo.syncAllHashTreeDatasets);
|
|
1414
1509
|
});
|
|
1415
1510
|
describe('succesful requests', () => {
|
|
1416
1511
|
beforeEach(() => {
|
|
@@ -1429,6 +1524,9 @@ describe('plugin-meetings', () => {
|
|
|
1429
1524
|
webex.meetings.meetingCollection.getByKey = sinon.stub().returns({
|
|
1430
1525
|
locusInfo,
|
|
1431
1526
|
});
|
|
1527
|
+
webex.meetings.meetingCollection.getAll = sinon.stub().returns({
|
|
1528
|
+
meeting1: {locusInfo, locusUrl: url1},
|
|
1529
|
+
});
|
|
1432
1530
|
});
|
|
1433
1531
|
it('tests the sync meeting calls for existing meeting', async () => {
|
|
1434
1532
|
await webex.meetings.syncMeetings();
|
|
@@ -1436,6 +1534,7 @@ describe('plugin-meetings', () => {
|
|
|
1436
1534
|
assert.calledOnce(webex.meetings.meetingCollection.getByKey);
|
|
1437
1535
|
assert.calledOnce(locusInfo.parse);
|
|
1438
1536
|
assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
|
|
1537
|
+
assert.calledOnce(locusInfo.syncAllHashTreeDatasets);
|
|
1439
1538
|
});
|
|
1440
1539
|
});
|
|
1441
1540
|
describe('when meeting is not returned', () => {
|
|
@@ -1474,7 +1573,7 @@ describe('plugin-meetings', () => {
|
|
|
1474
1573
|
url: url1,
|
|
1475
1574
|
},
|
|
1476
1575
|
hashTreeMessage: undefined,
|
|
1477
|
-
});
|
|
1576
|
+
}, sinon.match.func);
|
|
1478
1577
|
});
|
|
1479
1578
|
});
|
|
1480
1579
|
describe('when destroying meeting is needed', () => {
|
|
@@ -1520,7 +1619,7 @@ describe('plugin-meetings', () => {
|
|
|
1520
1619
|
it('destroy any meeting that has no active locus url if keepOnlyLocusMeetings is not defined', async () => {
|
|
1521
1620
|
await webex.meetings.syncMeetings();
|
|
1522
1621
|
assert.calledOnce(webex.meetings.request.getActiveMeetings);
|
|
1523
|
-
assert.
|
|
1622
|
+
assert.calledTwice(webex.meetings.meetingCollection.getAll);
|
|
1524
1623
|
assert.calledWith(destroySpy, meetingCollectionMeetings.noLongerValidLocusMeeting);
|
|
1525
1624
|
assert.calledWith(destroySpy, meetingCollectionMeetings.otherNonLocusMeeting1);
|
|
1526
1625
|
assert.calledWith(destroySpy, meetingCollectionMeetings.otherNonLocusMeeting2);
|
|
@@ -1532,7 +1631,7 @@ describe('plugin-meetings', () => {
|
|
|
1532
1631
|
it('destroy any meeting that has no active locus url if keepOnlyLocusMeetings === true', async () => {
|
|
1533
1632
|
await webex.meetings.syncMeetings({keepOnlyLocusMeetings: true});
|
|
1534
1633
|
assert.calledOnce(webex.meetings.request.getActiveMeetings);
|
|
1535
|
-
assert.
|
|
1634
|
+
assert.calledTwice(webex.meetings.meetingCollection.getAll);
|
|
1536
1635
|
assert.calledWith(destroySpy, meetingCollectionMeetings.noLongerValidLocusMeeting);
|
|
1537
1636
|
assert.calledWith(destroySpy, meetingCollectionMeetings.otherNonLocusMeeting1);
|
|
1538
1637
|
assert.calledWith(destroySpy, meetingCollectionMeetings.otherNonLocusMeeting2);
|
|
@@ -1544,7 +1643,7 @@ describe('plugin-meetings', () => {
|
|
|
1544
1643
|
it('destroy any LOCUS meetings that have no active locus url if keepOnlyLocusMeetings === false', async () => {
|
|
1545
1644
|
await webex.meetings.syncMeetings({keepOnlyLocusMeetings: false});
|
|
1546
1645
|
assert.calledOnce(webex.meetings.request.getActiveMeetings);
|
|
1547
|
-
assert.
|
|
1646
|
+
assert.calledTwice(webex.meetings.meetingCollection.getAll);
|
|
1548
1647
|
assert.calledWith(destroySpy, meetingCollectionMeetings.noLongerValidLocusMeeting);
|
|
1549
1648
|
assert.callCount(destroySpy, 1);
|
|
1550
1649
|
|
|
@@ -1552,6 +1651,147 @@ describe('plugin-meetings', () => {
|
|
|
1552
1651
|
});
|
|
1553
1652
|
});
|
|
1554
1653
|
});
|
|
1654
|
+
|
|
1655
|
+
describe('when globalMeetingId preserves breakout meetings', () => {
|
|
1656
|
+
let destroySpy;
|
|
1657
|
+
let cleanUpSpy;
|
|
1658
|
+
|
|
1659
|
+
beforeEach(() => {
|
|
1660
|
+
destroySpy = sinon.spy(webex.meetings, 'destroy');
|
|
1661
|
+
cleanUpSpy = sinon.stub(MeetingUtil, 'cleanUp').returns(Promise.resolve());
|
|
1662
|
+
});
|
|
1663
|
+
|
|
1664
|
+
afterEach(() => {
|
|
1665
|
+
cleanUpSpy.restore();
|
|
1666
|
+
});
|
|
1667
|
+
|
|
1668
|
+
it('should not destroy a meeting whose globalMeetingId matches an active locus', async () => {
|
|
1669
|
+
const meetingCollectionMeetings = {
|
|
1670
|
+
breakoutMeeting: {
|
|
1671
|
+
locusUrl: 'breakout-url',
|
|
1672
|
+
locusInfo: {
|
|
1673
|
+
info: {globalMeetingId: 'gmid-123'},
|
|
1674
|
+
syncAllHashTreeDatasets: sinon.stub().resolves(),
|
|
1675
|
+
},
|
|
1676
|
+
sendCallAnalyzerMetrics: sinon.stub(),
|
|
1677
|
+
},
|
|
1678
|
+
};
|
|
1679
|
+
|
|
1680
|
+
webex.meetings.meetingCollection.getAll = sinon
|
|
1681
|
+
.stub()
|
|
1682
|
+
.returns(meetingCollectionMeetings);
|
|
1683
|
+
webex.meetings.request.getActiveMeetings = sinon.stub().resolves({
|
|
1684
|
+
loci: [{url: 'main-url', info: {globalMeetingId: 'gmid-123'}}],
|
|
1685
|
+
});
|
|
1686
|
+
|
|
1687
|
+
await webex.meetings.syncMeetings();
|
|
1688
|
+
|
|
1689
|
+
assert.notCalled(destroySpy);
|
|
1690
|
+
});
|
|
1691
|
+
|
|
1692
|
+
it('should destroy a meeting whose globalMeetingId does NOT match any active locus', async () => {
|
|
1693
|
+
const meetingCollectionMeetings = {
|
|
1694
|
+
breakoutMeeting: {
|
|
1695
|
+
locusUrl: 'breakout-url',
|
|
1696
|
+
locusInfo: {
|
|
1697
|
+
info: {globalMeetingId: 'gmid-other'},
|
|
1698
|
+
syncAllHashTreeDatasets: sinon.stub().resolves(),
|
|
1699
|
+
},
|
|
1700
|
+
sendCallAnalyzerMetrics: sinon.stub(),
|
|
1701
|
+
},
|
|
1702
|
+
};
|
|
1703
|
+
|
|
1704
|
+
webex.meetings.meetingCollection.getAll = sinon
|
|
1705
|
+
.stub()
|
|
1706
|
+
.returns(meetingCollectionMeetings);
|
|
1707
|
+
webex.meetings.request.getActiveMeetings = sinon.stub().resolves({
|
|
1708
|
+
loci: [{url: 'main-url', info: {globalMeetingId: 'gmid-123'}}],
|
|
1709
|
+
});
|
|
1710
|
+
|
|
1711
|
+
await webex.meetings.syncMeetings();
|
|
1712
|
+
|
|
1713
|
+
assert.calledOnce(destroySpy);
|
|
1714
|
+
assert.calledWith(destroySpy, meetingCollectionMeetings.breakoutMeeting);
|
|
1715
|
+
});
|
|
1716
|
+
});
|
|
1717
|
+
|
|
1718
|
+
describe('skipHashTreeSync parameter', () => {
|
|
1719
|
+
it('should skip syncAllHashTreeDatasets when skipHashTreeSync is true', async () => {
|
|
1720
|
+
const mockLocusInfo = {
|
|
1721
|
+
syncAllHashTreeDatasets: sinon.stub().resolves(),
|
|
1722
|
+
};
|
|
1723
|
+
|
|
1724
|
+
webex.meetings.request.getActiveMeetings = sinon.stub().resolves({loci: []});
|
|
1725
|
+
webex.meetings.meetingCollection.getAll = sinon.stub().returns({
|
|
1726
|
+
meeting1: {locusInfo: mockLocusInfo},
|
|
1727
|
+
});
|
|
1728
|
+
|
|
1729
|
+
await webex.meetings.syncMeetings({keepOnlyLocusMeetings: false, skipHashTreeSync: true});
|
|
1730
|
+
|
|
1731
|
+
assert.calledOnce(webex.meetings.request.getActiveMeetings);
|
|
1732
|
+
assert.notCalled(mockLocusInfo.syncAllHashTreeDatasets);
|
|
1733
|
+
});
|
|
1734
|
+
|
|
1735
|
+
it('should call syncAllHashTreeDatasets when skipHashTreeSync is false (default)', async () => {
|
|
1736
|
+
const mockLocusInfo = {
|
|
1737
|
+
syncAllHashTreeDatasets: sinon.stub().resolves(),
|
|
1738
|
+
};
|
|
1739
|
+
|
|
1740
|
+
webex.meetings.request.getActiveMeetings = sinon.stub().resolves({loci: []});
|
|
1741
|
+
webex.meetings.meetingCollection.getAll = sinon.stub().returns({
|
|
1742
|
+
meeting1: {locusInfo: mockLocusInfo},
|
|
1743
|
+
});
|
|
1744
|
+
|
|
1745
|
+
await webex.meetings.syncMeetings({keepOnlyLocusMeetings: false, skipHashTreeSync: false});
|
|
1746
|
+
|
|
1747
|
+
assert.calledOnce(webex.meetings.request.getActiveMeetings);
|
|
1748
|
+
assert.calledOnce(mockLocusInfo.syncAllHashTreeDatasets);
|
|
1749
|
+
});
|
|
1750
|
+
});
|
|
1751
|
+
|
|
1752
|
+
describe('syncAllHashTreeDatasets in syncMeetings', () => {
|
|
1753
|
+
it('should call syncAllHashTreeDatasets for multiple meetings, skipping those without locusInfo', async () => {
|
|
1754
|
+
const mockLocusInfo1 = {
|
|
1755
|
+
syncAllHashTreeDatasets: sinon.stub().resolves(),
|
|
1756
|
+
};
|
|
1757
|
+
const mockLocusInfo2 = {
|
|
1758
|
+
syncAllHashTreeDatasets: sinon.stub().resolves(),
|
|
1759
|
+
};
|
|
1760
|
+
|
|
1761
|
+
webex.meetings.request.getActiveMeetings = sinon.stub().resolves({loci: []});
|
|
1762
|
+
webex.meetings.meetingCollection.getAll = sinon.stub().returns({
|
|
1763
|
+
meeting1: {locusInfo: mockLocusInfo1},
|
|
1764
|
+
meeting2: {locusInfo: undefined},
|
|
1765
|
+
meeting3: {locusInfo: mockLocusInfo2},
|
|
1766
|
+
meeting4: {},
|
|
1767
|
+
});
|
|
1768
|
+
|
|
1769
|
+
await webex.meetings.syncMeetings({keepOnlyLocusMeetings: false});
|
|
1770
|
+
|
|
1771
|
+
assert.calledOnce(mockLocusInfo1.syncAllHashTreeDatasets);
|
|
1772
|
+
assert.calledOnce(mockLocusInfo2.syncAllHashTreeDatasets);
|
|
1773
|
+
});
|
|
1774
|
+
|
|
1775
|
+
it('should not call syncAllHashTreeDatasets when getActiveMeetings throws an error', async () => {
|
|
1776
|
+
const mockLocusInfo = {
|
|
1777
|
+
syncAllHashTreeDatasets: sinon.stub().resolves(),
|
|
1778
|
+
};
|
|
1779
|
+
|
|
1780
|
+
webex.meetings.request.getActiveMeetings = sinon.stub().rejects(new Error('network error'));
|
|
1781
|
+
webex.meetings.meetingCollection.getAll = sinon.stub().returns({
|
|
1782
|
+
meeting1: {locusInfo: mockLocusInfo},
|
|
1783
|
+
});
|
|
1784
|
+
|
|
1785
|
+
try {
|
|
1786
|
+
await webex.meetings.syncMeetings();
|
|
1787
|
+
assert.fail('should have thrown');
|
|
1788
|
+
} catch (err) {
|
|
1789
|
+
assert.equal(err.message, 'network error');
|
|
1790
|
+
}
|
|
1791
|
+
|
|
1792
|
+
assert.notCalled(mockLocusInfo.syncAllHashTreeDatasets);
|
|
1793
|
+
});
|
|
1794
|
+
});
|
|
1555
1795
|
});
|
|
1556
1796
|
describe('#fetchStaticMeetingLink', () => {
|
|
1557
1797
|
const conversationUrl = 'conv.fakeconversationurl.com';
|
|
@@ -2015,7 +2255,7 @@ describe('plugin-meetings', () => {
|
|
|
2015
2255
|
},
|
|
2016
2256
|
},
|
|
2017
2257
|
hashTreeMessage: undefined,
|
|
2018
|
-
});
|
|
2258
|
+
}, sinon.match.func);
|
|
2019
2259
|
});
|
|
2020
2260
|
it('should setup the meeting from a hash tree event', async () => {
|
|
2021
2261
|
const selfData = {};
|
|
@@ -2049,7 +2289,7 @@ describe('plugin-meetings', () => {
|
|
|
2049
2289
|
info: infoData,
|
|
2050
2290
|
},
|
|
2051
2291
|
hashTreeMessage,
|
|
2052
|
-
});
|
|
2292
|
+
}, sinon.match.func);
|
|
2053
2293
|
});
|
|
2054
2294
|
|
|
2055
2295
|
it('should ignore hash tree event when created locus has INACTIVE fullState', async () => {
|
|
@@ -2129,7 +2369,7 @@ describe('plugin-meetings', () => {
|
|
|
2129
2369
|
},
|
|
2130
2370
|
},
|
|
2131
2371
|
hashTreeMessage: undefined,
|
|
2132
|
-
});
|
|
2372
|
+
}, sinon.match.func);
|
|
2133
2373
|
});
|
|
2134
2374
|
|
|
2135
2375
|
it('sends client event correctly on finally', async () => {
|
|
@@ -2205,7 +2445,7 @@ describe('plugin-meetings', () => {
|
|
|
2205
2445
|
},
|
|
2206
2446
|
},
|
|
2207
2447
|
hashTreeMessage: undefined,
|
|
2208
|
-
});
|
|
2448
|
+
}, sinon.match.func);
|
|
2209
2449
|
});
|
|
2210
2450
|
|
|
2211
2451
|
const generateFakeLocusData = (isUnifiedSpaceMeeting) => ({
|
|
@@ -2833,6 +3073,39 @@ describe('plugin-meetings', () => {
|
|
|
2833
3073
|
checkCreateMeetingWithNoMeetingInfo(true, true);
|
|
2834
3074
|
});
|
|
2835
3075
|
|
|
3076
|
+
it('does not emit meeting:added when meeting is destroyed due to missing meeting info', async () => {
|
|
3077
|
+
// Make destroy actually remove the meeting from the collection
|
|
3078
|
+
// so that getMeetingByType returns null in the finally block
|
|
3079
|
+
webex.meetings.destroy = sinon.stub().callsFake((meeting) => {
|
|
3080
|
+
webex.meetings.meetingCollection.delete(meeting.id);
|
|
3081
|
+
});
|
|
3082
|
+
|
|
3083
|
+
try {
|
|
3084
|
+
await webex.meetings.createMeeting(
|
|
3085
|
+
'test destination',
|
|
3086
|
+
'test type',
|
|
3087
|
+
undefined,
|
|
3088
|
+
undefined,
|
|
3089
|
+
undefined,
|
|
3090
|
+
true
|
|
3091
|
+
);
|
|
3092
|
+
assert.fail('should have thrown NoMeetingInfoError');
|
|
3093
|
+
} catch (err) {
|
|
3094
|
+
assert.instanceOf(err, NoMeetingInfoError);
|
|
3095
|
+
}
|
|
3096
|
+
|
|
3097
|
+
assert.calledOnce(webex.meetings.destroy);
|
|
3098
|
+
|
|
3099
|
+
// meeting:added should NOT have been triggered since the meeting was destroyed
|
|
3100
|
+
assert.neverCalledWith(
|
|
3101
|
+
TriggerProxy.trigger,
|
|
3102
|
+
sinon.match.any,
|
|
3103
|
+
sinon.match({function: 'createMeeting'}),
|
|
3104
|
+
'meeting:added',
|
|
3105
|
+
sinon.match.any
|
|
3106
|
+
);
|
|
3107
|
+
});
|
|
3108
|
+
|
|
2836
3109
|
it('creates the meeting avoiding meeting info fetch by passing type as DESTINATION_TYPE.ONE_ON_ONE_CALL', async () => {
|
|
2837
3110
|
const meeting = await webex.meetings.createMeeting(
|
|
2838
3111
|
'test destination',
|
|
@@ -2847,6 +3120,30 @@ describe('plugin-meetings', () => {
|
|
|
2847
3120
|
|
|
2848
3121
|
assert.notCalled(webex.meetings.meetingInfo.fetchMeetingInfo);
|
|
2849
3122
|
});
|
|
3123
|
+
|
|
3124
|
+
[
|
|
3125
|
+
{fullStateType: 'CALL'},
|
|
3126
|
+
{fullStateType: 'SIP_BRIDGE'},
|
|
3127
|
+
{fullStateType: 'SPACE_SHARE'},
|
|
3128
|
+
].forEach(({fullStateType}) => {
|
|
3129
|
+
it(`skips meeting info fetch when LOCUS_ID destination is a 1:1 call (fullState.type ${fullStateType})`, async () => {
|
|
3130
|
+
const locusDestination = {
|
|
3131
|
+
fullState: {type: fullStateType},
|
|
3132
|
+
};
|
|
3133
|
+
|
|
3134
|
+
const meeting = await webex.meetings.createMeeting(
|
|
3135
|
+
locusDestination,
|
|
3136
|
+
DESTINATION_TYPE.LOCUS_ID
|
|
3137
|
+
);
|
|
3138
|
+
|
|
3139
|
+
assert.instanceOf(
|
|
3140
|
+
meeting,
|
|
3141
|
+
Meeting,
|
|
3142
|
+
'createMeeting should eventually resolve to a Meeting Object'
|
|
3143
|
+
);
|
|
3144
|
+
assert.notCalled(webex.meetings.meetingInfo.fetchMeetingInfo);
|
|
3145
|
+
});
|
|
3146
|
+
});
|
|
2850
3147
|
});
|
|
2851
3148
|
|
|
2852
3149
|
describe('rejected MeetingInfo.#fetchMeetingInfo - does not log for known Error types', () => {
|
|
@@ -3270,10 +3567,13 @@ describe('plugin-meetings', () => {
|
|
|
3270
3567
|
};
|
|
3271
3568
|
|
|
3272
3569
|
it('triggers correct event when SELF_CANNOT_VIEW_PARTICIPANT_LIST_CHANGE emitted', async () => {
|
|
3570
|
+
sinon.stub(meeting, 'updateMeetingActions');
|
|
3273
3571
|
checkSelfTrigger(
|
|
3274
3572
|
LOCUSINFO.EVENTS.SELF_CANNOT_VIEW_PARTICIPANT_LIST_CHANGE,
|
|
3275
3573
|
EVENT_TRIGGERS.MEETING_SELF_CANNOT_VIEW_PARTICIPANT_LIST
|
|
3276
3574
|
);
|
|
3575
|
+
assert.calledOnce(meeting.updateMeetingActions);
|
|
3576
|
+
meeting.updateMeetingActions.restore();
|
|
3277
3577
|
});
|
|
3278
3578
|
|
|
3279
3579
|
it('triggers correct event when SELF_IS_SHARING_BLOCKED_CHANGE emitted', async () => {
|
|
@@ -3426,6 +3726,21 @@ describe('plugin-meetings', () => {
|
|
|
3426
3726
|
'Meetings:index#isNeedHandleMainLocus --> self device left&moved in main locus with self joined status, not need to handle'
|
|
3427
3727
|
);
|
|
3428
3728
|
});
|
|
3729
|
+
|
|
3730
|
+
it('check breakout ended with self removed, return false', () => {
|
|
3731
|
+
webex.meetings.meetingCollection.getActiveBreakoutLocus = sinon.stub().returns(null);
|
|
3732
|
+
newLocus.self.state = 'LEFT';
|
|
3733
|
+
newLocus.self.reason = 'OTHER';
|
|
3734
|
+
newLocus.self.removed = true;
|
|
3735
|
+
newLocus.fullState = {state: 'INACTIVE', endMeetingReason: 'BREAKOUT_ENDED'};
|
|
3736
|
+
LoggerProxy.logger.log = sinon.stub();
|
|
3737
|
+
const result = webex.meetings.isNeedHandleMainLocus(meeting, newLocus);
|
|
3738
|
+
assert.equal(result, false);
|
|
3739
|
+
assert.calledWith(
|
|
3740
|
+
LoggerProxy.logger.log,
|
|
3741
|
+
'Meetings:index#isNeedHandleMainLocus --> self moved main locus with self removed status or with device resource moved, not need to handle'
|
|
3742
|
+
);
|
|
3743
|
+
});
|
|
3429
3744
|
});
|
|
3430
3745
|
|
|
3431
3746
|
describe('#isNeedHandleLocusDTO', () => {
|
|
@@ -3486,6 +3801,18 @@ describe('plugin-meetings', () => {
|
|
|
3486
3801
|
const result = webex.meetings.isNeedHandleLocusDTO(meeting, newLocus);
|
|
3487
3802
|
assert.equal(result, false);
|
|
3488
3803
|
});
|
|
3804
|
+
it('breakout session with breakout ended, return false', () => {
|
|
3805
|
+
newLocus.controls.breakout = {
|
|
3806
|
+
sessionType: 'BREAKOUT',
|
|
3807
|
+
};
|
|
3808
|
+
newLocus.self.state = 'LEFT';
|
|
3809
|
+
newLocus.self.reason = 'OTHER';
|
|
3810
|
+
newLocus.self.devices = [];
|
|
3811
|
+
newLocus.fullState = {state: 'INACTIVE', endMeetingReason: 'BREAKOUT_ENDED'};
|
|
3812
|
+
LoggerProxy.logger.log = sinon.stub();
|
|
3813
|
+
const result = webex.meetings.isNeedHandleLocusDTO(meeting, newLocus);
|
|
3814
|
+
assert.equal(result, false);
|
|
3815
|
+
});
|
|
3489
3816
|
it('moved to lobby, return true', () => {
|
|
3490
3817
|
newLocus.controls.breakout = {
|
|
3491
3818
|
sessionType: 'MAIN',
|