Files
browser/platform_web/schemas/serverManagement.test.ts
T

123 lines
5.6 KiB
TypeScript

import { describe, expect, it } from "vitest";
import type { GamePluginResponse } from "../api/types";
import { defaultServerCreateForm, runtimeBindingFields } from "../contracts/serverManagement";
import { minimalServerCreateRequestFromForm, serverCreateRequestFromForm, serverInstanceIdFromName } 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("derives logical binding fields from the selected profile", () => {
expect(runtimeBindingFields(plugin, "local")).toEqual([
{ key: "java-runtime", required: false, sensitive: false },
{ key: "log-source", required: true, sensitive: false },
{ key: "package-source", required: false, sensitive: false },
{ key: "rcon.password", required: true, sensitive: true },
{ key: "server-root", required: true, sensitive: false }
]);
expect(runtimeBindingFields(plugin, "local").some((field) => field.key === "ftp.profile")).toBe(false);
});
it("submits deployment inputs without binding a Run or runtime profile", () => {
const form = defaultServerCreateForm([plugin], []);
expect(form.profileKey).toBe("local");
expect(
serverCreateRequestFromForm(
{
...form,
id: " server-1 ",
name: " Runtime Server ",
bindings: { "server-root": " runtime.server-root ", "rcon.password": " secret://runtime/server-1/rcon ", "java-runtime": " " }
},
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 ",
deploymentTargetId: "run-builder",
runEndpointId: "run-existing",
bindings: { "rcon.password": "secret://must-not-submit" },
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 ", bindings: {} }, 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("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);
});
});