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>
164 lines
5.5 KiB
Go
164 lines
5.5 KiB
Go
package mining
|
|
|
|
import (
|
|
"net/http"
|
|
"testing"
|
|
)
|
|
|
|
// 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"
|
|
if err.Error() != expected {
|
|
t.Errorf("Expected %q, got %q", expected, err.Error())
|
|
}
|
|
}
|
|
|
|
// 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)
|
|
|
|
if err.Cause != cause {
|
|
t.Error("Cause was not set")
|
|
}
|
|
|
|
if err.Unwrap() != cause {
|
|
t.Error("Unwrap did not return cause")
|
|
}
|
|
}
|
|
|
|
// 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")
|
|
|
|
if err.Details != "port must be between 1024 and 65535" {
|
|
t.Errorf("Details not set correctly: %s", err.Details)
|
|
}
|
|
}
|
|
|
|
// 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")
|
|
|
|
if err.Suggestion != "check your network" {
|
|
t.Errorf("Suggestion not set correctly: %s", err.Suggestion)
|
|
}
|
|
}
|
|
|
|
// ErrMinerNotFound("test").StatusCode() == 404
|
|
// ErrMinerExists("test").StatusCode() == 409
|
|
func TestErrors_StatusCode_Good(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
err *MiningError
|
|
expected int
|
|
}{
|
|
{"default", NewMiningError("TEST", "test"), http.StatusInternalServerError},
|
|
{"not found", ErrMinerNotFound("test"), http.StatusNotFound},
|
|
{"conflict", ErrMinerExists("test"), http.StatusConflict},
|
|
{"bad request", ErrInvalidConfig("bad"), http.StatusBadRequest},
|
|
{"service unavailable", ErrConnectionFailed("pool"), http.StatusServiceUnavailable},
|
|
{"timeout", ErrTimeout("operation"), http.StatusGatewayTimeout},
|
|
}
|
|
|
|
for _, c := range cases {
|
|
t.Run(c.name, func(t *testing.T) {
|
|
if c.err.StatusCode() != c.expected {
|
|
t.Errorf("Expected status %d, got %d", c.expected, c.err.StatusCode())
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// ErrMinerNotFound("test").IsRetryable() == false
|
|
// ErrInstallFailed("xmrig").IsRetryable() == true
|
|
func TestErrors_IsRetryable_Good(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
err *MiningError
|
|
retryable bool
|
|
}{
|
|
{"not found", ErrMinerNotFound("test"), false},
|
|
{"exists", ErrMinerExists("test"), false},
|
|
{"invalid config", ErrInvalidConfig("bad"), false},
|
|
{"install failed", ErrInstallFailed("xmrig"), true},
|
|
{"start failed", ErrStartFailed("test"), true},
|
|
{"connection failed", ErrConnectionFailed("pool"), true},
|
|
{"timeout", ErrTimeout("operation"), true},
|
|
{"database error", ErrDatabaseError("query"), true},
|
|
}
|
|
|
|
for _, c := range cases {
|
|
t.Run(c.name, func(t *testing.T) {
|
|
if c.err.IsRetryable() != c.retryable {
|
|
t.Errorf("Expected retryable=%v, got %v", c.retryable, c.err.IsRetryable())
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// ErrMinerNotFound("test").Code == ErrCodeMinerNotFound
|
|
// ErrStartFailed("test").Code == ErrCodeStartFailed
|
|
func TestErrors_PredefinedErrors_Good(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
err *MiningError
|
|
code string
|
|
}{
|
|
{"ErrMinerNotFound", ErrMinerNotFound("test"), ErrCodeMinerNotFound},
|
|
{"ErrMinerExists", ErrMinerExists("test"), ErrCodeMinerExists},
|
|
{"ErrMinerNotRunning", ErrMinerNotRunning("test"), ErrCodeMinerNotRunning},
|
|
{"ErrInstallFailed", ErrInstallFailed("xmrig"), ErrCodeInstallFailed},
|
|
{"ErrStartFailed", ErrStartFailed("test"), ErrCodeStartFailed},
|
|
{"ErrStopFailed", ErrStopFailed("test"), ErrCodeStopFailed},
|
|
{"ErrInvalidConfig", ErrInvalidConfig("bad port"), ErrCodeInvalidConfig},
|
|
{"ErrUnsupportedMiner", ErrUnsupportedMiner("unknown"), ErrCodeUnsupportedMiner},
|
|
{"ErrConnectionFailed", ErrConnectionFailed("pool:3333"), ErrCodeConnectionFailed},
|
|
{"ErrTimeout", ErrTimeout("GetStats"), ErrCodeTimeout},
|
|
{"ErrDatabaseError", ErrDatabaseError("insert"), ErrCodeDatabaseError},
|
|
{"ErrProfileNotFound", ErrProfileNotFound("abc123"), ErrCodeProfileNotFound},
|
|
{"ErrProfileExists", ErrProfileExists("My Profile"), ErrCodeProfileExists},
|
|
{"ErrInternal", ErrInternal("unexpected error"), ErrCodeInternalError},
|
|
}
|
|
|
|
for _, c := range cases {
|
|
t.Run(c.name, func(t *testing.T) {
|
|
if c.err.Code != c.code {
|
|
t.Errorf("Expected code %s, got %s", c.code, c.err.Code)
|
|
}
|
|
if c.err.Message == "" {
|
|
t.Error("Message should not be empty")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// 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").
|
|
WithCause(cause).
|
|
WithDetails("timeout after 30s").
|
|
WithSuggestion("check firewall settings")
|
|
|
|
if err.Code != ErrCodeConnectionFailed {
|
|
t.Errorf("Code changed: %s", err.Code)
|
|
}
|
|
if err.Cause != cause {
|
|
t.Error("Cause not set")
|
|
}
|
|
if err.Details != "timeout after 30s" {
|
|
t.Errorf("Details not set: %s", err.Details)
|
|
}
|
|
if err.Suggestion != "check firewall settings" {
|
|
t.Errorf("Suggestion not set: %s", err.Suggestion)
|
|
}
|
|
}
|