@webex/plugin-meetings 1.150.1 → 1.151.3

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.
@@ -51,6 +51,7 @@ import {
51
51
  MEETING_STATE_MACHINE,
52
52
  MEETING_STATE,
53
53
  MEETINGS,
54
+ METRICS_JOIN_TIMES_MAX_DURATION,
54
55
  METRICS_OPERATIONAL_MEASURES,
55
56
  MQA_STATS,
56
57
  NETWORK_STATUS,
@@ -1065,10 +1066,45 @@ export default class Meeting extends StatelessWebexPlugin {
1065
1066
  };
1066
1067
  }
1067
1068
 
1069
+ const localSDPGenRemoteSDPRecv = this.getLocalSDPGenRemoteSDPRecvDelay();
1070
+
1071
+ if (localSDPGenRemoteSDPRecv) {
1072
+ options.joinTimes = {
1073
+ ...options.joinTimes,
1074
+ localSDPGenRemoteSDPRecv
1075
+ };
1076
+ }
1077
+
1078
+ const callInitiateJoinReq = this.getCallInitiateJoinReq();
1079
+
1080
+ if (callInitiateJoinReq) {
1081
+ options.joinTimes = {
1082
+ ...options.joinTimes,
1083
+ callInitiateJoinReq
1084
+ };
1085
+ }
1086
+
1087
+ const joinReqResp = this.getJoinReqResp();
1088
+
1089
+ if (joinReqResp) {
1090
+ options.joinTimes = {
1091
+ ...options.joinTimes,
1092
+ joinReqResp
1093
+ };
1094
+ }
1095
+
1096
+ const getTotalJmt = this.getTotalJmt();
1097
+
1098
+ if (getTotalJmt) {
1099
+ options.joinTimes = {
1100
+ ...options.joinTimes,
1101
+ getTotalJmt
1102
+ };
1103
+ }
1104
+
1068
1105
  if (options.type === MQA_STATS.CA_TYPE) {
1069
1106
  payload = Metrics.initMediaPayload(options.event, identifiers, options);
1070
1107
  }
1071
-
1072
1108
  else {
1073
1109
  payload = Metrics.initPayload(options.event, identifiers, options);
1074
1110
  }
@@ -3372,12 +3408,13 @@ export default class Meeting extends StatelessWebexPlugin {
3372
3408
  }
3373
3409
  }
3374
3410
 
3375
- return MeetingUtil.joinMeetingOptions(this, options).then((join) => {
3376
- this.meetingFiniteStateMachine.join();
3377
- LoggerProxy.logger.log('Meeting:index#join --> Success');
3411
+ return MeetingUtil.joinMeetingOptions(this, options)
3412
+ .then((join) => {
3413
+ this.meetingFiniteStateMachine.join();
3414
+ LoggerProxy.logger.log('Meeting:index#join --> Success');
3378
3415
 
3379
- return join;
3380
- })
3416
+ return join;
3417
+ })
3381
3418
  .then((join) => {
3382
3419
  joinSuccess(join);
3383
3420
  this.deferJoin = undefined;
@@ -3851,7 +3888,8 @@ export default class Meeting extends StatelessWebexPlugin {
3851
3888
  meetingId: this.id,
3852
3889
  remoteQualityLevel: this.mediaProperties.remoteQualityLevel,
3853
3890
  enableRtx: this.config.enableRtx,
3854
- enableExtmap: this.config.enableExtmap
3891
+ enableExtmap: this.config.enableExtmap,
3892
+ setStartLocalSDPGenRemoteSDPRecvDelay: this.setStartLocalSDPGenRemoteSDPRecvDelay.bind(this)
3855
3893
  })
3856
3894
  .then((peerConnection) => this.getDevices().then((devices) => {
3857
3895
  MeetingUtil.handleDeviceLogging(devices);
@@ -5238,9 +5276,9 @@ export default class Meeting extends StatelessWebexPlugin {
5238
5276
  }
5239
5277
 
5240
5278
  /**
5241
- * @param {string} typeMedia 'audio' or 'video'
5242
- * @returns {undefined}
5243
- */
5279
+ * @param {string} typeMedia 'audio' or 'video'
5280
+ * @returns {undefined}
5281
+ */
5244
5282
  setEndSendingMediaDelay(typeMedia) {
5245
5283
  this[`endSendingMediaDelay${typeMedia}`] = performance.now();
5246
5284
  }
@@ -5255,4 +5293,127 @@ export default class Meeting extends StatelessWebexPlugin {
5255
5293
 
5256
5294
  return (start && end) ? end - start : undefined;
5257
5295
  }
5296
+
5297
+ /**
5298
+ *
5299
+ * @returns {undefined}
5300
+ */
5301
+ setStartLocalSDPGenRemoteSDPRecvDelay() {
5302
+ if (!this.startLocalSDPGenRemoteSDPRecvDelay) {
5303
+ this.startLocalSDPGenRemoteSDPRecvDelay = performance.now();
5304
+ this.endLocalSDPGenRemoteSDPRecvDelay = undefined;
5305
+ }
5306
+ }
5307
+
5308
+ /**
5309
+ *
5310
+ * @returns {undefined}
5311
+ */
5312
+ setEndLocalSDPGenRemoteSDPRecvDelay() {
5313
+ if (!this.endLocalSDPGenRemoteSDPRecvDelay) {
5314
+ this.endLocalSDPGenRemoteSDPRecvDelay = performance.now();
5315
+ }
5316
+ }
5317
+
5318
+ /**
5319
+ *
5320
+ * @returns {string} duration between local SDP generation and remote SDP reception
5321
+ */
5322
+ getLocalSDPGenRemoteSDPRecvDelay() {
5323
+ const start = this.startLocalSDPGenRemoteSDPRecvDelay;
5324
+ const end = this.endLocalSDPGenRemoteSDPRecvDelay;
5325
+
5326
+ if (start && end) {
5327
+ const calculatedDelay = end - start;
5328
+
5329
+ return calculatedDelay > METRICS_JOIN_TIMES_MAX_DURATION ?
5330
+ undefined :
5331
+ calculatedDelay;
5332
+ }
5333
+
5334
+ return undefined;
5335
+ }
5336
+
5337
+ /**
5338
+ *
5339
+ * @returns {undefined}
5340
+ */
5341
+ setStartCallInitiateJoinReq() {
5342
+ this.startCallInitiateJoinReq = performance.now();
5343
+ this.endCallInitiateJoinReq = undefined;
5344
+ }
5345
+
5346
+ /**
5347
+ *
5348
+ * @returns {undefined}
5349
+ */
5350
+ setEndCallInitiateJoinReq() {
5351
+ this.endCallInitiateJoinReq = performance.now();
5352
+ }
5353
+
5354
+ /**
5355
+ *
5356
+ * @returns {string} duration between call initiate and sending join request to locus
5357
+ */
5358
+ getCallInitiateJoinReq() {
5359
+ const start = this.startCallInitiateJoinReq;
5360
+ const end = this.endCallInitiateJoinReq;
5361
+
5362
+ if (start && end) {
5363
+ const calculatedDelay = end - start;
5364
+
5365
+ return calculatedDelay > METRICS_JOIN_TIMES_MAX_DURATION ?
5366
+ undefined :
5367
+ calculatedDelay;
5368
+ }
5369
+
5370
+ return undefined;
5371
+ }
5372
+
5373
+ /**
5374
+ *
5375
+ * @returns {undefined}
5376
+ */
5377
+ setStartJoinReqResp() {
5378
+ this.startJoinReqResp = performance.now();
5379
+ this.endJoinReqResp = undefined;
5380
+ }
5381
+
5382
+ /**
5383
+ *
5384
+ * @returns {undefined}
5385
+ */
5386
+ setEndJoinReqResp() {
5387
+ this.endJoinReqResp = performance.now();
5388
+ }
5389
+
5390
+ /**
5391
+ *
5392
+ * @returns {string} duration between sending locus join request and receiving join response
5393
+ */
5394
+ getJoinReqResp() {
5395
+ const start = this.startJoinReqResp;
5396
+ const end = this.endJoinReqResp;
5397
+
5398
+ if (start && end) {
5399
+ const calculatedDelay = end - start;
5400
+
5401
+ return calculatedDelay > METRICS_JOIN_TIMES_MAX_DURATION ?
5402
+ undefined :
5403
+ calculatedDelay;
5404
+ }
5405
+
5406
+ return undefined;
5407
+ }
5408
+
5409
+ /**
5410
+ *
5411
+ * @returns {string} duration between call initiate and successful locus join (even if it is in lobby)
5412
+ */
5413
+ getTotalJmt() {
5414
+ const start = this.startCallInitiateJoinReq;
5415
+ const end = this.endJoinReqResp;
5416
+
5417
+ return (start && end) ? end - start : undefined;
5418
+ }
5258
5419
  }
@@ -21,7 +21,8 @@ import {
21
21
  MEET,
22
22
  MEET_M,
23
23
  HTTPS_PROTOCOL,
24
- UUID_REG
24
+ UUID_REG,
25
+ VALID_EMAIL_ADDRESS
25
26
  } from '../constants';
26
27
  import ParameterError from '../common/errors/parameter';
27
28
  import LoggerProxy from '../common/logs/logger-proxy';
@@ -116,8 +117,27 @@ MeetingInfoUtil.getSipUriFromHydraPersonId = (destination, webex) => webex.peopl
116
117
 
117
118
 
118
119
  MeetingInfoUtil.getDestinationType = async (from) => {
119
- const {destination, type, webex} = from;
120
+ const {type, webex} = from;
121
+ let {destination} = from;
122
+
123
+ if (type === _PERSONAL_ROOM_) { // this case checks if your type is personal room
124
+ if (!destination) { // if we are not getting anything in desination we fetch org and user ids from webex instance
125
+ destination = {
126
+ userId: webex.internal.device.userId,
127
+ orgId: webex.internal.device.orgId
128
+ };
129
+ }
130
+ else {
131
+ const options = VALID_EMAIL_ADDRESS.test(destination) ? {email: destination} : {id: destination};// we are assuming userId as default
132
+ const res = await webex.people.list(options);
133
+
134
+ let {orgId, id: userId} = res.items[0];
120
135
 
136
+ userId = deconstructHydraId(userId).id;
137
+ orgId = deconstructHydraId(orgId).id;
138
+ destination = {userId, orgId};
139
+ }
140
+ }
121
141
  if (type) {
122
142
  return {
123
143
  destination,
@@ -193,15 +213,17 @@ MeetingInfoUtil.getDestinationType = async (from) => {
193
213
  */
194
214
  MeetingInfoUtil.getRequestBody = (options) => {
195
215
  const {type, destination} = options;
196
- const body = {};
216
+ const body = {
217
+ supportHostKey: true
218
+ };
197
219
 
198
220
  switch (type) {
199
221
  case _SIP_URI_:
200
222
  body.sipUrl = destination;
201
223
  break;
202
224
  case _PERSONAL_ROOM_:
203
- body.userId = destination;
204
- body.orgId = ''; // TODO: when to use the org iD (fetch others PMR)
225
+ body.userId = destination.userId;
226
+ body.orgId = destination.orgId;
205
227
  break;
206
228
  case _MEETING_ID_:
207
229
  body.meetingKey = destination;
@@ -214,6 +236,9 @@ MeetingInfoUtil.getRequestBody = (options) => {
214
236
  if (destination.info?.webExMeetingId) {
215
237
  body.meetingKey = destination.info.webExMeetingId;
216
238
  }
239
+ else if (destination.info?.sipUri) {
240
+ body.sipUrl = destination.info.sipUri;
241
+ }
217
242
  break;
218
243
  case _MEETING_LINK_:
219
244
  body.meetingUrl = destination;
@@ -6,10 +6,10 @@ import util from 'util';
6
6
  import {includes} from 'lodash';
7
7
  import uuid from 'uuid';
8
8
  import window from 'global/window';
9
+ import anonymize from 'ip-anonymize';
9
10
 
10
11
  import LoggerProxy from '../common/logs/logger-proxy';
11
12
  import {MEETING_ERRORS} from '../constants';
12
- import StaticConfig from '../common/config';
13
13
  import BrowserDetection from '../common/browser-detection';
14
14
 
15
15
  import {
@@ -34,21 +34,19 @@ const {
34
34
  } = BrowserDetection();
35
35
 
36
36
  // Apply a CIDR /28 format to the IP address
37
- const getLocalNetworkPrefix = (localIp) => {
38
- if (!localIp) {
39
- return undefined;
40
- }
41
- const parts = localIp.split('.');
42
-
43
- // eslint-disable-next-line no-bitwise
44
- parts[3] &= 240;
45
-
46
- return parts.join('.');
47
- };
37
+ const anonymizeIPAddress = (localIp) => anonymize(localIp);
48
38
 
49
39
  const triggerTimers = ({event, meeting, data}) => {
50
40
  switch (event) {
41
+ case eventType.CALL_INITIATED:
42
+ meeting.setStartCallInitiateJoinReq();
43
+ break;
44
+ case eventType.LOCUS_JOIN_REQUEST:
45
+ meeting.setEndCallInitiateJoinReq();
46
+ meeting.setStartJoinReqResp();
47
+ break;
51
48
  case eventType.LOCUS_JOIN_RESPONSE:
49
+ meeting.setEndJoinReqResp();
52
50
  meeting.setStartSetupDelay(mediaType.AUDIO);
53
51
  meeting.setStartSetupDelay(mediaType.VIDEO);
54
52
  meeting.setStartSendingMediaDelay(mediaType.AUDIO);
@@ -60,6 +58,12 @@ const triggerTimers = ({event, meeting, data}) => {
60
58
  case eventType.SENDING_MEDIA_START:
61
59
  meeting.setEndSendingMediaDelay(data.mediaType);
62
60
  break;
61
+ case eventType.LOCAL_SDP_GENERATED:
62
+ meeting.setStartLocalSDPGenRemoteSDPRecvDelay();
63
+ break;
64
+ case eventType.REMOTE_SDP_RECEIVED:
65
+ meeting.setEndLocalSDPGenRemoteSDPRecvDelay();
66
+ break;
63
67
  default:
64
68
  break;
65
69
  }
@@ -144,6 +148,7 @@ class Metrics {
144
148
 
145
149
  if (!meeting && meetingId) {
146
150
  meeting = this.meetingCollection.get(meetingId);
151
+ options.meeting = meeting;
147
152
  }
148
153
 
149
154
  if (meeting) {
@@ -185,7 +190,7 @@ class Metrics {
185
190
  clientInfo: {
186
191
  clientType: options.clientType,
187
192
  clientVersion: `${CLIENT_NAME}/${this.webex.version}`,
188
- localNetworkPrefix: getLocalNetworkPrefix(this.webex.meetings.geoHintInfo?.clientAddress),
193
+ localNetworkPrefix: anonymizeIPAddress(this.webex.meetings.geoHintInfo?.clientAddress),
189
194
  osVersion: getOSVersion() || 'unknown',
190
195
  subClientType: options.subClientType,
191
196
  os: this.getOsName(),
@@ -228,6 +233,9 @@ class Metrics {
228
233
  if (options.recoveredBy) {
229
234
  payload.event.recoveredBy = options.recoveredBy;
230
235
  }
236
+ if (options.joinTimes) {
237
+ payload.event.joinTimes = options.joinTimes;
238
+ }
231
239
  }
232
240
 
233
241
  return payload;
@@ -259,7 +267,7 @@ class Metrics {
259
267
  * @memberof Metrics
260
268
  */
261
269
  initMediaPayload(eventType, identifiers, options = {}) {
262
- const {audioSetupDelay, videoSetupDelay} = options;
270
+ const {audioSetupDelay, videoSetupDelay, joinTimes} = options;
263
271
 
264
272
  const payload = {
265
273
  eventId: uuid.v4(),
@@ -273,7 +281,7 @@ class Metrics {
273
281
  clientInfo: {
274
282
  clientType: options.clientType, // TODO: Only clientType: 'TEAMS_CLIENT' is whitelisted
275
283
  clientVersion: `${CLIENT_NAME}/${this.webex.version}`,
276
- localNetworkPrefix: getLocalNetworkPrefix(this.webex.meetings.geoHintInfo?.clientAddress),
284
+ localNetworkPrefix: anonymizeIPAddress(this.webex.meetings.geoHintInfo?.clientAddress),
277
285
  os: this.getOsName(),
278
286
  osVersion: getOSVersion() || UNKNOWN,
279
287
  subClientType: options.subClientType,
@@ -290,7 +298,10 @@ class Metrics {
290
298
  canProceed: true,
291
299
  identifiers,
292
300
  intervals: [options.intervalData],
293
- eventData: {webClientDomain: window.location.hostname},
301
+ joinTimes,
302
+ eventData: {
303
+ webClientDomain: window.location.hostname
304
+ },
294
305
  sourceMetadata: {
295
306
  applicationSoftwareType: CLIENT_NAME,
296
307
  applicationSoftwareVersion: this.webex.version,
@@ -455,7 +466,7 @@ class Metrics {
455
466
  userAgentToString() {
456
467
  let userAgentOption;
457
468
  let browserInfo;
458
- const clientInfo = util.format('client=%s', `${StaticConfig.meetings.metrics.clientName}`);
469
+ const clientInfo = util.format('client=%s', `${this.webex.meetings?.metrics?.clientName}`);
459
470
 
460
471
  if (['chrome', 'firefox', 'msie', 'msedge', 'safari'].indexOf(getBrowserName().toLowerCase()) !== -1) {
461
472
  browserInfo = util.format('browser=%s', `${getBrowserName().toLowerCase()}/${getBrowserVersion().split('.')[0]}`);
@@ -288,7 +288,12 @@ pc.addStream = (peerConnection, stream) => {
288
288
  * @param {String} meetingId
289
289
  * @returns {undefined}
290
290
  */
291
- pc.setRemoteSessionDetails = (peerConnection, typeStr, remoteSdp, meetingId) => {
291
+ pc.setRemoteSessionDetails = (
292
+ peerConnection,
293
+ typeStr,
294
+ remoteSdp,
295
+ meetingId,
296
+ ) => {
292
297
  LoggerProxy.logger.log(`PeerConnectionManager:index#setRemoteSessionDetails --> Setting the remote description type: ${typeStr}State: ${peerConnection.signalingState}`);
293
298
  const sdp = remoteSdp;
294
299
 
@@ -314,7 +319,7 @@ pc.setRemoteSessionDetails = (peerConnection, typeStr, remoteSdp, meetingId) =>
314
319
  })
315
320
  )
316
321
  .then(() => {
317
- if (!peerConnection.remoteDescription) {
322
+ if (peerConnection.signalingState === SDP.STABLE) {
318
323
  Metrics.postEvent({
319
324
  event: eventType.REMOTE_SDP_RECEIVED,
320
325
  meetingId
@@ -519,7 +519,10 @@ skipInNode(describe)('plugin-meetings', () => {
519
519
  .then((response) => {
520
520
  assert.equal(response[0].result.memberId, alice.meeting.selfId);
521
521
  }),
522
- testUtils.waitForEvents([{scope: bob.meeting.members, event: 'members:update'}]),
522
+ testUtils.waitForEvents([{scope: bob.meeting.members, event: 'members:update'}])
523
+ .then((response) => {
524
+ console.log('SCREEN SHARE RESPONSE ', JSON.stringify(response, testUtils.getCircularReplacer()));
525
+ }),
523
526
  testUtils.waitForEvents([{scope: alice.meeting, event: 'media:ready'}])
524
527
  .then((response) => {
525
528
  console.log('MEDIA:READY event ', response[0].result);
@@ -549,7 +552,7 @@ skipInNode(describe)('plugin-meetings', () => {
549
552
  }),
550
553
  testUtils.waitForEvents([{scope: alice.meeting.members, event: 'members:update'}])
551
554
  .then((response) => {
552
- console.log('SCREEN SHARE RESPONSE ', JSON.stringify(response));
555
+ console.log('SCREEN SHARE RESPONSE ', JSON.stringify(response, testUtils.getCircularReplacer()));
553
556
  }),
554
557
  testUtils.waitForEvents([{scope: bob.meeting, event: 'media:ready'}])
555
558
  .then((response) => {
@@ -601,7 +604,7 @@ skipInNode(describe)('plugin-meetings', () => {
601
604
  }),
602
605
  testUtils.waitForEvents([{scope: bob.meeting.members, event: 'members:update'}])
603
606
  .then((response) => {
604
- console.log('WHITEBOARD SHARE RESPONSE ', JSON.stringify(response));
607
+ console.log('WHITEBOARD SHARE RESPONSE ', JSON.stringify(response, testUtils.getCircularReplacer()));
605
608
  })
606
609
  ])
607
610
  .then(() => {
@@ -624,7 +627,7 @@ skipInNode(describe)('plugin-meetings', () => {
624
627
  }),
625
628
  testUtils.waitForEvents([{scope: alice.meeting.members, event: 'members:update'}])
626
629
  .then((response) => {
627
- console.log('WHITEBOARD SHARE RESPONSE ', JSON.stringify(response));
630
+ console.log('WHITEBOARD SHARE RESPONSE ', JSON.stringify(response, testUtils.getCircularReplacer()));
628
631
  })
629
632
  ])
630
633
  .then(() => {
@@ -660,7 +663,7 @@ skipInNode(describe)('plugin-meetings', () => {
660
663
  }),
661
664
  testUtils.waitForEvents([{scope: bob.meeting.members, event: 'members:update'}])
662
665
  .then((response) => {
663
- console.log('WHITEBOARD SHARE RESPONSE ', JSON.stringify(response));
666
+ console.log('WHITEBOARD SHARE RESPONSE ', JSON.stringify(response, testUtils.getCircularReplacer()));
664
667
  })
665
668
  ])
666
669
  .then(() => {
@@ -679,7 +682,7 @@ skipInNode(describe)('plugin-meetings', () => {
679
682
  }),
680
683
  testUtils.waitForEvents([{scope: alice.meeting.members, event: 'members:update'}])
681
684
  .then((response) => {
682
- console.log('SCREEN SHARE RESPONSE ', JSON.stringify(response));
685
+ console.log('SCREEN SHARE RESPONSE ', JSON.stringify(response, testUtils.getCircularReplacer()));
683
686
  }),
684
687
  testUtils.waitForEvents([{scope: bob.meeting, event: 'media:ready'}])
685
688
  .then((response) => {
@@ -715,7 +718,7 @@ skipInNode(describe)('plugin-meetings', () => {
715
718
  }),
716
719
  testUtils.waitForEvents([{scope: alice.meeting.members, event: 'members:update'}])
717
720
  .then((response) => {
718
- console.log('WHITEBOARD SHARE RESPONSE ', JSON.stringify(response));
721
+ console.log('WHITEBOARD SHARE RESPONSE ', JSON.stringify(response, testUtils.getCircularReplacer()));
719
722
  })
720
723
  ])
721
724
  .then(() => {
@@ -65,8 +65,14 @@ skipInNode(describe)('plugin-meetings', () => {
65
65
  testUtils.delayedPromise(alice.meeting.join()),
66
66
  testUtils.waitForEvents([
67
67
  {scope: bob.webex.meetings, event: 'meeting:added', user: bob},
68
- {scope: chris.webex.meetings, event: 'meeting:added', user: chris}])
69
- ])));
68
+ {scope: chris.webex.meetings, event: 'meeting:added', user: chris}
69
+ ])
70
+ ]).then(() => {
71
+ // TODO Renenable after unified flag is enabled
72
+ // const {meetingNumber} = bob.meeting.meetingInfo;
73
+
74
+ // assert(meetingNumber === alice.meeting.meetingNumber, 'meetingNumber matches alice meeting number');
75
+ })));
70
76
 
71
77
  xit('Should fetch user info using user hydra id with the new api', () => alice.webex.rooms.create({title: 'sample'})
72
78
  .then((room) => MeetingInfoUtil.getDestinationType({
@@ -95,7 +101,6 @@ skipInNode(describe)('plugin-meetings', () => {
95
101
  assert(meetingNumber === alice.meeting.meetingNumber, 'meetingNumber matches alice meeting number');
96
102
  });
97
103
 
98
-
99
104
  it('Bob and chris joins space meeting', () => testUtils.waitForStateChange(alice.meeting, 'JOINED')
100
105
  .then(() => testUtils.waitForStateChange(bob.meeting, 'IDLE'))
101
106
  .then(() => testUtils.waitForStateChange(chris.meeting, 'IDLE'))
@@ -110,7 +110,6 @@ describe('plugin-meetings', () => {
110
110
 
111
111
 
112
112
  TriggerProxy.trigger = sinon.stub().returns(true);
113
- Metrics.initPayload = sinon.stub();
114
113
  Metrics.postEvent = sinon.stub();
115
114
  Metrics.initialSetup(null, webex);
116
115
  MediaUtil.createPeerConnection = sinon.stub().returns({});
@@ -2,7 +2,7 @@
2
2
  * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
3
  */
4
4
 
5
- import {assert} from '@webex/test-helper-chai';
5
+ import {assert, expect} from '@webex/test-helper-chai';
6
6
  import sinon from 'sinon';
7
7
  import {
8
8
  _MEETING_ID_,
@@ -68,17 +68,78 @@ describe('plugin-meetings', () => {
68
68
  assert.equal(res.type, _CONVERSATION_URL_);
69
69
  assert.equal(res.destination, 'https://conv-a.wbx2.com/conversation/api/v1/conversations/bfb49280');
70
70
  });
71
+
72
+ describe('PMR', () => {
73
+ const mockedListReturn = {userId: '01824b9b-adef-4b10-b5c1-8a2fe2fb7c0e', orgId: '1eb65fdf-9643-417f-9974-ad72cae0e10f'};
74
+ const mockedList = {
75
+ items: [{
76
+ id: 'Y2lzY29zcGFyazovL3VzL1BFT1BMRS8wMTgyNGI5Yi1hZGVmLTRiMTAtYjVjMS04YTJmZTJmYjdjMGU',
77
+ orgId: 'Y2lzY29zcGFyazovL3VzL09SR0FOSVpBVElPTi8xZWI2NWZkZi05NjQzLTQxN2YtOTk3NC1hZDcyY2FlMGUxMGY'
78
+ }]
79
+
80
+ };
81
+
82
+ it('should return a userID and orgID without passing a destination', async () => {
83
+ const res = await MeetingInfoUtil.getDestinationType({
84
+ type: _PERSONAL_ROOM_,
85
+ webex: {
86
+ internal: {
87
+ device: {
88
+ userId: '01824b9b-adef-4b10-b5c1-8a2fe2fb7c0e',
89
+ orgId: '1eb65fdf-9643-417f-9974-ad72cae0e10f'
90
+ }
91
+ }
92
+ }
93
+ });
94
+
95
+ expect(res.destination.userId).to.equal('01824b9b-adef-4b10-b5c1-8a2fe2fb7c0e');
96
+ expect(res.destination.orgId).to.equal('1eb65fdf-9643-417f-9974-ad72cae0e10f');
97
+ });
98
+
99
+ it('should return a userID and orgID when passing an email', async () => {
100
+ const res = await MeetingInfoUtil.getDestinationType({
101
+ type: _PERSONAL_ROOM_,
102
+ destination: 'amritesi@cisco.com',
103
+ webex: {
104
+ people: {list: sinon.stub().returns(mockedList)}
105
+
106
+ }
107
+ });
108
+ const {orgId, userId} = res.destination;
109
+
110
+ expect(userId).to.equal(mockedListReturn.userId);
111
+ expect(orgId).to.equal(mockedListReturn.orgId);
112
+ });
113
+
114
+ it('should return a userID and orgID when passing an id', async () => {
115
+ const res = await MeetingInfoUtil.getDestinationType({
116
+ type: _PERSONAL_ROOM_,
117
+ destination: '01824b9b-adef-4b10-b5c1-8a2fe2fb7c0e',
118
+ webex: {
119
+ people: {list: sinon.stub().returns(mockedList)}
120
+ }
121
+
122
+ });
123
+ const {orgId, userId} = res.destination;
124
+
125
+ expect(userId).to.equal(mockedListReturn.userId);
126
+ expect(orgId).to.equal(mockedListReturn.orgId);
127
+ });
128
+ });
71
129
  });
72
130
 
73
131
  describe('#getRequestBody', () => {
74
132
  it('for _PERSONAL_ROOM_', () => {
75
133
  const res = MeetingInfoUtil.getRequestBody({
76
134
  type: _PERSONAL_ROOM_,
77
- destination: 'userId_1234'
135
+ destination: {
136
+ userId: '01824b9b-adef-4b10-b5c1-8a2fe2fb7c0e',
137
+ orgId: '1eb65fdf-9643-417f-9974-ad72cae0e10f'
138
+ }
78
139
  });
79
140
 
80
- assert.equal(res.orgId, '');
81
- assert.equal(res.userId, 'userId_1234');
141
+ assert.equal(res.orgId, '1eb65fdf-9643-417f-9974-ad72cae0e10f');
142
+ assert.equal(res.userId, '01824b9b-adef-4b10-b5c1-8a2fe2fb7c0e');
82
143
  });
83
144
 
84
145
  it('for _MEETING_ID_', () => {
@@ -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');