tv-anarchy/Tests/TVAnarchyCoreTests/TransferHealthTests.swift

95 lines
4.9 KiB
Swift

import XCTest
@testable import TVAnarchyCore
final class TransferHealthTests: XCTestCase {
func testStatusMapping() {
func h(_ status: Int, complete: Bool = false, rate: Int = 0) -> TransferHealth {
TransferHealth.classify(status: status, isComplete: complete, rateDownload: rate,
peersConnected: 5, error: 0, secondsStuck: nil)
}
XCTAssertEqual(h(6), .seeding)
XCTAssertEqual(h(0, complete: true), .done)
XCTAssertEqual(h(0, complete: false), .stopped)
XCTAssertEqual(h(1), .checking)
XCTAssertEqual(h(3), .queued)
XCTAssertEqual(h(4, rate: 1_000), .downloading)
}
func testErrorWins() {
// Tracker error (2) and local error (3) are genuine errored, beating an
// otherwise-healthy downloading state.
XCTAssertEqual(
TransferHealth.classify(status: 4, isComplete: false, rateDownload: 5_000,
peersConnected: 9, error: 3, secondsStuck: 0), .errored)
XCTAssertEqual(
TransferHealth.classify(status: 4, isComplete: false, rateDownload: 5_000,
peersConnected: 9, error: 2, secondsStuck: 0), .errored)
}
/// A tracker *warning* (error == 1) is one tracker flapping on an otherwise
/// healthy torrent must NOT red-flag/notify (would spam on benign warnings).
func testTrackerWarningIsNotErrored() {
// Healthy downloading torrent that carries a stale tracker warning.
XCTAssertEqual(
TransferHealth.classify(status: 4, isComplete: false, rateDownload: 5_000,
peersConnected: 9, error: 1, secondsStuck: 0), .downloading)
// A seeding torrent with a tracker warning is still just seeding.
XCTAssertEqual(
TransferHealth.classify(status: 6, isComplete: true, rateDownload: 0,
peersConnected: 0, error: 1, secondsStuck: nil), .seeding)
XCTAssertFalse(TransferHealth.seeding.needsAttention)
}
func testStalledVsDeadThresholds() {
// 0 rate, peers present, past the stall window stalled.
XCTAssertEqual(
TransferHealth.classify(status: 4, isComplete: false, rateDownload: 0,
peersConnected: 4, error: 0, secondsStuck: 130), .stalled)
// 0 rate, NO peers, past the dead window dead.
XCTAssertEqual(
TransferHealth.classify(status: 4, isComplete: false, rateDownload: 0,
peersConnected: 0, error: 0, secondsStuck: 400), .dead)
// briefly 0 rate, not yet past stall still downloading (no false alarm).
XCTAssertEqual(
TransferHealth.classify(status: 4, isComplete: false, rateDownload: 0,
peersConnected: 0, error: 0, secondsStuck: 10), .downloading)
}
func testAttentionAndSortOrder() {
XCTAssertTrue(TransferHealth.errored.needsAttention)
XCTAssertTrue(TransferHealth.dead.needsAttention)
XCTAssertFalse(TransferHealth.downloading.needsAttention)
// attention states sort ahead of active work, which sorts ahead of idle.
XCTAssertLessThan(TransferHealth.dead.sortRank, TransferHealth.downloading.sortRank)
XCTAssertLessThan(TransferHealth.downloading.sortRank, TransferHealth.seeding.sortRank)
}
@MainActor
func testDownloadOrderAttentionFirstThenEta() {
func row(_ id: Int, eta: Int) -> TorrentRow {
try! JSONDecoder().decode(TorrentRow.self, from: Data(#"""
{"id":\#(id),"name":"t\#(id)","percentDone":0.5,"status":4,"doneDate":0,"addedDate":1,
"haveValid":1,"sizeWhenDone":2,"rateDownload":1,"rateUpload":0,"uploadRatio":0,
"eta":\#(eta),"downloadDir":"/d"}
"""#.utf8))
}
let soon = row(1, eta: 60), later = row(2, eta: 600), dead = row(3, eta: -1)
// dead needs attention first regardless of ETA; then soonest ETA.
XCTAssertTrue(DownloadsController.downloadOrder(dead, .dead, soon, .downloading))
XCTAssertTrue(DownloadsController.downloadOrder(soon, .downloading, later, .downloading))
XCTAssertFalse(DownloadsController.downloadOrder(later, .downloading, soon, .downloading))
}
/// A row from a pre-Part-E cli (no error/peers fields) still decodes + classifies.
func testRowWithoutDebugFieldsDecodesAndClassifies() throws {
let json = #"""
{"id":1,"name":"X","percentDone":0.5,"status":4,"doneDate":0,"addedDate":1,
"haveValid":1,"sizeWhenDone":2,"rateDownload":1000,"rateUpload":0,
"uploadRatio":0,"eta":60,"downloadDir":"/d"}
"""#
let row = try JSONDecoder().decode(TorrentRow.self, from: Data(json.utf8))
XCTAssertNil(row.error)
XCTAssertNil(row.peersConnected)
XCTAssertEqual(row.health(), .downloading)
}
}