@@ -17,7 +17,6 @@ import (
1717 "github.com/stretchr/testify/require"
1818 "github.com/urfave/cli"
1919
20- commonkeystore "github.com/smartcontractkit/chainlink-common/keystore"
2120 commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config"
2221 "github.com/smartcontractkit/chainlink-common/pkg/sqlutil"
2322 pgcommon "github.com/smartcontractkit/chainlink-common/pkg/sqlutil/pg"
@@ -509,64 +508,34 @@ func TestShell_RemoveBlocks(t *testing.T) {
509508func TestShell_BeforeNode (t * testing.T ) {
510509 testutils .SkipShortDB (t )
511510
512- // Use heavyweight.FullTestDBV2 (real isolated per-test Postgres DB,
513- // dropped on t.Cleanup) because both subtests must share a persisted
514- // encrypted key ring:
515- //
516- // 1. keystore.Unlock on an *empty* keystore silently creates a fresh
517- // key ring encrypted with whatever password you pass — so any
518- // password "works" against an empty DB, including the wrong one.
519- // The incorrect_password subtest can only fail meaningfully if
520- // there is an existing ring to fail decryption against.
521- //
522- // 2. txdb isolation can't be used here: chainlink-common's
523- // pg.NewConnection deliberately passes uuid.New().String() as the
524- // DSN to the txdb driver on every call (see
525- // chainlink-common/pkg/sqlutil/pg/pg.go:69 — "Each ORM should be
526- // encapsulated in its own transaction"). That means the seed
527- // connection and BeforeNode's LockedDB land on different keys in
528- // the txdb driver's DSN-keyed conns map and get independent
529- // transactions, so the seed would be invisible to BeforeNode.
530- // This convention is also why Erik's PR #21504, which tried to
531- // force txdb via a newAppWithOpts override, couldn't make the
532- // incorrect_password case work.
533- //
534- // A real per-test physical DB gives us the cross-connection visibility
535- // the test needs, with its own cleanup and without polluting the
536- // shared chainlink_test DB used by every other test.
537- cfg , sqlxDB := heavyweight .FullTestDBV2 (t , func (c * chainlink.Config , s * chainlink.Secrets ) {
538- s .Password .Keystore = models .NewSecret ("dummy-to-pass-validation" )
539- c .EVM [0 ].Nodes [0 ].Name = ptr ("fake" )
540- c .EVM [0 ].Nodes [0 ].HTTPURL = commonconfig .MustParseURL ("http://fake.com" )
541- c .EVM [0 ].Nodes [0 ].WSURL = commonconfig .MustParseURL ("WSS://fake.com/ws" )
542- c .Insecure .OCRDevelopmentMode = nil
543- })
544-
545- // Seed one CSA key encrypted with the correct password so the
546- // incorrect_password subtest has something to fail decryption against.
547- correctPwd , err := utils .PasswordFromFile ("../internal/fixtures/correct_password.txt" )
548- require .NoError (t , err )
549- ctx := testutils .Context (t )
550- seedDS := sqlutil .WrapDataSource (sqlxDB , logger .TestLogger (t ),
551- sqlutil .TimeoutHook (cfg .Database ().DefaultQueryTimeout ),
552- sqlutil .MonitorHook (cfg .Database ().LogSQL ))
553- seedKS := keystore .New (seedDS , commonkeystore .FastScryptParams , logger .TestLogger (t ).Infof )
554- require .NoError (t , seedKS .Unlock (ctx , correctPwd ))
555- _ , err = seedKS .CSA ().Create (ctx )
556- require .NoError (t , err )
557-
511+ // Uses txdb via configtest.NewGeneralConfig (the codebase default) so
512+ // each subtest runs in its own rolled-back transaction. We deliberately
513+ // do NOT test the "wrong password against an existing key ring" case
514+ // here — that is a keystore invariant, already covered by
515+ // TestMasterKeystore_Unlock_Save/won't_load_a_saved_keyRing_if_the_password_is_incorrect
516+ // in core/services/keystore/master_test.go, which owns that layer.
517+ // Testing it at the CLI level would require cross-connection visibility
518+ // that txdb doesn't provide in this codebase (pg.NewConnection generates
519+ // a fresh UUID DSN per call — see chainlink-common/pkg/sqlutil/pg/pg.go:69).
558520 tests := []struct {
559521 name string
560522 pwdfile string
561523 wantUnlocked bool
562524 }{
563525 {"correct password" , "../internal/fixtures/correct_password.txt" , true },
564- {"incorrect password" , "../internal/fixtures/incorrect_password.txt" , false },
565526 {"wrong file" , "doesntexist.txt" , false },
566527 }
567528
568529 for _ , test := range tests {
569530 t .Run (test .name , func (t * testing.T ) {
531+ cfg := configtest .NewGeneralConfig (t , func (c * chainlink.Config , s * chainlink.Secrets ) {
532+ s .Password .Keystore = models .NewSecret ("dummy-to-pass-validation" )
533+ c .EVM [0 ].Nodes [0 ].Name = ptr ("fake" )
534+ c .EVM [0 ].Nodes [0 ].HTTPURL = commonconfig .MustParseURL ("http://fake.com" )
535+ c .EVM [0 ].Nodes [0 ].WSURL = commonconfig .MustParseURL ("WSS://fake.com/ws" )
536+ c .Insecure .OCRDevelopmentMode = nil
537+ })
538+
570539 shell := cmd.Shell {
571540 Config : cfg ,
572541 KeyStoreAuthenticator : cmd.TerminalKeyStoreAuthenticator {
@@ -611,112 +580,75 @@ func TestShell_BeforeNode(t *testing.T) {
611580func TestShell_RunNode_WithBeforeNode (t * testing.T ) {
612581 testutils .SkipShortDB (t )
613582
614- // See TestShell_BeforeNode for the full rationale (TL;DR: txdb can't
615- // be used to seed shared state because pg.NewConnection generates a
616- // fresh UUID DSN per call, isolating every pool into its own
617- // transaction — so we need a real per-test physical DB instead) .
618- cfg , sqlxDB := heavyweight . FullTestDBV2 (t , func (c * chainlink.Config , s * chainlink.Secrets ) {
583+ // Uses txdb via configtest.NewGeneralConfig. We only exercise the
584+ // happy path here — the wrong-password case is covered at the correct
585+ // layer by TestMasterKeystore_Unlock_Save in core/services/keystore
586+ // and does not need to be reasserted through the CLI .
587+ cfg := configtest . NewGeneralConfig (t , func (c * chainlink.Config , s * chainlink.Secrets ) {
619588 s .Password .Keystore = models .NewSecret ("dummy-to-pass-validation" )
620589 c .EVM [0 ].Nodes [0 ].Name = ptr ("fake" )
621590 c .EVM [0 ].Nodes [0 ].HTTPURL = commonconfig .MustParseURL ("http://fake.com" )
622591 c .EVM [0 ].Nodes [0 ].WSURL = commonconfig .MustParseURL ("WSS://fake.com/ws" )
623592 c .Insecure .OCRDevelopmentMode = nil
624593 })
625594
626- // Seed one CSA key encrypted with the correct password so the
627- // incorrect_password subtest has something to fail decryption against.
628- correctPwd , err := utils .PasswordFromFile ("../internal/fixtures/correct_password.txt" )
629- require .NoError (t , err )
630- seedCtx := testutils .Context (t )
631- seedDS := sqlutil .WrapDataSource (sqlxDB , logger .TestLogger (t ),
632- sqlutil .TimeoutHook (cfg .Database ().DefaultQueryTimeout ),
633- sqlutil .MonitorHook (cfg .Database ().LogSQL ))
634- seedKS := keystore .New (seedDS , commonkeystore .FastScryptParams , logger .TestLogger (t ).Infof )
635- require .NoError (t , seedKS .Unlock (seedCtx , correctPwd ))
636- _ , err = seedKS .CSA ().Create (seedCtx )
637- require .NoError (t , err )
638-
639- tests := []struct {
640- name string
641- pwdfile string
642- expectStart bool
643- }{
644- {"correct password" , "../internal/fixtures/correct_password.txt" , true },
645- {"incorrect password" , "../internal/fixtures/incorrect_password.txt" , false },
646- }
595+ db := pgtest .NewSqlxDB (t )
596+ keyStore := cltest .NewKeyStore (t , db )
597+ authProviderORM := localauth .NewORM (db , time .Minute , logger .TestLogger (t ), audit .NoopLogger )
647598
648- for _ , test := range tests {
649- t .Run (test .name , func (t * testing.T ) {
650- // Use the shared sqlxDB for the mock application's keystore and
651- // auth provider so they see the seeded key ring and any state
652- // written by BeforeNode.
653- db := sqlxDB
654- keyStore := cltest .NewKeyStore (t , db )
655- authProviderORM := localauth .NewORM (db , time .Minute , logger .TestLogger (t ), audit .NoopLogger )
599+ testRelayers := genTestEVMRelayers (t , cfg , db , keyStore .Eth (), & keystore.CSASigner {CSA : keyStore .CSA ()})
656600
657- testRelayers := genTestEVMRelayers (t , cfg , db , keyStore .Eth (), & keystore.CSASigner {CSA : keyStore .CSA ()})
601+ // Purge fixture users to test assumption of single admin
602+ pgtest .MustExec (t , db , "DELETE FROM users;" )
658603
659- // Purge fixture users to test assumption of single admin
660- pgtest .MustExec (t , db , "DELETE FROM users;" )
604+ app := mocks .NewApplication (t )
605+ app .On ("AuthenticationProvider" ).Return (authProviderORM ).Maybe ()
606+ app .On ("BasicAdminUsersORM" ).Return (authProviderORM ).Maybe ()
607+ app .On ("GetKeyStore" ).Return (keyStore ).Maybe ()
608+ app .On ("GetRelayers" ).Return (testRelayers ).Maybe ()
609+ app .On ("Start" , mock .Anything ).Maybe ().Return (nil )
610+ app .On ("Stop" ).Maybe ().Return (nil )
611+ app .On ("ID" ).Maybe ().Return (uuid .New ())
661612
662- app := mocks .NewApplication (t )
663- app .On ("AuthenticationProvider" ).Return (authProviderORM ).Maybe ()
664- app .On ("BasicAdminUsersORM" ).Return (authProviderORM ).Maybe ()
665- app .On ("GetKeyStore" ).Return (keyStore ).Maybe ()
666- app .On ("GetRelayers" ).Return (testRelayers ).Maybe ()
667- app .On ("Start" , mock .Anything ).Maybe ().Return (nil )
668- app .On ("Stop" ).Maybe ().Return (nil )
669- app .On ("ID" ).Maybe ().Return (uuid .New ())
613+ ethClient := clienttest .NewClient (t )
614+ ethClient .On ("Dial" , mock .Anything ).Return (nil ).Maybe ()
615+ ethClient .On ("BalanceAt" , mock .Anything , mock .Anything , mock .Anything ).Return (big .NewInt (10 ), nil ).Maybe ()
670616
671- ethClient := clienttest .NewClient (t )
672- ethClient .On ("Dial" , mock .Anything ).Return (nil ).Maybe ()
673- ethClient .On ("BalanceAt" , mock .Anything , mock .Anything , mock .Anything ).Return (big .NewInt (10 ), nil ).Maybe ()
617+ cltest .MustInsertRandomKey (t , keyStore .Eth ())
618+ apiPrompt := cltest .NewMockAPIInitializer (t )
674619
675- cltest .MustInsertRandomKey (t , keyStore .Eth ())
676- apiPrompt := cltest .NewMockAPIInitializer (t )
677-
678- shell := cmd.Shell {
679- Config : cfg ,
680- FallbackAPIInitializer : apiPrompt ,
681- Runner : cltest.EmptyRunner {},
682- AppFactory : cltest.InstanceAppFactory {App : app },
683- KeyStoreAuthenticator : cmd.TerminalKeyStoreAuthenticator {
684- Prompter : & cltest.MockCountingPrompter {T : t , NotTerminal : true },
685- },
686- Logger : logger .TestLogger (t ),
687- }
688- // Reset for test isolation
689- defer resetShellForTest (& shell )
620+ shell := cmd.Shell {
621+ Config : cfg ,
622+ FallbackAPIInitializer : apiPrompt ,
623+ Runner : cltest.EmptyRunner {},
624+ AppFactory : cltest.InstanceAppFactory {App : app },
625+ KeyStoreAuthenticator : cmd.TerminalKeyStoreAuthenticator {
626+ Prompter : & cltest.MockCountingPrompter {T : t , NotTerminal : true },
627+ },
628+ Logger : logger .TestLogger (t ),
629+ }
630+ // Reset for test isolation
631+ defer resetShellForTest (& shell )
690632
691- set := flag .NewFlagSet ("test" , 0 )
692- flagSetApplyFromAction (shell .RunNode , set , "" )
693- require .NoError (t , set .Set ("password" , test . pwdfile ))
633+ set := flag .NewFlagSet ("test" , 0 )
634+ flagSetApplyFromAction (shell .RunNode , set , "" )
635+ require .NoError (t , set .Set ("password" , "../internal/fixtures/correct_password.txt" ))
694636
695- c := cli .NewContext (nil , set , nil )
637+ c := cli .NewContext (nil , set , nil )
696638
697- err := shell .BeforeNode (c )
639+ err := shell .BeforeNode (c )
640+ require .NoError (t , err , "BeforeNode should succeed" )
641+ assert .NotNil (t , shell .KeyStore )
642+ assert .NotNil (t , shell .DS )
643+ assert .NotNil (t , shell .LDB )
698644
699- if test .expectStart {
700- require .NoError (t , err , "BeforeNode should succeed" )
701- // Verify components are initialized
702- assert .NotNil (t , shell .KeyStore )
703- assert .NotNil (t , shell .DS )
704- assert .NotNil (t , shell .LDB )
645+ // Now test RunNode with pre-authenticated keystore.
646+ err = shell .RunNode (c )
647+ require .NoError (t , err , "RunNode should succeed with authenticated keystore" )
648+ assert .Equal (t , 1 , apiPrompt .Count , "API should be initialized" )
705649
706- // Now test RunNode with pre-authenticated keystore
707- // Note: RunNode will start the app but we expect it to work since keystore is authenticated
708- err = shell .RunNode (c )
709- require .NoError (t , err , "RunNode should succeed with authenticated keystore" )
710- assert .Equal (t , 1 , apiPrompt .Count , "API should be initialized" )
711- } else {
712- require .Error (t , err , "BeforeNode should fail with incorrect password" )
713- // Don't test RunNode if BeforeNode failed
714- }
715- // Clean up database if it was opened
716- if shell .LDB != nil {
717- cleanupErr := shell .AfterNode (c )
718- require .NoError (t , cleanupErr )
719- }
720- })
650+ // Clean up database if it was opened
651+ if shell .LDB != nil {
652+ require .NoError (t , shell .AfterNode (c ))
721653 }
722654}
0 commit comments