@webex/calling 3.8.0-next.9 → 3.8.0-web-workers-keepalive.2

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 (41) hide show
  1. package/dist/CallingClient/line/line.test.js +4 -10
  2. package/dist/CallingClient/line/line.test.js.map +1 -1
  3. package/dist/CallingClient/registration/register.js +333 -333
  4. package/dist/CallingClient/registration/register.js.map +1 -1
  5. package/dist/CallingClient/registration/register.test.js +312 -263
  6. package/dist/CallingClient/registration/register.test.js.map +1 -1
  7. package/dist/CallingClient/registration/webWorker.js +115 -0
  8. package/dist/CallingClient/registration/webWorker.js.map +1 -0
  9. package/dist/CallingClient/registration/webWorker.test.js +256 -0
  10. package/dist/CallingClient/registration/webWorker.test.js.map +1 -0
  11. package/dist/SDKConnector/types.js.map +1 -1
  12. package/dist/Voicemail/WxCallBackendConnector.js +189 -120
  13. package/dist/Voicemail/WxCallBackendConnector.js.map +1 -1
  14. package/dist/Voicemail/WxCallBackendConnector.test.js +199 -4
  15. package/dist/Voicemail/WxCallBackendConnector.test.js.map +1 -1
  16. package/dist/Voicemail/types.js.map +1 -1
  17. package/dist/common/testUtil.js +3 -0
  18. package/dist/common/testUtil.js.map +1 -1
  19. package/dist/common/types.js +8 -1
  20. package/dist/common/types.js.map +1 -1
  21. package/dist/module/CallingClient/registration/register.js +50 -54
  22. package/dist/module/CallingClient/registration/webWorker.js +59 -0
  23. package/dist/module/Voicemail/WxCallBackendConnector.js +17 -1
  24. package/dist/module/common/testUtil.js +3 -0
  25. package/dist/module/common/types.js +7 -0
  26. package/dist/types/CallingClient/registration/register.d.ts +1 -2
  27. package/dist/types/CallingClient/registration/register.d.ts.map +1 -1
  28. package/dist/types/CallingClient/registration/webWorker.d.ts +2 -0
  29. package/dist/types/CallingClient/registration/webWorker.d.ts.map +1 -0
  30. package/dist/types/SDKConnector/types.d.ts +3 -0
  31. package/dist/types/SDKConnector/types.d.ts.map +1 -1
  32. package/dist/types/Voicemail/Voicemail.d.ts +1 -1
  33. package/dist/types/Voicemail/WxCallBackendConnector.d.ts +3 -1
  34. package/dist/types/Voicemail/WxCallBackendConnector.d.ts.map +1 -1
  35. package/dist/types/Voicemail/types.d.ts +1 -1
  36. package/dist/types/Voicemail/types.d.ts.map +1 -1
  37. package/dist/types/common/testUtil.d.ts +3 -0
  38. package/dist/types/common/testUtil.d.ts.map +1 -1
  39. package/dist/types/common/types.d.ts +12 -0
  40. package/dist/types/common/types.d.ts.map +1 -1
  41. package/package.json +5 -4
@@ -323,16 +323,15 @@ describe('Registration Tests', function () {
323
323
  while (1) switch (_context7.prev = _context7.next) {
324
324
  case 0:
325
325
  /* keep keepalive as active so that it wont interfere with the failback tests */
326
- jest.spyOn(reg, 'postKeepAlive').mockResolvedValue(successPayload);
327
326
  jest.useFakeTimers();
328
327
  postRegistrationSpy.mockRejectedValueOnce(failurePayload).mockRejectedValueOnce(failurePayload).mockResolvedValueOnce(successPayload);
329
- _context7.next = 5;
328
+ _context7.next = 4;
330
329
  return reg.triggerRegistration();
331
- case 5:
330
+ case 4:
332
331
  jest.advanceTimersByTime(_constants.REG_TRY_BACKUP_TIMER_VAL_IN_SEC * _constants.SEC_TO_MSEC_MFACTOR);
333
- _context7.next = 8;
332
+ _context7.next = 7;
334
333
  return flushPromises();
335
- case 8:
334
+ case 7:
336
335
  reg.rehomingIntervalMin = _constants.DEFAULT_REHOMING_INTERVAL_MIN;
337
336
  reg.rehomingIntervalMax = _constants.DEFAULT_REHOMING_INTERVAL_MAX;
338
337
 
@@ -342,7 +341,7 @@ describe('Registration Tests', function () {
342
341
  /* Active Url must match with the backup url as per the test */
343
342
  expect(reg.getActiveMobiusUrl()).toStrictEqual(mobiusUris.backup[0]);
344
343
  expect(reg.getStatus()).toEqual(_types.RegistrationStatus.ACTIVE);
345
- case 13:
344
+ case 12:
346
345
  case "end":
347
346
  return _context7.stop();
348
347
  }
@@ -544,13 +543,6 @@ describe('Registration Tests', function () {
544
543
 
545
544
  // Keep-alive related test cases
546
545
  describe('Keep-alive Tests', function () {
547
- var logObj = {
548
- file: _constants.REGISTRATION_FILE,
549
- method: 'startKeepaliveTimer'
550
- };
551
- var mockKeepAliveBody = {
552
- device: _registerFixtures.mockPostResponse.device
553
- };
554
546
  var beforeEachSetupForKeepalive = /*#__PURE__*/function () {
555
547
  var _ref14 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee14() {
556
548
  return _regenerator.default.wrap(function _callee14$(_context14) {
@@ -562,7 +554,8 @@ describe('Registration Tests', function () {
562
554
  return reg.triggerRegistration();
563
555
  case 4:
564
556
  expect(reg.getStatus()).toBe(_types.RegistrationStatus.ACTIVE);
565
- case 5:
557
+ expect(reg.webWorker).toBeDefined();
558
+ case 6:
566
559
  case "end":
567
560
  return _context14.stop();
568
561
  }
@@ -575,10 +568,7 @@ describe('Registration Tests', function () {
575
568
  afterEach(function () {
576
569
  jest.clearAllTimers();
577
570
  jest.clearAllMocks();
578
- if (reg.keepaliveTimer) {
579
- clearInterval(reg.keepaliveTimer);
580
- reg.keepaliveTimer = undefined;
581
- }
571
+ reg.clearKeepaliveTimer();
582
572
  reg.reconnectPending = false;
583
573
  var calls = (0, _values.default)(reg.callManager.getActiveCalls());
584
574
  calls.forEach(function (call) {
@@ -586,165 +576,164 @@ describe('Registration Tests', function () {
586
576
  });
587
577
  });
588
578
  it('verify successful keep-alive cases', /*#__PURE__*/(0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee15() {
589
- var keepAlivePayload, funcSpy;
579
+ var postMessageSpy;
590
580
  return _regenerator.default.wrap(function _callee15$(_context15) {
591
581
  while (1) switch (_context15.prev = _context15.next) {
592
582
  case 0:
593
- _context15.next = 2;
583
+ postMessageSpy = jest.spyOn(Worker.prototype, 'postMessage');
584
+ _context15.next = 3;
594
585
  return beforeEachSetupForKeepalive();
595
- case 2:
596
- keepAlivePayload = {
597
- statusCode: 200,
598
- body: mockKeepAliveBody
599
- };
600
- webex.request.mockReturnValue(keepAlivePayload);
601
- funcSpy = jest.spyOn(reg, 'postKeepAlive');
602
- jest.advanceTimersByTime(2 * _registerFixtures.mockPostResponse.keepaliveInterval * _constants.SEC_TO_MSEC_MFACTOR);
603
- _context15.next = 8;
604
- return flushPromises();
605
- case 8:
606
- expect(funcSpy).toBeCalledTimes(2); // should be called 2 times: first try and after the interval.
607
- expect(logSpy).lastCalledWith('Sent Keepalive, status: 200', logObj);
608
- case 10:
586
+ case 3:
587
+ expect(reg.webWorker).toBeDefined();
588
+ expect(postMessageSpy).toHaveBeenCalledWith(expect.objectContaining({
589
+ type: 'START_KEEPALIVE',
590
+ accessToken: expect.any(String),
591
+ deviceUrl: expect.any(String),
592
+ interval: expect.any(Number),
593
+ retryCountThreshold: expect.any(Number),
594
+ url: expect.any(String)
595
+ }));
596
+ reg.webWorker.onmessage({
597
+ data: {
598
+ type: 'KEEPALIVE_SUCCESS',
599
+ statusCode: 200
600
+ }
601
+ });
602
+ expect(lineEmitter).toBeCalledWith(_types4.LINE_EVENTS.RECONNECTED);
603
+ case 7:
609
604
  case "end":
610
605
  return _context15.stop();
611
606
  }
612
607
  }, _callee15);
613
608
  })));
614
609
  it('verify failure keep-alive cases: Retry Success', /*#__PURE__*/(0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee16() {
615
- var failurePayload, successPayload, timer;
610
+ var worker;
616
611
  return _regenerator.default.wrap(function _callee16$(_context16) {
617
612
  while (1) switch (_context16.prev = _context16.next) {
618
613
  case 0:
619
614
  _context16.next = 2;
620
615
  return beforeEachSetupForKeepalive();
621
616
  case 2:
622
- failurePayload = {
623
- statusCode: 503,
624
- body: mockKeepAliveBody
625
- };
626
- successPayload = {
627
- statusCode: 200,
628
- body: mockKeepAliveBody
629
- };
630
- timer = reg.keepaliveTimer;
617
+ worker = reg.webWorker;
631
618
  lineEmitter.mockClear();
632
- webex.request.mockRejectedValueOnce(failurePayload).mockResolvedValue(successPayload);
633
- jest.advanceTimersByTime(2 * _registerFixtures.mockPostResponse.keepaliveInterval * _constants.SEC_TO_MSEC_MFACTOR);
634
- _context16.next = 10;
635
- return flushPromises();
636
- case 10:
637
- expect(handleErrorSpy).toBeCalledOnceWith(failurePayload, expect.anything(), {
638
- method: 'startKeepaliveTimer',
639
- file: _constants.REGISTRATION_FILE
619
+ worker.onmessage({
620
+ data: {
621
+ type: 'KEEPALIVE_FAILURE',
622
+ err: {
623
+ statusCode: 503
624
+ },
625
+ keepAliveRetryCount: 1
626
+ }
640
627
  });
641
- expect(reg.getStatus()).toBe(_types.RegistrationStatus.ACTIVE);
642
- expect(reg.keepaliveTimer).toBe(timer);
643
- expect(lineEmitter).nthCalledWith(1, _types4.LINE_EVENTS.RECONNECTING);
644
- expect(lineEmitter).nthCalledWith(2, _types4.LINE_EVENTS.RECONNECTED);
645
- expect(lineEmitter).toBeCalledTimes(2);
646
- case 16:
628
+ worker.onmessage({
629
+ data: {
630
+ type: 'KEEPALIVE_SUCCESS',
631
+ statusCode: 200
632
+ }
633
+ });
634
+ expect(lineEmitter).toHaveBeenCalledWith(_types4.LINE_EVENTS.RECONNECTED);
635
+ case 7:
647
636
  case "end":
648
637
  return _context16.stop();
649
638
  }
650
639
  }, _callee16);
651
640
  })));
652
641
  it('verify failure keep-alive cases: Restore failure', /*#__PURE__*/(0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee17() {
653
- var restoreSpy, restartRegSpy, reconnectSpy, failurePayload, clearIntervalSpy, timer;
642
+ var reconnectSpy, RETRY_COUNT_THRESHOLD, failureEvent;
654
643
  return _regenerator.default.wrap(function _callee17$(_context17) {
655
644
  while (1) switch (_context17.prev = _context17.next) {
656
645
  case 0:
657
646
  _context17.next = 2;
658
647
  return beforeEachSetupForKeepalive();
659
648
  case 2:
660
- restoreSpy = jest.spyOn(reg, 'restorePreviousRegistration');
661
- restartRegSpy = jest.spyOn(reg, 'restartRegistration');
662
- reconnectSpy = jest.spyOn(reg, 'reconnectOnFailure');
663
- failurePayload = {
664
- statusCode: 503,
665
- body: mockKeepAliveBody
666
- };
667
- clearIntervalSpy = jest.spyOn(global, 'clearInterval');
649
+ reconnectSpy = jest.spyOn(reg, 'reconnectOnFailure'); // Clear previous event emissions
668
650
  lineEmitter.mockClear();
669
- webex.request.mockRejectedValue(failurePayload);
651
+
652
+ // Assume registration is active
670
653
  expect(reg.getStatus()).toEqual(_types.RegistrationStatus.ACTIVE);
671
- timer = reg.keepaliveTimer;
672
- jest.advanceTimersByTime(5 * _registerFixtures.mockPostResponse.keepaliveInterval * _constants.SEC_TO_MSEC_MFACTOR);
673
- _context17.next = 14;
674
- return flushPromises();
675
- case 14:
676
- expect(clearIntervalSpy).toBeCalledOnceWith(timer);
677
654
 
678
- // sendKeepAlive tries to retry 5 times before accepting failure
679
- // later 2 attempts to register with primary server
680
- expect(handleErrorSpy).toBeCalledTimes(7);
681
- expect(reg.getStatus()).toEqual(_types.RegistrationStatus.INACTIVE);
682
- expect(reg.reconnectPending).toStrictEqual(false);
683
- expect(reconnectSpy).toBeCalledOnceWith(_constants.KEEPALIVE_UTIL);
684
- expect(restoreSpy).toBeCalledOnceWith(_constants.KEEPALIVE_UTIL);
685
- expect(restartRegSpy).toBeCalledOnceWith(_constants.KEEPALIVE_UTIL);
686
- expect(webex.request).toBeCalledTimes(7);
687
- expect(reg.keepaliveTimer).toBe(undefined);
688
- expect(lineEmitter).nthCalledWith(1, _types4.LINE_EVENTS.RECONNECTING);
689
- expect(lineEmitter).nthCalledWith(4, _types4.LINE_EVENTS.RECONNECTING);
690
- expect(lineEmitter).nthCalledWith(5, _types4.LINE_EVENTS.UNREGISTERED);
655
+ // Use fake timers to trigger keepalive initialization
656
+ jest.useFakeTimers();
657
+ jest.advanceTimersByTime(_registerFixtures.mockPostResponse.keepaliveInterval * _constants.SEC_TO_MSEC_MFACTOR);
691
658
 
692
- /** there will be 2 registration attempts */
693
- expect(lineEmitter).nthCalledWith(6, _types4.LINE_EVENTS.CONNECTING);
694
- expect(lineEmitter).nthCalledWith(7, _types4.LINE_EVENTS.UNREGISTERED);
695
- expect(lineEmitter).nthCalledWith(8, _types4.LINE_EVENTS.CONNECTING);
696
- expect(lineEmitter).nthCalledWith(9, _types4.LINE_EVENTS.UNREGISTERED);
697
- expect(lineEmitter).toBeCalledTimes(9);
698
- case 31:
659
+ // Simulate the worker sending a KEEPALIVE_FAILURE message with retry count at threshold.
660
+ RETRY_COUNT_THRESHOLD = reg.isCCFlow ? 4 : 5;
661
+ failureEvent = {
662
+ data: {
663
+ type: _types.WorkerMessageType.KEEPALIVE_FAILURE,
664
+ err: {
665
+ statusCode: 503
666
+ },
667
+ keepAliveRetryCount: RETRY_COUNT_THRESHOLD
668
+ }
669
+ };
670
+ reg.webWorker.onmessage(failureEvent);
671
+ _context17.next = 12;
672
+ return flushPromises();
673
+ case 12:
674
+ expect(reg.getStatus()).toEqual(_types.RegistrationStatus.INACTIVE);
675
+ expect(lineEmitter).toHaveBeenCalledWith(_types4.LINE_EVENTS.UNREGISTERED);
676
+ expect(reconnectSpy).toBeCalledOnceWith('startKeepaliveTimer');
677
+ jest.useRealTimers();
678
+ case 16:
699
679
  case "end":
700
680
  return _context17.stop();
701
681
  }
702
682
  }, _callee17);
703
683
  })));
704
684
  it('verify failure keep-alive cases: Restore Success', /*#__PURE__*/(0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee18() {
705
- var restoreSpy, restartRegSpy, reconnectSpy, failurePayload, successPayload, clearIntervalSpy, url, timer;
685
+ var reconnectSpy, url;
706
686
  return _regenerator.default.wrap(function _callee18$(_context18) {
707
687
  while (1) switch (_context18.prev = _context18.next) {
708
688
  case 0:
709
689
  _context18.next = 2;
710
690
  return beforeEachSetupForKeepalive();
711
691
  case 2:
712
- restoreSpy = jest.spyOn(reg, 'restorePreviousRegistration');
713
- restartRegSpy = jest.spyOn(reg, 'restartRegistration');
692
+ expect(reg.webWorker).toBeDefined();
714
693
  reconnectSpy = jest.spyOn(reg, 'reconnectOnFailure');
715
- failurePayload = {
716
- statusCode: 503,
717
- body: mockKeepAliveBody
718
- };
719
- successPayload = {
720
- statusCode: 200,
721
- body: mockKeepAliveBody
722
- };
723
- clearIntervalSpy = jest.spyOn(global, 'clearInterval');
724
- webex.request.mockRejectedValueOnce(failurePayload).mockRejectedValueOnce(failurePayload).mockRejectedValueOnce(failurePayload).mockRejectedValueOnce(failurePayload).mockRejectedValueOnce(failurePayload).mockResolvedValue(successPayload);
725
-
726
- /* successful registration */
727
- // webex.request.mockResolvedValue(successPayload);
728
-
729
- expect(reg.getStatus()).toEqual(_types.RegistrationStatus.ACTIVE);
730
- url = 'https://mobius.asydm-m-1.prod.infra.webex.com/api/v1';
731
- /* set active Url and expect the registration to restore to this url */
732
- reg.setActiveMobiusUrl(url);
733
- timer = reg.keepaliveTimer;
734
- jest.advanceTimersByTime(5 * _registerFixtures.mockPostResponse.keepaliveInterval * _constants.SEC_TO_MSEC_MFACTOR);
694
+ url = 'https://mobius-dfw.webex.com/api/v1/calling/web/';
695
+ reg.webWorker.onmessage({
696
+ data: {
697
+ type: _types.WorkerMessageType.KEEPALIVE_FAILURE,
698
+ err: {
699
+ statusCode: 503
700
+ },
701
+ keepAliveRetryCount: 5
702
+ }
703
+ });
704
+ jest.advanceTimersByTime(1000);
705
+ _context18.next = 9;
706
+ return flushPromises();
707
+ case 9:
708
+ expect(reg.webWorker).toBeUndefined();
709
+ expect(reconnectSpy).toBeCalledOnceWith(reg.startKeepaliveTimer.name);
710
+ webex.request.mockResolvedValueOnce(successPayload);
711
+ _context18.next = 14;
712
+ return reg.triggerRegistration();
713
+ case 14:
735
714
  _context18.next = 16;
736
715
  return flushPromises();
737
716
  case 16:
738
- expect(clearIntervalSpy).toBeCalledOnceWith(timer);
739
- expect(handleErrorSpy).toBeCalledTimes(5);
717
+ expect(reg.webWorker).toBeDefined();
718
+ reg.webWorker.onmessage({
719
+ data: {
720
+ type: _types.WorkerMessageType.KEEPALIVE_SUCCESS,
721
+ statusCode: 200
722
+ }
723
+ });
724
+
725
+ // Advance timers and flush any remaining promises.
726
+ jest.advanceTimersByTime(1000);
727
+ _context18.next = 21;
728
+ return flushPromises();
729
+ case 21:
740
730
  expect(reg.getStatus()).toEqual(_types.RegistrationStatus.ACTIVE);
741
- expect(reconnectSpy).toBeCalledOnceWith(_constants.KEEPALIVE_UTIL);
742
- expect(restoreSpy).toBeCalledOnceWith(_constants.KEEPALIVE_UTIL);
743
- expect(restartRegSpy).not.toBeCalled();
731
+ // reconnectSpy should have been called only once.
732
+ expect(reconnectSpy).toBeCalledTimes(1);
733
+ expect(restoreSpy).toBeCalledOnceWith(reg.startKeepaliveTimer.name);
734
+ expect(restartSpy).toBeCalledOnceWith(reg.startKeepaliveTimer.name);
735
+ // Active Mobius URL should remain unchanged.
744
736
  expect(reg.getActiveMobiusUrl()).toStrictEqual(url);
745
- expect(reg.reconnectPending).toStrictEqual(false);
746
- expect(reg.keepaliveTimer).toBeTruthy();
747
- expect(reg.keepaliveTimer).not.toBe(timer);
748
737
  case 26:
749
738
  case "end":
750
739
  return _context18.stop();
@@ -752,42 +741,84 @@ describe('Registration Tests', function () {
752
741
  }, _callee18);
753
742
  })));
754
743
  it('verify failure followed by recovery of keepalive', /*#__PURE__*/(0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee19() {
755
- var failurePayload, successPayload, clearIntervalSpy, timer;
756
744
  return _regenerator.default.wrap(function _callee19$(_context19) {
757
745
  while (1) switch (_context19.prev = _context19.next) {
758
746
  case 0:
759
747
  _context19.next = 2;
760
748
  return beforeEachSetupForKeepalive();
761
749
  case 2:
762
- failurePayload = {
763
- statusCode: 503,
764
- body: mockKeepAliveBody
765
- };
766
- successPayload = {
767
- statusCode: 200,
768
- body: mockKeepAliveBody
769
- };
770
- clearIntervalSpy = jest.spyOn(global, 'clearInterval');
771
- webex.request.mockRejectedValueOnce(failurePayload).mockRejectedValueOnce(failurePayload).mockResolvedValue(successPayload);
772
750
  expect(reg.getStatus()).toBe(_types.RegistrationStatus.ACTIVE);
773
- timer = reg.keepaliveTimer; // sendKeepAlive tries to retry 3 times and receiving success on third time
774
- jest.advanceTimersByTime(3 * _registerFixtures.mockPostResponse.keepaliveInterval * _constants.SEC_TO_MSEC_MFACTOR);
775
- _context19.next = 11;
751
+ expect(reg.webWorker).toBeDefined();
752
+ webex.request.mockRejectedValueOnce(failurePayload).mockRejectedValueOnce(failurePayload).mockResolvedValue(successPayload);
753
+ reg.webWorker.onmessage({
754
+ data: {
755
+ type: _types.WorkerMessageType.KEEPALIVE_FAILURE,
756
+ err: failurePayload,
757
+ keepAliveRetryCount: reg.isCCFlow ? 4 : 5
758
+ }
759
+ });
760
+ _context19.next = 8;
776
761
  return flushPromises();
777
- case 11:
778
- expect(webex.request).toBeCalledTimes(3);
779
- expect(reg.getStatus()).toBe(_types.RegistrationStatus.ACTIVE);
780
- expect(handleErrorSpy).toBeCalledTimes(2);
781
- expect(clearIntervalSpy).not.toBeCalled();
782
- expect(reg.keepaliveTimer).toBe(timer);
783
- case 16:
762
+ case 8:
763
+ expect(reg.webWorker).toBeUndefined();
764
+ expect(handleErrorSpy).toBeCalledTimes(3);
765
+ _context19.next = 12;
766
+ return reg.triggerRegistration();
767
+ case 12:
768
+ _context19.next = 14;
769
+ return flushPromises();
770
+ case 14:
771
+ expect(reg.webWorker).toBeDefined();
772
+ reg.webWorker.onmessage({
773
+ data: {
774
+ type: _types.WorkerMessageType.KEEPALIVE_SUCCESS,
775
+ statusCode: 200
776
+ }
777
+ });
778
+ _context19.next = 18;
779
+ return flushPromises();
780
+ case 18:
781
+ // In a complete failure‐then-recovery scenario, we expect another failure event to have been handled.
782
+ // For that, simulate a second failure event on the new worker.
783
+ reg.webWorker.onmessage({
784
+ data: {
785
+ type: _types.WorkerMessageType.KEEPALIVE_FAILURE,
786
+ err: failurePayload,
787
+ keepAliveRetryCount: reg.isCCFlow ? 4 : 5
788
+ }
789
+ });
790
+ _context19.next = 21;
791
+ return flushPromises();
792
+ case 21:
793
+ expect(handleErrorSpy).toBeCalledTimes(4);
794
+
795
+ // And then re-register successfully:
796
+ _context19.next = 24;
797
+ return reg.triggerRegistration();
798
+ case 24:
799
+ _context19.next = 26;
800
+ return flushPromises();
801
+ case 26:
802
+ expect(reg.webWorker).toBeDefined();
803
+ reg.webWorker.onmessage({
804
+ data: {
805
+ type: _types.WorkerMessageType.KEEPALIVE_SUCCESS,
806
+ statusCode: 200
807
+ }
808
+ });
809
+ _context19.next = 30;
810
+ return flushPromises();
811
+ case 30:
812
+ expect(reg.getStatus()).toEqual(_types.RegistrationStatus.ACTIVE);
813
+ expect(reg.webWorker).toBeDefined();
814
+ case 32:
784
815
  case "end":
785
816
  return _context19.stop();
786
817
  }
787
818
  }, _callee19);
788
819
  })));
789
820
  it('cc: verify failover to backup server after 4 keep alive failure with primary server', /*#__PURE__*/(0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee20() {
790
- var failurePayload, successPayload, clearIntervalSpy, timer;
821
+ var clearKeepaliveSpy, reconnectSpy;
791
822
  return _regenerator.default.wrap(function _callee20$(_context20) {
792
823
  while (1) switch (_context20.prev = _context20.next) {
793
824
  case 0:
@@ -798,159 +829,177 @@ describe('Registration Tests', function () {
798
829
  _context20.next = 3;
799
830
  return beforeEachSetupForKeepalive();
800
831
  case 3:
801
- failurePayload = {
802
- statusCode: 503,
803
- body: mockKeepAliveBody
804
- };
805
- successPayload = {
806
- statusCode: 200,
807
- body: mockKeepAliveBody
808
- };
809
- clearIntervalSpy = jest.spyOn(global, 'clearInterval');
810
- jest.spyOn(reg, 'postKeepAlive').mockRejectedValueOnce(failurePayload).mockRejectedValueOnce(failurePayload).mockRejectedValueOnce(failurePayload).mockRejectedValueOnce(failurePayload).mockResolvedValue(successPayload);
811
- expect(reg.getStatus()).toBe(_types.RegistrationStatus.ACTIVE);
812
- timer = reg.keepaliveTimer;
813
- jest.advanceTimersByTime(5 * _registerFixtures.mockPostResponse.keepaliveInterval * _constants.SEC_TO_MSEC_MFACTOR);
814
- _context20.next = 12;
815
- return flushPromises();
816
- case 12:
817
- expect(clearIntervalSpy).toBeCalledOnceWith(timer);
818
- expect(reg.getStatus()).toBe(_types.RegistrationStatus.INACTIVE);
819
- expect(reg.keepaliveTimer).not.toBe(timer);
820
- webex.request.mockResolvedValue(successPayload);
821
- jest.advanceTimersByTime(_constants.REG_TRY_BACKUP_TIMER_VAL_FOR_CC_IN_SEC * _constants.SEC_TO_MSEC_MFACTOR);
822
- _context20.next = 19;
832
+ webex.request.mockResolvedValueOnce(successPayload);
833
+ _context20.next = 6;
834
+ return reg.triggerRegistration();
835
+ case 6:
836
+ expect(reg.getStatus()).toEqual(_types.RegistrationStatus.ACTIVE);
837
+ expect(reg.webWorker).toBeDefined();
838
+
839
+ // Spy on clearKeepaliveTimer and simulate reconnectOnFailure behavior
840
+ clearKeepaliveSpy = jest.spyOn(reg, 'clearKeepaliveTimer');
841
+ reconnectSpy = jest.spyOn(reg, 'reconnectOnFailure'); // Simulate a KEEPALIVE_FAILURE message from the worker with a retry count equal to threshold (4 for CC)
842
+ reg.webWorker.onmessage({
843
+ data: {
844
+ type: _types.WorkerMessageType.KEEPALIVE_FAILURE,
845
+ err: {
846
+ statusCode: 503
847
+ },
848
+ keepAliveRetryCount: 4
849
+ }
850
+ });
851
+
852
+ // Wait for any asynchronous actions to complete
853
+ _context20.next = 13;
823
854
  return flushPromises();
824
- case 19:
825
- /* Active Url must match with the backup url as per the test */
855
+ case 13:
856
+ // Verify that the keepalive timer was cleared and reconnectOnFailure was triggered
857
+ expect(clearKeepaliveSpy).toHaveBeenCalled();
858
+ expect(reconnectSpy).toHaveBeenCalledWith(reg.startKeepaliveTimer.name);
859
+
860
+ // Verify that the active Mobius URL has been updated to the backup server and registration is active
826
861
  expect(reg.getActiveMobiusUrl()).toEqual(mobiusUris.backup[0]);
827
- expect(reg.getStatus()).toBe(_types.RegistrationStatus.ACTIVE);
828
- case 21:
862
+ expect(reg.getStatus()).toEqual(_types.RegistrationStatus.ACTIVE);
863
+ case 17:
829
864
  case "end":
830
865
  return _context20.stop();
831
866
  }
832
867
  }, _callee20);
833
868
  })));
834
869
  it('verify final error for keep-alive', /*#__PURE__*/(0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee21() {
835
- var restoreSpy, restartRegSpy, reconnectSpy, failurePayload, clearIntervalSpy;
870
+ var threshold, reconnectSpy;
836
871
  return _regenerator.default.wrap(function _callee21$(_context21) {
837
872
  while (1) switch (_context21.prev = _context21.next) {
838
873
  case 0:
839
874
  _context21.next = 2;
840
875
  return beforeEachSetupForKeepalive();
841
876
  case 2:
842
- restoreSpy = jest.spyOn(reg, 'restorePreviousRegistration');
843
- restartRegSpy = jest.spyOn(reg, 'restartRegistration');
877
+ threshold = reg.isCCFlow ? 4 : 5;
844
878
  reconnectSpy = jest.spyOn(reg, 'reconnectOnFailure');
845
- failurePayload = {
846
- statusCode: 404,
847
- body: mockKeepAliveBody
848
- };
849
- clearIntervalSpy = jest.spyOn(global, 'clearInterval');
850
- webex.request.mockRejectedValue(failurePayload);
851
- expect(reg.getStatus()).toBe(_types.RegistrationStatus.ACTIVE);
852
-
853
- /* send one keepalive */
854
- jest.advanceTimersByTime(_registerFixtures.mockPostResponse.keepaliveInterval * _constants.SEC_TO_MSEC_MFACTOR);
855
- _context21.next = 12;
856
- return flushPromises();
857
- case 12:
858
- expect(clearIntervalSpy).toBeCalledTimes(1);
859
- expect(reg.getStatus()).toBe(_types.RegistrationStatus.INACTIVE);
860
- expect(reconnectSpy).not.toBeCalled();
861
- expect(restoreSpy).not.toBeCalled();
862
- expect(restartRegSpy).not.toBeCalled();
863
- expect(reg.reconnectPending).toStrictEqual(false);
864
- expect(webex.request).toBeCalledOnceWith({
865
- headers: mockResponse.headers,
866
- uri: "".concat(mockKeepAliveBody.device.uri, "/status"),
867
- method: 'POST',
868
- service: mockResponse.service
869
- });
870
- expect(reg.keepaliveTimer).toBe(undefined);
871
- expect(handleErrorSpy).toBeCalledOnceWith(failurePayload, expect.anything(), {
872
- file: _constants.REGISTRATION_FILE,
873
- method: _constants.KEEPALIVE_UTIL
879
+ jest.spyOn(utils, 'handleRegistrationErrors').mockResolvedValue(true);
880
+ reg.webWorker.onmessage({
881
+ data: {
882
+ type: _types.WorkerMessageType.KEEPALIVE_FAILURE,
883
+ err: {
884
+ statusCode: 404
885
+ },
886
+ keepAliveRetryCount: threshold
887
+ }
874
888
  });
875
- case 21:
889
+ _context21.next = 8;
890
+ return flushPromises();
891
+ case 8:
892
+ expect(reg.getStatus()).toEqual(_types.RegistrationStatus.INACTIVE);
893
+ expect(lineEmitter).toHaveBeenCalledWith(_types4.LINE_EVENTS.UNREGISTERED);
894
+ expect(reconnectSpy).not.toHaveBeenCalled();
895
+ case 11:
876
896
  case "end":
877
897
  return _context21.stop();
878
898
  }
879
899
  }, _callee21);
880
900
  })));
881
901
  it('verify failure keep-alive case with active call present: Restore Success after call ends', /*#__PURE__*/(0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee22() {
882
- var restoreSpy, restartRegSpy, reconnectSpy, failurePayload, successPayload, clearIntervalSpy, url, timer, call;
902
+ var clearTimerSpy, threshold, failureEvent;
883
903
  return _regenerator.default.wrap(function _callee22$(_context22) {
884
904
  while (1) switch (_context22.prev = _context22.next) {
885
905
  case 0:
886
906
  _context22.next = 2;
887
907
  return beforeEachSetupForKeepalive();
888
908
  case 2:
889
- restoreSpy = jest.spyOn(reg, 'restorePreviousRegistration');
890
- restartRegSpy = jest.spyOn(reg, 'restartRegistration');
891
- reconnectSpy = jest.spyOn(reg, 'reconnectOnFailure');
892
- failurePayload = {
893
- statusCode: 503,
894
- body: mockKeepAliveBody
895
- };
896
- successPayload = {
897
- statusCode: 200,
898
- body: mockKeepAliveBody
909
+ // Simulate an active call.
910
+ reg.callManager.createCall();
911
+ expect((0, _keys.default)(reg.callManager.getActiveCalls()).length).toBeGreaterThan(0);
912
+ clearTimerSpy = jest.spyOn(reg, 'clearKeepaliveTimer');
913
+ threshold = reg.isCCFlow ? 4 : 5; // Simulate a KEEPALIVE_FAILURE event with a 503 error at threshold.
914
+ failureEvent = {
915
+ data: {
916
+ type: _types.WorkerMessageType.KEEPALIVE_FAILURE,
917
+ err: {
918
+ statusCode: 503
919
+ },
920
+ keepAliveRetryCount: threshold
921
+ }
899
922
  };
900
- clearIntervalSpy = jest.spyOn(global, 'clearInterval');
901
- webex.request.mockRejectedValueOnce(failurePayload).mockRejectedValueOnce(failurePayload).mockRejectedValueOnce(failurePayload).mockRejectedValueOnce(failurePayload).mockRejectedValueOnce(failurePayload).mockResolvedValue(successPayload);
902
-
903
- // jest.spyOn(callingClient['registration'], 'createDevice').mockResolvedValue(successPayload);
904
- url = 'https://mobius.asydm-m-1.prod.infra.webex.com/api/v1';
905
- reg.setActiveMobiusUrl(url);
906
- expect(reg.reconnectPending).toStrictEqual(false);
907
- timer = reg.keepaliveTimer;
908
- /* add a call to the callManager */
909
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
910
- call = reg.callManager.createCall();
911
- expect((0, _keys.default)(reg.callManager.getActiveCalls()).length).toBe(1);
912
-
913
- /* send one keepalive */
914
- jest.advanceTimersByTime(5 * _registerFixtures.mockPostResponse.keepaliveInterval * _constants.SEC_TO_MSEC_MFACTOR);
915
- _context22.next = 18;
923
+ reg.webWorker.onmessage(failureEvent);
924
+ _context22.next = 10;
916
925
  return flushPromises();
917
- case 18:
918
- expect(clearIntervalSpy).toBeCalledOnceWith(timer);
919
- expect(handleErrorSpy).toBeCalledTimes(5);
920
- expect(reg.keepaliveTimer).toStrictEqual(undefined);
921
- expect(reg.failbackTimer).toStrictEqual(undefined);
922
- expect(reg.getStatus()).toBe(_types.RegistrationStatus.INACTIVE);
923
- expect(lineEmitter).lastCalledWith(_types4.LINE_EVENTS.UNREGISTERED);
924
- expect(reconnectSpy).toBeCalledOnceWith(_constants.KEEPALIVE_UTIL);
925
- expect(restoreSpy).not.toBeCalled();
926
- expect(restartRegSpy).not.toBeCalled();
927
- expect(reg.reconnectPending).toStrictEqual(true);
928
- expect(logSpy).toBeCalledWith('Active call(s) present, deferred reconnect till call cleanup.', {
929
- file: _constants.REGISTRATION_FILE,
930
- method: expect.any(String)
931
- });
932
- reconnectSpy.mockClear();
926
+ case 10:
927
+ // At this point, clearKeepaliveTimer was called so the worker is terminated.
928
+ expect(clearTimerSpy).toHaveBeenCalled();
929
+ expect(reg.getStatus()).toEqual(_types.RegistrationStatus.INACTIVE);
930
+ expect(reg.webWorker).toBeUndefined();
933
931
 
934
- /* simulate call disconnect and Calling client will trigger reconnect upon receiving disconnect event from CallManager */
932
+ // Now simulate call cleanup.
935
933
  reg.callManager.callCollection = {};
936
- _context22.next = 33;
937
- return reg.reconnectOnFailure(_constants.CALLS_CLEARED_HANDLER_UTIL);
938
- case 33:
939
- expect((0, _keys.default)(reg.callManager.getActiveCalls()).length).toBe(0);
940
- expect(reg.getStatus()).toBe(_types.RegistrationStatus.ACTIVE);
941
- expect(reconnectSpy).toBeCalledOnceWith(_constants.CALLS_CLEARED_HANDLER_UTIL);
942
- expect(restoreSpy).toBeCalledOnceWith(_constants.CALLS_CLEARED_HANDLER_UTIL);
943
- expect(restartRegSpy).not.toBeCalled();
944
- expect(reg.reconnectPending).toStrictEqual(false);
945
- expect(reg.getActiveMobiusUrl()).toStrictEqual(url);
946
- expect(reg.keepaliveTimer).toBeTruthy();
947
- expect(reg.keepaliveTimer).not.toBe(timer);
948
- case 42:
934
+ webex.request.mockResolvedValueOnce(successPayload);
935
+
936
+ // Call reconnectOnFailure manually. With no active calls, this should trigger re-registration.
937
+ _context22.next = 17;
938
+ return reg.reconnectOnFailure('activeCallEnded');
939
+ case 17:
940
+ _context22.next = 19;
941
+ return flushPromises();
942
+ case 19:
943
+ // After re-registration, registration status becomes ACTIVE and a new worker is created.
944
+ expect(reg.getStatus()).toEqual(_types.RegistrationStatus.ACTIVE);
945
+ expect(reg.isReconnectPending()).toBe(false);
946
+ expect(reg.webWorker).toBeDefined();
947
+ case 22:
949
948
  case "end":
950
949
  return _context22.stop();
951
950
  }
952
951
  }, _callee22);
953
952
  })));
953
+ it('should emit LINE_EVENTS.ERROR when keepalive fails with a final error', /*#__PURE__*/(0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee24() {
954
+ return _regenerator.default.wrap(function _callee24$(_context24) {
955
+ while (1) switch (_context24.prev = _context24.next) {
956
+ case 0:
957
+ _context24.next = 2;
958
+ return beforeEachSetupForKeepalive();
959
+ case 2:
960
+ expect(reg.webWorker).toBeDefined();
961
+ lineEmitter.mockClear();
962
+ jest.spyOn(utils, 'handleRegistrationErrors').mockImplementationOnce( /*#__PURE__*/function () {
963
+ var _ref24 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee23(error, callback) {
964
+ var clientError;
965
+ return _regenerator.default.wrap(function _callee23$(_context23) {
966
+ while (1) switch (_context23.prev = _context23.next) {
967
+ case 0:
968
+ clientError = (0, _LineError.createLineError)('User is unauthorized due to an expired token. Sign out, then sign back in.', {}, _types3.ERROR_TYPE.TOKEN_ERROR, _types.RegistrationStatus.INACTIVE);
969
+ callback(clientError, true);
970
+ return _context23.abrupt("return", true);
971
+ case 3:
972
+ case "end":
973
+ return _context23.stop();
974
+ }
975
+ }, _callee23);
976
+ }));
977
+ return function (_x, _x2) {
978
+ return _ref24.apply(this, arguments);
979
+ };
980
+ }());
981
+ reg.webWorker.onmessage({
982
+ data: {
983
+ type: _types.WorkerMessageType.KEEPALIVE_FAILURE,
984
+ err: {
985
+ statusCode: 401,
986
+ message: 'Unauthorized'
987
+ },
988
+ keepAliveRetryCount: 1
989
+ }
990
+ });
991
+ _context24.next = 8;
992
+ return flushPromises();
993
+ case 8:
994
+ expect(lineEmitter).toHaveBeenNthCalledWith(1, _types4.LINE_EVENTS.ERROR, undefined, new Error('User is unauthorized due to an expired token. Sign out, then sign back in.'));
995
+ expect(reg.getStatus()).toBe(_types.RegistrationStatus.INACTIVE);
996
+ expect(reg.webWorker).toBeUndefined();
997
+ case 11:
998
+ case "end":
999
+ return _context24.stop();
1000
+ }
1001
+ }, _callee24);
1002
+ })));
954
1003
  });
955
1004
  });
956
1005
  //# sourceMappingURL=register.test.js.map