mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-24 11:25:50 -06:00
docs: document subagent registry persistence tests
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
// Subagent registry persistence tests cover JSON registry restore, child
|
||||
// session timing writes, and restart cleanup behavior.
|
||||
import fsSync from "node:fs";
|
||||
import fs from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
@@ -123,6 +125,8 @@ describe("subagent registry persistence", () => {
|
||||
persisted: Record<string, unknown>,
|
||||
opts?: { seedChildSessions?: boolean },
|
||||
) => {
|
||||
// Each persisted-registry fixture gets its own state dir so session stores
|
||||
// and registry files are tested through the same paths production resolves.
|
||||
tempStateDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-subagent-"));
|
||||
process.env.OPENCLAW_STATE_DIR = tempStateDir;
|
||||
const registryPath = path.join(tempStateDir, "subagents", "runs.json");
|
||||
@@ -187,6 +191,8 @@ describe("subagent registry persistence", () => {
|
||||
};
|
||||
|
||||
const fastPersistSubagentRunsToDisk = (runs: Map<string, SubagentRunRecord>) => {
|
||||
// Most tests assert restore semantics, not async writer behavior, so this
|
||||
// synchronous writer keeps registry state immediately observable.
|
||||
const registryPath = tempStateDir
|
||||
? path.join(tempStateDir, "subagents", "runs.json")
|
||||
: resolveSubagentRegistryPath();
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// Subagent registry steer-restart tests cover replacing child runs after steer
|
||||
// commands while preserving lifecycle hooks and completion delivery.
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { ContextEngine } from "../context-engine/types.js";
|
||||
|
||||
@@ -195,6 +197,8 @@ describe("subagent registry steer restarts", () => {
|
||||
};
|
||||
|
||||
const createDeferredAnnounceResolver = (): ((value: boolean) => void) => {
|
||||
// Deferred announce lets tests observe registry state while delivery is
|
||||
// still in flight, then release the promise deterministically.
|
||||
let resolveAnnounce: ((value: boolean) => void) | undefined;
|
||||
announceSpy.mockImplementationOnce(
|
||||
() =>
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// Subagent registry SQLite store tests cover whole-snapshot persistence and
|
||||
// one-time import from the legacy JSON registry file.
|
||||
import fs from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
@@ -107,6 +109,8 @@ describe("subagent registry sqlite store", () => {
|
||||
});
|
||||
|
||||
it("imports the legacy json registry when sqlite has no runs", async () => {
|
||||
// Import deletes the JSON source after the first successful migration so
|
||||
// later loads treat SQLite as canonical state.
|
||||
const legacyRun = createRun({
|
||||
runId: "legacy-run",
|
||||
childSessionKey: "agent:main:subagent:legacy",
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// Subagent registry test helpers expose the in-memory run map for small unit
|
||||
// tests that do not need persistence, lifecycle hooks, or gateway mocks.
|
||||
import { subagentRuns } from "./subagent-registry-memory.js";
|
||||
import type { SubagentRunRecord } from "./subagent-registry.types.js";
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// Subagent run liveness tests cover stale-unended detection and child-link
|
||||
// retention windows for registry list/read paths.
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
isLiveUnendedSubagentRun,
|
||||
@@ -54,6 +56,8 @@ describe("subagent run liveness", () => {
|
||||
});
|
||||
|
||||
it("ignores non-real fixture timestamps as unknown instead of stale", () => {
|
||||
// Small fixture timestamps appear in tests and old synthetic records; they
|
||||
// should not be interpreted as Unix epoch production runs.
|
||||
const entry = {
|
||||
createdAt: 100,
|
||||
};
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// Subagent spawn context tests cover isolated, forked, lightweight, and
|
||||
// thread-bound bootstrap context preparation for child sessions.
|
||||
import path from "node:path";
|
||||
import { MAX_TIMER_TIMEOUT_MS } from "@openclaw/normalization-core/number-coercion";
|
||||
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
@@ -42,6 +44,8 @@ describe("sessions_spawn context modes", () => {
|
||||
});
|
||||
|
||||
function usePersistentStoreMock(store: SessionStore) {
|
||||
// The spawn path mutates the session store in-place; this mock keeps that
|
||||
// contract visible without touching disk.
|
||||
updateSessionStoreMock.mockImplementation(async (_storePath: unknown, mutator: unknown) => {
|
||||
if (typeof mutator !== "function") {
|
||||
throw new Error("missing session store mutator");
|
||||
@@ -198,6 +202,8 @@ describe("sessions_spawn context modes", () => {
|
||||
});
|
||||
|
||||
it("falls back to isolated context when requested fork is too large", async () => {
|
||||
// Forking very large transcripts would create expensive child context, so
|
||||
// the accepted run records the downgrade in its note.
|
||||
const store: SessionStore = {
|
||||
main: {
|
||||
sessionId: "parent-session-id",
|
||||
|
||||
Reference in New Issue
Block a user