@@ -2,10 +2,12 @@ package provider
22
33import (
44 "context"
5+ "strconv"
56 "sync"
67 "testing"
78 "time"
89
10+ "github.com/smartcontractkit/freeport"
911 "github.com/stretchr/testify/assert"
1012 "github.com/stretchr/testify/require"
1113
@@ -33,7 +35,7 @@ func TestCTFAnvilChainProvider_Initialize(t *testing.T) {
3335 assert .Equal (t , selector , provider .ChainSelector ())
3436 assert .Equal (t , "Anvil EVM CTF Chain Provider" , provider .Name ())
3537
36- ctx , cancel := context .WithTimeout (context . Background (), 5 * time .Minute )
38+ ctx , cancel := context .WithTimeout (t . Context (), 5 * time .Minute )
3739 defer cancel ()
3840
3941 // Initialize the provider
@@ -281,7 +283,7 @@ func TestCTFAnvilChainProvider_InitializeErrors(t *testing.T) {
281283
282284 provider := NewCTFAnvilChainProvider (tt .selector , tt .config )
283285
284- ctx , cancel := context .WithTimeout (context . Background (), 30 * time .Second )
286+ ctx , cancel := context .WithTimeout (t . Context (), 30 * time .Second )
285287 defer cancel ()
286288
287289 _ , err := provider .Initialize (ctx )
@@ -311,7 +313,7 @@ func TestCTFAnvilChainProvider_SignerIntegration(t *testing.T) {
311313 selector := uint64 (13264668187771770619 ) // Chain ID 31337
312314 provider := NewCTFAnvilChainProvider (selector , config )
313315
314- ctx , cancel := context .WithTimeout (context . Background (), 5 * time .Minute )
316+ ctx , cancel := context .WithTimeout (t . Context (), 5 * time .Minute )
315317 defer cancel ()
316318
317319 blockchain , err := provider .Initialize (ctx )
@@ -350,7 +352,7 @@ func TestCTFAnvilChainProvider_SignerIntegration(t *testing.T) {
350352 selector := uint64 (13264668187771770619 ) // Chain ID 31337
351353 provider := NewCTFAnvilChainProvider (selector , config )
352354
353- ctx , cancel := context .WithTimeout (context . Background (), 5 * time .Minute )
355+ ctx , cancel := context .WithTimeout (t . Context (), 5 * time .Minute )
354356 defer cancel ()
355357
356358 blockchain , err := provider .Initialize (ctx )
@@ -388,7 +390,7 @@ func TestCTFAnvilChainProvider_SignerIntegration(t *testing.T) {
388390 selector := uint64 (13264668187771770619 ) // Chain ID 31337
389391 provider := NewCTFAnvilChainProvider (selector , config )
390392
391- ctx , cancel := context .WithTimeout (context . Background (), 5 * time .Minute )
393+ ctx , cancel := context .WithTimeout (t . Context (), 5 * time .Minute )
392394 defer cancel ()
393395
394396 blockchain , err := provider .Initialize (ctx )
@@ -427,7 +429,7 @@ func TestCTFAnvilChainProvider_SignerIntegration(t *testing.T) {
427429 selector := uint64 (13264668187771770619 ) // Chain ID 31337
428430 provider := NewCTFAnvilChainProvider (selector , config )
429431
430- ctx , cancel := context .WithTimeout (context . Background (), 5 * time .Minute )
432+ ctx , cancel := context .WithTimeout (t . Context (), 5 * time .Minute )
431433 defer cancel ()
432434
433435 blockchain , err := provider .Initialize (ctx )
@@ -462,7 +464,7 @@ func TestCTFAnvilChainProvider_SignerIntegration(t *testing.T) {
462464 selector := uint64 (13264668187771770619 ) // Chain ID 31337
463465 provider := NewCTFAnvilChainProvider (selector , config )
464466
465- ctx , cancel := context .WithTimeout (context . Background (), 5 * time .Minute )
467+ ctx , cancel := context .WithTimeout (t . Context (), 5 * time .Minute )
466468 defer cancel ()
467469
468470 blockchain , err := provider .Initialize (ctx )
@@ -473,3 +475,165 @@ func TestCTFAnvilChainProvider_SignerIntegration(t *testing.T) {
473475 assert .True (t , clientOptsCalled , "ClientOpts should have been called during initialization" )
474476 })
475477}
478+
479+ func TestCTFAnvilChainProvider_Cleanup (t * testing.T ) {
480+ t .Parallel ()
481+
482+ t .Run ("cleanup after initialization with T provided" , func (t * testing.T ) {
483+ t .Parallel ()
484+
485+ var once sync.Once
486+ config := CTFAnvilChainProviderConfig {
487+ Once : & once ,
488+ ConfirmFunctor : ConfirmFuncGeth (2 * time .Minute ),
489+ T : t ,
490+ }
491+
492+ selector := uint64 (13264668187771770619 ) // Chain ID 31337
493+ provider := NewCTFAnvilChainProvider (selector , config )
494+
495+ ctx , cancel := context .WithTimeout (t .Context (), 5 * time .Minute )
496+ defer cancel ()
497+
498+ blockchain , err := provider .Initialize (ctx )
499+ require .NoError (t , err )
500+ require .NotNil (t , blockchain )
501+
502+ assert .NotNil (t , provider .container , "Container reference should be stored after initialization" )
503+
504+ err = provider .Cleanup (ctx )
505+ require .NoError (t , err , "Cleanup should succeed" )
506+
507+ assert .Nil (t , provider .container , "Container reference should be cleared after cleanup" )
508+ })
509+
510+ t .Run ("cleanup after initialization with fixed port (T=nil)" , func (t * testing.T ) {
511+ t .Parallel ()
512+
513+ // Allocate a free port for this test
514+ port := freeport .GetOne (t )
515+ defer freeport .Return ([]int {port })
516+
517+ var once sync.Once
518+ config := CTFAnvilChainProviderConfig {
519+ Once : & once ,
520+ ConfirmFunctor : ConfirmFuncGeth (2 * time .Minute ),
521+ Port : strconv .Itoa (port ), // Use allocated port to avoid conflicts
522+ T : nil , // No T provided - simulates production usage
523+ }
524+
525+ selector := uint64 (13264668187771770619 ) // Chain ID 31337
526+ provider := NewCTFAnvilChainProvider (selector , config )
527+
528+ ctx , cancel := context .WithTimeout (t .Context (), 5 * time .Minute )
529+ defer cancel ()
530+
531+ blockchain , err := provider .Initialize (ctx )
532+ require .NoError (t , err )
533+ require .NotNil (t , blockchain )
534+
535+ assert .NotNil (t , provider .container , "Container reference should be stored after initialization" )
536+
537+ err = provider .Cleanup (ctx )
538+ require .NoError (t , err , "Cleanup should succeed even when T is nil" )
539+
540+ assert .Nil (t , provider .container , "Container reference should be cleared after cleanup" )
541+ })
542+
543+ t .Run ("cleanup before initialization" , func (t * testing.T ) {
544+ t .Parallel ()
545+
546+ var once sync.Once
547+ config := CTFAnvilChainProviderConfig {
548+ Once : & once ,
549+ ConfirmFunctor : ConfirmFuncGeth (2 * time .Minute ),
550+ T : t ,
551+ }
552+
553+ selector := uint64 (13264668187771770619 ) // Chain ID 31337
554+ provider := NewCTFAnvilChainProvider (selector , config )
555+
556+ ctx , cancel := context .WithTimeout (t .Context (), 30 * time .Second )
557+ defer cancel ()
558+
559+ // Test cleanup before initialization - should be a no-op
560+ err := provider .Cleanup (ctx )
561+ require .NoError (t , err , "Cleanup should succeed even when no container exists" )
562+
563+ // Verify container is still nil
564+ assert .Nil (t , provider .container , "Container reference should remain nil" )
565+ })
566+
567+ t .Run ("multiple cleanup calls" , func (t * testing.T ) {
568+ t .Parallel ()
569+
570+ var once sync.Once
571+ config := CTFAnvilChainProviderConfig {
572+ Once : & once ,
573+ ConfirmFunctor : ConfirmFuncGeth (2 * time .Minute ),
574+ T : t ,
575+ }
576+
577+ selector := uint64 (13264668187771770619 ) // Chain ID 31337
578+ provider := NewCTFAnvilChainProvider (selector , config )
579+
580+ ctx , cancel := context .WithTimeout (t .Context (), 5 * time .Minute )
581+ defer cancel ()
582+
583+ blockchain , err := provider .Initialize (ctx )
584+ require .NoError (t , err )
585+ require .NotNil (t , blockchain )
586+
587+ // First cleanup
588+ err = provider .Cleanup (ctx )
589+ require .NoError (t , err , "First cleanup should succeed" )
590+ assert .Nil (t , provider .container , "Container reference should be cleared after first cleanup" )
591+
592+ // Second cleanup - should be a no-op
593+ err = provider .Cleanup (ctx )
594+ require .NoError (t , err , "Second cleanup should succeed (no-op)" )
595+ assert .Nil (t , provider .container , "Container reference should remain nil after second cleanup" )
596+
597+ // Third cleanup - should still be a no-op
598+ err = provider .Cleanup (ctx )
599+ require .NoError (t , err , "Third cleanup should succeed (no-op)" )
600+ assert .Nil (t , provider .container , "Container reference should remain nil after third cleanup" )
601+ })
602+
603+ t .Run ("cleanup with cancelled context" , func (t * testing.T ) {
604+ t .Parallel ()
605+
606+ var once sync.Once
607+ config := CTFAnvilChainProviderConfig {
608+ Once : & once ,
609+ ConfirmFunctor : ConfirmFuncGeth (2 * time .Minute ),
610+ T : t ,
611+ }
612+
613+ selector := uint64 (13264668187771770619 ) // Chain ID 31337
614+ provider := NewCTFAnvilChainProvider (selector , config )
615+
616+ ctx , cancel := context .WithTimeout (t .Context (), 5 * time .Minute )
617+ defer cancel ()
618+
619+ blockchain , err := provider .Initialize (ctx )
620+ require .NoError (t , err )
621+ require .NotNil (t , blockchain )
622+
623+ cancelledCtx , cancelFunc := context .WithCancel (t .Context ())
624+ cancelFunc () // Cancel immediately
625+
626+ // Test cleanup with cancelled context - should return an error
627+ err = provider .Cleanup (cancelledCtx )
628+ require .Error (t , err , "Cleanup should fail with cancelled context" )
629+ assert .Contains (t , err .Error (), "failed to terminate Anvil container" , "Error should mention container termination failure" )
630+
631+ // Container reference should still exist since cleanup failed
632+ assert .NotNil (t , provider .container , "Container reference should remain when cleanup fails" )
633+
634+ // Cleanup with proper context should still work
635+ err = provider .Cleanup (ctx )
636+ require .NoError (t , err , "Cleanup with valid context should succeed after previous failure" )
637+ assert .Nil (t , provider .container , "Container reference should be cleared after successful cleanup" )
638+ })
639+ }
0 commit comments