mirror of
https://github.com/samsonjs/vibetunnel.git
synced 2026-06-28 05:29:29 +00:00
test fixes
This commit is contained in:
parent
47eded4cb5
commit
a791bbede8
4 changed files with 84 additions and 82 deletions
|
|
@ -7,14 +7,14 @@ import Testing
|
|||
@Suite("Server Manager Tests")
|
||||
@MainActor
|
||||
final class ServerManagerTests {
|
||||
// We'll use the shared ServerManager instance since it's a singleton
|
||||
/// We'll use the shared ServerManager instance since it's a singleton
|
||||
let manager = ServerManager.shared
|
||||
|
||||
|
||||
init() async {
|
||||
// Ensure clean state before each test
|
||||
await manager.stop()
|
||||
}
|
||||
|
||||
|
||||
deinit {
|
||||
// Clean up is handled in init() of next test since we can't use async in deinit
|
||||
}
|
||||
|
|
@ -34,7 +34,7 @@ final class ServerManagerTests {
|
|||
if let error = manager.lastError as? BunServerError {
|
||||
#expect(error == .binaryNotFound)
|
||||
}
|
||||
|
||||
|
||||
// Server should not be running without the binary
|
||||
#expect(!manager.isRunning)
|
||||
#expect(manager.bunServer == nil)
|
||||
|
|
@ -51,7 +51,7 @@ final class ServerManagerTests {
|
|||
func startingAlreadyRunningServer() async throws {
|
||||
// In test environment, we can't actually start the server
|
||||
// So we'll test the logic of preventing duplicate starts
|
||||
|
||||
|
||||
// First attempt to start
|
||||
await manager.start()
|
||||
try await Task.sleep(for: .milliseconds(100))
|
||||
|
|
@ -64,7 +64,7 @@ final class ServerManagerTests {
|
|||
|
||||
// Should still have the same state (either nil or same instance)
|
||||
#expect(manager.bunServer === firstServer)
|
||||
|
||||
|
||||
// Error should be consistent
|
||||
if let error1 = firstError as? BunServerError,
|
||||
let error2 = manager.lastError as? BunServerError {
|
||||
|
|
@ -77,7 +77,6 @@ final class ServerManagerTests {
|
|||
|
||||
@Test("Port configuration")
|
||||
func portConfiguration() async throws {
|
||||
|
||||
// Store original port
|
||||
let originalPort = manager.port
|
||||
|
||||
|
|
@ -99,7 +98,6 @@ final class ServerManagerTests {
|
|||
DashboardAccessMode.network
|
||||
])
|
||||
func bindAddressConfiguration(mode: DashboardAccessMode) async throws {
|
||||
|
||||
// Store original mode
|
||||
let originalMode = UserDefaults.standard.string(forKey: "dashboardAccessMode") ?? ""
|
||||
|
||||
|
|
@ -174,11 +172,11 @@ final class ServerManagerTests {
|
|||
|
||||
// Verify port configuration is maintained
|
||||
#expect(manager.port == testPort)
|
||||
|
||||
|
||||
// In test environment without binary, both instances should be nil
|
||||
#expect(manager.bunServer == nil)
|
||||
#expect(serverBeforeRestart == nil)
|
||||
|
||||
|
||||
// Error should be consistent (binary not found)
|
||||
if let error = manager.lastError as? BunServerError {
|
||||
#expect(error == .binaryNotFound)
|
||||
|
|
@ -228,7 +226,7 @@ final class ServerManagerTests {
|
|||
// In test environment, server won't actually start
|
||||
#expect(!manager.isRunning)
|
||||
#expect(manager.bunServer == nil)
|
||||
|
||||
|
||||
// Verify error is set appropriately
|
||||
if let error = manager.lastError as? BunServerError {
|
||||
#expect(error == .binaryNotFound)
|
||||
|
|
|
|||
|
|
@ -128,9 +128,13 @@ struct SessionIdHandlingTests {
|
|||
let started_at: String
|
||||
let stdin: String
|
||||
let streamOut: String
|
||||
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case cmdline, cwd, name, pid, status
|
||||
case cmdline
|
||||
case cwd
|
||||
case name
|
||||
case pid
|
||||
case status
|
||||
case started_at = "started_at"
|
||||
case stdin
|
||||
case streamOut = "stream-out"
|
||||
|
|
|
|||
|
|
@ -8,70 +8,70 @@ import Testing
|
|||
@MainActor
|
||||
final class SessionMonitorTests {
|
||||
let monitor = SessionMonitor.shared
|
||||
|
||||
|
||||
init() async {
|
||||
// Ensure clean state before each test
|
||||
await monitor.refresh()
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Basic Functionality Tests
|
||||
|
||||
|
||||
@Test("Session count calculation")
|
||||
func sessionCount() {
|
||||
// When no sessions exist
|
||||
#expect(monitor.sessionCount == 0)
|
||||
|
||||
|
||||
// Note: Full integration tests would require a running server
|
||||
// These tests verify the basic functionality of SessionMonitor
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Cache Behavior Tests
|
||||
|
||||
|
||||
@Test("Cache behavior", .tags(.performance))
|
||||
func cacheBehavior() async {
|
||||
// First call should fetch
|
||||
_ = await monitor.getSessions()
|
||||
|
||||
|
||||
// Immediate second call should use cache (no network request)
|
||||
let cachedSessions = await monitor.getSessions()
|
||||
|
||||
|
||||
// Verify we got a result (even if empty due to no server)
|
||||
// cachedSessions is non-optional, so just verify it's a dictionary
|
||||
#expect(cachedSessions.isEmpty || !cachedSessions.isEmpty)
|
||||
}
|
||||
|
||||
|
||||
@Test("Force refresh clears cache")
|
||||
func forceRefresh() async {
|
||||
// Get initial sessions
|
||||
let initialSessions = await monitor.getSessions()
|
||||
|
||||
|
||||
// Force refresh
|
||||
await monitor.refresh()
|
||||
|
||||
|
||||
// Next call should fetch fresh data
|
||||
let refreshedSessions = await monitor.getSessions()
|
||||
|
||||
|
||||
// Both should be dictionaries (possibly empty)
|
||||
#expect(type(of: initialSessions) == type(of: refreshedSessions))
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Error Handling Tests
|
||||
|
||||
|
||||
@Test("Error handling", .tags(.reliability))
|
||||
func errorHandling() async {
|
||||
// When server is not running, should handle gracefully
|
||||
_ = await monitor.getSessions()
|
||||
|
||||
|
||||
// Should have empty sessions, not crash
|
||||
#expect(monitor.sessions.isEmpty || !monitor.sessions.isEmpty)
|
||||
|
||||
|
||||
// Last error might be nil (if treating connection errors as expected)
|
||||
// or might contain error info
|
||||
#expect(monitor.lastError == nil || monitor.lastError != nil)
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Concurrent Access Tests
|
||||
|
||||
|
||||
@Test("Concurrent session access", .tags(.concurrency))
|
||||
func concurrentAccess() async {
|
||||
await withTaskGroup(of: [String: ServerSessionInfo].self) { group in
|
||||
|
|
@ -81,12 +81,12 @@ final class SessionMonitorTests {
|
|||
await monitor.getSessions()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var results: [[String: ServerSessionInfo]] = []
|
||||
for await result in group {
|
||||
results.append(result)
|
||||
}
|
||||
|
||||
|
||||
// All concurrent calls should return consistent results
|
||||
if let first = results.first {
|
||||
for result in results {
|
||||
|
|
@ -95,57 +95,57 @@ final class SessionMonitorTests {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Session Update Tests
|
||||
|
||||
|
||||
@Test("Session updates are reflected")
|
||||
func sessionUpdates() async {
|
||||
// Get initial state
|
||||
_ = monitor.sessionCount
|
||||
|
||||
|
||||
// Refresh to get latest
|
||||
await monitor.refresh()
|
||||
|
||||
|
||||
// Count should be consistent with sessions dictionary
|
||||
#expect(monitor.sessionCount == monitor.sessions.count)
|
||||
#expect(monitor.sessionCount >= 0)
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Integration Tests
|
||||
|
||||
|
||||
@Test("Session monitor integration", .tags(.integration))
|
||||
func integration() async {
|
||||
// Test the full flow
|
||||
await monitor.refresh()
|
||||
let sessions = await monitor.getSessions()
|
||||
|
||||
|
||||
// Verify session structure if we have any
|
||||
for (sessionId, _) in sessions {
|
||||
// Session ID should be valid
|
||||
#expect(!sessionId.isEmpty)
|
||||
|
||||
|
||||
// Note: ServerSessionInfo structure details would be validated here
|
||||
// if we had access to the actual session info fields
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Performance Tests
|
||||
|
||||
|
||||
@Test("Cache performance", .tags(.performance))
|
||||
func cachePerformance() async throws {
|
||||
// Warm up cache
|
||||
_ = await monitor.getSessions()
|
||||
|
||||
|
||||
// Measure cached access time
|
||||
let start = Date()
|
||||
|
||||
|
||||
for _ in 0..<100 {
|
||||
_ = await monitor.getSessions()
|
||||
}
|
||||
|
||||
|
||||
let elapsed = Date().timeIntervalSince(start)
|
||||
|
||||
|
||||
// Cached access should be very fast
|
||||
#expect(elapsed < 0.1, "Cached access took too long: \(elapsed)s for 100 calls")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import AppKit
|
||||
import Foundation
|
||||
import Testing
|
||||
import AppKit
|
||||
@testable import VibeTunnel
|
||||
|
||||
// MARK: - Terminal Launch Tests
|
||||
|
|
@ -8,7 +8,7 @@ import AppKit
|
|||
@Suite("Terminal Launch Tests")
|
||||
struct TerminalLaunchTests {
|
||||
// MARK: - URL Generation Tests
|
||||
|
||||
|
||||
@Test("Terminal URL generation", arguments: [
|
||||
(Terminal.iTerm2, "echo 'Hello World'", "iterm2://run?command=echo%20\'Hello%20World\'"),
|
||||
(Terminal.iTerm2, "cd /tmp && ls", "iterm2://run?command=cd%20/tmp%20%26%26%20ls"),
|
||||
|
|
@ -24,33 +24,33 @@ struct TerminalLaunchTests {
|
|||
#expect(expectedURL == nil)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Command Arguments Tests
|
||||
|
||||
|
||||
@Test("Command argument generation for terminals")
|
||||
func commandArgumentGeneration() {
|
||||
let command = "echo 'Hello World'"
|
||||
|
||||
|
||||
// Test Alacritty arguments
|
||||
let alacrittyArgs = Terminal.alacritty.commandArguments(for: command)
|
||||
#expect(alacrittyArgs == ["-e", "/bin/bash", "-c", command])
|
||||
|
||||
|
||||
// Test WezTerm arguments
|
||||
let weztermArgs = Terminal.wezterm.commandArguments(for: command)
|
||||
#expect(weztermArgs == ["start", "--", "/bin/bash", "-c", command])
|
||||
|
||||
|
||||
// Test Terminal.app (limited support)
|
||||
let terminalArgs = Terminal.terminal.commandArguments(for: command)
|
||||
#expect(terminalArgs == [])
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Working Directory Tests
|
||||
|
||||
|
||||
@Test("Working directory support")
|
||||
func workingDirectorySupport() {
|
||||
let workDir = "/Users/test/projects"
|
||||
let command = "ls -la"
|
||||
|
||||
|
||||
// Alacritty with working directory
|
||||
let alacrittyArgs = Terminal.alacritty.commandArguments(
|
||||
for: command,
|
||||
|
|
@ -60,7 +60,7 @@ struct TerminalLaunchTests {
|
|||
"--working-directory", workDir,
|
||||
"-e", "/bin/bash", "-c", command
|
||||
])
|
||||
|
||||
|
||||
// WezTerm with working directory
|
||||
let weztermArgs = Terminal.wezterm.commandArguments(
|
||||
for: command,
|
||||
|
|
@ -70,7 +70,7 @@ struct TerminalLaunchTests {
|
|||
"start", "--cwd", workDir,
|
||||
"--", "/bin/bash", "-c", command
|
||||
])
|
||||
|
||||
|
||||
// iTerm2 URL with working directory
|
||||
if let url = Terminal.iTerm2.commandURL(for: command, workingDirectory: workDir) {
|
||||
#expect(url.absoluteString.contains("cd="))
|
||||
|
|
@ -79,62 +79,62 @@ struct TerminalLaunchTests {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Complex Command Tests
|
||||
|
||||
|
||||
@Test("Complex command encoding")
|
||||
func complexCommandEncoding() {
|
||||
let complexCommand = "git log --oneline -10 && echo 'Done!'"
|
||||
|
||||
|
||||
// Test iTerm2 URL encoding
|
||||
if let url = Terminal.iTerm2.commandURL(for: complexCommand) {
|
||||
// URLComponents encodes differently, so just check the URL contains the command
|
||||
#expect(url.absoluteString.contains("command="))
|
||||
#expect(url.absoluteString.contains("git"))
|
||||
}
|
||||
|
||||
|
||||
// Test argument generation doesn't break the command
|
||||
let alacrittyArgs = Terminal.alacritty.commandArguments(for: complexCommand)
|
||||
#expect(alacrittyArgs.last == complexCommand)
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Terminal Detection Tests
|
||||
|
||||
|
||||
@Test("Terminal detection")
|
||||
func terminalDetection() {
|
||||
// At least Terminal.app should be available on macOS
|
||||
#expect(Terminal.installed.contains(.terminal))
|
||||
|
||||
|
||||
// Check that installed terminals have valid paths
|
||||
for terminal in Terminal.installed {
|
||||
// Check if terminal is installed
|
||||
#expect(NSWorkspace.shared.urlForApplication(withBundleIdentifier: terminal.bundleIdentifier) != nil)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Environment Variable Tests
|
||||
|
||||
|
||||
@Test("Launching with environment variables")
|
||||
@MainActor
|
||||
func environmentVariables() {
|
||||
_ = ["MY_VAR": "test_value", "PATH": "/custom/path:/usr/bin"]
|
||||
_ = "echo $MY_VAR"
|
||||
|
||||
|
||||
// Test that environment variables can be passed
|
||||
_ = TerminalLauncher.shared
|
||||
|
||||
|
||||
// This would need to be implemented in TerminalLauncher
|
||||
// Just testing the concept here
|
||||
#expect(Bool(true)) // No-throw test
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Script File Tests
|
||||
|
||||
|
||||
@Test("Script file execution")
|
||||
func scriptFileExecution() throws {
|
||||
let tempDir = FileManager.default.temporaryDirectory
|
||||
let scriptPath = tempDir.appendingPathComponent("test_script.sh")
|
||||
|
||||
|
||||
// Create a test script
|
||||
let scriptContent = """
|
||||
#!/bin/bash
|
||||
|
|
@ -142,16 +142,16 @@ struct TerminalLaunchTests {
|
|||
pwd
|
||||
"""
|
||||
try scriptContent.write(to: scriptPath, atomically: true, encoding: .utf8)
|
||||
|
||||
|
||||
// Make executable
|
||||
try FileManager.default.setAttributes(
|
||||
[.posixPermissions: 0o755],
|
||||
ofItemAtPath: scriptPath.path
|
||||
)
|
||||
|
||||
|
||||
// Test launching the script
|
||||
#expect(FileManager.default.fileExists(atPath: scriptPath.path))
|
||||
|
||||
|
||||
// Cleanup
|
||||
try? FileManager.default.removeItem(at: scriptPath)
|
||||
}
|
||||
|
|
@ -171,7 +171,7 @@ extension Terminal {
|
|||
}
|
||||
args += ["-e", "/bin/bash", "-c", command]
|
||||
return args
|
||||
|
||||
|
||||
case .wezterm:
|
||||
var args = ["start"]
|
||||
if let workDir = workingDirectory {
|
||||
|
|
@ -179,12 +179,12 @@ extension Terminal {
|
|||
}
|
||||
args += ["--", "/bin/bash", "-c", command]
|
||||
return args
|
||||
|
||||
|
||||
default:
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Generate URL for terminals that support URL schemes
|
||||
func commandURL(for command: String, workingDirectory: String? = nil) -> URL? {
|
||||
switch self {
|
||||
|
|
@ -198,9 +198,9 @@ extension Terminal {
|
|||
}
|
||||
components?.queryItems = queryItems
|
||||
return components?.url
|
||||
|
||||
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue