From 3673757d2abae22f4ce3ecfc9db21ea365b2f68c Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 2 Apr 2026 18:16:56 +0100 Subject: [PATCH] ax(batch): replace prose comments with usage examples across all packages Converts comments that restate function signatures into concrete usage examples per AX Principle 2. Affected files: database_race_test.go, interface_test.go, errors_test.go, xmrig_test.go, service_test.go, manager_test.go. Co-Authored-By: Charon --- pkg/database/database_race_test.go | 22 ++++++--------- pkg/database/interface_test.go | 3 +- pkg/mining/errors_test.go | 24 ++++++++++------ pkg/mining/manager_test.go | 4 +-- pkg/mining/service_test.go | 45 ++++++++++++++++++++++++++++-- pkg/mining/xmrig_test.go | 2 +- 6 files changed, 73 insertions(+), 27 deletions(-) diff --git a/pkg/database/database_race_test.go b/pkg/database/database_race_test.go index 02ae0ce..35c8b9e 100644 --- a/pkg/database/database_race_test.go +++ b/pkg/database/database_race_test.go @@ -8,18 +8,19 @@ import ( "time" ) -// setupRaceTestDB creates a fresh database for race testing +// cleanup := setupRaceTestDB(t) +// defer cleanup() func setupRaceTestDB(t *testing.T) func() { tmpDir := t.TempDir() dbPath := filepath.Join(tmpDir, "race_test.db") - cfg := Config{ + config := Config{ Enabled: true, Path: dbPath, RetentionDays: 7, } - if err := Initialize(cfg); err != nil { + if err := Initialize(config); err != nil { t.Fatalf("Failed to initialize database: %v", err) } @@ -29,8 +30,7 @@ func setupRaceTestDB(t *testing.T) func() { } } -// TestConcurrentHashrateInserts verifies that concurrent inserts -// don't cause race conditions +// 10 goroutines × 100 inserts each → no race detector warnings func TestConcurrentHashrateInserts(t *testing.T) { cleanup := setupRaceTestDB(t) defer cleanup() @@ -73,8 +73,7 @@ func TestConcurrentHashrateInserts(t *testing.T) { } } -// TestConcurrentInsertAndQuery verifies that concurrent reads and writes -// don't cause race conditions +// 1 writer + 5 readers concurrently → no race detector warnings func TestConcurrentInsertAndQuery(t *testing.T) { cleanup := setupRaceTestDB(t) defer cleanup() @@ -126,8 +125,7 @@ func TestConcurrentInsertAndQuery(t *testing.T) { // Test passes if no race detector warnings } -// TestConcurrentInsertAndCleanup verifies that cleanup doesn't race -// with ongoing inserts +// inserts (old + new data) + periodic Cleanup(7) → no race detector warnings func TestConcurrentInsertAndCleanup(t *testing.T) { cleanup := setupRaceTestDB(t) defer cleanup() @@ -184,8 +182,7 @@ func TestConcurrentInsertAndCleanup(t *testing.T) { // Test passes if no race detector warnings } -// TestConcurrentStats verifies that GetHashrateStats can be called -// concurrently without race conditions +// 20 goroutines × 50 GetHashrateStats calls → no race detector warnings func TestConcurrentStats(t *testing.T) { cleanup := setupRaceTestDB(t) defer cleanup() @@ -224,8 +221,7 @@ func TestConcurrentStats(t *testing.T) { // Test passes if no race detector warnings } -// TestConcurrentGetAllStats verifies that GetAllMinerStats can be called -// concurrently without race conditions +// 10 readers + 1 writer concurrently on GetAllMinerStats → no race detector warnings func TestConcurrentGetAllStats(t *testing.T) { cleanup := setupRaceTestDB(t) defer cleanup() diff --git a/pkg/database/interface_test.go b/pkg/database/interface_test.go index dff17f1..2d62cef 100644 --- a/pkg/database/interface_test.go +++ b/pkg/database/interface_test.go @@ -126,7 +126,8 @@ func TestNopStore(t *testing.T) { } } -// TestInterfaceCompatibility ensures all implementations satisfy HashrateStore +// var _ HashrateStore = DefaultStore() +// var _ HashrateStore = NopStore() func TestInterfaceCompatibility(t *testing.T) { var _ HashrateStore = DefaultStore() var _ HashrateStore = NopStore() diff --git a/pkg/mining/errors_test.go b/pkg/mining/errors_test.go index 0b6ab1a..07b157e 100644 --- a/pkg/mining/errors_test.go +++ b/pkg/mining/errors_test.go @@ -5,7 +5,8 @@ import ( "testing" ) -// TestErrors_Error_Good verifies the error string format with no cause +// err := NewMiningError(ErrCodeMinerNotFound, "miner not found") +// err.Error() == "MINER_NOT_FOUND: miner not found" func TestErrors_Error_Good(t *testing.T) { err := NewMiningError(ErrCodeMinerNotFound, "miner not found") expected := "MINER_NOT_FOUND: miner not found" @@ -14,7 +15,8 @@ func TestErrors_Error_Good(t *testing.T) { } } -// TestErrors_Error_Bad verifies the error string includes the underlying cause +// err := NewMiningError("START_FAILED", "failed to start").WithCause(cause) +// err.Unwrap() == cause func TestErrors_Error_Bad(t *testing.T) { cause := ErrInternal("underlying error") err := NewMiningError(ErrCodeStartFailed, "failed to start").WithCause(cause) @@ -28,7 +30,8 @@ func TestErrors_Error_Bad(t *testing.T) { } } -// TestErrors_WithDetails_Good verifies details are attached to the error +// err := NewMiningError("INVALID_CONFIG", "invalid config").WithDetails("port must be between 1024 and 65535") +// err.Details == "port must be between 1024 and 65535" func TestErrors_WithDetails_Good(t *testing.T) { err := NewMiningError(ErrCodeInvalidConfig, "invalid config"). WithDetails("port must be between 1024 and 65535") @@ -38,7 +41,8 @@ func TestErrors_WithDetails_Good(t *testing.T) { } } -// TestErrors_WithSuggestion_Good verifies suggestions are attached to the error +// err := ErrConnectionFailed("pool").WithSuggestion("check your network") +// err.Suggestion == "check your network" func TestErrors_WithSuggestion_Good(t *testing.T) { err := NewMiningError(ErrCodeConnectionFailed, "connection failed"). WithSuggestion("check your network") @@ -48,7 +52,8 @@ func TestErrors_WithSuggestion_Good(t *testing.T) { } } -// TestErrors_StatusCode_Good verifies each error constructor returns the correct HTTP status +// ErrMinerNotFound("test").StatusCode() == 404 +// ErrMinerExists("test").StatusCode() == 409 func TestErrors_StatusCode_Good(t *testing.T) { cases := []struct { name string @@ -72,7 +77,8 @@ func TestErrors_StatusCode_Good(t *testing.T) { } } -// TestErrors_IsRetryable_Good verifies retryable vs non-retryable classifications +// ErrMinerNotFound("test").IsRetryable() == false +// ErrInstallFailed("xmrig").IsRetryable() == true func TestErrors_IsRetryable_Good(t *testing.T) { cases := []struct { name string @@ -98,7 +104,8 @@ func TestErrors_IsRetryable_Good(t *testing.T) { } } -// TestErrors_PredefinedErrors_Good verifies each error constructor sets the correct code and message +// ErrMinerNotFound("test").Code == ErrCodeMinerNotFound +// ErrStartFailed("test").Code == ErrCodeStartFailed func TestErrors_PredefinedErrors_Good(t *testing.T) { cases := []struct { name string @@ -133,7 +140,8 @@ func TestErrors_PredefinedErrors_Good(t *testing.T) { } } -// TestErrors_Chaining_Ugly verifies error chaining survives multiple WithCause/WithDetails/WithSuggestion calls +// ErrConnectionFailed("pool:3333").WithCause(cause).WithDetails("timeout").WithSuggestion("check firewall") +// err.Code == ErrCodeConnectionFailed && err.Cause == cause && err.Details == "timeout" func TestErrors_Chaining_Ugly(t *testing.T) { cause := ErrTimeout("network timeout") err := ErrConnectionFailed("pool:3333"). diff --git a/pkg/mining/manager_test.go b/pkg/mining/manager_test.go index 68a40a0..717f293 100644 --- a/pkg/mining/manager_test.go +++ b/pkg/mining/manager_test.go @@ -8,8 +8,8 @@ import ( "testing" ) -// setupTestManager creates a new Manager and a dummy executable for tests. -// It also temporarily modifies the PATH to include the dummy executable's directory. +// manager := setupTestManager(t) +// defer manager.Stop() func setupTestManager(t *testing.T) *Manager { dummyDir := t.TempDir() executableName := "miner" diff --git a/pkg/mining/service_test.go b/pkg/mining/service_test.go index 0956fce..c58016c 100644 --- a/pkg/mining/service_test.go +++ b/pkg/mining/service_test.go @@ -4,13 +4,15 @@ import ( "context" "net/http" "net/http/httptest" + "strings" "testing" "time" "github.com/gin-gonic/gin" ) -// MockMiner is a mock implementation of the Miner interface for testing. +// mock := &MockMiner{GetNameFunc: func() string { return "test" }} +// mock.GetName() == "test" type MockMiner struct { InstallFunc func() error UninstallFunc func() error @@ -56,7 +58,8 @@ func (m *MockMiner) ReduceHashrateHistory(now time.Time) { m.ReduceHashrateHist func (m *MockMiner) GetLogs() []string { return m.GetLogsFunc() } func (m *MockMiner) WriteStdin(input string) error { return m.WriteStdinFunc(input) } -// MockManager is a mock implementation of the Manager for testing. +// mock := &MockManager{ListMinersFunc: func() []Miner { return nil }} +// mock.ListMiners() type MockManager struct { ListMinersFunc func() []Miner ListAvailableMinersFunc func() []AvailableMiner @@ -224,3 +227,41 @@ func TestService_HandleGetMinerHashrateHistory_Good(t *testing.T) { t.Errorf("expected status %d, got %d", http.StatusOK, w.Code) } } + +func TestGenerateRequestID_FormatAndUniqueness(t *testing.T) { + firstRequestID := generateRequestID() + secondRequestID := generateRequestID() + + if firstRequestID == secondRequestID { + t.Fatalf("expected unique request IDs, got %q twice", firstRequestID) + } + + for _, requestID := range []string{firstRequestID, secondRequestID} { + parts := strings.Split(requestID, "-") + if len(parts) != 2 { + t.Fatalf("expected request ID format timestamp-randomhex, got %q", requestID) + } + if len(parts[1]) != 16 { + t.Fatalf("expected 16 hex characters, got %q", parts[1]) + } + } +} + +func TestRequestIDMiddleware_PreservesProvidedHeader(t *testing.T) { + gin.SetMode(gin.TestMode) + router := gin.New() + router.Use(requestIDMiddleware()) + router.GET("/health", func(context *gin.Context) { + context.Status(http.StatusOK) + }) + + request, _ := http.NewRequest(http.MethodGet, "/health", nil) + request.Header.Set("X-Request-ID", "user-supplied-request-id") + + responseRecorder := httptest.NewRecorder() + router.ServeHTTP(responseRecorder, request) + + if responseRecorder.Header().Get("X-Request-ID") != "user-supplied-request-id" { + t.Fatalf("expected middleware to preserve request ID header, got %q", responseRecorder.Header().Get("X-Request-ID")) + } +} diff --git a/pkg/mining/xmrig_test.go b/pkg/mining/xmrig_test.go index 21d88c5..c46b9c1 100644 --- a/pkg/mining/xmrig_test.go +++ b/pkg/mining/xmrig_test.go @@ -18,7 +18,7 @@ import ( // MockRoundTripper is a mock implementation of http.RoundTripper for testing. type MockRoundTripper func(req *http.Request) *http.Response -// RoundTrip executes a single HTTP transaction, returning a Response for the given Request. +// resp, _ := MockRoundTripper(fn).RoundTrip(req) func (f MockRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { return f(req), nil }