mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-27 21:07:01 -06:00
test(gateway): capture session-store forensics on adoption flake (#122718)
The concurrent keyed sessions.create adoption assertion flaked once on CI (run 31609081812) with the persisted row missing while all 16 creates succeeded. Owner-path analysis (fenced create path, direct SQL read, post-commit publication, async tails, sqlite target resolution) found no reachable mechanism and the failure never reproduced locally (11 runs). On mismatch the assertion now reports the case dir's sqlite files, the resolved target path, and raw session_nodes rows so the next occurrence identifies the writer/reader split instead of printing undefined.
This commit is contained in:
committed by
GitHub
parent
d82edfc4d2
commit
ab6d4655a2
@@ -1,6 +1,7 @@
|
||||
// Session creation tests protect dashboard-origin session records, transcript
|
||||
// creation, parent linkage, and model/provider overrides exposed by the gateway API.
|
||||
import { execFile } from "node:child_process";
|
||||
import { readdirSync } from "node:fs";
|
||||
import fs from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
@@ -215,6 +216,24 @@ test("sessions.create and sessions.delete preserve every concurrent session life
|
||||
}
|
||||
});
|
||||
|
||||
// The adoption assertion below flaked once on CI (run 31609081812) with the persisted
|
||||
// row missing while all 16 creates succeeded; exhaustive owner-path analysis found no
|
||||
// mechanism, and the failure never reproduced locally. On mismatch, capture which SQLite
|
||||
// files exist and what session_nodes actually holds so the next occurrence names the
|
||||
// writer/reader split instead of printing a bare undefined.
|
||||
function describeSessionStoreForensics(storePath: string): string {
|
||||
const storeDir = path.dirname(storePath);
|
||||
const files = readdirSync(storeDir).toSorted();
|
||||
const target = resolveSqliteTargetFromSessionStorePath(storePath, { agentId: "main" });
|
||||
const database = openOpenClawAgentDatabase({ agentId: "main", path: target.path });
|
||||
const rows = database.db
|
||||
.prepare(
|
||||
"SELECT session_key, length(entry_json) AS entry_bytes, updated_at FROM session_nodes ORDER BY session_key",
|
||||
)
|
||||
.all();
|
||||
return JSON.stringify({ storeDir, files, resolvedTargetPath: target.path, rows });
|
||||
}
|
||||
|
||||
test("concurrent sessions.create requests adopt one canonical keyed session", async () => {
|
||||
const { storePath } = await createSessionStoreDir();
|
||||
const key = "agent:main:dashboard:concurrent-keyed-session";
|
||||
@@ -232,9 +251,12 @@ test("concurrent sessions.create requests adopt one canonical keyed session", as
|
||||
expect(new Set(created.map((result) => result.payload?.key))).toEqual(new Set([key]));
|
||||
const sessionIds = new Set(created.map((result) => result.payload?.sessionId));
|
||||
expect(sessionIds.size).toBe(1);
|
||||
expect(loadSessionEntry({ sessionKey: key, storePath })?.sessionId).toBe(
|
||||
created[0]?.payload?.sessionId,
|
||||
);
|
||||
const persistedSessionId = loadSessionEntry({ sessionKey: key, storePath })?.sessionId;
|
||||
const canonicalSessionId = created[0]?.payload?.sessionId;
|
||||
expect(
|
||||
persistedSessionId,
|
||||
persistedSessionId === canonicalSessionId ? "" : describeSessionStoreForensics(storePath),
|
||||
).toBe(canonicalSessionId);
|
||||
});
|
||||
|
||||
test("keyed sessions remain recoverable across overlapping create and delete waves", async () => {
|
||||
|
||||
Reference in New Issue
Block a user