Files
terebi/Checks/automatic-quality.swift
T

146 lines
7.5 KiB
Swift

import Foundation
@main
struct AutomaticQualityChecks {
static func require(_ condition: @autoclosure () -> Bool, _ message: String) {
if !condition() { fatalError("FAIL: " + message) }
}
static func sample(at now: Double, ahead: Double? = 30, height: Int? = 720) -> AutomaticQuality.Sample {
.init(position: 100 + now, duration: 1000, ahead: ahead, height: height,
heights: [240, 480, 720, 1080, 2160])
}
static func main() {
var policy = AutomaticQuality()
for second in 0..<6 {
require(policy.choose(sample(at: Double(second), ahead: 3), at: Double(second)) == nil,
"brief low reserve does not change quality")
}
require(policy.choose(sample(at: 6, ahead: 3), at: 6) == 480, "persistent low reserve steps down one rung")
policy.resetHealth() // Automatic reopen resets evidence without losing its cooldown.
for second in 7..<36 {
require(policy.choose(sample(at: Double(second), ahead: 3, height: 480), at: Double(second)) == nil,
"automatic reopen preserves the 30-second switch cooldown")
}
require(policy.choose(sample(at: 36, ahead: 3, height: 480), at: 36) == 240,
"continued shortage may downshift after cooldown")
policy = AutomaticQuality()
for second in 0..<60 {
require(policy.choose(sample(at: Double(second), height: 240), at: Double(second)) == nil,
"upshift waits for sustained healthy recorded playback")
}
require(policy.choose(sample(at: 60, height: 240), at: 60) == 480,
"healthy playback increases exactly one rung")
for second in 61..<90 {
require(policy.choose(sample(at: Double(second), ahead: 1, height: 480), at: Double(second)) == nil,
"a sudden shortage cannot immediately reverse an upshift")
}
require(policy.choose(sample(at: 90, ahead: 1, height: 480), at: 90) == 240,
"downshift becomes possible after upshift cooldown")
policy = AutomaticQuality()
for second in 0...5 {
require(policy.choose(sample(at: Double(second), ahead: 3), at: Double(second)) == nil, "low reserve warmup")
}
require(policy.choose(sample(at: 6, ahead: 8), at: 6) == nil, "middle reserve clears low-water evidence")
for second in 7..<13 {
require(policy.choose(sample(at: Double(second), ahead: 3), at: Double(second)) == nil,
"hysteresis requires a fresh continuous shortage")
}
require(policy.choose(sample(at: 13, ahead: 3), at: 13) == 480, "new shortage has its own threshold")
policy = AutomaticQuality()
for second in 0...90 {
require(policy.choose(sample(at: Double(second), ahead: 19, height: 480), at: Double(second)) == nil,
"middle reserve is not healthy enough for an upshift")
}
for suppression in ["disabled", "paused", "seeking", "opening", "local", "missing height", "empty heights", "EOF"] {
policy = AutomaticQuality()
for second in 0...150 {
let now = Double(second)
var input = sample(at: now, ahead: 1)
switch suppression {
case "disabled": input.enabled = false
case "paused": input.playing = false
case "seeking": input.seeking = true
case "opening": input.opening = true
case "local": input.network = false
case "missing height": input.height = nil
case "empty heights": input.heights = []
default: input.duration = input.position + 14
}
require(policy.choose(input, at: now) == nil, suppression + " suppresses quality switching")
}
}
for interruption in ["pause", "seek", "open"] {
policy = AutomaticQuality()
require(policy.choose(sample(at: 0), at: 0) == nil, "start healthy evidence")
var input = sample(at: 59)
input.playing = interruption != "pause"
input.seeking = interruption == "seek"
input.opening = interruption == "open"
require(policy.choose(input, at: 59) == nil, "interrupt healthy evidence")
require(policy.choose(sample(at: 60), at: 60) == nil, "resume starts fresh health")
require(policy.choose(sample(at: 119), at: 119) == nil, "no pre-interruption health is reused")
require(policy.choose(sample(at: 120), at: 120) == 1080, "fresh uninterrupted health can upshift")
}
policy = AutomaticQuality()
var sparse = sample(at: 0, ahead: 1)
sparse.heights = [2160, 1080, 480, 144, 480, 0, -1]
require(policy.choose(sparse, at: 0) == nil, "sparse heights warmup")
sparse.position += 6
require(policy.choose(sparse, at: 6) == 480, "nearest lower available rung handles sparse heights")
policy = AutomaticQuality()
sparse.height = 2160
require(policy.choose(sparse, at: 0) == 1080, "enabling auto caps an existing high-resolution selection")
policy = AutomaticQuality()
for second in 0...150 {
require(policy.choose(sample(at: Double(second), height: 1080), at: Double(second)) == nil,
"automatic upshift never exceeds 1080p")
}
for live in [false, true] {
policy = AutomaticQuality()
for second in 0..<120 {
let now = Double(second)
var input = sample(at: now, ahead: live ? 0 : nil, height: 480)
input.live = live
input.duration = 0
require(policy.choose(input, at: now) == nil, "live/unknown reserve needs 120 seconds of stability")
}
var input = sample(at: 120, ahead: live ? 0 : nil, height: 480)
input.live = live
input.duration = 0
require(policy.choose(input, at: 120) == 720, "live/unknown reserve can cautiously upshift")
policy = AutomaticQuality()
input.buffering = true
for second in 0..<3 {
require(policy.choose(input, at: Double(second)) == nil, "brief live/unknown stall is tolerated")
}
require(policy.choose(input, at: 3) == 240, "persistent live/unknown stall downshifts")
}
policy = AutomaticQuality()
let frozen = sample(at: 0, ahead: nil)
for second in 0..<6 {
require(policy.choose(frozen, at: Double(second)) == nil, "position stall first waits for progress then hysteresis")
}
require(policy.choose(frozen, at: 6) == 480, "lack of playback progress also detects a stall")
policy = AutomaticQuality()
require(policy.choose(sample(at: 0, ahead: 1), at: 0) == nil, "failure scenario warmup")
require(policy.choose(sample(at: 6, ahead: 1), at: 6) == 480, "failure scenario requests a switch")
policy.extractionFailed(at: 7)
policy.resetHealth()
for second in 8..<127 {
require(policy.choose(sample(at: Double(second), ahead: 1), at: Double(second)) == nil,
"extraction failure preserves old height and backs off for 120 seconds")
}
require(policy.choose(sample(at: 127, ahead: 1), at: 127) == 480,
"failure backoff permits a later attempt, not a retry every poll")
print("Automatic quality checks passed")
}
}