@webex/plugin-meetings 1.149.2 → 1.151.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.
@@ -1,7 +1,7 @@
1
1
  /*!
2
2
  * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
3
  */
4
-
4
+ import {cloneDeep, isEqual} from 'lodash';
5
5
  import sinon from 'sinon';
6
6
  import StateMachine from 'javascript-state-machine';
7
7
  import uuid from 'uuid';
@@ -27,6 +27,13 @@ import LoggerConfig from '@webex/plugin-meetings/src/common/logs/logger-config';
27
27
  import TriggerProxy from '@webex/plugin-meetings/src/common/events/trigger-proxy';
28
28
  import BrowserDetection from '@webex/plugin-meetings/src/common/browser-detection';
29
29
  import Metrics from '@webex/plugin-meetings/src/metrics';
30
+ import {
31
+ FLOOR_ACTION,
32
+ SHARE_STATUS,
33
+ METRICS_OPERATIONAL_MEASURES,
34
+ EVENTS,
35
+ EVENT_TRIGGERS
36
+ } from '@webex/plugin-meetings/src/constants';
30
37
 
31
38
  import {
32
39
  UserNotJoinedError,
@@ -35,7 +42,6 @@ import {
35
42
  NoMediaEstablishedYetError
36
43
  } from '../../../../src/common/errors/webex-errors';
37
44
  import WebExMeetingsErrors from '../../../../src/common/errors/webex-meetings-error';
38
- import {METRICS_OPERATIONAL_MEASURES, EVENTS, EVENT_TRIGGERS} from '../../../../src/constants';
39
45
  import ParameterError from '../../../../src/common/errors/parameter';
40
46
  import DefaultSDKConfig from '../../../../src/config';
41
47
  import testUtils from '../../../utils/testUtils';
@@ -104,7 +110,6 @@ describe('plugin-meetings', () => {
104
110
 
105
111
 
106
112
  TriggerProxy.trigger = sinon.stub().returns(true);
107
- Metrics.initPayload = sinon.stub();
108
113
  Metrics.postEvent = sinon.stub();
109
114
  Metrics.initialSetup(null, webex);
110
115
  MediaUtil.createPeerConnection = sinon.stub().returns({});
@@ -2571,6 +2576,545 @@ describe('plugin-meetings', () => {
2571
2576
  });
2572
2577
  });
2573
2578
  });
2579
+
2580
+ describe('whiteboard share', () => {
2581
+ describe('#startWhiteboardShare', () => {
2582
+ beforeEach(() => {
2583
+ meeting.locusInfo.mediaShares = [{name: 'whiteboard', url: url1}];
2584
+ meeting.locusInfo.self = {url: url1};
2585
+ meeting.meetingRequest.changeMeetingFloor = sinon.stub().returns(Promise.resolve());
2586
+ });
2587
+ it('should have #startWhiteboardShare', () => {
2588
+ assert.exists(meeting.startWhiteboardShare);
2589
+ });
2590
+ it('should send the whiteboard share', async () => {
2591
+ const whiteboardShare = meeting.startWhiteboardShare({
2592
+ channelUrl: url2
2593
+ });
2594
+
2595
+ assert.exists(whiteboardShare.then);
2596
+ await whiteboardShare;
2597
+ assert.calledOnce(meeting.meetingRequest.changeMeetingFloor);
2598
+ });
2599
+ });
2600
+ describe('#stopWhiteboardShare', () => {
2601
+ it('should have #stopWhiteboardShare', () => {
2602
+ assert.exists(meeting.stopWhiteboardShare);
2603
+ });
2604
+ beforeEach(() => {
2605
+ meeting.locusInfo.mediaShares = [{name: 'whiteboard', url: url1}];
2606
+ meeting.locusInfo.self = {url: url1};
2607
+ meeting.meetingRequest.changeMeetingFloor = sinon.stub().returns(Promise.resolve());
2608
+ });
2609
+ it('should stop the whiteboard share', async () => {
2610
+ const whiteboardShare = meeting.stopWhiteboardShare();
2611
+
2612
+ assert.exists(whiteboardShare.then);
2613
+ await whiteboardShare;
2614
+ assert.calledOnce(meeting.meetingRequest.changeMeetingFloor);
2615
+ });
2616
+ });
2617
+ });
2618
+ describe('share scenarios', () => {
2619
+ describe('setUpLocusMediaSharesListener', () => {
2620
+ beforeEach(() => {
2621
+ meeting.selfId = '9528d952-e4de-46cf-8157-fd4823b98377';
2622
+ sinon.stub(meeting, 'updateShare').returns(Promise.resolve());
2623
+ });
2624
+
2625
+ afterEach(() => {
2626
+ meeting.updateShare.restore();
2627
+ });
2628
+
2629
+ const USER_IDS = {
2630
+ ME: '9528d952-e4de-46cf-8157-fd4823b98377',
2631
+ REMOTE_A: '5be7e7b0-b304-48da-8083-83bd72b5300d',
2632
+ REMOTE_B: 'd4d102a1-17ce-4e17-9b08-bded3de467e4'
2633
+ };
2634
+
2635
+ const RESOURCE_URLS = {
2636
+ WHITEBOARD_A: 'https://board-a.wbx2.com/board/api/v1/channels/49cfb550-5517-11eb-a2af-1b9e4bc3da13',
2637
+ WHITEBOARD_B: 'https://board-a.wbx2.com/board/api/v1/channels/977a7330-54f4-11eb-b1ef-91f5eefc7bf3'
2638
+ };
2639
+
2640
+ const generateContent = (beneficiaryId = null, disposition = null) => ({beneficiaryId, disposition});
2641
+ const generateWhiteboard = (beneficiaryId = null, disposition = null, resourceUrl = null) => ({beneficiaryId, disposition, resourceUrl});
2642
+
2643
+ const generateData = (payload, isGranting, isContent, beneficiaryId, resourceUrl, isAccepting, otherBeneficiaryId) => {
2644
+ const newPayload = cloneDeep(payload);
2645
+
2646
+ newPayload.previous = cloneDeep(payload.current);
2647
+
2648
+ const eventTrigger = {
2649
+ share: [],
2650
+ member: {
2651
+ eventName: EVENT_TRIGGERS.MEMBERS_CONTENT_UPDATE,
2652
+ eventPayload: {
2653
+ activeSharingId: null,
2654
+ endedSharingId: null
2655
+ }
2656
+ }
2657
+ };
2658
+
2659
+ let shareStatus = null;
2660
+ const activeSharingId = {
2661
+ whiteboard: null,
2662
+ content: null
2663
+ };
2664
+
2665
+ if (isGranting) {
2666
+ if (isContent) {
2667
+ activeSharingId.content = beneficiaryId;
2668
+ newPayload.current.content = generateContent(beneficiaryId, FLOOR_ACTION.GRANTED);
2669
+
2670
+ if (isEqual(newPayload.current, newPayload.previous)) {
2671
+ eventTrigger.member = null;
2672
+ }
2673
+ else {
2674
+ if (newPayload.current.whiteboard.beneficiaryId) {
2675
+ if (newPayload.current.whiteboard.disposition === FLOOR_ACTION.GRANTED) {
2676
+ newPayload.current.whiteboard.disposition = FLOOR_ACTION.RELEASED;
2677
+ eventTrigger.share.push({
2678
+ eventName: EVENT_TRIGGERS.MEETING_STOPPED_SHARING_WHITEBOARD,
2679
+ functionName: 'stopWhiteboardShare'
2680
+ });
2681
+ eventTrigger.member.eventPayload.endedSharingId = newPayload.current.whiteboard.beneficiaryId;
2682
+ }
2683
+ }
2684
+
2685
+ if (newPayload.previous.content.beneficiaryId) {
2686
+ if (newPayload.previous.content.beneficiaryId !== newPayload.current.content.beneficiaryId) {
2687
+ if (newPayload.previous.content.beneficiaryId === USER_IDS.ME) {
2688
+ eventTrigger.share.push({
2689
+ eventName: EVENT_TRIGGERS.MEETING_STOPPED_SHARING_LOCAL,
2690
+ functionName: 'stopFloorRequest'
2691
+ });
2692
+ }
2693
+ else if (newPayload.current.content.beneficiaryId === USER_IDS.ME) {
2694
+ eventTrigger.share.push({
2695
+ eventName: EVENT_TRIGGERS.MEETING_STOPPED_SHARING_REMOTE,
2696
+ functionName: 'remoteShare'
2697
+ });
2698
+ }
2699
+ eventTrigger.member.eventPayload.endedSharingId = newPayload.previous.content.beneficiaryId;
2700
+ }
2701
+ }
2702
+
2703
+ if (isAccepting) {
2704
+ eventTrigger.share.push({
2705
+ eventName: EVENT_TRIGGERS.MEETING_STOPPED_SHARING_WHITEBOARD,
2706
+ functionName: 'stopWhiteboardShare'
2707
+ });
2708
+ }
2709
+
2710
+ if (beneficiaryId === USER_IDS.ME) {
2711
+ eventTrigger.share.push({
2712
+ eventName: EVENT_TRIGGERS.MEETING_STARTED_SHARING_LOCAL,
2713
+ functionName: 'share'
2714
+ });
2715
+ }
2716
+ else {
2717
+ eventTrigger.share.push({
2718
+ eventName: EVENT_TRIGGERS.MEETING_STARTED_SHARING_REMOTE,
2719
+ functionName: 'remoteShare',
2720
+ eventPayload: {memberId: beneficiaryId}
2721
+ });
2722
+ }
2723
+ }
2724
+
2725
+ if (beneficiaryId === USER_IDS.ME) {
2726
+ shareStatus = SHARE_STATUS.LOCAL_SHARE_ACTIVE;
2727
+ }
2728
+ else {
2729
+ shareStatus = SHARE_STATUS.REMOTE_SHARE_ACTIVE;
2730
+ }
2731
+ }
2732
+ else {
2733
+ newPayload.current.whiteboard = generateWhiteboard(beneficiaryId, FLOOR_ACTION.GRANTED, resourceUrl);
2734
+
2735
+ if (newPayload.current.content.beneficiaryId) {
2736
+ if (newPayload.current.content.disposition === FLOOR_ACTION.GRANTED) {
2737
+ newPayload.current.content.disposition = FLOOR_ACTION.RELEASED;
2738
+ if (newPayload.current.content.beneficiaryId === USER_IDS.ME) {
2739
+ eventTrigger.share.push({
2740
+ eventName: EVENT_TRIGGERS.MEETING_STOPPED_SHARING_LOCAL,
2741
+ functionName: 'stopFloorRequest'
2742
+ });
2743
+ }
2744
+ else {
2745
+ eventTrigger.share.push({
2746
+ eventName: EVENT_TRIGGERS.MEETING_STOPPED_SHARING_REMOTE,
2747
+ functionName: 'remoteShare'
2748
+ });
2749
+ }
2750
+
2751
+ eventTrigger.member.eventPayload.endedSharingId = newPayload.current.content.beneficiaryId;
2752
+ }
2753
+ }
2754
+
2755
+ if (newPayload.previous.content.beneficiaryId) {
2756
+ if (newPayload.previous.content.beneficiaryId !== newPayload.current.content.beneficiaryId) {
2757
+ if (newPayload.previous.content.beneficiaryId === USER_IDS.ME) {
2758
+ eventTrigger.share.push({
2759
+ eventName: EVENT_TRIGGERS.MEETING_STOPPED_SHARING_LOCAL,
2760
+ functionName: 'stopFloorRequest'
2761
+ });
2762
+ }
2763
+ else if (newPayload.current.content.beneficiaryId === USER_IDS.ME) {
2764
+ eventTrigger.share.push({
2765
+ eventName: EVENT_TRIGGERS.MEETING_STOPPED_SHARING_REMOTE,
2766
+ functionName: 'remoteShare'
2767
+ });
2768
+ }
2769
+ eventTrigger.member.eventPayload.endedSharingId = newPayload.previous.content.beneficiaryId;
2770
+ }
2771
+ }
2772
+
2773
+ if (newPayload.previous.whiteboard.beneficiaryId) {
2774
+ if (newPayload.previous.whiteboard.beneficiaryId !== newPayload.current.whiteboard.beneficiaryId) {
2775
+ eventTrigger.member.eventPayload.endedSharingId = newPayload.previous.whiteboard.beneficiaryId;
2776
+ }
2777
+ }
2778
+
2779
+ activeSharingId.whiteboard = beneficiaryId;
2780
+
2781
+ eventTrigger.share.push({
2782
+ eventName: EVENT_TRIGGERS.MEETING_STARTED_SHARING_WHITEBOARD,
2783
+ functionName: 'startWhiteboardShare',
2784
+ eventPayload: {resourceUrl, memberId: beneficiaryId}
2785
+ });
2786
+
2787
+ shareStatus = SHARE_STATUS.WHITEBOARD_SHARE_ACTIVE;
2788
+ }
2789
+
2790
+ if (eventTrigger.member) {
2791
+ eventTrigger.member.eventPayload.activeSharingId = beneficiaryId;
2792
+ }
2793
+ }
2794
+ else {
2795
+ eventTrigger.member.eventPayload.endedSharingId = beneficiaryId;
2796
+
2797
+ if (isContent) {
2798
+ newPayload.current.content.disposition = FLOOR_ACTION.RELEASED;
2799
+
2800
+ if (beneficiaryId === USER_IDS.ME) {
2801
+ eventTrigger.share.push({
2802
+ eventName: EVENT_TRIGGERS.MEETING_STOPPED_SHARING_LOCAL,
2803
+ functionName: 'stopFloorRequest'
2804
+ });
2805
+ }
2806
+ else {
2807
+ eventTrigger.share.push({
2808
+ eventName: EVENT_TRIGGERS.MEETING_STOPPED_SHARING_REMOTE,
2809
+ functionName: 'remoteShare'
2810
+ });
2811
+ }
2812
+
2813
+ shareStatus = SHARE_STATUS.NO_SHARE;
2814
+ }
2815
+ else {
2816
+ newPayload.current.whiteboard.disposition = FLOOR_ACTION.RELEASED;
2817
+
2818
+ if (isAccepting) {
2819
+ newPayload.current.content.disposition = FLOOR_ACTION.ACCEPTED;
2820
+ newPayload.current.content.beneficiaryId = otherBeneficiaryId;
2821
+
2822
+ eventTrigger.share.push({
2823
+ eventName: EVENT_TRIGGERS.MEETING_STARTED_SHARING_WHITEBOARD,
2824
+ functionName: 'startWhiteboardShare',
2825
+ eventPayload: {resourceUrl, memberId: beneficiaryId}
2826
+ });
2827
+
2828
+ shareStatus = SHARE_STATUS.WHITEBOARD_SHARE_ACTIVE;
2829
+ }
2830
+ else {
2831
+ eventTrigger.share.push({
2832
+ eventName: EVENT_TRIGGERS.MEETING_STOPPED_SHARING_WHITEBOARD,
2833
+ functionName: 'stopWhiteboardShare'
2834
+ });
2835
+
2836
+ shareStatus = SHARE_STATUS.NO_SHARE;
2837
+ }
2838
+ }
2839
+ }
2840
+
2841
+ return {
2842
+ payload: newPayload, eventTrigger, shareStatus, activeSharingId
2843
+ };
2844
+ };
2845
+
2846
+ const blankPayload = {
2847
+ previous: {
2848
+ content: generateContent(),
2849
+ whiteboard: generateWhiteboard()
2850
+ },
2851
+ current: {
2852
+ content: generateContent(),
2853
+ whiteboard: generateWhiteboard()
2854
+ }
2855
+ };
2856
+
2857
+
2858
+ const payloadTestHelper = (data) => {
2859
+ assert.equal(meeting.shareStatus, SHARE_STATUS.NO_SHARE);
2860
+
2861
+ // Called once --> members:update (ignore)
2862
+ let callCounter = 1;
2863
+
2864
+ data.forEach((d, index) => {
2865
+ meeting.locusInfo.emit({function: 'test', file: 'test'}, EVENTS.LOCUS_INFO_UPDATE_MEDIA_SHARES, d.payload);
2866
+
2867
+ assert.equal(meeting.shareStatus, data[index].shareStatus);
2868
+
2869
+ callCounter += data[index].eventTrigger.share.length + (data[index].eventTrigger.member ? 1 : 0);
2870
+
2871
+ assert.callCount(TriggerProxy.trigger, callCounter);
2872
+
2873
+ assert.equal(meeting.members.mediaShareWhiteboardId, data[index].activeSharingId.whiteboard);
2874
+ assert.equal(meeting.members.mediaShareContentId, data[index].activeSharingId.content);
2875
+ });
2876
+
2877
+ assert.callCount(TriggerProxy.trigger, callCounter);
2878
+
2879
+ // Start with 1 to ignore members:update trigger
2880
+
2881
+
2882
+ let i = 1;
2883
+ let offset = 2;
2884
+
2885
+ while (i < callCounter) {
2886
+ const index = Math.floor(i / offset);
2887
+
2888
+ const {share, member} = data[index].eventTrigger;
2889
+
2890
+ for (let idx = 0; idx < share.length; idx += 1) {
2891
+ const shareCallArgs = TriggerProxy.trigger.getCall(i + idx).args;
2892
+ const {functionName, eventName, eventPayload} = share[idx];
2893
+ const fileName = functionName === 'remoteShare' ? 'meetings/index' : 'meeting/index';
2894
+
2895
+ assert.deepEqual(shareCallArgs[1], {
2896
+ file: fileName,
2897
+ function: functionName
2898
+ });
2899
+
2900
+
2901
+ assert.equal(shareCallArgs[2], eventName);
2902
+
2903
+ if (functionName === 'startWhiteboardShare') {
2904
+ assert.deepEqual(shareCallArgs[3], eventPayload);
2905
+ }
2906
+
2907
+ if (functionName === 'remoteShare' && eventName === EVENT_TRIGGERS.MEETING_STARTED_SHARING_REMOTE) {
2908
+ assert.deepEqual(shareCallArgs[3], eventPayload);
2909
+ }
2910
+ }
2911
+
2912
+ // Check Trigger --> members:content:update
2913
+ if (member) {
2914
+ const memberCallArgs = TriggerProxy.trigger.getCall(i + share.length).args;
2915
+
2916
+ assert.deepEqual(memberCallArgs[1], {
2917
+ file: 'members',
2918
+ function: 'locusMediaSharesUpdate'
2919
+ });
2920
+ assert.equal(memberCallArgs[2], member.eventName);
2921
+
2922
+ // Check payload --> {activeSharingId, endedSharingId}
2923
+ assert.deepEqual(memberCallArgs[3], member.eventPayload);
2924
+
2925
+ i += 1;
2926
+ }
2927
+
2928
+ i += share.length;
2929
+
2930
+ if (share.length + 1 > offset) {
2931
+ offset = (offset + share.length + 1) / 2;
2932
+ }
2933
+ else if (share.length + 1 < offset) {
2934
+ offset = (share.length + 1) + 0.5;
2935
+ }
2936
+ }
2937
+ };
2938
+
2939
+ it('should have #setUpLocusMediaSharesListener', () => {
2940
+ assert.exists(meeting.setUpLocusMediaSharesListener);
2941
+ });
2942
+
2943
+ describe('Whiteboard A --> Whiteboard B', () => {
2944
+ it('Scenario #1: you share both whiteboards', () => {
2945
+ const data1 = generateData(blankPayload, true, false, USER_IDS.ME, RESOURCE_URLS.WHITEBOARD_A);
2946
+ const data2 = generateData(data1.payload, true, false, USER_IDS.ME, RESOURCE_URLS.WHITEBOARD_B);
2947
+ const data3 = generateData(data2.payload, false, false, USER_IDS.ME);
2948
+
2949
+ payloadTestHelper([data1, data2, data3]);
2950
+ });
2951
+
2952
+ it('Scenario #2: you share whiteboard A and remote person A shares whiteboard B', () => {
2953
+ const data1 = generateData(blankPayload, true, false, USER_IDS.ME, RESOURCE_URLS.WHITEBOARD_A);
2954
+ const data2 = generateData(data1.payload, true, false, USER_IDS.REMOTE_A, RESOURCE_URLS.WHITEBOARD_B);
2955
+ const data3 = generateData(data2.payload, false, false, USER_IDS.REMOTE_A);
2956
+
2957
+ payloadTestHelper([data1, data2, data3]);
2958
+ });
2959
+
2960
+ it('Scenario #3: remote person A shares whiteboard A and you share whiteboard B', () => {
2961
+ const data1 = generateData(blankPayload, true, false, USER_IDS.REMOTE_A, RESOURCE_URLS.WHITEBOARD_A);
2962
+ const data2 = generateData(data1.payload, true, false, USER_IDS.ME, RESOURCE_URLS.WHITEBOARD_B);
2963
+ const data3 = generateData(data2.payload, false, false, USER_IDS.ME);
2964
+
2965
+ payloadTestHelper([data1, data2, data3]);
2966
+ });
2967
+
2968
+ it('Scenario #4: remote person A shares both whiteboards', () => {
2969
+ const data1 = generateData(blankPayload, true, false, USER_IDS.REMOTE_A, RESOURCE_URLS.WHITEBOARD_A);
2970
+ const data2 = generateData(data1.payload, true, false, USER_IDS.REMOTE_A, RESOURCE_URLS.WHITEBOARD_B);
2971
+ const data3 = generateData(data2.payload, false, false, USER_IDS.REMOTE_A);
2972
+
2973
+ payloadTestHelper([data1, data2, data3]);
2974
+ });
2975
+
2976
+ it('Scenario #5: remote person A shares whiteboard A and remote person B shares whiteboard B', () => {
2977
+ const data1 = generateData(blankPayload, true, false, USER_IDS.REMOTE_A, RESOURCE_URLS.WHITEBOARD_A);
2978
+ const data2 = generateData(data1.payload, true, false, USER_IDS.REMOTE_B, RESOURCE_URLS.WHITEBOARD_B);
2979
+ const data3 = generateData(data2.payload, false, false, USER_IDS.REMOTE_B);
2980
+
2981
+ payloadTestHelper([data1, data2, data3]);
2982
+ });
2983
+ });
2984
+
2985
+ describe('Whiteboard A --> Desktop', () => {
2986
+ it('Scenario #1: you share whiteboard and then share desktop', () => {
2987
+ const data1 = generateData(blankPayload, true, false, USER_IDS.ME, RESOURCE_URLS.WHITEBOARD_A);
2988
+ const data2 = generateData(data1.payload, false, false, USER_IDS.ME, RESOURCE_URLS.WHITEBOARD_A, true, USER_IDS.ME);
2989
+ const data3 = generateData(data2.payload, true, true, USER_IDS.ME, undefined, true, USER_IDS.ME);
2990
+ const data4 = generateData(data3.payload, false, true, USER_IDS.ME);
2991
+
2992
+ payloadTestHelper([data1, data2, data3, data4]);
2993
+ });
2994
+
2995
+ it('Scenario #2: you share whiteboard A and remote person A shares desktop', () => {
2996
+ const data1 = generateData(blankPayload, true, false, USER_IDS.ME, RESOURCE_URLS.WHITEBOARD_A);
2997
+ const data2 = generateData(data1.payload, false, false, USER_IDS.ME, RESOURCE_URLS.WHITEBOARD_A, true, USER_IDS.REMOTE_A);
2998
+ const data3 = generateData(data2.payload, true, true, USER_IDS.REMOTE_A, undefined, true, USER_IDS.ME);
2999
+ const data4 = generateData(data3.payload, false, true, USER_IDS.REMOTE_A);
3000
+
3001
+ payloadTestHelper([data1, data2, data3, data4]);
3002
+ });
3003
+
3004
+ it('Scenario #3: remote person A shares whiteboard and you share desktop', () => {
3005
+ const data1 = generateData(blankPayload, true, false, USER_IDS.REMOTE_A, RESOURCE_URLS.WHITEBOARD_A);
3006
+ const data2 = generateData(data1.payload, false, false, USER_IDS.REMOTE_A, RESOURCE_URLS.WHITEBOARD_A, true, USER_IDS.ME);
3007
+ const data3 = generateData(data2.payload, true, true, USER_IDS.ME, undefined, true, USER_IDS.REMOTE_A);
3008
+ const data4 = generateData(data3.payload, false, true, USER_IDS.ME);
3009
+
3010
+ payloadTestHelper([data1, data2, data3, data4]);
3011
+ });
3012
+
3013
+ it('Scenario #4: remote person A shares whiteboard and then shares desktop', () => {
3014
+ const data1 = generateData(blankPayload, true, false, USER_IDS.REMOTE_A, RESOURCE_URLS.WHITEBOARD_A);
3015
+ const data2 = generateData(data1.payload, false, false, USER_IDS.REMOTE_A, RESOURCE_URLS.WHITEBOARD_A, true, USER_IDS.REMOTE_A);
3016
+ const data3 = generateData(data2.payload, true, true, USER_IDS.REMOTE_A, undefined, true, USER_IDS.REMOTE_A);
3017
+ const data4 = generateData(data3.payload, false, true, USER_IDS.REMOTE_A);
3018
+
3019
+ payloadTestHelper([data1, data2, data3, data4]);
3020
+ });
3021
+
3022
+ it('Scenario #5: remote person A shares whiteboard and remote person B shares desktop', () => {
3023
+ const data1 = generateData(blankPayload, true, false, USER_IDS.REMOTE_A, RESOURCE_URLS.WHITEBOARD_A);
3024
+ const data2 = generateData(data1.payload, false, false, USER_IDS.REMOTE_A, RESOURCE_URLS.WHITEBOARD_A, true, USER_IDS.REMOTE_B);
3025
+ const data3 = generateData(data2.payload, true, true, USER_IDS.REMOTE_B, undefined, true, USER_IDS.REMOTE_A);
3026
+ const data4 = generateData(data3.payload, false, true, USER_IDS.REMOTE_B);
3027
+
3028
+ payloadTestHelper([data1, data2, data3, data4]);
3029
+ });
3030
+ });
3031
+
3032
+ describe('Desktop --> Whiteboard A', () => {
3033
+ it('Scenario #1: you share desktop and then share whiteboard', () => {
3034
+ const data1 = generateData(blankPayload, true, true, USER_IDS.ME);
3035
+ const data2 = generateData(data1.payload, true, false, USER_IDS.ME, RESOURCE_URLS.WHITEBOARD_A);
3036
+ const data3 = generateData(data2.payload, false, false, USER_IDS.ME);
3037
+
3038
+ payloadTestHelper([data1, data2, data3]);
3039
+ });
3040
+
3041
+ it('Scenario #2: you share desktop and remote person A shares whiteboard', () => {
3042
+ const data1 = generateData(blankPayload, true, true, USER_IDS.ME);
3043
+ const data2 = generateData(data1.payload, true, false, USER_IDS.REMOTE_A, RESOURCE_URLS.WHITEBOARD_A);
3044
+ const data3 = generateData(data2.payload, false, false, USER_IDS.REMOTE_A);
3045
+
3046
+ payloadTestHelper([data1, data2, data3]);
3047
+ });
3048
+
3049
+ it('Scenario #3: remote person A shares desktop and you share whiteboard', () => {
3050
+ const data1 = generateData(blankPayload, true, true, USER_IDS.REMOTE_A);
3051
+ const data2 = generateData(data1.payload, true, false, USER_IDS.REMOTE_A, RESOURCE_URLS.WHITEBOARD_A);
3052
+ const data3 = generateData(data2.payload, false, false, USER_IDS.REMOTE_A);
3053
+
3054
+ payloadTestHelper([data1, data2, data3]);
3055
+ });
3056
+
3057
+ it('Scenario #4: remote person A shares desktop and then shares whiteboard', () => {
3058
+ const data1 = generateData(blankPayload, true, true, USER_IDS.REMOTE_A);
3059
+ const data2 = generateData(data1.payload, true, false, USER_IDS.ME, RESOURCE_URLS.WHITEBOARD_A);
3060
+ const data3 = generateData(data2.payload, false, false, USER_IDS.ME);
3061
+
3062
+ payloadTestHelper([data1, data2, data3]);
3063
+ });
3064
+
3065
+ it('Scenario #5: remote person A shares desktop and remote person B shares whiteboard', () => {
3066
+ const data1 = generateData(blankPayload, true, true, USER_IDS.REMOTE_A);
3067
+ const data2 = generateData(data1.payload, true, false, USER_IDS.REMOTE_A, RESOURCE_URLS.WHITEBOARD_A);
3068
+ const data3 = generateData(data2.payload, false, false, USER_IDS.REMOTE_A);
3069
+
3070
+ payloadTestHelper([data1, data2, data3]);
3071
+ });
3072
+ });
3073
+
3074
+ describe('Desktop A --> Desktop B', () => {
3075
+ it('Scenario #1: you share desktop A and then share desktop B', () => {
3076
+ const data1 = generateData(blankPayload, true, true, USER_IDS.ME);
3077
+ const data2 = generateData(data1.payload, false, true, USER_IDS.ME);
3078
+ const data3 = generateData(data2.payload, true, true, USER_IDS.ME);
3079
+ const data4 = generateData(data3.payload, false, true, USER_IDS.ME);
3080
+
3081
+ payloadTestHelper([data1, data2, data3, data4]);
3082
+ });
3083
+
3084
+ it('Scenario #2: you share desktop A and remote person A shares desktop B', () => {
3085
+ const data1 = generateData(blankPayload, true, true, USER_IDS.ME);
3086
+ const data2 = generateData(data1.payload, true, true, USER_IDS.REMOTE_A);
3087
+ const data3 = generateData(data2.payload, false, true, USER_IDS.REMOTE_A);
3088
+
3089
+ payloadTestHelper([data1, data2, data3]);
3090
+ });
3091
+
3092
+ it('Scenario #3: remote person A shares desktop A and you share desktop B', () => {
3093
+ const data1 = generateData(blankPayload, true, true, USER_IDS.REMOTE_A);
3094
+ const data2 = generateData(data1.payload, true, true, USER_IDS.ME);
3095
+ const data3 = generateData(data2.payload, false, true, USER_IDS.ME);
3096
+
3097
+ payloadTestHelper([data1, data2, data3]);
3098
+ });
3099
+
3100
+ it('Scenario #4: remote person A shares desktop A and then shares desktop B', () => {
3101
+ const data1 = generateData(blankPayload, true, true, USER_IDS.REMOTE_A);
3102
+ const data2 = generateData(data1.payload, true, true, USER_IDS.REMOTE_A);
3103
+ const data3 = generateData(data2.payload, false, true, USER_IDS.REMOTE_A);
3104
+
3105
+ payloadTestHelper([data1, data2, data3]);
3106
+ });
3107
+
3108
+ it('Scenario #5: remote person A shares desktop A and remote person B shares desktop B', () => {
3109
+ const data1 = generateData(blankPayload, true, true, USER_IDS.REMOTE_A);
3110
+ const data2 = generateData(data1.payload, true, true, USER_IDS.REMOTE_B);
3111
+ const data3 = generateData(data2.payload, false, true, USER_IDS.REMOTE_B);
3112
+
3113
+ payloadTestHelper([data1, data2, data3]);
3114
+ });
3115
+ });
3116
+ });
3117
+ });
2574
3118
  });
2575
3119
  });
2576
3120
  });
@@ -24,6 +24,14 @@ const {
24
24
  browserOnly(describe)('Meeting metrics', () => {
25
25
  let webex, mockSubmitMetric, sandbox;
26
26
 
27
+ const geoHintInfo = {
28
+ clientAddress: '2001:0db8:0000:08d3:0000:0000:0070:0000',
29
+ clientRegion: 'US-WEST',
30
+ countryCode: 'US',
31
+ regionCode: 'US-WEST',
32
+ timezone: 'America/Los_Angeles'
33
+ };
34
+
27
35
  beforeEach(() => {
28
36
  sandbox = sinon.createSandbox();
29
37
  mockSubmitMetric = sandbox.stub();
@@ -40,7 +48,6 @@ browserOnly(describe)('Meeting metrics', () => {
40
48
  clientId: 'mock-client-id'
41
49
  }
42
50
  };
43
-
44
51
  webex.internal.metrics.submitClientMetrics = mockSubmitMetric;
45
52
  metrics.initialSetup({}, webex);
46
53
  });
@@ -49,6 +56,40 @@ browserOnly(describe)('Meeting metrics', () => {
49
56
  sandbox.restore();
50
57
  });
51
58
 
59
+ describe('initPayload / initMediaPayload', () => {
60
+ it('should create payload with masked IPv4', () => {
61
+ geoHintInfo.clientAddress = '128.0.0.1';
62
+ webex.meetings = {
63
+ geoHintInfo
64
+ };
65
+ metrics.initialSetup({}, webex);
66
+ const payload = metrics.initPayload('myMetric', {}, {clientType: 'TEAMS_CLIENT'});
67
+
68
+ assert(payload.origin.clientInfo.localNetworkPrefix === '128.0.0.0');
69
+ assert(payload.event.name === 'myMetric');
70
+
71
+ const payload2 = metrics.initMediaPayload('myMetric', {}, {clientType: 'TEAMS_CLIENT'});
72
+
73
+ assert(payload2.origin.clientInfo.localNetworkPrefix === '128.0.0.0');
74
+ });
75
+
76
+ it('should create payload with masked IPv6', () => {
77
+ geoHintInfo.clientAddress = '2001:0db8:0000:08d3:0000:0000:0070:0000';
78
+ webex.meetings = {
79
+ geoHintInfo
80
+ };
81
+ metrics.initialSetup({}, webex);
82
+ const payload = metrics.initPayload('myIPv6Metric', {}, {clientType: 'TEAMS_CLIENT'});
83
+
84
+ assert(payload.origin.clientInfo.localNetworkPrefix === '2001:d00::');
85
+ assert(payload.event.name === 'myIPv6Metric');
86
+
87
+ const payload2 = metrics.initMediaPayload('myIPv6Metric', {}, {clientType: 'TEAMS_CLIENT'});
88
+
89
+ assert(payload2.origin.clientInfo.localNetworkPrefix === '2001:d00::');
90
+ });
91
+ });
92
+
52
93
  describe('#sendOperationalMetric', () => {
53
94
  it('sends client metric via Metrics plugin', () => {
54
95
  metrics.sendOperationalMetric('myMetric');
@@ -236,6 +236,22 @@ const waitUntil = (waitTime) => new Promise((resolve) => {
236
236
 
237
237
  const flushPromises = () => new Promise(setImmediate);
238
238
 
239
+ const getCircularReplacer = () => {
240
+ const seen = new WeakSet();
241
+
242
+ return (_, value) => {
243
+ if (typeof value === 'object' && value !== null) {
244
+ if (seen.has(value)) {
245
+ return;
246
+ }
247
+ seen.add(value);
248
+ }
249
+
250
+ // eslint-disable-next-line consistent-return
251
+ return value;
252
+ };
253
+ };
254
+
239
255
  export default {
240
256
  waitForSpy,
241
257
  waitForStateChange,
@@ -246,6 +262,7 @@ export default {
246
262
  addMedia,
247
263
  waitUntil,
248
264
  delayedTest,
249
- flushPromises
265
+ flushPromises,
266
+ getCircularReplacer
250
267
  };
251
268
 
@@ -12,6 +12,8 @@ require('@webex/internal-plugin-user');
12
12
  require('@webex/internal-plugin-device');
13
13
  require('@webex/internal-plugin-conversation');
14
14
  require('@webex/internal-plugin-support');
15
+ require('@webex/plugin-people');
16
+ require('@webex/plugin-rooms');
15
17
  require('@webex/plugin-meetings');
16
18
 
17
19
  const generateTestUsers = (options) => testUser.create({count: options.count})