import { describe, expect, it } from "vitest"; import { canRestartServer, canStartServer, canStopServer, canUpdateServerGame, gameUpdateStatusFromProbe, gameUpdateStatusLabel, steamUpdateProbe, runtimeObservationFreshness } from "./serverManagement"; import type { DependencyCatalogResponse, DependencyProbeViewResponse, RunEndpointResponse, ServerInstanceResponse, ServerInstanceState } from "../api/types"; describe("server management lifecycle contracts", () => { it("allows explicit starts from recoverable non-running states", () => { const startable: ServerInstanceState[] = ["ready", "stopped", "failed"]; const blocked: ServerInstanceState[] = ["draft", "installing", "running", "deleted"]; expect(startable.every(canStartServer)).toBe(true); expect(blocked.some(canStartServer)).toBe(false); }); it("keeps stop limited to running servers", () => { expect(canStopServer("running")).toBe(true); expect(canStopServer("failed")).toBe(false); }); it("keeps restart and update dispatch inside the states the platform accepts", () => { const restartable: ServerInstanceState[] = ["running", "stopped"]; const updatable: ServerInstanceState[] = ["running", "stopped", "ready", "failed"]; expect(restartable.every(canRestartServer)).toBe(true); expect((["draft", "installing", "ready", "failed", "deleted"] as ServerInstanceState[]).some(canRestartServer)).toBe(false); expect(updatable.every(canUpdateServerGame)).toBe(true); expect((["draft", "installing", "deleted"] as ServerInstanceState[]).some(canUpdateServerGame)).toBe(false); }); it("reads the Steam build probe evidence into an update decision", () => { const catalog = { serverInstanceId: "server-1", pluginId: "game.scum", pluginVersion: "0.1.16", profileKey: "run-local", targetOs: "windows", targetArch: "amd64", updatedAt: "2026-09-15T00:00:00Z", plans: [], probes: [{ key: "scum-server-build", kind: "steam.update", required: false, state: "present", evidence: "installed=100 latest=200 update=yes" }] } as DependencyCatalogResponse; const probe = steamUpdateProbe(catalog); expect(probe?.key).toBe("scum-server-build"); const status = gameUpdateStatusFromProbe(probe); expect(status).toEqual({ availability: "available", installed: "100", latest: "200" }); expect(gameUpdateStatusLabel(status)).toBe("发现新版本"); const current = gameUpdateStatusFromProbe({ ...probe, evidence: "installed=200 latest=200 update=no" } as DependencyProbeViewResponse); expect(current?.availability).toBe("up-to-date"); const unknown = gameUpdateStatusFromProbe({ ...probe, evidence: "installed=none latest=200 update=yes" } as DependencyProbeViewResponse); expect(unknown).toEqual({ availability: "available", installed: "none", latest: "200" }); const missing = gameUpdateStatusFromProbe({ ...probe, kind: "java.version" } as DependencyProbeViewResponse); expect(missing).toBeUndefined(); }); it("distinguishes a fresh Run observation from an unverified historical lifecycle state", () => { const instance = { id: "server-1", state: "running", runEndpointId: "run-1" } as ServerInstanceResponse; const endpoint = { id: "run-1", status: "online", lastHeartbeatAt: "2026-08-07T10:00:00Z" } as RunEndpointResponse; expect(runtimeObservationFreshness(instance, endpoint, Date.parse("2026-08-07T10:00:30Z"))).toBe("fresh"); expect(runtimeObservationFreshness(instance, endpoint, Date.parse("2026-08-07T10:01:00Z"))).toBe("unverified"); expect(runtimeObservationFreshness(instance, { ...endpoint, status: "offline" }, Date.parse("2026-08-07T10:00:01Z"))).toBe("unverified"); }); });