mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-21 10:16:44 +00:00
* refactor(apple): unify offline client databases * refactor(apple): remove dead cache APIs * fix(apple): satisfy native storage gates * fix(apple): sync generated localization catalog * Revert "fix(apple): sync generated localization catalog" This reverts commit d0f5e7b74932e98ccc5f1984840e8f9d545edc2d. * fix(i18n): keep source validation pre-merge * test(macos): isolate flaky suite state * test(macos): isolate log locator on main actor
179 lines
7.2 KiB
Swift
179 lines
7.2 KiB
Swift
import Foundation
|
|
import Testing
|
|
@testable import OpenClaw
|
|
|
|
struct ChatTranscriptCacheIdentityTests {
|
|
private static let defaultStateDir = URL(fileURLWithPath: "/Users/tester/.openclaw", isDirectory: true)
|
|
|
|
@Test func `unconfigured mode has no cache identity`() {
|
|
let id = MacChatTranscriptCache.gatewayID(
|
|
mode: .unconfigured,
|
|
localStateDir: Self.defaultStateDir,
|
|
remoteTransport: .ssh,
|
|
directURL: nil,
|
|
sshTarget: "user@host",
|
|
sshRemotePort: 18789)
|
|
#expect(id == nil)
|
|
}
|
|
|
|
@Test @MainActor func `windows share one outbox owner per gateway`() {
|
|
let databaseDirectoryURL = FileManager.default.temporaryDirectory
|
|
.appendingPathComponent("openclaw-cache-owner-\(UUID().uuidString)", isDirectory: true)
|
|
defer { try? FileManager.default.removeItem(at: databaseDirectoryURL) }
|
|
let gatewayID = "gw-shared-\(UUID().uuidString)"
|
|
let first = MacChatTranscriptCache.store(
|
|
databaseDirectoryURL: databaseDirectoryURL,
|
|
gatewayID: gatewayID)
|
|
let second = MacChatTranscriptCache.store(
|
|
databaseDirectoryURL: databaseDirectoryURL,
|
|
gatewayID: gatewayID)
|
|
|
|
#expect(first === second)
|
|
}
|
|
|
|
@Test func `local mode keys on state dir so profiles never collide`() {
|
|
let defaultProfile = MacChatTranscriptCache.gatewayID(
|
|
mode: .local,
|
|
localStateDir: Self.defaultStateDir,
|
|
remoteTransport: .ssh,
|
|
directURL: nil,
|
|
sshTarget: "",
|
|
sshRemotePort: 18789)
|
|
let devProfile = MacChatTranscriptCache.gatewayID(
|
|
mode: .local,
|
|
localStateDir: URL(fileURLWithPath: "/Users/tester/.openclaw-dev", isDirectory: true),
|
|
remoteTransport: .ssh,
|
|
directURL: nil,
|
|
sshTarget: "",
|
|
sshRemotePort: 18789)
|
|
#expect(defaultProfile == "local:/Users/tester/.openclaw")
|
|
#expect(devProfile == "local:/Users/tester/.openclaw-dev")
|
|
#expect(defaultProfile != devProfile)
|
|
}
|
|
|
|
@Test func `local state dir aliases resolve to one identity`() throws {
|
|
// macOS tmp lives behind a /var -> /private/var symlink; both spellings
|
|
// of the same state dir must map to a single cache scope.
|
|
let canonical = FileManager.default.temporaryDirectory
|
|
.appendingPathComponent("openclaw-cache-identity-\(UUID().uuidString)", isDirectory: true)
|
|
try FileManager.default.createDirectory(at: canonical, withIntermediateDirectories: true)
|
|
defer { try? FileManager.default.removeItem(at: canonical) }
|
|
let resolved = canonical.resolvingSymlinksInPath()
|
|
let viaSymlink = MacChatTranscriptCache.gatewayID(
|
|
mode: .local,
|
|
localStateDir: canonical,
|
|
remoteTransport: .ssh,
|
|
directURL: nil,
|
|
sshTarget: "",
|
|
sshRemotePort: 18789)
|
|
let viaResolved = MacChatTranscriptCache.gatewayID(
|
|
mode: .local,
|
|
localStateDir: resolved,
|
|
remoteTransport: .ssh,
|
|
directURL: nil,
|
|
sshTarget: "",
|
|
sshRemotePort: 18789)
|
|
#expect(viaSymlink == viaResolved)
|
|
}
|
|
|
|
@Test func `remote direct keys on the full canonical url`() {
|
|
let explicitPort = MacChatTranscriptCache.gatewayID(
|
|
mode: .remote,
|
|
localStateDir: Self.defaultStateDir,
|
|
remoteTransport: .direct,
|
|
directURL: URL(string: "ws://Gateway.Example.com:9001"),
|
|
sshTarget: "",
|
|
sshRemotePort: 18789)
|
|
#expect(explicitPort == "remote:ws://gateway.example.com:9001")
|
|
|
|
let defaultWSSPort = MacChatTranscriptCache.gatewayID(
|
|
mode: .remote,
|
|
localStateDir: Self.defaultStateDir,
|
|
remoteTransport: .direct,
|
|
directURL: URL(string: "wss://gw.example.com"),
|
|
sshTarget: "",
|
|
sshRemotePort: 18789)
|
|
#expect(defaultWSSPort == "remote:wss://gw.example.com:443")
|
|
|
|
// One origin can route to several gateways by path; each path is its
|
|
// own cache scope.
|
|
let teamA = MacChatTranscriptCache.gatewayID(
|
|
mode: .remote,
|
|
localStateDir: Self.defaultStateDir,
|
|
remoteTransport: .direct,
|
|
directURL: URL(string: "wss://gw.example.com/team-a"),
|
|
sshTarget: "",
|
|
sshRemotePort: 18789)
|
|
let teamB = MacChatTranscriptCache.gatewayID(
|
|
mode: .remote,
|
|
localStateDir: Self.defaultStateDir,
|
|
remoteTransport: .direct,
|
|
directURL: URL(string: "wss://gw.example.com/team-b"),
|
|
sshTarget: "",
|
|
sshRemotePort: 18789)
|
|
#expect(teamA == "remote:wss://gw.example.com:443/team-a")
|
|
#expect(teamB == "remote:wss://gw.example.com:443/team-b")
|
|
#expect(teamA != teamB)
|
|
|
|
// Percent-encoded path spelling is part of the request URL and must
|
|
// not collapse into the decoded form's scope.
|
|
let encodedPath = MacChatTranscriptCache.gatewayID(
|
|
mode: .remote,
|
|
localStateDir: Self.defaultStateDir,
|
|
remoteTransport: .direct,
|
|
directURL: URL(string: "wss://gw.example.com/team%2Fa"),
|
|
sshTarget: "",
|
|
sshRemotePort: 18789)
|
|
let decodedPath = MacChatTranscriptCache.gatewayID(
|
|
mode: .remote,
|
|
localStateDir: Self.defaultStateDir,
|
|
remoteTransport: .direct,
|
|
directURL: URL(string: "wss://gw.example.com/team/a"),
|
|
sshTarget: "",
|
|
sshRemotePort: 18789)
|
|
#expect(encodedPath == "remote:wss://gw.example.com:443/team%2Fa")
|
|
#expect(encodedPath != decodedPath)
|
|
|
|
let missingURL = MacChatTranscriptCache.gatewayID(
|
|
mode: .remote,
|
|
localStateDir: Self.defaultStateDir,
|
|
remoteTransport: .direct,
|
|
directURL: nil,
|
|
sshTarget: "",
|
|
sshRemotePort: 18789)
|
|
#expect(missingURL == nil)
|
|
}
|
|
|
|
@Test func `remote ssh keys on the ssh target and remote gateway port`() {
|
|
let id = MacChatTranscriptCache.gatewayID(
|
|
mode: .remote,
|
|
localStateDir: Self.defaultStateDir,
|
|
remoteTransport: .ssh,
|
|
directURL: nil,
|
|
sshTarget: " user@studio.local ",
|
|
sshRemotePort: 18789)
|
|
#expect(id == "ssh:user@studio.local:18789")
|
|
|
|
// One SSH target can front several gateways on different remote ports;
|
|
// each must get its own cache scope.
|
|
let otherGateway = MacChatTranscriptCache.gatewayID(
|
|
mode: .remote,
|
|
localStateDir: Self.defaultStateDir,
|
|
remoteTransport: .ssh,
|
|
directURL: nil,
|
|
sshTarget: "user@studio.local",
|
|
sshRemotePort: 19001)
|
|
#expect(otherGateway == "ssh:user@studio.local:19001")
|
|
#expect(otherGateway != id)
|
|
|
|
let missingTarget = MacChatTranscriptCache.gatewayID(
|
|
mode: .remote,
|
|
localStateDir: Self.defaultStateDir,
|
|
remoteTransport: .ssh,
|
|
directURL: nil,
|
|
sshTarget: " ",
|
|
sshRemotePort: 18789)
|
|
#expect(missingTarget == nil)
|
|
}
|
|
}
|