test(08-02): add performance tests with large datasets
Added 4 performance tests with 1K, 5K, 10K games to validate DAG algorithm scalability. Tests currently failing (RED phase). Tests: - 1K games: <2s expected - 5K games: <10s expected - 10K games: <30s expected - 10K games: memory stability Helper generateLargeDataset() creates realistic test data with distributed stadiums and games across time spans. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -534,4 +534,113 @@ struct GameDAGRouterTests {
|
||||
|
||||
#expect(routeWithBoth != nil, "4 hours available (with 1hr arrival buffer) should be feasible")
|
||||
}
|
||||
|
||||
// MARK: - Performance Tests
|
||||
|
||||
/// Generates a large dataset of games and stadiums for performance testing.
|
||||
/// Games are distributed across stadiums and days to simulate realistic data.
|
||||
private func generateLargeDataset(
|
||||
gameCount: Int,
|
||||
stadiumCount: Int,
|
||||
daysSpan: Int
|
||||
) -> (games: [Game], stadiums: [UUID: Stadium]) {
|
||||
// Create stadiums distributed across the US (roughly)
|
||||
var stadiums: [UUID: Stadium] = [:]
|
||||
let baseDate = date("2026-06-01 19:00")
|
||||
|
||||
for i in 0..<stadiumCount {
|
||||
// Distribute stadiums geographically (rough US coverage)
|
||||
let lat = 30.0 + Double(i % 20) * 1.0 // 30-50 latitude
|
||||
let lon = -120.0 + Double(i / 20) * 5.0 // -120 to -70 longitude
|
||||
let stadium = makeStadium(
|
||||
city: "City\(i)",
|
||||
lat: lat,
|
||||
lon: lon
|
||||
)
|
||||
stadiums[stadium.id] = stadium
|
||||
}
|
||||
|
||||
// Create games distributed across stadiums and days
|
||||
var games: [Game] = []
|
||||
let stadiumIds = Array(stadiums.keys)
|
||||
|
||||
for i in 0..<gameCount {
|
||||
// Distribute games across days
|
||||
let dayOffset = Double(i * daysSpan) / Double(gameCount)
|
||||
let hoursOffset = Double(i % 3) * 3.0 // Vary game times within day
|
||||
let gameTime = baseDate.addingTimeInterval(dayOffset * 24 * 3600 + hoursOffset * 3600)
|
||||
|
||||
// Pick a stadium (cycle through them)
|
||||
let stadiumId = stadiumIds[i % stadiumIds.count]
|
||||
|
||||
let game = makeGame(stadiumId: stadiumId, startTime: gameTime)
|
||||
games.append(game)
|
||||
}
|
||||
|
||||
return (games, stadiums)
|
||||
}
|
||||
|
||||
@Test("Performance: 1000 games completes in under 2 seconds")
|
||||
func performance_1000Games_CompletesInTime() {
|
||||
let (games, stadiums) = generateLargeDataset(gameCount: 1000, stadiumCount: 50, daysSpan: 30)
|
||||
|
||||
let start = ContinuousClock.now
|
||||
let routes = GameDAGRouter.findRoutes(
|
||||
games: games,
|
||||
stadiums: stadiums,
|
||||
constraints: .default
|
||||
)
|
||||
let elapsed = start.duration(to: .now)
|
||||
|
||||
#expect(routes.count > 0, "Should return routes")
|
||||
#expect(elapsed < .seconds(2), "Should complete within 2 seconds, actual: \(elapsed)")
|
||||
}
|
||||
|
||||
@Test("Performance: 5000 games completes in under 10 seconds")
|
||||
func performance_5000Games_CompletesInTime() {
|
||||
let (games, stadiums) = generateLargeDataset(gameCount: 5000, stadiumCount: 100, daysSpan: 60)
|
||||
|
||||
let start = ContinuousClock.now
|
||||
let routes = GameDAGRouter.findRoutes(
|
||||
games: games,
|
||||
stadiums: stadiums,
|
||||
constraints: .default
|
||||
)
|
||||
let elapsed = start.duration(to: .now)
|
||||
|
||||
#expect(routes.count > 0, "Should return routes")
|
||||
#expect(elapsed < .seconds(10), "Should complete within 10 seconds, actual: \(elapsed)")
|
||||
}
|
||||
|
||||
@Test("Performance: 10000 games completes in under 30 seconds")
|
||||
func performance_10000Games_CompletesInTime() {
|
||||
let (games, stadiums) = generateLargeDataset(gameCount: 10000, stadiumCount: 150, daysSpan: 90)
|
||||
|
||||
let start = ContinuousClock.now
|
||||
let routes = GameDAGRouter.findRoutes(
|
||||
games: games,
|
||||
stadiums: stadiums,
|
||||
constraints: .default
|
||||
)
|
||||
let elapsed = start.duration(to: .now)
|
||||
|
||||
#expect(routes.count > 0, "Should return routes")
|
||||
#expect(elapsed < .seconds(30), "Should complete within 30 seconds, actual: \(elapsed)")
|
||||
}
|
||||
|
||||
@Test("Performance: 10000 games does not cause memory issues")
|
||||
func performance_10000Games_NoMemorySpike() {
|
||||
let (games, stadiums) = generateLargeDataset(gameCount: 10000, stadiumCount: 150, daysSpan: 90)
|
||||
|
||||
// Run the algorithm
|
||||
let routes = GameDAGRouter.findRoutes(
|
||||
games: games,
|
||||
stadiums: stadiums,
|
||||
constraints: .default
|
||||
)
|
||||
|
||||
// Verify routes returned (not OOM)
|
||||
#expect(routes.count > 0, "Should return routes without memory crash")
|
||||
#expect(routes.count <= 100, "Should return reasonable number of routes")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user