Files
openclaw/src/state/sqlite-query-plan.test.ts
Peter Lee b9ae0a76fa test: prefer shared temp dir helpers in config, gateway, cron, crestodian, and state tests (#96711)
* fix: add temp dir cleanup to 14 P0 test files (Group A)

* fix: restore os import and fix fs.rmSync call in temp dir cleanup

* fix: use shared temp dir helpers in config, gateway, cron, crestodian, and state tests

* fix(test): rename underscore-prefixed temp dir vars and remove unused imports

* fix(test): remove unused path import in crestodian audit test

* fix(test): reorder expected plans to match buildVitestRunPlans output after rebase
2026-07-01 01:24:21 -07:00

198 lines
5.5 KiB
TypeScript

// SQLite query-plan tests pin hot OpenClaw state indexes used by perf proof.
import type { DatabaseSync } from "node:sqlite";
import { afterAll, afterEach, describe, expect, it } from "vitest";
import { cleanupTempDirs, makeTempDir } from "../../test/helpers/temp-dir.js";
import {
closeOpenClawAgentDatabasesForTest,
openOpenClawAgentDatabase,
} from "./openclaw-agent-db.js";
import {
closeOpenClawStateDatabaseForTest,
openOpenClawStateDatabase,
} from "./openclaw-state-db.js";
const planTempDirs: string[] = [];
function createTempStateDir(): string {
return makeTempDir(planTempDirs, "openclaw-sqlite-plan-");
}
function explainQueryPlan(
db: DatabaseSync,
sql: string,
params: readonly (number | string | null)[] = [],
): string {
const rows = db.prepare(`EXPLAIN QUERY PLAN ${sql}`).all(...params) as Array<{
detail?: unknown;
}>;
return rows
.map((row) => (typeof row.detail === "string" ? row.detail : JSON.stringify(row.detail ?? "")))
.join("\n");
}
function expectPlanUsesIndex(params: {
db: DatabaseSync;
indexName: string;
params?: readonly (number | string | null)[];
sql: string;
}): void {
expect(explainQueryPlan(params.db, params.sql, params.params)).toContain(params.indexName);
}
function expectPlanIncludes(params: {
db: DatabaseSync;
expected: string;
params?: readonly (number | string | null)[];
sql: string;
}): void {
expect(explainQueryPlan(params.db, params.sql, params.params)).toContain(params.expected);
}
afterAll(() => {
cleanupTempDirs(planTempDirs);
});
afterEach(() => {
closeOpenClawAgentDatabasesForTest();
closeOpenClawStateDatabaseForTest();
});
describe("sqlite hot query plans", () => {
it("uses shared state indexes for list and queue queries", () => {
const stateDir = createTempStateDir();
const database = openOpenClawStateDatabase({
env: { OPENCLAW_STATE_DIR: stateDir },
});
expectPlanUsesIndex({
db: database.db,
indexName: "idx_cron_jobs_store_order",
params: ["/state/cron/jobs.json"],
sql: `
SELECT job_id, name, updated_at
FROM cron_jobs
WHERE store_key = ?
ORDER BY sort_order ASC, updated_at ASC, job_id
LIMIT 25
`,
});
expectPlanUsesIndex({
db: database.db,
indexName: "idx_cron_jobs_enabled_next_run",
params: ["/state/cron/jobs.json"],
sql: `
SELECT job_id, next_run_at_ms
FROM cron_jobs
WHERE store_key = ? AND enabled = 1 AND next_run_at_ms IS NOT NULL
ORDER BY next_run_at_ms ASC, job_id
LIMIT 25
`,
});
expectPlanUsesIndex({
db: database.db,
indexName: "idx_cron_run_logs_store_ts",
params: ["/state/cron/jobs.json"],
sql: `
SELECT job_id, seq, ts
FROM cron_run_logs
WHERE store_key = ?
ORDER BY ts DESC, seq DESC
LIMIT 50
`,
});
expectPlanUsesIndex({
db: database.db,
indexName: "idx_cron_run_logs_job_status",
params: ["/state/cron/jobs.json", "job-1", "completed"],
sql: `
SELECT seq, ts, status
FROM cron_run_logs
WHERE store_key = ? AND job_id = ? AND status = ?
ORDER BY ts DESC, seq DESC
LIMIT 50
`,
});
expectPlanUsesIndex({
db: database.db,
indexName: "idx_delivery_queue_pending",
params: ["outbound", "pending"],
sql: `
SELECT id, entry_json
FROM delivery_queue_entries
WHERE queue_name = ? AND status = ?
ORDER BY enqueued_at ASC, id
LIMIT 50
`,
});
expectPlanUsesIndex({
db: database.db,
indexName: "idx_delivery_queue_session",
params: ["outbound", "pending", "agent:main:main"],
sql: `
SELECT id, entry_json
FROM delivery_queue_entries
WHERE queue_name = ? AND status = ? AND session_key = ?
ORDER BY enqueued_at ASC, id
LIMIT 50
`,
});
expectPlanUsesIndex({
db: database.db,
indexName: "idx_plugin_state_listing",
params: ["telegram", "kv"],
sql: `
SELECT entry_key, value_json
FROM plugin_state_entries
WHERE plugin_id = ? AND namespace = ?
ORDER BY created_at ASC, entry_key
LIMIT 50
`,
});
expectPlanUsesIndex({
db: database.db,
indexName: "idx_channel_ingress_pending",
params: ["ingress", "pending"],
sql: `
SELECT event_id, payload_json
FROM channel_ingress_events
WHERE queue_name = ? AND status = ?
ORDER BY received_at ASC, event_id
LIMIT 50
`,
});
});
it("uses per-agent cache indexes for session metadata and expiry scans", () => {
const stateDir = createTempStateDir();
const database = openOpenClawAgentDatabase({
agentId: "worker-1",
env: { OPENCLAW_STATE_DIR: stateDir },
});
expectPlanIncludes({
db: database.db,
expected: "sqlite_autoindex_cache_entries_1",
params: ["session_entries"],
sql: `
SELECT key, value_json
FROM cache_entries
WHERE scope = ?
ORDER BY key ASC
LIMIT 50
`,
});
expectPlanUsesIndex({
db: database.db,
indexName: "idx_agent_cache_expiry",
params: ["session_entries"],
sql: `
SELECT key, expires_at
FROM cache_entries
WHERE scope = ? AND expires_at IS NOT NULL
ORDER BY expires_at ASC, key
LIMIT 50
`,
});
});
});