@webex/plugin-meetings 3.0.0-beta.27 → 3.0.0-beta.29
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 +22 -1
- package/dist/breakouts/breakout.js.map +1 -1
- package/dist/breakouts/index.js +59 -1
- package/dist/breakouts/index.js.map +1 -1
- package/dist/breakouts/request.js +78 -0
- package/dist/breakouts/request.js.map +1 -0
- package/dist/breakouts/utils.js +23 -0
- package/dist/breakouts/utils.js.map +1 -0
- package/dist/members/index.js +1 -0
- package/dist/members/index.js.map +1 -1
- package/dist/multistream/receiveSlot.js +9 -0
- package/dist/multistream/receiveSlot.js.map +1 -1
- package/dist/multistream/receiveSlotManager.js +15 -0
- package/dist/multistream/receiveSlotManager.js.map +1 -1
- package/dist/types/breakouts/request.d.ts +22 -0
- package/dist/types/breakouts/utils.d.ts +1 -0
- package/dist/types/multistream/receiveSlot.d.ts +3 -1
- package/dist/types/multistream/receiveSlotManager.d.ts +5 -0
- package/package.json +18 -18
- package/src/breakouts/README.md +2 -2
- package/src/breakouts/breakout.ts +20 -0
- package/src/breakouts/index.ts +58 -2
- package/src/breakouts/request.ts +55 -0
- package/src/breakouts/utils.ts +15 -0
- package/src/members/index.ts +2 -0
- package/src/multistream/receiveSlot.ts +8 -1
- package/src/multistream/receiveSlotManager.ts +12 -0
- package/test/unit/spec/breakouts/breakout.ts +32 -4
- package/test/unit/spec/breakouts/index.ts +105 -10
- package/test/unit/spec/breakouts/request.ts +104 -0
- package/test/unit/spec/breakouts/utils.js +21 -0
- package/test/unit/spec/multistream/receiveSlot.ts +36 -0
- package/test/unit/spec/multistream/receiveSlotManager.ts +28 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import {StatelessWebexPlugin} from '@webex/webex-core';
|
|
2
|
+
import LoggerProxy from '../common/logs/logger-proxy';
|
|
3
|
+
import {getBroadcastRoles} from './utils';
|
|
4
|
+
import {HTTP_VERBS} from '../constants';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @class BreakoutRequest
|
|
8
|
+
*/
|
|
9
|
+
export default class BreakoutRequest extends StatelessWebexPlugin {
|
|
10
|
+
/**
|
|
11
|
+
* Broadcast message to all breakout session's participants
|
|
12
|
+
* @param {String} url
|
|
13
|
+
* @param {String} message
|
|
14
|
+
* @param {Object} options
|
|
15
|
+
* @param {string} groupId
|
|
16
|
+
* @param {string} sessionId
|
|
17
|
+
* @returns {Promise}
|
|
18
|
+
*/
|
|
19
|
+
broadcast({
|
|
20
|
+
url,
|
|
21
|
+
message,
|
|
22
|
+
options,
|
|
23
|
+
groupId,
|
|
24
|
+
sessionId,
|
|
25
|
+
}: {
|
|
26
|
+
url: string;
|
|
27
|
+
message: string;
|
|
28
|
+
options?: object;
|
|
29
|
+
groupId: string;
|
|
30
|
+
sessionId?: string;
|
|
31
|
+
}) {
|
|
32
|
+
const roles = getBroadcastRoles(options);
|
|
33
|
+
const params = {
|
|
34
|
+
id: groupId,
|
|
35
|
+
recipientRoles: roles.length ? roles : undefined,
|
|
36
|
+
sessions: sessionId ? [{id: sessionId}] : undefined,
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// @ts-ignore
|
|
40
|
+
return this.request({
|
|
41
|
+
method: HTTP_VERBS.POST,
|
|
42
|
+
uri: `${url}/message`,
|
|
43
|
+
body: {
|
|
44
|
+
message,
|
|
45
|
+
groups: [params],
|
|
46
|
+
},
|
|
47
|
+
}).catch((error) => {
|
|
48
|
+
if (error.body && error.body.errorCode === 201409036 && error.statusCode === 409) {
|
|
49
|
+
LoggerProxy.logger.info(`Breakouts#broadcast --> no joined participants`);
|
|
50
|
+
} else {
|
|
51
|
+
throw error;
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// eslint-disable-next-line import/prefer-default-export
|
|
2
|
+
export const getBroadcastRoles = (options): string[] => {
|
|
3
|
+
const recipientRoles = [];
|
|
4
|
+
if (!options || (!options.cohosts && !options.presenters)) {
|
|
5
|
+
return recipientRoles;
|
|
6
|
+
}
|
|
7
|
+
if (options.cohosts) {
|
|
8
|
+
recipientRoles.push('COHOST');
|
|
9
|
+
}
|
|
10
|
+
if (options.presenters) {
|
|
11
|
+
recipientRoles.push('PRESENTER');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return recipientRoles;
|
|
15
|
+
};
|
package/src/members/index.ts
CHANGED
|
@@ -296,6 +296,8 @@ export default class Members extends StatelessWebexPlugin {
|
|
|
296
296
|
const delta = this.handleLocusInfoUpdatedParticipants(payload);
|
|
297
297
|
const full = this.handleMembersUpdate(delta); // SDK should propagate the full list for both delta and non delta updates
|
|
298
298
|
|
|
299
|
+
this.receiveSlotManager.updateMemberIds();
|
|
300
|
+
|
|
299
301
|
Trigger.trigger(
|
|
300
302
|
this,
|
|
301
303
|
{
|
|
@@ -91,7 +91,7 @@ export class ReceiveSlot extends EventsScope {
|
|
|
91
91
|
/**
|
|
92
92
|
* registers event handlers with the underlying ReceiveSlot
|
|
93
93
|
*/
|
|
94
|
-
setupEventListeners() {
|
|
94
|
+
private setupEventListeners() {
|
|
95
95
|
const scope = {
|
|
96
96
|
file: 'meeting/receiveSlot',
|
|
97
97
|
function: 'setupEventListeners',
|
|
@@ -116,6 +116,13 @@ export class ReceiveSlot extends EventsScope {
|
|
|
116
116
|
);
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
+
/** Tries to find the member id for this receive slot if it hasn't got one */
|
|
120
|
+
public findMemberId() {
|
|
121
|
+
if (this.#memberId === undefined && this.#csi) {
|
|
122
|
+
this.#memberId = this.findMemberIdCallback(this.#csi);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
119
126
|
/**
|
|
120
127
|
* The MediaStream object associated with this slot.
|
|
121
128
|
*
|
|
@@ -141,4 +141,16 @@ export class ReceiveSlotManager {
|
|
|
141
141
|
numFreeSlots,
|
|
142
142
|
};
|
|
143
143
|
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Tries to find the member id on all allocated receive slots
|
|
147
|
+
* This function should be called when new members are added to the meeting.
|
|
148
|
+
*/
|
|
149
|
+
updateMemberIds() {
|
|
150
|
+
Object.keys(this.allocatedSlots).forEach((key) => {
|
|
151
|
+
this.allocatedSlots[key].forEach((slot: ReceiveSlot) => {
|
|
152
|
+
slot.findMemberId();
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
}
|
|
144
156
|
}
|
|
@@ -35,7 +35,7 @@ describe('plugin-meetings', () => {
|
|
|
35
35
|
describe('#join', () => {
|
|
36
36
|
it('makes the request as expected', async () => {
|
|
37
37
|
const result = await breakout.join()
|
|
38
|
-
|
|
38
|
+
|
|
39
39
|
assert.calledOnceWithExactly(webex.request, {
|
|
40
40
|
method: 'POST',
|
|
41
41
|
uri: 'url/move',
|
|
@@ -44,7 +44,7 @@ describe('plugin-meetings', () => {
|
|
|
44
44
|
sessionId: 'sessionId'
|
|
45
45
|
}
|
|
46
46
|
});
|
|
47
|
-
|
|
47
|
+
|
|
48
48
|
assert.equal(result, 'REQUEST_RETURN_VALUE')
|
|
49
49
|
});
|
|
50
50
|
});
|
|
@@ -88,7 +88,7 @@ describe('plugin-meetings', () => {
|
|
|
88
88
|
describe('#askForHelp', () => {
|
|
89
89
|
it('makes the request as expected', async () => {
|
|
90
90
|
const result = await breakout.askForHelp()
|
|
91
|
-
|
|
91
|
+
|
|
92
92
|
assert.calledOnceWithExactly(webex.request, {
|
|
93
93
|
method: 'POST',
|
|
94
94
|
uri: 'url/help',
|
|
@@ -97,7 +97,35 @@ describe('plugin-meetings', () => {
|
|
|
97
97
|
sessionId: 'sessionId'
|
|
98
98
|
}
|
|
99
99
|
});
|
|
100
|
-
|
|
100
|
+
|
|
101
|
+
assert.equal(result, 'REQUEST_RETURN_VALUE')
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
describe('#broadcast', () => {
|
|
106
|
+
it('makes the request as expected', async () => {
|
|
107
|
+
breakout.breakoutRequest.broadcast = sinon.stub().returns(Promise.resolve('REQUEST_RETURN_VALUE'));
|
|
108
|
+
let result = await breakout.broadcast('hello')
|
|
109
|
+
assert.calledWithExactly(breakout.breakoutRequest.broadcast, {
|
|
110
|
+
url: 'url',
|
|
111
|
+
message: 'hello',
|
|
112
|
+
options: undefined,
|
|
113
|
+
groupId: 'groupId',
|
|
114
|
+
sessionId: 'sessionId'
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
assert.equal(result, 'REQUEST_RETURN_VALUE')
|
|
118
|
+
|
|
119
|
+
result = await breakout.broadcast('hello', {presenters: true, cohosts: true})
|
|
120
|
+
|
|
121
|
+
assert.calledWithExactly(breakout.breakoutRequest.broadcast, {
|
|
122
|
+
url: 'url',
|
|
123
|
+
message: 'hello',
|
|
124
|
+
options: {presenters: true, cohosts: true},
|
|
125
|
+
groupId: 'groupId',
|
|
126
|
+
sessionId: 'sessionId'
|
|
127
|
+
});
|
|
128
|
+
|
|
101
129
|
assert.equal(result, 'REQUEST_RETURN_VALUE')
|
|
102
130
|
});
|
|
103
131
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {assert} from '@webex/test-helper-chai';
|
|
1
|
+
import {assert, expect} from '@webex/test-helper-chai';
|
|
2
2
|
import Breakout from '@webex/plugin-meetings/src/breakouts/breakout';
|
|
3
3
|
import Breakouts from '@webex/plugin-meetings/src/breakouts';
|
|
4
4
|
import BreakoutCollection from '@webex/plugin-meetings/src/breakouts/collection';
|
|
@@ -20,9 +20,11 @@ describe('plugin-meetings', () => {
|
|
|
20
20
|
webex.internal.llm.on = sinon.stub();
|
|
21
21
|
webex.internal.mercury.on = sinon.stub();
|
|
22
22
|
breakouts = new Breakouts({}, {parent: webex});
|
|
23
|
+
breakouts.groupId = 'groupId';
|
|
24
|
+
breakouts.sessionId = 'sessionId';
|
|
25
|
+
breakouts.url = 'url';
|
|
23
26
|
breakouts.locusUrl = 'locusUrl';
|
|
24
27
|
breakouts.breakoutServiceUrl = 'breakoutServiceUrl';
|
|
25
|
-
breakouts.url = 'url';
|
|
26
28
|
webex.request = sinon.stub().returns(Promise.resolve('REQUEST_RETURN_VALUE'));
|
|
27
29
|
});
|
|
28
30
|
|
|
@@ -31,7 +33,7 @@ describe('plugin-meetings', () => {
|
|
|
31
33
|
assert.equal(breakouts.namespace, 'Meetings');
|
|
32
34
|
});
|
|
33
35
|
|
|
34
|
-
it('emits BREAKOUTS_CLOSING event when the status is CLOSING', () => {
|
|
36
|
+
it('emits BREAKOUTS_CLOSING event when the status is CLOSING', () => {
|
|
35
37
|
let called = false;
|
|
36
38
|
breakouts.listenTo(breakouts, BREAKOUTS.EVENTS.BREAKOUTS_CLOSING, () => {
|
|
37
39
|
called = true;
|
|
@@ -58,7 +60,7 @@ describe('plugin-meetings', () => {
|
|
|
58
60
|
it('triggers message event when a message received', () => {
|
|
59
61
|
const call = webex.internal.llm.on.getCall(0);
|
|
60
62
|
const callback = call.args[1];
|
|
61
|
-
|
|
63
|
+
|
|
62
64
|
assert.equal(call.args[0], 'event:breakout.message');
|
|
63
65
|
|
|
64
66
|
let message;
|
|
@@ -90,7 +92,7 @@ describe('plugin-meetings', () => {
|
|
|
90
92
|
it('triggers member update event when a roster received', () => {
|
|
91
93
|
const call = webex.internal.mercury.on.getCall(0);
|
|
92
94
|
const callback = call.args[1];
|
|
93
|
-
|
|
95
|
+
|
|
94
96
|
assert.equal(call.args[0], 'event:breakout.roster');
|
|
95
97
|
|
|
96
98
|
let called = false;
|
|
@@ -204,9 +206,9 @@ describe('plugin-meetings', () => {
|
|
|
204
206
|
describe('#cleanUp', () => {
|
|
205
207
|
it('stops listening', () => {
|
|
206
208
|
breakouts.stopListening = sinon.stub();
|
|
207
|
-
|
|
209
|
+
|
|
208
210
|
breakouts.cleanUp();
|
|
209
|
-
|
|
211
|
+
|
|
210
212
|
assert.calledOnceWithExactly(breakouts.stopListening);
|
|
211
213
|
});
|
|
212
214
|
});
|
|
@@ -230,7 +232,7 @@ describe('plugin-meetings', () => {
|
|
|
230
232
|
});
|
|
231
233
|
|
|
232
234
|
describe('#queryRosters', () => {
|
|
233
|
-
|
|
235
|
+
|
|
234
236
|
it('makes the expected query', async () => {
|
|
235
237
|
|
|
236
238
|
webex.request.returns(Promise.resolve({
|
|
@@ -249,7 +251,7 @@ describe('plugin-meetings', () => {
|
|
|
249
251
|
breakouts.handleRosterUpdate = sinon.stub();
|
|
250
252
|
|
|
251
253
|
const result = await breakouts.queryRosters();
|
|
252
|
-
|
|
254
|
+
|
|
253
255
|
assert.calledOnceWithExactly(webex.request, {
|
|
254
256
|
uri: 'url/roster',
|
|
255
257
|
qs: { locusUrl: 'dGVzdA==' }
|
|
@@ -293,6 +295,67 @@ describe('plugin-meetings', () => {
|
|
|
293
295
|
});
|
|
294
296
|
});
|
|
295
297
|
|
|
298
|
+
describe('#getMainSession', () => {
|
|
299
|
+
it('returns main session as expect', () => {
|
|
300
|
+
breakouts.updateBreakout({
|
|
301
|
+
sessionId: 'sessionId',
|
|
302
|
+
groupId: 'groupId',
|
|
303
|
+
sessionType: 'sessionType',
|
|
304
|
+
url: 'url',
|
|
305
|
+
name: 'name',
|
|
306
|
+
allowBackToMain: true,
|
|
307
|
+
delayCloseTime: 10,
|
|
308
|
+
enableBreakoutSession: true,
|
|
309
|
+
startTime: 'startTime',
|
|
310
|
+
status: 'active',
|
|
311
|
+
locusUrl: 'locusUrl'
|
|
312
|
+
});
|
|
313
|
+
const payload = {
|
|
314
|
+
breakoutSessions: {
|
|
315
|
+
active: [{sessionId: 'sessionId1'}],
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
breakouts.updateBreakoutSessions(payload);
|
|
319
|
+
|
|
320
|
+
breakouts.set('sessionType', BREAKOUTS.SESSION_TYPES.MAIN);
|
|
321
|
+
let result = breakouts.getMainSession();
|
|
322
|
+
assert.equal(result.sessionId, 'sessionId');
|
|
323
|
+
|
|
324
|
+
const payload2 = {
|
|
325
|
+
breakoutSessions: {
|
|
326
|
+
active: [{sessionId: 'sessionId1', sessionType: BREAKOUTS.SESSION_TYPES.MAIN}],
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
breakouts.updateBreakoutSessions(payload2);
|
|
330
|
+
breakouts.set('sessionType', 'BREAKOUT');
|
|
331
|
+
result = breakouts.getMainSession();
|
|
332
|
+
assert.equal(result.sessionId, 'sessionId1');
|
|
333
|
+
});
|
|
334
|
+
it('throw error if cannot find main session', () => {
|
|
335
|
+
const fn = () => {
|
|
336
|
+
breakouts.getMainSession();
|
|
337
|
+
}
|
|
338
|
+
expect(fn).to.throw(/no main session found/);
|
|
339
|
+
});
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
describe('#askAllToReturn', () => {
|
|
343
|
+
it('makes the request as expected', async () => {
|
|
344
|
+
breakouts.set('sessionType', BREAKOUTS.SESSION_TYPES.MAIN);
|
|
345
|
+
breakouts.currentBreakoutSession.sessionId = 'sessionId';
|
|
346
|
+
breakouts.currentBreakoutSession.groupId = 'groupId';
|
|
347
|
+
const result = await breakouts.askAllToReturn();
|
|
348
|
+
assert.calledOnceWithExactly(webex.request, {
|
|
349
|
+
method: 'POST',
|
|
350
|
+
uri: 'url/requestMove',
|
|
351
|
+
body: {
|
|
352
|
+
groupId: 'groupId',
|
|
353
|
+
sessionId: 'sessionId'
|
|
354
|
+
}
|
|
355
|
+
});
|
|
356
|
+
});
|
|
357
|
+
});
|
|
358
|
+
|
|
296
359
|
describe('#breakoutServiceUrlUpdate', () => {
|
|
297
360
|
it('sets the breakoutService url', () => {
|
|
298
361
|
breakouts.breakoutServiceUrlUpdate('newBreakoutServiceUrl');
|
|
@@ -313,7 +376,7 @@ describe('plugin-meetings', () => {
|
|
|
313
376
|
}}))
|
|
314
377
|
breakouts.updateBreakout = sinon.stub().resolves();
|
|
315
378
|
breakouts.doToggleBreakout = sinon.stub().resolves();
|
|
316
|
-
|
|
379
|
+
|
|
317
380
|
await breakouts.toggleBreakout(false);
|
|
318
381
|
assert.calledOnceWithExactly(breakouts.enableBreakouts);
|
|
319
382
|
assert.calledOnceWithExactly(breakouts.updateBreakout, {
|
|
@@ -351,6 +414,38 @@ describe('plugin-meetings', () => {
|
|
|
351
414
|
});
|
|
352
415
|
});
|
|
353
416
|
|
|
417
|
+
describe('#broadcast', () => {
|
|
418
|
+
it('makes the request as expected', async () => {
|
|
419
|
+
breakouts.breakoutRequest.broadcast = sinon.stub().returns(Promise.resolve('REQUEST_RETURN_VALUE'));
|
|
420
|
+
let result = await breakouts.broadcast('hello');
|
|
421
|
+
assert.calledWithExactly(breakouts.breakoutRequest.broadcast, {
|
|
422
|
+
url: 'url',
|
|
423
|
+
message: 'hello',
|
|
424
|
+
options: undefined,
|
|
425
|
+
groupId: 'groupId'
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
assert.equal(result, 'REQUEST_RETURN_VALUE');
|
|
429
|
+
|
|
430
|
+
result = await breakouts.broadcast('hello', {presenters: true, cohosts: true});
|
|
431
|
+
assert.calledWithExactly(breakouts.breakoutRequest.broadcast, {
|
|
432
|
+
url: 'url',
|
|
433
|
+
groupId: 'groupId',
|
|
434
|
+
message: 'hello',
|
|
435
|
+
options: {presenters: true, cohosts: true}
|
|
436
|
+
});
|
|
437
|
+
assert.equal(result, 'REQUEST_RETURN_VALUE')
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
it('throw error if no breakout group id found', () => {
|
|
441
|
+
breakouts.set('sessionType', BREAKOUTS.SESSION_TYPES.MAIN);
|
|
442
|
+
const fn = () => {
|
|
443
|
+
breakouts.broadcast('hello');
|
|
444
|
+
}
|
|
445
|
+
expect(fn).to.throw(/no breakout session found/);
|
|
446
|
+
});
|
|
447
|
+
});
|
|
448
|
+
|
|
354
449
|
describe('doToggleBreakout', () => {
|
|
355
450
|
it('makes the request as expected', async () => {
|
|
356
451
|
const result = await breakouts.doToggleBreakout(true);
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import sinon from 'sinon';
|
|
2
|
+
import {assert, expect} from '@webex/test-helper-chai';
|
|
3
|
+
import MockWebex from '@webex/test-helper-mock-webex';
|
|
4
|
+
import BreakoutRequest from "@webex/plugin-meetings/src/breakouts/request";
|
|
5
|
+
import LoggerProxy from '@webex/plugin-meetings/src/common/logs/logger-proxy';
|
|
6
|
+
|
|
7
|
+
describe('plugin-meetings', () => {
|
|
8
|
+
describe('BreakoutRequest', () => {
|
|
9
|
+
let webex;
|
|
10
|
+
let breakoutRequest;
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
// @ts-ignore
|
|
13
|
+
webex = new MockWebex({});
|
|
14
|
+
// @ts-ignore
|
|
15
|
+
breakoutRequest = new BreakoutRequest({webex});
|
|
16
|
+
webex.request = sinon.stub().returns(Promise.resolve('REQUEST_RETURN_VALUE'));
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
describe('#broadcast', () => {
|
|
20
|
+
it('makes request as expected', async () => {
|
|
21
|
+
let result = await breakoutRequest.broadcast({url: 'url', message: 'hello', groupId: 'groupId'});
|
|
22
|
+
assert.calledWithExactly(webex.request, {
|
|
23
|
+
method: 'POST',
|
|
24
|
+
uri: 'url/message',
|
|
25
|
+
body: {
|
|
26
|
+
message: 'hello',
|
|
27
|
+
groups: [{
|
|
28
|
+
id: 'groupId',
|
|
29
|
+
recipientRoles: undefined,
|
|
30
|
+
sessions: undefined
|
|
31
|
+
}],
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
assert.equal(result, 'REQUEST_RETURN_VALUE');
|
|
35
|
+
|
|
36
|
+
result = await breakoutRequest.broadcast({
|
|
37
|
+
url: 'url',
|
|
38
|
+
message: 'hello',
|
|
39
|
+
groupId: 'groupId',
|
|
40
|
+
options: {
|
|
41
|
+
presenters: true,
|
|
42
|
+
cohosts: true
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
assert.calledWithExactly(webex.request, {
|
|
46
|
+
method: 'POST',
|
|
47
|
+
uri: 'url/message',
|
|
48
|
+
body: {
|
|
49
|
+
message: 'hello',
|
|
50
|
+
groups: [{
|
|
51
|
+
id: 'groupId',
|
|
52
|
+
recipientRoles: ['COHOST', 'PRESENTER'],
|
|
53
|
+
sessions: undefined
|
|
54
|
+
}]
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
assert.equal(result, 'REQUEST_RETURN_VALUE');
|
|
58
|
+
|
|
59
|
+
result = await breakoutRequest.broadcast({
|
|
60
|
+
url: 'url',
|
|
61
|
+
message: 'hello',
|
|
62
|
+
groupId: 'groupId',
|
|
63
|
+
options: {
|
|
64
|
+
presenters: true,
|
|
65
|
+
cohosts: true
|
|
66
|
+
},
|
|
67
|
+
sessionId: 'sessionId'
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
assert.calledWithExactly(webex.request, {
|
|
71
|
+
method: 'POST',
|
|
72
|
+
uri: 'url/message',
|
|
73
|
+
body: {
|
|
74
|
+
message: 'hello',
|
|
75
|
+
groups: [{
|
|
76
|
+
id: 'groupId',
|
|
77
|
+
recipientRoles: ['COHOST', 'PRESENTER'],
|
|
78
|
+
sessions: [{id: 'sessionId'}]
|
|
79
|
+
}]
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
assert.equal(result, 'REQUEST_RETURN_VALUE');
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('catch 409 error and log', async () => {
|
|
86
|
+
const error = {statusCode: 409, body: {errorCode: 201409036}};
|
|
87
|
+
webex.request.rejects(error);
|
|
88
|
+
LoggerProxy.logger.info = sinon.stub();
|
|
89
|
+
await breakoutRequest.broadcast({url: 'url', message: 'hello', groupId: 'groupId'});
|
|
90
|
+
assert.calledOnceWithExactly(
|
|
91
|
+
LoggerProxy.logger.info,
|
|
92
|
+
'Breakouts#broadcast --> no joined participants'
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
const otherError = new Error('something wrong');
|
|
96
|
+
webex.request.rejects(otherError);
|
|
97
|
+
LoggerProxy.logger.error = sinon.stub();
|
|
98
|
+
await breakoutRequest.broadcast({url: 'url', message: 'hello', groupId: 'groupId'}).catch((error) => {
|
|
99
|
+
assert.equal(error.toString(), 'Error: something wrong');
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import {assert} from '@webex/test-helper-chai';
|
|
2
|
+
import {getBroadcastRoles} from '@webex/plugin-meetings/src/breakouts/utils'
|
|
3
|
+
describe('plugin-meetings', () => {
|
|
4
|
+
describe('Breakouts utils', () => {
|
|
5
|
+
describe('#getBroadcastRoles', () => {
|
|
6
|
+
it('return expect roles', () => {
|
|
7
|
+
let roles = getBroadcastRoles();
|
|
8
|
+
assert.deepEqual(roles, []);
|
|
9
|
+
|
|
10
|
+
roles = getBroadcastRoles({cohosts: true});
|
|
11
|
+
assert.deepEqual(roles, ['COHOST']);
|
|
12
|
+
|
|
13
|
+
roles = getBroadcastRoles({presenters: true});
|
|
14
|
+
assert.deepEqual(roles, ['PRESENTER']);
|
|
15
|
+
|
|
16
|
+
roles = getBroadcastRoles({presenters: true, cohosts: true});
|
|
17
|
+
assert.deepEqual(roles, ['COHOST', 'PRESENTER']);
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
});
|
|
@@ -101,4 +101,40 @@ describe('ReceiveSlot', () => {
|
|
|
101
101
|
assert.strictEqual(receiveSlot.csi, undefined);
|
|
102
102
|
assert.strictEqual(receiveSlot.sourceState, 'no source');
|
|
103
103
|
});
|
|
104
|
+
|
|
105
|
+
describe('findMemberId()', () => {
|
|
106
|
+
it('doesn\'t do anything if csi is not set', () => {
|
|
107
|
+
// by default the receiveSlot does not have any csi or member id
|
|
108
|
+
receiveSlot.findMemberId();
|
|
109
|
+
|
|
110
|
+
assert.notCalled(findMemberIdCallbackStub);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('finds a member id if member id is undefined and CSI is known', () => {
|
|
114
|
+
// setup receiveSlot to have a csi without a member id
|
|
115
|
+
const csi = 12345;
|
|
116
|
+
fakeWcmeSlot.emit(WcmeReceiveSlotEvents.SourceUpdate, 'live', csi);
|
|
117
|
+
findMemberIdCallbackStub.reset();
|
|
118
|
+
|
|
119
|
+
receiveSlot.findMemberId();
|
|
120
|
+
|
|
121
|
+
assert.calledOnce(findMemberIdCallbackStub);
|
|
122
|
+
assert.calledWith(findMemberIdCallbackStub, csi);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('doesn\'t do anything if member id already set', () => {
|
|
126
|
+
// setup receiveSlot to have a csi and a member id
|
|
127
|
+
const csi = 12345;
|
|
128
|
+
const memberId = '12345678-1234-5678-9012-345678901234';
|
|
129
|
+
|
|
130
|
+
findMemberIdCallbackStub.returns(memberId);
|
|
131
|
+
|
|
132
|
+
fakeWcmeSlot.emit(WcmeReceiveSlotEvents.SourceUpdate, 'live', csi);
|
|
133
|
+
findMemberIdCallbackStub.reset();
|
|
134
|
+
|
|
135
|
+
receiveSlot.findMemberId();
|
|
136
|
+
|
|
137
|
+
assert.notCalled(findMemberIdCallbackStub);
|
|
138
|
+
});
|
|
139
|
+
});
|
|
104
140
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import sinon from 'sinon';
|
|
2
2
|
import {assert} from '@webex/test-helper-chai';
|
|
3
3
|
import {MediaType} from '@webex/internal-media-core';
|
|
4
|
+
import {ReceiveSlot} from '@webex/plugin-meetings/src/multistream/receiveSlot';
|
|
4
5
|
import {ReceiveSlotManager} from '@webex/plugin-meetings/src/multistream/receiveSlotManager';
|
|
5
6
|
import * as ReceiveSlotModule from '@webex/plugin-meetings/src/multistream/receiveSlot';
|
|
6
7
|
|
|
@@ -30,6 +31,7 @@ describe('ReceiveSlotManager', () => {
|
|
|
30
31
|
const fakeReceiveSlot = {
|
|
31
32
|
id: `fake sdk receive slot ${fakeReceiveSlots.length + 1}`,
|
|
32
33
|
mediaType,
|
|
34
|
+
findMemberId: sinon.stub(),
|
|
33
35
|
};
|
|
34
36
|
|
|
35
37
|
fakeReceiveSlots.push(fakeReceiveSlot);
|
|
@@ -170,4 +172,30 @@ describe('ReceiveSlotManager', () => {
|
|
|
170
172
|
numFreeSlots: {'VIDEO-MAIN': 1},
|
|
171
173
|
});
|
|
172
174
|
});
|
|
175
|
+
|
|
176
|
+
describe('updateMemberIds', () => {
|
|
177
|
+
|
|
178
|
+
it('calls findMemberId() on all allocated receive slots', async () => {
|
|
179
|
+
const audioSlots: ReceiveSlot[] = [];
|
|
180
|
+
const videoSlots: ReceiveSlot[] = [];
|
|
181
|
+
|
|
182
|
+
// allocate a bunch of receive slots
|
|
183
|
+
audioSlots.push(await receiveSlotManager.allocateSlot(MediaType.AudioMain));
|
|
184
|
+
audioSlots.push(await receiveSlotManager.allocateSlot(MediaType.AudioMain));
|
|
185
|
+
videoSlots.push(await receiveSlotManager.allocateSlot(MediaType.VideoMain));
|
|
186
|
+
videoSlots.push(await receiveSlotManager.allocateSlot(MediaType.VideoMain));
|
|
187
|
+
videoSlots.push(await receiveSlotManager.allocateSlot(MediaType.VideoMain));
|
|
188
|
+
|
|
189
|
+
receiveSlotManager.updateMemberIds();
|
|
190
|
+
|
|
191
|
+
assert.strictEqual(audioSlots.length, 2);
|
|
192
|
+
assert.strictEqual(videoSlots.length, 3);
|
|
193
|
+
|
|
194
|
+
assert.strictEqual(fakeReceiveSlots.length, audioSlots.length + videoSlots.length);
|
|
195
|
+
|
|
196
|
+
fakeReceiveSlots.forEach(slot => {
|
|
197
|
+
assert.calledOnce(slot.findMemberId);
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
});
|
|
173
201
|
});
|