Files
clawdbot/apps/macos/Tests/ClawdisIPCTests/GatewayEndpointStoreTests.swift
2026-01-02 17:15:26 +01:00

157 lines
4.9 KiB
Swift

import Foundation
import Testing
@testable import Clawdis
@Suite struct GatewayEndpointStoreTests {
private final class ModeBox: @unchecked Sendable {
private let lock = NSLock()
private var value: AppState.ConnectionMode
init(_ initial: AppState.ConnectionMode) {
self.value = initial
}
func get() -> AppState.ConnectionMode {
self.lock.lock()
defer { self.lock.unlock() }
return self.value
}
func set(_ next: AppState.ConnectionMode) {
self.lock.lock()
defer { self.lock.unlock() }
self.value = next
}
}
@Test func localRefreshResolvesToLocalhostPort() async throws {
let mode = ModeBox(.local)
let store = GatewayEndpointStore(deps: .init(
mode: { mode.get() },
token: { "t" },
password: { nil },
localPort: { 1234 },
remotePortIfRunning: { nil },
ensureRemoteTunnel: { 18789 }))
await store.refresh()
let cfg = try await store.requireConfig()
#expect(cfg.url.absoluteString == "ws://127.0.0.1:1234")
#expect(cfg.token == "t")
}
@Test func remoteWithoutTunnelRecoversByEnsuringTunnel() async throws {
let mode = ModeBox(.remote)
let store = GatewayEndpointStore(deps: .init(
mode: { mode.get() },
token: { nil },
password: { nil },
localPort: { 18789 },
remotePortIfRunning: { nil },
ensureRemoteTunnel: { 18789 }))
let cfg = try await store.requireConfig()
#expect(cfg.url.absoluteString == "ws://127.0.0.1:18789")
#expect(cfg.token == nil)
}
@Test func ensureRemoteTunnelPublishesReadyState() async throws {
let mode = ModeBox(.remote)
let store = GatewayEndpointStore(deps: .init(
mode: { mode.get() },
token: { "tok" },
password: { "pw" },
localPort: { 1 },
remotePortIfRunning: { 5555 },
ensureRemoteTunnel: { 5555 }))
let stream = await store.subscribe(bufferingNewest: 10)
var iterator = stream.makeAsyncIterator()
_ = await iterator.next() // initial
_ = try await store.ensureRemoteControlTunnel()
let next = await iterator.next()
guard case let .ready(mode, url, token, password) = next else {
Issue.record("expected .ready after ensure, got \(String(describing: next))")
return
}
#expect(mode == .remote)
#expect(url.absoluteString == "ws://127.0.0.1:5555")
#expect(token == "tok")
#expect(password == "pw")
}
@Test func resolvesGatewayPasswordByMode() {
let root: [String: Any] = [
"gateway": [
"auth": ["password": " local "],
"remote": ["password": " remote "],
],
]
let env: [String: String] = [:]
#expect(GatewayEndpointStore._testResolveGatewayPassword(
isRemote: false,
root: root,
env: env) == "local")
#expect(GatewayEndpointStore._testResolveGatewayPassword(
isRemote: true,
root: root,
env: env) == "remote")
}
@Test func gatewayPasswordEnvOverridesConfig() {
let root: [String: Any] = [
"gateway": [
"auth": ["password": "local"],
"remote": ["password": "remote"],
],
]
let env = ["CLAWDIS_GATEWAY_PASSWORD": " env "]
#expect(GatewayEndpointStore._testResolveGatewayPassword(
isRemote: false,
root: root,
env: env) == "env")
#expect(GatewayEndpointStore._testResolveGatewayPassword(
isRemote: true,
root: root,
env: env) == "env")
}
@Test func gatewayPasswordIgnoresWhitespaceValues() {
let root: [String: Any] = [
"gateway": [
"auth": ["password": " "],
"remote": ["password": "\n\t"],
],
]
let env = ["CLAWDIS_GATEWAY_PASSWORD": " "]
#expect(GatewayEndpointStore._testResolveGatewayPassword(
isRemote: false,
root: root,
env: env) == nil)
#expect(GatewayEndpointStore._testResolveGatewayPassword(
isRemote: true,
root: root,
env: env) == nil)
}
@Test func unconfiguredModeRejectsConfig() async {
let mode = ModeBox(.unconfigured)
let store = GatewayEndpointStore(deps: .init(
mode: { mode.get() },
token: { nil },
password: { nil },
localPort: { 18789 },
remotePortIfRunning: { nil },
ensureRemoteTunnel: { 18789 }))
await #expect(throws: Error.self) {
_ = try await store.requireConfig()
}
}
}