118 lines
4.4 KiB
Swift
118 lines
4.4 KiB
Swift
import AdaptiveReplayKit
|
|
import Foundation
|
|
import Testing
|
|
|
|
struct ReplayTraceSegmentationTests {
|
|
private static let epoch = Date(timeIntervalSinceReferenceDate: 0)
|
|
|
|
private func at(_ seconds: TimeInterval) -> Date {
|
|
Self.epoch.addingTimeInterval(seconds)
|
|
}
|
|
|
|
private func decision(_ seconds: TimeInterval, delay: TimeInterval = 600) -> AdaptiveRefreshTraceRecord {
|
|
.decision(
|
|
timestamp: self.at(seconds),
|
|
menuAgeSeconds: nil,
|
|
lowPowerModeEnabled: false,
|
|
thermalState: .nominal,
|
|
reason: "longIdle",
|
|
delaySeconds: delay)
|
|
}
|
|
|
|
@Test
|
|
func `segmentation excludes only time beyond the expected deadline`() {
|
|
let firstRun = stride(from: 0.0, through: 3000.0, by: 600.0).map { self.decision($0) }
|
|
let secondRun = stride(from: 68400.0, through: 71400.0, by: 600.0).map { self.decision($0) }
|
|
let trace = firstRun + secondRun + [.refreshCompleted(timestamp: self.at(72000))]
|
|
|
|
let report = ReplayTraceSegmenter.automatic(trace)
|
|
|
|
#expect(report.segments.count == 2)
|
|
#expect(report.segments[0].start == self.at(0))
|
|
#expect(report.segments[0].end == self.at(3600))
|
|
#expect(report.segments[1].start == self.at(68400))
|
|
#expect(report.segments[1].end == self.at(72000))
|
|
#expect(report.excludedGapSeconds == 18 * 60 * 60)
|
|
#expect(report.includedSpanSeconds == 2 * 60 * 60)
|
|
}
|
|
|
|
@Test
|
|
func `segmented rate uses summed span instead of averaging segment rates`() {
|
|
let firstRun = stride(from: 0.0, through: 3000.0, by: 600.0).map { self.decision($0) }
|
|
let secondRun = stride(from: 68400.0, through: 71400.0, by: 600.0).map { self.decision($0) }
|
|
let trace = firstRun + secondRun + [.refreshCompleted(timestamp: self.at(72000))]
|
|
|
|
let metrics = ReplayEngine.runSegmented(trace: trace, policy: FixedIntervalPolicy(minutes: 10))
|
|
|
|
#expect(metrics.totalRefreshCount == 12)
|
|
#expect(metrics.simulatedSpanSeconds == 7200)
|
|
#expect(metrics.refreshCountPer24h == 144)
|
|
#expect(metrics.segmentCount == 2)
|
|
#expect(metrics.excludedGapSeconds == 18 * 60 * 60)
|
|
}
|
|
|
|
@Test
|
|
func `a normal scheduled wait remains in the preceding segment`() {
|
|
let trace = [
|
|
self.decision(0, delay: 1800),
|
|
.menuOpen(timestamp: self.at(1700)),
|
|
self.decision(4000, delay: 1800),
|
|
]
|
|
|
|
let report = ReplayTraceSegmenter.automatic(trace)
|
|
|
|
#expect(report.segments.count == 2)
|
|
#expect(report.segments[0].end == self.at(1800))
|
|
#expect(report.excludedGapSeconds == 2200)
|
|
}
|
|
|
|
@Test
|
|
func `menu opens before the first recorded refresh are censored equally`() throws {
|
|
let trace = [
|
|
self.decision(0, delay: 600),
|
|
.menuOpen(timestamp: self.at(100)),
|
|
.refreshCompleted(timestamp: self.at(600)),
|
|
self.decision(600, delay: 600),
|
|
.menuOpen(timestamp: self.at(700)),
|
|
.refreshCompleted(timestamp: self.at(1200)),
|
|
]
|
|
|
|
let metrics = ReplayEngine.runSegmented(trace: trace, policy: FixedIntervalPolicy(minutes: 10))
|
|
|
|
#expect(metrics.boundaryCensoredMenuOpenCount == 1)
|
|
#expect(try #require(metrics.stalenessAtMenuOpen).sampleCount == 1)
|
|
}
|
|
|
|
@Test
|
|
func `recorded refresh anchors staleness before a policy refresh`() throws {
|
|
let trace = [
|
|
self.decision(0, delay: 600),
|
|
.refreshCompleted(timestamp: self.at(600)),
|
|
.menuOpen(timestamp: self.at(700)),
|
|
self.decision(1200, delay: 600),
|
|
]
|
|
|
|
let metrics = ReplayEngine.runSegmented(trace: trace, policy: ManualPolicy())
|
|
let staleness = try #require(metrics.stalenessAtMenuOpen)
|
|
|
|
#expect(staleness.sampleCount == 1)
|
|
#expect(staleness.mean == 100)
|
|
}
|
|
|
|
@Test
|
|
func `recorded refresh supersedes an earlier simulated refresh`() throws {
|
|
let trace = [
|
|
self.decision(0, delay: 650),
|
|
.refreshCompleted(timestamp: self.at(650)),
|
|
.menuOpen(timestamp: self.at(700)),
|
|
self.decision(1200, delay: 600),
|
|
]
|
|
|
|
let metrics = ReplayEngine.runSegmented(trace: trace, policy: FixedIntervalPolicy(minutes: 10))
|
|
let staleness = try #require(metrics.stalenessAtMenuOpen)
|
|
|
|
#expect(staleness.sampleCount == 1)
|
|
#expect(staleness.mean == 50)
|
|
}
|
|
}
|