vibetunnel/mac/VibeTunnelTests/GitRepositoryMonitorRaceConditionTests.swift
2025-07-20 16:58:01 +02:00

110 lines
3.9 KiB
Swift

import Foundation
import Testing
@testable import VibeTunnel
/// Tests to verify that the race condition in GitHub URL fetching is fixed
@Suite("Git Repository Monitor Race Condition Tests", .tags(.concurrency, .gitRepository))
@MainActor
struct GitRepositoryMonitorRaceConditionTests {
@Test(
"Concurrent GitHub URL fetches don't cause duplicate Git operations",
.tags(.attachmentTests),
.enabled(if: TestConditions.isInGitRepository())
)
func concurrentGitHubURLFetches() async throws {
// Attach test environment information
Attachment.record("""
Git Repository: \(FileManager.default.fileExists(atPath: ".git") ? "Valid" : "Invalid")
Test Repository Path: /test/repo/path
Concurrent Operations: 10
Test Type: Race Condition Prevention
""", named: "Git Test Environment")
// Attach initial monitor state
Attachment.record("Monitor created: \(type(of: GitRepositoryMonitor()))", named: "Initial Monitor State")
let monitor = GitRepositoryMonitor()
let testRepoPath = "/test/repo/path"
// Create a mock repository
_ = GitRepository(
path: testRepoPath,
modifiedCount: 0,
addedCount: 0,
deletedCount: 0,
untrackedCount: 0,
currentBranch: "main"
)
// Use reflection to access private properties for testing
let mirror = Mirror(reflecting: monitor)
// Find the githubURLFetchesInProgress property
var inProgressSet: Set<String>?
for child in mirror.children {
if child.label == "githubURLFetchesInProgress",
let set = child.value as? Set<String>
{
inProgressSet = set
break
}
}
// Simulate multiple concurrent requests for the same repository
let concurrentTasks = (0..<10).map { _ in
Task {
// Access private method through mirror or simulate the behavior
// Since we can't directly call private methods, we'll test the public API
_ = await monitor.findRepository(for: testRepoPath)
}
}
// Wait a bit to allow tasks to start (increased for CI)
let waitTime: UInt64 = TestConditions.isRunningInCI() ? 500_000_000 : 100_000_000 // 0.5s in CI, 0.1s locally
try await Task.sleep(nanoseconds: waitTime)
// Verify that in-progress tracking is working
// Note: This is a simplified test since we can't easily access private properties
// In a real scenario, we'd need to refactor for better testability
// Wait for all tasks to complete
for task in concurrentTasks {
_ = await task.value
}
// Clear cache to clean up
monitor.clearCache()
}
@Test("GitHub URL fetch completes even on failure")
func gitHubURLFetchFailureHandling() async throws {
let monitor = GitRepositoryMonitor()
let invalidRepoPath = "/this/is/not/a/git/repo"
// This should not throw and should handle the failure gracefully
let result = await monitor.findRepository(for: invalidRepoPath)
// Should return nil for invalid repo
#expect(result == nil)
// Clear cache to clean up
monitor.clearCache()
}
@Test("Clear cache removes in-progress fetches")
func clearCacheRemovesInProgressFetches() async throws {
let monitor = GitRepositoryMonitor()
// Start a fetch (simulated through public API)
let testPath = "/test/path"
Task {
_ = await monitor.findRepository(for: testPath)
}
// Clear cache immediately
monitor.clearCache()
// Verify cache is cleared (through public API)
let cached = monitor.getCachedRepository(for: testPath)
#expect(cached == nil)
}
}