功能修改
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import type { JobResponse, RunEndpointResponse, ServerInstanceResponse } from "../api/types";
|
||||
import type { OperationRecord } from "./workspace";
|
||||
import { jobBuckets, projectOperationForTray, summarizeEndpointOperations, summarizeServerOperations } from "./operationsConsole";
|
||||
|
||||
function job(id: string, state: JobResponse["state"], updatedAt: string, serverInstanceId = "server-1"): JobResponse {
|
||||
return {
|
||||
id,
|
||||
serverInstanceId,
|
||||
runEndpointId: "endpoint-1",
|
||||
capability: "server.lifecycle.start",
|
||||
idempotencyKey: `idem-${id}`,
|
||||
state,
|
||||
progress: { percent: state === "succeeded" ? 100 : 40 },
|
||||
retryPolicy: { maxAttempts: 3, initialBackoffSeconds: 1, maxBackoffSeconds: 10 },
|
||||
attempt: 1,
|
||||
reconcileCount: 0,
|
||||
createdAt: updatedAt,
|
||||
updatedAt
|
||||
};
|
||||
}
|
||||
|
||||
function server(id: string, state: ServerInstanceResponse["state"], updatedAt: string): ServerInstanceResponse {
|
||||
return {
|
||||
id,
|
||||
pluginId: "scum-server-plugin",
|
||||
pluginVersion: "1.0.0",
|
||||
runEndpointId: "endpoint-1",
|
||||
name: id,
|
||||
adminUserIds: [],
|
||||
state,
|
||||
configVersion: 1,
|
||||
createdAt: updatedAt,
|
||||
updatedAt
|
||||
};
|
||||
}
|
||||
|
||||
describe("operations console contracts", () => {
|
||||
it("classifies active, retrying, failed, and terminal jobs using Platform state", () => {
|
||||
const buckets = jobBuckets([
|
||||
job("queued", "queued", "2026-07-18T10:00:00Z"),
|
||||
job("retrying", "retrying", "2026-07-18T10:02:00Z"),
|
||||
job("failed", "failed", "2026-07-18T10:03:00Z"),
|
||||
job("succeeded", "succeeded", "2026-07-18T10:01:00Z")
|
||||
]);
|
||||
|
||||
expect(buckets.active.map((item) => item.id)).toEqual(["retrying", "queued"]);
|
||||
expect(buckets.retrying.map((item) => item.id)).toEqual(["retrying"]);
|
||||
expect(buckets.failed.map((item) => item.id)).toEqual(["failed"]);
|
||||
expect(buckets.succeeded.map((item) => item.id)).toEqual(["succeeded"]);
|
||||
});
|
||||
|
||||
it("orders failed servers and failed jobs before active and healthy servers", () => {
|
||||
const summaries = summarizeServerOperations(
|
||||
[
|
||||
server("healthy", "running", "2026-07-18T10:04:00Z"),
|
||||
server("active", "ready", "2026-07-18T10:03:00Z"),
|
||||
server("job-failed", "stopped", "2026-07-18T10:02:00Z"),
|
||||
server("server-failed", "failed", "2026-07-18T10:01:00Z")
|
||||
],
|
||||
new Map(),
|
||||
[job("active-job", "running", "2026-07-18T10:05:00Z", "active"), job("failed-job", "failed", "2026-07-18T10:06:00Z", "job-failed")]
|
||||
);
|
||||
|
||||
expect(summaries.map((item) => item.instance.id)).toEqual(["server-failed", "job-failed", "active", "healthy"]);
|
||||
expect(summaries.find((item) => item.instance.id === "job-failed")?.failedJobs).toBe(1);
|
||||
});
|
||||
|
||||
it("summarizes only endpoint-safe capacity and status values", () => {
|
||||
const endpoints: RunEndpointResponse[] = [
|
||||
{
|
||||
id: "endpoint-1",
|
||||
displayName: "Primary",
|
||||
version: "1.0.0",
|
||||
status: "online",
|
||||
capabilities: ["server.lifecycle.start"],
|
||||
capacity: { maxJobs: 4, runningJobs: 2, queuedJobs: 1 },
|
||||
lastHeartbeatAt: "2026-07-18T10:00:00Z"
|
||||
},
|
||||
{
|
||||
id: "endpoint-2",
|
||||
displayName: "Secondary",
|
||||
version: "1.0.0",
|
||||
status: "degraded",
|
||||
capabilities: [],
|
||||
capacity: { maxJobs: 2, runningJobs: 1, queuedJobs: 3 },
|
||||
lastHeartbeatAt: "2026-07-18T10:00:00Z"
|
||||
}
|
||||
];
|
||||
|
||||
expect(summarizeEndpointOperations(endpoints)).toEqual({ total: 2, online: 1, degraded: 1, offline: 0, disabled: 0, activeJobs: 3, queuedJobs: 4 });
|
||||
});
|
||||
|
||||
it("projects an allowlisted operation tray shape and protects unsafe target strings", () => {
|
||||
const operation = {
|
||||
id: "op-1",
|
||||
intent: "更新配置",
|
||||
targetKind: "config",
|
||||
targetId: "/Users/operator/private.cfg",
|
||||
requester: "Operator",
|
||||
status: "failed",
|
||||
errorReason: "平台拒绝请求:Bearer raw-token /Users/operator/private.cfg PID=4201 unix:///var/run/run.sock",
|
||||
diagnosticId: "/private/tmp/diagnostic.json",
|
||||
createdAt: "2026-07-18T10:00:00Z",
|
||||
updatedAt: "2026-07-18T10:01:00Z",
|
||||
rawToken: "run-token-should-not-project"
|
||||
} as OperationRecord & { rawToken: string };
|
||||
|
||||
const projected = projectOperationForTray(operation);
|
||||
expect(projected.targetLabel).toBe("配置 / 受保护目标");
|
||||
expect(JSON.stringify(projected)).not.toContain("/Users/");
|
||||
expect(JSON.stringify(projected)).not.toContain("run-token");
|
||||
expect(JSON.stringify(projected)).not.toContain("raw-token");
|
||||
expect(JSON.stringify(projected)).not.toContain("/var/run/");
|
||||
expect(JSON.stringify(projected)).not.toContain("4201");
|
||||
expect(projected.diagnosticId).toBe("受保护诊断");
|
||||
expect(projected).not.toHaveProperty("requester");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user