Add notification surface regression test
This commit is contained in:
parent
0010e10bf5
commit
9841cb50bf
1 changed files with 135 additions and 3 deletions
|
|
@ -148,6 +148,70 @@ final class TerminalControllerSocketSecurityTests: XCTestCase {
|
|||
XCTAssertEqual(payload["has_ssh_options"] as? Bool, true)
|
||||
}
|
||||
|
||||
func testNotificationCreateUsesExplicitSurfaceIDWhenProvided() async throws {
|
||||
let socketPath = makeSocketPath("notify-surface")
|
||||
let manager = TabManager()
|
||||
let store = TerminalNotificationStore.shared
|
||||
let appDelegate = AppDelegate.shared ?? AppDelegate()
|
||||
|
||||
let originalTabManager = appDelegate.tabManager
|
||||
let originalNotificationStore = appDelegate.notificationStore
|
||||
|
||||
store.replaceNotificationsForTesting([])
|
||||
store.configureNotificationDeliveryHandlerForTesting { _, _ in }
|
||||
appDelegate.tabManager = manager
|
||||
appDelegate.notificationStore = store
|
||||
|
||||
defer {
|
||||
store.replaceNotificationsForTesting([])
|
||||
store.resetNotificationDeliveryHandlerForTesting()
|
||||
appDelegate.tabManager = originalTabManager
|
||||
appDelegate.notificationStore = originalNotificationStore
|
||||
}
|
||||
|
||||
guard let workspace = manager.selectedWorkspace,
|
||||
let focusedPanelId = workspace.focusedPanelId else {
|
||||
XCTFail("Expected selected workspace with a focused panel")
|
||||
return
|
||||
}
|
||||
guard let targetPanel = workspace.newTerminalSplit(from: focusedPanelId, orientation: .horizontal) else {
|
||||
XCTFail("Expected split panel to be created")
|
||||
return
|
||||
}
|
||||
workspace.focusPanel(focusedPanelId)
|
||||
|
||||
TerminalController.shared.start(
|
||||
tabManager: manager,
|
||||
socketPath: socketPath,
|
||||
accessMode: .allowAll
|
||||
)
|
||||
try waitForSocket(at: socketPath)
|
||||
|
||||
let response = try await withCheckedThrowingContinuation { continuation in
|
||||
DispatchQueue.global(qos: .userInitiated).async {
|
||||
do {
|
||||
let response = try self.sendV2Request(
|
||||
method: "notification.create",
|
||||
params: [
|
||||
"workspace_id": workspace.id.uuidString,
|
||||
"surface_id": targetPanel.id.uuidString,
|
||||
"title": "Targeted"
|
||||
],
|
||||
to: socketPath
|
||||
)
|
||||
continuation.resume(returning: response)
|
||||
} catch {
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let result = try XCTUnwrap(response["result"] as? [String: Any])
|
||||
XCTAssertEqual(result["surface_id"] as? String, targetPanel.id.uuidString)
|
||||
XCTAssertTrue(store.hasUnreadNotification(forTabId: workspace.id, surfaceId: targetPanel.id))
|
||||
XCTAssertFalse(store.hasUnreadNotification(forTabId: workspace.id, surfaceId: focusedPanelId))
|
||||
}
|
||||
|
||||
private func waitForSocket(at path: String, timeout: TimeInterval = 2.0) throws {
|
||||
let expectation = XCTNSPredicateExpectation(
|
||||
predicate: NSPredicate { _, _ in
|
||||
|
|
@ -212,7 +276,75 @@ final class TerminalControllerSocketSecurityTests: XCTestCase {
|
|||
return responses
|
||||
}
|
||||
|
||||
private func writeLine(_ command: String, to fd: Int32) throws {
|
||||
private nonisolated func sendV2Request(
|
||||
method: String,
|
||||
params: [String: Any],
|
||||
to socketPath: String
|
||||
) throws -> [String: Any] {
|
||||
let fd = try connect(to: socketPath)
|
||||
defer { Darwin.close(fd) }
|
||||
|
||||
let payload: [String: Any] = [
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"method": method,
|
||||
"params": params
|
||||
]
|
||||
let data = try JSONSerialization.data(withJSONObject: payload)
|
||||
guard let line = String(data: data, encoding: .utf8) else {
|
||||
throw NSError(domain: NSCocoaErrorDomain, code: 0, userInfo: [
|
||||
NSLocalizedDescriptionKey: "Failed to encode JSON-RPC request"
|
||||
])
|
||||
}
|
||||
try writeLine(line, to: fd)
|
||||
|
||||
let responseLine = try readLine(from: fd)
|
||||
let responseData = Data(responseLine.utf8)
|
||||
return try XCTUnwrap(
|
||||
try JSONSerialization.jsonObject(with: responseData) as? [String: Any],
|
||||
"Expected JSON-RPC response object"
|
||||
)
|
||||
}
|
||||
|
||||
private nonisolated func connect(to socketPath: String) throws -> Int32 {
|
||||
let fd = Darwin.socket(AF_UNIX, SOCK_STREAM, 0)
|
||||
guard fd >= 0 else {
|
||||
throw posixError("socket(AF_UNIX)")
|
||||
}
|
||||
|
||||
var addr = sockaddr_un()
|
||||
addr.sun_family = sa_family_t(AF_UNIX)
|
||||
|
||||
let bytes = Array(socketPath.utf8)
|
||||
let maxPathLen = MemoryLayout.size(ofValue: addr.sun_path)
|
||||
guard bytes.count < maxPathLen else {
|
||||
Darwin.close(fd)
|
||||
throw NSError(domain: NSPOSIXErrorDomain, code: Int(ENAMETOOLONG))
|
||||
}
|
||||
|
||||
withUnsafeMutablePointer(to: &addr.sun_path) { pathPtr in
|
||||
let cPath = UnsafeMutableRawPointer(pathPtr).assumingMemoryBound(to: CChar.self)
|
||||
cPath.initialize(repeating: 0, count: maxPathLen)
|
||||
for (index, byte) in bytes.enumerated() {
|
||||
cPath[index] = CChar(bitPattern: byte)
|
||||
}
|
||||
}
|
||||
|
||||
let addrLen = socklen_t(MemoryLayout<sa_family_t>.size + bytes.count + 1)
|
||||
let connectResult = withUnsafePointer(to: &addr) { ptr -> Int32 in
|
||||
ptr.withMemoryRebound(to: sockaddr.self, capacity: 1) { sockaddrPtr in
|
||||
Darwin.connect(fd, sockaddrPtr, addrLen)
|
||||
}
|
||||
}
|
||||
guard connectResult == 0 else {
|
||||
let error = posixError("connect(\(socketPath))")
|
||||
Darwin.close(fd)
|
||||
throw error
|
||||
}
|
||||
return fd
|
||||
}
|
||||
|
||||
private nonisolated func writeLine(_ command: String, to fd: Int32) throws {
|
||||
let payload = Array((command + "\n").utf8)
|
||||
var offset = 0
|
||||
while offset < payload.count {
|
||||
|
|
@ -226,7 +358,7 @@ final class TerminalControllerSocketSecurityTests: XCTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
private func readLine(from fd: Int32) throws -> String {
|
||||
private nonisolated func readLine(from fd: Int32) throws -> String {
|
||||
var buffer = [UInt8](repeating: 0, count: 1)
|
||||
var data = Data()
|
||||
|
||||
|
|
@ -248,7 +380,7 @@ final class TerminalControllerSocketSecurityTests: XCTestCase {
|
|||
return line
|
||||
}
|
||||
|
||||
private func posixError(_ operation: String) -> NSError {
|
||||
private nonisolated func posixError(_ operation: String) -> NSError {
|
||||
NSError(
|
||||
domain: NSPOSIXErrorDomain,
|
||||
code: Int(errno),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue