import { describe, expect, it } from "vitest"; import type { GamePluginResponse, ServerInstanceResponse } from "../api/types"; import { defaultServerCreateForm } from "../contracts/serverManagement"; import { minimalServerCreateRequestFromForm, serverCreateRequestFromForm, serverInstanceIdFromName, serverLifecycleCommandRequest } from "./serverManagement"; const plugin: GamePluginResponse = { id: "game.runtime", name: "Runtime Game", version: "1.0.0", serverType: "runtime", manifestRef: "artifact://runtime-manifest", createFormSchemaRef: "schemas/create.json", createFields: [ { key: "gamePort", label: "游戏端口", type: "port", required: true, defaultValue: "7777" }, { key: "maxPlayers", label: "最大玩家数", type: "number", required: true, defaultValue: "64" } ], requiredRunCapabilities: ["process.install"], declaredPermissions: ["server.create"], permissions: { ai: false, logs: true, files: false, jobs: true, artifacts: false }, lifecycleActions: { install: "actions/install.json", start: "actions/start.json", stop: "actions/stop.json" }, bridgeActions: [], pages: [], tags: [], aiPurposes: [], productionLifecycle: { operations: ["install", "enable", "disable", "upgrade", "rollback", "retire", "dependency-check"], dependencyPolicy: "optional", approvalRequired: ["disable", "rollback", "retire"] }, status: "installed", runtimeProfiles: { discovery: [{ key: "root-check", kind: "file.exists", targetKey: "server-root", required: true }], dependencyProbes: [{ key: "java", kind: "java.version", targetKey: "java-runtime", required: false }], installPlans: [{ key: "java-install", title: "Java", steps: [{ type: "package", targetKey: "package-source" }] }], logSources: [{ key: "main-log", kind: "file.tail", targetKey: "log-source", streamKey: "main" }], transportProfiles: [ { key: "rcon", kind: "rcon", targetKey: "rcon.password", capabilities: ["remote.run.rcon.command"] }, { key: "ftp", kind: "ftp", targetKey: "ftp.profile", capabilities: ["remote.ftp.read"] } ], lifecycleProfiles: [ { key: "local", mode: "local-process", capabilities: ["process.install", "process.start", "process.stop"], transportKeys: ["rcon"] }, { key: "hosted", mode: "hosted-ftp-rcon", capabilities: ["remote.ftp.read"], transportKeys: ["ftp"] } ] } }; describe("runtime profile server creation contracts", () => { it("submits deployment inputs without binding a Run or runtime profile", () => { const form = defaultServerCreateForm([plugin]); expect( serverCreateRequestFromForm( { ...form, id: " server-1 ", name: " Runtime Server ", }, 17 ) ).toEqual({ id: "server-1", pluginId: "game.runtime", name: "Runtime Server", idempotencyKey: "web:create:server-1:17", deployment: { mode: "guided-install", createInputs: { gamePort: "7777", maxPlayers: "64" } } }); }); it("maps the create UI to a minimal server request", () => { const form = defaultServerCreateForm([plugin]); const request = minimalServerCreateRequestFromForm({ ...form, name: " Minimal Runtime Server ", serverRoot: "/srv/must-not-submit" }, 16); expect(request).toEqual({ id: "server-minimal-runtime-server-16", pluginId: "game.runtime", name: "Minimal Runtime Server", idempotencyKey: "web:create:server-minimal-runtime-server-16:16" }); }); it("generates server instance ids from the visible server name", () => { const form = defaultServerCreateForm([plugin]); const request = serverCreateRequestFromForm({ ...form, name: " Runtime Server " }, 17); expect(request).toMatchObject({ id: "server-runtime-server-17", name: "Runtime Server", idempotencyKey: "web:create:server-runtime-server-17:17" }); expect(serverInstanceIdFromName("测试服", 18)).toBe("server-18"); }); it("matches the platform lifecycle command DTO exactly", () => { const instance = { id: "server-1", configVersion: 7, configChecksum: "sha256:unused" } as ServerInstanceResponse; expect(serverLifecycleCommandRequest(instance, "start", 20)).toEqual({ expectedConfigVersion: 7, idempotencyKey: "web:start:server-1:20" }); }); it("keeps complete paths and commands in a write-only deployment payload", () => { const form = defaultServerCreateForm([plugin]); const request = serverCreateRequestFromForm({ ...form, name: "Venv Server", deploymentMode: "custom-command", serverRoot: "/srv/venv-server", workingDirectory: "/srv/venv-server", startCommand: "/srv/venv-server/.venv/bin/python server.py", shell: "" }, 19); expect("runEndpointId" in request).toBe(false); expect("profileKey" in request).toBe(false); expect("bindings" in request).toBe(false); expect(request.deployment).toMatchObject({ mode: "custom-command", serverRoot: "/srv/venv-server", workingDirectory: "/srv/venv-server", startCommand: "/srv/venv-server/.venv/bin/python server.py" }); expect("profileKey" in (request.deployment ?? {})).toBe(false); expect("runtimeBindings" in (request.deployment ?? {})).toBe(false); }); });