@webex/plugin-meetings 3.7.0 → 3.8.0-next.10
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/annotation/index.js +17 -0
- package/dist/annotation/index.js.map +1 -1
- package/dist/breakouts/breakout.js +1 -1
- package/dist/breakouts/index.js +1 -1
- package/dist/common/errors/join-forbidden-error.js +52 -0
- package/dist/common/errors/join-forbidden-error.js.map +1 -0
- package/dist/common/errors/{webinar-registration-error.js → join-webinar-error.js} +12 -12
- package/dist/common/errors/join-webinar-error.js.map +1 -0
- package/dist/common/errors/multistream-not-supported-error.js +53 -0
- package/dist/common/errors/multistream-not-supported-error.js.map +1 -0
- package/dist/config.js +3 -1
- package/dist/config.js.map +1 -1
- package/dist/constants.js +69 -6
- package/dist/constants.js.map +1 -1
- package/dist/index.js +16 -11
- package/dist/index.js.map +1 -1
- package/dist/interpretation/index.js +4 -4
- package/dist/interpretation/index.js.map +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/locus-info/index.js +14 -3
- package/dist/locus-info/index.js.map +1 -1
- package/dist/locus-info/selfUtils.js +35 -17
- package/dist/locus-info/selfUtils.js.map +1 -1
- package/dist/media/MediaConnectionAwaiter.js +1 -0
- package/dist/media/MediaConnectionAwaiter.js.map +1 -1
- package/dist/media/properties.js +30 -16
- package/dist/media/properties.js.map +1 -1
- package/dist/meeting/brbState.js +167 -0
- package/dist/meeting/brbState.js.map +1 -0
- package/dist/meeting/in-meeting-actions.js +13 -1
- package/dist/meeting/in-meeting-actions.js.map +1 -1
- package/dist/meeting/index.js +1373 -1052
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/locusMediaRequest.js +32 -11
- package/dist/meeting/locusMediaRequest.js.map +1 -1
- package/dist/meeting/muteState.js +1 -6
- package/dist/meeting/muteState.js.map +1 -1
- package/dist/meeting/request.js +51 -29
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting/request.type.js.map +1 -1
- package/dist/meeting/util.js +103 -67
- package/dist/meeting/util.js.map +1 -1
- package/dist/meeting-info/meeting-info-v2.js +115 -45
- package/dist/meeting-info/meeting-info-v2.js.map +1 -1
- package/dist/meeting-info/utilv2.js +6 -2
- package/dist/meeting-info/utilv2.js.map +1 -1
- package/dist/meetings/index.js +107 -55
- package/dist/meetings/index.js.map +1 -1
- package/dist/meetings/meetings.types.js +2 -0
- package/dist/meetings/meetings.types.js.map +1 -1
- package/dist/meetings/util.js +1 -1
- package/dist/meetings/util.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 +39 -28
- package/dist/member/util.js.map +1 -1
- package/dist/members/util.js +4 -2
- package/dist/members/util.js.map +1 -1
- package/dist/metrics/constants.js +6 -1
- package/dist/metrics/constants.js.map +1 -1
- package/dist/multistream/remoteMedia.js +30 -15
- package/dist/multistream/remoteMedia.js.map +1 -1
- package/dist/multistream/remoteMediaManager.js +40 -8
- package/dist/multistream/remoteMediaManager.js.map +1 -1
- package/dist/multistream/sendSlotManager.js +24 -0
- package/dist/multistream/sendSlotManager.js.map +1 -1
- package/dist/reachability/clusterReachability.js +12 -15
- package/dist/reachability/clusterReachability.js.map +1 -1
- package/dist/reachability/index.js +471 -140
- package/dist/reachability/index.js.map +1 -1
- package/dist/{rtcMetrics/constants.js → reachability/reachability.types.js} +1 -5
- package/dist/reachability/reachability.types.js.map +1 -0
- package/dist/reachability/request.js +21 -8
- package/dist/reachability/request.js.map +1 -1
- package/dist/recording-controller/enums.js +8 -4
- package/dist/recording-controller/enums.js.map +1 -1
- package/dist/recording-controller/index.js +18 -9
- package/dist/recording-controller/index.js.map +1 -1
- package/dist/recording-controller/util.js +13 -9
- package/dist/recording-controller/util.js.map +1 -1
- package/dist/roap/index.js +15 -15
- package/dist/roap/index.js.map +1 -1
- package/dist/roap/request.js +45 -79
- package/dist/roap/request.js.map +1 -1
- package/dist/roap/turnDiscovery.js +3 -6
- package/dist/roap/turnDiscovery.js.map +1 -1
- package/dist/types/annotation/index.d.ts +5 -0
- package/dist/types/common/errors/join-forbidden-error.d.ts +15 -0
- package/dist/types/common/errors/{webinar-registration-error.d.ts → join-webinar-error.d.ts} +2 -2
- package/dist/types/common/errors/multistream-not-supported-error.d.ts +17 -0
- package/dist/types/config.d.ts +2 -0
- package/dist/types/constants.d.ts +54 -1
- package/dist/types/index.d.ts +3 -3
- package/dist/types/locus-info/index.d.ts +2 -1
- package/dist/types/meeting/brbState.d.ts +54 -0
- package/dist/types/meeting/in-meeting-actions.d.ts +12 -0
- package/dist/types/meeting/index.d.ts +86 -14
- package/dist/types/meeting/locusMediaRequest.d.ts +6 -3
- package/dist/types/meeting/request.d.ts +14 -3
- package/dist/types/meeting/request.type.d.ts +6 -0
- package/dist/types/meeting/util.d.ts +3 -3
- package/dist/types/meeting-info/meeting-info-v2.d.ts +30 -5
- package/dist/types/meetings/index.d.ts +20 -2
- package/dist/types/meetings/meetings.types.d.ts +8 -0
- package/dist/types/member/index.d.ts +1 -0
- package/dist/types/member/types.d.ts +7 -0
- package/dist/types/members/util.d.ts +2 -0
- package/dist/types/metrics/constants.d.ts +6 -1
- package/dist/types/multistream/remoteMediaManager.d.ts +10 -1
- package/dist/types/multistream/sendSlotManager.d.ts +8 -1
- package/dist/types/reachability/clusterReachability.d.ts +1 -10
- package/dist/types/reachability/index.d.ts +83 -36
- package/dist/types/reachability/reachability.types.d.ts +64 -0
- package/dist/types/reachability/request.d.ts +5 -1
- package/dist/types/recording-controller/enums.d.ts +5 -2
- package/dist/types/recording-controller/index.d.ts +1 -0
- package/dist/types/recording-controller/util.d.ts +2 -1
- package/dist/types/roap/request.d.ts +1 -13
- package/dist/webinar/index.js +390 -7
- package/dist/webinar/index.js.map +1 -1
- package/package.json +23 -22
- package/src/annotation/index.ts +16 -0
- package/src/common/errors/join-forbidden-error.ts +26 -0
- package/src/common/errors/join-webinar-error.ts +24 -0
- package/src/common/errors/multistream-not-supported-error.ts +30 -0
- package/src/config.ts +2 -0
- package/src/constants.ts +62 -3
- package/src/index.ts +5 -3
- package/src/interpretation/index.ts +3 -3
- package/src/locus-info/index.ts +20 -3
- package/src/locus-info/selfUtils.ts +24 -6
- package/src/media/MediaConnectionAwaiter.ts +2 -0
- package/src/media/properties.ts +34 -13
- package/src/meeting/brbState.ts +169 -0
- package/src/meeting/in-meeting-actions.ts +25 -0
- package/src/meeting/index.ts +485 -88
- package/src/meeting/locusMediaRequest.ts +38 -12
- package/src/meeting/muteState.ts +1 -6
- package/src/meeting/request.ts +30 -12
- package/src/meeting/request.type.ts +7 -0
- package/src/meeting/util.ts +32 -13
- package/src/meeting-info/meeting-info-v2.ts +83 -12
- package/src/meeting-info/utilv2.ts +17 -3
- package/src/meetings/index.ts +79 -20
- package/src/meetings/meetings.types.ts +10 -0
- package/src/meetings/util.ts +2 -1
- package/src/member/index.ts +9 -0
- package/src/member/types.ts +8 -0
- package/src/member/util.ts +34 -24
- package/src/members/util.ts +1 -0
- package/src/metrics/constants.ts +6 -1
- package/src/multistream/remoteMedia.ts +28 -15
- package/src/multistream/remoteMediaManager.ts +32 -10
- package/src/multistream/sendSlotManager.ts +31 -0
- package/src/reachability/clusterReachability.ts +5 -15
- package/src/reachability/index.ts +315 -75
- package/src/reachability/reachability.types.ts +85 -0
- package/src/reachability/request.ts +55 -31
- package/src/recording-controller/enums.ts +5 -2
- package/src/recording-controller/index.ts +17 -4
- package/src/recording-controller/util.ts +28 -9
- package/src/roap/index.ts +14 -13
- package/src/roap/request.ts +30 -44
- package/src/roap/turnDiscovery.ts +2 -4
- package/src/webinar/index.ts +235 -9
- package/test/unit/spec/annotation/index.ts +46 -1
- package/test/unit/spec/interpretation/index.ts +39 -1
- package/test/unit/spec/locus-info/index.js +292 -60
- package/test/unit/spec/locus-info/selfConstant.js +7 -0
- package/test/unit/spec/locus-info/selfUtils.js +101 -1
- package/test/unit/spec/media/properties.ts +15 -0
- package/test/unit/spec/meeting/brbState.ts +114 -0
- package/test/unit/spec/meeting/in-meeting-actions.ts +15 -1
- package/test/unit/spec/meeting/index.js +908 -124
- package/test/unit/spec/meeting/locusMediaRequest.ts +111 -66
- package/test/unit/spec/meeting/muteState.js +0 -24
- package/test/unit/spec/meeting/request.js +3 -26
- package/test/unit/spec/meeting/utils.js +73 -28
- package/test/unit/spec/meeting-info/meetinginfov2.js +46 -4
- package/test/unit/spec/meeting-info/utilv2.js +26 -0
- package/test/unit/spec/meetings/index.js +172 -18
- package/test/unit/spec/meetings/utils.js +10 -0
- package/test/unit/spec/member/util.js +52 -11
- package/test/unit/spec/members/utils.js +95 -0
- package/test/unit/spec/multistream/remoteMedia.ts +11 -7
- package/test/unit/spec/multistream/remoteMediaManager.ts +397 -118
- package/test/unit/spec/reachability/clusterReachability.ts +7 -0
- package/test/unit/spec/reachability/index.ts +391 -9
- package/test/unit/spec/reachability/request.js +48 -12
- package/test/unit/spec/recording-controller/index.js +61 -5
- package/test/unit/spec/recording-controller/util.js +39 -3
- package/test/unit/spec/roap/index.ts +48 -1
- package/test/unit/spec/roap/request.ts +51 -109
- package/test/unit/spec/roap/turnDiscovery.ts +202 -147
- package/test/unit/spec/webinar/index.ts +509 -0
- package/dist/common/errors/webinar-registration-error.js.map +0 -1
- package/dist/networkQualityMonitor/index.js +0 -227
- package/dist/networkQualityMonitor/index.js.map +0 -1
- package/dist/rtcMetrics/constants.js.map +0 -1
- package/dist/rtcMetrics/index.js +0 -197
- package/dist/rtcMetrics/index.js.map +0 -1
- package/dist/types/networkQualityMonitor/index.d.ts +0 -70
- package/dist/types/rtcMetrics/constants.d.ts +0 -4
- package/dist/types/rtcMetrics/index.d.ts +0 -71
- package/src/common/errors/webinar-registration-error.ts +0 -27
|
@@ -15,6 +15,7 @@ describe('ClusterReachability', () => {
|
|
|
15
15
|
let previousRTCPeerConnection;
|
|
16
16
|
let clusterReachability;
|
|
17
17
|
let fakePeerConnection;
|
|
18
|
+
let gatherIceCandidatesSpy;
|
|
18
19
|
|
|
19
20
|
const emittedEvents: Record<Events, (ResultEventData | ClientMediaIpsUpdatedEventData)[]> = {
|
|
20
21
|
[Events.resultReady]: [],
|
|
@@ -44,6 +45,8 @@ describe('ClusterReachability', () => {
|
|
|
44
45
|
xtls: ['stun:xtls1.webex.com', 'stun:xtls2.webex.com:443'],
|
|
45
46
|
});
|
|
46
47
|
|
|
48
|
+
gatherIceCandidatesSpy = sinon.spy(clusterReachability, 'gatherIceCandidates');
|
|
49
|
+
|
|
47
50
|
resetEmittedEvents();
|
|
48
51
|
|
|
49
52
|
clusterReachability.on(Events.resultReady, (data: ResultEventData) => {
|
|
@@ -151,6 +154,10 @@ describe('ClusterReachability', () => {
|
|
|
151
154
|
assert.calledOnceWithExactly(fakePeerConnection.createOffer, {offerToReceiveAudio: true});
|
|
152
155
|
assert.calledOnce(fakePeerConnection.setLocalDescription);
|
|
153
156
|
|
|
157
|
+
// Make sure that gatherIceCandidates is called before setLocalDescription
|
|
158
|
+
// as setLocalDescription triggers the ICE gathering process
|
|
159
|
+
assert.isTrue(gatherIceCandidatesSpy.calledBefore(fakePeerConnection.setLocalDescription));
|
|
160
|
+
|
|
154
161
|
clusterReachability.abort();
|
|
155
162
|
await promise;
|
|
156
163
|
|
|
@@ -538,6 +538,14 @@ describe('gatherReachability', () => {
|
|
|
538
538
|
assert.equal(storedResultForJoinCookie, JSON.stringify(expectedJoinCookie));
|
|
539
539
|
};
|
|
540
540
|
|
|
541
|
+
it('rejects if reachability is disabled in config', async () => {
|
|
542
|
+
webex.config.meetings.enableReachabilityChecks = false;
|
|
543
|
+
|
|
544
|
+
const reachability = new Reachability(webex);
|
|
545
|
+
|
|
546
|
+
await assert.isRejected(reachability.gatherReachability('test'), 'enableReachabilityChecks is disabled in config');
|
|
547
|
+
});
|
|
548
|
+
|
|
541
549
|
[
|
|
542
550
|
// ========================================================================
|
|
543
551
|
{
|
|
@@ -1050,6 +1058,7 @@ describe('gatherReachability', () => {
|
|
|
1050
1058
|
|
|
1051
1059
|
// the metrics related to ipver and trigger are not tested in these tests and are all the same, so setting them up here
|
|
1052
1060
|
const expectedMetricsFull = {
|
|
1061
|
+
aborted: false,
|
|
1053
1062
|
...expectedMetrics,
|
|
1054
1063
|
ipver_firstIpV4: -1,
|
|
1055
1064
|
ipver_firstIpV6: -1,
|
|
@@ -1238,6 +1247,7 @@ describe('gatherReachability', () => {
|
|
|
1238
1247
|
|
|
1239
1248
|
// finally, check the metrics - they should contain values from ipNetworkDetector
|
|
1240
1249
|
assert.calledWith(Metrics.sendBehavioralMetric, 'js_sdk_reachability_completed', {
|
|
1250
|
+
aborted: false,
|
|
1241
1251
|
vmn_udp_min: -1,
|
|
1242
1252
|
vmn_udp_max: -1,
|
|
1243
1253
|
vmn_udp_average: -1,
|
|
@@ -1622,14 +1632,14 @@ describe('gatherReachability', () => {
|
|
|
1622
1632
|
const reachability = new Reachability(webex);
|
|
1623
1633
|
|
|
1624
1634
|
let getClustersCallCount = 0;
|
|
1625
|
-
|
|
1635
|
+
|
|
1626
1636
|
reachability.reachabilityRequest.getClusters = sinon.stub().callsFake(() => {
|
|
1627
1637
|
getClustersCallCount++;
|
|
1628
1638
|
|
|
1629
1639
|
if (getClustersCallCount == 1) {
|
|
1630
1640
|
throw new Error('fake error');
|
|
1631
1641
|
}
|
|
1632
|
-
|
|
1642
|
+
|
|
1633
1643
|
return getClustersResult;
|
|
1634
1644
|
});
|
|
1635
1645
|
|
|
@@ -1637,7 +1647,7 @@ describe('gatherReachability', () => {
|
|
|
1637
1647
|
|
|
1638
1648
|
await simulateTimeout();
|
|
1639
1649
|
await promise;
|
|
1640
|
-
|
|
1650
|
+
|
|
1641
1651
|
assert.equal(getClustersCallCount, 2);
|
|
1642
1652
|
|
|
1643
1653
|
assert.calledOnce(clusterReachabilityCtorStub);
|
|
@@ -1647,7 +1657,7 @@ describe('gatherReachability', () => {
|
|
|
1647
1657
|
const reachability = new Reachability(webex);
|
|
1648
1658
|
|
|
1649
1659
|
let getClustersCallCount = 0;
|
|
1650
|
-
|
|
1660
|
+
|
|
1651
1661
|
reachability.reachabilityRequest.getClusters = sinon.stub().callsFake(() => {
|
|
1652
1662
|
getClustersCallCount++;
|
|
1653
1663
|
|
|
@@ -1657,13 +1667,356 @@ describe('gatherReachability', () => {
|
|
|
1657
1667
|
const promise = reachability.gatherReachability('test');
|
|
1658
1668
|
|
|
1659
1669
|
await simulateTimeout();
|
|
1660
|
-
|
|
1670
|
+
|
|
1661
1671
|
await promise;
|
|
1662
|
-
|
|
1672
|
+
|
|
1663
1673
|
assert.equal(getClustersCallCount, 2);
|
|
1664
1674
|
|
|
1665
1675
|
assert.neverCalledWith(clusterReachabilityCtorStub);
|
|
1666
1676
|
});
|
|
1677
|
+
|
|
1678
|
+
describe('fallback mechanism and multiple calls to getClusters', () => {
|
|
1679
|
+
let receivedEvents;
|
|
1680
|
+
|
|
1681
|
+
const mockGetClustersEmptyResult = {
|
|
1682
|
+
discoveryOptions: {
|
|
1683
|
+
['early-call-min-clusters']: 0,
|
|
1684
|
+
['report-version']: 1,
|
|
1685
|
+
},
|
|
1686
|
+
clusters: {}, // empty cluster list
|
|
1687
|
+
joinCookie: {id: 'cookie'},
|
|
1688
|
+
};
|
|
1689
|
+
|
|
1690
|
+
beforeEach(() => {
|
|
1691
|
+
webex.config.meetings.experimental = {
|
|
1692
|
+
enableTcpReachability: true,
|
|
1693
|
+
enableTlsReachability: true,
|
|
1694
|
+
};
|
|
1695
|
+
|
|
1696
|
+
receivedEvents = {
|
|
1697
|
+
done: 0,
|
|
1698
|
+
};
|
|
1699
|
+
});
|
|
1700
|
+
|
|
1701
|
+
it('keeps retrying if minimum required clusters are not reached', async () => {
|
|
1702
|
+
const reachability = new Reachability(webex);
|
|
1703
|
+
|
|
1704
|
+
reachability.on('reachability:done', () => {
|
|
1705
|
+
receivedEvents.done += 1;
|
|
1706
|
+
});
|
|
1707
|
+
|
|
1708
|
+
const mockGetClustersResult1 = {
|
|
1709
|
+
discoveryOptions: {
|
|
1710
|
+
['early-call-min-clusters']: 2,
|
|
1711
|
+
['report-version']: 1,
|
|
1712
|
+
},
|
|
1713
|
+
clusters: {
|
|
1714
|
+
clusterA0: {
|
|
1715
|
+
udp: ['udp-urlA'],
|
|
1716
|
+
tcp: ['tcp-urlA'],
|
|
1717
|
+
xtls: ['xtls-urlA'],
|
|
1718
|
+
isVideoMesh: false,
|
|
1719
|
+
},
|
|
1720
|
+
clusterB0: {
|
|
1721
|
+
udp: ['udp-urlB'],
|
|
1722
|
+
tcp: ['tcp-urlB'],
|
|
1723
|
+
xtls: ['xtls-urlB'],
|
|
1724
|
+
isVideoMesh: false,
|
|
1725
|
+
},
|
|
1726
|
+
},
|
|
1727
|
+
joinCookie: {id: 'cookie1'},
|
|
1728
|
+
};
|
|
1729
|
+
const mockGetClustersResult2 = {
|
|
1730
|
+
discoveryOptions: {
|
|
1731
|
+
['early-call-min-clusters']: 2,
|
|
1732
|
+
['report-version']: 1,
|
|
1733
|
+
},
|
|
1734
|
+
clusters: {
|
|
1735
|
+
clusterA1: {
|
|
1736
|
+
udp: ['udp-urlA'],
|
|
1737
|
+
tcp: ['tcp-urlA'],
|
|
1738
|
+
xtls: ['xtls-urlA'],
|
|
1739
|
+
isVideoMesh: false,
|
|
1740
|
+
},
|
|
1741
|
+
clusterB1: {
|
|
1742
|
+
udp: ['udp-urlB'],
|
|
1743
|
+
tcp: ['tcp-urlB'],
|
|
1744
|
+
xtls: ['xtls-urlB'],
|
|
1745
|
+
isVideoMesh: false,
|
|
1746
|
+
},
|
|
1747
|
+
},
|
|
1748
|
+
joinCookie: {id: 'cookie2'},
|
|
1749
|
+
};
|
|
1750
|
+
const mockGetClustersResult3 = {
|
|
1751
|
+
discoveryOptions: {
|
|
1752
|
+
['early-call-min-clusters']: 1,
|
|
1753
|
+
['report-version']: 1,
|
|
1754
|
+
},
|
|
1755
|
+
clusters: {
|
|
1756
|
+
clusterA2: {
|
|
1757
|
+
udp: ['udp-urlA'],
|
|
1758
|
+
tcp: ['tcp-urlA'],
|
|
1759
|
+
xtls: ['xtls-urlA'],
|
|
1760
|
+
isVideoMesh: false,
|
|
1761
|
+
},
|
|
1762
|
+
clusterB2: {
|
|
1763
|
+
udp: ['udp-urlB'],
|
|
1764
|
+
tcp: ['tcp-urlB'],
|
|
1765
|
+
xtls: ['xtls-urlB'],
|
|
1766
|
+
isVideoMesh: false,
|
|
1767
|
+
},
|
|
1768
|
+
},
|
|
1769
|
+
joinCookie: {id: 'cookie3'},
|
|
1770
|
+
};
|
|
1771
|
+
|
|
1772
|
+
reachability.reachabilityRequest.getClusters = sinon.stub();
|
|
1773
|
+
reachability.reachabilityRequest.getClusters.onCall(0).returns(mockGetClustersResult1);
|
|
1774
|
+
reachability.reachabilityRequest.getClusters.onCall(1).returns(mockGetClustersResult2);
|
|
1775
|
+
|
|
1776
|
+
reachability.reachabilityRequest.getClusters.onCall(2).returns(mockGetClustersResult3);
|
|
1777
|
+
|
|
1778
|
+
const resultPromise = reachability.gatherReachability('test');
|
|
1779
|
+
|
|
1780
|
+
await testUtils.flushPromises();
|
|
1781
|
+
|
|
1782
|
+
// trigger some mock result events from ClusterReachability instances,
|
|
1783
|
+
// but only from 1 cluster, so not enough to reach the minimum required
|
|
1784
|
+
mockClusterReachabilityInstances['clusterA0'].emitFakeResult('udp', {
|
|
1785
|
+
result: 'reachable',
|
|
1786
|
+
clientMediaIPs: ['1.2.3.4'],
|
|
1787
|
+
latencyInMilliseconds: 11,
|
|
1788
|
+
});
|
|
1789
|
+
|
|
1790
|
+
clock.tick(3000);
|
|
1791
|
+
await resultPromise;
|
|
1792
|
+
await testUtils.flushPromises();
|
|
1793
|
+
|
|
1794
|
+
// because the minimum was not reached, another call to getClusters should be made
|
|
1795
|
+
assert.calledTwice(reachability.reachabilityRequest.getClusters);
|
|
1796
|
+
|
|
1797
|
+
// simulate no results this time
|
|
1798
|
+
|
|
1799
|
+
// check that while the 2nd attempt is in progress, the join cookie is already available from the 2nd call to getClusters
|
|
1800
|
+
const clientMediaPreferences = await reachability.getClientMediaPreferences(
|
|
1801
|
+
true,
|
|
1802
|
+
IP_VERSION.unknown
|
|
1803
|
+
);
|
|
1804
|
+
|
|
1805
|
+
assert.deepEqual(clientMediaPreferences.joinCookie, mockGetClustersResult2.joinCookie);
|
|
1806
|
+
|
|
1807
|
+
clock.tick(3000);
|
|
1808
|
+
await testUtils.flushPromises();
|
|
1809
|
+
|
|
1810
|
+
assert.calledThrice(reachability.reachabilityRequest.getClusters);
|
|
1811
|
+
|
|
1812
|
+
await testUtils.flushPromises();
|
|
1813
|
+
|
|
1814
|
+
// this time 1 result will be enough to reach the minimum
|
|
1815
|
+
mockClusterReachabilityInstances['clusterA2'].emitFakeResult('udp', {
|
|
1816
|
+
result: 'reachable',
|
|
1817
|
+
clientMediaIPs: ['1.2.3.4'],
|
|
1818
|
+
latencyInMilliseconds: 11,
|
|
1819
|
+
});
|
|
1820
|
+
clock.tick(3000);
|
|
1821
|
+
|
|
1822
|
+
// the reachability results should include only results from the last attempt
|
|
1823
|
+
await checkResults(
|
|
1824
|
+
{
|
|
1825
|
+
clusterA2: {
|
|
1826
|
+
udp: {result: 'reachable', clientMediaIPs: ['1.2.3.4'], latencyInMilliseconds: 11},
|
|
1827
|
+
tcp: {result: 'unreachable'},
|
|
1828
|
+
xtls: {result: 'unreachable'},
|
|
1829
|
+
isVideoMesh: false,
|
|
1830
|
+
},
|
|
1831
|
+
clusterB2: {
|
|
1832
|
+
udp: {result: 'unreachable'},
|
|
1833
|
+
tcp: {result: 'unreachable'},
|
|
1834
|
+
xtls: {result: 'unreachable'},
|
|
1835
|
+
isVideoMesh: false,
|
|
1836
|
+
},
|
|
1837
|
+
},
|
|
1838
|
+
mockGetClustersResult3.joinCookie
|
|
1839
|
+
);
|
|
1840
|
+
|
|
1841
|
+
// wait some more time to make sure that there are no timers that fire from one of the previous checks
|
|
1842
|
+
clock.tick(20000);
|
|
1843
|
+
|
|
1844
|
+
// as the first 2 attempts failed and didn't reach the overall timeout, there should be only 1 done event emitted
|
|
1845
|
+
assert.equal(receivedEvents.done, 1);
|
|
1846
|
+
});
|
|
1847
|
+
|
|
1848
|
+
it('handles getClusters() returning empty list on 1st call', async () => {
|
|
1849
|
+
const reachability = new Reachability(webex);
|
|
1850
|
+
|
|
1851
|
+
reachability.on('reachability:done', () => {
|
|
1852
|
+
receivedEvents.done += 1;
|
|
1853
|
+
});
|
|
1854
|
+
|
|
1855
|
+
reachability.reachabilityRequest.getClusters = sinon
|
|
1856
|
+
.stub()
|
|
1857
|
+
.resolves(mockGetClustersEmptyResult);
|
|
1858
|
+
|
|
1859
|
+
const resultPromise = reachability.gatherReachability('test');
|
|
1860
|
+
|
|
1861
|
+
await testUtils.flushPromises();
|
|
1862
|
+
|
|
1863
|
+
clock.tick(3000);
|
|
1864
|
+
await resultPromise;
|
|
1865
|
+
await testUtils.flushPromises();
|
|
1866
|
+
|
|
1867
|
+
assert.calledOnce(reachability.reachabilityRequest.getClusters);
|
|
1868
|
+
reachability.reachabilityRequest.getClusters.resetHistory();
|
|
1869
|
+
|
|
1870
|
+
assert.equal(receivedEvents.done, 1);
|
|
1871
|
+
await checkResults({}, mockGetClustersEmptyResult.joinCookie);
|
|
1872
|
+
|
|
1873
|
+
// because we didn't actually test anything (we got empty cluster list from getClusters()), we should
|
|
1874
|
+
// not say that webex backend is unreachable
|
|
1875
|
+
assert.equal(await reachability.isWebexMediaBackendUnreachable(), false);
|
|
1876
|
+
|
|
1877
|
+
// wait to check that there are no other things happening
|
|
1878
|
+
clock.tick(20000);
|
|
1879
|
+
await testUtils.flushPromises();
|
|
1880
|
+
|
|
1881
|
+
assert.notCalled(reachability.reachabilityRequest.getClusters);
|
|
1882
|
+
assert.equal(receivedEvents.done, 1);
|
|
1883
|
+
});
|
|
1884
|
+
|
|
1885
|
+
it('handles getClusters() returning empty list on 2nd call', async () => {
|
|
1886
|
+
const reachability = new Reachability(webex);
|
|
1887
|
+
|
|
1888
|
+
reachability.on('reachability:done', () => {
|
|
1889
|
+
receivedEvents.done += 1;
|
|
1890
|
+
});
|
|
1891
|
+
|
|
1892
|
+
const mockGetClustersResult1 = {
|
|
1893
|
+
discoveryOptions: {
|
|
1894
|
+
['early-call-min-clusters']: 2,
|
|
1895
|
+
['report-version']: 1,
|
|
1896
|
+
},
|
|
1897
|
+
clusters: {
|
|
1898
|
+
clusterA0: {
|
|
1899
|
+
udp: ['udp-urlA'],
|
|
1900
|
+
tcp: ['tcp-urlA'],
|
|
1901
|
+
xtls: ['xtls-urlA'],
|
|
1902
|
+
isVideoMesh: false,
|
|
1903
|
+
},
|
|
1904
|
+
clusterB0: {
|
|
1905
|
+
udp: ['udp-urlB'],
|
|
1906
|
+
tcp: ['tcp-urlB'],
|
|
1907
|
+
xtls: ['xtls-urlB'],
|
|
1908
|
+
isVideoMesh: false,
|
|
1909
|
+
},
|
|
1910
|
+
},
|
|
1911
|
+
joinCookie: {id: 'cookie1'},
|
|
1912
|
+
};
|
|
1913
|
+
|
|
1914
|
+
reachability.reachabilityRequest.getClusters = sinon.stub();
|
|
1915
|
+
reachability.reachabilityRequest.getClusters.onCall(0).returns(mockGetClustersResult1);
|
|
1916
|
+
reachability.reachabilityRequest.getClusters.onCall(1).returns(mockGetClustersEmptyResult);
|
|
1917
|
+
|
|
1918
|
+
const resultPromise = reachability.gatherReachability('test');
|
|
1919
|
+
|
|
1920
|
+
await testUtils.flushPromises();
|
|
1921
|
+
|
|
1922
|
+
clock.tick(3000);
|
|
1923
|
+
await resultPromise;
|
|
1924
|
+
await testUtils.flushPromises();
|
|
1925
|
+
|
|
1926
|
+
// because the minimum was not reached, another call to getClusters should be made
|
|
1927
|
+
assert.calledTwice(reachability.reachabilityRequest.getClusters);
|
|
1928
|
+
|
|
1929
|
+
// the reachability results should include only results from the last attempt
|
|
1930
|
+
await checkResults({}, mockGetClustersEmptyResult.joinCookie);
|
|
1931
|
+
|
|
1932
|
+
// as the first 2 attempts failed and didn't reach the overall timeout, there should be only 1 done event emitted
|
|
1933
|
+
assert.equal(receivedEvents.done, 1);
|
|
1934
|
+
// because we didn't actually test anything (we got empty cluster list from getClusters()), we should
|
|
1935
|
+
// not say that webex backend is unreachable
|
|
1936
|
+
assert.equal(await reachability.isWebexMediaBackendUnreachable(), false);
|
|
1937
|
+
});
|
|
1938
|
+
});
|
|
1939
|
+
|
|
1940
|
+
describe('stopReachability', () => {
|
|
1941
|
+
let reachability;
|
|
1942
|
+
let receivedEvents;
|
|
1943
|
+
let sendMetricSpy;
|
|
1944
|
+
|
|
1945
|
+
beforeEach(() => {
|
|
1946
|
+
reachability = new Reachability(webex);
|
|
1947
|
+
|
|
1948
|
+
receivedEvents = {};
|
|
1949
|
+
|
|
1950
|
+
sendMetricSpy = sinon.stub(reachability, 'sendMetric').resolves();
|
|
1951
|
+
});
|
|
1952
|
+
|
|
1953
|
+
const setListener = (event) => {
|
|
1954
|
+
reachability.on(event, () => {
|
|
1955
|
+
receivedEvents[event] = receivedEvents[event] + 1 || 1;
|
|
1956
|
+
});
|
|
1957
|
+
};
|
|
1958
|
+
it('works as expected', async () => {
|
|
1959
|
+
setListener('reachability:stopped');
|
|
1960
|
+
setListener('reachability:done');
|
|
1961
|
+
setListener('reachability:firstResultAvailable');
|
|
1962
|
+
|
|
1963
|
+
const mockGetClustersResult = {
|
|
1964
|
+
clusters: {
|
|
1965
|
+
clusterA: {
|
|
1966
|
+
udp: ['udp-urlA'],
|
|
1967
|
+
tcp: ['tcp-urlA'],
|
|
1968
|
+
xtls: ['xtls-urlA'],
|
|
1969
|
+
isVideoMesh: false,
|
|
1970
|
+
},
|
|
1971
|
+
clusterB: {
|
|
1972
|
+
udp: ['udp-urlB'],
|
|
1973
|
+
tcp: ['tcp-urlB'],
|
|
1974
|
+
xtls: ['xtls-urlB'],
|
|
1975
|
+
isVideoMesh: false,
|
|
1976
|
+
},
|
|
1977
|
+
},
|
|
1978
|
+
joinCookie: {id: 'id'},
|
|
1979
|
+
};
|
|
1980
|
+
|
|
1981
|
+
reachability.reachabilityRequest.getClusters = sinon.stub().returns(mockGetClustersResult);
|
|
1982
|
+
|
|
1983
|
+
const gatherReachabilityFallbackSpy = sinon.spy(reachability, 'gatherReachabilityFallback');
|
|
1984
|
+
|
|
1985
|
+
const resultPromise = reachability.gatherReachability('test');
|
|
1986
|
+
|
|
1987
|
+
await testUtils.flushPromises();
|
|
1988
|
+
|
|
1989
|
+
reachability.stopReachability();
|
|
1990
|
+
|
|
1991
|
+
await resultPromise;
|
|
1992
|
+
|
|
1993
|
+
// simulate a lot of time passing to check that all timers were stopped and nothing else happens
|
|
1994
|
+
clock.tick(99000);
|
|
1995
|
+
|
|
1996
|
+
assert.calledOnceWithExactly(mockClusterReachabilityInstances['clusterA'].abort);
|
|
1997
|
+
assert.calledOnceWithExactly(mockClusterReachabilityInstances['clusterB'].abort);
|
|
1998
|
+
|
|
1999
|
+
assert.calledOnceWithExactly(sendMetricSpy, true);
|
|
2000
|
+
|
|
2001
|
+
assert.equal(receivedEvents['reachability:stopped'], 1);
|
|
2002
|
+
assert.equal(receivedEvents['reachability:done'], undefined);
|
|
2003
|
+
assert.equal(receivedEvents['reachability:firstResultAvailable'], undefined);
|
|
2004
|
+
|
|
2005
|
+
assert.notCalled(gatherReachabilityFallbackSpy);
|
|
2006
|
+
});
|
|
2007
|
+
|
|
2008
|
+
it('does nothing if called without reachability being started', async () => {
|
|
2009
|
+
const reachability = new Reachability(webex);
|
|
2010
|
+
|
|
2011
|
+
reachability.stopReachability();
|
|
2012
|
+
|
|
2013
|
+
assert.notCalled(sendMetricSpy);
|
|
2014
|
+
|
|
2015
|
+
assert.equal(receivedEvents['reachability:stopped'], undefined);
|
|
2016
|
+
assert.equal(receivedEvents['reachability:done'], undefined);
|
|
2017
|
+
assert.equal(receivedEvents['reachability:firstResultAvailable'], undefined);
|
|
2018
|
+
});
|
|
2019
|
+
});
|
|
1667
2020
|
});
|
|
1668
2021
|
|
|
1669
2022
|
describe('getReachabilityResults', () => {
|
|
@@ -2225,19 +2578,18 @@ describe('getStatistics', () => {
|
|
|
2225
2578
|
describe('sendMetric', () => {
|
|
2226
2579
|
let webex;
|
|
2227
2580
|
let reachability;
|
|
2581
|
+
let getStatisticsStub;
|
|
2228
2582
|
|
|
2229
2583
|
beforeEach(() => {
|
|
2230
2584
|
webex = new MockWebex();
|
|
2231
2585
|
reachability = new TestReachability(webex);
|
|
2232
2586
|
|
|
2233
2587
|
sinon.stub(Metrics, 'sendBehavioralMetric');
|
|
2234
|
-
});
|
|
2235
2588
|
|
|
2236
|
-
it('works as expected', async () => {
|
|
2237
2589
|
// setup stub for getStatistics to return values that show what parameters it was called with,
|
|
2238
2590
|
// this way we can verify that the correct results of calls to getStatistics are placed
|
|
2239
2591
|
// in correct data fields when sendBehavioralMetric() is called
|
|
2240
|
-
|
|
2592
|
+
getStatisticsStub = sinon
|
|
2241
2593
|
.stub(reachability, 'getStatistics')
|
|
2242
2594
|
.callsFake((results, protocol, isVideoMesh) => {
|
|
2243
2595
|
return {result: 'fake', protocol, isVideoMesh};
|
|
@@ -2258,7 +2610,13 @@ describe('sendMetric', () => {
|
|
|
2258
2610
|
isVideoMesh: false,
|
|
2259
2611
|
},
|
|
2260
2612
|
});
|
|
2613
|
+
});
|
|
2261
2614
|
|
|
2615
|
+
afterEach(() => {
|
|
2616
|
+
sinon.restore();
|
|
2617
|
+
});
|
|
2618
|
+
|
|
2619
|
+
it('works as expected', async () => {
|
|
2262
2620
|
await reachability.sendMetric();
|
|
2263
2621
|
|
|
2264
2622
|
// each call to getStatistics should be made with all the results from all fake clusterReachability:
|
|
@@ -2282,6 +2640,30 @@ describe('sendMetric', () => {
|
|
|
2282
2640
|
assert.alwaysCalledWith(getStatisticsStub, expectedResults, sinon.match.any, sinon.match.any);
|
|
2283
2641
|
|
|
2284
2642
|
assert.calledWith(Metrics.sendBehavioralMetric, 'js_sdk_reachability_completed', {
|
|
2643
|
+
aborted: false,
|
|
2644
|
+
vmn_udp_result: 'fake',
|
|
2645
|
+
vmn_udp_protocol: 'udp',
|
|
2646
|
+
vmn_udp_isVideoMesh: true,
|
|
2647
|
+
|
|
2648
|
+
public_udp_result: 'fake',
|
|
2649
|
+
public_udp_protocol: 'udp',
|
|
2650
|
+
public_udp_isVideoMesh: false,
|
|
2651
|
+
|
|
2652
|
+
public_tcp_result: 'fake',
|
|
2653
|
+
public_tcp_protocol: 'tcp',
|
|
2654
|
+
public_tcp_isVideoMesh: false,
|
|
2655
|
+
|
|
2656
|
+
public_xtls_result: 'fake',
|
|
2657
|
+
public_xtls_protocol: 'xtls',
|
|
2658
|
+
public_xtls_isVideoMesh: false,
|
|
2659
|
+
});
|
|
2660
|
+
});
|
|
2661
|
+
|
|
2662
|
+
it('sends metric with "aborted:true" if called with aborted=true arg', async () => {
|
|
2663
|
+
await reachability.sendMetric(true);
|
|
2664
|
+
|
|
2665
|
+
assert.calledWith(Metrics.sendBehavioralMetric, 'js_sdk_reachability_completed', {
|
|
2666
|
+
aborted: true,
|
|
2285
2667
|
vmn_udp_result: 'fake',
|
|
2286
2668
|
vmn_udp_protocol: 'udp',
|
|
2287
2669
|
vmn_udp_isVideoMesh: true,
|
|
@@ -35,16 +35,11 @@ describe('plugin-meetings/reachability', () => {
|
|
|
35
35
|
});
|
|
36
36
|
|
|
37
37
|
describe('#getClusters', () => {
|
|
38
|
+
let previousReport;
|
|
38
39
|
|
|
39
40
|
beforeEach(() => {
|
|
40
41
|
sinon.spy(webex.internal.newMetrics.callDiagnosticLatencies, 'measureLatency');
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
afterEach(() => {
|
|
44
|
-
sinon.restore();
|
|
45
|
-
});
|
|
46
42
|
|
|
47
|
-
it('sends a GET request with the correct params', async () => {
|
|
48
43
|
webex.request = sinon.mock().returns(Promise.resolve({
|
|
49
44
|
body: {
|
|
50
45
|
clusterClasses: {
|
|
@@ -59,24 +54,65 @@ describe('plugin-meetings/reachability', () => {
|
|
|
59
54
|
|
|
60
55
|
webex.config.meetings.reachabilityGetClusterTimeout = 3000;
|
|
61
56
|
|
|
62
|
-
|
|
57
|
+
previousReport = {
|
|
58
|
+
id: 'fake previous report',
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
afterEach(() => {
|
|
63
|
+
sinon.restore();
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('sends a POST request with the correct params when trigger is "startup"', async () => {
|
|
67
|
+
const res = await reachabilityRequest.getClusters('startup', IP_VERSION.only_ipv4, previousReport);
|
|
63
68
|
const requestParams = webex.request.getCall(0).args[0];
|
|
64
69
|
|
|
65
70
|
assert.deepEqual(requestParams, {
|
|
66
|
-
method: '
|
|
71
|
+
method: 'POST',
|
|
67
72
|
resource: `clusters`,
|
|
68
73
|
api: 'calliopeDiscovery',
|
|
69
74
|
shouldRefreshAccessToken: false,
|
|
70
|
-
qs: {
|
|
71
|
-
JCSupport: 1,
|
|
72
|
-
ipver: 4,
|
|
73
|
-
},
|
|
74
75
|
timeout: 3000,
|
|
76
|
+
body: {
|
|
77
|
+
ipver: IP_VERSION.only_ipv4,
|
|
78
|
+
'supported-options': {
|
|
79
|
+
'report-version': 1,
|
|
80
|
+
'early-call-min-clusters': true,
|
|
81
|
+
},
|
|
82
|
+
'previous-report': previousReport,
|
|
83
|
+
trigger: 'startup',
|
|
84
|
+
},
|
|
75
85
|
});
|
|
76
86
|
|
|
77
87
|
assert.deepEqual(res.clusters.clusterId, {udp: "testUDP", isVideoMesh: true})
|
|
78
88
|
assert.deepEqual(res.joinCookie, {anycastEntryPoint: "aws-eu-west-1"})
|
|
79
89
|
assert.calledOnceWithExactly(webex.internal.newMetrics.callDiagnosticLatencies.measureLatency, sinon.match.func, 'internal.get.cluster.time');
|
|
80
90
|
});
|
|
91
|
+
|
|
92
|
+
it('sends a POST request with the correct params when trigger is other than "startup"', async () => {
|
|
93
|
+
const res = await reachabilityRequest.getClusters('early-call/no-min-reached', IP_VERSION.only_ipv4, previousReport);
|
|
94
|
+
const requestParams = webex.request.getCall(0).args[0];
|
|
95
|
+
|
|
96
|
+
assert.deepEqual(requestParams, {
|
|
97
|
+
method: 'POST',
|
|
98
|
+
resource: `clusters`,
|
|
99
|
+
api: 'calliopeDiscovery',
|
|
100
|
+
shouldRefreshAccessToken: false,
|
|
101
|
+
timeout: 3000,
|
|
102
|
+
body: {
|
|
103
|
+
ipver: IP_VERSION.only_ipv4,
|
|
104
|
+
'supported-options': {
|
|
105
|
+
'report-version': 1,
|
|
106
|
+
'early-call-min-clusters': true,
|
|
107
|
+
},
|
|
108
|
+
'previous-report': previousReport,
|
|
109
|
+
trigger: 'early-call/no-min-reached',
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
assert.deepEqual(res.clusters.clusterId, {udp: "testUDP", isVideoMesh: true})
|
|
114
|
+
assert.deepEqual(res.joinCookie, {anycastEntryPoint: "aws-eu-west-1"})
|
|
115
|
+
assert.notCalled(webex.internal.newMetrics.callDiagnosticLatencies.measureLatency);
|
|
116
|
+
});
|
|
81
117
|
});
|
|
82
118
|
});
|