From 99f37ed1bc7f5d03bd2ef1b56bc3228559adcb6e Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 2 Apr 2026 12:20:58 +0100 Subject: [PATCH] ax(mining): rename circuit_breaker_test.go to TestFilename_Function_{Good,Bad,Ugly} convention All test functions in circuit_breaker_test.go now follow the AX-required naming pattern. Added missing _Bad and _Ugly variants and usage-example comments on each test function. Co-Authored-By: Charon --- pkg/mining/circuit_breaker_test.go | 113 ++++++++++++++++++----------- 1 file changed, 70 insertions(+), 43 deletions(-) diff --git a/pkg/mining/circuit_breaker_test.go b/pkg/mining/circuit_breaker_test.go index b0e5d4a..637a1fe 100644 --- a/pkg/mining/circuit_breaker_test.go +++ b/pkg/mining/circuit_breaker_test.go @@ -7,7 +7,10 @@ import ( "time" ) -func TestCircuitBreakerDefaultConfig(t *testing.T) { +// TestCircuitBreaker_DefaultConfig_Good verifies that DefaultCircuitBreakerConfig() returns sane defaults. +// configuration := DefaultCircuitBreakerConfig() +// configuration.FailureThreshold == 3 +func TestCircuitBreaker_DefaultConfig_Good(t *testing.T) { configuration := DefaultCircuitBreakerConfig() if configuration.FailureThreshold != 3 { @@ -21,7 +24,9 @@ func TestCircuitBreakerDefaultConfig(t *testing.T) { } } -func TestCircuitBreakerStateString(t *testing.T) { +// TestCircuitBreaker_StateString_Good verifies all known CircuitState values stringify correctly. +// CircuitClosed.String() == "closed" +func TestCircuitBreaker_StateString_Good(t *testing.T) { tests := []struct { state CircuitState expected string @@ -29,7 +34,6 @@ func TestCircuitBreakerStateString(t *testing.T) { {CircuitClosed, "closed"}, {CircuitOpen, "open"}, {CircuitHalfOpen, "half-open"}, - {CircuitState(99), "unknown"}, } for _, tt := range tests { @@ -39,14 +43,24 @@ func TestCircuitBreakerStateString(t *testing.T) { } } -func TestCircuitBreakerClosed(t *testing.T) { +// TestCircuitBreaker_StateString_Ugly verifies unknown CircuitState values stringify to "unknown". +// CircuitState(99).String() == "unknown" +func TestCircuitBreaker_StateString_Ugly(t *testing.T) { + if got := CircuitState(99).String(); got != "unknown" { + t.Errorf("expected 'unknown' for unknown state, got %s", got) + } +} + +// TestCircuitBreaker_Execute_Good verifies a closed circuit allows execution and returns results. +// cb := NewCircuitBreaker("test", DefaultCircuitBreakerConfig()) +// result, err := cb.Execute(func() (interface{}, error) { return "success", nil }) +func TestCircuitBreaker_Execute_Good(t *testing.T) { cb := NewCircuitBreaker("test", DefaultCircuitBreakerConfig()) if cb.State() != CircuitClosed { t.Error("expected initial state to be closed") } - // Successful execution result, err := cb.Execute(func() (interface{}, error) { return "success", nil }) @@ -62,7 +76,9 @@ func TestCircuitBreakerClosed(t *testing.T) { } } -func TestCircuitBreakerOpensAfterFailures(t *testing.T) { +// TestCircuitBreaker_Execute_Bad verifies that exceeding FailureThreshold opens the circuit. +// cb.Execute(failingFn) × FailureThreshold → cb.State() == CircuitOpen +func TestCircuitBreaker_Execute_Bad(t *testing.T) { configuration := CircuitBreakerConfig{ FailureThreshold: 2, ResetTimeout: time.Minute, @@ -72,7 +88,6 @@ func TestCircuitBreakerOpensAfterFailures(t *testing.T) { testErr := errors.New("test error") - // First failure _, err := cb.Execute(func() (interface{}, error) { return nil, testErr }) @@ -83,7 +98,6 @@ func TestCircuitBreakerOpensAfterFailures(t *testing.T) { t.Error("should still be closed after 1 failure") } - // Second failure - should open circuit _, err = cb.Execute(func() (interface{}, error) { return nil, testErr }) @@ -95,16 +109,17 @@ func TestCircuitBreakerOpensAfterFailures(t *testing.T) { } } -func TestCircuitBreakerRejectsWhenOpen(t *testing.T) { +// TestCircuitBreaker_Execute_Ugly verifies that an open circuit rejects calls with ErrCircuitOpen. +// cb (open) → cb.Execute(fn) returns ErrCircuitOpen without calling fn +func TestCircuitBreaker_Execute_Ugly(t *testing.T) { configuration := CircuitBreakerConfig{ FailureThreshold: 1, - ResetTimeout: time.Hour, // Long timeout to keep circuit open + ResetTimeout: time.Hour, SuccessThreshold: 1, } cb := NewCircuitBreaker("test", configuration) - // Open the circuit - cb.Execute(func() (interface{}, error) { + cb.Execute(func() (interface{}, error) { //nolint:errcheck return nil, errors.New("fail") }) @@ -112,7 +127,6 @@ func TestCircuitBreakerRejectsWhenOpen(t *testing.T) { t.Fatal("circuit should be open") } - // Next request should be rejected called := false _, err := cb.Execute(func() (interface{}, error) { called = true @@ -127,7 +141,10 @@ func TestCircuitBreakerRejectsWhenOpen(t *testing.T) { } } -func TestCircuitBreakerTransitionsToHalfOpen(t *testing.T) { +// TestCircuitBreaker_HalfOpen_Good verifies that the circuit transitions from open to half-open after ResetTimeout, +// and closes again on a successful probe. +// cb (open) → sleep(ResetTimeout) → cb.Execute(successFn) → cb.State() == CircuitClosed +func TestCircuitBreaker_HalfOpen_Good(t *testing.T) { configuration := CircuitBreakerConfig{ FailureThreshold: 1, ResetTimeout: 50 * time.Millisecond, @@ -135,8 +152,7 @@ func TestCircuitBreakerTransitionsToHalfOpen(t *testing.T) { } cb := NewCircuitBreaker("test", configuration) - // Open the circuit - cb.Execute(func() (interface{}, error) { + cb.Execute(func() (interface{}, error) { //nolint:errcheck return nil, errors.New("fail") }) @@ -144,10 +160,8 @@ func TestCircuitBreakerTransitionsToHalfOpen(t *testing.T) { t.Fatal("circuit should be open") } - // Wait for reset timeout time.Sleep(100 * time.Millisecond) - // Next request should transition to half-open and execute result, err := cb.Execute(func() (interface{}, error) { return "probe success", nil }) @@ -163,7 +177,9 @@ func TestCircuitBreakerTransitionsToHalfOpen(t *testing.T) { } } -func TestCircuitBreakerHalfOpenFailureReopens(t *testing.T) { +// TestCircuitBreaker_HalfOpen_Bad verifies that a failed probe in half-open state reopens the circuit. +// cb (half-open) → cb.Execute(failFn) → cb.State() == CircuitOpen +func TestCircuitBreaker_HalfOpen_Bad(t *testing.T) { configuration := CircuitBreakerConfig{ FailureThreshold: 1, ResetTimeout: 50 * time.Millisecond, @@ -171,16 +187,13 @@ func TestCircuitBreakerHalfOpenFailureReopens(t *testing.T) { } cb := NewCircuitBreaker("test", configuration) - // Open the circuit - cb.Execute(func() (interface{}, error) { + cb.Execute(func() (interface{}, error) { //nolint:errcheck return nil, errors.New("fail") }) - // Wait for reset timeout time.Sleep(100 * time.Millisecond) - // Probe fails - cb.Execute(func() (interface{}, error) { + cb.Execute(func() (interface{}, error) { //nolint:errcheck return nil, errors.New("probe failed") }) @@ -189,7 +202,9 @@ func TestCircuitBreakerHalfOpenFailureReopens(t *testing.T) { } } -func TestCircuitBreakerCaching(t *testing.T) { +// TestCircuitBreaker_Caching_Good verifies that a successful result is cached and returned when the circuit is open. +// cb.Execute(successFn) → opens circuit → cb.Execute(anyFn) returns cached value +func TestCircuitBreaker_Caching_Good(t *testing.T) { configuration := CircuitBreakerConfig{ FailureThreshold: 1, ResetTimeout: time.Hour, @@ -197,7 +212,6 @@ func TestCircuitBreakerCaching(t *testing.T) { } cb := NewCircuitBreaker("test", configuration) - // Successful call - caches result result, err := cb.Execute(func() (interface{}, error) { return "cached value", nil }) @@ -208,12 +222,10 @@ func TestCircuitBreakerCaching(t *testing.T) { t.Fatalf("expected 'cached value', got %v", result) } - // Open the circuit - cb.Execute(func() (interface{}, error) { + cb.Execute(func() (interface{}, error) { //nolint:errcheck return nil, errors.New("fail") }) - // Should return cached value when circuit is open result, err = cb.Execute(func() (interface{}, error) { return "should not run", nil }) @@ -226,17 +238,17 @@ func TestCircuitBreakerCaching(t *testing.T) { } } -func TestCircuitBreakerGetCached(t *testing.T) { +// TestCircuitBreaker_GetCached_Good verifies that GetCached returns the last successful result. +// cb.Execute(successFn) → result, ok := cb.GetCached() → ok == true +func TestCircuitBreaker_GetCached_Good(t *testing.T) { cb := NewCircuitBreaker("test", DefaultCircuitBreakerConfig()) - // No cache initially _, ok := cb.GetCached() if ok { t.Error("expected no cached value initially") } - // Cache a value - cb.Execute(func() (interface{}, error) { + cb.Execute(func() (interface{}, error) { //nolint:errcheck return "test value", nil }) @@ -249,7 +261,20 @@ func TestCircuitBreakerGetCached(t *testing.T) { } } -func TestCircuitBreakerReset(t *testing.T) { +// TestCircuitBreaker_GetCached_Bad verifies that GetCached returns false when no execution has occurred. +// cb := NewCircuitBreaker(...) → _, ok := cb.GetCached() → ok == false +func TestCircuitBreaker_GetCached_Bad(t *testing.T) { + cb := NewCircuitBreaker("test", DefaultCircuitBreakerConfig()) + + _, ok := cb.GetCached() + if ok { + t.Error("expected no cached value on fresh circuit breaker") + } +} + +// TestCircuitBreaker_Reset_Good verifies that Reset forces the circuit back to closed state. +// cb (open) → cb.Reset() → cb.State() == CircuitClosed +func TestCircuitBreaker_Reset_Good(t *testing.T) { configuration := CircuitBreakerConfig{ FailureThreshold: 1, ResetTimeout: time.Hour, @@ -257,8 +282,7 @@ func TestCircuitBreakerReset(t *testing.T) { } cb := NewCircuitBreaker("test", configuration) - // Open the circuit - cb.Execute(func() (interface{}, error) { + cb.Execute(func() (interface{}, error) { //nolint:errcheck return nil, errors.New("fail") }) @@ -266,7 +290,6 @@ func TestCircuitBreakerReset(t *testing.T) { t.Fatal("circuit should be open") } - // Manual reset cb.Reset() if cb.State() != CircuitClosed { @@ -274,7 +297,9 @@ func TestCircuitBreakerReset(t *testing.T) { } } -func TestCircuitBreakerConcurrency(t *testing.T) { +// TestCircuitBreaker_Concurrency_Ugly verifies no panics occur under concurrent execution with mixed success/failure. +// 100 goroutines concurrently call cb.Execute — no race condition or panic should occur. +func TestCircuitBreaker_Concurrency_Ugly(t *testing.T) { cb := NewCircuitBreaker("test", DefaultCircuitBreakerConfig()) var wg sync.WaitGroup @@ -282,7 +307,7 @@ func TestCircuitBreakerConcurrency(t *testing.T) { wg.Add(1) go func(n int) { defer wg.Done() - cb.Execute(func() (interface{}, error) { + cb.Execute(func() (interface{}, error) { //nolint:errcheck if n%3 == 0 { return nil, errors.New("fail") } @@ -292,11 +317,12 @@ func TestCircuitBreakerConcurrency(t *testing.T) { } wg.Wait() - // Just verify no panics occurred _ = cb.State() } -func TestGetGitHubCircuitBreaker(t *testing.T) { +// TestCircuitBreaker_GitHubSingleton_Good verifies that getGitHubCircuitBreaker returns the same instance each call. +// cb1 := getGitHubCircuitBreaker(); cb2 := getGitHubCircuitBreaker(); cb1 == cb2 +func TestCircuitBreaker_GitHubSingleton_Good(t *testing.T) { cb1 := getGitHubCircuitBreaker() cb2 := getGitHubCircuitBreaker() @@ -310,12 +336,13 @@ func TestGetGitHubCircuitBreaker(t *testing.T) { } // Benchmark tests + func BenchmarkCircuitBreakerExecute(b *testing.B) { cb := NewCircuitBreaker("bench", DefaultCircuitBreakerConfig()) b.ResetTimer() for i := 0; i < b.N; i++ { - cb.Execute(func() (interface{}, error) { + cb.Execute(func() (interface{}, error) { //nolint:errcheck return "result", nil }) } @@ -326,7 +353,7 @@ func BenchmarkCircuitBreakerConcurrent(b *testing.B) { b.RunParallel(func(pb *testing.PB) { for pb.Next() { - cb.Execute(func() (interface{}, error) { + cb.Execute(func() (interface{}, error) { //nolint:errcheck return "result", nil }) }