49 lines
2.4 KiB
Swift
49 lines
2.4 KiB
Swift
|
|
import XCTest
|
||
|
|
@testable import ClaireTrayApp
|
||
|
|
|
||
|
|
final class WatchdogTests: XCTestCase {
|
||
|
|
private let t0 = Date(timeIntervalSince1970: 1_000_000)
|
||
|
|
|
||
|
|
func testHealthyStaysOK() {
|
||
|
|
var w = Watchdog(failureThreshold: 3, cooldown: 120, maxAttempts: 5)
|
||
|
|
XCTAssertEqual(w.record(healthy: true, now: t0), .ok)
|
||
|
|
XCTAssertEqual(w.record(healthy: true, now: t0.addingTimeInterval(25)), .ok)
|
||
|
|
}
|
||
|
|
|
||
|
|
func testRecoversOnlyAfterThreshold() {
|
||
|
|
var w = Watchdog(failureThreshold: 3, cooldown: 120, maxAttempts: 5)
|
||
|
|
XCTAssertEqual(w.record(healthy: false, now: t0), .watching) // 1
|
||
|
|
XCTAssertEqual(w.record(healthy: false, now: t0.addingTimeInterval(25)), .watching) // 2
|
||
|
|
XCTAssertEqual(w.record(healthy: false, now: t0.addingTimeInterval(50)), .recover) // 3 → kick
|
||
|
|
}
|
||
|
|
|
||
|
|
func testCooldownSuppressesRepeatKicks() {
|
||
|
|
var w = Watchdog(failureThreshold: 1, cooldown: 120, maxAttempts: 5)
|
||
|
|
XCTAssertEqual(w.record(healthy: false, now: t0), .recover) // kick at t0
|
||
|
|
// Within cooldown: no second kick.
|
||
|
|
XCTAssertEqual(w.record(healthy: false, now: t0.addingTimeInterval(60)), .watching)
|
||
|
|
// After cooldown: kick again.
|
||
|
|
XCTAssertEqual(w.record(healthy: false, now: t0.addingTimeInterval(130)), .recover)
|
||
|
|
}
|
||
|
|
|
||
|
|
func testGivesUpAfterMaxAttempts() {
|
||
|
|
var w = Watchdog(failureThreshold: 1, cooldown: 0, maxAttempts: 2)
|
||
|
|
XCTAssertEqual(w.record(healthy: false, now: t0), .recover) // attempt 1
|
||
|
|
XCTAssertEqual(w.record(healthy: false, now: t0.addingTimeInterval(1)), .recover) // attempt 2
|
||
|
|
XCTAssertEqual(w.record(healthy: false, now: t0.addingTimeInterval(2)), .gaveUp) // ceiling hit
|
||
|
|
XCTAssertTrue(w.gaveUp)
|
||
|
|
}
|
||
|
|
|
||
|
|
func testRecoveryResetsAfterDaemonHealthyAgain() {
|
||
|
|
var w = Watchdog(failureThreshold: 1, cooldown: 0, maxAttempts: 2)
|
||
|
|
_ = w.record(healthy: false, now: t0) // recover
|
||
|
|
_ = w.record(healthy: false, now: t0.addingTimeInterval(1)) // recover
|
||
|
|
_ = w.record(healthy: false, now: t0.addingTimeInterval(2)) // gaveUp
|
||
|
|
XCTAssertTrue(w.gaveUp)
|
||
|
|
XCTAssertEqual(w.record(healthy: true, now: t0.addingTimeInterval(3)), .ok) // recovered
|
||
|
|
XCTAssertFalse(w.gaveUp)
|
||
|
|
// Counters reset → a fresh failure run can recover again.
|
||
|
|
XCTAssertEqual(w.record(healthy: false, now: t0.addingTimeInterval(4)), .recover)
|
||
|
|
}
|
||
|
|
}
|