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) } } 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) } }