@@ -28,11 +28,15 @@ import {
28
28
DONE as DISCOVERY_DONE ,
29
29
updateDiscoveryConnection
30
30
} from 'shared/modules/discovery/discoveryDuck'
31
+ import forceResetPasswordQueryHelper , {
32
+ MultiDatabaseNotSupportedError
33
+ } from './forceResetPasswordQueryHelper'
31
34
32
35
jest . mock ( 'services/bolt/bolt' , ( ) => {
33
36
return {
34
37
closeConnection : jest . fn ( ) ,
35
- openConnection : jest . fn ( )
38
+ openConnection : jest . fn ( ) ,
39
+ directConnect : jest . fn ( )
36
40
}
37
41
} )
38
42
@@ -457,3 +461,310 @@ describe('switchConnectionEpic', () => {
457
461
return p
458
462
} )
459
463
} )
464
+
465
+ describe ( 'handleForcePasswordChangeEpic' , ( ) => {
466
+ const bus = createBus ( )
467
+ const epicMiddleware = createEpicMiddleware (
468
+ connections . handleForcePasswordChangeEpic
469
+ )
470
+ const mockStore = configureMockStore ( [
471
+ epicMiddleware ,
472
+ createReduxMiddleware ( bus )
473
+ ] )
474
+
475
+ let store : any
476
+
477
+ const $$responseChannel = 'test-channel'
478
+ const action = {
479
+ host : 'bolt://localhost:7687' ,
480
+ type : connections . FORCE_CHANGE_PASSWORD ,
481
+ password : 'changeme' ,
482
+ newPassword : 'password1' ,
483
+ $$responseChannel
484
+ }
485
+
486
+ const executePasswordResetQuerySpy = jest . spyOn (
487
+ forceResetPasswordQueryHelper ,
488
+ 'executePasswordResetQuery'
489
+ )
490
+
491
+ const executeAlterCurrentUserQuerySpy = jest . spyOn (
492
+ forceResetPasswordQueryHelper ,
493
+ 'executeAlterCurrentUserQuery'
494
+ )
495
+
496
+ const executeCallChangePasswordQuerySpy = jest . spyOn (
497
+ forceResetPasswordQueryHelper ,
498
+ 'executeCallChangePasswordQuery'
499
+ )
500
+
501
+ const mockSessionClose = jest . fn ( )
502
+ const mockSessionExecuteWrite = jest . fn ( )
503
+
504
+ const mockDriver = {
505
+ session : jest . fn ( ) . mockReturnValue ( {
506
+ close : mockSessionClose ,
507
+ executeWrite : mockSessionExecuteWrite
508
+ } ) ,
509
+ close : jest . fn ( ) . mockReturnValue ( true )
510
+ }
511
+
512
+ beforeAll ( ( ) => {
513
+ store = mockStore ( { } )
514
+ } )
515
+
516
+ beforeEach ( ( ) => {
517
+ ; ( bolt . directConnect as jest . Mock ) . mockResolvedValue ( mockDriver )
518
+ } )
519
+
520
+ afterEach ( ( ) => {
521
+ store . clearActions ( )
522
+ bus . reset ( )
523
+ jest . clearAllMocks ( )
524
+ } )
525
+
526
+ test ( 'handleForcePasswordChangeEpic resolves with an error if directConnect fails' , ( ) => {
527
+ // Given
528
+ const message = 'An error occurred.'
529
+ ; ( bolt . directConnect as jest . Mock ) . mockRejectedValue ( new Error ( message ) )
530
+
531
+ const p = new Promise < void > ( ( resolve , reject ) => {
532
+ bus . take ( $$responseChannel , currentAction => {
533
+ // Then
534
+ const actions = store . getActions ( )
535
+ try {
536
+ expect ( actions ) . toEqual ( [ action , currentAction ] )
537
+
538
+ expect ( executeAlterCurrentUserQuerySpy ) . not . toHaveBeenCalled ( )
539
+
540
+ expect ( executeCallChangePasswordQuerySpy ) . not . toHaveBeenCalled ( )
541
+
542
+ expect ( executePasswordResetQuerySpy ) . not . toHaveBeenCalled ( )
543
+
544
+ expect ( currentAction ) . toEqual ( {
545
+ error : expect . objectContaining ( {
546
+ message
547
+ } ) ,
548
+ success : false ,
549
+ type : $$responseChannel
550
+ } )
551
+
552
+ resolve ( )
553
+
554
+ expect ( mockDriver . close ) . not . toHaveBeenCalled ( )
555
+ expect ( mockSessionClose ) . not . toHaveBeenCalled ( )
556
+ } catch ( e ) {
557
+ reject ( e )
558
+ }
559
+ } )
560
+ } )
561
+
562
+ // When
563
+ epicMiddleware . replaceEpic ( connections . handleForcePasswordChangeEpic )
564
+ store . clearActions ( )
565
+ store . dispatch ( action )
566
+
567
+ // Return
568
+ return p
569
+ } )
570
+
571
+ test ( 'handleForcePasswordChangeEpic resolves when successfully executing cypher query' , ( ) => {
572
+ // Given
573
+ mockSessionExecuteWrite . mockResolvedValue ( true )
574
+
575
+ const p = new Promise < void > ( ( resolve , reject ) => {
576
+ bus . take ( $$responseChannel , currentAction => {
577
+ // Then
578
+ const actions = store . getActions ( )
579
+ try {
580
+ expect ( actions ) . toEqual ( [ action , currentAction ] )
581
+
582
+ expect ( executeAlterCurrentUserQuerySpy ) . toHaveBeenCalledTimes ( 1 )
583
+
584
+ expect ( executeCallChangePasswordQuerySpy ) . not . toHaveBeenCalled ( )
585
+
586
+ expect ( executePasswordResetQuerySpy ) . toHaveBeenCalledTimes ( 1 )
587
+
588
+ expect ( executePasswordResetQuerySpy ) . toHaveBeenCalledWith (
589
+ expect . anything ( ) ,
590
+ expect . objectContaining ( {
591
+ parameters : { newPw : 'password1' , oldPw : 'changeme' } ,
592
+ query : 'ALTER CURRENT USER SET PASSWORD FROM $oldPw TO $newPw'
593
+ } ) ,
594
+ expect . anything ( ) ,
595
+ { database : 'system' }
596
+ )
597
+
598
+ expect ( currentAction ) . toEqual ( {
599
+ result : { meta : 'bolt://localhost:7687' } ,
600
+ success : true ,
601
+ type : $$responseChannel
602
+ } )
603
+
604
+ resolve ( )
605
+
606
+ expect ( mockDriver . close ) . toHaveBeenCalledTimes ( 1 )
607
+ expect ( mockSessionClose ) . toHaveBeenCalledTimes ( 1 )
608
+ } catch ( e ) {
609
+ reject ( e )
610
+ }
611
+ } )
612
+ } )
613
+
614
+ // When
615
+ epicMiddleware . replaceEpic ( connections . handleForcePasswordChangeEpic )
616
+ store . clearActions ( )
617
+ store . dispatch ( action )
618
+
619
+ // Return
620
+ return p
621
+ } )
622
+
623
+ test ( 'handleForcePasswordChangeEpic resolves with an error if cypher query fails' , ( ) => {
624
+ // Given
625
+ const message = 'A password must be at least 8 characters.'
626
+ mockSessionExecuteWrite
627
+ . mockRejectedValueOnce ( new Error ( message ) )
628
+ . mockResolvedValue ( true )
629
+
630
+ const p = new Promise < void > ( ( resolve , reject ) => {
631
+ bus . take ( $$responseChannel , currentAction => {
632
+ // Then
633
+ const actions = store . getActions ( )
634
+ try {
635
+ expect ( actions ) . toEqual ( [ action , currentAction ] )
636
+
637
+ expect ( executeAlterCurrentUserQuerySpy ) . toHaveBeenCalledTimes ( 1 )
638
+
639
+ expect ( executeCallChangePasswordQuerySpy ) . not . toHaveBeenCalled ( )
640
+
641
+ expect ( executePasswordResetQuerySpy ) . toHaveBeenCalledTimes ( 1 )
642
+
643
+ expect ( currentAction ) . toEqual ( {
644
+ error : expect . objectContaining ( {
645
+ message
646
+ } ) ,
647
+ success : false ,
648
+ type : $$responseChannel
649
+ } )
650
+
651
+ resolve ( )
652
+
653
+ expect ( mockDriver . close ) . toHaveBeenCalledTimes ( 1 )
654
+ expect ( mockSessionClose ) . toHaveBeenCalledTimes ( 1 )
655
+ } catch ( e ) {
656
+ reject ( e )
657
+ }
658
+ } )
659
+ } )
660
+
661
+ // When
662
+ epicMiddleware . replaceEpic ( connections . handleForcePasswordChangeEpic )
663
+ store . clearActions ( )
664
+ store . dispatch ( action )
665
+
666
+ // Return
667
+ return p
668
+ } )
669
+
670
+ test ( 'handleForcePasswordChangeEpic resolves when successfully falling back to dbms function call' , ( ) => {
671
+ // Given
672
+ mockSessionExecuteWrite
673
+ . mockRejectedValueOnce ( new MultiDatabaseNotSupportedError ( ) )
674
+ . mockResolvedValue ( true )
675
+
676
+ const p = new Promise < void > ( ( resolve , reject ) => {
677
+ bus . take ( $$responseChannel , currentAction => {
678
+ // Then
679
+ const actions = store . getActions ( )
680
+ try {
681
+ expect ( actions ) . toEqual ( [ action , currentAction ] )
682
+
683
+ expect ( executeAlterCurrentUserQuerySpy ) . toHaveBeenCalledTimes ( 1 )
684
+
685
+ expect ( executeCallChangePasswordQuerySpy ) . toHaveBeenCalledTimes ( 1 )
686
+
687
+ expect ( executePasswordResetQuerySpy ) . toHaveBeenCalledTimes ( 2 )
688
+
689
+ expect ( executePasswordResetQuerySpy ) . toHaveBeenLastCalledWith (
690
+ expect . anything ( ) ,
691
+ expect . objectContaining ( {
692
+ parameters : { password : 'password1' } ,
693
+ query : 'CALL dbms.security.changePassword($password)'
694
+ } ) ,
695
+ expect . anything ( ) ,
696
+ undefined
697
+ )
698
+
699
+ expect ( currentAction ) . toEqual ( {
700
+ result : { meta : 'bolt://localhost:7687' } ,
701
+ success : true ,
702
+ type : $$responseChannel
703
+ } )
704
+
705
+ resolve ( )
706
+
707
+ expect ( mockDriver . close ) . toHaveBeenCalledTimes ( 1 )
708
+ expect ( mockSessionClose ) . toHaveBeenCalledTimes ( 2 )
709
+ } catch ( e ) {
710
+ reject ( e )
711
+ }
712
+ } )
713
+ } )
714
+
715
+ // When
716
+ epicMiddleware . replaceEpic ( connections . handleForcePasswordChangeEpic )
717
+ store . clearActions ( )
718
+ store . dispatch ( action )
719
+
720
+ // Return
721
+ return p
722
+ } )
723
+
724
+ test ( 'handleForcePasswordChangeEpic resolves with an error if dbms function call fails' , ( ) => {
725
+ // Given
726
+ const message = 'A password must be at least 8 characters.'
727
+ mockSessionExecuteWrite
728
+ . mockRejectedValueOnce ( new MultiDatabaseNotSupportedError ( ) )
729
+ . mockRejectedValue ( new Error ( message ) )
730
+
731
+ const p = new Promise < void > ( ( resolve , reject ) => {
732
+ bus . take ( $$responseChannel , currentAction => {
733
+ // Then
734
+ const actions = store . getActions ( )
735
+ try {
736
+ expect ( actions ) . toEqual ( [ action , currentAction ] )
737
+
738
+ expect ( executeAlterCurrentUserQuerySpy ) . toHaveBeenCalledTimes ( 1 )
739
+
740
+ expect ( executeCallChangePasswordQuerySpy ) . toHaveBeenCalledTimes ( 1 )
741
+
742
+ expect ( executePasswordResetQuerySpy ) . toHaveBeenCalledTimes ( 2 )
743
+
744
+ expect ( currentAction ) . toEqual ( {
745
+ error : expect . objectContaining ( {
746
+ message
747
+ } ) ,
748
+ success : false ,
749
+ type : $$responseChannel
750
+ } )
751
+
752
+ resolve ( )
753
+
754
+ expect ( mockDriver . close ) . toHaveBeenCalledTimes ( 1 )
755
+ expect ( mockSessionClose ) . toHaveBeenCalledTimes ( 2 )
756
+ } catch ( e ) {
757
+ reject ( e )
758
+ }
759
+ } )
760
+ } )
761
+
762
+ // When
763
+ epicMiddleware . replaceEpic ( connections . handleForcePasswordChangeEpic )
764
+ store . clearActions ( )
765
+ store . dispatch ( action )
766
+
767
+ // Return
768
+ return p
769
+ } )
770
+ } )
0 commit comments