@webex/plugin-meetings 3.8.1-next.2 → 3.8.1-next.21

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 (54) hide show
  1. package/README.md +26 -13
  2. package/dist/breakouts/breakout.js +1 -1
  3. package/dist/breakouts/index.js +1 -1
  4. package/dist/constants.js +2 -1
  5. package/dist/constants.js.map +1 -1
  6. package/dist/interpretation/index.js +1 -1
  7. package/dist/interpretation/siLanguage.js +1 -1
  8. package/dist/locus-info/index.js +35 -16
  9. package/dist/locus-info/index.js.map +1 -1
  10. package/dist/media/index.js +2 -2
  11. package/dist/media/index.js.map +1 -1
  12. package/dist/meeting/brbState.js +12 -12
  13. package/dist/meeting/brbState.js.map +1 -1
  14. package/dist/meeting/index.js +85 -78
  15. package/dist/meeting/index.js.map +1 -1
  16. package/dist/members/index.js +8 -6
  17. package/dist/members/index.js.map +1 -1
  18. package/dist/members/request.js +3 -3
  19. package/dist/members/request.js.map +1 -1
  20. package/dist/members/util.js +18 -6
  21. package/dist/members/util.js.map +1 -1
  22. package/dist/multistream/sendSlotManager.js +32 -2
  23. package/dist/multistream/sendSlotManager.js.map +1 -1
  24. package/dist/reachability/index.js +5 -10
  25. package/dist/reachability/index.js.map +1 -1
  26. package/dist/types/constants.d.ts +1 -0
  27. package/dist/types/meeting/brbState.d.ts +0 -1
  28. package/dist/types/meeting/index.d.ts +12 -3
  29. package/dist/types/members/index.d.ts +8 -3
  30. package/dist/types/members/request.d.ts +1 -1
  31. package/dist/types/members/util.d.ts +5 -2
  32. package/dist/types/multistream/sendSlotManager.d.ts +16 -0
  33. package/dist/types/reachability/index.d.ts +2 -2
  34. package/dist/webinar/index.js +1 -1
  35. package/package.json +24 -24
  36. package/src/constants.ts +1 -0
  37. package/src/locus-info/index.ts +46 -19
  38. package/src/media/index.ts +2 -2
  39. package/src/meeting/brbState.ts +8 -7
  40. package/src/meeting/index.ts +48 -32
  41. package/src/members/index.ts +7 -5
  42. package/src/members/request.ts +2 -2
  43. package/src/members/util.ts +14 -3
  44. package/src/multistream/sendSlotManager.ts +34 -2
  45. package/src/reachability/index.ts +5 -13
  46. package/test/unit/spec/locus-info/index.js +140 -44
  47. package/test/unit/spec/media/index.ts +107 -0
  48. package/test/unit/spec/meeting/brbState.ts +11 -9
  49. package/test/unit/spec/meeting/index.js +131 -39
  50. package/test/unit/spec/members/index.js +32 -9
  51. package/test/unit/spec/members/request.js +2 -2
  52. package/test/unit/spec/members/utils.js +27 -7
  53. package/test/unit/spec/multistream/sendSlotManager.ts +59 -0
  54. package/test/unit/spec/reachability/index.ts +2 -6
@@ -614,20 +614,20 @@ describe('plugin-meetings', () => {
614
614
  assert.calledWith(meeting.members.cancelPhoneInvite, uuid1);
615
615
  });
616
616
  });
617
- describe('#cancelSIPInvite', () => {
618
- it('should have #cancelSIPInvite', () => {
619
- assert.exists(meeting.cancelSIPInvite);
617
+ describe('#cancelInviteByMemberId', () => {
618
+ it('should have #cancelInviteByMemberId', () => {
619
+ assert.exists(meeting.cancelInviteByMemberId);
620
620
  });
621
621
  beforeEach(() => {
622
- meeting.members.cancelSIPInvite = sinon.stub().returns(Promise.resolve(test1));
622
+ meeting.members.cancelInviteByMemberId = sinon.stub().returns(Promise.resolve(test1));
623
623
  });
624
- it('should proxy members #cancelSIPInvite and return a promise', async () => {
625
- const cancel = meeting.cancelSIPInvite({memberId: uuid1});
624
+ it('should proxy members #cancelInviteByMemberId and return a promise', async () => {
625
+ const cancel = meeting.cancelInviteByMemberId({memberId: uuid1});
626
626
 
627
627
  assert.exists(cancel.then);
628
628
  await cancel;
629
- assert.calledOnce(meeting.members.cancelSIPInvite);
630
- assert.calledWith(meeting.members.cancelSIPInvite, {memberId: uuid1});
629
+ assert.calledOnce(meeting.members.cancelInviteByMemberId);
630
+ assert.calledWith(meeting.members.cancelInviteByMemberId, {memberId: uuid1});
631
631
  });
632
632
  });
633
633
  describe('#admit', () => {
@@ -1208,8 +1208,76 @@ describe('plugin-meetings', () => {
1208
1208
  reason: 'joinWithMedia failure',
1209
1209
  });
1210
1210
  });
1211
- });
1212
1211
 
1212
+ it('should ignore sendVideo/receiveVideo when videoEnabled is false', async () => {
1213
+ await meeting.joinWithMedia({
1214
+ joinOptions,
1215
+ mediaOptions: {
1216
+ videoEnabled: false,
1217
+ sendVideo: true,
1218
+ receiveVideo: true,
1219
+ allowMediaInLobby: true,
1220
+ },
1221
+ });
1222
+
1223
+ assert.calledWithMatch(
1224
+ meeting.addMediaInternal,
1225
+ sinon.match.any,
1226
+ sinon.match.any,
1227
+ sinon.match.any,
1228
+ sinon.match.has('videoEnabled', false)
1229
+ .and(sinon.match.has('allowMediaInLobby', true))
1230
+ );
1231
+ });
1232
+
1233
+ it('should ignore sendAudio/receiveAudio when audioEnabled is false', async () => {
1234
+ await meeting.joinWithMedia({
1235
+ joinOptions,
1236
+ mediaOptions: {
1237
+ audioEnabled: false,
1238
+ sendAudio: true,
1239
+ receiveAudio: false,
1240
+ allowMediaInLobby: true,
1241
+ },
1242
+ });
1243
+
1244
+ assert.calledWithMatch(
1245
+ meeting.addMediaInternal,
1246
+ sinon.match.any,
1247
+ sinon.match.any,
1248
+ sinon.match.any,
1249
+ sinon.match.has('audioEnabled', false)
1250
+ .and(sinon.match.has('allowMediaInLobby', true))
1251
+ );
1252
+ });
1253
+
1254
+
1255
+ it('should use provided send/receive values when videoEnabled/audioEnabled are true or not set', async () => {
1256
+ await meeting.joinWithMedia({
1257
+ joinOptions,
1258
+ mediaOptions: {
1259
+ sendVideo: true,
1260
+ receiveVideo: false,
1261
+ sendAudio: false,
1262
+ receiveAudio: true,
1263
+ allowMediaInLobby: true,
1264
+ },
1265
+ });
1266
+
1267
+ assert.calledWith(
1268
+ meeting.addMediaInternal,
1269
+ sinon.match.any,
1270
+ sinon.match.any,
1271
+ sinon.match.any,
1272
+ sinon.match({
1273
+ sendVideo: true,
1274
+ receiveVideo: false,
1275
+ sendAudio: false,
1276
+ receiveAudio: true,
1277
+ })
1278
+ );
1279
+ });
1280
+ });
1213
1281
  describe('#isTranscriptionSupported', () => {
1214
1282
  it('should return false if the feature is not supported for the meeting', () => {
1215
1283
  meeting.locusInfo.controls = {transcribe: {caption: false}};
@@ -1240,7 +1308,7 @@ describe('plugin-meetings', () => {
1240
1308
  LOCUSINFO.EVENTS.CONTROLS_MEETING_TRANSCRIPTION_SPOKEN_LANGUAGE_UPDATED,
1241
1309
  {spokenLanguage: 'fr'},
1242
1310
  );
1243
- assert.calledWith(webex.internal.voicea.onSpokenLanguageUpdate, 'fr');
1311
+ assert.calledWith(webex.internal.voicea.onSpokenLanguageUpdate, 'fr', meeting.id);
1244
1312
  assert.equal(meeting.transcription.languageOptions.currentSpokenLanguage, 'fr');
1245
1313
  assert.calledWith(
1246
1314
  TriggerProxy.trigger,
@@ -2227,8 +2295,9 @@ describe('plugin-meetings', () => {
2227
2295
  someReachabilityMetric1: 'some value1',
2228
2296
  someReachabilityMetric2: 'some value2',
2229
2297
  selectedCandidatePairChanges: 2,
2230
- isSubnetReachable: null,
2231
- selectedCluster: null,
2298
+ subnet_reachable: null,
2299
+ selected_cluster: null,
2300
+ selected_subnet: null,
2232
2301
  numTransports: 1,
2233
2302
  iceCandidatesCount: 0,
2234
2303
  }
@@ -2275,8 +2344,9 @@ describe('plugin-meetings', () => {
2275
2344
  signalingState: 'unknown',
2276
2345
  connectionState: 'unknown',
2277
2346
  iceConnectionState: 'unknown',
2278
- isSubnetReachable: null,
2279
- selectedCluster: null,
2347
+ subnet_reachable: null,
2348
+ selected_cluster: null,
2349
+ selected_subnet: null,
2280
2350
  })
2281
2351
  );
2282
2352
 
@@ -2342,8 +2412,9 @@ describe('plugin-meetings', () => {
2342
2412
  selectedCandidatePairChanges: 2,
2343
2413
  numTransports: 1,
2344
2414
  iceCandidatesCount: 0,
2345
- isSubnetReachable: null,
2346
- selectedCluster: null,
2415
+ subnet_reachable: null,
2416
+ selected_cluster: null,
2417
+ selected_subnet: null,
2347
2418
  }
2348
2419
  );
2349
2420
  });
@@ -2401,8 +2472,9 @@ describe('plugin-meetings', () => {
2401
2472
  signalingState: 'have-local-offer',
2402
2473
  connectionState: 'connecting',
2403
2474
  iceConnectionState: 'checking',
2404
- isSubnetReachable: null,
2405
- selectedCluster: null,
2475
+ subnet_reachable: null,
2476
+ selected_cluster: null,
2477
+ selected_subnet: null,
2406
2478
  })
2407
2479
  );
2408
2480
 
@@ -2460,8 +2532,9 @@ describe('plugin-meetings', () => {
2460
2532
  signalingState: 'have-local-offer',
2461
2533
  connectionState: 'connecting',
2462
2534
  iceConnectionState: 'checking',
2463
- isSubnetReachable: null,
2464
- selectedCluster: null,
2535
+ subnet_reachable: null,
2536
+ selected_cluster: null,
2537
+ selected_subnet: null,
2465
2538
  })
2466
2539
  );
2467
2540
 
@@ -2983,8 +3056,9 @@ describe('plugin-meetings', () => {
2983
3056
  selectedCandidatePairChanges: 2,
2984
3057
  numTransports: 1,
2985
3058
  iceCandidatesCount: 0,
2986
- isSubnetReachable: null,
2987
- selectedCluster: null,
3059
+ subnet_reachable: null,
3060
+ selected_cluster: null,
3061
+ selected_subnet: null,
2988
3062
  },
2989
3063
  ]);
2990
3064
 
@@ -3191,8 +3265,9 @@ describe('plugin-meetings', () => {
3191
3265
  retriedWithTurnServer: true,
3192
3266
  isJoinWithMediaRetry: false,
3193
3267
  iceCandidatesCount: 0,
3194
- isSubnetReachable: null,
3195
- selectedCluster: null,
3268
+ subnet_reachable: null,
3269
+ selected_cluster: null,
3270
+ selected_subnet: null,
3196
3271
  },
3197
3272
  ]);
3198
3273
  meeting.roap.doTurnDiscovery;
@@ -3355,8 +3430,9 @@ describe('plugin-meetings', () => {
3355
3430
  iceCandidatesCount: 3,
3356
3431
  '701_error': 3,
3357
3432
  '701_turn_host_lookup_received_error': 1,
3358
- isSubnetReachable: null,
3359
- selectedCluster: 'some.cluster',
3433
+ subnet_reachable: null,
3434
+ selected_cluster: 'some.cluster',
3435
+ selected_subnet: null,
3360
3436
  }
3361
3437
  );
3362
3438
 
@@ -3419,8 +3495,9 @@ describe('plugin-meetings', () => {
3419
3495
  iceConnectionState: 'unknown',
3420
3496
  selectedCandidatePairChanges: 2,
3421
3497
  numTransports: 1,
3422
- isSubnetReachable: null,
3423
- selectedCluster: null,
3498
+ subnet_reachable: null,
3499
+ selected_cluster: null,
3500
+ selected_subnet: null,
3424
3501
  iceCandidatesCount: 0,
3425
3502
  }
3426
3503
  );
@@ -3482,8 +3559,9 @@ describe('plugin-meetings', () => {
3482
3559
  numTransports: 1,
3483
3560
  '701_error': 2,
3484
3561
  '701_turn_host_lookup_received_error': 1,
3485
- isSubnetReachable: null,
3486
- selectedCluster: null,
3562
+ subnet_reachable: null,
3563
+ selected_cluster: null,
3564
+ selected_subnet: null,
3487
3565
  iceCandidatesCount: 0,
3488
3566
  }
3489
3567
  );
@@ -3491,7 +3569,7 @@ describe('plugin-meetings', () => {
3491
3569
  assert.isOk(errorThrown);
3492
3570
  });
3493
3571
 
3494
- it('should send valid isSubnetReachability if media connection success', async () => {
3572
+ it('should send subnet reachablity metrics if media connection success', async () => {
3495
3573
  meeting.roap.doTurnDiscovery = sinon.stub().returns({
3496
3574
  turnServerInfo: undefined,
3497
3575
  turnDiscoverySkippedReason: undefined,
@@ -3505,6 +3583,12 @@ describe('plugin-meetings', () => {
3505
3583
  stopReachability: sinon.stub(),
3506
3584
  isSubnetReachable: sinon.stub().returns(false),
3507
3585
  };
3586
+ meeting.mediaServerIp = '1.2.3.4';
3587
+ meeting.mediaConnections = [
3588
+ {
3589
+ mediaAgentCluster: 'some.cluster',
3590
+ }
3591
+ ]
3508
3592
 
3509
3593
  const forceRtcMetricsSend = sinon.stub().resolves();
3510
3594
  const closeMediaConnectionStub = sinon.stub();
@@ -3532,12 +3616,13 @@ describe('plugin-meetings', () => {
3532
3616
  isJoinWithMediaRetry: false,
3533
3617
  iceCandidatesCount: 0,
3534
3618
  reachability_public_udp_success: 5,
3535
- isSubnetReachable: false,
3536
- selectedCluster: null,
3619
+ subnet_reachable: false,
3620
+ selected_cluster: 'some.cluster',
3621
+ selected_subnet: '1.X.X.X',
3537
3622
  });
3538
3623
  });
3539
3624
 
3540
- it('should send valid isSubnetReachability if media connection fails', async () => {
3625
+ it('should send subnet reachablity metrics if media connection fails', async () => {
3541
3626
  let errorThrown = undefined;
3542
3627
 
3543
3628
  meeting.roap.doTurnDiscovery = sinon.stub().returns({
@@ -3553,6 +3638,12 @@ describe('plugin-meetings', () => {
3553
3638
  stopReachability: sinon.stub(),
3554
3639
  isSubnetReachable: sinon.stub().returns(true),
3555
3640
  };
3641
+ meeting.mediaServerIp = '1.2.3.4';
3642
+ meeting.mediaConnections = [
3643
+ {
3644
+ mediaAgentCluster: 'some.cluster',
3645
+ }
3646
+ ]
3556
3647
 
3557
3648
  const forceRtcMetricsSend = sinon.stub().resolves();
3558
3649
  const closeMediaConnectionStub = sinon.stub();
@@ -3594,8 +3685,9 @@ describe('plugin-meetings', () => {
3594
3685
  selectedCandidatePairChanges: 2,
3595
3686
  numTransports: 1,
3596
3687
  reachability_public_udp_success: 5,
3597
- isSubnetReachable: true,
3598
- selectedCluster: null,
3688
+ subnet_reachable: true,
3689
+ selected_cluster: 'some.cluster',
3690
+ selected_subnet: '1.X.X.X',
3599
3691
  iceCandidatesCount: 0,
3600
3692
  }
3601
3693
  );
@@ -4262,11 +4354,11 @@ describe('plugin-meetings', () => {
4262
4354
 
4263
4355
  const error = new Error();
4264
4356
  meeting.meetingRequest.setBrb = sinon.stub().rejects(error);
4265
-
4357
+
4266
4358
  await expect(
4267
4359
  meeting.beRightBack(true)
4268
- ).to.be.rejectedWith(error);
4269
-
4360
+ ).to.be.rejectedWith(error);
4361
+
4270
4362
  assert.isFalse(meeting.brbState.state.syncToServerInProgress);
4271
4363
  });
4272
4364
  });
@@ -176,6 +176,20 @@ describe('plugin-meetings', () => {
176
176
  assert.calledOnce(MembersUtil.isInvalidInvitee);
177
177
  assert.isFalse(MembersUtil.isInvalidInvitee({email: 'sip:test@cisco.com'}), 'SIP email should be valid');
178
178
  });
179
+
180
+ it('should accept valid phone with isInternalNumber', async () => {
181
+ sandbox.spy(MembersUtil, 'isInvalidInvitee');
182
+
183
+ const members = createMembers({url: true});
184
+
185
+ await members.addMember({phoneNumber: '+8618578675309', isInternalNumber: false});
186
+
187
+ assert.calledOnce(MembersUtil.isInvalidInvitee);
188
+ assert.isFalse(MembersUtil.isInvalidInvitee({ phoneNumber: '+8618578675309', isInternalNumber: false }));
189
+ assert.isTrue(MembersUtil.isInvalidInvitee({ phoneNumber: '18578675309', isInternalNumber: false }));
190
+ assert.isFalse(MembersUtil.isInvalidInvitee({phoneNumber: '18578675309', isInternalNumber: true}));
191
+ assert.isTrue(MembersUtil.isInvalidInvitee({phoneNumber: '+8618578675309', isInternalNumber: true}));
192
+ });
179
193
  });
180
194
 
181
195
  describe('#admitMembers', () => {
@@ -465,29 +479,38 @@ describe('plugin-meetings', () => {
465
479
  });
466
480
  });
467
481
 
468
- describe('#cancelSIPInvite', () => {
482
+ describe('#cancelInviteByMemberId', () => {
469
483
  const memberId = uuid.v4();
470
- it('should invoke cancelSIPInviteOptions from MembersUtil when cancelSIPInvite is called with valid params', async () => {
471
- sandbox.spy(MembersUtil, 'cancelSIPInviteOptions');
484
+ it('should invoke cancelInviteByMemberIdOptions from MembersUtil when cancelInviteByMemberId is called with valid params', async () => {
485
+ sandbox.spy(MembersUtil, 'cancelInviteByMemberIdOptions');
486
+
487
+ const members = createMembers({url: url1});
488
+
489
+ await members.cancelInviteByMemberId({memberId});
490
+ assert.calledOnce(MembersUtil.cancelInviteByMemberIdOptions);
491
+ });
492
+
493
+ it('should invoke cancelInviteByMemberIdOptions from MembersUtil when cancelInviteByMemberId is called with isInternalNumber', async () => {
494
+ sandbox.spy(MembersUtil, 'cancelInviteByMemberIdOptions');
472
495
 
473
496
  const members = createMembers({url: url1});
474
497
 
475
- await members.cancelSIPInvite({memberId});
476
- assert.calledOnce(MembersUtil.cancelSIPInviteOptions);
498
+ await members.cancelInviteByMemberId({memberId, isInternalNumber: true});
499
+ assert.calledOnce(MembersUtil.cancelInviteByMemberIdOptions);
477
500
  });
478
501
 
479
502
  it('should throw a rejection if there is no locus url', async () => {
480
503
  const members = createMembers({url: false});
481
504
 
482
- assert.isRejected(members.cancelSIPInvite({memberId}));
505
+ assert.isRejected(members.cancelInviteByMemberId({memberId}));
483
506
  });
484
507
 
485
508
  it('should throw a rejection if memberId is not provided', async () => {
486
509
  const members = createMembers({url: url1});
487
510
 
488
- assert.isRejected(members.cancelSIPInvite({}));
489
- assert.isRejected(members.cancelSIPInvite({memberId: null}));
490
- assert.isRejected(members.cancelSIPInvite({memberId: undefined}));
511
+ assert.isRejected(members.cancelInviteByMemberId({}));
512
+ assert.isRejected(members.cancelInviteByMemberId({memberId: null}));
513
+ assert.isRejected(members.cancelInviteByMemberId({memberId: undefined}));
491
514
  });
492
515
  });
493
516
 
@@ -221,7 +221,7 @@ describe('plugin-meetings', () => {
221
221
  });
222
222
  });
223
223
 
224
- describe('#cancelSIPInvite', () => {
224
+ describe('#cancelInviteByMemberId', () => {
225
225
  const memberId = uuid.v4();
226
226
  it('sends a PUT to the locus endpoint', async () => {
227
227
  const options = {
@@ -231,7 +231,7 @@ describe('plugin-meetings', () => {
231
231
  locusUrl: url1,
232
232
  };
233
233
 
234
- await membersRequest.cancelSIPInvite(options);
234
+ await membersRequest.cancelInviteByMemberId(options);
235
235
 
236
236
  checkRequest({
237
237
  method: 'PUT',
@@ -302,6 +302,26 @@ describe('plugin-meetings', () => {
302
302
  });
303
303
  });
304
304
 
305
+ it('returns the correct body with phone number and isInternalNumber', () => {
306
+ const options = {
307
+ invitee: {
308
+ phoneNumber: '1234567890',
309
+ isInternalNumber: false
310
+ },
311
+ alertIfActive: false,
312
+ };
313
+
314
+ assert.deepEqual(MembersUtil.getAddMemberBody(options), {
315
+ invitees: [
316
+ {
317
+ address: '1234567890',
318
+ isInternalNumber: false
319
+ },
320
+ ],
321
+ alertIfActive: false,
322
+ });
323
+ });
324
+
305
325
  it('returns the correct body with fallback to email', () => {
306
326
  const options = {
307
327
  invitee: {
@@ -391,14 +411,14 @@ describe('plugin-meetings', () => {
391
411
  });
392
412
  });
393
413
 
394
- describe('#cancelSIPInviteOptions', () => {
414
+ describe('#cancelInviteByMemberIdOptions', () => {
395
415
  it('returns the correct options', () => {
396
416
  const locusUrl = 'TestLocusUrl';
397
417
  const memberId = 'test';
398
- const invitee = {memberId};
418
+ const invitee = {memberId, isInternalNumber: false};
399
419
 
400
420
  assert.deepEqual(
401
- MembersUtil.cancelSIPInviteOptions(
421
+ MembersUtil.cancelInviteByMemberIdOptions(
402
422
  invitee,
403
423
  locusUrl
404
424
  ),
@@ -410,22 +430,22 @@ describe('plugin-meetings', () => {
410
430
  });
411
431
  });
412
432
 
413
- describe('#generateCancelSIPInviteRequestParams', () => {
433
+ describe('#generateCancelInviteByMemberIdRequestParams', () => {
414
434
  it('returns the correct params', () => {
415
435
  const locusUrl = 'TestLocusUrl';
416
436
  const memberId = 'test';
417
437
  const options = {
418
438
  locusUrl,
419
- invitee: {memberId}
439
+ invitee: {memberId, isInternalNumber: false}
420
440
  };
421
441
  const body = {
422
442
  actionType: 'REMOVE',
423
- invitees: [{address: options.invitee.memberId}],
443
+ invitees: [{address: options.invitee.memberId, isInternalNumber: false}],
424
444
  };
425
445
 
426
446
  const uri = options.locusUrl;
427
447
 
428
- assert.deepEqual(MembersUtil.generateCancelSIPInviteRequestParams(options), {
448
+ assert.deepEqual(MembersUtil.generateCancelInviteByMemberIdRequestParams(options), {
429
449
  method: HTTP_VERBS.PUT,
430
450
  uri,
431
451
  body,
@@ -272,4 +272,63 @@ describe('SendSlotsManager', () => {
272
272
  expect(() => sendSlotsManager.getSlot(MediaType.VideoSlides)).to.throw();
273
273
  });
274
274
  });
275
+
276
+ describe('sourceStateOverride', () => {
277
+ let mediaConnection: MultistreamRoapMediaConnection;
278
+ beforeEach(() => {
279
+ mediaConnection = {
280
+ createSendSlot: sinon.stub().returns({
281
+ setSourceStateOverride: sinon.stub().resolves(),
282
+ clearSourceStateOverride: sinon.stub().resolves(),
283
+ }),
284
+ } as MultistreamRoapMediaConnection;
285
+ });
286
+
287
+ it(`can set source state override for ${MediaType.VideoMain}`, () => {
288
+ const slot: any = sendSlotsManager.createSlot(mediaConnection, MediaType.VideoMain);
289
+
290
+ const set = () => sendSlotsManager.setSourceStateOverride(MediaType.VideoMain, 'away');
291
+
292
+ expect(set).not.to.throw();
293
+ expect(slot.setSourceStateOverride.calledWith('away')).to.be.true;
294
+ });
295
+
296
+ [MediaType.VideoSlides, MediaType.AudioMain, MediaType.AudioSlides].forEach((mediaType) => {
297
+ it(`can't set source state override for ${mediaType}`, () => {
298
+ const slot: any = sendSlotsManager.createSlot(mediaConnection, mediaType);
299
+
300
+ const set = () => sendSlotsManager.setSourceStateOverride(mediaType, 'away');
301
+
302
+ expect(set).to.throw();
303
+ expect(slot.setSourceStateOverride.called).to.be.false;
304
+ });
305
+ });
306
+
307
+ it("can't set source state override for non-existing slot", () => {
308
+ const set = () => sendSlotsManager.setSourceStateOverride(MediaType.VideoMain, 'away');
309
+ expect(set).to.throw(`Slot for ${MediaType.VideoMain} does not exist`);
310
+ });
311
+
312
+ it('can clear source state override', () => {
313
+ const slot: any = sendSlotsManager.createSlot(mediaConnection, MediaType.VideoMain);
314
+ sendSlotsManager.setSourceStateOverride(MediaType.VideoMain, 'away');
315
+
316
+ expect(slot.setSourceStateOverride.calledWith('away')).to.be.true;
317
+ expect(slot.clearSourceStateOverride.called).to.be.false;
318
+
319
+ sendSlotsManager.setSourceStateOverride(MediaType.VideoMain, null);
320
+ expect(slot.clearSourceStateOverride.called).to.be.true;
321
+ });
322
+
323
+ it("won't set source state override if it didn't change", () => {
324
+ const slot: any = sendSlotsManager.createSlot(mediaConnection, MediaType.VideoMain);
325
+ sendSlotsManager.setSourceStateOverride(MediaType.VideoMain, 'away');
326
+
327
+ expect(slot.setSourceStateOverride.calledWith('away')).to.be.true;
328
+ slot.setSourceStateOverride.resetHistory();
329
+
330
+ sendSlotsManager.setSourceStateOverride(MediaType.VideoMain, 'away');
331
+ expect(slot.setSourceStateOverride.called).to.be.false;
332
+ });
333
+ });
275
334
  });
@@ -2764,14 +2764,10 @@ describe('isSubnetReachable', () => {
2764
2764
  });
2765
2765
 
2766
2766
  it('returns true if the subnet is reachable', () => {
2767
- assert(reachability.isSubnetReachable('1.2.3.4'));
2767
+ assert(reachability.isSubnetReachable('1'));
2768
2768
  });
2769
2769
 
2770
2770
  it(`returns false if the subnet is unreachable`, () => {
2771
- assert(!reachability.isSubnetReachable('11.2.3.4'));
2772
- });
2773
-
2774
- it('returns null if the subnet is not provided', () => {
2775
- assert.isNull(reachability.isSubnetReachable(undefined));
2771
+ assert(!reachability.isSubnetReachable('11'));
2776
2772
  });
2777
2773
  });