Skip to content
This repository was archived by the owner on Sep 23, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions Sources/Vorssaint/Services/Metrics/SpeedTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ final class SpeedTest: NSObject, ObservableObject {
// so request under that and loop chunks back-to-back until the time box — that
// keeps a fast link's pipe full for a full measurement window.
private let downloadBytes = 90_000_000
private let uploadBytes = 100_000_000
private let uploadBytes: Int

private let queue = OperationQueue()
private var session: URLSession!
Expand All @@ -48,8 +48,10 @@ final class SpeedTest: NSObject, ObservableObject {
private var generation = 0
private var stopWork: DispatchWorkItem?

init(configuration: URLSessionConfiguration = .ephemeral, sampleSeconds: TimeInterval = 5) {
init(configuration: URLSessionConfiguration = .ephemeral, sampleSeconds: TimeInterval = 5,
uploadBytes: Int = 100_000_000) {
self.sampleSeconds = sampleSeconds
self.uploadBytes = uploadBytes
super.init()
queue.maxConcurrentOperationCount = 1
configuration.requestCachePolicy = .reloadIgnoringLocalCacheData
Expand Down
4 changes: 2 additions & 2 deletions Tests/MetricsTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3585,10 +3585,10 @@ UninstallerSelectionTests.run { expect($0, $1) }
// decision above is made consciously, never by omission.
let releasePlist = NSDictionary(contentsOfFile: "Resources/Info.plist")
let plistVersion = (releasePlist?["CFBundleShortVersionString"] as? String) ?? ""
expect(plistVersion == "0.1.1",
expect(plistVersion == "0.1.2",
"bumping the app version requires re-deciding the support prompt pin above")
let plistBuild = (releasePlist?["CFBundleVersion"] as? String) ?? ""
expect(plistBuild == "2",
expect(plistBuild == "3",
"every app version needs its own incremented bundle build")
expect(!SupportUpdateIntroInfo.shouldShow(appVersion: plistVersion, lastSeenVersion: nil)
&& !UpdateHighlightsInfo.shouldShow(appVersion: plistVersion, lastSeenVersion: nil),
Expand Down
8 changes: 4 additions & 4 deletions Tests/ProductSettingsTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ enum ProductSettingsTests {
static func run(_ expect: (Bool, String) -> Void) {
let changelog = """
## [Unreleased]
## [0.1.1] - 2026-09-15
## [0.1.2] - 2026-09-16
### Added
- Input tuning and graph controls.
## [0.1.0] - 2026-09-11
Expand All @@ -17,7 +17,7 @@ enum ProductSettingsTests {
"""
let current = ReleaseNotes.current(changelog: changelog)
expect(current.version == ProductIdentity.currentReleaseNotesVersion, "current notes use product identity")
expect(current.version == "0.1.1", "current kururu build selects the new release")
expect(current.version == "0.1.2", "current kururu build selects the new release")
expect(current.sections.first?.bulletItems == ["Input tuning and graph controls."], "real parser selects the new product body")
let localized = ["en", "zh-Hans", "de", "fr", "es", "ja"].map {
ReleaseNotes.current(languageCode: $0, changelog: changelog)
Expand All @@ -28,10 +28,10 @@ enum ProductSettingsTests {
expect(localized.allSatisfy { !$0.sections.flatMap(\.bulletItems).joined().contains("Upstream historical scope") }, "current localized notes never show upstream history")
let historical = ReleaseNotes.notes(for: "3.3.5", changelog: changelog)
expect(historical.date == "2026-09-06" && historical.sections.first?.paragraphItems == ["Upstream historical scope."], "numbered history still parses")
expect(ReleaseNotes.allVersions(changelog: changelog) == ["0.1.1", "0.1.0", "3.3.5"], "product release precedes upstream history; unreleased is omitted")
expect(ReleaseNotes.allVersions(changelog: changelog) == ["0.1.2", "0.1.0", "3.3.5"], "product release precedes upstream history; unreleased is omitted")
expect(ReleaseNotes.current(changelog: nil).sections.isEmpty, "missing product notes do not fall back to upstream")
let labels = ["en", "zh-Hans", "de", "fr", "es", "ja"].map { current.versionLabel(languageCode: $0) }
expect(labels.allSatisfy { $0 == "v0.1.1 · 2026-09-15" }, "all locales show the product release version and date")
expect(labels.allSatisfy { $0 == "v0.1.2 · 2026-09-16" }, "all locales show the product release version and date")
expect(historical.versionLabel(languageCode: "en") == "v3.3.5 · 2026-09-06", "published label retained")
expect(!BuildCapabilityPolicy.allowsUpdates(configured: false, development: false), "unconfigured release cannot update")
expect(!BuildCapabilityPolicy.allowsUpdates(configured: true, development: true), "development cannot update")
Expand Down
27 changes: 26 additions & 1 deletion Tests/SpeedTestTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ enum SpeedTestTests {
let configuration = URLSessionConfiguration.ephemeral
configuration.protocolClasses = [SpeedTestProtocol.self]
configuration.httpAdditionalHeaders = ["X-Test-Scenario": testCase.name]
let test = SpeedTest(configuration: configuration, sampleSeconds: 0.1)
// These cases test HTTP status handling, not a 100 MB upload benchmark.
let test = SpeedTest(configuration: configuration, sampleSeconds: 0.1, uploadBytes: 1_024)
test.start()
let deadline = Date().addingTimeInterval(3)
var completed = false
Expand Down Expand Up @@ -62,6 +63,10 @@ enum SpeedTestTests {
expect(test.phase == phase, "speed test \(testCase.name) stays terminal after its time box")
expect(SpeedTestProtocol.requests(for: testCase.name) == testCase.requests,
"speed test \(testCase.name) stops requesting data at the failed phase")
if testCase.requests.contains("upload") {
expect(SpeedTestProtocol.uploadSize(for: testCase.name) == 1_024,
"speed test \(testCase.name) uses the small fixture upload body")
}
test.cancel()
}
}
Expand All @@ -70,6 +75,13 @@ enum SpeedTestTests {
private final class SpeedTestProtocol: URLProtocol {
private static let lock = NSLock()
private static var recordedRequests: [String: [String]] = [:]
private static var uploadSizes: [String: Int] = [:]

static func uploadSize(for scenario: String) -> Int? {
lock.lock()
defer { lock.unlock() }
return uploadSizes[scenario]
}

static func requests(for scenario: String) -> [String] {
lock.lock()
Expand All @@ -84,7 +96,20 @@ private final class SpeedTestProtocol: URLProtocol {
let scenario = request.value(forHTTPHeaderField: "X-Test-Scenario") ?? ""
let url = request.url!
let phase = url.path == "/__up" ? "upload" : url.query == "bytes=0" ? "latency" : "download"
var uploadSize = request.httpBody?.count ?? 0
if phase == "upload", let stream = request.httpBodyStream {
stream.open()
defer { stream.close() }
// One byte beyond the fixture size detects an accidental real upload.
var buffer = [UInt8](repeating: 0, count: 1_025)
while uploadSize < buffer.count {
let count = stream.read(&buffer, maxLength: buffer.count - uploadSize)
guard count > 0 else { break }
uploadSize += count
}
}
Self.lock.lock()
if phase == "upload" { Self.uploadSizes[scenario] = uploadSize }
Self.recordedRequests[scenario, default: []].append(phase)
let downloadCount = Self.recordedRequests[scenario, default: []].filter { $0 == "download" }.count
Self.lock.unlock()
Expand Down