fix(macos): ignore launchd token in remote mode
This commit is contained in:
@@ -172,6 +172,10 @@ actor GatewayEndpointStore {
|
|||||||
return configToken
|
return configToken
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if isRemote {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
if let token = launchdSnapshot?.token?.trimmingCharacters(in: .whitespacesAndNewlines),
|
if let token = launchdSnapshot?.token?.trimmingCharacters(in: .whitespacesAndNewlines),
|
||||||
!token.isEmpty
|
!token.isEmpty
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import SwiftUI
|
|||||||
import Testing
|
import Testing
|
||||||
@testable import Clawdbot
|
@testable import Clawdbot
|
||||||
|
|
||||||
|
private typealias SnapshotAnyCodable = Clawdbot.AnyCodable
|
||||||
|
|
||||||
@Suite(.serialized)
|
@Suite(.serialized)
|
||||||
@MainActor
|
@MainActor
|
||||||
struct ChannelsSettingsSmokeTests {
|
struct ChannelsSettingsSmokeTests {
|
||||||
@@ -17,8 +19,11 @@ struct ChannelsSettingsSmokeTests {
|
|||||||
"signal": "Signal",
|
"signal": "Signal",
|
||||||
"imessage": "iMessage",
|
"imessage": "iMessage",
|
||||||
],
|
],
|
||||||
|
channelDetailLabels: nil,
|
||||||
|
channelSystemImages: nil,
|
||||||
|
channelMeta: nil,
|
||||||
channels: [
|
channels: [
|
||||||
"whatsapp": AnyCodable([
|
"whatsapp": SnapshotAnyCodable([
|
||||||
"configured": true,
|
"configured": true,
|
||||||
"linked": true,
|
"linked": true,
|
||||||
"authAgeMs": 86_400_000,
|
"authAgeMs": 86_400_000,
|
||||||
@@ -37,7 +42,7 @@ struct ChannelsSettingsSmokeTests {
|
|||||||
"lastEventAt": 1_700_000_060_000,
|
"lastEventAt": 1_700_000_060_000,
|
||||||
"lastError": "needs login",
|
"lastError": "needs login",
|
||||||
]),
|
]),
|
||||||
"telegram": AnyCodable([
|
"telegram": SnapshotAnyCodable([
|
||||||
"configured": true,
|
"configured": true,
|
||||||
"tokenSource": "env",
|
"tokenSource": "env",
|
||||||
"running": true,
|
"running": true,
|
||||||
@@ -52,7 +57,7 @@ struct ChannelsSettingsSmokeTests {
|
|||||||
],
|
],
|
||||||
"lastProbeAt": 1_700_000_050_000,
|
"lastProbeAt": 1_700_000_050_000,
|
||||||
]),
|
]),
|
||||||
"signal": AnyCodable([
|
"signal": SnapshotAnyCodable([
|
||||||
"configured": true,
|
"configured": true,
|
||||||
"baseUrl": "http://127.0.0.1:8080",
|
"baseUrl": "http://127.0.0.1:8080",
|
||||||
"running": true,
|
"running": true,
|
||||||
@@ -65,7 +70,7 @@ struct ChannelsSettingsSmokeTests {
|
|||||||
],
|
],
|
||||||
"lastProbeAt": 1_700_000_050_000,
|
"lastProbeAt": 1_700_000_050_000,
|
||||||
]),
|
]),
|
||||||
"imessage": AnyCodable([
|
"imessage": SnapshotAnyCodable([
|
||||||
"configured": false,
|
"configured": false,
|
||||||
"running": false,
|
"running": false,
|
||||||
"lastError": "not configured",
|
"lastError": "not configured",
|
||||||
@@ -100,15 +105,18 @@ struct ChannelsSettingsSmokeTests {
|
|||||||
"signal": "Signal",
|
"signal": "Signal",
|
||||||
"imessage": "iMessage",
|
"imessage": "iMessage",
|
||||||
],
|
],
|
||||||
|
channelDetailLabels: nil,
|
||||||
|
channelSystemImages: nil,
|
||||||
|
channelMeta: nil,
|
||||||
channels: [
|
channels: [
|
||||||
"whatsapp": AnyCodable([
|
"whatsapp": SnapshotAnyCodable([
|
||||||
"configured": false,
|
"configured": false,
|
||||||
"linked": false,
|
"linked": false,
|
||||||
"running": false,
|
"running": false,
|
||||||
"connected": false,
|
"connected": false,
|
||||||
"reconnectAttempts": 0,
|
"reconnectAttempts": 0,
|
||||||
]),
|
]),
|
||||||
"telegram": AnyCodable([
|
"telegram": SnapshotAnyCodable([
|
||||||
"configured": false,
|
"configured": false,
|
||||||
"running": false,
|
"running": false,
|
||||||
"lastError": "bot missing",
|
"lastError": "bot missing",
|
||||||
@@ -120,7 +128,7 @@ struct ChannelsSettingsSmokeTests {
|
|||||||
],
|
],
|
||||||
"lastProbeAt": 1_700_000_100_000,
|
"lastProbeAt": 1_700_000_100_000,
|
||||||
]),
|
]),
|
||||||
"signal": AnyCodable([
|
"signal": SnapshotAnyCodable([
|
||||||
"configured": false,
|
"configured": false,
|
||||||
"baseUrl": "http://127.0.0.1:8080",
|
"baseUrl": "http://127.0.0.1:8080",
|
||||||
"running": false,
|
"running": false,
|
||||||
@@ -133,7 +141,7 @@ struct ChannelsSettingsSmokeTests {
|
|||||||
],
|
],
|
||||||
"lastProbeAt": 1_700_000_200_000,
|
"lastProbeAt": 1_700_000_200_000,
|
||||||
]),
|
]),
|
||||||
"imessage": AnyCodable([
|
"imessage": SnapshotAnyCodable([
|
||||||
"configured": false,
|
"configured": false,
|
||||||
"running": false,
|
"running": false,
|
||||||
"lastError": "not configured",
|
"lastError": "not configured",
|
||||||
|
|||||||
@@ -11,16 +11,19 @@ struct CronJobEditorSmokeTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test func cronJobEditorBuildsBodyForNewJob() {
|
@Test func cronJobEditorBuildsBodyForNewJob() {
|
||||||
|
let channelsStore = ChannelsStore(isPreview: true)
|
||||||
let view = CronJobEditor(
|
let view = CronJobEditor(
|
||||||
job: nil,
|
job: nil,
|
||||||
isSaving: .constant(false),
|
isSaving: .constant(false),
|
||||||
error: .constant(nil),
|
error: .constant(nil),
|
||||||
|
channelsStore: channelsStore,
|
||||||
onCancel: {},
|
onCancel: {},
|
||||||
onSave: { _ in })
|
onSave: { _ in })
|
||||||
_ = view.body
|
_ = view.body
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test func cronJobEditorBuildsBodyForExistingJob() {
|
@Test func cronJobEditorBuildsBodyForExistingJob() {
|
||||||
|
let channelsStore = ChannelsStore(isPreview: true)
|
||||||
let job = CronJob(
|
let job = CronJob(
|
||||||
id: "job-1",
|
id: "job-1",
|
||||||
agentId: "ops",
|
agentId: "ops",
|
||||||
@@ -54,31 +57,36 @@ struct CronJobEditorSmokeTests {
|
|||||||
job: job,
|
job: job,
|
||||||
isSaving: .constant(false),
|
isSaving: .constant(false),
|
||||||
error: .constant(nil),
|
error: .constant(nil),
|
||||||
|
channelsStore: channelsStore,
|
||||||
onCancel: {},
|
onCancel: {},
|
||||||
onSave: { _ in })
|
onSave: { _ in })
|
||||||
_ = view.body
|
_ = view.body
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test func cronJobEditorExercisesBuilders() {
|
@Test func cronJobEditorExercisesBuilders() {
|
||||||
|
let channelsStore = ChannelsStore(isPreview: true)
|
||||||
var view = CronJobEditor(
|
var view = CronJobEditor(
|
||||||
job: nil,
|
job: nil,
|
||||||
isSaving: .constant(false),
|
isSaving: .constant(false),
|
||||||
error: .constant(nil),
|
error: .constant(nil),
|
||||||
|
channelsStore: channelsStore,
|
||||||
onCancel: {},
|
onCancel: {},
|
||||||
onSave: { _ in })
|
onSave: { _ in })
|
||||||
view.exerciseForTesting()
|
view.exerciseForTesting()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test func cronJobEditorIncludesDeleteAfterRunForAtSchedule() throws {
|
@Test func cronJobEditorIncludesDeleteAfterRunForAtSchedule() throws {
|
||||||
|
let channelsStore = ChannelsStore(isPreview: true)
|
||||||
let view = CronJobEditor(
|
let view = CronJobEditor(
|
||||||
job: nil,
|
job: nil,
|
||||||
isSaving: .constant(false),
|
isSaving: .constant(false),
|
||||||
error: .constant(nil),
|
error: .constant(nil),
|
||||||
|
channelsStore: channelsStore,
|
||||||
onCancel: {},
|
onCancel: {},
|
||||||
onSave: { _ in })
|
onSave: { _ in })
|
||||||
|
|
||||||
var root: [String: Any] = [:]
|
var root: [String: Any] = [:]
|
||||||
view.applyDeleteAfterRun(to: &root, scheduleKind: .at, deleteAfterRun: true)
|
view.applyDeleteAfterRun(to: &root, scheduleKind: CronJobEditor.ScheduleKind.at, deleteAfterRun: true)
|
||||||
let raw = root["deleteAfterRun"] as? Bool
|
let raw = root["deleteAfterRun"] as? Bool
|
||||||
#expect(raw == true)
|
#expect(raw == true)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import ClawdbotKit
|
||||||
import Foundation
|
import Foundation
|
||||||
import os
|
import os
|
||||||
import Testing
|
import Testing
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import ClawdbotKit
|
||||||
import Foundation
|
import Foundation
|
||||||
import os
|
import os
|
||||||
import Testing
|
import Testing
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import ClawdbotKit
|
||||||
import Foundation
|
import Foundation
|
||||||
import os
|
import os
|
||||||
import Testing
|
import Testing
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import ClawdbotKit
|
||||||
import Foundation
|
import Foundation
|
||||||
import os
|
import os
|
||||||
import Testing
|
import Testing
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import ClawdbotKit
|
||||||
import Foundation
|
import Foundation
|
||||||
import Testing
|
import Testing
|
||||||
@testable import Clawdbot
|
@testable import Clawdbot
|
||||||
|
|||||||
@@ -7,15 +7,17 @@ import Testing
|
|||||||
|
|
||||||
@Suite(.serialized)
|
@Suite(.serialized)
|
||||||
struct LowCoverageHelperTests {
|
struct LowCoverageHelperTests {
|
||||||
|
private typealias ProtoAnyCodable = ClawdbotProtocol.AnyCodable
|
||||||
|
|
||||||
@Test func anyCodableHelperAccessors() throws {
|
@Test func anyCodableHelperAccessors() throws {
|
||||||
let payload: [String: AnyCodable] = [
|
let payload: [String: ProtoAnyCodable] = [
|
||||||
"title": AnyCodable("Hello"),
|
"title": ProtoAnyCodable("Hello"),
|
||||||
"flag": AnyCodable(true),
|
"flag": ProtoAnyCodable(true),
|
||||||
"count": AnyCodable(3),
|
"count": ProtoAnyCodable(3),
|
||||||
"ratio": AnyCodable(1.25),
|
"ratio": ProtoAnyCodable(1.25),
|
||||||
"list": AnyCodable([AnyCodable("a"), AnyCodable(2)]),
|
"list": ProtoAnyCodable([ProtoAnyCodable("a"), ProtoAnyCodable(2)]),
|
||||||
]
|
]
|
||||||
let any = AnyCodable(payload)
|
let any = ProtoAnyCodable(payload)
|
||||||
let dict = try #require(any.dictionaryValue)
|
let dict = try #require(any.dictionaryValue)
|
||||||
#expect(dict["title"]?.stringValue == "Hello")
|
#expect(dict["title"]?.stringValue == "Hello")
|
||||||
#expect(dict["flag"]?.boolValue == true)
|
#expect(dict["flag"]?.boolValue == true)
|
||||||
@@ -76,31 +78,27 @@ struct LowCoverageHelperTests {
|
|||||||
#expect(result.stderr.contains("stderr-1999"))
|
#expect(result.stderr.contains("stderr-1999"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test func pairedNodesStorePersists() async throws {
|
@Test func nodeInfoCodableRoundTrip() throws {
|
||||||
let dir = FileManager().temporaryDirectory
|
let info = NodeInfo(
|
||||||
.appendingPathComponent("paired-\(UUID().uuidString)", isDirectory: true)
|
|
||||||
try FileManager().createDirectory(at: dir, withIntermediateDirectories: true)
|
|
||||||
let url = dir.appendingPathComponent("nodes.json")
|
|
||||||
let store = PairedNodesStore(fileURL: url)
|
|
||||||
await store.load()
|
|
||||||
#expect(await store.all().isEmpty)
|
|
||||||
|
|
||||||
let node = PairedNode(
|
|
||||||
nodeId: "node-1",
|
nodeId: "node-1",
|
||||||
displayName: "Node One",
|
displayName: "Node One",
|
||||||
platform: "macOS",
|
platform: "macOS",
|
||||||
version: "1.0",
|
version: "1.0",
|
||||||
|
coreVersion: "1.0-core",
|
||||||
|
uiVersion: "1.0-ui",
|
||||||
deviceFamily: "Mac",
|
deviceFamily: "Mac",
|
||||||
modelIdentifier: "MacBookPro",
|
modelIdentifier: "MacBookPro",
|
||||||
token: "token",
|
remoteIp: "192.168.1.2",
|
||||||
createdAtMs: 1,
|
caps: ["chat"],
|
||||||
lastSeenAtMs: nil)
|
commands: ["send"],
|
||||||
try await store.upsert(node)
|
permissions: ["send": true],
|
||||||
#expect(await store.find(nodeId: "node-1")?.displayName == "Node One")
|
paired: true,
|
||||||
|
connected: false)
|
||||||
try await store.touchSeen(nodeId: "node-1")
|
let data = try JSONEncoder().encode(info)
|
||||||
let updated = await store.find(nodeId: "node-1")
|
let decoded = try JSONDecoder().decode(NodeInfo.self, from: data)
|
||||||
#expect(updated?.lastSeenAtMs != nil)
|
#expect(decoded.nodeId == "node-1")
|
||||||
|
#expect(decoded.isPaired == true)
|
||||||
|
#expect(decoded.isConnected == false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test @MainActor func presenceReporterHelpers() {
|
@Test @MainActor func presenceReporterHelpers() {
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import Testing
|
|||||||
features: [:],
|
features: [:],
|
||||||
snapshot: snapshot,
|
snapshot: snapshot,
|
||||||
canvashosturl: nil,
|
canvashosturl: nil,
|
||||||
|
auth: nil,
|
||||||
policy: [:])
|
policy: [:])
|
||||||
|
|
||||||
let mapped = MacGatewayChatTransport.mapPushToTransportEvent(.snapshot(hello))
|
let mapped = MacGatewayChatTransport.mapPushToTransportEvent(.snapshot(hello))
|
||||||
|
|||||||
@@ -3,13 +3,15 @@ import SwiftUI
|
|||||||
import Testing
|
import Testing
|
||||||
@testable import Clawdbot
|
@testable import Clawdbot
|
||||||
|
|
||||||
|
private typealias ProtoAnyCodable = ClawdbotProtocol.AnyCodable
|
||||||
|
|
||||||
@Suite(.serialized)
|
@Suite(.serialized)
|
||||||
@MainActor
|
@MainActor
|
||||||
struct OnboardingWizardStepViewTests {
|
struct OnboardingWizardStepViewTests {
|
||||||
@Test func noteStepBuilds() {
|
@Test func noteStepBuilds() {
|
||||||
let step = WizardStep(
|
let step = WizardStep(
|
||||||
id: "step-1",
|
id: "step-1",
|
||||||
type: AnyCodable("note"),
|
type: ProtoAnyCodable("note"),
|
||||||
title: "Welcome",
|
title: "Welcome",
|
||||||
message: "Hello",
|
message: "Hello",
|
||||||
options: nil,
|
options: nil,
|
||||||
@@ -22,17 +24,17 @@ struct OnboardingWizardStepViewTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test func selectStepBuilds() {
|
@Test func selectStepBuilds() {
|
||||||
let options: [[String: AnyCodable]] = [
|
let options: [[String: ProtoAnyCodable]] = [
|
||||||
["value": AnyCodable("local"), "label": AnyCodable("Local"), "hint": AnyCodable("This Mac")],
|
["value": ProtoAnyCodable("local"), "label": ProtoAnyCodable("Local"), "hint": ProtoAnyCodable("This Mac")],
|
||||||
["value": AnyCodable("remote"), "label": AnyCodable("Remote")],
|
["value": ProtoAnyCodable("remote"), "label": ProtoAnyCodable("Remote")],
|
||||||
]
|
]
|
||||||
let step = WizardStep(
|
let step = WizardStep(
|
||||||
id: "step-2",
|
id: "step-2",
|
||||||
type: AnyCodable("select"),
|
type: ProtoAnyCodable("select"),
|
||||||
title: "Mode",
|
title: "Mode",
|
||||||
message: "Choose a mode",
|
message: "Choose a mode",
|
||||||
options: options,
|
options: options,
|
||||||
initialvalue: AnyCodable("local"),
|
initialvalue: ProtoAnyCodable("local"),
|
||||||
placeholder: nil,
|
placeholder: nil,
|
||||||
sensitive: nil,
|
sensitive: nil,
|
||||||
executor: nil)
|
executor: nil)
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ extension URLSessionWebSocketTask: WebSocketTasking {}
|
|||||||
|
|
||||||
public struct WebSocketTaskBox: @unchecked Sendable {
|
public struct WebSocketTaskBox: @unchecked Sendable {
|
||||||
public let task: any WebSocketTasking
|
public let task: any WebSocketTasking
|
||||||
|
public init(task: any WebSocketTasking) {
|
||||||
|
self.task = task
|
||||||
|
}
|
||||||
|
|
||||||
public var state: URLSessionTask.State { self.task.state }
|
public var state: URLSessionTask.State { self.task.state }
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user