feat: complete catalog-driven preprocessing
Publish documentation / publish (push) Successful in 2m12s
Publish documentation / publish (push) Successful in 2m12s
This commit is contained in:
@@ -0,0 +1,174 @@
|
||||
import { render, screen, waitFor } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import { http, HttpResponse } from "msw";
|
||||
import { server } from "../test/msw";
|
||||
import type { WorkspacePreprocessingStatus } from "../api/workspace-preprocessing";
|
||||
import { WorkspacePreprocessingControl } from "./WorkspacePreprocessingControl";
|
||||
|
||||
function renderControl(status: WorkspacePreprocessingStatus) {
|
||||
const client = new QueryClient({ defaultOptions: { queries: { retry: false } } });
|
||||
return render(
|
||||
<QueryClientProvider client={client}>
|
||||
<WorkspacePreprocessingControl
|
||||
workspaceId="catalog-workspace"
|
||||
status={status}
|
||||
loading={false}
|
||||
unavailable={false}
|
||||
canManage
|
||||
/>
|
||||
</QueryClientProvider>,
|
||||
);
|
||||
}
|
||||
|
||||
test("failed state shows the reason and only the latest run diagnostic", async () => {
|
||||
renderControl({
|
||||
schemaVersion: 1,
|
||||
workspaceId: "catalog-workspace",
|
||||
state: "failed",
|
||||
actionable: true,
|
||||
clearable: true,
|
||||
detail: "The schema index could not be rebuilt.",
|
||||
reason: "The schema indexing worker stopped before publication.",
|
||||
nextStep: "Check the core service log, then retry.",
|
||||
lastFailure: {
|
||||
stage: "schema_index",
|
||||
errorCode: "schema_index_failed",
|
||||
finishedAt: "2026-09-05T10:04:00.000Z",
|
||||
},
|
||||
});
|
||||
|
||||
expect(screen.getByText("The schema indexing worker stopped before publication.")).toBeVisible();
|
||||
await userEvent.click(screen.getByText("Last run details"));
|
||||
expect(screen.getByText("schema_index", { selector: "dd" })).toBeVisible();
|
||||
expect(screen.getByText("schema_index_failed", { selector: "dd" })).toBeVisible();
|
||||
expect(screen.getByText(/docker compose logs core/)).toBeVisible();
|
||||
expect(screen.queryByText(/history/i)).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
test("blocked state gives the current prerequisite and no run details", () => {
|
||||
renderControl({
|
||||
schemaVersion: 1,
|
||||
workspaceId: "catalog-workspace",
|
||||
state: "blocked",
|
||||
actionable: false,
|
||||
clearable: true,
|
||||
detail: "Catalog synchronization is required.",
|
||||
reason: "Database configuration v4 is newer than Catalog synchronization v3.",
|
||||
nextStep: "Open Database management and run Synchronize schema.",
|
||||
});
|
||||
|
||||
expect(screen.getByText("Database configuration v4 is newer than Catalog synchronization v3.")).toBeVisible();
|
||||
expect(screen.getByText("No preprocessing log is available because a run did not start.")).toBeVisible();
|
||||
expect(screen.queryByText("Last run details")).not.toBeInTheDocument();
|
||||
expect(screen.getByRole("button", { name: "Run" })).toBeDisabled();
|
||||
});
|
||||
|
||||
test("running state shows the current durable phase instead of only a spinner", () => {
|
||||
renderControl({
|
||||
schemaVersion: 1,
|
||||
workspaceId: "catalog-workspace",
|
||||
state: "running",
|
||||
actionable: false,
|
||||
clearable: false,
|
||||
detail: "Indexing Evidence.",
|
||||
progress: { stage: "evidence", step: 3, totalSteps: 4 },
|
||||
});
|
||||
|
||||
expect(screen.getByText("Indexing Evidence")).toBeVisible();
|
||||
expect(screen.getByText("3 / 4")).toBeVisible();
|
||||
expect(screen.getByRole("progressbar", { name: "Preprocessing progress" })).toHaveAttribute(
|
||||
"aria-valuetext",
|
||||
"Indexing Evidence, stage 3 of 4",
|
||||
);
|
||||
expect(screen.getByRole("button", { name: "Running" })).toBeDisabled();
|
||||
});
|
||||
|
||||
test("ready state offers an explicit rerun from the GUI", async () => {
|
||||
let calls = 0;
|
||||
server.use(http.post("/api/workspaces/catalog-workspace/preprocessing", () => {
|
||||
calls += 1;
|
||||
return HttpResponse.json({
|
||||
schemaVersion: 1,
|
||||
workspaceId: "catalog-workspace",
|
||||
state: "ready",
|
||||
actionable: true,
|
||||
clearable: true,
|
||||
detail: "Catalog revision 18 is indexed.",
|
||||
});
|
||||
}));
|
||||
renderControl({
|
||||
schemaVersion: 1,
|
||||
workspaceId: "catalog-workspace",
|
||||
state: "ready",
|
||||
actionable: true,
|
||||
clearable: true,
|
||||
detail: "Catalog revision 18 is indexed.",
|
||||
});
|
||||
|
||||
await userEvent.click(screen.getByRole("button", { name: "Run again" }));
|
||||
await waitFor(() => expect(calls).toBe(1));
|
||||
});
|
||||
|
||||
test("Retry invokes the single preprocessing endpoint", async () => {
|
||||
let calls = 0;
|
||||
server.use(http.post("/api/workspaces/catalog-workspace/preprocessing", () => {
|
||||
calls += 1;
|
||||
return HttpResponse.json({
|
||||
schemaVersion: 1,
|
||||
workspaceId: "catalog-workspace",
|
||||
state: "ready",
|
||||
actionable: true,
|
||||
clearable: true,
|
||||
detail: "Catalog revision 18 is indexed.",
|
||||
});
|
||||
}));
|
||||
renderControl({
|
||||
schemaVersion: 1,
|
||||
workspaceId: "catalog-workspace",
|
||||
state: "failed",
|
||||
actionable: true,
|
||||
clearable: true,
|
||||
detail: "Preprocessing did not complete.",
|
||||
reason: "The worker stopped.",
|
||||
nextStep: "Retry.",
|
||||
lastFailure: {
|
||||
stage: "preprocessing",
|
||||
errorCode: "preprocessing_failed",
|
||||
finishedAt: "2026-09-05T10:04:00.000Z",
|
||||
},
|
||||
});
|
||||
|
||||
await userEvent.click(screen.getByRole("button", { name: "Retry" }));
|
||||
await waitFor(() => expect(calls).toBe(1));
|
||||
});
|
||||
|
||||
test("Clear uses the approved inline review and preserves memory in its scope copy", async () => {
|
||||
let calls = 0;
|
||||
server.use(http.delete("/api/workspaces/catalog-workspace/preprocessing", () => {
|
||||
calls += 1;
|
||||
return HttpResponse.json({
|
||||
schemaVersion: 1,
|
||||
workspaceId: "catalog-workspace",
|
||||
state: "required",
|
||||
actionable: true,
|
||||
clearable: false,
|
||||
detail: "Reference vectors and LSH are empty. Memory is preserved.",
|
||||
});
|
||||
}));
|
||||
renderControl({
|
||||
schemaVersion: 1,
|
||||
workspaceId: "catalog-workspace",
|
||||
state: "ready",
|
||||
actionable: true,
|
||||
clearable: true,
|
||||
detail: "Catalog revision 18 is indexed.",
|
||||
});
|
||||
|
||||
await userEvent.click(screen.getByRole("button", { name: "Clear" }));
|
||||
expect(screen.getByText("Clear derived data?")).toBeVisible();
|
||||
expect(screen.getByText("Schema/Evidence vectors, LSH and derived checkpoints")).toBeVisible();
|
||||
expect(screen.getByText("Memory and solved questions")).toBeVisible();
|
||||
await userEvent.click(screen.getByRole("button", { name: "Clear derived data" }));
|
||||
await waitFor(() => expect(calls).toBe(1));
|
||||
});
|
||||
Reference in New Issue
Block a user