@webex/plugin-meetings 3.12.0-next.64 → 3.12.0-next.66
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/aiEnableRequest/index.js +1 -1
- package/dist/breakouts/breakout.js +1 -1
- package/dist/breakouts/index.js +1 -1
- package/dist/constants.js +17 -3
- package/dist/constants.js.map +1 -1
- package/dist/interceptors/dataChannelAuthToken.js +75 -15
- package/dist/interceptors/dataChannelAuthToken.js.map +1 -1
- package/dist/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/meeting/index.js +738 -679
- package/dist/meeting/index.js.map +1 -1
- package/dist/types/constants.d.ts +1 -1
- package/dist/types/meeting/index.d.ts +2 -2
- package/dist/webinar/index.js +247 -152
- package/dist/webinar/index.js.map +1 -1
- package/package.json +3 -3
- package/src/constants.ts +2 -1
- package/src/interceptors/dataChannelAuthToken.ts +88 -12
- package/src/meeting/index.ts +111 -49
- package/src/webinar/index.ts +140 -29
- package/test/unit/spec/interceptors/dataChannelAuthToken.ts +196 -0
- package/test/unit/spec/meeting/index.js +139 -23
- package/test/unit/spec/webinar/index.ts +257 -21
|
@@ -5,7 +5,9 @@ import MockWebex from '@webex/test-helper-mock-webex';
|
|
|
5
5
|
import uuid from 'uuid';
|
|
6
6
|
import sinon from 'sinon';
|
|
7
7
|
import {DataChannelTokenType} from '@webex/internal-plugin-llm';
|
|
8
|
-
import {LLM_PRACTICE_SESSION, SHARE_STATUS} from '@webex/plugin-meetings/src/constants';
|
|
8
|
+
import {LLM_PRACTICE_SESSION, LOCUS_LLM_EVENT, SHARE_STATUS} from '@webex/plugin-meetings/src/constants';
|
|
9
|
+
|
|
10
|
+
const PRACTICE_SESSION_KEY = LLM_PRACTICE_SESSION || DataChannelTokenType.PracticeSession;
|
|
9
11
|
|
|
10
12
|
describe('plugin-meetings', () => {
|
|
11
13
|
describe('Webinar', () => {
|
|
@@ -33,6 +35,17 @@ describe('plugin-meetings', () => {
|
|
|
33
35
|
webex.internal.llm = {
|
|
34
36
|
getDatachannelToken: sinon.stub().returns(undefined),
|
|
35
37
|
setDatachannelToken: sinon.stub(),
|
|
38
|
+
setRefreshHandler: sinon.stub(),
|
|
39
|
+
getOwnerMeetingId: sinon.stub().returns(undefined),
|
|
40
|
+
resolveSessionOwnership: sinon.stub().callsFake((ownerMeetingId, sessionId) => {
|
|
41
|
+
const currentOwner = webex.internal.llm.getOwnerMeetingId(sessionId);
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
currentOwner,
|
|
45
|
+
isOwner: !currentOwner || !ownerMeetingId || currentOwner === ownerMeetingId,
|
|
46
|
+
};
|
|
47
|
+
}),
|
|
48
|
+
setOwnerMeetingId: sinon.stub(),
|
|
36
49
|
isDataChannelTokenEnabled: sinon.stub().resolves(false),
|
|
37
50
|
isConnected: sinon.stub().returns(false),
|
|
38
51
|
disconnectLLM: sinon.stub().resolves(),
|
|
@@ -226,8 +239,9 @@ describe('plugin-meetings', () => {
|
|
|
226
239
|
let relayListener;
|
|
227
240
|
|
|
228
241
|
beforeEach(() => {
|
|
242
|
+
webinar.meetingId = 'meeting-id';
|
|
229
243
|
relayListener = sinon.stub();
|
|
230
|
-
webinar.
|
|
244
|
+
webinar.llmListeners = {relay: relayListener, locusLLM: null};
|
|
231
245
|
});
|
|
232
246
|
|
|
233
247
|
it('disconnects the practice session channel and removes the tracked relay listener', async () => {
|
|
@@ -236,27 +250,99 @@ describe('plugin-meetings', () => {
|
|
|
236
250
|
assert.calledOnceWithExactly(
|
|
237
251
|
webex.internal.llm.disconnectLLM,
|
|
238
252
|
{code: 3050, reason: 'done (permanent)'},
|
|
239
|
-
|
|
253
|
+
PRACTICE_SESSION_KEY,
|
|
254
|
+
webinar.meetingId
|
|
255
|
+
);
|
|
256
|
+
assert.calledWithExactly(
|
|
257
|
+
webex.internal.llm.off,
|
|
258
|
+
`event:relay.event:${PRACTICE_SESSION_KEY}`,
|
|
259
|
+
relayListener
|
|
260
|
+
);
|
|
261
|
+
assert.isNull(webinar.llmListeners.relay);
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
it('skips disconnect when practice-session owner is another meeting', async () => {
|
|
265
|
+
webex.internal.llm.getOwnerMeetingId.returns('other-meeting-id');
|
|
266
|
+
webex.internal.llm.disconnectLLM.resolves(false);
|
|
267
|
+
|
|
268
|
+
await webinar.cleanupPSDataChannel();
|
|
269
|
+
|
|
270
|
+
assert.calledOnceWithExactly(
|
|
271
|
+
webex.internal.llm.disconnectLLM,
|
|
272
|
+
{code: 3050, reason: 'done (permanent)'},
|
|
273
|
+
PRACTICE_SESSION_KEY,
|
|
274
|
+
webinar.meetingId
|
|
240
275
|
);
|
|
276
|
+
assert.notCalled(webex.internal.llm.setOwnerMeetingId);
|
|
241
277
|
assert.calledOnceWithExactly(
|
|
242
278
|
webex.internal.llm.off,
|
|
243
|
-
`event:relay.event:${
|
|
279
|
+
`event:relay.event:${PRACTICE_SESSION_KEY}`,
|
|
244
280
|
relayListener
|
|
245
281
|
);
|
|
246
|
-
assert.isNull(webinar._practiceSessionRelayListener);
|
|
247
282
|
});
|
|
248
283
|
|
|
249
284
|
it('skips relay listener removal when no listener has been tracked', async () => {
|
|
250
|
-
webinar.
|
|
285
|
+
webinar.llmListeners.relay = null;
|
|
251
286
|
|
|
252
287
|
await webinar.cleanupPSDataChannel();
|
|
253
288
|
|
|
254
289
|
const relayOffCalls = webex.internal.llm.off.args.filter(
|
|
255
|
-
([event]) => event === `event:relay.event:${
|
|
290
|
+
([event]) => event === `event:relay.event:${PRACTICE_SESSION_KEY}`
|
|
256
291
|
);
|
|
257
292
|
assert.equal(relayOffCalls.length, 0);
|
|
258
293
|
});
|
|
259
294
|
|
|
295
|
+
it('removes tracked relay listener even when disconnect throws', async () => {
|
|
296
|
+
const disconnectError = new Error('disconnect failed');
|
|
297
|
+
webex.internal.llm.disconnectLLM.rejects(disconnectError);
|
|
298
|
+
|
|
299
|
+
let caughtError;
|
|
300
|
+
|
|
301
|
+
try {
|
|
302
|
+
await webinar.cleanupPSDataChannel();
|
|
303
|
+
} catch (error) {
|
|
304
|
+
caughtError = error;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
assert.equal(caughtError, disconnectError);
|
|
308
|
+
assert.calledOnceWithExactly(
|
|
309
|
+
webex.internal.llm.setOwnerMeetingId,
|
|
310
|
+
undefined,
|
|
311
|
+
PRACTICE_SESSION_KEY
|
|
312
|
+
);
|
|
313
|
+
assert.calledOnceWithExactly(
|
|
314
|
+
webex.internal.llm.off,
|
|
315
|
+
`event:relay.event:${PRACTICE_SESSION_KEY}`,
|
|
316
|
+
relayListener
|
|
317
|
+
);
|
|
318
|
+
assert.notOk(webinar._practiceSessionRelayListener);
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
it('disconnects and removes the tracked locusLLM listener', async () => {
|
|
322
|
+
const locusLLMListener = sinon.stub();
|
|
323
|
+
webinar.llmListeners.locusLLM = locusLLMListener;
|
|
324
|
+
|
|
325
|
+
await webinar.cleanupPSDataChannel();
|
|
326
|
+
|
|
327
|
+
assert.calledWithExactly(
|
|
328
|
+
webex.internal.llm.off,
|
|
329
|
+
`${LOCUS_LLM_EVENT}:${LLM_PRACTICE_SESSION}`,
|
|
330
|
+
locusLLMListener
|
|
331
|
+
);
|
|
332
|
+
assert.isNull(webinar.llmListeners.locusLLM);
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
it('skips locusLLM listener removal when no listener has been tracked', async () => {
|
|
336
|
+
webinar.llmListeners.locusLLM = null;
|
|
337
|
+
|
|
338
|
+
await webinar.cleanupPSDataChannel();
|
|
339
|
+
|
|
340
|
+
const locusLLMOffCalls = webex.internal.llm.off.args.filter(
|
|
341
|
+
([event]) => event === `${LOCUS_LLM_EVENT}:${LLM_PRACTICE_SESSION}`
|
|
342
|
+
);
|
|
343
|
+
assert.equal(locusLLMOffCalls.length, 0);
|
|
344
|
+
});
|
|
345
|
+
|
|
260
346
|
it('does not consult the meeting collection during cleanup', async () => {
|
|
261
347
|
webex.meetings.getMeetingByType = sinon.stub();
|
|
262
348
|
|
|
@@ -289,13 +375,18 @@ describe('plugin-meetings', () => {
|
|
|
289
375
|
describe('#updatePSDataChannel', () => {
|
|
290
376
|
let meeting;
|
|
291
377
|
let processRelayEvent;
|
|
378
|
+
let processLocusLLMEvent;
|
|
292
379
|
|
|
293
380
|
beforeEach(() => {
|
|
381
|
+
webinar.meetingId = 'meeting-id';
|
|
294
382
|
processRelayEvent = sinon.stub();
|
|
383
|
+
processLocusLLMEvent = sinon.stub();
|
|
295
384
|
meeting = {
|
|
385
|
+
id: 'meeting-id',
|
|
296
386
|
locusUrl: 'locusUrl',
|
|
297
387
|
isJoined: sinon.stub().returns(true),
|
|
298
388
|
processRelayEvent,
|
|
389
|
+
processLocusLLMEvent,
|
|
299
390
|
locusInfo: {
|
|
300
391
|
url: 'locus-url',
|
|
301
392
|
info: {practiceSessionDatachannelUrl: 'dc-url'},
|
|
@@ -306,7 +397,7 @@ describe('plugin-meetings', () => {
|
|
|
306
397
|
|
|
307
398
|
// Default session is connected by default; practice session is not
|
|
308
399
|
webex.internal.llm.isConnected = sinon.stub().callsFake((sessionId) => {
|
|
309
|
-
return sessionId !==
|
|
400
|
+
return sessionId !== PRACTICE_SESSION_KEY;
|
|
310
401
|
});
|
|
311
402
|
|
|
312
403
|
// Token is pre-saved into LLM by saveDataChannelToken
|
|
@@ -342,14 +433,15 @@ describe('plugin-meetings', () => {
|
|
|
342
433
|
assert.calledWithExactly(
|
|
343
434
|
webex.internal.llm.setDatachannelToken,
|
|
344
435
|
'ps-token-from-refresh',
|
|
345
|
-
DataChannelTokenType.PracticeSession
|
|
436
|
+
DataChannelTokenType.PracticeSession,
|
|
437
|
+
'meeting-id'
|
|
346
438
|
);
|
|
347
439
|
assert.calledWith(
|
|
348
440
|
webex.internal.llm.registerAndConnect,
|
|
349
441
|
'locus-url',
|
|
350
442
|
'dc-url',
|
|
351
443
|
'ps-token-from-refresh',
|
|
352
|
-
|
|
444
|
+
PRACTICE_SESSION_KEY
|
|
353
445
|
);
|
|
354
446
|
});
|
|
355
447
|
|
|
@@ -409,6 +501,8 @@ describe('plugin-meetings', () => {
|
|
|
409
501
|
const result = await webinar.updatePSDataChannel();
|
|
410
502
|
|
|
411
503
|
assert.isUndefined(result);
|
|
504
|
+
assert.notCalled(webex.internal.llm.setRefreshHandler);
|
|
505
|
+
assert.notCalled(webex.internal.llm.setOwnerMeetingId);
|
|
412
506
|
assert.notCalled(webex.internal.llm.registerAndConnect);
|
|
413
507
|
});
|
|
414
508
|
|
|
@@ -429,12 +523,17 @@ describe('plugin-meetings', () => {
|
|
|
429
523
|
const result = await webinar.updatePSDataChannel();
|
|
430
524
|
|
|
431
525
|
assert.calledOnce(webex.internal.llm.registerAndConnect);
|
|
526
|
+
assert.calledWithExactly(
|
|
527
|
+
webex.internal.llm.setOwnerMeetingId,
|
|
528
|
+
'meeting-id',
|
|
529
|
+
PRACTICE_SESSION_KEY
|
|
530
|
+
);
|
|
432
531
|
assert.calledWith(
|
|
433
532
|
webex.internal.llm.registerAndConnect,
|
|
434
533
|
'locus-url',
|
|
435
534
|
'dc-url',
|
|
436
535
|
'ps-token',
|
|
437
|
-
|
|
536
|
+
PRACTICE_SESSION_KEY
|
|
438
537
|
);
|
|
439
538
|
assert.calledOnceWithExactly(webex.internal.voicea.announce);
|
|
440
539
|
assert.equal(result, 'REGISTER_AND_CONNECT_RESULT');
|
|
@@ -450,7 +549,8 @@ describe('plugin-meetings', () => {
|
|
|
450
549
|
|
|
451
550
|
assert.calledWithExactly(
|
|
452
551
|
webex.internal.llm.getDatachannelToken,
|
|
453
|
-
DataChannelTokenType.PracticeSession
|
|
552
|
+
DataChannelTokenType.PracticeSession,
|
|
553
|
+
webinar.meetingId
|
|
454
554
|
);
|
|
455
555
|
assert.notCalled(webex.internal.llm.setDatachannelToken);
|
|
456
556
|
assert.calledWith(
|
|
@@ -458,7 +558,7 @@ describe('plugin-meetings', () => {
|
|
|
458
558
|
'locus-url',
|
|
459
559
|
'dc-url',
|
|
460
560
|
'cached-token',
|
|
461
|
-
|
|
561
|
+
PRACTICE_SESSION_KEY
|
|
462
562
|
);
|
|
463
563
|
});
|
|
464
564
|
|
|
@@ -476,26 +576,51 @@ describe('plugin-meetings', () => {
|
|
|
476
576
|
await webinar.updatePSDataChannel();
|
|
477
577
|
|
|
478
578
|
// Stores the exact listener reference for deterministic cleanup
|
|
479
|
-
assert.equal(webinar.
|
|
579
|
+
assert.equal(webinar.llmListeners.relay, processRelayEvent);
|
|
480
580
|
assert.calledWith(
|
|
481
581
|
webex.internal.llm.on,
|
|
482
|
-
`event:relay.event:${
|
|
582
|
+
`event:relay.event:${PRACTICE_SESSION_KEY}`,
|
|
483
583
|
processRelayEvent
|
|
484
584
|
);
|
|
485
585
|
});
|
|
486
586
|
|
|
487
587
|
it('removes a previously tracked relay listener before re-binding on reconnect', async () => {
|
|
488
588
|
const previousListener = sinon.stub();
|
|
489
|
-
webinar.
|
|
589
|
+
webinar.llmListeners = {relay: previousListener, locusLLM: null};
|
|
490
590
|
|
|
491
591
|
await webinar.updatePSDataChannel();
|
|
492
592
|
|
|
493
593
|
assert.calledWith(
|
|
494
594
|
webex.internal.llm.off,
|
|
495
|
-
`event:relay.event:${
|
|
595
|
+
`event:relay.event:${PRACTICE_SESSION_KEY}`,
|
|
496
596
|
previousListener
|
|
497
597
|
);
|
|
498
|
-
assert.equal(webinar.
|
|
598
|
+
assert.equal(webinar.llmListeners.relay, processRelayEvent);
|
|
599
|
+
});
|
|
600
|
+
|
|
601
|
+
it('tracks and binds the locusLLM listener after successful connect', async () => {
|
|
602
|
+
await webinar.updatePSDataChannel();
|
|
603
|
+
|
|
604
|
+
assert.equal(webinar.llmListeners.locusLLM, processLocusLLMEvent);
|
|
605
|
+
assert.calledWith(
|
|
606
|
+
webex.internal.llm.on,
|
|
607
|
+
`${LOCUS_LLM_EVENT}:${LLM_PRACTICE_SESSION}`,
|
|
608
|
+
processLocusLLMEvent
|
|
609
|
+
);
|
|
610
|
+
});
|
|
611
|
+
|
|
612
|
+
it('removes a previously tracked locusLLM listener before re-binding on reconnect', async () => {
|
|
613
|
+
const previousListener = sinon.stub();
|
|
614
|
+
webinar.llmListeners = {relay: null, locusLLM: previousListener};
|
|
615
|
+
|
|
616
|
+
await webinar.updatePSDataChannel();
|
|
617
|
+
|
|
618
|
+
assert.calledWith(
|
|
619
|
+
webex.internal.llm.off,
|
|
620
|
+
`${LOCUS_LLM_EVENT}:${LLM_PRACTICE_SESSION}`,
|
|
621
|
+
previousListener
|
|
622
|
+
);
|
|
623
|
+
assert.equal(webinar.llmListeners.locusLLM, processLocusLLMEvent);
|
|
499
624
|
});
|
|
500
625
|
|
|
501
626
|
it('subscribes to transcription when caption intent is enabled', async () => {
|
|
@@ -525,6 +650,8 @@ describe('plugin-meetings', () => {
|
|
|
525
650
|
// Should register an 'online' listener but NOT call registerAndConnect yet
|
|
526
651
|
assert.calledWith(webex.internal.llm.on, 'online', sinon.match.func);
|
|
527
652
|
assert.notCalled(webex.internal.llm.registerAndConnect);
|
|
653
|
+
assert.notCalled(webex.internal.llm.setRefreshHandler);
|
|
654
|
+
assert.notCalled(webex.internal.llm.setOwnerMeetingId);
|
|
528
655
|
// Should store the pending listener
|
|
529
656
|
assert.isNotNull(webinar._pendingOnlineListener);
|
|
530
657
|
});
|
|
@@ -556,7 +683,7 @@ describe('plugin-meetings', () => {
|
|
|
556
683
|
|
|
557
684
|
// Now simulate default session coming online
|
|
558
685
|
webex.internal.llm.isConnected = sinon.stub().callsFake((sessionId) => {
|
|
559
|
-
return sessionId !==
|
|
686
|
+
return sessionId !== PRACTICE_SESSION_KEY;
|
|
560
687
|
});
|
|
561
688
|
|
|
562
689
|
// Fire the captured listener
|
|
@@ -583,7 +710,7 @@ describe('plugin-meetings', () => {
|
|
|
583
710
|
|
|
584
711
|
// Now default session comes online
|
|
585
712
|
webex.internal.llm.isConnected = sinon.stub().callsFake((sessionId) => {
|
|
586
|
-
return sessionId !==
|
|
713
|
+
return sessionId !== PRACTICE_SESSION_KEY;
|
|
587
714
|
});
|
|
588
715
|
|
|
589
716
|
// Fire the listener — re-invokes updatePSDataChannel which will see isPracticeSession = false
|
|
@@ -596,7 +723,7 @@ describe('plugin-meetings', () => {
|
|
|
596
723
|
it('proceeds immediately when default session is already connected', async () => {
|
|
597
724
|
// Default session already connected, practice session not
|
|
598
725
|
webex.internal.llm.isConnected = sinon.stub().callsFake((sessionId) => {
|
|
599
|
-
return sessionId !==
|
|
726
|
+
return sessionId !== PRACTICE_SESSION_KEY;
|
|
600
727
|
});
|
|
601
728
|
|
|
602
729
|
const result = await webinar.updatePSDataChannel();
|
|
@@ -608,6 +735,115 @@ describe('plugin-meetings', () => {
|
|
|
608
735
|
assert.calledOnce(webex.internal.llm.registerAndConnect);
|
|
609
736
|
assert.equal(result, 'REGISTER_AND_CONNECT_RESULT');
|
|
610
737
|
});
|
|
738
|
+
|
|
739
|
+
it('does not override practice refresh handler or reconnect when owned by another meeting', async () => {
|
|
740
|
+
webex.internal.llm.getOwnerMeetingId.returns('other-meeting-id');
|
|
741
|
+
webex.internal.llm.isConnected = sinon.stub().callsFake((sessionId) => {
|
|
742
|
+
return sessionId !== undefined;
|
|
743
|
+
});
|
|
744
|
+
|
|
745
|
+
const result = await webinar.updatePSDataChannel();
|
|
746
|
+
|
|
747
|
+
assert.isUndefined(result);
|
|
748
|
+
assert.notCalled(webex.internal.llm.setRefreshHandler);
|
|
749
|
+
assert.notCalled(webex.internal.llm.registerAndConnect);
|
|
750
|
+
});
|
|
751
|
+
|
|
752
|
+
it('does not reconnect when practice session is disconnected but owned by another meeting', async () => {
|
|
753
|
+
webex.internal.llm.getOwnerMeetingId.returns('other-meeting-id');
|
|
754
|
+
webex.internal.llm.isConnected = sinon.stub().returns(false);
|
|
755
|
+
|
|
756
|
+
const result = await webinar.updatePSDataChannel();
|
|
757
|
+
|
|
758
|
+
assert.isUndefined(result);
|
|
759
|
+
assert.notCalled(webex.internal.llm.setRefreshHandler);
|
|
760
|
+
assert.notCalled(webex.internal.llm.setOwnerMeetingId);
|
|
761
|
+
assert.notCalled(webex.internal.llm.registerAndConnect);
|
|
762
|
+
});
|
|
763
|
+
|
|
764
|
+
it('does not write owner or connect if ownership changes before pre-connect owner write', async () => {
|
|
765
|
+
let ownerMeetingId = 'meeting-id';
|
|
766
|
+
|
|
767
|
+
webex.internal.llm.getOwnerMeetingId.callsFake(() => ownerMeetingId);
|
|
768
|
+
webex.internal.llm.isDataChannelTokenEnabled.resolves(true);
|
|
769
|
+
webex.internal.llm.getDatachannelToken = sinon.stub().returns(undefined);
|
|
770
|
+
|
|
771
|
+
let resolveRefresh;
|
|
772
|
+
meeting.refreshDataChannelToken = sinon.stub().returns(
|
|
773
|
+
new Promise((resolve) => {
|
|
774
|
+
resolveRefresh = resolve;
|
|
775
|
+
})
|
|
776
|
+
);
|
|
777
|
+
|
|
778
|
+
const updatePromise = webinar.updatePSDataChannel();
|
|
779
|
+
|
|
780
|
+
ownerMeetingId = 'other-meeting-id';
|
|
781
|
+
resolveRefresh({
|
|
782
|
+
body: {
|
|
783
|
+
datachannelToken: 'ps-token-from-refresh',
|
|
784
|
+
dataChannelTokenType: DataChannelTokenType.PracticeSession,
|
|
785
|
+
},
|
|
786
|
+
});
|
|
787
|
+
|
|
788
|
+
const result = await updatePromise;
|
|
789
|
+
|
|
790
|
+
assert.isUndefined(result);
|
|
791
|
+
assert.notCalled(webex.internal.llm.setRefreshHandler);
|
|
792
|
+
assert.notCalled(webex.internal.llm.setOwnerMeetingId);
|
|
793
|
+
assert.notCalled(webex.internal.llm.registerAndConnect);
|
|
794
|
+
});
|
|
795
|
+
|
|
796
|
+
it('does not overwrite owner after connect when ownership changed during registerAndConnect', async () => {
|
|
797
|
+
let ownerMeetingId = 'meeting-id';
|
|
798
|
+
|
|
799
|
+
webex.internal.llm.getOwnerMeetingId.callsFake(() => ownerMeetingId);
|
|
800
|
+
webex.internal.llm.registerAndConnect = sinon.stub().callsFake(async () => {
|
|
801
|
+
ownerMeetingId = 'other-meeting-id';
|
|
802
|
+
|
|
803
|
+
return 'REGISTER_AND_CONNECT_RESULT';
|
|
804
|
+
});
|
|
805
|
+
|
|
806
|
+
const result = await webinar.updatePSDataChannel();
|
|
807
|
+
|
|
808
|
+
assert.equal(result, 'REGISTER_AND_CONNECT_RESULT');
|
|
809
|
+
assert.calledOnce(webex.internal.llm.setOwnerMeetingId);
|
|
810
|
+
assert.calledWithExactly(
|
|
811
|
+
webex.internal.llm.setOwnerMeetingId,
|
|
812
|
+
'meeting-id',
|
|
813
|
+
PRACTICE_SESSION_KEY
|
|
814
|
+
);
|
|
815
|
+
});
|
|
816
|
+
|
|
817
|
+
it('clears pre-claimed owner when registerAndConnect rejects', async () => {
|
|
818
|
+
const registerError = new Error('register failed');
|
|
819
|
+
let ownerMeetingId = 'meeting-id';
|
|
820
|
+
|
|
821
|
+
webex.internal.llm.getOwnerMeetingId.callsFake(() => ownerMeetingId);
|
|
822
|
+
webex.internal.llm.setOwnerMeetingId.callsFake((id) => {
|
|
823
|
+
ownerMeetingId = id;
|
|
824
|
+
});
|
|
825
|
+
webex.internal.llm.registerAndConnect = sinon.stub().rejects(registerError);
|
|
826
|
+
|
|
827
|
+
try {
|
|
828
|
+
await webinar.updatePSDataChannel();
|
|
829
|
+
assert.fail('Expected updatePSDataChannel to reject when registerAndConnect fails');
|
|
830
|
+
} catch (error) {
|
|
831
|
+
assert.equal(error, registerError);
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
assert.calledTwice(webex.internal.llm.setOwnerMeetingId);
|
|
835
|
+
assert.calledWithExactly(
|
|
836
|
+
webex.internal.llm.setOwnerMeetingId.firstCall,
|
|
837
|
+
'meeting-id',
|
|
838
|
+
PRACTICE_SESSION_KEY
|
|
839
|
+
);
|
|
840
|
+
assert.calledWithExactly(
|
|
841
|
+
webex.internal.llm.setOwnerMeetingId.secondCall,
|
|
842
|
+
undefined,
|
|
843
|
+
PRACTICE_SESSION_KEY
|
|
844
|
+
);
|
|
845
|
+
assert.isUndefined(ownerMeetingId);
|
|
846
|
+
});
|
|
611
847
|
});
|
|
612
848
|
|
|
613
849
|
describe('#updateStatusByRole', () => {
|