@webex/plugin-meetings 3.9.0 → 3.10.0
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/dist/breakouts/breakout.js +1 -1
- package/dist/breakouts/index.js +1 -1
- package/dist/constants.js +8 -0
- package/dist/constants.js.map +1 -1
- package/dist/controls-options-manager/index.js +22 -5
- package/dist/controls-options-manager/index.js.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/interceptors/index.js +7 -0
- package/dist/interceptors/index.js.map +1 -1
- package/dist/interceptors/locusRouteToken.js +116 -0
- package/dist/interceptors/locusRouteToken.js.map +1 -0
- package/dist/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/locus-info/controlsUtils.js +11 -2
- package/dist/locus-info/controlsUtils.js.map +1 -1
- package/dist/locus-info/index.js +56 -14
- package/dist/locus-info/index.js.map +1 -1
- package/dist/locus-info/parser.js +4 -1
- package/dist/locus-info/parser.js.map +1 -1
- package/dist/media/properties.js +53 -5
- package/dist/media/properties.js.map +1 -1
- package/dist/meeting/in-meeting-actions.js +8 -0
- package/dist/meeting/in-meeting-actions.js.map +1 -1
- package/dist/meeting/index.js +339 -185
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/muteState.js +2 -5
- package/dist/meeting/muteState.js.map +1 -1
- package/dist/meeting/request.js +177 -14
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting/util.js +39 -11
- package/dist/meeting/util.js.map +1 -1
- package/dist/meeting-info/meeting-info-v2.js +29 -21
- package/dist/meeting-info/meeting-info-v2.js.map +1 -1
- package/dist/meetings/index.js +31 -25
- package/dist/meetings/index.js.map +1 -1
- package/dist/member/index.js +9 -0
- package/dist/member/index.js.map +1 -1
- package/dist/member/types.js.map +1 -1
- package/dist/member/util.js +10 -0
- package/dist/member/util.js.map +1 -1
- package/dist/members/collection.js +13 -0
- package/dist/members/collection.js.map +1 -1
- package/dist/members/index.js +42 -20
- package/dist/members/index.js.map +1 -1
- package/dist/members/util.js +7 -2
- package/dist/members/util.js.map +1 -1
- package/dist/metrics/constants.js +2 -1
- package/dist/metrics/constants.js.map +1 -1
- package/dist/reachability/index.js +3 -3
- package/dist/reachability/index.js.map +1 -1
- package/dist/types/constants.d.ts +7 -0
- package/dist/types/controls-options-manager/index.d.ts +9 -1
- package/dist/types/interceptors/index.d.ts +2 -1
- package/dist/types/interceptors/locusRouteToken.d.ts +38 -0
- package/dist/types/locus-info/index.d.ts +56 -2
- package/dist/types/media/properties.d.ts +21 -0
- package/dist/types/meeting/in-meeting-actions.d.ts +8 -0
- package/dist/types/meeting/index.d.ts +41 -1
- package/dist/types/meeting/request.d.ts +42 -0
- package/dist/types/meeting/util.d.ts +13 -3
- package/dist/types/meeting-info/meeting-info-v2.d.ts +6 -3
- package/dist/types/meetings/index.d.ts +3 -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 +5 -0
- package/dist/types/members/collection.d.ts +6 -0
- package/dist/types/members/index.d.ts +12 -2
- package/dist/types/members/util.d.ts +6 -3
- package/dist/types/metrics/constants.d.ts +1 -0
- package/dist/webinar/index.js +1 -1
- package/package.json +23 -23
- package/src/constants.ts +10 -0
- package/src/controls-options-manager/index.ts +26 -5
- package/src/index.ts +2 -1
- package/src/interceptors/index.ts +2 -1
- package/src/interceptors/locusRouteToken.ts +80 -0
- package/src/locus-info/controlsUtils.ts +18 -0
- package/src/locus-info/index.ts +99 -17
- package/src/locus-info/parser.ts +5 -1
- package/src/media/properties.ts +43 -0
- package/src/meeting/in-meeting-actions.ts +16 -0
- package/src/meeting/index.ts +204 -24
- package/src/meeting/muteState.ts +2 -6
- package/src/meeting/request.ts +141 -0
- package/src/meeting/util.ts +50 -20
- package/src/meeting-info/meeting-info-v2.ts +24 -5
- package/src/meetings/index.ts +9 -3
- package/src/member/index.ts +10 -0
- package/src/member/types.ts +1 -0
- package/src/member/util.ts +14 -0
- package/src/members/collection.ts +11 -0
- package/src/members/index.ts +38 -5
- package/src/members/util.ts +18 -2
- package/src/metrics/constants.ts +1 -0
- package/src/reachability/index.ts +3 -3
- package/test/unit/spec/common/browser-detection.js +0 -24
- package/test/unit/spec/controls-options-manager/index.js +47 -0
- package/test/unit/spec/fixture/locus.js +1 -0
- package/test/unit/spec/interceptors/locusRouteToken.ts +87 -0
- package/test/unit/spec/locus-info/index.js +91 -15
- package/test/unit/spec/locus-info/parser.js +3 -2
- package/test/unit/spec/media/properties.ts +137 -0
- package/test/unit/spec/meeting/in-meeting-actions.ts +8 -0
- package/test/unit/spec/meeting/index.js +398 -30
- package/test/unit/spec/meeting/muteState.js +32 -6
- package/test/unit/spec/meeting/request.js +21 -0
- package/test/unit/spec/meeting/utils.js +49 -17
- package/test/unit/spec/meeting-info/meetinginfov2.js +8 -3
- package/test/unit/spec/meetings/index.js +10 -5
- package/test/unit/spec/member/util.js +24 -0
- package/test/unit/spec/members/collection.js +120 -0
- package/test/unit/spec/members/index.js +72 -3
- package/test/unit/spec/members/request.js +55 -0
- package/test/unit/spec/members/utils.js +116 -14
- package/test/unit/spec/reachability/index.ts +158 -3
- package/test/unit/spec/roap/turnDiscovery.ts +3 -3
|
@@ -772,7 +772,7 @@ describe('plugin-meetings', () => {
|
|
|
772
772
|
},
|
|
773
773
|
};
|
|
774
774
|
locusInfo.emitScoped = sinon.stub();
|
|
775
|
-
locusInfo.updateParticipants({});
|
|
775
|
+
locusInfo.updateParticipants({}, []);
|
|
776
776
|
|
|
777
777
|
// if this assertion fails, double-check the attributes used in
|
|
778
778
|
// the updateParticipants function in locus-info/index.js
|
|
@@ -790,6 +790,7 @@ describe('plugin-meetings', () => {
|
|
|
790
790
|
selfId: '2',
|
|
791
791
|
hostId: '3',
|
|
792
792
|
isReplace: undefined,
|
|
793
|
+
removedParticipantIds: [],
|
|
793
794
|
}
|
|
794
795
|
);
|
|
795
796
|
// note: in a real use case, recordingId, selfId, and hostId would all be the same
|
|
@@ -814,7 +815,7 @@ describe('plugin-meetings', () => {
|
|
|
814
815
|
};
|
|
815
816
|
|
|
816
817
|
locusInfo.emitScoped = sinon.stub();
|
|
817
|
-
locusInfo.updateParticipants({}, true);
|
|
818
|
+
locusInfo.updateParticipants({}, [], true);
|
|
818
819
|
|
|
819
820
|
assert.calledWith(
|
|
820
821
|
locusInfo.emitScoped,
|
|
@@ -830,6 +831,7 @@ describe('plugin-meetings', () => {
|
|
|
830
831
|
selfId: '2',
|
|
831
832
|
hostId: '3',
|
|
832
833
|
isReplace: true,
|
|
834
|
+
removedParticipantIds: [],
|
|
833
835
|
}
|
|
834
836
|
);
|
|
835
837
|
});
|
|
@@ -847,7 +849,7 @@ describe('plugin-meetings', () => {
|
|
|
847
849
|
];
|
|
848
850
|
|
|
849
851
|
locusInfo.emitScoped = sinon.stub();
|
|
850
|
-
locusInfo.updateParticipants(failureParticipant);
|
|
852
|
+
locusInfo.updateParticipants(failureParticipant, []);
|
|
851
853
|
assert.calledWith(
|
|
852
854
|
locusInfo.emitScoped,
|
|
853
855
|
{
|
|
@@ -1641,6 +1643,28 @@ describe('plugin-meetings', () => {
|
|
|
1641
1643
|
);
|
|
1642
1644
|
});
|
|
1643
1645
|
|
|
1646
|
+
it('should trigger MEETING_INFO_UPDATED even if the roles array is empty', () => {
|
|
1647
|
+
const initialInfo = cloneDeep(meetingInfo);
|
|
1648
|
+
|
|
1649
|
+
const updateSelf = cloneDeep(self);
|
|
1650
|
+
updateSelf.controls.role.roles = [];
|
|
1651
|
+
|
|
1652
|
+
locusInfo.emitScoped = sinon.stub();
|
|
1653
|
+
locusInfo.updateMeetingInfo(initialInfo, updateSelf);
|
|
1654
|
+
|
|
1655
|
+
assert.calledWith(
|
|
1656
|
+
locusInfo.emitScoped,
|
|
1657
|
+
{
|
|
1658
|
+
file: 'locus-info',
|
|
1659
|
+
function: 'updateMeetingInfo',
|
|
1660
|
+
},
|
|
1661
|
+
LOCUSINFO.EVENTS.MEETING_INFO_UPDATED,
|
|
1662
|
+
{
|
|
1663
|
+
isInitializing: !self,
|
|
1664
|
+
}
|
|
1665
|
+
);
|
|
1666
|
+
});
|
|
1667
|
+
|
|
1644
1668
|
const checkMeetingInfoUpdatedCalled = (expected, payload) => {
|
|
1645
1669
|
const expectedArgs = [
|
|
1646
1670
|
locusInfo.emitScoped,
|
|
@@ -2016,6 +2040,18 @@ describe('plugin-meetings', () => {
|
|
|
2016
2040
|
});
|
|
2017
2041
|
});
|
|
2018
2042
|
|
|
2043
|
+
describe('#handleLocusAPIResponse', () => {
|
|
2044
|
+
it('calls handleLocusDelta', () => {
|
|
2045
|
+
const fakeLocus = {eventType: LOCUSEVENT.DIFFERENCE};
|
|
2046
|
+
|
|
2047
|
+
sinon.stub(locusInfo, 'handleLocusDelta');
|
|
2048
|
+
|
|
2049
|
+
locusInfo.handleLocusAPIResponse(mockMeeting, {locus: fakeLocus});
|
|
2050
|
+
|
|
2051
|
+
assert.calledWith(locusInfo.handleLocusDelta, fakeLocus, mockMeeting);
|
|
2052
|
+
});
|
|
2053
|
+
});
|
|
2054
|
+
|
|
2019
2055
|
describe('#LocusDeltaEvents', () => {
|
|
2020
2056
|
const fakeMeeting = 'fakeMeeting';
|
|
2021
2057
|
let sandbox = null;
|
|
@@ -2028,7 +2064,7 @@ describe('plugin-meetings', () => {
|
|
|
2028
2064
|
|
|
2029
2065
|
fakeLocus = {
|
|
2030
2066
|
meeting: true,
|
|
2031
|
-
participants:
|
|
2067
|
+
participants: [],
|
|
2032
2068
|
url: 'newLocusUrl',
|
|
2033
2069
|
syncUrl: 'newSyncUrl',
|
|
2034
2070
|
};
|
|
@@ -2347,23 +2383,23 @@ describe('plugin-meetings', () => {
|
|
|
2347
2383
|
|
|
2348
2384
|
it('applyLocusDeltaData handles LOCUS_URL_CHANGED action correctly', () => {
|
|
2349
2385
|
const {LOCUS_URL_CHANGED} = LocusDeltaParser.loci;
|
|
2350
|
-
const
|
|
2386
|
+
const fakeFullLocus = {
|
|
2387
|
+
url: 'new full loci url',
|
|
2388
|
+
};
|
|
2351
2389
|
const meeting = {
|
|
2352
2390
|
meetingRequest: {
|
|
2353
|
-
getLocusDTO: sandbox.stub().resolves({body:
|
|
2391
|
+
getLocusDTO: sandbox.stub().resolves({body: fakeFullLocus}),
|
|
2354
2392
|
},
|
|
2355
2393
|
locusInfo: {
|
|
2356
2394
|
handleLocusDelta: sandbox.stub(),
|
|
2357
2395
|
},
|
|
2358
|
-
locusUrl: 'current locus url',
|
|
2396
|
+
locusUrl: 'current BO session locus url',
|
|
2359
2397
|
};
|
|
2360
2398
|
|
|
2361
|
-
locusInfo.locusParser.workingCopy =
|
|
2362
|
-
syncUrl: 'current sync url',
|
|
2363
|
-
};
|
|
2399
|
+
locusInfo.locusParser.workingCopy = null;
|
|
2364
2400
|
|
|
2365
2401
|
locusInfo.applyLocusDeltaData(LOCUS_URL_CHANGED, fakeLocus, meeting);
|
|
2366
|
-
assert.calledOnceWithExactly(meeting.meetingRequest.getLocusDTO, {url:
|
|
2402
|
+
assert.calledOnceWithExactly(meeting.meetingRequest.getLocusDTO, {url: fakeLocus.url});
|
|
2367
2403
|
});
|
|
2368
2404
|
|
|
2369
2405
|
describe('edge cases for sync failing', () => {
|
|
@@ -2503,7 +2539,7 @@ describe('plugin-meetings', () => {
|
|
|
2503
2539
|
});
|
|
2504
2540
|
|
|
2505
2541
|
it('onDeltaLocus handle delta data', () => {
|
|
2506
|
-
fakeLocus.participants =
|
|
2542
|
+
fakeLocus.participants = [];
|
|
2507
2543
|
const fakeBreakout = {
|
|
2508
2544
|
sessionId: 'sessionId',
|
|
2509
2545
|
groupId: 'groupId',
|
|
@@ -2520,11 +2556,11 @@ describe('plugin-meetings', () => {
|
|
|
2520
2556
|
};
|
|
2521
2557
|
locusInfo.updateParticipants = sinon.stub();
|
|
2522
2558
|
locusInfo.onDeltaLocus(fakeLocus);
|
|
2523
|
-
assert.calledWith(locusInfo.updateParticipants,
|
|
2559
|
+
assert.calledWith(locusInfo.updateParticipants, [], undefined, false);
|
|
2524
2560
|
|
|
2525
2561
|
fakeLocus.controls.breakout.sessionId = 'sessionId2';
|
|
2526
2562
|
locusInfo.onDeltaLocus(fakeLocus);
|
|
2527
|
-
assert.calledWith(locusInfo.updateParticipants,
|
|
2563
|
+
assert.calledWith(locusInfo.updateParticipants, [], undefined, true);
|
|
2528
2564
|
});
|
|
2529
2565
|
|
|
2530
2566
|
it('onDeltaLocus merges delta participants with existing participants', () => {
|
|
@@ -2541,7 +2577,7 @@ describe('plugin-meetings', () => {
|
|
|
2541
2577
|
existingParticipants,
|
|
2542
2578
|
FAKE_DELTA_PARTICIPANTS
|
|
2543
2579
|
);
|
|
2544
|
-
assert.calledWith(locusInfo.updateParticipants, FAKE_DELTA_PARTICIPANTS, false);
|
|
2580
|
+
assert.calledWith(locusInfo.updateParticipants, FAKE_DELTA_PARTICIPANTS, undefined, false);
|
|
2545
2581
|
});
|
|
2546
2582
|
|
|
2547
2583
|
[true, false].forEach((isDelta) =>
|
|
@@ -2984,6 +3020,45 @@ describe('plugin-meetings', () => {
|
|
|
2984
3020
|
});
|
|
2985
3021
|
});
|
|
2986
3022
|
|
|
3023
|
+
describe('#updateLocusUrl', () => {
|
|
3024
|
+
it('trigger LOCUS_INFO_UPDATE_URL event with isMainLocus is true as default', () => {
|
|
3025
|
+
const fakeUrl = "https://fake.com/locus";
|
|
3026
|
+
locusInfo.emitScoped = sinon.stub();
|
|
3027
|
+
locusInfo.updateLocusUrl(fakeUrl);
|
|
3028
|
+
|
|
3029
|
+
assert.calledWith(
|
|
3030
|
+
locusInfo.emitScoped,
|
|
3031
|
+
{
|
|
3032
|
+
file: 'locus-info',
|
|
3033
|
+
function: 'updateLocusUrl',
|
|
3034
|
+
},
|
|
3035
|
+
EVENTS.LOCUS_INFO_UPDATE_URL,
|
|
3036
|
+
{
|
|
3037
|
+
url: fakeUrl,
|
|
3038
|
+
isMainLocus: true
|
|
3039
|
+
},
|
|
3040
|
+
);
|
|
3041
|
+
});
|
|
3042
|
+
it('trigger LOCUS_INFO_UPDATE_URL event with isMainLocus is false', () => {
|
|
3043
|
+
const fakeUrl = "https://fake.com/locus";
|
|
3044
|
+
locusInfo.emitScoped = sinon.stub();
|
|
3045
|
+
locusInfo.updateLocusUrl(fakeUrl, false);
|
|
3046
|
+
|
|
3047
|
+
assert.calledWith(
|
|
3048
|
+
locusInfo.emitScoped,
|
|
3049
|
+
{
|
|
3050
|
+
file: 'locus-info',
|
|
3051
|
+
function: 'updateLocusUrl',
|
|
3052
|
+
},
|
|
3053
|
+
EVENTS.LOCUS_INFO_UPDATE_URL,
|
|
3054
|
+
{
|
|
3055
|
+
url: fakeUrl,
|
|
3056
|
+
isMainLocus: false
|
|
3057
|
+
},
|
|
3058
|
+
);
|
|
3059
|
+
});
|
|
3060
|
+
});
|
|
3061
|
+
|
|
2987
3062
|
// semi-integration tests that use real LocusInfo with real Parser
|
|
2988
3063
|
// and test various scenarios related to handling out-of-order Locus delta events
|
|
2989
3064
|
describe('handling of out-of-order Locus delta events', () => {
|
|
@@ -3052,6 +3127,7 @@ describe('plugin-meetings', () => {
|
|
|
3052
3127
|
id: 'test person id',
|
|
3053
3128
|
},
|
|
3054
3129
|
},
|
|
3130
|
+
participants: [],
|
|
3055
3131
|
});
|
|
3056
3132
|
|
|
3057
3133
|
updateLocusInfoStub.resetHistory();
|
|
@@ -253,7 +253,8 @@ describe('locus-info/parser', () => {
|
|
|
253
253
|
});
|
|
254
254
|
|
|
255
255
|
it('replaces current loci when the locus URL changes and incoming sequence is later, even when baseSequence doesn\'t match', () => {
|
|
256
|
-
const {
|
|
256
|
+
const {LOCUS_URL_CHANGED} = LocusDeltaParser.loci;
|
|
257
|
+
sandbox.stub(LocusDeltaParser, 'compare').returns(LOCUS_URL_CHANGED);
|
|
257
258
|
|
|
258
259
|
parser.queue.dequeue = sandbox.stub().returns(NEW_LOCI);
|
|
259
260
|
parser.onDeltaAction = sandbox.stub();
|
|
@@ -262,7 +263,7 @@ describe('locus-info/parser', () => {
|
|
|
262
263
|
|
|
263
264
|
parser.processDeltaEvent();
|
|
264
265
|
|
|
265
|
-
assert.equal(parser.workingCopy,
|
|
266
|
+
assert.equal(parser.workingCopy, null);
|
|
266
267
|
});
|
|
267
268
|
|
|
268
269
|
it('does not replace current loci when the locus URL changes but incoming sequence is not later', () => {
|
|
@@ -6,6 +6,8 @@ import * as tsSdpModule from '@webex/ts-sdp';
|
|
|
6
6
|
import MediaProperties from '@webex/plugin-meetings/src/media/properties';
|
|
7
7
|
import {Defer} from '@webex/common';
|
|
8
8
|
import MediaConnectionAwaiter from '../../../../src/media/MediaConnectionAwaiter';
|
|
9
|
+
import Metrics from '../../../../src/metrics';
|
|
10
|
+
import BEHAVIORAL_METRICS from '../../../../src/metrics/constants';
|
|
9
11
|
|
|
10
12
|
describe('MediaProperties', () => {
|
|
11
13
|
let mediaProperties;
|
|
@@ -389,4 +391,139 @@ describe('MediaProperties', () => {
|
|
|
389
391
|
});
|
|
390
392
|
});
|
|
391
393
|
});
|
|
394
|
+
|
|
395
|
+
// issue types and subtypes used in these tests are just examples
|
|
396
|
+
// they don't reflect real issue types/subtypes used in production
|
|
397
|
+
describe('sendMediaIssueMetric', () => {
|
|
398
|
+
let sendBehavioralMetricStub;
|
|
399
|
+
let clock;
|
|
400
|
+
|
|
401
|
+
beforeEach(() => {
|
|
402
|
+
clock = sinon.useFakeTimers();
|
|
403
|
+
sendBehavioralMetricStub = sinon.stub(Metrics, 'sendBehavioralMetric');
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
afterEach(() => {
|
|
407
|
+
clock.restore();
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
it('should send a behavioral metric with correct parameters', () => {
|
|
411
|
+
const issueType = 'audio';
|
|
412
|
+
const issueSubType = 'packet-loss';
|
|
413
|
+
const correlationId = 'test-correlation-id-123';
|
|
414
|
+
|
|
415
|
+
mediaProperties.sendMediaIssueMetric(issueType, issueSubType, correlationId);
|
|
416
|
+
|
|
417
|
+
assert.calledOnce(sendBehavioralMetricStub);
|
|
418
|
+
assert.calledWith(sendBehavioralMetricStub, BEHAVIORAL_METRICS.MEDIA_ISSUE_DETECTED, {
|
|
419
|
+
correlationId,
|
|
420
|
+
'audio_packet-loss': 1,
|
|
421
|
+
});
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
it('should increment count while being throttled and reset it once metric goes out', () => {
|
|
425
|
+
const issueType = 'video';
|
|
426
|
+
const issueSubType = 'freeze';
|
|
427
|
+
const correlationId = 'test-correlation-id';
|
|
428
|
+
|
|
429
|
+
// Call multiple times with same issue type/subtype
|
|
430
|
+
mediaProperties.sendMediaIssueMetric(issueType, issueSubType, correlationId);
|
|
431
|
+
mediaProperties.sendMediaIssueMetric(issueType, issueSubType, correlationId);
|
|
432
|
+
mediaProperties.sendMediaIssueMetric(issueType, issueSubType, correlationId);
|
|
433
|
+
|
|
434
|
+
// First call should go through immediately, subsequent calls are throttled
|
|
435
|
+
assert.calledOnce(sendBehavioralMetricStub);
|
|
436
|
+
assert.calledWith(sendBehavioralMetricStub, BEHAVIORAL_METRICS.MEDIA_ISSUE_DETECTED, {
|
|
437
|
+
correlationId,
|
|
438
|
+
video_freeze: 1, // Only the first call goes through due to throttling
|
|
439
|
+
});
|
|
440
|
+
sendBehavioralMetricStub.resetHistory();
|
|
441
|
+
|
|
442
|
+
assert.equal(mediaProperties.mediaIssueCounters['video_freeze'], 2); // counter should be reset after the first metric goes out, hence only 2 not 3 here
|
|
443
|
+
|
|
444
|
+
clock.tick(5 * 60 * 1000); // Advance time by 5 minutes to expire throttle
|
|
445
|
+
|
|
446
|
+
assert.calledOnceWithExactly(
|
|
447
|
+
sendBehavioralMetricStub,
|
|
448
|
+
BEHAVIORAL_METRICS.MEDIA_ISSUE_DETECTED,
|
|
449
|
+
{
|
|
450
|
+
correlationId,
|
|
451
|
+
video_freeze: 2,
|
|
452
|
+
}
|
|
453
|
+
);
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
it('should track different issue types separately in counters', () => {
|
|
457
|
+
const correlationId = 'test-correlation-id';
|
|
458
|
+
|
|
459
|
+
// Send different issue types
|
|
460
|
+
mediaProperties.sendMediaIssueMetric('audio', 'packet-loss', correlationId);
|
|
461
|
+
mediaProperties.sendMediaIssueMetric('video', 'freeze', correlationId);
|
|
462
|
+
mediaProperties.sendMediaIssueMetric('audio', 'packet-loss', correlationId);
|
|
463
|
+
mediaProperties.sendMediaIssueMetric('audio', 'packet-loss', correlationId);
|
|
464
|
+
mediaProperties.sendMediaIssueMetric('audio', 'packet-loss', correlationId);
|
|
465
|
+
mediaProperties.sendMediaIssueMetric('video', 'freeze', correlationId);
|
|
466
|
+
|
|
467
|
+
// First call should go through immediately, subsequent calls are throttled
|
|
468
|
+
assert.calledOnceWithExactly(
|
|
469
|
+
sendBehavioralMetricStub,
|
|
470
|
+
BEHAVIORAL_METRICS.MEDIA_ISSUE_DETECTED,
|
|
471
|
+
{
|
|
472
|
+
correlationId,
|
|
473
|
+
'audio_packet-loss': 1,
|
|
474
|
+
}
|
|
475
|
+
);
|
|
476
|
+
|
|
477
|
+
// But the counters should be tracked separately
|
|
478
|
+
assert.equal(mediaProperties.mediaIssueCounters['audio_packet-loss'], 3);
|
|
479
|
+
assert.equal(mediaProperties.mediaIssueCounters['video_freeze'], 2);
|
|
480
|
+
|
|
481
|
+
sendBehavioralMetricStub.resetHistory();
|
|
482
|
+
|
|
483
|
+
clock.tick(5 * 60 * 1000); // Advance time by 5 minutes to expire throttle
|
|
484
|
+
|
|
485
|
+
assert.calledOnceWithExactly(
|
|
486
|
+
sendBehavioralMetricStub,
|
|
487
|
+
BEHAVIORAL_METRICS.MEDIA_ISSUE_DETECTED,
|
|
488
|
+
{
|
|
489
|
+
correlationId,
|
|
490
|
+
video_freeze: 2,
|
|
491
|
+
'audio_packet-loss': 3,
|
|
492
|
+
}
|
|
493
|
+
);
|
|
494
|
+
});
|
|
495
|
+
|
|
496
|
+
it('should flush throttled metrics when unsetPeerConnection is called', () => {
|
|
497
|
+
const issueType = 'share';
|
|
498
|
+
const issueSubType = 'connection-lost';
|
|
499
|
+
const correlationId = 'test-correlation-id';
|
|
500
|
+
|
|
501
|
+
// Send metrics multiple times
|
|
502
|
+
mediaProperties.sendMediaIssueMetric(issueType, issueSubType, correlationId);
|
|
503
|
+
mediaProperties.sendMediaIssueMetric(issueType, issueSubType, correlationId);
|
|
504
|
+
|
|
505
|
+
// First call should go through immediately
|
|
506
|
+
assert.calledOnceWithExactly(
|
|
507
|
+
sendBehavioralMetricStub,
|
|
508
|
+
BEHAVIORAL_METRICS.MEDIA_ISSUE_DETECTED,
|
|
509
|
+
{
|
|
510
|
+
correlationId,
|
|
511
|
+
'share_connection-lost': 1,
|
|
512
|
+
}
|
|
513
|
+
);
|
|
514
|
+
sendBehavioralMetricStub.resetHistory();
|
|
515
|
+
|
|
516
|
+
// Call unsetPeerConnection which should flush throttled metrics
|
|
517
|
+
mediaProperties.unsetPeerConnection();
|
|
518
|
+
|
|
519
|
+
assert.calledOnceWithExactly(
|
|
520
|
+
sendBehavioralMetricStub,
|
|
521
|
+
BEHAVIORAL_METRICS.MEDIA_ISSUE_DETECTED,
|
|
522
|
+
{
|
|
523
|
+
correlationId,
|
|
524
|
+
'share_connection-lost': 1,
|
|
525
|
+
}
|
|
526
|
+
);
|
|
527
|
+
});
|
|
528
|
+
});
|
|
392
529
|
});
|
|
@@ -35,9 +35,12 @@ describe('plugin-meetings', () => {
|
|
|
35
35
|
isLocalRecordingStarted: null,
|
|
36
36
|
isLocalRecordingStopped: null,
|
|
37
37
|
isLocalRecordingPaused: null,
|
|
38
|
+
isLocalStreamingStarted:null,
|
|
39
|
+
isLocalStreamingStopped:null,
|
|
38
40
|
isManualCaptionActive: null,
|
|
39
41
|
isPremiseRecordingEnabled: null,
|
|
40
42
|
isSaveTranscriptsEnabled: null,
|
|
43
|
+
isSpokenLanguageAutoDetectionEnabled: null,
|
|
41
44
|
isWebexAssistantActive: null,
|
|
42
45
|
canViewCaptionPanel: null,
|
|
43
46
|
isRealTimeTranslationEnabled: null,
|
|
@@ -85,6 +88,7 @@ describe('plugin-meetings', () => {
|
|
|
85
88
|
canDoVideo: null,
|
|
86
89
|
canAnnotate: null,
|
|
87
90
|
canUseVoip: null,
|
|
91
|
+
showAutoEndMeetingWarning: null,
|
|
88
92
|
supportHQV: null,
|
|
89
93
|
supportHDV: null,
|
|
90
94
|
canShareWhiteBoard: null,
|
|
@@ -135,6 +139,8 @@ describe('plugin-meetings', () => {
|
|
|
135
139
|
'isLocalRecordingStarted',
|
|
136
140
|
'isLocalRecordingStopped',
|
|
137
141
|
'isLocalRecordingPaused',
|
|
142
|
+
'isLocalStreamingStarted',
|
|
143
|
+
'isLocalStreamingStopped',
|
|
138
144
|
'canSetMuteOnEntry',
|
|
139
145
|
'canUnsetMuteOnEntry',
|
|
140
146
|
'canSetDisallowUnmute',
|
|
@@ -151,6 +157,7 @@ describe('plugin-meetings', () => {
|
|
|
151
157
|
'isManualCaptionActive',
|
|
152
158
|
'isPremiseRecordingEnabled',
|
|
153
159
|
'isSaveTranscriptsEnabled',
|
|
160
|
+
'isSpokenLanguageAutoDetectionEnabled',
|
|
154
161
|
'isWebexAssistantActive',
|
|
155
162
|
'canViewCaptionPanel',
|
|
156
163
|
'isRealTimeTranslationEnabled',
|
|
@@ -195,6 +202,7 @@ describe('plugin-meetings', () => {
|
|
|
195
202
|
'canRealtimeCloseCaption',
|
|
196
203
|
'canRealtimeCloseCaptionManual',
|
|
197
204
|
'canChat',
|
|
205
|
+
'showAutoEndMeetingWarning',
|
|
198
206
|
'canDoVideo',
|
|
199
207
|
'canAnnotate',
|
|
200
208
|
'canUseVoip',
|