Files
Esa Kataja dfbd74b0d2 add: queue total ETA from current encode speed
The queue card now shows an estimated time to clear: current job remaining +
sum(pending source durations) / current speed. Durations come from a
path+mtime-keyed cache that probes each file once in the background (ffprobe
format=duration, header-only), so the 1s poll never re-probes; entries are
pruned to the live queue. No speed (idle/held) -> no estimate; files still
being probed mark it partial (shown as '~Xh+').

Closes #9
2026-06-21 20:48:37 +03:00

63 lines
1.8 KiB
Go

package server
import (
"testing"
"time"
)
func TestQueueETASeconds(t *testing.T) {
// No speed → can't extrapolate.
if got := queueETASeconds(100, 3600, 0); got != 0 {
t.Errorf("speed 0: got %d, want 0", got)
}
// current remaining 600s + 1800s of queued source at 0.5x (=3600s) = 4200s.
if got := queueETASeconds(600, 1800, 0.5); got != 4200 {
t.Errorf("got %d, want 4200", got)
}
// At 2x, 1800s of source encodes in 900s; + 600 remaining = 1500.
if got := queueETASeconds(600, 1800, 2); got != 1500 {
t.Errorf("got %d, want 1500", got)
}
// Empty queue → just the current job's remaining.
if got := queueETASeconds(600, 0, 1); got != 600 {
t.Errorf("got %d, want 600", got)
}
}
// waitCached polls Get (the probe resolves on a background goroutine).
func waitCached(c *durationCache, p string, mt time.Time) (float64, bool) {
for i := 0; i < 200; i++ {
if sec, ok := c.Get(p, mt); ok {
return sec, true
}
time.Sleep(2 * time.Millisecond)
}
return 0, false
}
func TestDurationCache(t *testing.T) {
c := newDurationCache(func(p string) (float64, error) { return 42, nil })
mt := time.Unix(1000, 0)
if _, ok := c.Get("/a.mkv", mt); ok {
t.Fatal("first Get should miss")
}
if sec, ok := waitCached(c, "/a.mkv", mt); !ok || sec != 42 {
t.Fatalf("after probe: got %v ok=%v, want 42 true", sec, ok)
}
// A changed mtime invalidates the entry.
if _, ok := c.Get("/a.mkv", time.Unix(2000, 0)); ok {
t.Error("changed mtime should miss")
}
if _, ok := waitCached(c, "/a.mkv", time.Unix(2000, 0)); !ok {
t.Fatal("re-probe under new mtime should cache")
}
// Retain drops entries for paths not in the keep set.
c.Retain([]string{"/b.mkv"})
if _, ok := c.Get("/a.mkv", time.Unix(2000, 0)); ok {
t.Error("Retain should have dropped /a.mkv")
}
}