@webex/plugin-meetings 3.8.0-next.4 → 3.8.0-next.41

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.
Files changed (130) hide show
  1. package/dist/breakouts/breakout.js +1 -1
  2. package/dist/breakouts/index.js +1 -1
  3. package/dist/config.js +1 -0
  4. package/dist/config.js.map +1 -1
  5. package/dist/constants.js +14 -1
  6. package/dist/constants.js.map +1 -1
  7. package/dist/controls-options-manager/enums.js +2 -0
  8. package/dist/controls-options-manager/enums.js.map +1 -1
  9. package/dist/controls-options-manager/types.js.map +1 -1
  10. package/dist/controls-options-manager/util.js +52 -0
  11. package/dist/controls-options-manager/util.js.map +1 -1
  12. package/dist/interpretation/index.js +1 -1
  13. package/dist/interpretation/siLanguage.js +1 -1
  14. package/dist/locus-info/controlsUtils.js +28 -10
  15. package/dist/locus-info/controlsUtils.js.map +1 -1
  16. package/dist/locus-info/index.js +20 -1
  17. package/dist/locus-info/index.js.map +1 -1
  18. package/dist/media/index.js +3 -15
  19. package/dist/media/index.js.map +1 -1
  20. package/dist/meeting/in-meeting-actions.js +11 -1
  21. package/dist/meeting/in-meeting-actions.js.map +1 -1
  22. package/dist/meeting/index.js +443 -256
  23. package/dist/meeting/index.js.map +1 -1
  24. package/dist/meeting/locusMediaRequest.js +21 -22
  25. package/dist/meeting/locusMediaRequest.js.map +1 -1
  26. package/dist/meeting/muteState.js +0 -2
  27. package/dist/meeting/muteState.js.map +1 -1
  28. package/dist/meeting/request.js +30 -0
  29. package/dist/meeting/request.js.map +1 -1
  30. package/dist/meeting/request.type.js.map +1 -1
  31. package/dist/meeting/util.js +10 -2
  32. package/dist/meeting/util.js.map +1 -1
  33. package/dist/meeting-info/meeting-info-v2.js +359 -60
  34. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  35. package/dist/meetings/index.js +60 -1
  36. package/dist/meetings/index.js.map +1 -1
  37. package/dist/member/index.js +10 -0
  38. package/dist/member/index.js.map +1 -1
  39. package/dist/member/util.js +3 -0
  40. package/dist/member/util.js.map +1 -1
  41. package/dist/metrics/constants.js +9 -0
  42. package/dist/metrics/constants.js.map +1 -1
  43. package/dist/reachability/clusterReachability.js +52 -8
  44. package/dist/reachability/clusterReachability.js.map +1 -1
  45. package/dist/reachability/index.js +70 -45
  46. package/dist/reachability/index.js.map +1 -1
  47. package/dist/reachability/reachability.types.js +14 -0
  48. package/dist/reachability/reachability.types.js.map +1 -1
  49. package/dist/reachability/request.js +19 -3
  50. package/dist/reachability/request.js.map +1 -1
  51. package/dist/reconnection-manager/index.js +2 -2
  52. package/dist/reconnection-manager/index.js.map +1 -1
  53. package/dist/recording-controller/util.js +5 -5
  54. package/dist/recording-controller/util.js.map +1 -1
  55. package/dist/roap/index.js.map +1 -1
  56. package/dist/roap/turnDiscovery.js +45 -27
  57. package/dist/roap/turnDiscovery.js.map +1 -1
  58. package/dist/roap/types.js +17 -0
  59. package/dist/roap/types.js.map +1 -0
  60. package/dist/types/config.d.ts +1 -0
  61. package/dist/types/constants.d.ts +10 -0
  62. package/dist/types/controls-options-manager/enums.d.ts +3 -1
  63. package/dist/types/controls-options-manager/types.d.ts +7 -1
  64. package/dist/types/locus-info/index.d.ts +1 -0
  65. package/dist/types/meeting/in-meeting-actions.d.ts +10 -0
  66. package/dist/types/meeting/index.d.ts +47 -1
  67. package/dist/types/meeting/muteState.d.ts +0 -1
  68. package/dist/types/meeting/request.d.ts +12 -1
  69. package/dist/types/meeting/request.type.d.ts +6 -0
  70. package/dist/types/meeting/util.d.ts +2 -1
  71. package/dist/types/meeting-info/meeting-info-v2.d.ts +80 -0
  72. package/dist/types/meetings/index.d.ts +29 -0
  73. package/dist/types/member/index.d.ts +1 -0
  74. package/dist/types/metrics/constants.d.ts +9 -0
  75. package/dist/types/reachability/clusterReachability.d.ts +13 -1
  76. package/dist/types/reachability/index.d.ts +2 -1
  77. package/dist/types/reachability/reachability.types.d.ts +5 -0
  78. package/dist/types/roap/index.d.ts +3 -2
  79. package/dist/types/roap/turnDiscovery.d.ts +5 -17
  80. package/dist/types/roap/types.d.ts +16 -0
  81. package/dist/webinar/index.js +1 -1
  82. package/package.json +22 -22
  83. package/src/config.ts +1 -0
  84. package/src/constants.ts +17 -0
  85. package/src/controls-options-manager/enums.ts +2 -0
  86. package/src/controls-options-manager/types.ts +11 -1
  87. package/src/controls-options-manager/util.ts +62 -0
  88. package/src/locus-info/controlsUtils.ts +44 -14
  89. package/src/locus-info/index.ts +23 -1
  90. package/src/media/index.ts +5 -21
  91. package/src/meeting/in-meeting-actions.ts +20 -0
  92. package/src/meeting/index.ts +263 -69
  93. package/src/meeting/locusMediaRequest.ts +27 -22
  94. package/src/meeting/muteState.ts +0 -2
  95. package/src/meeting/request.ts +36 -1
  96. package/src/meeting/request.type.ts +7 -0
  97. package/src/meeting/util.ts +9 -2
  98. package/src/meeting-info/meeting-info-v2.ts +247 -6
  99. package/src/meetings/index.ts +72 -1
  100. package/src/member/index.ts +11 -0
  101. package/src/member/util.ts +3 -0
  102. package/src/metrics/constants.ts +9 -0
  103. package/src/reachability/clusterReachability.ts +47 -1
  104. package/src/reachability/index.ts +15 -0
  105. package/src/reachability/reachability.types.ts +6 -0
  106. package/src/reachability/request.ts +7 -0
  107. package/src/reconnection-manager/index.ts +2 -2
  108. package/src/recording-controller/util.ts +17 -13
  109. package/src/roap/index.ts +3 -7
  110. package/src/roap/turnDiscovery.ts +34 -39
  111. package/src/roap/types.ts +23 -0
  112. package/test/unit/spec/controls-options-manager/util.js +120 -0
  113. package/test/unit/spec/locus-info/controlsUtils.js +103 -9
  114. package/test/unit/spec/locus-info/index.js +28 -0
  115. package/test/unit/spec/media/index.ts +6 -16
  116. package/test/unit/spec/meeting/in-meeting-actions.ts +13 -4
  117. package/test/unit/spec/meeting/index.js +490 -130
  118. package/test/unit/spec/meeting/locusMediaRequest.ts +95 -87
  119. package/test/unit/spec/meeting/muteState.js +0 -2
  120. package/test/unit/spec/meeting/request.js +32 -1
  121. package/test/unit/spec/meeting/utils.js +115 -18
  122. package/test/unit/spec/meeting-info/meetinginfov2.js +443 -114
  123. package/test/unit/spec/meetings/index.js +78 -1
  124. package/test/unit/spec/member/index.js +7 -0
  125. package/test/unit/spec/member/util.js +24 -0
  126. package/test/unit/spec/reachability/clusterReachability.ts +47 -1
  127. package/test/unit/spec/reachability/index.ts +12 -0
  128. package/test/unit/spec/reachability/request.js +47 -2
  129. package/test/unit/spec/reconnection-manager/index.js +4 -4
  130. package/test/unit/spec/roap/turnDiscovery.ts +110 -28
@@ -1,14 +1,18 @@
1
1
  import 'jsdom-global/register';
2
2
  import sinon from 'sinon';
3
3
  import {assert} from '@webex/test-helper-chai';
4
- import { cloneDeep } from 'lodash';
5
-
4
+ import {cloneDeep} from 'lodash';
5
+ import {EventEmitter} from 'events';
6
6
  import MockWebex from '@webex/test-helper-mock-webex';
7
7
  import Meetings from '@webex/plugin-meetings';
8
- import { LocalMuteRequest, LocusMediaRequest, RoapRequest } from "@webex/plugin-meetings/src/meeting/locusMediaRequest";
8
+ import {
9
+ LocalMuteRequest,
10
+ LocusMediaRequest,
11
+ RoapRequest,
12
+ } from '@webex/plugin-meetings/src/meeting/locusMediaRequest';
9
13
  import testUtils from '../../../utils/testUtils';
10
- import { Defer } from '@webex/common';
11
- import { IP_VERSION } from '../../../../src/constants';
14
+ import {Defer} from '@webex/common';
15
+ import {IP_VERSION} from '../../../../src/constants';
12
16
 
13
17
  describe('LocusMediaRequest.send()', () => {
14
18
  let locusMediaRequest: LocusMediaRequest;
@@ -16,10 +20,10 @@ describe('LocusMediaRequest.send()', () => {
16
20
  let mockWebex;
17
21
 
18
22
  const fakeLocusResponse = {
19
- locus: { something: 'whatever'}
23
+ locus: {something: 'whatever'},
20
24
  };
21
25
 
22
- const exampleRoapRequestBody:RoapRequest = {
26
+ const exampleRoapRequestBody: RoapRequest = {
23
27
  type: 'RoapMessage',
24
28
  mediaId: 'mediaId',
25
29
  selfUrl: 'fakeMeetingSelfUrl',
@@ -31,8 +35,11 @@ describe('LocusMediaRequest.send()', () => {
31
35
  tieBreaker: 0xfffffffe,
32
36
  },
33
37
  reachability: {
34
- 'wjfkm.wjfkm.*': {udp:{reachable: true}, tcp:{reachable:false}},
35
- '1eb65fdf-9643-417f-9974-ad72cae0e10f.59268c12-7a04-4b23-a1a1-4c74be03019a.*': {udp:{reachable: false}, tcp:{reachable:true}},
38
+ 'wjfkm.wjfkm.*': {udp: {reachable: true}, tcp: {reachable: false}},
39
+ '1eb65fdf-9643-417f-9974-ad72cae0e10f.59268c12-7a04-4b23-a1a1-4c74be03019a.*': {
40
+ udp: {reachable: false},
41
+ tcp: {reachable: true},
42
+ },
36
43
  },
37
44
  clientMediaPreferences: {
38
45
  preferTranscoding: false,
@@ -45,19 +52,22 @@ describe('LocusMediaRequest.send()', () => {
45
52
  reachability: {
46
53
  version: '1',
47
54
  result: 'some fake reachability result',
48
- }
49
- }
55
+ },
56
+ },
50
57
  };
51
58
 
52
- const createExpectedRoapBody = (expectedMessageType, expectedMute:{audioMuted: boolean, videoMuted: boolean}) => {
59
+ const createExpectedRoapBody = (
60
+ expectedMessageType,
61
+ expectedMute: {audioMuted: boolean; videoMuted: boolean}
62
+ ) => {
53
63
  return {
54
- device: { url: 'deviceUrl', deviceType: 'deviceType', regionCode: 'regionCode' },
64
+ device: {url: 'deviceUrl', deviceType: 'deviceType', regionCode: 'regionCode'},
55
65
  correlationId: 'correlationId',
56
66
  localMedias: [
57
67
  {
58
68
  localSdp: `{"audioMuted":${expectedMute.audioMuted},"videoMuted":${expectedMute.videoMuted},"roapMessage":{"messageType":"${expectedMessageType}","sdps":["sdp"],"version":"2","seq":1,"tieBreaker":4294967294},"reachability":{"wjfkm.wjfkm.*":{"udp":{"reachable":true},"tcp":{"reachable":false}},"1eb65fdf-9643-417f-9974-ad72cae0e10f.59268c12-7a04-4b23-a1a1-4c74be03019a.*":{"udp":{"reachable":false},"tcp":{"reachable":true}}}}`,
59
- mediaId: 'mediaId'
60
- }
69
+ mediaId: 'mediaId',
70
+ },
61
71
  ],
62
72
  clientMediaPreferences: {
63
73
  preferTranscoding: false,
@@ -65,24 +75,27 @@ describe('LocusMediaRequest.send()', () => {
65
75
  joinCookie: {
66
76
  anycastEntryPoint: 'aws-eu-west-1',
67
77
  clientIpAddress: 'some ip',
68
- timeShot: '2023-05-23T08:03:49Z'
78
+ timeShot: '2023-05-23T08:03:49Z',
69
79
  },
70
80
  reachability: {
71
81
  version: '1',
72
82
  result: 'some fake reachability result',
73
- }
74
- }
83
+ },
84
+ },
75
85
  };
76
86
  };
77
87
 
78
- const exampleLocalMuteRequestBody:LocalMuteRequest = {
88
+ const exampleLocalMuteRequestBody: LocalMuteRequest = {
79
89
  type: 'LocalMute',
80
90
  mediaId: 'mediaId',
81
91
  selfUrl: 'fakeMeetingSelfUrl',
82
92
  muteOptions: {},
83
93
  };
84
94
 
85
- const createExpectedLocalMuteBody = (expectedMute:{audioMuted: boolean, videoMuted: boolean}, sequence = undefined) => {
95
+ const createExpectedLocalMuteBody = (
96
+ expectedMute: {audioMuted: boolean; videoMuted: boolean},
97
+ sequence = undefined
98
+ ) => {
86
99
  const body: any = {
87
100
  device: {
88
101
  url: 'deviceUrl',
@@ -116,33 +129,37 @@ describe('LocusMediaRequest.send()', () => {
116
129
 
117
130
  mockWebex.internal = {
118
131
  newMetrics: {
119
- submitClientEvent: sinon.stub()
132
+ submitClientEvent: sinon.stub(),
120
133
  },
121
134
  };
122
135
 
123
- locusMediaRequest = new LocusMediaRequest({
124
- device: {
125
- url: 'deviceUrl',
126
- deviceType: 'deviceType',
127
- regionCode: 'regionCode',
136
+ locusMediaRequest = new LocusMediaRequest(
137
+ {
138
+ device: {
139
+ url: 'deviceUrl',
140
+ deviceType: 'deviceType',
141
+ regionCode: 'regionCode',
142
+ },
143
+ correlationId: 'correlationId',
144
+ meetingId: 'meetingId',
145
+ preferTranscoding: true,
128
146
  },
129
- correlationId: 'correlationId',
130
- meetingId: 'meetingId',
131
- preferTranscoding: true,
132
- }, {
133
- parent: mockWebex,
134
- });
147
+ {
148
+ parent: mockWebex,
149
+ }
150
+ );
135
151
  webexRequestStub = sinon.stub(locusMediaRequest, 'request').resolves(fakeLocusResponse);
136
- })
152
+ });
137
153
 
138
- const sendLocalMute = (muteOptions, overrides={}) => locusMediaRequest.send({...exampleLocalMuteRequestBody, ...overrides, muteOptions});
154
+ const sendLocalMute = (muteOptions, overrides = {}) =>
155
+ locusMediaRequest.send({...exampleLocalMuteRequestBody, ...overrides, muteOptions});
139
156
 
140
157
  const sendRoapMessage = (messageType) => {
141
158
  const request = cloneDeep(exampleRoapRequestBody);
142
159
 
143
160
  request.roapMessage.messageType = messageType;
144
161
  return locusMediaRequest.send(request);
145
- }
162
+ };
146
163
 
147
164
  /** Helper function that makes sure the LocusMediaRequest.confluenceState is 'created' */
148
165
  const ensureConfluenceCreated = async () => {
@@ -150,27 +167,7 @@ describe('LocusMediaRequest.send()', () => {
150
167
 
151
168
  webexRequestStub.resetHistory();
152
169
  mockWebex.internal.newMetrics.submitClientEvent.resetHistory();
153
- }
154
-
155
- const checkMetrics = (expectedMetrics: boolean = true) => {
156
- if (expectedMetrics) {
157
- assert.calledWith(mockWebex.internal.newMetrics.submitClientEvent, {
158
- name: 'client.locus.media.request',
159
- options: {
160
- meetingId: 'meetingId',
161
- },
162
- });
163
-
164
- assert.calledWith(mockWebex.internal.newMetrics.submitClientEvent, {
165
- name: 'client.locus.media.response',
166
- options: {
167
- meetingId: 'meetingId',
168
- },
169
- });
170
- } else {
171
- assert.notCalled(mockWebex.internal.newMetrics.submitClientEvent);
172
- }
173
- }
170
+ };
174
171
 
175
172
  it('sends a roap message', async () => {
176
173
  const result = await sendRoapMessage('OFFER');
@@ -181,9 +178,9 @@ describe('LocusMediaRequest.send()', () => {
181
178
  method: 'PUT',
182
179
  uri: 'fakeMeetingSelfUrl/media',
183
180
  body: createExpectedRoapBody('OFFER', {audioMuted: true, videoMuted: true}),
181
+ upload: sinon.match.instanceOf(EventEmitter),
182
+ download: sinon.match.instanceOf(EventEmitter),
184
183
  });
185
-
186
- checkMetrics();
187
184
  });
188
185
 
189
186
  it('sends correct metric event when roap message fails', async () => {
@@ -210,9 +207,9 @@ describe('LocusMediaRequest.send()', () => {
210
207
  method: 'PUT',
211
208
  uri: 'fakeMeetingSelfUrl/media',
212
209
  body: createExpectedLocalMuteBody({audioMuted: false, videoMuted: false}),
210
+ upload: sinon.match.instanceOf(EventEmitter),
211
+ download: sinon.match.instanceOf(EventEmitter),
213
212
  });
214
-
215
- checkMetrics(false);
216
213
  });
217
214
 
218
215
  it('sends a local mute request with sequence', async () => {
@@ -228,6 +225,8 @@ describe('LocusMediaRequest.send()', () => {
228
225
  method: 'PUT',
229
226
  uri: 'fakeMeetingSelfUrl/media',
230
227
  body: createExpectedLocalMuteBody({audioMuted: false, videoMuted: false}, sequence),
228
+ upload: sinon.match.instanceOf(EventEmitter),
229
+ download: sinon.match.instanceOf(EventEmitter),
231
230
  });
232
231
  });
233
232
 
@@ -237,15 +236,13 @@ describe('LocusMediaRequest.send()', () => {
237
236
  let result1;
238
237
  let result2;
239
238
 
240
- const promise1 = sendLocalMute({audioMuted: true, videoMuted: false})
241
- .then((result) => {
242
- result1 = result;
243
- });
239
+ const promise1 = sendLocalMute({audioMuted: true, videoMuted: false}).then((result) => {
240
+ result1 = result;
241
+ });
244
242
 
245
- const promise2 = sendLocalMute({audioMuted: false, videoMuted: true})
246
- .then((result) => {
247
- result2 = result;
248
- });
243
+ const promise2 = sendLocalMute({audioMuted: false, videoMuted: true}).then((result) => {
244
+ result2 = result;
245
+ });
249
246
 
250
247
  await testUtils.flushPromises();
251
248
 
@@ -258,9 +255,9 @@ describe('LocusMediaRequest.send()', () => {
258
255
  method: 'PUT',
259
256
  uri: 'fakeMeetingSelfUrl/media',
260
257
  body: createExpectedLocalMuteBody({audioMuted: false, videoMuted: true}),
258
+ upload: sinon.match.instanceOf(EventEmitter),
259
+ download: sinon.match.instanceOf(EventEmitter),
261
260
  });
262
-
263
- checkMetrics(false);
264
261
  });
265
262
 
266
263
  it('sends a local mute request with the last audio/video mute values', async () => {
@@ -277,9 +274,9 @@ describe('LocusMediaRequest.send()', () => {
277
274
  method: 'PUT',
278
275
  uri: 'fakeMeetingSelfUrl/media',
279
276
  body: createExpectedLocalMuteBody({audioMuted: true, videoMuted: false}),
277
+ upload: sinon.match.instanceOf(EventEmitter),
278
+ download: sinon.match.instanceOf(EventEmitter),
280
279
  });
281
-
282
- checkMetrics(false);
283
280
  });
284
281
 
285
282
  it('sends only roap when roap and local mute are requested', async () => {
@@ -296,9 +293,9 @@ describe('LocusMediaRequest.send()', () => {
296
293
  method: 'PUT',
297
294
  uri: 'fakeMeetingSelfUrl/media',
298
295
  body: createExpectedRoapBody('OFFER', {audioMuted: true, videoMuted: false}),
296
+ upload: sinon.match.instanceOf(EventEmitter),
297
+ download: sinon.match.instanceOf(EventEmitter),
299
298
  });
300
-
301
- checkMetrics();
302
299
  });
303
300
 
304
301
  describe('queueing', () => {
@@ -328,10 +325,10 @@ describe('LocusMediaRequest.send()', () => {
328
325
  * after the processing cycle from which it was called is finished.
329
326
  * This helper function waits for this to happen - it's needed, because we're using
330
327
  * fake timers in these tests
331
- */
328
+ */
332
329
  const ensureQueueProcessingIsStarted = () => {
333
330
  clock.tick(1);
334
- }
331
+ };
335
332
  it('queues requests if there is one already in progress', async () => {
336
333
  results.push(sendRoapMessage('OFFER'));
337
334
 
@@ -342,6 +339,8 @@ describe('LocusMediaRequest.send()', () => {
342
339
  method: 'PUT',
343
340
  uri: 'fakeMeetingSelfUrl/media',
344
341
  body: createExpectedRoapBody('OFFER', {audioMuted: true, videoMuted: true}),
342
+ upload: sinon.match.instanceOf(EventEmitter),
343
+ download: sinon.match.instanceOf(EventEmitter),
345
344
  });
346
345
 
347
346
  webexRequestStub.resetHistory();
@@ -364,6 +363,8 @@ describe('LocusMediaRequest.send()', () => {
364
363
  method: 'PUT',
365
364
  uri: 'fakeMeetingSelfUrl/media',
366
365
  body: createExpectedRoapBody('OK', {audioMuted: true, videoMuted: true}),
366
+ upload: sinon.match.instanceOf(EventEmitter),
367
+ download: sinon.match.instanceOf(EventEmitter),
367
368
  });
368
369
 
369
370
  // promise returned by the first call to send OFFER should be resolved by now
@@ -386,6 +387,8 @@ describe('LocusMediaRequest.send()', () => {
386
387
  method: 'PUT',
387
388
  uri: 'fakeMeetingSelfUrl/media',
388
389
  body: createExpectedRoapBody('OFFER', {audioMuted: false, videoMuted: false}),
390
+ upload: sinon.match.instanceOf(EventEmitter),
391
+ download: sinon.match.instanceOf(EventEmitter),
389
392
  });
390
393
 
391
394
  webexRequestStub.resetHistory();
@@ -410,6 +413,8 @@ describe('LocusMediaRequest.send()', () => {
410
413
  method: 'PUT',
411
414
  uri: 'fakeMeetingSelfUrl/media',
412
415
  body: createExpectedRoapBody('OK', {audioMuted: false, videoMuted: true}),
416
+ upload: sinon.match.instanceOf(EventEmitter),
417
+ download: sinon.match.instanceOf(EventEmitter),
413
418
  });
414
419
 
415
420
  // promise returned by the first call to send OFFER should be resolved by now
@@ -438,16 +443,17 @@ describe('LocusMediaRequest.send()', () => {
438
443
 
439
444
  ensureQueueProcessingIsStarted();
440
445
 
441
- sendLocalMute({audioMuted: false, videoMuted: true})
442
- .then((response) => {
443
- result = response;
444
- });
446
+ sendLocalMute({audioMuted: false, videoMuted: true}).then((response) => {
447
+ result = response;
448
+ });
445
449
 
446
450
  // only roap offer should have been sent so far
447
451
  assert.calledOnceWithExactly(webexRequestStub, {
448
452
  method: 'PUT',
449
453
  uri: 'fakeMeetingSelfUrl/media',
450
454
  body: createExpectedRoapBody('OFFER', {audioMuted: true, videoMuted: true}),
455
+ upload: sinon.match.instanceOf(EventEmitter),
456
+ download: sinon.match.instanceOf(EventEmitter),
451
457
  });
452
458
  assert.equal(result, undefined); // sendLocalMute shouldn't resolve yet, as the request should be queued
453
459
  assert.equal(locusMediaRequest.isConfluenceCreated(), false);
@@ -464,10 +470,12 @@ describe('LocusMediaRequest.send()', () => {
464
470
  method: 'PUT',
465
471
  uri: 'fakeMeetingSelfUrl/media',
466
472
  body: createExpectedLocalMuteBody({audioMuted: false, videoMuted: true}),
473
+ upload: sinon.match.instanceOf(EventEmitter),
474
+ download: sinon.match.instanceOf(EventEmitter),
467
475
  });
468
476
 
469
477
  // check also the result once Locus replies to local mute
470
- const fakeLocusResponse = { response: 'ok'};
478
+ const fakeLocusResponse = {response: 'ok'};
471
479
  requestsToLocus[1].resolve(fakeLocusResponse);
472
480
  await testUtils.flushPromises();
473
481
  assert.deepEqual(result, fakeLocusResponse);
@@ -487,10 +495,9 @@ describe('LocusMediaRequest.send()', () => {
487
495
  assert.equal(locusMediaRequest.isConfluenceCreated(), true);
488
496
 
489
497
  // now send local mute
490
- sendLocalMute({audioMuted: false, videoMuted: true})
491
- .then((response) => {
492
- result = response;
493
- });
498
+ sendLocalMute({audioMuted: false, videoMuted: true}).then((response) => {
499
+ result = response;
500
+ });
494
501
 
495
502
  ensureQueueProcessingIsStarted();
496
503
 
@@ -499,8 +506,9 @@ describe('LocusMediaRequest.send()', () => {
499
506
  method: 'PUT',
500
507
  uri: 'fakeMeetingSelfUrl/media',
501
508
  body: createExpectedLocalMuteBody({audioMuted: false, videoMuted: true}),
509
+ upload: sinon.match.instanceOf(EventEmitter),
510
+ download: sinon.match.instanceOf(EventEmitter),
502
511
  });
503
512
  });
504
-
505
513
  });
506
- })
514
+ });
@@ -2,7 +2,6 @@ import sinon from 'sinon';
2
2
  import {assert} from '@webex/test-helper-chai';
3
3
  import MeetingUtil from '@webex/plugin-meetings/src/meeting/util';
4
4
  import {createMuteState, MuteState} from '@webex/plugin-meetings/src/meeting/muteState';
5
- import PermissionError from '@webex/plugin-meetings/src/common/errors/permission';
6
5
  import {AUDIO, VIDEO} from '@webex/plugin-meetings/src/constants';
7
6
 
8
7
  import testUtils from '../../../utils/testUtils';
@@ -39,7 +38,6 @@ describe('plugin-meetings', () => {
39
38
  unmuteAllowed: true,
40
39
  remoteVideoMuted: false,
41
40
  unmuteVideoAllowed: true,
42
-
43
41
  locusInfo: {
44
42
  handleLocusDelta: sinon.stub(),
45
43
  },
@@ -1,4 +1,5 @@
1
1
  import 'jsdom-global/register';
2
+ import {v4 as uuidv4} from 'uuid';
2
3
  import sinon from 'sinon';
3
4
  import {assert} from '@webex/test-helper-chai';
4
5
  import MockWebex from '@webex/test-helper-mock-webex';
@@ -205,7 +206,7 @@ describe('plugin-meetings', () => {
205
206
  roapMessage,
206
207
  reachability,
207
208
  permissionToken,
208
- clientMediaPreferences
209
+ clientMediaPreferences,
209
210
  });
210
211
  const requestParams = meetingsRequest.request.getCall(0).args[0];
211
212
 
@@ -630,6 +631,36 @@ describe('plugin-meetings', () => {
630
631
  });
631
632
  });
632
633
 
634
+ describe('#setPostMeetingDataConsent', () => {
635
+ [true, false].forEach((consent) => {
636
+ it(`sends request to set post meeting data consent with ${consent}`, async () => {
637
+ const locusUrl = `https://locus-test.wbx2.com/locus/api/v1/loci/${consent}`;
638
+ const selfId = uuidv4();
639
+ const deviceUrl = `https://wdm-test.wbx2.com/wdm/api/v1/devices/${consent}`;
640
+
641
+ const consentPromise = meetingsRequest.setPostMeetingDataConsent({
642
+ postMeetingDataConsent: consent,
643
+ locusUrl,
644
+ selfId,
645
+ deviceUrl,
646
+ });
647
+ assert.exists(consentPromise.then);
648
+ await consentPromise;
649
+
650
+ checkRequest({
651
+ method: 'PATCH',
652
+ uri: `${locusUrl}/participant/${selfId}/controls`,
653
+ body: {
654
+ consent: {
655
+ postMeetingDataConsent: consent,
656
+ deviceUrl,
657
+ },
658
+ },
659
+ });
660
+ });
661
+ });
662
+ });
663
+
633
664
  describe('#prepareLeaveMeetingRequestOptions', () => {
634
665
  it('returns expected result', async () => {
635
666
  const result = meetingsRequest.prepareLeaveMeetingRequestOptions({
@@ -66,7 +66,7 @@ describe('plugin-meetings', () => {
66
66
 
67
67
  describe('#cleanup', () => {
68
68
  it('do clean up on meeting object with LLM enabled', async () => {
69
- meeting.config = {enableAutomaticLLM : true};
69
+ meeting.config = {enableAutomaticLLM: true};
70
70
  await MeetingUtil.cleanUp(meeting);
71
71
  assert.calledOnce(meeting.cleanupLocalStreams);
72
72
  assert.calledOnce(meeting.closeRemoteStreams);
@@ -84,7 +84,7 @@ describe('plugin-meetings', () => {
84
84
  });
85
85
 
86
86
  it('do clean up on meeting object with LLM disabled', async () => {
87
- meeting.config = {enableAutomaticLLM : false};
87
+ meeting.config = {enableAutomaticLLM: false};
88
88
  await MeetingUtil.cleanUp(meeting);
89
89
  assert.calledOnce(meeting.cleanupLocalStreams);
90
90
  assert.calledOnce(meeting.closeRemoteStreams);
@@ -392,8 +392,7 @@ describe('plugin-meetings', () => {
392
392
  meetingJoinUrl: 'meetingJoinUrl',
393
393
  locusUrl: 'locusUrl',
394
394
  meetingRequest: {
395
- joinMeeting: sinon.stub().returns(
396
- Promise.resolve(joinMeetingResponse)),
395
+ joinMeeting: sinon.stub().returns(Promise.resolve(joinMeetingResponse)),
397
396
  },
398
397
  getWebexObject: sinon.stub().returns(webex),
399
398
  setLocus: sinon.stub(),
@@ -410,23 +409,29 @@ describe('plugin-meetings', () => {
410
409
  id: 'fake client media preferences',
411
410
  };
412
411
 
413
- webex.meetings.reachability.getReachabilityReportToAttachToRoap.resolves(FAKE_REACHABILITY_REPORT);
414
- webex.meetings.reachability.getClientMediaPreferences.resolves(FAKE_CLIENT_MEDIA_PREFERENCES);
412
+ webex.meetings.reachability.getReachabilityReportToAttachToRoap.resolves(
413
+ FAKE_REACHABILITY_REPORT
414
+ );
415
+ webex.meetings.reachability.getClientMediaPreferences.resolves(
416
+ FAKE_CLIENT_MEDIA_PREFERENCES
417
+ );
415
418
 
416
- sinon
417
- .stub(webex.internal.device.ipNetworkDetector, 'supportsIpV4')
418
- .get(() => true);
419
- sinon
420
- .stub(webex.internal.device.ipNetworkDetector, 'supportsIpV6')
421
- .get(() => true);
419
+ sinon.stub(webex.internal.device.ipNetworkDetector, 'supportsIpV4').get(() => true);
420
+ sinon.stub(webex.internal.device.ipNetworkDetector, 'supportsIpV6').get(() => true);
422
421
 
423
422
  await MeetingUtil.joinMeeting(meeting, {
424
423
  reachability: 'reachability',
425
424
  roapMessage: 'roapMessage',
426
425
  });
427
426
 
428
- assert.calledOnceWithExactly(webex.meetings.reachability.getReachabilityReportToAttachToRoap);
429
- assert.calledOnceWithExactly(webex.meetings.reachability.getClientMediaPreferences, meeting.isMultistream, IP_VERSION.ipv4_and_ipv6);
427
+ assert.calledOnceWithExactly(
428
+ webex.meetings.reachability.getReachabilityReportToAttachToRoap
429
+ );
430
+ assert.calledOnceWithExactly(
431
+ webex.meetings.reachability.getClientMediaPreferences,
432
+ meeting.isMultistream,
433
+ IP_VERSION.ipv4_and_ipv6
434
+ );
430
435
 
431
436
  assert.calledOnce(meeting.meetingRequest.joinMeeting);
432
437
  const parameter = meeting.meetingRequest.joinMeeting.getCall(0).args[0];
@@ -436,9 +441,9 @@ describe('plugin-meetings', () => {
436
441
  assert.equal(parameter.clientMediaPreferences, FAKE_CLIENT_MEDIA_PREFERENCES);
437
442
  assert.equal(parameter.roapMessage, 'roapMessage');
438
443
 
439
- assert.calledOnce(meeting.setLocus)
444
+ assert.calledOnce(meeting.setLocus);
440
445
  const setLocusParameter = meeting.setLocus.getCall(0).args[0];
441
- assert.deepEqual(setLocusParameter, MeetingUtil.parseLocusJoin(joinMeetingResponse))
446
+ assert.deepEqual(setLocusParameter, MeetingUtil.parseLocusJoin(joinMeetingResponse));
442
447
 
443
448
  assert.calledWith(webex.internal.newMetrics.submitClientEvent, {
444
449
  name: 'client.locus.join.request',
@@ -460,6 +465,49 @@ describe('plugin-meetings', () => {
460
465
  });
461
466
  });
462
467
 
468
+ it('#Should call `meetingRequest.joinMeeting and handle a date header in the response : isoLocalClientMeetingJoinedTime', async () => {
469
+ meeting.isMultistream = true;
470
+
471
+ const FAKE_REACHABILITY_REPORT = {
472
+ id: 'fake reachability report',
473
+ };
474
+ const FAKE_CLIENT_MEDIA_PREFERENCES = {
475
+ id: 'fake client media preferences',
476
+ };
477
+
478
+ webex.meetings.reachability.getReachabilityReportToAttachToRoap.resolves(
479
+ FAKE_REACHABILITY_REPORT
480
+ );
481
+ webex.meetings.reachability.getClientMediaPreferences.resolves(
482
+ FAKE_CLIENT_MEDIA_PREFERENCES
483
+ );
484
+
485
+ sinon.stub(webex.internal.device.ipNetworkDetector, 'supportsIpV4').get(() => true);
486
+ sinon.stub(webex.internal.device.ipNetworkDetector, 'supportsIpV6').get(() => true);
487
+
488
+ meeting.meetingRequest.joinMeeting.resolves({
489
+ headers: {
490
+ date: 'test',
491
+ },
492
+ body: {
493
+ mediaConnections: [{mediaId: 'test'}],
494
+ locus: {
495
+ url: 'test',
496
+ self: {
497
+ id: 'test',
498
+ },
499
+ },
500
+ },
501
+ });
502
+
503
+ await MeetingUtil.joinMeeting(meeting, {
504
+ reachability: 'reachability',
505
+ roapMessage: 'roapMessage',
506
+ });
507
+
508
+ assert.equal(meeting.isoLocalClientMeetingJoinTime, 'test');
509
+ });
510
+
463
511
  it('should handle failed reachability report retrieval', async () => {
464
512
  webex.meetings.reachability.getReachabilityReportToAttachToRoap.rejects(
465
513
  new Error('fake error')
@@ -516,6 +564,17 @@ describe('plugin-meetings', () => {
516
564
  assert.equal(parameter.liveAnnotationSupported, true);
517
565
  });
518
566
 
567
+ it('#Should call meetingRequest.joinMeeting with alias passed through', async () => {
568
+ await MeetingUtil.joinMeeting(meeting, {
569
+ alias: 'alias name',
570
+ });
571
+
572
+ assert.calledOnce(meeting.meetingRequest.joinMeeting);
573
+ const parameter = meeting.meetingRequest.joinMeeting.getCall(0).args[0];
574
+
575
+ assert.equal(parameter.alias, 'alias name');
576
+ });
577
+
519
578
  it('#Should call meetingRequest.joinMeeting with locale=en_UK, deviceCapabilities=["TEST"] when they are passed in as those values', async () => {
520
579
  await MeetingUtil.joinMeeting(meeting, {
521
580
  locale: 'en_UK',
@@ -685,6 +744,18 @@ describe('plugin-meetings', () => {
685
744
  });
686
745
  });
687
746
 
747
+ describe('requiresPostMeetingDataConsentPrompt', () => {
748
+ it('works as expected', () => {
749
+ assert.deepEqual(
750
+ MeetingUtil.requiresPostMeetingDataConsentPrompt([
751
+ 'SHOW_POST_MEETING_DATA_CONSENT_PROMPT',
752
+ ]),
753
+ true
754
+ );
755
+ assert.deepEqual(MeetingUtil.requiresPostMeetingDataConsentPrompt([]), false);
756
+ });
757
+ });
758
+
688
759
  describe('canUserRenameOthers', () => {
689
760
  it('works as expected', () => {
690
761
  assert.deepEqual(MeetingUtil.canUserRenameOthers(['CAN_RENAME_OTHERS']), true);
@@ -694,8 +765,34 @@ describe('plugin-meetings', () => {
694
765
 
695
766
  describe('canShareWhiteBoard', () => {
696
767
  it('works as expected', () => {
697
- assert.deepEqual(MeetingUtil.canShareWhiteBoard(['SHARE_WHITEBOARD']), true);
698
- assert.deepEqual(MeetingUtil.canShareWhiteBoard([]), false);
768
+ assert.deepEqual(
769
+ MeetingUtil.canShareWhiteBoard(['SHARE_WHITEBOARD'], {
770
+ [SELF_POLICY.SUPPORT_WHITEBOARD]: true,
771
+ }),
772
+ true
773
+ );
774
+ assert.deepEqual(
775
+ MeetingUtil.canShareWhiteBoard([], {
776
+ [SELF_POLICY.SUPPORT_WHITEBOARD]: true,
777
+ }),
778
+ false
779
+ );
780
+ assert.deepEqual(
781
+ MeetingUtil.canShareWhiteBoard(['SHARE_WHITEBOARD'], {
782
+ [SELF_POLICY.SUPPORT_WHITEBOARD]: false,
783
+ }),
784
+ false
785
+ );
786
+ assert.deepEqual(
787
+ MeetingUtil.canShareWhiteBoard([], {
788
+ [SELF_POLICY.SUPPORT_WHITEBOARD]: false,
789
+ }),
790
+ false
791
+ );
792
+ assert.deepEqual(
793
+ MeetingUtil.canShareWhiteBoard(['SHARE_WHITEBOARD'], undefined),
794
+ false
795
+ );
699
796
  });
700
797
  });
701
798