package api import ( "context" "git.misaka.ren/m1saka/dsh-web/internal/store" "net/http" "net/http/httptest" "strings" "testing" ) func TestOrphanReclaimGuards(t *testing.T) { for _, kind := range []string{"safe", "running", "foreign-mount", "reference", "upgrade", "confirmation", "nonadmin"} { t.Run(kind, func(t *testing.T) { t.Setenv("HOST_DATA_ROOT", "/host/data") id, inst, owner := strings.Repeat("a", 64), strings.Repeat("b", 32), strings.Repeat("c", 32) deleted := false a, sid := runtimeTestAPI(t, func(w http.ResponseWriter, r *http.Request) { if r.Method == "DELETE" { if r.URL.Query().Get("force") != "false" || r.URL.Query().Get("v") != "false" { t.Fatal("unsafe deletion") } deleted = true w.WriteHeader(204) return } source := "/host/data/workspaces/" + owner + "/instances/" + inst + "/home" if kind == "foreign-mount" { source = "/unrelated" } writeJSON(w, map[string]any{"Id": id, "Name": "/dsh-inst-" + inst, "Config": map[string]any{"Labels": map[string]string{"dsh-mgr.role": "dsh", "dsh-mgr.instance": inst, "dsh-mgr.owner": owner}}, "State": map[string]any{"Status": "exited", "Running": kind == "running"}, "Mounts": []map[string]string{{"Type": "bind", "Source": source, "Destination": "/workspace"}}}) }) if err := a.s.CreateUser(store.User{ID: owner, Username: "orphan-owner"}, "unused"); err != nil { t.Fatal(err) } if kind != "nonadmin" { if _, err := a.s.DB.Exec("UPDATE users SET admin=1 WHERE id='owner'"); err != nil { t.Fatal(err) } } if kind == "reference" { if err := a.s.AddInstance(store.Instance{ID: inst, UID: owner, ContainerID: id}); err != nil { t.Fatal(err) } } if kind == "upgrade" { if _, err := a.s.DB.Exec("CREATE TABLE upgrade_journal(instance_id TEXT,old_container TEXT,new_container TEXT); INSERT INTO upgrade_journal VALUES(?,?,'')", inst, id); err != nil { t.Fatal(err) } } if kind == "safe" && a.checkOrphan(context.Background(), id) != nil { t.Fatal("safe orphan rejected") } confirm := id if kind == "confirmation" { confirm = "wrong" } w := httptest.NewRecorder() a.orphans(w, runtimeRequest("DELETE", "/api/orphans?id="+id+"&confirm="+confirm, "", sid)) if (w.Code == 200) != (kind == "safe") || deleted != (kind == "safe") { t.Fatalf("status=%d deleted=%v body=%s", w.Code, deleted, w.Body.String()) } }) } }