Initial curated projectbrain source from 8a7b1e0651dbdab97d744cbd2e653ab3970ac6c5
This commit is contained in:
commit
5aa3e8d685
700 files changed
+132801
No files matched your search
@@ -0,0 +1,96 @@
|
||||
import Fastify from "fastify";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { loadEnv } from "../src/config/env.js";
|
||||
import type { AutonomyRuntimeSnapshot } from "../src/services/autonomyRuntime.js";
|
||||
import { registerSystemReadinessRoutes } from "../src/routes/systemReadiness.js";
|
||||
|
||||
const mocks = vi.hoisted(() => ({ runtime: vi.fn(), query: vi.fn(), worker: vi.fn() }));
|
||||
vi.mock("../src/services/autonomyRuntime.js", () => ({ loadAutonomyRuntime: mocks.runtime }));
|
||||
vi.mock("../src/db/prisma.js", () => ({ prisma: {
|
||||
$queryRaw: mocks.query,
|
||||
project: { count: vi.fn(async () => 1) },
|
||||
blueprintGraph: { count: vi.fn(async () => 1) },
|
||||
portfolioRepository: { count: vi.fn(async () => 1) },
|
||||
giteaRepositoryLink: { count: vi.fn(async () => 1) },
|
||||
analysisWorkerHeartbeat: { findUnique: mocks.worker },
|
||||
analysisJob: { count: vi.fn(async () => 0) },
|
||||
} }));
|
||||
|
||||
const snapshot = (): AutonomyRuntimeSnapshot => ({
|
||||
executors: [], projects: [],
|
||||
counts: { connectedExecutors: 0, enabledProjects: 0, claimableProjects: 0,
|
||||
activeProjects: 0, pendingWorkItems: 0, blockedProjects: 0,
|
||||
waitingRoadmapProjects: 0, stalledProjects: 0 },
|
||||
});
|
||||
const apps: ReturnType<typeof Fastify>[] = [];
|
||||
const requestReadiness = async (runtime: AutonomyRuntimeSnapshot) => {
|
||||
mocks.runtime.mockResolvedValue(runtime);
|
||||
const app = Fastify();
|
||||
apps.push(app);
|
||||
await registerSystemReadinessRoutes(app, { env: loadEnv({
|
||||
NODE_ENV: "test", PROJECTBRAIN_DATA_SOURCE: "database",
|
||||
DATABASE_URL: "postgresql://fixture:fixture@localhost:5432/fixture",
|
||||
PROJECTBRAIN_OWNER_USERNAME: "fixture-owner",
|
||||
PROJECTBRAIN_OWNER_PASSWORD: "fixture-only-owner-password",
|
||||
PROJECTBRAIN_AUTH_SECRET: "fixture-only-auth-secret-at-least-32-characters",
|
||||
}) });
|
||||
const response = await app.inject({ method: "GET", url: "/api/system/readiness" });
|
||||
expect(response.statusCode).toBe(200);
|
||||
return response.json().data;
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
mocks.query.mockResolvedValue([{ count: 1n }]);
|
||||
mocks.worker.mockResolvedValue({ status: "ready", lastSeenAt: new Date() });
|
||||
});
|
||||
afterEach(async () => { await Promise.all(apps.splice(0).map((app) => app.close())); });
|
||||
|
||||
describe("autonomy readiness demand", () => {
|
||||
it.each([false, true])("does not require an executor when all Auto work is paused (historical heartbeat: %s)", async (historical) => {
|
||||
const runtime = snapshot();
|
||||
if (historical) runtime.executor = { status: "stale", instanceId: "old-web-task",
|
||||
startedAt: "2026-01-01T00:00:00.000Z", lastSeenAt: "2026-01-01T00:00:00.000Z" };
|
||||
const data = await requestReadiness(runtime);
|
||||
expect(data.status).toBe("ready");
|
||||
expect(data.checks.find((check: { id: string }) => check.id === "autonomy-executor")).toMatchObject({ status: "skip" });
|
||||
expect(data.autonomyExecutor).toMatchObject({ status: "ready", connectedExecutors: 0 });
|
||||
expect(data.autonomyExecutor.lastSeenAt).toBe(runtime.executor?.lastSeenAt);
|
||||
});
|
||||
|
||||
it.each(["enabledProjects", "claimableProjects", "activeProjects", "pendingWorkItems"] as const)(
|
||||
"preserves warning without an executor when %s is positive", async (count) => {
|
||||
const runtime = snapshot();
|
||||
runtime.counts[count] = 1;
|
||||
const data = await requestReadiness(runtime);
|
||||
expect(data.status).toBe("degraded");
|
||||
expect(data.checks.find((check: { id: string }) => check.id === "autonomy-executor")).toMatchObject({ status: "warn" });
|
||||
expect(data.autonomyExecutor.connectedExecutors).toBe(0);
|
||||
},
|
||||
);
|
||||
|
||||
it("keeps fresh connected executor and pending work ready", async () => {
|
||||
const runtime = snapshot();
|
||||
runtime.counts.connectedExecutors = runtime.counts.enabledProjects = runtime.counts.pendingWorkItems = 1;
|
||||
const data = await requestReadiness(runtime);
|
||||
expect(data.status).toBe("ready");
|
||||
expect(data.checks.find((check: { id: string }) => check.id === "autonomy-executor")).toMatchObject({ status: "pass" });
|
||||
});
|
||||
|
||||
it("retains a stale heartbeat warning when enabled work still needs the executor", async () => {
|
||||
const runtime = snapshot();
|
||||
runtime.counts.enabledProjects = runtime.counts.pendingWorkItems = 1;
|
||||
runtime.executor = { status: "stale", instanceId: "old-web-task",
|
||||
startedAt: "2026-01-01T00:00:00.000Z", lastSeenAt: "2026-01-01T00:00:00.000Z" };
|
||||
const data = await requestReadiness(runtime);
|
||||
expect(data.status).toBe("degraded");
|
||||
expect(data.autonomyExecutor).toMatchObject({ status: "degraded", connectedExecutors: 0,
|
||||
lastSeenAt: runtime.executor.lastSeenAt });
|
||||
expect(data.checks.find((check: { id: string }) => check.id === "autonomy-executor")).toMatchObject({ status: "warn" });
|
||||
});
|
||||
|
||||
it("does not suppress other readiness warnings while Auto is paused", async () => {
|
||||
mocks.worker.mockResolvedValue(null);
|
||||
expect((await requestReadiness(snapshot())).status).toBe("degraded");
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user