@webex/plugin-meetings 3.8.0-next.8 → 3.8.0-web-workers-keepalive.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/breakouts/breakout.js +1 -1
- package/dist/breakouts/index.js +1 -1
- package/dist/config.js +1 -0
- package/dist/config.js.map +1 -1
- package/dist/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/locus-info/controlsUtils.js +1 -1
- package/dist/locus-info/controlsUtils.js.map +1 -1
- package/dist/meeting/index.js +51 -5
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/util.js +4 -1
- package/dist/meeting/util.js.map +1 -1
- package/dist/meeting-info/meeting-info-v2.js +359 -60
- package/dist/meeting-info/meeting-info-v2.js.map +1 -1
- package/dist/meetings/index.js +60 -1
- package/dist/meetings/index.js.map +1 -1
- package/dist/member/index.js +10 -0
- package/dist/member/index.js.map +1 -1
- package/dist/member/util.js +3 -0
- package/dist/member/util.js.map +1 -1
- package/dist/metrics/constants.js +9 -0
- package/dist/metrics/constants.js.map +1 -1
- package/dist/reachability/clusterReachability.js +52 -8
- package/dist/reachability/clusterReachability.js.map +1 -1
- package/dist/reachability/index.js +70 -45
- package/dist/reachability/index.js.map +1 -1
- package/dist/reachability/reachability.types.js +14 -0
- package/dist/reachability/reachability.types.js.map +1 -1
- package/dist/reachability/request.js +19 -3
- package/dist/reachability/request.js.map +1 -1
- package/dist/types/config.d.ts +1 -0
- package/dist/types/meeting/index.d.ts +8 -0
- package/dist/types/meeting-info/meeting-info-v2.d.ts +80 -0
- package/dist/types/meetings/index.d.ts +29 -0
- package/dist/types/member/index.d.ts +1 -0
- package/dist/types/metrics/constants.d.ts +9 -0
- package/dist/types/reachability/clusterReachability.d.ts +13 -1
- package/dist/types/reachability/index.d.ts +2 -1
- package/dist/types/reachability/reachability.types.d.ts +5 -0
- package/dist/webinar/index.js +1 -1
- package/package.json +22 -22
- package/src/config.ts +1 -0
- package/src/locus-info/controlsUtils.ts +2 -2
- package/src/meeting/index.ts +51 -7
- package/src/meeting/util.ts +2 -1
- package/src/meeting-info/meeting-info-v2.ts +247 -6
- package/src/meetings/index.ts +72 -1
- package/src/member/index.ts +11 -0
- package/src/member/util.ts +3 -0
- package/src/metrics/constants.ts +9 -0
- package/src/reachability/clusterReachability.ts +47 -1
- package/src/reachability/index.ts +15 -0
- package/src/reachability/reachability.types.ts +6 -0
- package/src/reachability/request.ts +7 -0
- package/test/unit/spec/locus-info/controlsUtils.js +8 -0
- package/test/unit/spec/meeting/index.js +62 -4
- package/test/unit/spec/meeting/utils.js +55 -0
- package/test/unit/spec/meeting-info/meetinginfov2.js +443 -114
- package/test/unit/spec/meetings/index.js +78 -1
- package/test/unit/spec/member/index.js +7 -0
- package/test/unit/spec/member/util.js +24 -0
- package/test/unit/spec/reachability/clusterReachability.ts +47 -1
- package/test/unit/spec/reachability/index.ts +12 -0
- package/test/unit/spec/reachability/request.js +47 -2
@@ -285,7 +285,8 @@ describe('plugin-meetings', () => {
|
|
285
285
|
|
286
286
|
describe('failure', () => {
|
287
287
|
it('should not accept non-number input', () => {
|
288
|
-
const logUploadIntervalMultiplicationFactor =
|
288
|
+
const logUploadIntervalMultiplicationFactor =
|
289
|
+
webex.meetings.config.logUploadIntervalMultiplicationFactor;
|
289
290
|
|
290
291
|
webex.meetings._setLogUploadIntervalMultiplicationFactor('test');
|
291
292
|
assert.equal(
|
@@ -441,6 +442,19 @@ describe('plugin-meetings', () => {
|
|
441
442
|
assert.isTrue(webex.meetings.registered);
|
442
443
|
});
|
443
444
|
|
445
|
+
it('resolves even if startReachability() rejects', async () => {
|
446
|
+
webex.canAuthorize = true;
|
447
|
+
webex.meetings.registered = false;
|
448
|
+
webex.meetings.startReachability = sinon.stub().rejects(new Error('fake error'));
|
449
|
+
|
450
|
+
await webex.meetings.register();
|
451
|
+
assert.calledOnceWithExactly(webex.internal.device.register, undefined);
|
452
|
+
assert.called(webex.internal.services.getMeetingPreferences);
|
453
|
+
assert.called(webex.internal.services.fetchClientRegionInfo);
|
454
|
+
assert.called(webex.internal.mercury.connect);
|
455
|
+
assert.isTrue(webex.meetings.registered);
|
456
|
+
});
|
457
|
+
|
444
458
|
it('passes on the device registration options', async () => {
|
445
459
|
webex.canAuthorize = true;
|
446
460
|
webex.meetings.registered = false;
|
@@ -918,6 +932,69 @@ describe('plugin-meetings', () => {
|
|
918
932
|
});
|
919
933
|
});
|
920
934
|
});
|
935
|
+
describe('#fetchStaticMeetingLink', () => {
|
936
|
+
const conversationUrl = 'conv.fakeconversationurl.com';
|
937
|
+
|
938
|
+
afterEach(() => {
|
939
|
+
sinon.restore();
|
940
|
+
});
|
941
|
+
|
942
|
+
it('should have #fetchStaticMeetingLink', () => {
|
943
|
+
assert.exists(webex.meetings.fetchStaticMeetingLink);
|
944
|
+
});
|
945
|
+
|
946
|
+
it('should call MeetingInfo#fetchStaticMeetingLink() with proper params', () => {
|
947
|
+
webex.meetings.meetingInfo.fetchStaticMeetingLink = sinon
|
948
|
+
.stub()
|
949
|
+
.resolves(conversationUrl);
|
950
|
+
|
951
|
+
return webex.meetings.fetchStaticMeetingLink(conversationUrl).then(() => {
|
952
|
+
assert.calledWith(webex.meetings.meetingInfo.fetchStaticMeetingLink, conversationUrl);
|
953
|
+
});
|
954
|
+
});
|
955
|
+
});
|
956
|
+
describe('#enableStaticMeetingLink', () => {
|
957
|
+
const conversationUrl = 'conv.fakeconversationurl.com';
|
958
|
+
|
959
|
+
afterEach(() => {
|
960
|
+
sinon.restore();
|
961
|
+
});
|
962
|
+
|
963
|
+
it('should have #enableStaticMeetingLink', () => {
|
964
|
+
assert.exists(webex.meetings.enableStaticMeetingLink);
|
965
|
+
});
|
966
|
+
|
967
|
+
it('should call MeetingInfo#enableStaticMeetingLink() with proper params', () => {
|
968
|
+
webex.meetings.meetingInfo.enableStaticMeetingLink = sinon
|
969
|
+
.stub()
|
970
|
+
.resolves(conversationUrl);
|
971
|
+
|
972
|
+
return webex.meetings.enableStaticMeetingLink(conversationUrl).then(() => {
|
973
|
+
assert.calledWith(webex.meetings.meetingInfo.enableStaticMeetingLink, conversationUrl);
|
974
|
+
});
|
975
|
+
});
|
976
|
+
});
|
977
|
+
describe('#disableStaticMeetingLink', () => {
|
978
|
+
const conversationUrl = 'conv.fakeconversationurl.com';
|
979
|
+
|
980
|
+
afterEach(() => {
|
981
|
+
sinon.restore();
|
982
|
+
});
|
983
|
+
|
984
|
+
it('should have #disableStaticMeetingLink', () => {
|
985
|
+
assert.exists(webex.meetings.disableStaticMeetingLink);
|
986
|
+
});
|
987
|
+
|
988
|
+
it('should call MeetingInfo#disableStaticMeetingLink() with proper params', () => {
|
989
|
+
webex.meetings.meetingInfo.disableStaticMeetingLink = sinon
|
990
|
+
.stub()
|
991
|
+
.resolves(conversationUrl);
|
992
|
+
|
993
|
+
return webex.meetings.disableStaticMeetingLink(conversationUrl).then(() => {
|
994
|
+
assert.calledWith(webex.meetings.meetingInfo.disableStaticMeetingLink, conversationUrl);
|
995
|
+
});
|
996
|
+
});
|
997
|
+
});
|
921
998
|
describe('#create', () => {
|
922
999
|
let infoOptions;
|
923
1000
|
|
@@ -50,6 +50,13 @@ describe('member', () => {
|
|
50
50
|
|
51
51
|
assert.calledOnceWithExactly(MemberUtil.canReclaimHost, participant);
|
52
52
|
});
|
53
|
+
|
54
|
+
it('checks that processParticipant calls isPresenterAssignmentProhibited', () => {
|
55
|
+
sinon.spy(MemberUtil, 'isPresenterAssignmentProhibited');
|
56
|
+
member.processParticipant(participant);
|
57
|
+
|
58
|
+
assert.calledOnceWithExactly(MemberUtil.isPresenterAssignmentProhibited, participant);
|
59
|
+
});
|
53
60
|
})
|
54
61
|
|
55
62
|
describe('#processMember', () => {
|
@@ -557,6 +557,30 @@ describe('plugin-meetings', () => {
|
|
557
557
|
testResult(false, undefined, false);
|
558
558
|
});
|
559
559
|
});
|
560
|
+
|
561
|
+
describe('MemberUtil.isPresenterAssignmentProhibited', () => {
|
562
|
+
it('returns true when isPresenterAssignmentProhibited is true', () => {
|
563
|
+
const participant = {
|
564
|
+
presenterAssignmentNotAllowed: true
|
565
|
+
};
|
566
|
+
|
567
|
+
assert.isTrue(MemberUtil.isPresenterAssignmentProhibited(participant));
|
568
|
+
});
|
569
|
+
|
570
|
+
it('returns false when isPresenterAssignmentProhibited is false', () => {
|
571
|
+
const participant = {
|
572
|
+
presenterAssignmentNotAllowed: false,
|
573
|
+
};
|
574
|
+
|
575
|
+
assert.isFalse(MemberUtil.isPresenterAssignmentProhibited(participant));
|
576
|
+
});
|
577
|
+
|
578
|
+
it('returns undefined when isPresenterAssignmentProhibited is undefined', () => {
|
579
|
+
const participant = {};
|
580
|
+
|
581
|
+
assert.isUndefined(MemberUtil.isPresenterAssignmentProhibited(participant));
|
582
|
+
});
|
583
|
+
});
|
560
584
|
});
|
561
585
|
|
562
586
|
describe('extractMediaStatus', () => {
|
@@ -9,7 +9,9 @@ import {
|
|
9
9
|
ResultEventData,
|
10
10
|
Events,
|
11
11
|
ClientMediaIpsUpdatedEventData,
|
12
|
+
NatTypeUpdatedEventData,
|
12
13
|
} from '@webex/plugin-meetings/src/reachability/clusterReachability'; // replace with actual path
|
14
|
+
import { NatType } from 'packages/@webex/plugin-meetings/dist/reachability/reachability.types';
|
13
15
|
|
14
16
|
describe('ClusterReachability', () => {
|
15
17
|
let previousRTCPeerConnection;
|
@@ -17,15 +19,17 @@ describe('ClusterReachability', () => {
|
|
17
19
|
let fakePeerConnection;
|
18
20
|
let gatherIceCandidatesSpy;
|
19
21
|
|
20
|
-
const emittedEvents: Record<Events, (ResultEventData | ClientMediaIpsUpdatedEventData)[]> = {
|
22
|
+
const emittedEvents: Record<Events, (ResultEventData | ClientMediaIpsUpdatedEventData | NatTypeUpdatedEventData)[]> = {
|
21
23
|
[Events.resultReady]: [],
|
22
24
|
[Events.clientMediaIpsUpdated]: [],
|
25
|
+
[Events.natTypeUpdated]: [],
|
23
26
|
};
|
24
27
|
const FAKE_OFFER = {type: 'offer', sdp: 'fake sdp'};
|
25
28
|
|
26
29
|
const resetEmittedEvents = () => {
|
27
30
|
emittedEvents[Events.resultReady].length = 0;
|
28
31
|
emittedEvents[Events.clientMediaIpsUpdated].length = 0;
|
32
|
+
emittedEvents[Events.natTypeUpdated].length = 0;
|
29
33
|
};
|
30
34
|
beforeEach(() => {
|
31
35
|
fakePeerConnection = {
|
@@ -56,6 +60,10 @@ describe('ClusterReachability', () => {
|
|
56
60
|
clusterReachability.on(Events.clientMediaIpsUpdated, (data: ClientMediaIpsUpdatedEventData) => {
|
57
61
|
emittedEvents[Events.clientMediaIpsUpdated].push(data);
|
58
62
|
});
|
63
|
+
|
64
|
+
clusterReachability.on(Events.natTypeUpdated, (data: NatTypeUpdatedEventData) => {
|
65
|
+
emittedEvents[Events.natTypeUpdated].push(data);
|
66
|
+
});
|
59
67
|
});
|
60
68
|
|
61
69
|
afterEach(() => {
|
@@ -440,5 +448,43 @@ describe('ClusterReachability', () => {
|
|
440
448
|
xtls: {result: 'reachable', latencyInMilliseconds: 40},
|
441
449
|
});
|
442
450
|
});
|
451
|
+
|
452
|
+
it('determines correctly if symmetric-nat is detected', async () => {
|
453
|
+
const promise = clusterReachability.start();
|
454
|
+
|
455
|
+
// generate candidates with duplicate addresses
|
456
|
+
await clock.tickAsync(10);
|
457
|
+
fakePeerConnection.onicecandidate({candidate: {type: 'srflx', address: 'somePublicIp1', relatedPort: 3478, port: 1000}});
|
458
|
+
|
459
|
+
// check events emitted: there shouldn't be any natTypeUpdated emitted
|
460
|
+
assert.equal(emittedEvents[Events.natTypeUpdated].length, 0);
|
461
|
+
|
462
|
+
await clock.tickAsync(10);
|
463
|
+
fakePeerConnection.onicecandidate({candidate: {type: 'srflx', address: 'somePublicIp1', relatedPort: 3478, port: 2000}});
|
464
|
+
|
465
|
+
// should emit natTypeUpdated event
|
466
|
+
assert.equal(emittedEvents[Events.natTypeUpdated].length, 1);
|
467
|
+
assert.deepEqual(emittedEvents[Events.natTypeUpdated][0], {
|
468
|
+
natType: 'symmetric-nat',
|
469
|
+
});
|
470
|
+
|
471
|
+
// send also a relay candidate so that the reachability check finishes
|
472
|
+
fakePeerConnection.onicecandidate({candidate: {type: 'relay', address: 'someTurnRelayIp'}});
|
473
|
+
fakePeerConnection.onicecandidate({
|
474
|
+
candidate: {type: 'relay', address: 'someTurnRelayIp', port: 443},
|
475
|
+
});
|
476
|
+
|
477
|
+
await promise;
|
478
|
+
|
479
|
+
assert.deepEqual(clusterReachability.getResult(), {
|
480
|
+
udp: {
|
481
|
+
result: 'reachable',
|
482
|
+
latencyInMilliseconds: 10,
|
483
|
+
clientMediaIPs: ['somePublicIp1'],
|
484
|
+
},
|
485
|
+
tcp: {result: 'reachable', latencyInMilliseconds: 20},
|
486
|
+
xtls: {result: 'reachable', latencyInMilliseconds: 20},
|
487
|
+
});
|
488
|
+
});
|
443
489
|
});
|
444
490
|
});
|
@@ -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
|
{
|
@@ -2148,6 +2156,7 @@ describe('getReachabilityMetrics', () => {
|
|
2148
2156
|
reachability_vmn_tcp_failed: 0,
|
2149
2157
|
reachability_vmn_xtls_success: 0,
|
2150
2158
|
reachability_vmn_xtls_failed: 0,
|
2159
|
+
natType: 'unknown'
|
2151
2160
|
});
|
2152
2161
|
});
|
2153
2162
|
|
@@ -2215,6 +2224,7 @@ describe('getReachabilityMetrics', () => {
|
|
2215
2224
|
reachability_vmn_tcp_failed: 1,
|
2216
2225
|
reachability_vmn_xtls_success: 0,
|
2217
2226
|
reachability_vmn_xtls_failed: 0,
|
2227
|
+
natType: 'unknown'
|
2218
2228
|
}
|
2219
2229
|
);
|
2220
2230
|
});
|
@@ -2276,6 +2286,7 @@ describe('getReachabilityMetrics', () => {
|
|
2276
2286
|
reachability_vmn_tcp_failed: 0,
|
2277
2287
|
reachability_vmn_xtls_success: 0,
|
2278
2288
|
reachability_vmn_xtls_failed: 0,
|
2289
|
+
natType: 'unknown'
|
2279
2290
|
}
|
2280
2291
|
);
|
2281
2292
|
});
|
@@ -2337,6 +2348,7 @@ describe('getReachabilityMetrics', () => {
|
|
2337
2348
|
reachability_vmn_tcp_failed: 3,
|
2338
2349
|
reachability_vmn_xtls_success: 1,
|
2339
2350
|
reachability_vmn_xtls_failed: 1,
|
2351
|
+
natType: 'unknown'
|
2340
2352
|
}
|
2341
2353
|
);
|
2342
2354
|
});
|
@@ -12,6 +12,9 @@ describe('plugin-meetings/reachability', () => {
|
|
12
12
|
let reachabilityRequest;
|
13
13
|
let webex;
|
14
14
|
|
15
|
+
let appType;
|
16
|
+
let appVersion;
|
17
|
+
|
15
18
|
beforeEach(() => {
|
16
19
|
webex = new MockWebex({
|
17
20
|
children: {
|
@@ -20,6 +23,14 @@ describe('plugin-meetings/reachability', () => {
|
|
20
23
|
},
|
21
24
|
});
|
22
25
|
|
26
|
+
webex.config.support = {
|
27
|
+
'appType': 'NetworkChecker',
|
28
|
+
'appVersion': '43.3.0.1',
|
29
|
+
}
|
30
|
+
|
31
|
+
appType = webex?.config?.support?.appType;
|
32
|
+
appVersion = webex?.config?.support?.appVersion;
|
33
|
+
|
23
34
|
webex.meetings.clientRegion = {
|
24
35
|
countryCode: 'US',
|
25
36
|
regionCode: 'WEST-COAST',
|
@@ -56,7 +67,9 @@ describe('plugin-meetings/reachability', () => {
|
|
56
67
|
|
57
68
|
previousReport = {
|
58
69
|
id: 'fake previous report',
|
59
|
-
}
|
70
|
+
};
|
71
|
+
|
72
|
+
|
60
73
|
});
|
61
74
|
|
62
75
|
afterEach(() => {
|
@@ -79,6 +92,7 @@ describe('plugin-meetings/reachability', () => {
|
|
79
92
|
'report-version': 1,
|
80
93
|
'early-call-min-clusters': true,
|
81
94
|
},
|
95
|
+
'client-environment': { components: { [appType]: appVersion } },
|
82
96
|
'previous-report': previousReport,
|
83
97
|
trigger: 'startup',
|
84
98
|
},
|
@@ -105,6 +119,7 @@ describe('plugin-meetings/reachability', () => {
|
|
105
119
|
'report-version': 1,
|
106
120
|
'early-call-min-clusters': true,
|
107
121
|
},
|
122
|
+
'client-environment': { components: { [appType]: appVersion } },
|
108
123
|
'previous-report': previousReport,
|
109
124
|
trigger: 'early-call/no-min-reached',
|
110
125
|
},
|
@@ -114,5 +129,35 @@ describe('plugin-meetings/reachability', () => {
|
|
114
129
|
assert.deepEqual(res.joinCookie, {anycastEntryPoint: "aws-eu-west-1"})
|
115
130
|
assert.notCalled(webex.internal.newMetrics.callDiagnosticLatencies.measureLatency);
|
116
131
|
});
|
132
|
+
|
133
|
+
it('sends a POST request with the correct params when appVersion is undefined', async () => {
|
134
|
+
// Setting appType & appVersion to undefined
|
135
|
+
webex.config.support.appType = undefined;
|
136
|
+
webex.config.support.appVersion = undefined;
|
137
|
+
|
138
|
+
const res = await reachabilityRequest.getClusters('startup', IP_VERSION.only_ipv4, previousReport);
|
139
|
+
const requestParams = webex.request.getCall(0).args[0];
|
140
|
+
|
141
|
+
assert.deepEqual(requestParams, {
|
142
|
+
method: 'POST',
|
143
|
+
resource: `clusters`,
|
144
|
+
api: 'calliopeDiscovery',
|
145
|
+
shouldRefreshAccessToken: false,
|
146
|
+
timeout: 3000,
|
147
|
+
body: {
|
148
|
+
ipver: IP_VERSION.only_ipv4,
|
149
|
+
'supported-options': {
|
150
|
+
'report-version': 1,
|
151
|
+
'early-call-min-clusters': true,
|
152
|
+
},
|
153
|
+
'previous-report': previousReport,
|
154
|
+
trigger: 'startup',
|
155
|
+
},
|
156
|
+
});
|
157
|
+
|
158
|
+
assert.deepEqual(res.clusters.clusterId, {udp: "testUDP", isVideoMesh: true});
|
159
|
+
assert.deepEqual(res.joinCookie, {anycastEntryPoint: "aws-eu-west-1"});
|
160
|
+
assert.calledOnceWithExactly(webex.internal.newMetrics.callDiagnosticLatencies.measureLatency, sinon.match.func, 'internal.get.cluster.time');
|
161
|
+
});
|
117
162
|
});
|
118
|
-
});
|
163
|
+
});
|