2026-08-15 09:23:26 +12:00
|
|
|
package credits
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"testing"
|
|
|
|
|
"time"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// The queue is bounded, and saturation is a real state with a right answer: throw the
|
|
|
|
|
// speculation away. A queue holding forty episodes nobody has reached has stopped describing
|
|
|
|
|
// demand.
|
|
|
|
|
|
|
|
|
|
func queued(id string, priority int) Candidate {
|
|
|
|
|
return Candidate{ItemID: id, Priority: priority, LastViewed: now}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestQueueOrdersByPriority(t *testing.T) {
|
|
|
|
|
queue := NewQueue(10)
|
|
|
|
|
queue.Push(queued("ahead3", PriorityAhead3))
|
|
|
|
|
queue.Push(queued("live", PriorityLive))
|
|
|
|
|
queue.Push(queued("next", PriorityNext))
|
|
|
|
|
|
|
|
|
|
candidate, found := queue.Claim()
|
|
|
|
|
if !found || candidate.ItemID != "live" {
|
|
|
|
|
t.Fatalf("claimed %+v, want the live candidate first", candidate)
|
|
|
|
|
}
|
|
|
|
|
candidate, _ = queue.Claim()
|
|
|
|
|
if candidate.ItemID != "next" {
|
|
|
|
|
t.Fatalf("claimed %q second, want next", candidate.ItemID)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestSaturationDiscardsTheWeakestSpeculation(t *testing.T) {
|
|
|
|
|
queue := NewQueue(3)
|
|
|
|
|
queue.Push(queued("spec-a", PrioritySpeculative))
|
|
|
|
|
queue.Push(queued("spec-b", PrioritySpeculative+1))
|
|
|
|
|
queue.Push(queued("spec-c", PrioritySpeculative+2))
|
|
|
|
|
|
|
|
|
|
if queued := queue.Push(queued("live", PriorityLive)); !queued {
|
|
|
|
|
t.Fatal("a full queue refused live playback")
|
|
|
|
|
}
|
|
|
|
|
if queue.Len() != 3 {
|
|
|
|
|
t.Fatalf("queue length %d, want the limit of 3", queue.Len())
|
|
|
|
|
}
|
|
|
|
|
for _, candidate := range queue.Snapshot() {
|
|
|
|
|
if candidate.ItemID == "spec-a" {
|
|
|
|
|
t.Fatal("the weakest candidate survived saturation")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestSaturationRefusesWeakerWork(t *testing.T) {
|
|
|
|
|
queue := NewQueue(2)
|
|
|
|
|
queue.Push(queued("next-a", PriorityNext))
|
|
|
|
|
queue.Push(queued("next-b", PriorityNext))
|
|
|
|
|
|
|
|
|
|
if queue.Push(queued("spec", PrioritySpeculative)) {
|
|
|
|
|
t.Fatal("a full queue accepted work weaker than everything in it")
|
|
|
|
|
}
|
|
|
|
|
if queue.Len() != 2 {
|
|
|
|
|
t.Fatalf("queue length %d, want 2", queue.Len())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestPushMergesRatherThanDuplicating(t *testing.T) {
|
|
|
|
|
queue := NewQueue(10)
|
|
|
|
|
queue.Push(queued("bb-s06e08", PriorityAhead2))
|
|
|
|
|
queue.Push(Candidate{
|
|
|
|
|
ItemID: "bb-s06e08", Priority: PriorityNext, Reason: ReasonMultiUser,
|
|
|
|
|
UserCount: 2, LastViewed: now,
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
if queue.Len() != 1 {
|
|
|
|
|
t.Fatalf("queue length %d; the same episode must not be queued twice", queue.Len())
|
|
|
|
|
}
|
|
|
|
|
candidate, _ := queue.Claim()
|
|
|
|
|
if candidate.Priority != PriorityNext {
|
|
|
|
|
t.Fatalf("priority = %d; the stronger case should have won", candidate.Priority)
|
|
|
|
|
}
|
|
|
|
|
if candidate.UserCount != 2 {
|
|
|
|
|
t.Fatalf("UserCount = %d, want 2", candidate.UserCount)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// A weaker second viewer must never lower a candidate somebody else is about to reach.
|
|
|
|
|
func TestPushNeverLowersPriority(t *testing.T) {
|
|
|
|
|
queue := NewQueue(10)
|
|
|
|
|
queue.Push(queued("bb-s06e08", PriorityNext))
|
|
|
|
|
queue.Push(queued("bb-s06e08", PrioritySpeculative))
|
|
|
|
|
|
|
|
|
|
candidate, _ := queue.Claim()
|
|
|
|
|
if candidate.Priority != PriorityNext {
|
|
|
|
|
t.Fatalf("priority = %d, want %d", candidate.Priority, PriorityNext)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Cancelling a scan that is already reading a file, to replace it with a marginally better
|
|
|
|
|
// candidate, would waste exactly the disk activity this package exists to avoid.
|
|
|
|
|
func TestReplaceLeavesClaimedWorkAlone(t *testing.T) {
|
|
|
|
|
queue := NewQueue(10)
|
|
|
|
|
queue.Push(queued("in-flight", PriorityNext))
|
|
|
|
|
claimed, _ := queue.Claim()
|
|
|
|
|
|
|
|
|
|
queue.Replace([]Candidate{queued("fresh", PriorityNext), queued(claimed.ItemID, PriorityLive)})
|
|
|
|
|
|
|
|
|
|
for _, candidate := range queue.Snapshot() {
|
|
|
|
|
if candidate.ItemID == claimed.ItemID {
|
|
|
|
|
t.Fatal("a refresh re-queued an episode already being scanned")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
queue.Release(claimed.ItemID)
|
|
|
|
|
if queue.Push(queued(claimed.ItemID, PriorityNext)); queue.Len() != 2 {
|
|
|
|
|
t.Fatalf("queue length %d after release, want 2", queue.Len())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestClaimedItemsAreNotReQueued(t *testing.T) {
|
|
|
|
|
queue := NewQueue(10)
|
|
|
|
|
queue.Push(queued("bb-s06e08", PriorityNext))
|
|
|
|
|
claimed, _ := queue.Claim()
|
|
|
|
|
|
|
|
|
|
if queue.Push(queued(claimed.ItemID, PriorityLive)) {
|
|
|
|
|
t.Fatal("an episode being scanned was queued a second time")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestEmptyQueueClaimsNothing(t *testing.T) {
|
|
|
|
|
if _, found := NewQueue(5).Claim(); found {
|
|
|
|
|
t.Fatal("an empty queue produced work")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestQueueOrderIsTotalAndStable(t *testing.T) {
|
|
|
|
|
queue := NewQueue(10)
|
|
|
|
|
older := now.Add(-2 * time.Hour)
|
|
|
|
|
queue.Push(Candidate{ItemID: "b", Priority: PriorityNext, LastViewed: older})
|
|
|
|
|
queue.Push(Candidate{ItemID: "a", Priority: PriorityNext, LastViewed: now})
|
|
|
|
|
|
|
|
|
|
// Equal priority: the more recent demand goes first.
|
|
|
|
|
candidate, _ := queue.Claim()
|
|
|
|
|
if candidate.ItemID != "a" {
|
|
|
|
|
t.Fatalf("claimed %q; more recent demand should win a tie", candidate.ItemID)
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-08-16 12:13:51 +12:00
|
|
|
|
|
|
|
|
func TestReducingQueueLimitKeepsTheStrongestCandidates(t *testing.T) {
|
|
|
|
|
queue := NewQueue(5)
|
|
|
|
|
queue.Push(queued("weak", PrioritySpeculative))
|
|
|
|
|
queue.Push(queued("ahead", PriorityAhead2))
|
|
|
|
|
queue.Push(queued("next", PriorityNext))
|
|
|
|
|
|
|
|
|
|
queue.SetLimit(2)
|
|
|
|
|
|
|
|
|
|
pending := queue.Snapshot()
|
|
|
|
|
if len(pending) != 2 || pending[0].ItemID != "next" || pending[1].ItemID != "ahead" {
|
|
|
|
|
t.Fatalf("reduced queue = %+v; want the two strongest candidates", pending)
|
|
|
|
|
}
|
|
|
|
|
}
|