


























@@ -73,7 +73,97 @@ describe("sqlite WAL maintenance", () => {
7373}
7474});
757576-it("refuses NFS-backed databases when SQLite keeps WAL active", () => {
76+it.each([
77+["SMB", 0x517b],
78+["CIFS", 0xff534d42],
79+["SMB2", 0xfe534d42],
80+])("uses rollback journaling for databases on Linux %s volumes", (_label, fsType) => {
81+const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-sqlite-network-"));
82+try {
83+const db = createMockDb();
84+vi.spyOn(fs, "statfsSync").mockReturnValue(statfsFixture(fsType));
85+86+configureSqliteWalMaintenance(db, {
87+checkpointIntervalMs: 0,
88+databasePath: path.join(tempDir, "openclaw.sqlite"),
89+});
90+91+expect(db["prepare"]).toHaveBeenCalledWith("PRAGMA journal_mode = DELETE;");
92+} finally {
93+fs.rmSync(tempDir, { recursive: true, force: true });
94+}
95+});
96+97+it.each([
98+String.raw`\\server\share\openclaw.sqlite`,
99+String.raw`\\?\UNC\server\share\openclaw.sqlite`,
100+"//server/share/openclaw.sqlite",
101+"//?/UNC/server/share/openclaw.sqlite",
102+])("uses rollback journaling for databases on Windows UNC paths: %s", (databasePath) => {
103+const db = createMockDb();
104+vi.spyOn(process, "platform", "get").mockReturnValue("win32");
105+106+configureSqliteWalMaintenance(db, {
107+checkpointIntervalMs: 0,
108+ databasePath,
109+});
110+111+expect(db["prepare"]).toHaveBeenCalledWith("PRAGMA journal_mode = DELETE;");
112+expect(db["exec"]).not.toHaveBeenCalled();
113+});
114+115+it("uses rollback journaling for mapped Windows network drives", () => {
116+const db = createMockDb();
117+const databasePath = String.raw`Z:\state\openclaw.sqlite`;
118+vi.spyOn(process, "platform", "get").mockReturnValue("win32");
119+const realpath = vi
120+.spyOn(fs.realpathSync, "native")
121+.mockReturnValue(String.raw`\\server\share\state\openclaw.sqlite`);
122+123+configureSqliteWalMaintenance(db, {
124+checkpointIntervalMs: 0,
125+ databasePath,
126+});
127+128+expect(realpath).toHaveBeenCalledWith(databasePath);
129+expect(db["prepare"]).toHaveBeenCalledWith("PRAGMA journal_mode = DELETE;");
130+expect(db["exec"]).not.toHaveBeenCalled();
131+});
132+133+it("does not treat namespaced Windows local drives as UNC paths", () => {
134+const db = createMockDb();
135+const databasePath = String.raw`\\?\C:\state\openclaw.sqlite`;
136+vi.spyOn(process, "platform", "get").mockReturnValue("win32");
137+const realpath = vi.spyOn(fs.realpathSync, "native").mockReturnValue(databasePath);
138+139+configureSqliteWalMaintenance(db, {
140+checkpointIntervalMs: 0,
141+ databasePath,
142+});
143+144+expect(realpath).toHaveBeenCalledWith(databasePath);
145+expect(db["prepare"]).not.toHaveBeenCalled();
146+expect(db["exec"]).toHaveBeenNthCalledWith(1, "PRAGMA journal_mode = WAL;");
147+});
148+149+it("uses rollback journaling when Windows cannot classify an opened drive path", () => {
150+const db = createMockDb();
151+const databasePath = String.raw`Z:\restricted\openclaw.sqlite`;
152+vi.spyOn(process, "platform", "get").mockReturnValue("win32");
153+vi.spyOn(fs.realpathSync, "native").mockImplementation(() => {
154+throw new Error("access denied");
155+});
156+157+configureSqliteWalMaintenance(db, {
158+checkpointIntervalMs: 0,
159+ databasePath,
160+});
161+162+expect(db["prepare"]).toHaveBeenCalledWith("PRAGMA journal_mode = DELETE;");
163+expect(db["exec"]).not.toHaveBeenCalled();
164+});
165+166+it("refuses network-backed databases when SQLite keeps WAL active", () => {
77167const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-sqlite-nfs-"));
78168try {
79169const db = createMockDb();
@@ -137,6 +227,29 @@ describe("sqlite WAL maintenance", () => {
137227}
138228});
139229230+it("uses macOS SMB mount filesystem names", () => {
231+const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-sqlite-smb-"));
232+try {
233+const db = createMockDb();
234+vi.spyOn(fs, "statfsSync").mockReturnValue(statfsFixture(0));
235+vi.spyOn(fs, "readFileSync").mockImplementation(() => {
236+throw new Error("no proc mountinfo");
237+});
238+vi.spyOn(childProcess, "execFileSync").mockReturnValue(
239+Buffer.from(`//server/share on ${tempDir} (smbfs, nodev, nosuid)\n`),
240+);
241+242+configureSqliteWalMaintenance(db, {
243+checkpointIntervalMs: 0,
244+databasePath: path.join(tempDir, "openclaw.sqlite"),
245+});
246+247+expect(db["prepare"]).toHaveBeenCalledWith("PRAGMA journal_mode = DELETE;");
248+} finally {
249+fs.rmSync(tempDir, { recursive: true, force: true });
250+}
251+});
252+140253it("parses Linux mount command filesystem names when proc mountinfo is unavailable", () => {
141254const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-sqlite-nfs-"));
142255try {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。