@webex/plugin-meetings 3.3.1 → 3.4.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 +7 -2
- package/dist/breakouts/index.js.map +1 -1
- package/dist/constants.js +11 -4
- package/dist/constants.js.map +1 -1
- package/dist/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/locus-info/selfUtils.js +0 -5
- package/dist/locus-info/selfUtils.js.map +1 -1
- package/dist/media/MediaConnectionAwaiter.js +70 -15
- package/dist/media/MediaConnectionAwaiter.js.map +1 -1
- package/dist/media/index.js +12 -0
- package/dist/media/index.js.map +1 -1
- package/dist/meeting/connectionStateHandler.js +67 -0
- package/dist/meeting/connectionStateHandler.js.map +1 -0
- package/dist/meeting/index.js +552 -357
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/locusMediaRequest.js +7 -0
- package/dist/meeting/locusMediaRequest.js.map +1 -1
- package/dist/meeting/muteState.js +6 -1
- package/dist/meeting/muteState.js.map +1 -1
- package/dist/meeting/util.js +1 -0
- package/dist/meeting/util.js.map +1 -1
- package/dist/meeting-info/index.js +4 -4
- package/dist/meeting-info/index.js.map +1 -1
- package/dist/meeting-info/meeting-info-v2.js +2 -2
- package/dist/meeting-info/meeting-info-v2.js.map +1 -1
- package/dist/meeting-info/util.js +17 -17
- package/dist/meeting-info/util.js.map +1 -1
- package/dist/meeting-info/utilv2.js +16 -16
- package/dist/meeting-info/utilv2.js.map +1 -1
- package/dist/meetings/collection.js +1 -1
- package/dist/meetings/collection.js.map +1 -1
- package/dist/meetings/index.js +37 -33
- package/dist/meetings/index.js.map +1 -1
- package/dist/meetings/meetings.types.js +8 -0
- package/dist/meetings/meetings.types.js.map +1 -1
- package/dist/meetings/util.js +3 -2
- package/dist/meetings/util.js.map +1 -1
- package/dist/metrics/constants.js +2 -1
- package/dist/metrics/constants.js.map +1 -1
- package/dist/metrics/index.js +57 -0
- package/dist/metrics/index.js.map +1 -1
- package/dist/personal-meeting-room/index.js +1 -1
- package/dist/personal-meeting-room/index.js.map +1 -1
- package/dist/reachability/clusterReachability.js +108 -53
- package/dist/reachability/clusterReachability.js.map +1 -1
- package/dist/reachability/index.js +415 -56
- package/dist/reachability/index.js.map +1 -1
- package/dist/types/constants.d.ts +11 -3
- package/dist/types/media/MediaConnectionAwaiter.d.ts +24 -4
- package/dist/types/meeting/connectionStateHandler.d.ts +30 -0
- package/dist/types/meeting/index.d.ts +27 -7
- package/dist/types/meeting/locusMediaRequest.d.ts +2 -0
- package/dist/types/meeting-info/index.d.ts +3 -2
- package/dist/types/meeting-info/meeting-info-v2.d.ts +3 -2
- package/dist/types/meeting-info/util.d.ts +5 -4
- package/dist/types/meeting-info/utilv2.d.ts +3 -2
- package/dist/types/meetings/collection.d.ts +3 -2
- package/dist/types/meetings/index.d.ts +4 -3
- package/dist/types/meetings/meetings.types.d.ts +9 -0
- package/dist/types/metrics/constants.d.ts +1 -0
- package/dist/types/metrics/index.d.ts +15 -0
- package/dist/types/reachability/clusterReachability.d.ts +31 -3
- package/dist/types/reachability/index.d.ts +93 -2
- package/dist/webinar/index.js +1 -1
- package/package.json +23 -23
- package/src/breakouts/index.ts +7 -1
- package/src/constants.ts +13 -17
- package/src/locus-info/selfUtils.ts +0 -5
- package/src/media/MediaConnectionAwaiter.ts +89 -14
- package/src/media/index.ts +13 -0
- package/src/meeting/connectionStateHandler.ts +65 -0
- package/src/meeting/index.ts +526 -292
- package/src/meeting/locusMediaRequest.ts +5 -0
- package/src/meeting/muteState.ts +6 -1
- package/src/meeting/util.ts +1 -0
- package/src/meeting-info/index.ts +9 -6
- package/src/meeting-info/meeting-info-v2.ts +4 -4
- package/src/meeting-info/util.ts +23 -28
- package/src/meeting-info/utilv2.ts +18 -24
- package/src/meetings/collection.ts +3 -3
- package/src/meetings/index.ts +39 -40
- package/src/meetings/meetings.types.ts +11 -0
- package/src/meetings/util.ts +5 -4
- package/src/metrics/constants.ts +1 -0
- package/src/metrics/index.ts +44 -0
- package/src/personal-meeting-room/index.ts +2 -2
- package/src/reachability/clusterReachability.ts +86 -25
- package/src/reachability/index.ts +316 -27
- package/test/unit/spec/breakouts/index.ts +51 -32
- package/test/unit/spec/locus-info/selfUtils.js +25 -23
- package/test/unit/spec/media/MediaConnectionAwaiter.ts +131 -32
- package/test/unit/spec/media/index.ts +42 -27
- package/test/unit/spec/meeting/connectionStateHandler.ts +102 -0
- package/test/unit/spec/meeting/index.js +758 -179
- package/test/unit/spec/meeting/locusMediaRequest.ts +7 -0
- package/test/unit/spec/meeting/muteState.js +24 -0
- package/test/unit/spec/meeting-info/index.js +4 -4
- package/test/unit/spec/meeting-info/meetinginfov2.js +24 -28
- package/test/unit/spec/meeting-info/request.js +2 -2
- package/test/unit/spec/meeting-info/utilv2.js +41 -49
- package/test/unit/spec/meetings/index.js +14 -0
- package/test/unit/spec/metrics/index.js +126 -0
- package/test/unit/spec/multistream/mediaRequestManager.ts +2 -2
- package/test/unit/spec/personal-meeting-room/personal-meeting-room.js +2 -2
- package/test/unit/spec/reachability/clusterReachability.ts +116 -22
- package/test/unit/spec/reachability/index.ts +1153 -84
- package/test/unit/spec/rtcMetrics/index.ts +1 -0
- package/dist/mediaQualityMetrics/config.js +0 -321
- package/dist/mediaQualityMetrics/config.js.map +0 -1
- package/dist/statsAnalyzer/global.js +0 -44
- package/dist/statsAnalyzer/global.js.map +0 -1
- package/dist/statsAnalyzer/index.js +0 -1072
- package/dist/statsAnalyzer/index.js.map +0 -1
- package/dist/statsAnalyzer/mqaUtil.js +0 -368
- package/dist/statsAnalyzer/mqaUtil.js.map +0 -1
- package/dist/types/mediaQualityMetrics/config.d.ts +0 -247
- package/dist/types/statsAnalyzer/global.d.ts +0 -36
- package/dist/types/statsAnalyzer/index.d.ts +0 -217
- package/dist/types/statsAnalyzer/mqaUtil.d.ts +0 -48
- package/src/mediaQualityMetrics/config.ts +0 -255
- package/src/statsAnalyzer/global.ts +0 -37
- package/src/statsAnalyzer/index.ts +0 -1318
- package/src/statsAnalyzer/mqaUtil.ts +0 -463
- package/test/unit/spec/stats-analyzer/index.js +0 -1819
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import {assert} from '@webex/test-helper-chai';
|
|
2
2
|
import MockWebex from '@webex/test-helper-mock-webex';
|
|
3
3
|
import sinon from 'sinon';
|
|
4
|
+
import EventEmitter from 'events';
|
|
5
|
+
import testUtils from '../../../utils/testUtils';
|
|
4
6
|
import Reachability, {
|
|
5
7
|
ReachabilityResults,
|
|
6
8
|
ReachabilityResultsForBackend,
|
|
7
9
|
} from '@webex/plugin-meetings/src/reachability/';
|
|
10
|
+
import { ClusterNode } from '../../../../src/reachability/request';
|
|
8
11
|
import MeetingUtil from '@webex/plugin-meetings/src/meeting/util';
|
|
9
12
|
import * as ClusterReachabilityModule from '@webex/plugin-meetings/src/reachability/clusterReachability';
|
|
13
|
+
import Metrics from '@webex/plugin-meetings/src/metrics';
|
|
10
14
|
|
|
11
15
|
import {IP_VERSION} from '@webex/plugin-meetings/src/constants';
|
|
12
16
|
|
|
@@ -406,13 +410,71 @@ describe('isWebexMediaBackendUnreachable', () => {
|
|
|
406
410
|
});
|
|
407
411
|
});
|
|
408
412
|
|
|
413
|
+
/**
|
|
414
|
+
* helper class to mock ClusterReachability and allow to easily
|
|
415
|
+
* simulate 'resultReady' events from it
|
|
416
|
+
*/
|
|
417
|
+
class MockClusterReachability extends EventEmitter {
|
|
418
|
+
mockResult = {
|
|
419
|
+
udp: {
|
|
420
|
+
result: 'untested',
|
|
421
|
+
},
|
|
422
|
+
tcp: {
|
|
423
|
+
result: 'untested',
|
|
424
|
+
},
|
|
425
|
+
xtls: {
|
|
426
|
+
result: 'untested',
|
|
427
|
+
},
|
|
428
|
+
};
|
|
429
|
+
|
|
430
|
+
isVideoMesh: boolean;
|
|
431
|
+
name: string;
|
|
432
|
+
|
|
433
|
+
constructor(name: string, clusterInfo: ClusterNode) {
|
|
434
|
+
super();
|
|
435
|
+
this.name = name;
|
|
436
|
+
this.isVideoMesh = clusterInfo.isVideoMesh;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
abort = sinon.stub();
|
|
440
|
+
start = sinon.stub();
|
|
441
|
+
|
|
442
|
+
getResult() {
|
|
443
|
+
return this.mockResult;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* Emits a fake 'resultReady' event and makes sure that the same result
|
|
448
|
+
* is returned when getResult() is called.
|
|
449
|
+
*
|
|
450
|
+
* @param protocol
|
|
451
|
+
* @param result
|
|
452
|
+
*/
|
|
453
|
+
public emitFakeResult(protocol, result) {
|
|
454
|
+
this.mockResult[protocol] = result;
|
|
455
|
+
this.emit(ClusterReachabilityModule.Events.resultReady, {protocol, ...result});
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
public emitFakeClientMediaIpUpdate(protocol, newIp) {
|
|
459
|
+
this.mockResult[protocol].clientMediaIPs.push(newIp);
|
|
460
|
+
this.emit(ClusterReachabilityModule.Events.clientMediaIpsUpdated, {
|
|
461
|
+
protocol,
|
|
462
|
+
clientMediaIPs: this.mockResult[protocol].clientMediaIPs,
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
}
|
|
409
466
|
|
|
410
467
|
describe('gatherReachability', () => {
|
|
411
468
|
let webex;
|
|
469
|
+
let clock;
|
|
470
|
+
let clusterReachabilityCtorStub;
|
|
471
|
+
let mockClusterReachabilityInstances: Record<string, MockClusterReachability>;
|
|
412
472
|
|
|
413
473
|
beforeEach(async () => {
|
|
414
474
|
webex = new MockWebex();
|
|
415
475
|
|
|
476
|
+
sinon.stub(Metrics, 'sendBehavioralMetric');
|
|
477
|
+
|
|
416
478
|
await webex.boundedStorage.put(
|
|
417
479
|
'Reachability',
|
|
418
480
|
'reachability.result',
|
|
@@ -423,94 +485,820 @@ describe('gatherReachability', () => {
|
|
|
423
485
|
'reachability.joinCookie',
|
|
424
486
|
JSON.stringify({old: 'joinCookie'})
|
|
425
487
|
);
|
|
488
|
+
|
|
489
|
+
clock = sinon.useFakeTimers();
|
|
490
|
+
|
|
491
|
+
mockClusterReachabilityInstances = {};
|
|
492
|
+
|
|
493
|
+
clusterReachabilityCtorStub = sinon
|
|
494
|
+
.stub(ClusterReachabilityModule, 'ClusterReachability')
|
|
495
|
+
.callsFake((id, cluster) => {
|
|
496
|
+
const mockInstance = new MockClusterReachability(id, cluster);
|
|
497
|
+
|
|
498
|
+
mockClusterReachabilityInstances[id] = mockInstance;
|
|
499
|
+
return mockInstance;
|
|
500
|
+
});
|
|
426
501
|
});
|
|
427
502
|
|
|
428
503
|
afterEach(() => {
|
|
429
504
|
sinon.restore();
|
|
505
|
+
clock.restore();
|
|
430
506
|
});
|
|
431
507
|
|
|
432
|
-
|
|
508
|
+
// simulates time progression so that Reachability times out
|
|
509
|
+
const simulateTimeout = async () => {
|
|
510
|
+
await testUtils.flushPromises();
|
|
511
|
+
clock.tick(3000);
|
|
512
|
+
};
|
|
513
|
+
|
|
514
|
+
const checkResults = async (expectedResults, expectedJoinCookie) => {
|
|
515
|
+
const storedResultForReachabilityResult = await webex.boundedStorage.get(
|
|
516
|
+
'Reachability',
|
|
517
|
+
'reachability.result'
|
|
518
|
+
);
|
|
519
|
+
const storedResultForJoinCookie = await webex.boundedStorage.get(
|
|
520
|
+
'Reachability',
|
|
521
|
+
'reachability.joinCookie'
|
|
522
|
+
);
|
|
523
|
+
|
|
524
|
+
assert.equal(storedResultForReachabilityResult, JSON.stringify(expectedResults));
|
|
525
|
+
assert.equal(storedResultForJoinCookie, JSON.stringify(expectedJoinCookie));
|
|
526
|
+
};
|
|
527
|
+
|
|
528
|
+
[
|
|
529
|
+
// ========================================================================
|
|
530
|
+
{
|
|
531
|
+
title: '1 cluster with events triggered for each protocol',
|
|
532
|
+
waitShortTimeout: false,
|
|
533
|
+
waitLongTimeout: false,
|
|
534
|
+
mockClusters: {
|
|
535
|
+
cluster1: {
|
|
536
|
+
udp: ['udp-url1'],
|
|
537
|
+
tcp: ['tcp-url1'],
|
|
538
|
+
xtls: ['xtls-url1'],
|
|
539
|
+
isVideoMesh: false,
|
|
540
|
+
},
|
|
541
|
+
},
|
|
542
|
+
mockResultReadyEvents: [
|
|
543
|
+
{
|
|
544
|
+
clusterId: 'cluster1',
|
|
545
|
+
protocol: 'tcp',
|
|
546
|
+
result: {
|
|
547
|
+
result: 'reachable',
|
|
548
|
+
latencyInMilliseconds: 11,
|
|
549
|
+
},
|
|
550
|
+
},
|
|
551
|
+
{
|
|
552
|
+
clusterId: 'cluster1',
|
|
553
|
+
protocol: 'udp',
|
|
554
|
+
result: {
|
|
555
|
+
result: 'reachable',
|
|
556
|
+
clientMediaIPs: ['1.2.3.4'],
|
|
557
|
+
latencyInMilliseconds: 22,
|
|
558
|
+
},
|
|
559
|
+
},
|
|
560
|
+
{
|
|
561
|
+
clusterId: 'cluster1',
|
|
562
|
+
protocol: 'xtls',
|
|
563
|
+
result: {
|
|
564
|
+
result: 'reachable',
|
|
565
|
+
latencyInMilliseconds: 33,
|
|
566
|
+
},
|
|
567
|
+
},
|
|
568
|
+
],
|
|
569
|
+
expectedResults: {
|
|
570
|
+
cluster1: {
|
|
571
|
+
udp: {result: 'reachable', clientMediaIPs: ['1.2.3.4'], latencyInMilliseconds: 22},
|
|
572
|
+
tcp: {result: 'reachable', latencyInMilliseconds: 11},
|
|
573
|
+
xtls: {result: 'reachable', latencyInMilliseconds: 33},
|
|
574
|
+
isVideoMesh: false,
|
|
575
|
+
},
|
|
576
|
+
},
|
|
577
|
+
expectedMetrics: {
|
|
578
|
+
vmn_udp_min: -1,
|
|
579
|
+
vmn_udp_max: -1,
|
|
580
|
+
vmn_udp_average: -1,
|
|
581
|
+
public_udp_min: 22,
|
|
582
|
+
public_udp_max: 22,
|
|
583
|
+
public_udp_average: 22,
|
|
584
|
+
public_tcp_min: 11,
|
|
585
|
+
public_tcp_max: 11,
|
|
586
|
+
public_tcp_average: 11,
|
|
587
|
+
public_xtls_min: 33,
|
|
588
|
+
public_xtls_max: 33,
|
|
589
|
+
public_xtls_average: 33,
|
|
590
|
+
},
|
|
591
|
+
},
|
|
592
|
+
// ========================================================================
|
|
593
|
+
{
|
|
594
|
+
title:
|
|
595
|
+
'3 clusters: one with an event for each protocol, one with no events, one with no urls for tcp and xtls',
|
|
596
|
+
waitShortTimeout: 'public',
|
|
597
|
+
waitLongTimeout: true,
|
|
598
|
+
mockClusters: {
|
|
599
|
+
cluster1: {
|
|
600
|
+
udp: ['udp-url1.1', 'udp-url1.2'],
|
|
601
|
+
tcp: ['tcp-url1.1', 'tcp-url1.2'],
|
|
602
|
+
xtls: ['xtls-url1.1', 'xtls-url1.2'],
|
|
603
|
+
isVideoMesh: false,
|
|
604
|
+
},
|
|
605
|
+
cluster2: {
|
|
606
|
+
udp: ['udp-url2.1'],
|
|
607
|
+
tcp: ['tcp-url2.1'],
|
|
608
|
+
xtls: ['xtls-url2.1'],
|
|
609
|
+
isVideoMesh: false,
|
|
610
|
+
},
|
|
611
|
+
cluster3: {
|
|
612
|
+
udp: ['udp-url1'],
|
|
613
|
+
tcp: [],
|
|
614
|
+
xtls: [],
|
|
615
|
+
isVideoMesh: true,
|
|
616
|
+
},
|
|
617
|
+
},
|
|
618
|
+
mockResultReadyEvents: [
|
|
619
|
+
{
|
|
620
|
+
clusterId: 'cluster1',
|
|
621
|
+
protocol: 'udp',
|
|
622
|
+
result: {
|
|
623
|
+
result: 'reachable',
|
|
624
|
+
clientMediaIPs: ['1.2.3.4'],
|
|
625
|
+
latencyInMilliseconds: 13,
|
|
626
|
+
},
|
|
627
|
+
},
|
|
628
|
+
{
|
|
629
|
+
clusterId: 'cluster1',
|
|
630
|
+
protocol: 'tcp',
|
|
631
|
+
result: {
|
|
632
|
+
result: 'reachable',
|
|
633
|
+
latencyInMilliseconds: 53,
|
|
634
|
+
},
|
|
635
|
+
},
|
|
636
|
+
{
|
|
637
|
+
clusterId: 'cluster1',
|
|
638
|
+
protocol: 'xtls',
|
|
639
|
+
result: {
|
|
640
|
+
result: 'reachable',
|
|
641
|
+
latencyInMilliseconds: 113,
|
|
642
|
+
},
|
|
643
|
+
},
|
|
644
|
+
],
|
|
645
|
+
expectedResults: {
|
|
646
|
+
cluster1: {
|
|
647
|
+
udp: {result: 'reachable', clientMediaIPs: ['1.2.3.4'], latencyInMilliseconds: 13},
|
|
648
|
+
tcp: {result: 'reachable', latencyInMilliseconds: 53},
|
|
649
|
+
xtls: {result: 'reachable', latencyInMilliseconds: 113},
|
|
650
|
+
isVideoMesh: false,
|
|
651
|
+
},
|
|
652
|
+
cluster2: {
|
|
653
|
+
udp: {result: 'unreachable'},
|
|
654
|
+
tcp: {result: 'unreachable'},
|
|
655
|
+
xtls: {result: 'unreachable'},
|
|
656
|
+
isVideoMesh: false,
|
|
657
|
+
},
|
|
658
|
+
cluster3: {
|
|
659
|
+
udp: {result: 'unreachable'},
|
|
660
|
+
tcp: {result: 'untested'},
|
|
661
|
+
xtls: {result: 'untested'},
|
|
662
|
+
isVideoMesh: true,
|
|
663
|
+
},
|
|
664
|
+
},
|
|
665
|
+
expectedMetrics: {
|
|
666
|
+
vmn_udp_min: -1,
|
|
667
|
+
vmn_udp_max: -1,
|
|
668
|
+
vmn_udp_average: -1,
|
|
669
|
+
public_udp_min: 13,
|
|
670
|
+
public_udp_max: 13,
|
|
671
|
+
public_udp_average: 13,
|
|
672
|
+
public_tcp_min: 53,
|
|
673
|
+
public_tcp_max: 53,
|
|
674
|
+
public_tcp_average: 53,
|
|
675
|
+
public_xtls_min: 113,
|
|
676
|
+
public_xtls_max: 113,
|
|
677
|
+
public_xtls_average: 113,
|
|
678
|
+
},
|
|
679
|
+
},
|
|
680
|
+
// ========================================================================
|
|
681
|
+
{
|
|
682
|
+
title: '3 clusters: all with all results ready in time for all protocols',
|
|
683
|
+
waitShortTimeout: false,
|
|
684
|
+
waitLongTimeout: false,
|
|
685
|
+
mockClusters: {
|
|
686
|
+
cluster1: {
|
|
687
|
+
udp: ['udp-url1'],
|
|
688
|
+
tcp: ['tcp-url1'],
|
|
689
|
+
xtls: ['xtls-url1'],
|
|
690
|
+
isVideoMesh: false,
|
|
691
|
+
},
|
|
692
|
+
cluster2: {
|
|
693
|
+
udp: ['udp-url2'],
|
|
694
|
+
tcp: ['tcp-url2'],
|
|
695
|
+
xtls: ['xtls-url2'],
|
|
696
|
+
isVideoMesh: false,
|
|
697
|
+
},
|
|
698
|
+
cluster3: {
|
|
699
|
+
udp: ['udp-url3'],
|
|
700
|
+
tcp: ['tcp-url3'],
|
|
701
|
+
xtls: ['xtls-url3'],
|
|
702
|
+
isVideoMesh: false,
|
|
703
|
+
},
|
|
704
|
+
},
|
|
705
|
+
mockResultReadyEvents: [
|
|
706
|
+
{
|
|
707
|
+
clusterId: 'cluster1',
|
|
708
|
+
protocol: 'udp',
|
|
709
|
+
result: {
|
|
710
|
+
result: 'reachable',
|
|
711
|
+
clientMediaIPs: ['1.2.3.4'],
|
|
712
|
+
latencyInMilliseconds: 10,
|
|
713
|
+
},
|
|
714
|
+
},
|
|
715
|
+
{
|
|
716
|
+
clusterId: 'cluster1',
|
|
717
|
+
protocol: 'tcp',
|
|
718
|
+
result: {
|
|
719
|
+
result: 'reachable',
|
|
720
|
+
latencyInMilliseconds: 100,
|
|
721
|
+
},
|
|
722
|
+
},
|
|
723
|
+
{
|
|
724
|
+
clusterId: 'cluster1',
|
|
725
|
+
protocol: 'xtls',
|
|
726
|
+
result: {
|
|
727
|
+
result: 'reachable',
|
|
728
|
+
latencyInMilliseconds: 200,
|
|
729
|
+
},
|
|
730
|
+
},
|
|
731
|
+
{
|
|
732
|
+
clusterId: 'cluster2',
|
|
733
|
+
protocol: 'udp',
|
|
734
|
+
result: {
|
|
735
|
+
result: 'reachable',
|
|
736
|
+
clientMediaIPs: ['1.2.3.4'],
|
|
737
|
+
latencyInMilliseconds: 20,
|
|
738
|
+
},
|
|
739
|
+
},
|
|
740
|
+
{
|
|
741
|
+
clusterId: 'cluster2',
|
|
742
|
+
protocol: 'tcp',
|
|
743
|
+
result: {
|
|
744
|
+
result: 'reachable',
|
|
745
|
+
latencyInMilliseconds: 110,
|
|
746
|
+
},
|
|
747
|
+
},
|
|
748
|
+
{
|
|
749
|
+
clusterId: 'cluster2',
|
|
750
|
+
protocol: 'xtls',
|
|
751
|
+
result: {
|
|
752
|
+
result: 'reachable',
|
|
753
|
+
latencyInMilliseconds: 220,
|
|
754
|
+
},
|
|
755
|
+
},
|
|
756
|
+
{
|
|
757
|
+
clusterId: 'cluster3',
|
|
758
|
+
protocol: 'udp',
|
|
759
|
+
result: {
|
|
760
|
+
result: 'reachable',
|
|
761
|
+
clientMediaIPs: ['1.2.3.4'],
|
|
762
|
+
latencyInMilliseconds: 30,
|
|
763
|
+
},
|
|
764
|
+
},
|
|
765
|
+
{
|
|
766
|
+
clusterId: 'cluster3',
|
|
767
|
+
protocol: 'tcp',
|
|
768
|
+
result: {
|
|
769
|
+
result: 'reachable',
|
|
770
|
+
latencyInMilliseconds: 120,
|
|
771
|
+
},
|
|
772
|
+
},
|
|
773
|
+
{
|
|
774
|
+
clusterId: 'cluster3',
|
|
775
|
+
protocol: 'xtls',
|
|
776
|
+
result: {
|
|
777
|
+
result: 'reachable',
|
|
778
|
+
latencyInMilliseconds: 240,
|
|
779
|
+
},
|
|
780
|
+
},
|
|
781
|
+
],
|
|
782
|
+
expectedResults: {
|
|
783
|
+
cluster1: {
|
|
784
|
+
udp: {result: 'reachable', clientMediaIPs: ['1.2.3.4'], latencyInMilliseconds: 10},
|
|
785
|
+
tcp: {result: 'reachable', latencyInMilliseconds: 100},
|
|
786
|
+
xtls: {result: 'reachable', latencyInMilliseconds: 200},
|
|
787
|
+
isVideoMesh: false,
|
|
788
|
+
},
|
|
789
|
+
cluster2: {
|
|
790
|
+
udp: {result: 'reachable', clientMediaIPs: ['1.2.3.4'], latencyInMilliseconds: 20},
|
|
791
|
+
tcp: {result: 'reachable', latencyInMilliseconds: 110},
|
|
792
|
+
xtls: {result: 'reachable', latencyInMilliseconds: 220},
|
|
793
|
+
isVideoMesh: false,
|
|
794
|
+
},
|
|
795
|
+
cluster3: {
|
|
796
|
+
udp: {result: 'reachable', clientMediaIPs: ['1.2.3.4'], latencyInMilliseconds: 30},
|
|
797
|
+
tcp: {result: 'reachable', latencyInMilliseconds: 120},
|
|
798
|
+
xtls: {result: 'reachable', latencyInMilliseconds: 240},
|
|
799
|
+
isVideoMesh: false,
|
|
800
|
+
},
|
|
801
|
+
},
|
|
802
|
+
expectedMetrics: {
|
|
803
|
+
vmn_udp_min: -1,
|
|
804
|
+
vmn_udp_max: -1,
|
|
805
|
+
vmn_udp_average: -1,
|
|
806
|
+
public_udp_min: 10,
|
|
807
|
+
public_udp_max: 30,
|
|
808
|
+
public_udp_average: 20,
|
|
809
|
+
public_tcp_min: 100,
|
|
810
|
+
public_tcp_max: 120,
|
|
811
|
+
public_tcp_average: 110,
|
|
812
|
+
public_xtls_min: 200,
|
|
813
|
+
public_xtls_max: 240,
|
|
814
|
+
public_xtls_average: 220,
|
|
815
|
+
},
|
|
816
|
+
},
|
|
817
|
+
// ========================================================================
|
|
818
|
+
{
|
|
819
|
+
title: '2 clusters: both with no results at all',
|
|
820
|
+
waitShortTimeout: 'public',
|
|
821
|
+
waitLongTimeout: true,
|
|
822
|
+
mockClusters: {
|
|
823
|
+
cluster1: {
|
|
824
|
+
udp: ['udp-url1'],
|
|
825
|
+
tcp: ['tcp-url1'],
|
|
826
|
+
xtls: ['xtls-url1'],
|
|
827
|
+
isVideoMesh: false,
|
|
828
|
+
},
|
|
829
|
+
cluster2: {
|
|
830
|
+
udp: ['udp-url2'],
|
|
831
|
+
tcp: ['tcp-url2'],
|
|
832
|
+
xtls: ['xtls-url2'],
|
|
833
|
+
isVideoMesh: false,
|
|
834
|
+
},
|
|
835
|
+
},
|
|
836
|
+
mockResultReadyEvents: [],
|
|
837
|
+
expectedResults: {
|
|
838
|
+
cluster1: {
|
|
839
|
+
udp: {result: 'unreachable'},
|
|
840
|
+
tcp: {result: 'unreachable'},
|
|
841
|
+
xtls: {result: 'unreachable'},
|
|
842
|
+
isVideoMesh: false,
|
|
843
|
+
},
|
|
844
|
+
cluster2: {
|
|
845
|
+
udp: {result: 'unreachable'},
|
|
846
|
+
tcp: {result: 'unreachable'},
|
|
847
|
+
xtls: {result: 'unreachable'},
|
|
848
|
+
isVideoMesh: false,
|
|
849
|
+
},
|
|
850
|
+
},
|
|
851
|
+
expectedMetrics: {
|
|
852
|
+
vmn_udp_min: -1,
|
|
853
|
+
vmn_udp_max: -1,
|
|
854
|
+
vmn_udp_average: -1,
|
|
855
|
+
public_udp_min: -1,
|
|
856
|
+
public_udp_max: -1,
|
|
857
|
+
public_udp_average: -1,
|
|
858
|
+
public_tcp_min: -1,
|
|
859
|
+
public_tcp_max: -1,
|
|
860
|
+
public_tcp_average: -1,
|
|
861
|
+
public_xtls_min: -1,
|
|
862
|
+
public_xtls_max: -1,
|
|
863
|
+
public_xtls_average: -1,
|
|
864
|
+
},
|
|
865
|
+
},
|
|
866
|
+
// ========================================================================
|
|
867
|
+
{
|
|
868
|
+
title:
|
|
869
|
+
'3 clusters: 2 VMN clusters missing results, but the public one has all results within 1s',
|
|
870
|
+
waitShortTimeout: 'vmn',
|
|
871
|
+
waitLongTimeout: true,
|
|
872
|
+
mockClusters: {
|
|
873
|
+
vmnCluster1: {
|
|
874
|
+
udp: ['udp-url1'],
|
|
875
|
+
tcp: ['tcp-url1'],
|
|
876
|
+
xtls: ['xtls-url1'],
|
|
877
|
+
isVideoMesh: true,
|
|
878
|
+
},
|
|
879
|
+
publicCluster: {
|
|
880
|
+
udp: ['udp-url2'],
|
|
881
|
+
tcp: ['tcp-url2'],
|
|
882
|
+
xtls: ['xtls-url2'],
|
|
883
|
+
isVideoMesh: false,
|
|
884
|
+
},
|
|
885
|
+
vmnCluster2: {
|
|
886
|
+
udp: ['udp-url3'],
|
|
887
|
+
tcp: ['tcp-url3'],
|
|
888
|
+
xtls: ['xtls-url3'],
|
|
889
|
+
isVideoMesh: true,
|
|
890
|
+
},
|
|
891
|
+
},
|
|
892
|
+
mockResultReadyEvents: [
|
|
893
|
+
{
|
|
894
|
+
clusterId: 'publicCluster',
|
|
895
|
+
protocol: 'udp',
|
|
896
|
+
result: {
|
|
897
|
+
result: 'reachable',
|
|
898
|
+
clientMediaIPs: ['1.2.3.4'],
|
|
899
|
+
latencyInMilliseconds: 10,
|
|
900
|
+
},
|
|
901
|
+
},
|
|
902
|
+
{
|
|
903
|
+
clusterId: 'publicCluster',
|
|
904
|
+
protocol: 'tcp',
|
|
905
|
+
result: {
|
|
906
|
+
result: 'reachable',
|
|
907
|
+
latencyInMilliseconds: 100,
|
|
908
|
+
},
|
|
909
|
+
},
|
|
910
|
+
{
|
|
911
|
+
clusterId: 'publicCluster',
|
|
912
|
+
protocol: 'xtls',
|
|
913
|
+
result: {
|
|
914
|
+
result: 'reachable',
|
|
915
|
+
latencyInMilliseconds: 200,
|
|
916
|
+
},
|
|
917
|
+
},
|
|
918
|
+
],
|
|
919
|
+
expectedResults: {
|
|
920
|
+
vmnCluster1: {
|
|
921
|
+
udp: {result: 'unreachable'},
|
|
922
|
+
tcp: {result: 'untested'},
|
|
923
|
+
xtls: {result: 'untested'},
|
|
924
|
+
isVideoMesh: true,
|
|
925
|
+
},
|
|
926
|
+
publicCluster: {
|
|
927
|
+
udp: {result: 'reachable', clientMediaIPs: ['1.2.3.4'], latencyInMilliseconds: 10},
|
|
928
|
+
tcp: {result: 'reachable', latencyInMilliseconds: 100},
|
|
929
|
+
xtls: {result: 'reachable', latencyInMilliseconds: 200},
|
|
930
|
+
isVideoMesh: false,
|
|
931
|
+
},
|
|
932
|
+
vmnCluster2: {
|
|
933
|
+
udp: {result: 'unreachable'},
|
|
934
|
+
tcp: {result: 'untested'},
|
|
935
|
+
xtls: {result: 'untested'},
|
|
936
|
+
isVideoMesh: true,
|
|
937
|
+
},
|
|
938
|
+
},
|
|
939
|
+
expectedMetrics: {
|
|
940
|
+
vmn_udp_min: -1,
|
|
941
|
+
vmn_udp_max: -1,
|
|
942
|
+
vmn_udp_average: -1,
|
|
943
|
+
public_udp_min: 10,
|
|
944
|
+
public_udp_max: 10,
|
|
945
|
+
public_udp_average: 10,
|
|
946
|
+
public_tcp_min: 100,
|
|
947
|
+
public_tcp_max: 100,
|
|
948
|
+
public_tcp_average: 100,
|
|
949
|
+
public_xtls_min: 200,
|
|
950
|
+
public_xtls_max: 200,
|
|
951
|
+
public_xtls_average: 200,
|
|
952
|
+
},
|
|
953
|
+
},
|
|
954
|
+
// ========================================================================
|
|
955
|
+
{
|
|
956
|
+
title: '2 VMN clusters with all results',
|
|
957
|
+
waitShortTimeout: false,
|
|
958
|
+
waitLongTimeout: false,
|
|
959
|
+
mockClusters: {
|
|
960
|
+
vmnCluster1: {
|
|
961
|
+
udp: ['udp-url1'],
|
|
962
|
+
tcp: [],
|
|
963
|
+
xtls: [],
|
|
964
|
+
isVideoMesh: true,
|
|
965
|
+
},
|
|
966
|
+
vmnCluster2: {
|
|
967
|
+
udp: ['udp-url3'],
|
|
968
|
+
tcp: [],
|
|
969
|
+
xtls: [],
|
|
970
|
+
isVideoMesh: true,
|
|
971
|
+
},
|
|
972
|
+
},
|
|
973
|
+
mockResultReadyEvents: [
|
|
974
|
+
{
|
|
975
|
+
clusterId: 'vmnCluster1',
|
|
976
|
+
protocol: 'udp',
|
|
977
|
+
result: {
|
|
978
|
+
result: 'reachable',
|
|
979
|
+
clientMediaIPs: ['192.168.10.1'],
|
|
980
|
+
latencyInMilliseconds: 100,
|
|
981
|
+
},
|
|
982
|
+
},
|
|
983
|
+
{
|
|
984
|
+
clusterId: 'vmnCluster2',
|
|
985
|
+
protocol: 'udp',
|
|
986
|
+
result: {
|
|
987
|
+
result: 'reachable',
|
|
988
|
+
clientMediaIPs: ['192.168.0.1'],
|
|
989
|
+
latencyInMilliseconds: 300,
|
|
990
|
+
},
|
|
991
|
+
},
|
|
992
|
+
],
|
|
993
|
+
expectedResults: {
|
|
994
|
+
vmnCluster1: {
|
|
995
|
+
udp: {result: 'reachable', clientMediaIPs: ['192.168.10.1'], latencyInMilliseconds: 100},
|
|
996
|
+
tcp: {result: 'untested'},
|
|
997
|
+
xtls: {result: 'untested'},
|
|
998
|
+
isVideoMesh: true,
|
|
999
|
+
},
|
|
1000
|
+
vmnCluster2: {
|
|
1001
|
+
udp: {result: 'reachable', clientMediaIPs: ['192.168.0.1'], latencyInMilliseconds: 300},
|
|
1002
|
+
tcp: {result: 'untested'},
|
|
1003
|
+
xtls: {result: 'untested'},
|
|
1004
|
+
isVideoMesh: true,
|
|
1005
|
+
},
|
|
1006
|
+
},
|
|
1007
|
+
expectedMetrics: {
|
|
1008
|
+
vmn_udp_min: 100,
|
|
1009
|
+
vmn_udp_max: 300,
|
|
1010
|
+
vmn_udp_average: 200,
|
|
1011
|
+
public_udp_min: -1,
|
|
1012
|
+
public_udp_max: -1,
|
|
1013
|
+
public_udp_average: -1,
|
|
1014
|
+
public_tcp_min: -1,
|
|
1015
|
+
public_tcp_max: -1,
|
|
1016
|
+
public_tcp_average: -1,
|
|
1017
|
+
public_xtls_min: -1,
|
|
1018
|
+
public_xtls_max: -1,
|
|
1019
|
+
public_xtls_average: -1,
|
|
1020
|
+
},
|
|
1021
|
+
},
|
|
1022
|
+
].forEach(
|
|
1023
|
+
({
|
|
1024
|
+
title,
|
|
1025
|
+
waitShortTimeout,
|
|
1026
|
+
waitLongTimeout,
|
|
1027
|
+
mockClusters,
|
|
1028
|
+
mockResultReadyEvents,
|
|
1029
|
+
expectedResults,
|
|
1030
|
+
expectedMetrics,
|
|
1031
|
+
}) =>
|
|
1032
|
+
it(`works correctly for the case: ${title}`, async () => {
|
|
1033
|
+
webex.config.meetings.experimental = {
|
|
1034
|
+
enableTcpReachability: true,
|
|
1035
|
+
enableTlsReachability: true,
|
|
1036
|
+
};
|
|
1037
|
+
|
|
1038
|
+
const receivedEvents = {
|
|
1039
|
+
done: 0,
|
|
1040
|
+
firstResultAvailable: {
|
|
1041
|
+
udp: 0,
|
|
1042
|
+
tcp: 0,
|
|
1043
|
+
xtls: 0,
|
|
1044
|
+
},
|
|
1045
|
+
};
|
|
1046
|
+
|
|
1047
|
+
const reachability = new Reachability(webex);
|
|
1048
|
+
|
|
1049
|
+
reachability.on('reachability:done', () => {
|
|
1050
|
+
receivedEvents.done += 1;
|
|
1051
|
+
});
|
|
1052
|
+
reachability.on('reachability:firstResultAvailable', ({protocol}) => {
|
|
1053
|
+
receivedEvents.firstResultAvailable[protocol] += 1;
|
|
1054
|
+
});
|
|
1055
|
+
|
|
1056
|
+
const mockGetClustersResult = {
|
|
1057
|
+
clusters: {},
|
|
1058
|
+
joinCookie: {id: 'id'},
|
|
1059
|
+
};
|
|
1060
|
+
|
|
1061
|
+
Object.entries(mockClusters).forEach(([id, mockCluster]) => {
|
|
1062
|
+
mockGetClustersResult.clusters[id] = mockCluster;
|
|
1063
|
+
});
|
|
1064
|
+
|
|
1065
|
+
reachability.reachabilityRequest.getClusters = sinon.stub().returns(mockGetClustersResult);
|
|
1066
|
+
|
|
1067
|
+
const resultPromise = reachability.gatherReachability();
|
|
1068
|
+
|
|
1069
|
+
await testUtils.flushPromises();
|
|
1070
|
+
|
|
1071
|
+
// check that ClusterReachability instance was created for each cluster
|
|
1072
|
+
Object.entries(mockClusters).forEach(([id, mockCluster]) => {
|
|
1073
|
+
assert.calledWith(clusterReachabilityCtorStub, id, mockCluster);
|
|
1074
|
+
});
|
|
1075
|
+
|
|
1076
|
+
// trigger mock result events from ClusterReachability instances
|
|
1077
|
+
mockResultReadyEvents.forEach((mockEvent) => {
|
|
1078
|
+
mockClusterReachabilityInstances[mockEvent.clusterId].emitFakeResult(
|
|
1079
|
+
mockEvent.protocol,
|
|
1080
|
+
mockEvent.result
|
|
1081
|
+
);
|
|
1082
|
+
});
|
|
1083
|
+
|
|
1084
|
+
if (waitShortTimeout === 'public') {
|
|
1085
|
+
clock.tick(3000);
|
|
1086
|
+
}
|
|
1087
|
+
if (waitShortTimeout === 'vmn') {
|
|
1088
|
+
clock.tick(1000);
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
await resultPromise;
|
|
1092
|
+
|
|
1093
|
+
await checkResults(expectedResults, mockGetClustersResult.joinCookie);
|
|
1094
|
+
|
|
1095
|
+
if (waitLongTimeout) {
|
|
1096
|
+
// we need to wait either 14 or 12 seconds to get to the 15s timeout (depending on how much we waited earlier)
|
|
1097
|
+
clock.tick(waitShortTimeout === 'vmn' ? 14000 : 12000);
|
|
1098
|
+
|
|
1099
|
+
// we check the results again after the long timeout - they should be the same
|
|
1100
|
+
await checkResults(expectedResults, mockGetClustersResult.joinCookie);
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
// now check events emitted by Reachability class
|
|
1104
|
+
assert.equal(receivedEvents['done'], 1);
|
|
1105
|
+
|
|
1106
|
+
// if we've mocked at least one event for any protocol, check that we received
|
|
1107
|
+
// firstResultAvailable event for that protocol
|
|
1108
|
+
if (mockResultReadyEvents.filter((event) => event.protocol === 'udp').length > 0) {
|
|
1109
|
+
assert.equal(receivedEvents['firstResultAvailable']['udp'], 1);
|
|
1110
|
+
}
|
|
1111
|
+
if (mockResultReadyEvents.filter((event) => event.protocol === 'tcp').length > 0) {
|
|
1112
|
+
assert.equal(receivedEvents['firstResultAvailable']['tcp'], 1);
|
|
1113
|
+
}
|
|
1114
|
+
if (mockResultReadyEvents.filter((event) => event.protocol === 'xtls').length > 0) {
|
|
1115
|
+
assert.equal(receivedEvents['firstResultAvailable']['xtls'], 1);
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
// finally, check the metrics
|
|
1119
|
+
assert.calledWith(
|
|
1120
|
+
Metrics.sendBehavioralMetric,
|
|
1121
|
+
'js_sdk_reachability_completed',
|
|
1122
|
+
expectedMetrics
|
|
1123
|
+
);
|
|
1124
|
+
})
|
|
1125
|
+
);
|
|
1126
|
+
|
|
1127
|
+
it('keeps updating reachability results after the 3s public cloud timeout expires', async () => {
|
|
1128
|
+
webex.config.meetings.experimental = {
|
|
1129
|
+
enableTcpReachability: true,
|
|
1130
|
+
enableTlsReachability: true,
|
|
1131
|
+
};
|
|
1132
|
+
|
|
433
1133
|
const reachability = new Reachability(webex);
|
|
434
1134
|
|
|
435
|
-
const
|
|
1135
|
+
const mockGetClustersResult = {
|
|
436
1136
|
clusters: {
|
|
437
|
-
|
|
438
|
-
udp: '
|
|
1137
|
+
clusterA: {
|
|
1138
|
+
udp: ['udp-urlA'],
|
|
1139
|
+
tcp: ['tcp-urlA'],
|
|
1140
|
+
xtls: ['xtls-urlA'],
|
|
1141
|
+
isVideoMesh: false,
|
|
1142
|
+
},
|
|
1143
|
+
clusterB: {
|
|
1144
|
+
udp: ['udp-urlB'],
|
|
1145
|
+
tcp: ['tcp-urlB'],
|
|
1146
|
+
xtls: ['xtls-urlB'],
|
|
1147
|
+
isVideoMesh: false,
|
|
439
1148
|
},
|
|
440
1149
|
},
|
|
441
|
-
};
|
|
442
|
-
const getClustersResult = {
|
|
443
|
-
clusters: {clusterId: 'cluster'},
|
|
444
1150
|
joinCookie: {id: 'id'},
|
|
445
1151
|
};
|
|
446
1152
|
|
|
447
|
-
reachability.reachabilityRequest.getClusters = sinon.stub().returns(
|
|
448
|
-
(reachability as any).performReachabilityChecks = sinon.stub().returns(reachabilityResults);
|
|
1153
|
+
reachability.reachabilityRequest.getClusters = sinon.stub().returns(mockGetClustersResult);
|
|
449
1154
|
|
|
450
|
-
const
|
|
1155
|
+
const resultPromise = reachability.gatherReachability();
|
|
451
1156
|
|
|
452
|
-
|
|
1157
|
+
await testUtils.flushPromises();
|
|
453
1158
|
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
1159
|
+
// trigger some mock result events from ClusterReachability instances
|
|
1160
|
+
mockClusterReachabilityInstances['clusterA'].emitFakeResult('udp', {
|
|
1161
|
+
result: 'reachable',
|
|
1162
|
+
clientMediaIPs: ['1.2.3.4'],
|
|
1163
|
+
latencyInMilliseconds: 11,
|
|
1164
|
+
});
|
|
1165
|
+
mockClusterReachabilityInstances['clusterB'].emitFakeResult('udp', {
|
|
1166
|
+
result: 'reachable',
|
|
1167
|
+
clientMediaIPs: ['10.20.30.40'],
|
|
1168
|
+
latencyInMilliseconds: 22,
|
|
1169
|
+
});
|
|
1170
|
+
|
|
1171
|
+
clock.tick(3000);
|
|
1172
|
+
await resultPromise;
|
|
1173
|
+
|
|
1174
|
+
// check that the reachability results contain the 2 results from above
|
|
1175
|
+
await checkResults(
|
|
1176
|
+
{
|
|
1177
|
+
clusterA: {
|
|
1178
|
+
udp: {result: 'reachable', clientMediaIPs: ['1.2.3.4'], latencyInMilliseconds: 11},
|
|
1179
|
+
tcp: {result: 'unreachable'},
|
|
1180
|
+
xtls: {result: 'unreachable'},
|
|
1181
|
+
isVideoMesh: false,
|
|
1182
|
+
},
|
|
1183
|
+
clusterB: {
|
|
1184
|
+
udp: {result: 'reachable', clientMediaIPs: ['10.20.30.40'], latencyInMilliseconds: 22},
|
|
1185
|
+
tcp: {result: 'unreachable'},
|
|
1186
|
+
xtls: {result: 'unreachable'},
|
|
1187
|
+
isVideoMesh: false,
|
|
1188
|
+
},
|
|
1189
|
+
},
|
|
1190
|
+
mockGetClustersResult.joinCookie
|
|
461
1191
|
);
|
|
462
1192
|
|
|
463
|
-
|
|
464
|
-
|
|
1193
|
+
// now simulate some more "late" results
|
|
1194
|
+
mockClusterReachabilityInstances['clusterA'].emitFakeResult('tcp', {
|
|
1195
|
+
result: 'reachable',
|
|
1196
|
+
latencyInMilliseconds: 101,
|
|
1197
|
+
});
|
|
1198
|
+
mockClusterReachabilityInstances['clusterB'].emitFakeResult('xtls', {
|
|
1199
|
+
result: 'reachable',
|
|
1200
|
+
latencyInMilliseconds: 102,
|
|
1201
|
+
});
|
|
1202
|
+
|
|
1203
|
+
// and wait for the final overall timeout
|
|
1204
|
+
clock.tick(12000);
|
|
1205
|
+
|
|
1206
|
+
// the reachability results should include all results from above (including the late ones)
|
|
1207
|
+
await checkResults(
|
|
1208
|
+
{
|
|
1209
|
+
clusterA: {
|
|
1210
|
+
udp: {result: 'reachable', clientMediaIPs: ['1.2.3.4'], latencyInMilliseconds: 11},
|
|
1211
|
+
tcp: {result: 'reachable', latencyInMilliseconds: 101},
|
|
1212
|
+
xtls: {result: 'unreachable'},
|
|
1213
|
+
isVideoMesh: false,
|
|
1214
|
+
},
|
|
1215
|
+
clusterB: {
|
|
1216
|
+
udp: {result: 'reachable', clientMediaIPs: ['10.20.30.40'], latencyInMilliseconds: 22},
|
|
1217
|
+
tcp: {result: 'unreachable'},
|
|
1218
|
+
xtls: {result: 'reachable', latencyInMilliseconds: 102},
|
|
1219
|
+
isVideoMesh: false,
|
|
1220
|
+
},
|
|
1221
|
+
},
|
|
1222
|
+
mockGetClustersResult.joinCookie
|
|
1223
|
+
);
|
|
465
1224
|
});
|
|
466
1225
|
|
|
467
|
-
it('
|
|
1226
|
+
it('handles clientMediaIpsUpdated event by updating clientMediaIps in results', async () => {
|
|
1227
|
+
webex.config.meetings.experimental = {
|
|
1228
|
+
enableTcpReachability: true,
|
|
1229
|
+
enableTlsReachability: true,
|
|
1230
|
+
};
|
|
1231
|
+
|
|
468
1232
|
const reachability = new Reachability(webex);
|
|
469
1233
|
|
|
470
|
-
const
|
|
1234
|
+
const mockGetClustersResult = {
|
|
471
1235
|
clusters: {
|
|
472
|
-
|
|
473
|
-
udp: '
|
|
1236
|
+
clusterA: {
|
|
1237
|
+
udp: ['udp-urlA'],
|
|
1238
|
+
tcp: ['tcp-urlA'],
|
|
1239
|
+
xtls: ['xtls-urlA'],
|
|
1240
|
+
isVideoMesh: false,
|
|
474
1241
|
},
|
|
475
1242
|
},
|
|
476
|
-
};
|
|
477
|
-
const getClustersResult = {
|
|
478
|
-
clusters: {clusterId: 'cluster'},
|
|
479
1243
|
joinCookie: {id: 'id'},
|
|
480
1244
|
};
|
|
481
1245
|
|
|
1246
|
+
reachability.reachabilityRequest.getClusters = sinon.stub().returns(mockGetClustersResult);
|
|
1247
|
+
|
|
1248
|
+
const resultPromise = reachability.gatherReachability();
|
|
1249
|
+
|
|
1250
|
+
await testUtils.flushPromises();
|
|
1251
|
+
|
|
1252
|
+
// trigger a mock result event
|
|
1253
|
+
mockClusterReachabilityInstances['clusterA'].emitFakeResult('udp', {
|
|
1254
|
+
result: 'reachable',
|
|
1255
|
+
clientMediaIPs: ['64.103.40.20'],
|
|
1256
|
+
latencyInMilliseconds: 11,
|
|
1257
|
+
});
|
|
1258
|
+
// followed by some updates to client media IPs
|
|
1259
|
+
mockClusterReachabilityInstances['clusterA'].emitFakeClientMediaIpUpdate('udp', '64.103.40.21');
|
|
1260
|
+
mockClusterReachabilityInstances['clusterA'].emitFakeClientMediaIpUpdate('udp', '64.103.40.22');
|
|
1261
|
+
|
|
1262
|
+
// wait for the final overall timeout
|
|
1263
|
+
clock.tick(15000);
|
|
1264
|
+
await resultPromise;
|
|
1265
|
+
|
|
1266
|
+
// check that the reachability results contain all the client media ips
|
|
1267
|
+
await checkResults(
|
|
1268
|
+
{
|
|
1269
|
+
clusterA: {
|
|
1270
|
+
udp: {
|
|
1271
|
+
result: 'reachable',
|
|
1272
|
+
clientMediaIPs: ['64.103.40.20', '64.103.40.21', '64.103.40.22'],
|
|
1273
|
+
latencyInMilliseconds: 11,
|
|
1274
|
+
},
|
|
1275
|
+
tcp: {result: 'unreachable'},
|
|
1276
|
+
xtls: {result: 'unreachable'},
|
|
1277
|
+
isVideoMesh: false,
|
|
1278
|
+
},
|
|
1279
|
+
},
|
|
1280
|
+
mockGetClustersResult.joinCookie
|
|
1281
|
+
);
|
|
1282
|
+
});
|
|
1283
|
+
|
|
1284
|
+
it('keeps the stored reachability from previous call to gatherReachability if getClusters fails', async () => {
|
|
1285
|
+
const reachability = new Reachability(webex);
|
|
1286
|
+
|
|
482
1287
|
reachability.reachabilityRequest.getClusters = sinon.stub().throws();
|
|
483
1288
|
|
|
484
1289
|
const result = await reachability.gatherReachability();
|
|
485
1290
|
|
|
486
1291
|
assert.empty(result);
|
|
487
1292
|
|
|
488
|
-
|
|
489
|
-
'Reachability',
|
|
490
|
-
'reachability.result'
|
|
491
|
-
);
|
|
492
|
-
const storedResultForJoinCookie = await webex.boundedStorage.get(
|
|
493
|
-
'Reachability',
|
|
494
|
-
'reachability.joinCookie'
|
|
495
|
-
);
|
|
496
|
-
|
|
497
|
-
assert.equal(JSON.stringify({old: 'results'}), storedResultForReachabilityResult);
|
|
498
|
-
assert.equal(JSON.stringify({old: 'joinCookie'}), storedResultForJoinCookie);
|
|
1293
|
+
await checkResults({old: 'results'}, {old: 'joinCookie'});
|
|
499
1294
|
});
|
|
500
1295
|
|
|
501
1296
|
it('keeps the stored reachability from previous call to gatherReachability if performReachabilityChecks fails', async () => {
|
|
502
1297
|
const reachability = new Reachability(webex);
|
|
503
1298
|
|
|
504
|
-
const reachabilityResults = {
|
|
505
|
-
clusters: {
|
|
506
|
-
clusterId: {
|
|
507
|
-
udp: 'testUDP',
|
|
508
|
-
},
|
|
509
|
-
},
|
|
510
|
-
};
|
|
511
1299
|
const getClustersResult = {
|
|
512
1300
|
clusters: {clusterId: 'cluster'},
|
|
513
|
-
joinCookie: {id: 'id'},
|
|
1301
|
+
joinCookie: {id: 'cookie id'},
|
|
514
1302
|
};
|
|
515
1303
|
|
|
516
1304
|
reachability.reachabilityRequest.getClusters = sinon.stub().returns(getClustersResult);
|
|
@@ -520,17 +1308,7 @@ describe('gatherReachability', () => {
|
|
|
520
1308
|
|
|
521
1309
|
assert.empty(result);
|
|
522
1310
|
|
|
523
|
-
|
|
524
|
-
'Reachability',
|
|
525
|
-
'reachability.result'
|
|
526
|
-
);
|
|
527
|
-
const storedResultForJoinCookie = await webex.boundedStorage.get(
|
|
528
|
-
'Reachability',
|
|
529
|
-
'reachability.joinCookie'
|
|
530
|
-
);
|
|
531
|
-
|
|
532
|
-
assert.equal(JSON.stringify({old: 'results'}), storedResultForReachabilityResult);
|
|
533
|
-
assert.equal(JSON.stringify({old: 'joinCookie'}), storedResultForJoinCookie);
|
|
1311
|
+
await checkResults({old: 'results'}, {id: 'cookie id'});
|
|
534
1312
|
});
|
|
535
1313
|
|
|
536
1314
|
it('starts ClusterReachability on each media cluster', async () => {
|
|
@@ -561,14 +1339,10 @@ describe('gatherReachability', () => {
|
|
|
561
1339
|
|
|
562
1340
|
reachability.reachabilityRequest.getClusters = sinon.stub().returns(getClustersResult);
|
|
563
1341
|
|
|
564
|
-
const
|
|
565
|
-
const clusterReachabilityCtorStub = sinon
|
|
566
|
-
.stub(ClusterReachabilityModule, 'ClusterReachability')
|
|
567
|
-
.callsFake(() => ({
|
|
568
|
-
start: startStub,
|
|
569
|
-
}));
|
|
1342
|
+
const promise = reachability.gatherReachability();
|
|
570
1343
|
|
|
571
|
-
await
|
|
1344
|
+
await simulateTimeout();
|
|
1345
|
+
await promise;
|
|
572
1346
|
|
|
573
1347
|
assert.calledTwice(clusterReachabilityCtorStub);
|
|
574
1348
|
assert.calledWith(clusterReachabilityCtorStub, 'cluster 1', {
|
|
@@ -585,7 +1359,8 @@ describe('gatherReachability', () => {
|
|
|
585
1359
|
isVideoMesh: true,
|
|
586
1360
|
});
|
|
587
1361
|
|
|
588
|
-
assert.
|
|
1362
|
+
assert.calledOnce(mockClusterReachabilityInstances['cluster 1'].start);
|
|
1363
|
+
assert.calledOnce(mockClusterReachabilityInstances['cluster 2'].start);
|
|
589
1364
|
});
|
|
590
1365
|
|
|
591
1366
|
it('does not do TCP reachability if it is disabled in config', async () => {
|
|
@@ -610,13 +1385,9 @@ describe('gatherReachability', () => {
|
|
|
610
1385
|
|
|
611
1386
|
reachability.reachabilityRequest.getClusters = sinon.stub().returns(getClustersResult);
|
|
612
1387
|
|
|
613
|
-
const
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
start: sinon.stub().resolves({}),
|
|
617
|
-
}));
|
|
618
|
-
|
|
619
|
-
await reachability.gatherReachability();
|
|
1388
|
+
const promise = reachability.gatherReachability();
|
|
1389
|
+
await simulateTimeout();
|
|
1390
|
+
await promise;
|
|
620
1391
|
|
|
621
1392
|
assert.calledOnceWithExactly(clusterReachabilityCtorStub, 'cluster name', {
|
|
622
1393
|
isVideoMesh: false,
|
|
@@ -648,13 +1419,10 @@ describe('gatherReachability', () => {
|
|
|
648
1419
|
|
|
649
1420
|
reachability.reachabilityRequest.getClusters = sinon.stub().returns(getClustersResult);
|
|
650
1421
|
|
|
651
|
-
const
|
|
652
|
-
.stub(ClusterReachabilityModule, 'ClusterReachability')
|
|
653
|
-
.callsFake(() => ({
|
|
654
|
-
start: sinon.stub().resolves({}),
|
|
655
|
-
}));
|
|
1422
|
+
const promise = reachability.gatherReachability();
|
|
656
1423
|
|
|
657
|
-
await
|
|
1424
|
+
await simulateTimeout();
|
|
1425
|
+
await promise;
|
|
658
1426
|
|
|
659
1427
|
assert.calledOnceWithExactly(clusterReachabilityCtorStub, 'cluster name', {
|
|
660
1428
|
isVideoMesh: false,
|
|
@@ -686,13 +1454,10 @@ describe('gatherReachability', () => {
|
|
|
686
1454
|
|
|
687
1455
|
reachability.reachabilityRequest.getClusters = sinon.stub().returns(getClustersResult);
|
|
688
1456
|
|
|
689
|
-
const
|
|
690
|
-
.stub(ClusterReachabilityModule, 'ClusterReachability')
|
|
691
|
-
.callsFake(() => ({
|
|
692
|
-
start: sinon.stub().resolves({}),
|
|
693
|
-
}));
|
|
1457
|
+
const promise = reachability.gatherReachability();
|
|
694
1458
|
|
|
695
|
-
await
|
|
1459
|
+
await simulateTimeout();
|
|
1460
|
+
await promise;
|
|
696
1461
|
|
|
697
1462
|
assert.calledOnceWithExactly(clusterReachabilityCtorStub, 'cluster name', {
|
|
698
1463
|
isVideoMesh: false,
|
|
@@ -1033,3 +1798,307 @@ describe('getReachabilityMetrics', () => {
|
|
|
1033
1798
|
);
|
|
1034
1799
|
});
|
|
1035
1800
|
});
|
|
1801
|
+
|
|
1802
|
+
class TestReachability extends Reachability {
|
|
1803
|
+
constructor(webex: object) {
|
|
1804
|
+
super(webex);
|
|
1805
|
+
}
|
|
1806
|
+
|
|
1807
|
+
public testGetStatistics(
|
|
1808
|
+
results: Array<ClusterReachabilityModule.ClusterReachabilityResult & {isVideoMesh: boolean}>,
|
|
1809
|
+
protocol: 'udp' | 'tcp' | 'xtls',
|
|
1810
|
+
isVideoMesh: boolean
|
|
1811
|
+
) {
|
|
1812
|
+
return this.getStatistics(results, protocol, isVideoMesh);
|
|
1813
|
+
}
|
|
1814
|
+
|
|
1815
|
+
public testSendMetric() {
|
|
1816
|
+
return this.sendMetric();
|
|
1817
|
+
}
|
|
1818
|
+
|
|
1819
|
+
public setFakeClusterReachability(fakeClusterReachability) {
|
|
1820
|
+
this.clusterReachability = fakeClusterReachability;
|
|
1821
|
+
}
|
|
1822
|
+
}
|
|
1823
|
+
|
|
1824
|
+
describe('getStatistics', () => {
|
|
1825
|
+
let webex;
|
|
1826
|
+
let reachability;
|
|
1827
|
+
|
|
1828
|
+
beforeEach(() => {
|
|
1829
|
+
webex = new MockWebex();
|
|
1830
|
+
reachability = new TestReachability(webex);
|
|
1831
|
+
});
|
|
1832
|
+
|
|
1833
|
+
it('takes values from the correct protocol', () => {
|
|
1834
|
+
const results = [
|
|
1835
|
+
{
|
|
1836
|
+
udp: {
|
|
1837
|
+
result: 'reachable',
|
|
1838
|
+
latencyInMilliseconds: 10,
|
|
1839
|
+
},
|
|
1840
|
+
tcp: {
|
|
1841
|
+
result: 'reachable',
|
|
1842
|
+
latencyInMilliseconds: 1010,
|
|
1843
|
+
},
|
|
1844
|
+
xtls: {
|
|
1845
|
+
result: 'reachable',
|
|
1846
|
+
latencyInMilliseconds: 2010,
|
|
1847
|
+
},
|
|
1848
|
+
isVideoMesh: false,
|
|
1849
|
+
},
|
|
1850
|
+
{
|
|
1851
|
+
udp: {
|
|
1852
|
+
result: 'reachable',
|
|
1853
|
+
latencyInMilliseconds: 20,
|
|
1854
|
+
},
|
|
1855
|
+
tcp: {
|
|
1856
|
+
result: 'reachable',
|
|
1857
|
+
latencyInMilliseconds: 1020,
|
|
1858
|
+
},
|
|
1859
|
+
xtls: {
|
|
1860
|
+
result: 'reachable',
|
|
1861
|
+
latencyInMilliseconds: 2020,
|
|
1862
|
+
},
|
|
1863
|
+
isVideoMesh: false,
|
|
1864
|
+
},
|
|
1865
|
+
{
|
|
1866
|
+
udp: {
|
|
1867
|
+
result: 'reachable',
|
|
1868
|
+
latencyInMilliseconds: 30,
|
|
1869
|
+
},
|
|
1870
|
+
tcp: {
|
|
1871
|
+
result: 'reachable',
|
|
1872
|
+
latencyInMilliseconds: 1030,
|
|
1873
|
+
},
|
|
1874
|
+
xtls: {
|
|
1875
|
+
result: 'reachable',
|
|
1876
|
+
latencyInMilliseconds: 2030,
|
|
1877
|
+
},
|
|
1878
|
+
isVideoMesh: false,
|
|
1879
|
+
},
|
|
1880
|
+
];
|
|
1881
|
+
|
|
1882
|
+
assert.deepEqual(reachability.testGetStatistics(results, 'udp', false), {
|
|
1883
|
+
min: 10,
|
|
1884
|
+
max: 30,
|
|
1885
|
+
average: 20,
|
|
1886
|
+
});
|
|
1887
|
+
assert.deepEqual(reachability.testGetStatistics(results, 'tcp', false), {
|
|
1888
|
+
min: 1010,
|
|
1889
|
+
max: 1030,
|
|
1890
|
+
average: 1020,
|
|
1891
|
+
});
|
|
1892
|
+
assert.deepEqual(reachability.testGetStatistics(results, 'xtls', false), {
|
|
1893
|
+
min: 2010,
|
|
1894
|
+
max: 2030,
|
|
1895
|
+
average: 2020,
|
|
1896
|
+
});
|
|
1897
|
+
});
|
|
1898
|
+
|
|
1899
|
+
it('filters based on isVideoMesh value', () => {
|
|
1900
|
+
const results = [
|
|
1901
|
+
{
|
|
1902
|
+
udp: {
|
|
1903
|
+
result: 'reachable',
|
|
1904
|
+
latencyInMilliseconds: 10,
|
|
1905
|
+
},
|
|
1906
|
+
isVideoMesh: true,
|
|
1907
|
+
},
|
|
1908
|
+
{
|
|
1909
|
+
udp: {
|
|
1910
|
+
result: 'reachable',
|
|
1911
|
+
latencyInMilliseconds: 20,
|
|
1912
|
+
},
|
|
1913
|
+
isVideoMesh: true,
|
|
1914
|
+
},
|
|
1915
|
+
{
|
|
1916
|
+
udp: {
|
|
1917
|
+
result: 'reachable',
|
|
1918
|
+
latencyInMilliseconds: 30,
|
|
1919
|
+
},
|
|
1920
|
+
isVideoMesh: true,
|
|
1921
|
+
},
|
|
1922
|
+
{
|
|
1923
|
+
udp: {
|
|
1924
|
+
result: 'reachable',
|
|
1925
|
+
latencyInMilliseconds: 100,
|
|
1926
|
+
},
|
|
1927
|
+
isVideoMesh: false,
|
|
1928
|
+
},
|
|
1929
|
+
{
|
|
1930
|
+
udp: {
|
|
1931
|
+
result: 'reachable',
|
|
1932
|
+
latencyInMilliseconds: 200,
|
|
1933
|
+
},
|
|
1934
|
+
isVideoMesh: false,
|
|
1935
|
+
},
|
|
1936
|
+
];
|
|
1937
|
+
|
|
1938
|
+
assert.deepEqual(reachability.testGetStatistics(results, 'udp', true), {
|
|
1939
|
+
min: 10,
|
|
1940
|
+
max: 30,
|
|
1941
|
+
average: 20,
|
|
1942
|
+
});
|
|
1943
|
+
assert.deepEqual(reachability.testGetStatistics(results, 'udp', false), {
|
|
1944
|
+
min: 100,
|
|
1945
|
+
max: 200,
|
|
1946
|
+
average: 150,
|
|
1947
|
+
});
|
|
1948
|
+
});
|
|
1949
|
+
|
|
1950
|
+
it('only takes into account "reachable" results', () => {
|
|
1951
|
+
const results = [
|
|
1952
|
+
{
|
|
1953
|
+
udp: {
|
|
1954
|
+
result: 'reachable',
|
|
1955
|
+
latencyInMilliseconds: 10,
|
|
1956
|
+
},
|
|
1957
|
+
isVideoMesh: false,
|
|
1958
|
+
},
|
|
1959
|
+
{
|
|
1960
|
+
udp: {
|
|
1961
|
+
result: 'unreachable',
|
|
1962
|
+
latencyInMilliseconds: 100, // value put in here just for testing, in practice we wouldn't have any value here if it was unreachable
|
|
1963
|
+
},
|
|
1964
|
+
isVideoMesh: false,
|
|
1965
|
+
},
|
|
1966
|
+
{
|
|
1967
|
+
udp: {
|
|
1968
|
+
result: 'reachable',
|
|
1969
|
+
latencyInMilliseconds: 20,
|
|
1970
|
+
},
|
|
1971
|
+
isVideoMesh: false,
|
|
1972
|
+
},
|
|
1973
|
+
{
|
|
1974
|
+
udp: {
|
|
1975
|
+
result: 'untested',
|
|
1976
|
+
latencyInMilliseconds: 200, // value put in here just for testing, in practice we wouldn't have any value here if it was untested
|
|
1977
|
+
},
|
|
1978
|
+
isVideoMesh: false,
|
|
1979
|
+
},
|
|
1980
|
+
];
|
|
1981
|
+
|
|
1982
|
+
assert.deepEqual(reachability.testGetStatistics(results, 'udp', false), {
|
|
1983
|
+
min: 10,
|
|
1984
|
+
max: 20,
|
|
1985
|
+
average: 15,
|
|
1986
|
+
});
|
|
1987
|
+
});
|
|
1988
|
+
|
|
1989
|
+
it('handles the case when results are empty', () => {
|
|
1990
|
+
assert.deepEqual(reachability.testGetStatistics([], 'udp', false), {
|
|
1991
|
+
min: -1,
|
|
1992
|
+
max: -1,
|
|
1993
|
+
average: -1,
|
|
1994
|
+
});
|
|
1995
|
+
});
|
|
1996
|
+
|
|
1997
|
+
it('handles the case when results are empty after filtering', () => {
|
|
1998
|
+
const fakeResults = [
|
|
1999
|
+
{
|
|
2000
|
+
udp: {
|
|
2001
|
+
result: 'untested', // it will get filtered out because of this value
|
|
2002
|
+
latencyInMilliseconds: 10,
|
|
2003
|
+
},
|
|
2004
|
+
tcp: {
|
|
2005
|
+
result: 'reachable',
|
|
2006
|
+
latencyInMilliseconds: 10, // it will get filtered out because of the tcp protocol
|
|
2007
|
+
},
|
|
2008
|
+
isVideoMesh: false,
|
|
2009
|
+
},
|
|
2010
|
+
{
|
|
2011
|
+
udp: {
|
|
2012
|
+
result: 'reachable',
|
|
2013
|
+
latencyInMilliseconds: 10,
|
|
2014
|
+
},
|
|
2015
|
+
isVideoMesh: true, // it will get filtered out because of this value
|
|
2016
|
+
},
|
|
2017
|
+
];
|
|
2018
|
+
|
|
2019
|
+
assert.deepEqual(reachability.testGetStatistics(fakeResults, 'udp', false), {
|
|
2020
|
+
min: -1,
|
|
2021
|
+
max: -1,
|
|
2022
|
+
average: -1,
|
|
2023
|
+
});
|
|
2024
|
+
});
|
|
2025
|
+
});
|
|
2026
|
+
|
|
2027
|
+
describe('sendMetric', () => {
|
|
2028
|
+
let webex;
|
|
2029
|
+
let reachability;
|
|
2030
|
+
|
|
2031
|
+
beforeEach(() => {
|
|
2032
|
+
webex = new MockWebex();
|
|
2033
|
+
reachability = new TestReachability(webex);
|
|
2034
|
+
|
|
2035
|
+
sinon.stub(Metrics, 'sendBehavioralMetric');
|
|
2036
|
+
});
|
|
2037
|
+
|
|
2038
|
+
it('works as expected', async () => {
|
|
2039
|
+
// setup stub for getStatistics to return values that show what parameters it was called with,
|
|
2040
|
+
// this way we can verify that the correct results of calls to getStatistics are placed
|
|
2041
|
+
// in correct data fields when sendBehavioralMetric() is called
|
|
2042
|
+
const getStatisticsStub = sinon
|
|
2043
|
+
.stub(reachability, 'getStatistics')
|
|
2044
|
+
.callsFake((results, protocol, isVideoMesh) => {
|
|
2045
|
+
return {result: 'fake', protocol, isVideoMesh};
|
|
2046
|
+
});
|
|
2047
|
+
|
|
2048
|
+
// setup fake clusterReachability results
|
|
2049
|
+
reachability.setFakeClusterReachability({
|
|
2050
|
+
cluster1: {
|
|
2051
|
+
getResult: sinon.stub().returns({result: 'result 1'}),
|
|
2052
|
+
isVideoMesh: true,
|
|
2053
|
+
},
|
|
2054
|
+
cluster2: {
|
|
2055
|
+
getResult: sinon.stub().returns({result: 'result 2'}),
|
|
2056
|
+
isVideoMesh: false,
|
|
2057
|
+
},
|
|
2058
|
+
cluster3: {
|
|
2059
|
+
getResult: sinon.stub().returns({result: 'result 3'}),
|
|
2060
|
+
isVideoMesh: false,
|
|
2061
|
+
},
|
|
2062
|
+
});
|
|
2063
|
+
|
|
2064
|
+
await reachability.sendMetric();
|
|
2065
|
+
|
|
2066
|
+
// each call to getStatistics should be made with all the results from all fake clusterReachability:
|
|
2067
|
+
const expectedResults = [
|
|
2068
|
+
{
|
|
2069
|
+
result: 'result 1',
|
|
2070
|
+
isVideoMesh: true,
|
|
2071
|
+
},
|
|
2072
|
+
{
|
|
2073
|
+
result: 'result 2',
|
|
2074
|
+
isVideoMesh: false,
|
|
2075
|
+
},
|
|
2076
|
+
{
|
|
2077
|
+
result: 'result 3',
|
|
2078
|
+
isVideoMesh: false,
|
|
2079
|
+
},
|
|
2080
|
+
];
|
|
2081
|
+
|
|
2082
|
+
// check that getStatistics is called 4 times and each time with all the results
|
|
2083
|
+
assert.callCount(getStatisticsStub, 4);
|
|
2084
|
+
assert.alwaysCalledWith(getStatisticsStub, expectedResults, sinon.match.any, sinon.match.any);
|
|
2085
|
+
|
|
2086
|
+
assert.calledWith(Metrics.sendBehavioralMetric, 'js_sdk_reachability_completed', {
|
|
2087
|
+
vmn_udp_result: 'fake',
|
|
2088
|
+
vmn_udp_protocol: 'udp',
|
|
2089
|
+
vmn_udp_isVideoMesh: true,
|
|
2090
|
+
|
|
2091
|
+
public_udp_result: 'fake',
|
|
2092
|
+
public_udp_protocol: 'udp',
|
|
2093
|
+
public_udp_isVideoMesh: false,
|
|
2094
|
+
|
|
2095
|
+
public_tcp_result: 'fake',
|
|
2096
|
+
public_tcp_protocol: 'tcp',
|
|
2097
|
+
public_tcp_isVideoMesh: false,
|
|
2098
|
+
|
|
2099
|
+
public_xtls_result: 'fake',
|
|
2100
|
+
public_xtls_protocol: 'xtls',
|
|
2101
|
+
public_xtls_isVideoMesh: false,
|
|
2102
|
+
});
|
|
2103
|
+
});
|
|
2104
|
+
});
|