Files
openclaw/apps/shared/OpenClawKit/Tests/OpenClawNativeStateTests/OpenClawNativeStateSQLiteTests.swift
Peter Steinberger 4d27b5b67e refactor(macos): move PortGuardian state to SQLite (#110527)
* refactor: compose native SQLite bootstrap tables

* refactor: share native SQLite state bootstrap

* refactor(macos): move PortGuardian state to SQLite

* test: align PortGuardian future-schema fixture

* fix(macos): reserve PortGuardian ledger across tunnel spawn

* fix(ci): align PortGuardian migration gates

* fix(macos): tolerate vanished SQLite sidecars

* fix(macos): revalidate PortGuardian writes

* test(macos): use sqlite identity bootstrap
2026-07-18 18:15:17 +01:00

175 lines
6.7 KiB
Swift

import Foundation
import Testing
@testable import OpenClawNativeState
struct OpenClawNativeStateSQLiteTests {
@Test
func `version zero composes exact canonical tables`() throws {
try self.withDatabase { database in
try database.withImmediateTransaction {
try database.ensureCanonicalTable(.macosPortGuardianRecords)
try database.execute("""
INSERT INTO macos_port_guardian_records (pid, port, command, mode, timestamp)
VALUES (4242, 18789, '/usr/bin/ssh', 'remote', 42.5)
""")
try database.ensureCanonicalTable(.deviceIdentities)
}
#expect(try database.scalarInt64("PRAGMA user_version") == 0)
#expect(try database.scalarInt64(
"SELECT COUNT(*) FROM macos_port_guardian_records WHERE pid = 4242") == 1)
#expect(try database.scalarInt64(
"SELECT COUNT(*) FROM sqlite_schema WHERE name NOT LIKE 'sqlite_%'") == 4)
}
}
@Test
func `version zero rejects incomplete known sibling schema`() throws {
try self.withDatabase { database in
try database.execute("""
CREATE TABLE macos_port_guardian_records (
pid INTEGER NOT NULL PRIMARY KEY,
port INTEGER NOT NULL,
command TEXT NOT NULL,
mode TEXT NOT NULL,
timestamp REAL NOT NULL
) STRICT
""")
#expect(throws: OpenClawNativeStateError.self) {
try database.ensureCanonicalTable(.deviceIdentities)
}
}
}
@Test
func `versioned database never synthesizes a missing canonical table`() throws {
try self.withDatabase { database in
try database.execute("""
CREATE TABLE schema_meta (
meta_key TEXT NOT NULL PRIMARY KEY,
role TEXT NOT NULL,
schema_version INTEGER NOT NULL
) STRICT;
INSERT INTO schema_meta (meta_key, role, schema_version)
VALUES ('primary', 'global', 3);
PRAGMA user_version = 3;
""")
#expect(throws: OpenClawNativeStateError.self) {
try database.ensureCanonicalTable(.deviceIdentities)
}
#expect(try database.schemaObjectExists(type: "table", name: "device_identities") == false)
}
}
@Test
func `immediate transaction rolls back all writes`() throws {
try self.withDatabase { database in
try database.withImmediateTransaction {
try database.ensureCanonicalTable(.macosPortGuardianRecords)
}
#expect(throws: TestError.self) {
try database.withImmediateTransaction {
try database.execute("""
INSERT INTO macos_port_guardian_records (pid, port, command, mode, timestamp)
VALUES (4242, 18789, '/usr/bin/ssh', 'remote', 42.5)
""")
throw TestError.expected
}
}
#expect(try database.scalarInt64("SELECT COUNT(*) FROM macos_port_guardian_records") == 0)
}
}
@Test
func `concurrent version zero stores compose different tables`() async throws {
let directory = FileManager.default.temporaryDirectory
.appendingPathComponent(UUID().uuidString, isDirectory: true)
defer { try? FileManager.default.removeItem(at: directory) }
let databaseURL = directory.appendingPathComponent("openclaw.sqlite", isDirectory: false)
try await withThrowingTaskGroup(of: Void.self) { group in
for table in [
OpenClawNativeStateCanonicalTable.deviceIdentities,
.macosPortGuardianRecords,
] {
group.addTask {
let database = try OpenClawNativeStateSQLite(databaseURL: databaseURL)
try database.withImmediateTransaction {
try database.ensureCanonicalTable(table)
}
}
}
try await group.waitForAll()
}
let database = try OpenClawNativeStateSQLite(databaseURL: databaseURL)
#expect(try database.scalarInt64(
"SELECT COUNT(*) FROM sqlite_schema WHERE name NOT LIKE 'sqlite_%'") == 4)
}
@Test
func `vanished transient sidecar does not fail committed write cleanup`() throws {
let databaseURL = URL(fileURLWithPath: "/tmp/openclaw-native-state.sqlite")
var attemptedPaths: [String] = []
try OpenClawNativeStateSQLite.secureDatabaseFiles(
databaseURL,
fileExists: { _ in true },
setAttributes: { _, path in
attemptedPaths.append(path)
if path.hasSuffix("-wal") {
throw NSError(domain: NSCocoaErrorDomain, code: NSFileNoSuchFileError)
}
})
#expect(attemptedPaths == [
databaseURL.path,
databaseURL.path + "-wal",
databaseURL.path + "-shm",
databaseURL.path + "-journal",
])
}
@Test
func `missing database or nonmissing sidecar failure remains fatal`() {
let databaseURL = URL(fileURLWithPath: "/tmp/openclaw-native-state.sqlite")
let missing = NSError(domain: NSPOSIXErrorDomain, code: Int(POSIXErrorCode.ENOENT.rawValue))
let denied = NSError(domain: NSPOSIXErrorDomain, code: Int(POSIXErrorCode.EACCES.rawValue))
#expect(throws: NSError.self) {
try OpenClawNativeStateSQLite.secureDatabaseFiles(
databaseURL,
fileExists: { _ in true },
setAttributes: { _, path in
if path == databaseURL.path { throw missing }
})
}
#expect(throws: NSError.self) {
try OpenClawNativeStateSQLite.secureDatabaseFiles(
databaseURL,
fileExists: { _ in true },
setAttributes: { _, path in
if path.hasSuffix("-wal") { throw denied }
})
}
}
private enum TestError: Error {
case expected
}
private func withDatabase(
body: (OpenClawNativeStateSQLite) throws -> Void) throws
{
let directory = FileManager.default.temporaryDirectory
.appendingPathComponent(UUID().uuidString, isDirectory: true)
defer { try? FileManager.default.removeItem(at: directory) }
let database = try OpenClawNativeStateSQLite(
databaseURL: directory.appendingPathComponent("openclaw.sqlite", isDirectory: false))
try body(database)
}
}