@webex/plugin-meetings 3.12.0-next.4 → 3.12.0-next.41
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 +6 -2
- package/dist/breakouts/breakout.js.map +1 -1
- package/dist/breakouts/index.js +1 -1
- package/dist/constants.js +1 -1
- 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 +23 -21
- 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 +10 -1
- package/dist/hashTree/constants.js.map +1 -1
- package/dist/hashTree/hashTreeParser.js +554 -350
- package/dist/hashTree/hashTreeParser.js.map +1 -1
- package/dist/hashTree/utils.js +22 -0
- package/dist/hashTree/utils.js.map +1 -1
- package/dist/interceptors/locusRetry.js +23 -8
- package/dist/interceptors/locusRetry.js.map +1 -1
- package/dist/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/locus-info/index.js +274 -85
- package/dist/locus-info/index.js.map +1 -1
- package/dist/locus-info/types.js +16 -0
- package/dist/locus-info/types.js.map +1 -1
- package/dist/meeting/index.js +710 -499
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/util.js +1 -0
- package/dist/meeting/util.js.map +1 -1
- package/dist/meetings/index.js +174 -77
- package/dist/meetings/index.js.map +1 -1
- package/dist/meetings/util.js +49 -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 +3 -0
- package/dist/member/util.js.map +1 -1
- package/dist/types/controls-options-manager/constants.d.ts +6 -1
- package/dist/types/hashTree/constants.d.ts +1 -0
- package/dist/types/hashTree/hashTreeParser.d.ts +53 -15
- package/dist/types/hashTree/utils.d.ts +11 -0
- package/dist/types/interceptors/locusRetry.d.ts +4 -4
- package/dist/types/locus-info/index.d.ts +46 -6
- package/dist/types/locus-info/types.d.ts +17 -1
- package/dist/types/meeting/index.d.ts +64 -1
- 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 +1 -0
- package/dist/webinar/index.js +301 -226
- 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 +2 -1
- package/src/constants.ts +1 -1
- package/src/controls-options-manager/constants.ts +14 -1
- package/src/controls-options-manager/index.ts +26 -19
- package/src/controls-options-manager/util.ts +81 -1
- package/src/hashTree/constants.ts +9 -0
- package/src/hashTree/hashTreeParser.ts +278 -160
- package/src/hashTree/utils.ts +17 -0
- package/src/interceptors/locusRetry.ts +25 -4
- package/src/locus-info/index.ts +274 -93
- package/src/locus-info/types.ts +19 -1
- package/src/meeting/index.ts +206 -22
- package/src/meeting/util.ts +1 -0
- package/src/meetings/index.ts +77 -43
- package/src/meetings/util.ts +56 -1
- package/src/member/index.ts +10 -0
- package/src/member/types.ts +1 -0
- package/src/member/util.ts +3 -0
- package/src/webinar/index.ts +75 -1
- package/test/unit/spec/aiEnableRequest/index.ts +86 -0
- package/test/unit/spec/breakouts/breakout.ts +7 -3
- package/test/unit/spec/controls-options-manager/index.js +114 -6
- package/test/unit/spec/controls-options-manager/util.js +165 -0
- package/test/unit/spec/hashTree/hashTreeParser.ts +996 -51
- package/test/unit/spec/hashTree/utils.ts +88 -1
- package/test/unit/spec/interceptors/locusRetry.ts +205 -4
- package/test/unit/spec/locus-info/index.js +397 -81
- package/test/unit/spec/meeting/index.js +271 -44
- package/test/unit/spec/meeting/utils.js +4 -0
- package/test/unit/spec/meetings/index.js +195 -13
- package/test/unit/spec/meetings/utils.js +137 -0
- package/test/unit/spec/member/index.js +7 -0
- package/test/unit/spec/member/util.js +24 -0
- package/test/unit/spec/webinar/index.ts +60 -0
|
@@ -13,6 +13,7 @@ import MediaSharesUtils from '@webex/plugin-meetings/src/locus-info//mediaShares
|
|
|
13
13
|
import LocusDeltaParser from '@webex/plugin-meetings/src/locus-info/parser';
|
|
14
14
|
import Metrics from '@webex/plugin-meetings/src/metrics';
|
|
15
15
|
import * as HashTreeParserModule from '@webex/plugin-meetings/src/hashTree/hashTreeParser';
|
|
16
|
+
import MeetingsUtil from '@webex/plugin-meetings/src/meetings/util';
|
|
16
17
|
|
|
17
18
|
import {
|
|
18
19
|
LOCUSINFO,
|
|
@@ -220,6 +221,47 @@ describe('plugin-meetings', () => {
|
|
|
220
221
|
assert.isTrue(locusInfo.emitChange);
|
|
221
222
|
});
|
|
222
223
|
|
|
224
|
+
it('calls onLocusSynced callback passed as second argument with full locus from join response', async () => {
|
|
225
|
+
const syncedLocus = {url: 'http://locus-url.com', participants: []};
|
|
226
|
+
const onLocusSynced = sinon.stub();
|
|
227
|
+
|
|
228
|
+
await locusInfo.initialSetup(
|
|
229
|
+
{
|
|
230
|
+
trigger: 'join-response',
|
|
231
|
+
locus: syncedLocus,
|
|
232
|
+
},
|
|
233
|
+
onLocusSynced
|
|
234
|
+
);
|
|
235
|
+
|
|
236
|
+
assert.calledOnceWithExactly(onLocusSynced, syncedLocus);
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
it('swallows onLocusSynced callback errors and logs warn', async () => {
|
|
240
|
+
const syncedLocus = {url: 'http://locus-url.com', participants: []};
|
|
241
|
+
const callbackError = new Error('onLocusSynced failed');
|
|
242
|
+
const onLocusSynced = sinon.stub().throws(callbackError);
|
|
243
|
+
const loggerWarnStub = LoggerProxy.logger.warn?.isSinonProxy
|
|
244
|
+
? LoggerProxy.logger.warn
|
|
245
|
+
: sinon.stub(LoggerProxy.logger, 'warn');
|
|
246
|
+
|
|
247
|
+
loggerWarnStub.resetHistory();
|
|
248
|
+
|
|
249
|
+
await locusInfo.initialSetup(
|
|
250
|
+
{
|
|
251
|
+
trigger: 'join-response',
|
|
252
|
+
locus: syncedLocus,
|
|
253
|
+
},
|
|
254
|
+
onLocusSynced
|
|
255
|
+
);
|
|
256
|
+
|
|
257
|
+
assert.calledOnceWithExactly(onLocusSynced, syncedLocus);
|
|
258
|
+
assert.calledOnce(loggerWarnStub);
|
|
259
|
+
assert.match(
|
|
260
|
+
loggerWarnStub.firstCall.args[0],
|
|
261
|
+
/Locus-info:index#initialSetup --> onLocusSynced callback failed/
|
|
262
|
+
);
|
|
263
|
+
});
|
|
264
|
+
|
|
223
265
|
it('should initialize the hash tree parser correctly when triggered from a get loci response containing visible datasets', async () => {
|
|
224
266
|
const visibleDataSets = ['dataset1', 'dataset2'];
|
|
225
267
|
const locus = createLocusWithVisibleDataSets(visibleDataSets);
|
|
@@ -413,7 +455,7 @@ describe('plugin-meetings', () => {
|
|
|
413
455
|
};
|
|
414
456
|
|
|
415
457
|
// simulate an update from the HashTreeParser (normally this would be triggered by incoming locus messages)
|
|
416
|
-
locusInfoUpdateCallback(OBJECTS_UPDATED,
|
|
458
|
+
locusInfoUpdateCallback({updateType: OBJECTS_UPDATED,
|
|
417
459
|
updatedObjects: [{htMeta: {elementId: {type: 'self'}}, data: newSelf}],
|
|
418
460
|
});
|
|
419
461
|
|
|
@@ -440,7 +482,7 @@ describe('plugin-meetings', () => {
|
|
|
440
482
|
locusInfo.info.isWebinar = true;
|
|
441
483
|
|
|
442
484
|
// simulate an update from the HashTreeParser (normally this would be triggered by incoming locus messages)
|
|
443
|
-
locusInfoUpdateCallback(OBJECTS_UPDATED,
|
|
485
|
+
locusInfoUpdateCallback({updateType: OBJECTS_UPDATED,
|
|
444
486
|
updatedObjects: [{htMeta: {elementId: {type: 'self'}}, data: newSelf}],
|
|
445
487
|
});
|
|
446
488
|
|
|
@@ -473,7 +515,7 @@ describe('plugin-meetings', () => {
|
|
|
473
515
|
locusInfo.info.isWebinar = true;
|
|
474
516
|
|
|
475
517
|
// simulate an update from the HashTreeParser (normally this would be triggered by incoming locus messages)
|
|
476
|
-
locusInfoUpdateCallback(OBJECTS_UPDATED,
|
|
518
|
+
locusInfoUpdateCallback({updateType: OBJECTS_UPDATED,
|
|
477
519
|
updatedObjects: [{htMeta: {elementId: {type: 'self'}}, data: newSelf}],
|
|
478
520
|
});
|
|
479
521
|
|
|
@@ -501,7 +543,7 @@ describe('plugin-meetings', () => {
|
|
|
501
543
|
};
|
|
502
544
|
|
|
503
545
|
// simulate an update from the HashTreeParser (normally this would be triggered by incoming locus messages)
|
|
504
|
-
locusInfoUpdateCallback(OBJECTS_UPDATED,
|
|
546
|
+
locusInfoUpdateCallback({updateType: OBJECTS_UPDATED,
|
|
505
547
|
updatedObjects: [{htMeta: {elementId: {type: 'fullState'}}, data: newFullState}],
|
|
506
548
|
});
|
|
507
549
|
|
|
@@ -519,7 +561,7 @@ describe('plugin-meetings', () => {
|
|
|
519
561
|
};
|
|
520
562
|
|
|
521
563
|
// simulate an update from the HashTreeParser (normally this would be triggered by incoming locus messages)
|
|
522
|
-
locusInfoUpdateCallback(OBJECTS_UPDATED,
|
|
564
|
+
locusInfoUpdateCallback({updateType: OBJECTS_UPDATED,
|
|
523
565
|
updatedObjects: [{htMeta: {elementId: {type: 'info'}}, data: newInfo}],
|
|
524
566
|
});
|
|
525
567
|
|
|
@@ -537,7 +579,7 @@ describe('plugin-meetings', () => {
|
|
|
537
579
|
};
|
|
538
580
|
|
|
539
581
|
// simulate an update from the HashTreeParser (normally this would be triggered by incoming locus messages)
|
|
540
|
-
locusInfoUpdateCallback(OBJECTS_UPDATED,
|
|
582
|
+
locusInfoUpdateCallback({updateType: OBJECTS_UPDATED,
|
|
541
583
|
updatedObjects: [{htMeta: {elementId: {type: 'links'}}, data: newLinks}],
|
|
542
584
|
});
|
|
543
585
|
|
|
@@ -557,7 +599,7 @@ describe('plugin-meetings', () => {
|
|
|
557
599
|
};
|
|
558
600
|
|
|
559
601
|
// simulate an update from the HashTreeParser (normally this would be triggered by incoming locus messages)
|
|
560
|
-
locusInfoUpdateCallback(OBJECTS_UPDATED,
|
|
602
|
+
locusInfoUpdateCallback({updateType: OBJECTS_UPDATED,
|
|
561
603
|
updatedObjects: [{htMeta: newLocusHtMeta, data: newLocus}],
|
|
562
604
|
});
|
|
563
605
|
|
|
@@ -590,7 +632,7 @@ describe('plugin-meetings', () => {
|
|
|
590
632
|
};
|
|
591
633
|
|
|
592
634
|
// simulate an update from the HashTreeParser (normally this would be triggered by incoming locus messages)
|
|
593
|
-
locusInfoUpdateCallback(OBJECTS_UPDATED,
|
|
635
|
+
locusInfoUpdateCallback({updateType: OBJECTS_UPDATED,
|
|
594
636
|
updatedObjects: [
|
|
595
637
|
{
|
|
596
638
|
htMeta: newLocusHtMeta,
|
|
@@ -637,7 +679,7 @@ describe('plugin-meetings', () => {
|
|
|
637
679
|
};
|
|
638
680
|
|
|
639
681
|
// simulate an update from the HashTreeParser (normally this would be triggered by incoming locus messages)
|
|
640
|
-
locusInfoUpdateCallback(OBJECTS_UPDATED,
|
|
682
|
+
locusInfoUpdateCallback({updateType: OBJECTS_UPDATED,
|
|
641
683
|
updatedObjects: [
|
|
642
684
|
// first, a removal of LOCUS object
|
|
643
685
|
{htMeta: {elementId: {type: 'locus'}}, data: null},
|
|
@@ -671,7 +713,7 @@ describe('plugin-meetings', () => {
|
|
|
671
713
|
const newLocusHtMeta = {elementId: {type: 'locus', version: 99}};
|
|
672
714
|
|
|
673
715
|
// simulate an update from the HashTreeParser (normally this would be triggered by incoming locus messages)
|
|
674
|
-
locusInfoUpdateCallback(OBJECTS_UPDATED,
|
|
716
|
+
locusInfoUpdateCallback({updateType: OBJECTS_UPDATED,
|
|
675
717
|
updatedObjects: [
|
|
676
718
|
// first, an update
|
|
677
719
|
{htMeta: newLocusHtMeta, data: newLocus},
|
|
@@ -700,7 +742,7 @@ describe('plugin-meetings', () => {
|
|
|
700
742
|
};
|
|
701
743
|
|
|
702
744
|
// simulate an update from the HashTreeParser (normally this would be triggered by incoming locus messages)
|
|
703
|
-
locusInfoUpdateCallback(OBJECTS_UPDATED,
|
|
745
|
+
locusInfoUpdateCallback({updateType: OBJECTS_UPDATED,
|
|
704
746
|
updatedObjects: [
|
|
705
747
|
// first, an update
|
|
706
748
|
{htMeta: {elementId: {type: 'locus'}}, data: newLocus1},
|
|
@@ -730,7 +772,7 @@ describe('plugin-meetings', () => {
|
|
|
730
772
|
};
|
|
731
773
|
// simulate an update from the HashTreeParser (normally this would be triggered by incoming locus messages)
|
|
732
774
|
// with 1 participant added, 1 updated, and 1 removed
|
|
733
|
-
locusInfoUpdateCallback(OBJECTS_UPDATED,
|
|
775
|
+
locusInfoUpdateCallback({updateType: OBJECTS_UPDATED,
|
|
734
776
|
updatedObjects: [
|
|
735
777
|
{htMeta: {elementId: {type: 'participant', id: 'fake-ht-participant-1'}}, data: null},
|
|
736
778
|
{
|
|
@@ -774,7 +816,7 @@ describe('plugin-meetings', () => {
|
|
|
774
816
|
};
|
|
775
817
|
// simulate an update from the HashTreeParser (normally this would be triggered by incoming locus messages)
|
|
776
818
|
// with 1 participant added, 1 updated, and 1 removed
|
|
777
|
-
locusInfoUpdateCallback(OBJECTS_UPDATED,
|
|
819
|
+
locusInfoUpdateCallback({updateType: OBJECTS_UPDATED,
|
|
778
820
|
updatedObjects: [
|
|
779
821
|
{htMeta: {elementId: {type: 'mediashare', id: 'fake-ht-mediaShare-1'}}, data: null},
|
|
780
822
|
{
|
|
@@ -807,7 +849,7 @@ describe('plugin-meetings', () => {
|
|
|
807
849
|
};
|
|
808
850
|
// simulate an update from the HashTreeParser (normally this would be triggered by incoming locus messages)
|
|
809
851
|
// with 1 embedded app added, 1 updated, and 1 removed
|
|
810
|
-
locusInfoUpdateCallback(OBJECTS_UPDATED,
|
|
852
|
+
locusInfoUpdateCallback({updateType: OBJECTS_UPDATED,
|
|
811
853
|
updatedObjects: [
|
|
812
854
|
{htMeta: {elementId: {type: 'embeddedapp', id: 'fake-ht-embeddedApp-1'}}, data: null},
|
|
813
855
|
{
|
|
@@ -844,7 +886,7 @@ describe('plugin-meetings', () => {
|
|
|
844
886
|
};
|
|
845
887
|
|
|
846
888
|
// simulate an update from the HashTreeParser (normally this would be triggered by incoming locus messages)
|
|
847
|
-
locusInfoUpdateCallback(OBJECTS_UPDATED,
|
|
889
|
+
locusInfoUpdateCallback({updateType: OBJECTS_UPDATED,
|
|
848
890
|
updatedObjects: [
|
|
849
891
|
{
|
|
850
892
|
htMeta: {elementId: {type: 'mediashare', id: 'fake-ht-mediaShare-2'}},
|
|
@@ -883,7 +925,7 @@ describe('plugin-meetings', () => {
|
|
|
883
925
|
};
|
|
884
926
|
|
|
885
927
|
// simulate an update from the HashTreeParser (normally this would be triggered by incoming locus messages)
|
|
886
|
-
locusInfoUpdateCallback(OBJECTS_UPDATED,
|
|
928
|
+
locusInfoUpdateCallback({updateType: OBJECTS_UPDATED,
|
|
887
929
|
updatedObjects: [
|
|
888
930
|
{
|
|
889
931
|
htMeta: {elementId: {type: 'controlentry', id: 'control-1'}},
|
|
@@ -911,7 +953,7 @@ describe('plugin-meetings', () => {
|
|
|
911
953
|
|
|
912
954
|
it('should process locus update correctly when CONTROL object is received with no data', () => {
|
|
913
955
|
// simulate an update from the HashTreeParser (normally this would be triggered by incoming locus messages)
|
|
914
|
-
locusInfoUpdateCallback(OBJECTS_UPDATED,
|
|
956
|
+
locusInfoUpdateCallback({updateType: OBJECTS_UPDATED,
|
|
915
957
|
updatedObjects: [
|
|
916
958
|
{
|
|
917
959
|
htMeta: {elementId: {type: 'controlentry', id: 'some-control-id'}},
|
|
@@ -935,7 +977,7 @@ describe('plugin-meetings', () => {
|
|
|
935
977
|
const destroyStub = sinon.stub(locusInfo.webex.meetings, 'destroy');
|
|
936
978
|
|
|
937
979
|
// simulate an update from the HashTreeParser (normally this would be triggered by incoming locus messages)
|
|
938
|
-
locusInfoUpdateCallback(MEETING_ENDED);
|
|
980
|
+
locusInfoUpdateCallback({updateType: MEETING_ENDED});
|
|
939
981
|
|
|
940
982
|
assert.calledOnceWithExactly(collectionGetStub, locusInfo.meetingId);
|
|
941
983
|
assert.calledOnceWithExactly(
|
|
@@ -953,7 +995,7 @@ describe('plugin-meetings', () => {
|
|
|
953
995
|
const destroyStub = sinon.stub(locusInfo.webex.meetings, 'destroy');
|
|
954
996
|
|
|
955
997
|
// simulate an update from the HashTreeParser (normally this would be triggered by incoming locus messages)
|
|
956
|
-
locusInfoUpdateCallback(MEETING_ENDED);
|
|
998
|
+
locusInfoUpdateCallback({updateType: MEETING_ENDED});
|
|
957
999
|
|
|
958
1000
|
assert.calledOnceWithExactly(collectionGetStub, locusInfo.meetingId);
|
|
959
1001
|
assert.notCalled(destroyStub);
|
|
@@ -963,7 +1005,7 @@ describe('plugin-meetings', () => {
|
|
|
963
1005
|
const createdHashTreeParser = locusInfo.hashTreeParsers.get('fake-locus-url');
|
|
964
1006
|
createdHashTreeParser.initializedFromHashTree = false;
|
|
965
1007
|
|
|
966
|
-
locusInfoUpdateCallback(OBJECTS_UPDATED,
|
|
1008
|
+
locusInfoUpdateCallback({updateType: OBJECTS_UPDATED,
|
|
967
1009
|
updatedObjects: [
|
|
968
1010
|
{
|
|
969
1011
|
htMeta: {elementId: {type: 'self'}},
|
|
@@ -978,7 +1020,7 @@ describe('plugin-meetings', () => {
|
|
|
978
1020
|
});
|
|
979
1021
|
|
|
980
1022
|
it('should set forceReplaceMembers to false on subsequent updates (initializedFromHashTree is true)', () => {
|
|
981
|
-
locusInfoUpdateCallback(OBJECTS_UPDATED,
|
|
1023
|
+
locusInfoUpdateCallback({updateType: OBJECTS_UPDATED,
|
|
982
1024
|
updatedObjects: [
|
|
983
1025
|
{
|
|
984
1026
|
htMeta: {elementId: {type: 'self'}},
|
|
@@ -994,7 +1036,7 @@ describe('plugin-meetings', () => {
|
|
|
994
1036
|
it('should copy participant data to self when participant matches self identity and state is LEFT with reason MOVED', () => {
|
|
995
1037
|
locusInfo.self = {id: 'fake-self', identity: 'user-123'};
|
|
996
1038
|
|
|
997
|
-
locusInfoUpdateCallback(OBJECTS_UPDATED,
|
|
1039
|
+
locusInfoUpdateCallback({updateType: OBJECTS_UPDATED,
|
|
998
1040
|
updatedObjects: [
|
|
999
1041
|
{
|
|
1000
1042
|
htMeta: {elementId: {type: 'participant', id: 99}},
|
|
@@ -2024,7 +2066,7 @@ describe('plugin-meetings', () => {
|
|
|
2024
2066
|
function: 'updateSelf',
|
|
2025
2067
|
},
|
|
2026
2068
|
LOCUSINFO.EVENTS.SELF_REMOTE_MUTE_STATUS_UPDATED,
|
|
2027
|
-
{muted: true, unmuteAllowed: true}
|
|
2069
|
+
{muted: true, unmuteAllowed: true, modifiedBy: null}
|
|
2028
2070
|
);
|
|
2029
2071
|
|
|
2030
2072
|
// but sometimes "previous self" is defined, but without controls.audio.muted, so we test this here:
|
|
@@ -2039,7 +2081,7 @@ describe('plugin-meetings', () => {
|
|
|
2039
2081
|
function: 'updateSelf',
|
|
2040
2082
|
},
|
|
2041
2083
|
LOCUSINFO.EVENTS.SELF_REMOTE_MUTE_STATUS_UPDATED,
|
|
2042
|
-
{muted: true, unmuteAllowed: true}
|
|
2084
|
+
{muted: true, unmuteAllowed: true, modifiedBy: null}
|
|
2043
2085
|
);
|
|
2044
2086
|
});
|
|
2045
2087
|
|
|
@@ -2098,7 +2140,7 @@ describe('plugin-meetings', () => {
|
|
|
2098
2140
|
function: 'updateSelf',
|
|
2099
2141
|
},
|
|
2100
2142
|
LOCUSINFO.EVENTS.SELF_REMOTE_MUTE_STATUS_UPDATED,
|
|
2101
|
-
{muted: true, unmuteAllowed: true}
|
|
2143
|
+
{muted: true, unmuteAllowed: true, modifiedBy: null}
|
|
2102
2144
|
);
|
|
2103
2145
|
});
|
|
2104
2146
|
|
|
@@ -2237,7 +2279,7 @@ describe('plugin-meetings', () => {
|
|
|
2237
2279
|
function: 'updateSelf',
|
|
2238
2280
|
},
|
|
2239
2281
|
LOCUSINFO.EVENTS.SELF_REMOTE_MUTE_STATUS_UPDATED,
|
|
2240
|
-
{muted: true, unmuteAllowed: false}
|
|
2282
|
+
{muted: true, unmuteAllowed: false, modifiedBy: null}
|
|
2241
2283
|
);
|
|
2242
2284
|
|
|
2243
2285
|
// now change only disallowUnmute
|
|
@@ -2255,7 +2297,28 @@ describe('plugin-meetings', () => {
|
|
|
2255
2297
|
function: 'updateSelf',
|
|
2256
2298
|
},
|
|
2257
2299
|
LOCUSINFO.EVENTS.SELF_REMOTE_MUTE_STATUS_UPDATED,
|
|
2258
|
-
{muted: true, unmuteAllowed: true}
|
|
2300
|
+
{muted: true, unmuteAllowed: true, modifiedBy: null}
|
|
2301
|
+
);
|
|
2302
|
+
});
|
|
2303
|
+
|
|
2304
|
+
it('should include modifiedBy in payload when muted by host', () => {
|
|
2305
|
+
locusInfo.webex.internal.device.url = self.deviceUrl;
|
|
2306
|
+
locusInfo.updateSelf(self);
|
|
2307
|
+
const newSelf = cloneDeep(self);
|
|
2308
|
+
newSelf.controls.audio.muted = true;
|
|
2309
|
+
newSelf.controls.audio.meta = {modifiedBy: 'host-uuid-123'};
|
|
2310
|
+
|
|
2311
|
+
locusInfo.emitScoped = sinon.stub();
|
|
2312
|
+
locusInfo.updateSelf(newSelf);
|
|
2313
|
+
|
|
2314
|
+
assert.calledWith(
|
|
2315
|
+
locusInfo.emitScoped,
|
|
2316
|
+
{
|
|
2317
|
+
file: 'locus-info',
|
|
2318
|
+
function: 'updateSelf',
|
|
2319
|
+
},
|
|
2320
|
+
LOCUSINFO.EVENTS.SELF_REMOTE_MUTE_STATUS_UPDATED,
|
|
2321
|
+
{muted: true, unmuteAllowed: true, modifiedBy: 'host-uuid-123'}
|
|
2259
2322
|
);
|
|
2260
2323
|
});
|
|
2261
2324
|
|
|
@@ -3154,13 +3217,14 @@ describe('plugin-meetings', () => {
|
|
|
3154
3217
|
const createMockParser = (state = 'active') => ({
|
|
3155
3218
|
state,
|
|
3156
3219
|
stop: sinon.stub(),
|
|
3157
|
-
|
|
3220
|
+
resumeFromMessage: sinon.stub(),
|
|
3158
3221
|
handleMessage: sinon.stub(),
|
|
3159
3222
|
});
|
|
3160
3223
|
|
|
3161
3224
|
const createSelfElementWithReplaces = (replacedLocusUrl, replacedAt) => ({
|
|
3162
3225
|
htMeta: {elementId: {type: 'Self'}},
|
|
3163
3226
|
data: {
|
|
3227
|
+
deviceUrl,
|
|
3164
3228
|
devices: [{url: deviceUrl, replaces: [{locusUrl: replacedLocusUrl, replacedAt}]}],
|
|
3165
3229
|
},
|
|
3166
3230
|
});
|
|
@@ -3236,7 +3300,7 @@ describe('plugin-meetings', () => {
|
|
|
3236
3300
|
stateElementsMessage: message,
|
|
3237
3301
|
});
|
|
3238
3302
|
|
|
3239
|
-
assert.calledOnce(parserA.
|
|
3303
|
+
assert.calledOnce(parserA.resumeFromMessage);
|
|
3240
3304
|
assert.calledOnce(parserB.stop);
|
|
3241
3305
|
});
|
|
3242
3306
|
|
|
@@ -3259,7 +3323,7 @@ describe('plugin-meetings', () => {
|
|
|
3259
3323
|
stateElementsMessage: message,
|
|
3260
3324
|
});
|
|
3261
3325
|
|
|
3262
|
-
assert.notCalled(parserA.
|
|
3326
|
+
assert.notCalled(parserA.resumeFromMessage);
|
|
3263
3327
|
assert.notCalled(parserB.stop);
|
|
3264
3328
|
});
|
|
3265
3329
|
|
|
@@ -3278,7 +3342,7 @@ describe('plugin-meetings', () => {
|
|
|
3278
3342
|
stateElementsMessage: message,
|
|
3279
3343
|
});
|
|
3280
3344
|
|
|
3281
|
-
assert.notCalled(parserA.
|
|
3345
|
+
assert.notCalled(parserA.resumeFromMessage);
|
|
3282
3346
|
assert.notCalled(parserA.handleMessage);
|
|
3283
3347
|
});
|
|
3284
3348
|
|
|
@@ -3362,6 +3426,51 @@ describe('plugin-meetings', () => {
|
|
|
3362
3426
|
|
|
3363
3427
|
assert.calledOnceWithExactly(parserA.handleMessage, message);
|
|
3364
3428
|
});
|
|
3429
|
+
|
|
3430
|
+
it('should send mismatch metric when eventType is not HASH_TREE_DATA_UPDATED', () => {
|
|
3431
|
+
const locusUrlA = 'http://locus-url-A.com';
|
|
3432
|
+
const parserA = {state: 'active', handleMessage: sinon.stub()};
|
|
3433
|
+
locusInfo.hashTreeParsers.set(locusUrlA, {parser: parserA, initializedFromHashTree: true});
|
|
3434
|
+
|
|
3435
|
+
locusInfo.parse(mockMeeting, {
|
|
3436
|
+
eventType: LOCUSEVENT.SELF_CHANGED,
|
|
3437
|
+
stateElementsMessage: {locusUrl: locusUrlA, locusStateElements: [], dataSets: []},
|
|
3438
|
+
});
|
|
3439
|
+
|
|
3440
|
+
assert.calledOnceWithExactly(
|
|
3441
|
+
sendBehavioralMetricStub,
|
|
3442
|
+
'js_sdk_locus_classic_vs_hash_tree_mismatch',
|
|
3443
|
+
{
|
|
3444
|
+
correlationId: mockMeeting.correlationId,
|
|
3445
|
+
message: `got ${LOCUSEVENT.SELF_CHANGED}, expected ${LOCUSEVENT.HASH_TREE_DATA_UPDATED}`,
|
|
3446
|
+
}
|
|
3447
|
+
);
|
|
3448
|
+
assert.notCalled(parserA.handleMessage);
|
|
3449
|
+
});
|
|
3450
|
+
});
|
|
3451
|
+
|
|
3452
|
+
describe('#sendClassicVsHashTreeMismatchMetric', () => {
|
|
3453
|
+
it('should send the metric when called for the first time', () => {
|
|
3454
|
+
locusInfo.sendClassicVsHashTreeMismatchMetric(mockMeeting, 'some mismatch');
|
|
3455
|
+
|
|
3456
|
+
assert.calledOnceWithExactly(
|
|
3457
|
+
sendBehavioralMetricStub,
|
|
3458
|
+
'js_sdk_locus_classic_vs_hash_tree_mismatch',
|
|
3459
|
+
{
|
|
3460
|
+
correlationId: mockMeeting.correlationId,
|
|
3461
|
+
message: 'some mismatch',
|
|
3462
|
+
}
|
|
3463
|
+
);
|
|
3464
|
+
});
|
|
3465
|
+
|
|
3466
|
+
it('should send the metric up to 5 times and stop after that', () => {
|
|
3467
|
+
for (let i = 0; i < 7; i += 1) {
|
|
3468
|
+
locusInfo.sendClassicVsHashTreeMismatchMetric(mockMeeting, `mismatch ${i}`);
|
|
3469
|
+
}
|
|
3470
|
+
|
|
3471
|
+
assert.callCount(sendBehavioralMetricStub, 5);
|
|
3472
|
+
assert.equal(locusInfo.classicVsHashTreeMismatchMetricCounter, 5);
|
|
3473
|
+
});
|
|
3365
3474
|
});
|
|
3366
3475
|
|
|
3367
3476
|
describe('#handleLocusAPIResponse', () => {
|
|
@@ -3417,19 +3526,174 @@ describe('plugin-meetings', () => {
|
|
|
3417
3526
|
assert.calledOnceWithExactly(locusInfo.handleLocusDelta, fakeLocus, mockMeeting);
|
|
3418
3527
|
});
|
|
3419
3528
|
|
|
3420
|
-
it('should send mismatch metric
|
|
3529
|
+
it('should send mismatch metric in classic mode when wrapped response has dataSets', () => {
|
|
3421
3530
|
const fakeLocus = {url: 'http://locus-url.com'};
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3531
|
+
sinon.stub(locusInfo, 'handleLocusDelta');
|
|
3532
|
+
|
|
3533
|
+
locusInfo.handleLocusAPIResponse(mockMeeting, {
|
|
3534
|
+
locus: fakeLocus,
|
|
3535
|
+
dataSets: [{name: 'dataset1', url: 'test-url'}],
|
|
3426
3536
|
});
|
|
3427
|
-
sinon.stub(locusInfo, 'sendClassicVsHashTreeMismatchMetric');
|
|
3428
3537
|
|
|
3429
|
-
|
|
3538
|
+
assert.calledOnceWithExactly(
|
|
3539
|
+
sendBehavioralMetricStub,
|
|
3540
|
+
'js_sdk_locus_classic_vs_hash_tree_mismatch',
|
|
3541
|
+
{
|
|
3542
|
+
correlationId: mockMeeting.correlationId,
|
|
3543
|
+
message: 'unexpected hash tree dataSets in API response',
|
|
3544
|
+
}
|
|
3545
|
+
);
|
|
3546
|
+
assert.calledOnce(locusInfo.handleLocusDelta);
|
|
3547
|
+
});
|
|
3430
3548
|
|
|
3431
|
-
|
|
3432
|
-
|
|
3549
|
+
describe('parser switch via API response', () => {
|
|
3550
|
+
const deviceUrl = 'http://device-url.com';
|
|
3551
|
+
const locusUrlA = 'http://locus-url-A.com';
|
|
3552
|
+
const locusUrlB = 'http://locus-url-B.com';
|
|
3553
|
+
|
|
3554
|
+
let HashTreeParserStub;
|
|
3555
|
+
|
|
3556
|
+
const createMockApiParser = (state = 'active') => ({
|
|
3557
|
+
state,
|
|
3558
|
+
stop: sinon.stub(),
|
|
3559
|
+
resumeFromApiResponse: sinon.stub(),
|
|
3560
|
+
handleLocusUpdate: sinon.stub(),
|
|
3561
|
+
initializeFromGetLociResponse: sinon.stub(),
|
|
3562
|
+
});
|
|
3563
|
+
|
|
3564
|
+
const createLocusWithReplaces = (url, replacedLocusUrl, replacedAt) => ({
|
|
3565
|
+
url,
|
|
3566
|
+
self: {
|
|
3567
|
+
devices: [{url: deviceUrl, replaces: [{locusUrl: replacedLocusUrl, replacedAt}]}],
|
|
3568
|
+
},
|
|
3569
|
+
});
|
|
3570
|
+
|
|
3571
|
+
const createLocusWithoutReplaces = (url) => ({
|
|
3572
|
+
url,
|
|
3573
|
+
self: {devices: [{url: deviceUrl}]},
|
|
3574
|
+
});
|
|
3575
|
+
|
|
3576
|
+
beforeEach(() => {
|
|
3577
|
+
locusInfo.webex.internal.device.url = deviceUrl;
|
|
3578
|
+
HashTreeParserStub = sinon
|
|
3579
|
+
.stub(HashTreeParserModule, 'default')
|
|
3580
|
+
.returns(createMockApiParser());
|
|
3581
|
+
});
|
|
3582
|
+
|
|
3583
|
+
it('should create a new parser and initialize it when no entry exists for the locusUrl', () => {
|
|
3584
|
+
// existing parser for a different url so hashTreeParsers.size > 0
|
|
3585
|
+
locusInfo.hashTreeParsers.set(locusUrlA, {parser: createMockApiParser(), initializedFromHashTree: true});
|
|
3586
|
+
|
|
3587
|
+
const locus = createLocusWithReplaces(locusUrlB, locusUrlA, '2026-01-01T00:00:00Z');
|
|
3588
|
+
sinon.stub(locusInfo, 'handleLocusDelta');
|
|
3589
|
+
|
|
3590
|
+
locusInfo.handleLocusAPIResponse(mockMeeting, {locus});
|
|
3591
|
+
|
|
3592
|
+
assert.isTrue(locusInfo.hashTreeParsers.has(locusUrlB));
|
|
3593
|
+
const newEntry = locusInfo.hashTreeParsers.get(locusUrlB);
|
|
3594
|
+
assert.isFalse(newEntry.initializedFromHashTree);
|
|
3595
|
+
|
|
3596
|
+
// the stub returns the mock, so initializeFromGetLociResponse should be called on it
|
|
3597
|
+
const createdParser = HashTreeParserStub.returnValues[0];
|
|
3598
|
+
assert.calledOnceWithExactly(createdParser.initializeFromGetLociResponse, locus);
|
|
3599
|
+
assert.notCalled(locusInfo.handleLocusDelta);
|
|
3600
|
+
});
|
|
3601
|
+
|
|
3602
|
+
it('should reactivate a stopped parser when replaces info is newer', () => {
|
|
3603
|
+
const parserA = createMockApiParser('stopped');
|
|
3604
|
+
const parserB = createMockApiParser('active');
|
|
3605
|
+
locusInfo.hashTreeParsers.set(locusUrlA, {parser: parserA, replacedAt: '2026-01-01T00:00:00Z', initializedFromHashTree: true});
|
|
3606
|
+
locusInfo.hashTreeParsers.set(locusUrlB, {parser: parserB, initializedFromHashTree: true});
|
|
3607
|
+
|
|
3608
|
+
const locus = createLocusWithReplaces(locusUrlA, locusUrlB, '2026-02-01T00:00:00Z');
|
|
3609
|
+
|
|
3610
|
+
locusInfo.handleLocusAPIResponse(mockMeeting, {locus});
|
|
3611
|
+
|
|
3612
|
+
assert.calledOnce(parserA.resumeFromApiResponse);
|
|
3613
|
+
assert.calledWithExactly(parserA.resumeFromApiResponse, locus);
|
|
3614
|
+
assert.calledOnce(parserB.stop);
|
|
3615
|
+
assert.equal(locusInfo.hashTreeParsers.get(locusUrlB).replacedAt, '2026-02-01T00:00:00Z');
|
|
3616
|
+
assert.isFalse(locusInfo.hashTreeParsers.get(locusUrlA).initializedFromHashTree);
|
|
3617
|
+
});
|
|
3618
|
+
|
|
3619
|
+
it('should not reactivate a stopped parser when replaces info is not newer', () => {
|
|
3620
|
+
const parserA = createMockApiParser('stopped');
|
|
3621
|
+
const parserB = createMockApiParser('active');
|
|
3622
|
+
locusInfo.hashTreeParsers.set(locusUrlA, {parser: parserA, replacedAt: '2026-03-01T00:00:00Z', initializedFromHashTree: true});
|
|
3623
|
+
locusInfo.hashTreeParsers.set(locusUrlB, {parser: parserB, initializedFromHashTree: true});
|
|
3624
|
+
|
|
3625
|
+
const locus = createLocusWithReplaces(locusUrlA, locusUrlB, '2026-01-01T00:00:00Z');
|
|
3626
|
+
|
|
3627
|
+
locusInfo.handleLocusAPIResponse(mockMeeting, {locus});
|
|
3628
|
+
|
|
3629
|
+
assert.notCalled(parserA.resumeFromApiResponse);
|
|
3630
|
+
assert.notCalled(parserB.stop);
|
|
3631
|
+
});
|
|
3632
|
+
|
|
3633
|
+
it('should not reactivate a stopped parser when no replaces info is available', () => {
|
|
3634
|
+
const parserA = createMockApiParser('stopped');
|
|
3635
|
+
locusInfo.hashTreeParsers.set(locusUrlA, {parser: parserA, initializedFromHashTree: true});
|
|
3636
|
+
|
|
3637
|
+
const locus = createLocusWithoutReplaces(locusUrlA);
|
|
3638
|
+
|
|
3639
|
+
locusInfo.handleLocusAPIResponse(mockMeeting, {locus});
|
|
3640
|
+
|
|
3641
|
+
assert.notCalled(parserA.resumeFromApiResponse);
|
|
3642
|
+
});
|
|
3643
|
+
});
|
|
3644
|
+
});
|
|
3645
|
+
|
|
3646
|
+
describe('#syncAllHashTreeDatasets', () => {
|
|
3647
|
+
it('should call syncAllDatasets on each parser that has an entry', async () => {
|
|
3648
|
+
const parser1 = {syncAllDatasets: sinon.stub().resolves()};
|
|
3649
|
+
const parser2 = {syncAllDatasets: sinon.stub().resolves()};
|
|
3650
|
+
locusInfo.hashTreeParsers.set('url1', {parser: parser1});
|
|
3651
|
+
locusInfo.hashTreeParsers.set('url2', {parser: parser2});
|
|
3652
|
+
|
|
3653
|
+
await locusInfo.syncAllHashTreeDatasets();
|
|
3654
|
+
|
|
3655
|
+
assert.calledOnce(parser1.syncAllDatasets);
|
|
3656
|
+
assert.calledOnce(parser2.syncAllDatasets);
|
|
3657
|
+
});
|
|
3658
|
+
|
|
3659
|
+
it('should skip parser entries without a parser object', async () => {
|
|
3660
|
+
const parser1 = {syncAllDatasets: sinon.stub().resolves()};
|
|
3661
|
+
locusInfo.hashTreeParsers.set('url1', {parser: parser1});
|
|
3662
|
+
locusInfo.hashTreeParsers.set('url2', {parser: undefined});
|
|
3663
|
+
|
|
3664
|
+
await locusInfo.syncAllHashTreeDatasets();
|
|
3665
|
+
|
|
3666
|
+
assert.calledOnce(parser1.syncAllDatasets);
|
|
3667
|
+
});
|
|
3668
|
+
|
|
3669
|
+
it('should await each parsers syncAllDatasets sequentially', async () => {
|
|
3670
|
+
const callOrder = [];
|
|
3671
|
+
const parser1 = {syncAllDatasets: sinon.stub().callsFake(() => {
|
|
3672
|
+
callOrder.push('start1');
|
|
3673
|
+
return new Promise((resolve) => {
|
|
3674
|
+
setTimeout(() => {
|
|
3675
|
+
callOrder.push('end1');
|
|
3676
|
+
resolve();
|
|
3677
|
+
}, 100);
|
|
3678
|
+
});
|
|
3679
|
+
})};
|
|
3680
|
+
const parser2 = {syncAllDatasets: sinon.stub().callsFake(() => {
|
|
3681
|
+
callOrder.push('start2');
|
|
3682
|
+
return Promise.resolve();
|
|
3683
|
+
})};
|
|
3684
|
+
locusInfo.hashTreeParsers.set('url1', {parser: parser1});
|
|
3685
|
+
locusInfo.hashTreeParsers.set('url2', {parser: parser2});
|
|
3686
|
+
|
|
3687
|
+
const clock = sinon.useFakeTimers();
|
|
3688
|
+
const promise = locusInfo.syncAllHashTreeDatasets();
|
|
3689
|
+
// parser1 started but parser2 not yet
|
|
3690
|
+
assert.deepEqual(callOrder, ['start1']);
|
|
3691
|
+
|
|
3692
|
+
await clock.tickAsync(100);
|
|
3693
|
+
await promise;
|
|
3694
|
+
// parser1 finished, then parser2 started and finished
|
|
3695
|
+
assert.deepEqual(callOrder, ['start1', 'end1', 'start2']);
|
|
3696
|
+
clock.restore();
|
|
3433
3697
|
});
|
|
3434
3698
|
});
|
|
3435
3699
|
|
|
@@ -3521,49 +3785,23 @@ describe('plugin-meetings', () => {
|
|
|
3521
3785
|
assert.deepEqual(callOrder, ['updateLocusUrl', 'updateMeetingInfo']);
|
|
3522
3786
|
});
|
|
3523
3787
|
|
|
3524
|
-
it('#updateLocusInfo ignores
|
|
3525
|
-
const newLocus = {
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
state: 'LEFT',
|
|
3529
|
-
},
|
|
3530
|
-
};
|
|
3788
|
+
it('#updateLocusInfo ignores locus when isSelfMovedOrBreakoutEnded returns true', () => {
|
|
3789
|
+
const newLocus = {self: {state: 'JOINED'}};
|
|
3790
|
+
|
|
3791
|
+
sinon.stub(MeetingsUtil, 'isSelfMovedOrBreakoutEnded').returns(true);
|
|
3531
3792
|
|
|
3532
3793
|
locusInfo.updateControls = sinon.stub();
|
|
3533
|
-
locusInfo.updateConversationUrl = sinon.stub();
|
|
3534
|
-
locusInfo.updateCreated = sinon.stub();
|
|
3535
3794
|
locusInfo.updateFullState = sinon.stub();
|
|
3536
|
-
locusInfo.updateHostInfo = sinon.stub();
|
|
3537
|
-
locusInfo.updateMeetingInfo = sinon.stub();
|
|
3538
|
-
locusInfo.updateMediaShares = sinon.stub();
|
|
3539
|
-
locusInfo.updateReplaces = sinon.stub();
|
|
3540
3795
|
locusInfo.updateSelf = sinon.stub();
|
|
3541
|
-
locusInfo.updateLocusUrl = sinon.stub();
|
|
3542
|
-
locusInfo.updateAclUrl = sinon.stub();
|
|
3543
|
-
locusInfo.updateBasequence = sinon.stub();
|
|
3544
|
-
locusInfo.updateSequence = sinon.stub();
|
|
3545
|
-
locusInfo.updateEmbeddedApps = sinon.stub();
|
|
3546
|
-
locusInfo.updateLinks = sinon.stub();
|
|
3547
|
-
locusInfo.compareAndUpdate = sinon.stub();
|
|
3548
3796
|
|
|
3549
3797
|
locusInfo.updateLocusInfo(newLocus);
|
|
3550
3798
|
|
|
3799
|
+
assert.calledOnceWithExactly(MeetingsUtil.isSelfMovedOrBreakoutEnded, newLocus);
|
|
3551
3800
|
assert.notCalled(locusInfo.updateControls);
|
|
3552
|
-
assert.notCalled(locusInfo.updateConversationUrl);
|
|
3553
|
-
assert.notCalled(locusInfo.updateCreated);
|
|
3554
3801
|
assert.notCalled(locusInfo.updateFullState);
|
|
3555
|
-
assert.notCalled(locusInfo.updateHostInfo);
|
|
3556
|
-
assert.notCalled(locusInfo.updateMeetingInfo);
|
|
3557
|
-
assert.notCalled(locusInfo.updateMediaShares);
|
|
3558
|
-
assert.notCalled(locusInfo.updateReplaces);
|
|
3559
3802
|
assert.notCalled(locusInfo.updateSelf);
|
|
3560
|
-
|
|
3561
|
-
|
|
3562
|
-
assert.notCalled(locusInfo.updateBasequence);
|
|
3563
|
-
assert.notCalled(locusInfo.updateSequence);
|
|
3564
|
-
assert.notCalled(locusInfo.updateEmbeddedApps);
|
|
3565
|
-
assert.notCalled(locusInfo.updateLinks);
|
|
3566
|
-
assert.notCalled(locusInfo.compareAndUpdate);
|
|
3803
|
+
|
|
3804
|
+
MeetingsUtil.isSelfMovedOrBreakoutEnded.restore();
|
|
3567
3805
|
});
|
|
3568
3806
|
|
|
3569
3807
|
it('#updateLocusInfo puts the Locus DTO top level properties at the right place in LocusInfo class', () => {
|
|
@@ -4413,6 +4651,31 @@ describe('plugin-meetings', () => {
|
|
|
4413
4651
|
});
|
|
4414
4652
|
});
|
|
4415
4653
|
|
|
4654
|
+
describe('#cleanUp', () => {
|
|
4655
|
+
it('calls cleanUp on all hash tree parsers and clears maps', () => {
|
|
4656
|
+
const parser1 = {cleanUp: sinon.stub()};
|
|
4657
|
+
const parser2 = {cleanUp: sinon.stub()};
|
|
4658
|
+
|
|
4659
|
+
locusInfo.hashTreeParsers.set('url1', {parser: parser1, initializedFromHashTree: true});
|
|
4660
|
+
locusInfo.hashTreeParsers.set('url2', {parser: parser2, initializedFromHashTree: true});
|
|
4661
|
+
locusInfo.hashTreeObjectId2ParticipantId.set(1, 'participant1');
|
|
4662
|
+
|
|
4663
|
+
locusInfo.cleanUp();
|
|
4664
|
+
|
|
4665
|
+
assert.calledOnce(parser1.cleanUp);
|
|
4666
|
+
assert.calledOnce(parser2.cleanUp);
|
|
4667
|
+
assert.equal(locusInfo.hashTreeParsers.size, 0);
|
|
4668
|
+
assert.equal(locusInfo.hashTreeObjectId2ParticipantId.size, 0);
|
|
4669
|
+
});
|
|
4670
|
+
|
|
4671
|
+
it('works when there are no hash tree parsers', () => {
|
|
4672
|
+
locusInfo.cleanUp();
|
|
4673
|
+
|
|
4674
|
+
assert.equal(locusInfo.hashTreeParsers.size, 0);
|
|
4675
|
+
assert.equal(locusInfo.hashTreeObjectId2ParticipantId.size, 0);
|
|
4676
|
+
});
|
|
4677
|
+
});
|
|
4678
|
+
|
|
4416
4679
|
describe('#handleOneonOneEvent', () => {
|
|
4417
4680
|
beforeEach(() => {
|
|
4418
4681
|
locusInfo.emitScoped = sinon.stub();
|
|
@@ -4455,6 +4718,9 @@ describe('plugin-meetings', () => {
|
|
|
4455
4718
|
});
|
|
4456
4719
|
|
|
4457
4720
|
describe('#isMeetingActive', () => {
|
|
4721
|
+
beforeEach(() => {
|
|
4722
|
+
webex.internal.newMetrics.submitClientEvent.resetHistory();
|
|
4723
|
+
});
|
|
4458
4724
|
forEach([_CALL_, _SIP_BRIDGE_, _SPACE_SHARE_], (type) => {
|
|
4459
4725
|
describe(`type = ${type}`, () => {
|
|
4460
4726
|
it('sends client event correctly for state = inactive', () => {
|
|
@@ -4521,7 +4787,7 @@ describe('plugin-meetings', () => {
|
|
|
4521
4787
|
});
|
|
4522
4788
|
});
|
|
4523
4789
|
|
|
4524
|
-
it('sends client event correctly for state =
|
|
4790
|
+
it('sends client event correctly for state = MEETING_INACTIVE', () => {
|
|
4525
4791
|
locusInfo.getLocusPartner = sinon.stub().returns({state: MEETING_STATE.STATES.LEFT});
|
|
4526
4792
|
locusInfo.parsedLocus = {
|
|
4527
4793
|
fullState: {
|
|
@@ -4543,7 +4809,7 @@ describe('plugin-meetings', () => {
|
|
|
4543
4809
|
});
|
|
4544
4810
|
});
|
|
4545
4811
|
|
|
4546
|
-
it('
|
|
4812
|
+
it('does not send client event when state = INACTIVE and endMeetingReason = BREAKOUT_ENDED', () => {
|
|
4547
4813
|
locusInfo.getLocusPartner = sinon.stub().returns({state: MEETING_STATE.STATES.LEFT});
|
|
4548
4814
|
locusInfo.parsedLocus = {
|
|
4549
4815
|
fullState: {
|
|
@@ -4552,17 +4818,41 @@ describe('plugin-meetings', () => {
|
|
|
4552
4818
|
};
|
|
4553
4819
|
|
|
4554
4820
|
locusInfo.fullState = {
|
|
4555
|
-
|
|
4821
|
+
state: LOCUS.STATE.INACTIVE,
|
|
4822
|
+
endMeetingReason: 'BREAKOUT_ENDED',
|
|
4556
4823
|
};
|
|
4557
4824
|
|
|
4558
4825
|
locusInfo.isMeetingActive();
|
|
4559
4826
|
|
|
4560
|
-
assert.
|
|
4561
|
-
|
|
4562
|
-
|
|
4563
|
-
|
|
4827
|
+
assert.notCalled(webex.internal.newMetrics.submitClientEvent);
|
|
4828
|
+
});
|
|
4829
|
+
|
|
4830
|
+
it('sends client event correctly for state self removed', () => {
|
|
4831
|
+
locusInfo.emitScoped = sinon.stub();
|
|
4832
|
+
locusInfo.parsedLocus = {
|
|
4833
|
+
fullState: {
|
|
4834
|
+
type: _MEETING_,
|
|
4564
4835
|
},
|
|
4565
|
-
|
|
4836
|
+
self: {
|
|
4837
|
+
removed: true,
|
|
4838
|
+
}
|
|
4839
|
+
};
|
|
4840
|
+
|
|
4841
|
+
locusInfo.isMeetingActive();
|
|
4842
|
+
|
|
4843
|
+
assert.notCalled(webex.internal.newMetrics.submitClientEvent);
|
|
4844
|
+
assert.calledOnceWithExactly(
|
|
4845
|
+
locusInfo.emitScoped,
|
|
4846
|
+
{
|
|
4847
|
+
file: 'locus-info',
|
|
4848
|
+
function: 'isMeetingActive',
|
|
4849
|
+
},
|
|
4850
|
+
EVENTS.DESTROY_MEETING,
|
|
4851
|
+
{
|
|
4852
|
+
reason: MEETING_REMOVED_REASON.SELF_REMOVED,
|
|
4853
|
+
shouldLeave: false,
|
|
4854
|
+
}
|
|
4855
|
+
);
|
|
4566
4856
|
});
|
|
4567
4857
|
});
|
|
4568
4858
|
|
|
@@ -4954,6 +5244,31 @@ describe('plugin-meetings', () => {
|
|
|
4954
5244
|
);
|
|
4955
5245
|
assert.notCalled(getTheLocusToUpdateStub);
|
|
4956
5246
|
});
|
|
5247
|
+
|
|
5248
|
+
it('should call handleLocusAPIResponse for SDK_LOCUS_FROM_SYNC_MEETINGS when hash tree parsers exist', () => {
|
|
5249
|
+
const fakeLocusUrl = 'http://locus-url.com';
|
|
5250
|
+
const fakeLocus = {url: fakeLocusUrl, fullState: {state: 'ACTIVE'}};
|
|
5251
|
+
const mockHashTreeParser = {
|
|
5252
|
+
handleMessage: sinon.stub(),
|
|
5253
|
+
handleLocusUpdate: sinon.stub(),
|
|
5254
|
+
};
|
|
5255
|
+
locusInfo.hashTreeParsers.set(fakeLocusUrl, {
|
|
5256
|
+
parser: mockHashTreeParser,
|
|
5257
|
+
initializedFromHashTree: true,
|
|
5258
|
+
});
|
|
5259
|
+
|
|
5260
|
+
sinon.stub(locusInfo, 'handleLocusDelta');
|
|
5261
|
+
|
|
5262
|
+
locusInfo.parse(mockMeeting, {
|
|
5263
|
+
eventType: LOCUSEVENT.SDK_LOCUS_FROM_SYNC_MEETINGS,
|
|
5264
|
+
locus: fakeLocus,
|
|
5265
|
+
});
|
|
5266
|
+
|
|
5267
|
+
// should route through handleLocusAPIResponse which passes unwrapped LocusDTO to parser
|
|
5268
|
+
assert.calledOnce(mockHashTreeParser.handleLocusUpdate);
|
|
5269
|
+
assert.notCalled(mockHashTreeParser.handleMessage);
|
|
5270
|
+
assert.notCalled(locusInfo.handleLocusDelta);
|
|
5271
|
+
});
|
|
4957
5272
|
});
|
|
4958
5273
|
});
|
|
4959
5274
|
|
|
@@ -5146,6 +5461,7 @@ describe('plugin-meetings', () => {
|
|
|
5146
5461
|
return {
|
|
5147
5462
|
htMeta: {elementId: {type: 'Self'}},
|
|
5148
5463
|
data: {
|
|
5464
|
+
deviceUrl,
|
|
5149
5465
|
devices,
|
|
5150
5466
|
},
|
|
5151
5467
|
};
|