mirror of
https://github.com/farcasclaudiu/openclaw.git
synced 2026-06-29 15:01:48 +03:00
perf(test): speed up memory suites
This commit is contained in:
@@ -89,7 +89,7 @@ describe("memory index", () => {
|
|||||||
throw new Error("manager missing");
|
throw new Error("manager missing");
|
||||||
}
|
}
|
||||||
manager = result.manager;
|
manager = result.manager;
|
||||||
await result.manager.sync({ force: true });
|
await result.manager.sync({ reason: "test" });
|
||||||
const results = await result.manager.search("alpha");
|
const results = await result.manager.search("alpha");
|
||||||
expect(results.length).toBeGreaterThan(0);
|
expect(results.length).toBeGreaterThan(0);
|
||||||
expect(results[0]?.path).toContain("memory/2026-01-12.md");
|
expect(results[0]?.path).toContain("memory/2026-01-12.md");
|
||||||
@@ -141,7 +141,7 @@ describe("memory index", () => {
|
|||||||
if (!first.manager) {
|
if (!first.manager) {
|
||||||
throw new Error("manager missing");
|
throw new Error("manager missing");
|
||||||
}
|
}
|
||||||
await first.manager.sync({ force: true });
|
await first.manager.sync({ reason: "test" });
|
||||||
const callsAfterFirstSync = embedBatchCalls;
|
const callsAfterFirstSync = embedBatchCalls;
|
||||||
await first.manager.close();
|
await first.manager.close();
|
||||||
|
|
||||||
@@ -234,7 +234,7 @@ describe("memory index", () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await manager.sync({ force: true });
|
await manager.sync({ reason: "test" });
|
||||||
const results = await manager.search("zebra");
|
const results = await manager.search("zebra");
|
||||||
expect(results.length).toBeGreaterThan(0);
|
expect(results.length).toBeGreaterThan(0);
|
||||||
expect(results[0]?.path).toContain("memory/2026-01-12.md");
|
expect(results[0]?.path).toContain("memory/2026-01-12.md");
|
||||||
|
|||||||
@@ -172,7 +172,6 @@ describe("memory indexing with OpenAI batches", () => {
|
|||||||
manager = result.manager;
|
manager = result.manager;
|
||||||
const labels: string[] = [];
|
const labels: string[] = [];
|
||||||
await manager.sync({
|
await manager.sync({
|
||||||
force: true,
|
|
||||||
progress: (update) => {
|
progress: (update) => {
|
||||||
if (update.label) {
|
if (update.label) {
|
||||||
labels.push(update.label);
|
labels.push(update.label);
|
||||||
@@ -287,7 +286,7 @@ describe("memory indexing with OpenAI batches", () => {
|
|||||||
throw new Error("manager missing");
|
throw new Error("manager missing");
|
||||||
}
|
}
|
||||||
manager = result.manager;
|
manager = result.manager;
|
||||||
await manager.sync({ force: true });
|
await manager.sync({ reason: "test" });
|
||||||
|
|
||||||
const status = manager.status();
|
const status = manager.status();
|
||||||
expect(status.chunks).toBeGreaterThan(0);
|
expect(status.chunks).toBeGreaterThan(0);
|
||||||
@@ -300,7 +299,16 @@ describe("memory indexing with OpenAI batches", () => {
|
|||||||
it("tracks batch failures, resets on success, and disables after repeated failures", async () => {
|
it("tracks batch failures, resets on success, and disables after repeated failures", async () => {
|
||||||
const restoreTimeouts = useFastShortTimeouts();
|
const restoreTimeouts = useFastShortTimeouts();
|
||||||
const content = ["flaky", "batch"].join("\n\n");
|
const content = ["flaky", "batch"].join("\n\n");
|
||||||
await fs.writeFile(path.join(workspaceDir, "memory", "2026-01-09.md"), content);
|
const memoryFile = path.join(workspaceDir, "memory", "2026-01-09.md");
|
||||||
|
let mtimeMs = Date.now();
|
||||||
|
const touch = async () => {
|
||||||
|
mtimeMs += 1_000;
|
||||||
|
const date = new Date(mtimeMs);
|
||||||
|
await fs.utimes(memoryFile, date, date);
|
||||||
|
};
|
||||||
|
|
||||||
|
await fs.writeFile(memoryFile, content);
|
||||||
|
await touch();
|
||||||
|
|
||||||
let uploadedRequests: Array<{ custom_id?: string }> = [];
|
let uploadedRequests: Array<{ custom_id?: string }> = [];
|
||||||
let mode: "fail" | "ok" = "fail";
|
let mode: "fail" | "ok" = "fail";
|
||||||
@@ -395,20 +403,24 @@ describe("memory indexing with OpenAI batches", () => {
|
|||||||
manager = result.manager;
|
manager = result.manager;
|
||||||
|
|
||||||
// First failure: fallback to regular embeddings and increment failure count.
|
// First failure: fallback to regular embeddings and increment failure count.
|
||||||
await manager.sync({ force: true });
|
await manager.sync({ reason: "test" });
|
||||||
expect(embedBatch).toHaveBeenCalled();
|
expect(embedBatch).toHaveBeenCalled();
|
||||||
let status = manager.status();
|
let status = manager.status();
|
||||||
expect(status.batch?.enabled).toBe(true);
|
expect(status.batch?.enabled).toBe(true);
|
||||||
expect(status.batch?.failures).toBe(1);
|
expect(status.batch?.failures).toBe(1);
|
||||||
|
|
||||||
|
const markDirty = () => {
|
||||||
|
// `sync` only indexes when marked dirty (unless doing a full reindex).
|
||||||
|
(manager as unknown as { dirty: boolean }).dirty = true;
|
||||||
|
};
|
||||||
|
|
||||||
// Success should reset failure count.
|
// Success should reset failure count.
|
||||||
embedBatch.mockClear();
|
embedBatch.mockClear();
|
||||||
mode = "ok";
|
mode = "ok";
|
||||||
await fs.writeFile(
|
await fs.writeFile(memoryFile, ["flaky", "batch", "recovery"].join("\n\n"));
|
||||||
path.join(workspaceDir, "memory", "2026-01-09.md"),
|
await touch();
|
||||||
["flaky", "batch", "recovery"].join("\n\n"),
|
markDirty();
|
||||||
);
|
await manager.sync({ reason: "test" });
|
||||||
await manager.sync({ force: true });
|
|
||||||
status = manager.status();
|
status = manager.status();
|
||||||
expect(status.batch?.enabled).toBe(true);
|
expect(status.batch?.enabled).toBe(true);
|
||||||
expect(status.batch?.failures).toBe(0);
|
expect(status.batch?.failures).toBe(0);
|
||||||
@@ -416,20 +428,18 @@ describe("memory indexing with OpenAI batches", () => {
|
|||||||
|
|
||||||
// Two more failures after reset should disable remote batching.
|
// Two more failures after reset should disable remote batching.
|
||||||
mode = "fail";
|
mode = "fail";
|
||||||
await fs.writeFile(
|
await fs.writeFile(memoryFile, ["flaky", "batch", "fail-a"].join("\n\n"));
|
||||||
path.join(workspaceDir, "memory", "2026-01-09.md"),
|
await touch();
|
||||||
["flaky", "batch", "fail-a"].join("\n\n"),
|
markDirty();
|
||||||
);
|
await manager.sync({ reason: "test" });
|
||||||
await manager.sync({ force: true });
|
|
||||||
status = manager.status();
|
status = manager.status();
|
||||||
expect(status.batch?.enabled).toBe(true);
|
expect(status.batch?.enabled).toBe(true);
|
||||||
expect(status.batch?.failures).toBe(1);
|
expect(status.batch?.failures).toBe(1);
|
||||||
|
|
||||||
await fs.writeFile(
|
await fs.writeFile(memoryFile, ["flaky", "batch", "fail-b"].join("\n\n"));
|
||||||
path.join(workspaceDir, "memory", "2026-01-09.md"),
|
await touch();
|
||||||
["flaky", "batch", "fail-b"].join("\n\n"),
|
markDirty();
|
||||||
);
|
await manager.sync({ reason: "test" });
|
||||||
await manager.sync({ force: true });
|
|
||||||
status = manager.status();
|
status = manager.status();
|
||||||
expect(status.batch?.enabled).toBe(false);
|
expect(status.batch?.enabled).toBe(false);
|
||||||
expect(status.batch?.failures).toBeGreaterThanOrEqual(2);
|
expect(status.batch?.failures).toBeGreaterThanOrEqual(2);
|
||||||
@@ -437,11 +447,10 @@ describe("memory indexing with OpenAI batches", () => {
|
|||||||
// Once disabled, batch endpoints are skipped and fallback embeddings run directly.
|
// Once disabled, batch endpoints are skipped and fallback embeddings run directly.
|
||||||
const fetchCalls = fetchMock.mock.calls.length;
|
const fetchCalls = fetchMock.mock.calls.length;
|
||||||
embedBatch.mockClear();
|
embedBatch.mockClear();
|
||||||
await fs.writeFile(
|
await fs.writeFile(memoryFile, ["flaky", "batch", "fallback"].join("\n\n"));
|
||||||
path.join(workspaceDir, "memory", "2026-01-09.md"),
|
await touch();
|
||||||
["flaky", "batch", "fallback"].join("\n\n"),
|
markDirty();
|
||||||
);
|
await manager.sync({ reason: "test" });
|
||||||
await manager.sync({ force: true });
|
|
||||||
expect(fetchMock.mock.calls.length).toBe(fetchCalls);
|
expect(fetchMock.mock.calls.length).toBe(fetchCalls);
|
||||||
expect(embedBatch).toHaveBeenCalled();
|
expect(embedBatch).toHaveBeenCalled();
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -85,7 +85,6 @@ describe("memory embedding batches", () => {
|
|||||||
manager = result.manager;
|
manager = result.manager;
|
||||||
const updates: Array<{ completed: number; total: number; label?: string }> = [];
|
const updates: Array<{ completed: number; total: number; label?: string }> = [];
|
||||||
await manager.sync({
|
await manager.sync({
|
||||||
force: true,
|
|
||||||
progress: (update) => {
|
progress: (update) => {
|
||||||
updates.push(update);
|
updates.push(update);
|
||||||
},
|
},
|
||||||
@@ -130,7 +129,7 @@ describe("memory embedding batches", () => {
|
|||||||
throw new Error("manager missing");
|
throw new Error("manager missing");
|
||||||
}
|
}
|
||||||
manager = result.manager;
|
manager = result.manager;
|
||||||
await manager.sync({ force: true });
|
await manager.sync({ reason: "test" });
|
||||||
|
|
||||||
expect(embedBatch.mock.calls.length).toBe(1);
|
expect(embedBatch.mock.calls.length).toBe(1);
|
||||||
});
|
});
|
||||||
@@ -191,7 +190,7 @@ describe("memory embedding batches", () => {
|
|||||||
}
|
}
|
||||||
manager = result.manager;
|
manager = result.manager;
|
||||||
try {
|
try {
|
||||||
await manager.sync({ force: true });
|
await manager.sync({ reason: "test" });
|
||||||
} finally {
|
} finally {
|
||||||
setTimeoutSpy.mockRestore();
|
setTimeoutSpy.mockRestore();
|
||||||
}
|
}
|
||||||
@@ -224,7 +223,7 @@ describe("memory embedding batches", () => {
|
|||||||
throw new Error("manager missing");
|
throw new Error("manager missing");
|
||||||
}
|
}
|
||||||
manager = result.manager;
|
manager = result.manager;
|
||||||
await manager.sync({ force: true });
|
await manager.sync({ reason: "test" });
|
||||||
|
|
||||||
const inputs = embedBatch.mock.calls.flatMap((call) => call[0] ?? []);
|
const inputs = embedBatch.mock.calls.flatMap((call) => call[0] ?? []);
|
||||||
expect(inputs).not.toContain("");
|
expect(inputs).not.toContain("");
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ describe("memory embedding token limits", () => {
|
|||||||
throw new Error("manager missing");
|
throw new Error("manager missing");
|
||||||
}
|
}
|
||||||
manager = result.manager;
|
manager = result.manager;
|
||||||
await manager.sync({ force: true });
|
await manager.sync({ reason: "test" });
|
||||||
|
|
||||||
const inputs = embedBatch.mock.calls.flatMap((call) => call[0] ?? []);
|
const inputs = embedBatch.mock.calls.flatMap((call) => call[0] ?? []);
|
||||||
expect(inputs.length).toBeGreaterThan(1);
|
expect(inputs.length).toBeGreaterThan(1);
|
||||||
@@ -111,7 +111,7 @@ describe("memory embedding token limits", () => {
|
|||||||
throw new Error("manager missing");
|
throw new Error("manager missing");
|
||||||
}
|
}
|
||||||
manager = result.manager;
|
manager = result.manager;
|
||||||
await manager.sync({ force: true });
|
await manager.sync({ reason: "test" });
|
||||||
|
|
||||||
const batchSizes = embedBatch.mock.calls.map(
|
const batchSizes = embedBatch.mock.calls.map(
|
||||||
(call) => (call[0] as string[] | undefined)?.length ?? 0,
|
(call) => (call[0] as string[] | undefined)?.length ?? 0,
|
||||||
|
|||||||
@@ -1009,12 +1009,16 @@ describe("QmdMemoryManager", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
async function waitForCondition(check: () => boolean, timeoutMs: number): Promise<void> {
|
async function waitForCondition(check: () => boolean, timeoutMs: number): Promise<void> {
|
||||||
const deadline = Date.now() + timeoutMs;
|
// Tests only need to yield the event loop a few times; real-time sleeps slow the suite down.
|
||||||
while (Date.now() < deadline) {
|
const maxTicks = Math.max(10, Math.min(5000, timeoutMs * 5));
|
||||||
|
for (let tick = 0; tick < maxTicks; tick += 1) {
|
||||||
if (check()) {
|
if (check()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await new Promise<void>((resolve) => setImmediate(resolve));
|
await new Promise<void>((resolve) => setImmediate(resolve));
|
||||||
}
|
}
|
||||||
|
if (check()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
throw new Error("condition was not met in time");
|
throw new Error("condition was not met in time");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user