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
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
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")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user