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 <charon@lethean.io>
This commit is contained in:
Claude 2026-04-02 18:16:56 +01:00
parent fcae672dbc
commit 3673757d2a
No known key found for this signature in database
GPG key ID: AF404715446AEB41
6 changed files with 73 additions and 27 deletions

View file

@ -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()

View file

@ -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()

View file

@ -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").

View file

@ -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"

View file

@ -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"))
}
}

View file

@ -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
}