App v0.2.26 and gateway 0.1.20
Client: seek controls, Bazarr subtitle download and cast panel in the player; MDBList ratings strip; episode and schedule detail pages; series pace estimate; what's new panel; install-permission onboarding step; synced per-profile preferences; Emby outage banner. Gateway: rebuilt admin console (one fragment per page), preference history and restore, merged Continue Watching, Emby health probe, subtitle selection and Bazarr download, structured request logging with per-request identity, and embedded build version. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
2675e6d82b
commit
4a4df7a73c
@@ -99,6 +99,87 @@ func TestTracearrSessionTerminalRequiresCompletedState(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestImportDueMeasuresElapsedTimeRatherThanProcessUptime(t *testing.T) {
|
||||
now := time.Date(2026, 8, 4, 12, 0, 0, 0, time.UTC)
|
||||
at := func(d time.Duration) *time.Time {
|
||||
value := now.Add(-d)
|
||||
return &value
|
||||
}
|
||||
const incremental = 5 * time.Minute
|
||||
const full = 24 * time.Hour
|
||||
|
||||
for _, testCase := range []struct {
|
||||
name string
|
||||
state store.TracearrImportState
|
||||
wantFull bool
|
||||
wantDue bool
|
||||
wantSkip bool
|
||||
}{
|
||||
{
|
||||
name: "never imported runs a full pass",
|
||||
state: store.TracearrImportState{}, wantFull: true, wantDue: true,
|
||||
},
|
||||
{
|
||||
// The restart case: without persisted stamps every boot re-imported.
|
||||
name: "recent import is not repeated after a restart",
|
||||
state: store.TracearrImportState{
|
||||
LastIncrementalAt: at(30 * time.Second), LastFullAt: at(2 * time.Hour),
|
||||
},
|
||||
wantSkip: true,
|
||||
},
|
||||
{
|
||||
name: "elapsed incremental interval is due",
|
||||
state: store.TracearrImportState{
|
||||
LastIncrementalAt: at(6 * time.Minute), LastFullAt: at(2 * time.Hour),
|
||||
},
|
||||
wantDue: true,
|
||||
},
|
||||
{
|
||||
// A gateway restarted daily never reconciled: the full ticker restarted too.
|
||||
name: "elapsed full interval wins over the incremental one",
|
||||
state: store.TracearrImportState{
|
||||
LastIncrementalAt: at(6 * time.Minute), LastFullAt: at(25 * time.Hour),
|
||||
},
|
||||
wantFull: true, wantDue: true,
|
||||
},
|
||||
{
|
||||
name: "a stamp in the future does not strand the importer",
|
||||
state: store.TracearrImportState{
|
||||
LastIncrementalAt: at(-time.Hour), LastFullAt: at(-time.Hour),
|
||||
},
|
||||
wantFull: true, wantDue: true,
|
||||
},
|
||||
} {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
gotFull, gotDue := importDue(testCase.state, now, incremental, full)
|
||||
if testCase.wantSkip {
|
||||
if gotDue {
|
||||
t.Fatal("import ran when none was owed")
|
||||
}
|
||||
return
|
||||
}
|
||||
if gotDue != testCase.wantDue || gotFull != testCase.wantFull {
|
||||
t.Fatalf("full=%v due=%v, want full=%v due=%v",
|
||||
gotFull, gotDue, testCase.wantFull, testCase.wantDue)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestImportDueRespectsDisabledIntervals(t *testing.T) {
|
||||
now := time.Date(2026, 8, 4, 12, 0, 0, 0, time.UTC)
|
||||
if _, due := importDue(store.TracearrImportState{}, now, 0, 0); due {
|
||||
t.Fatal("import was due with scheduling turned off")
|
||||
}
|
||||
stale := now.Add(-48 * time.Hour)
|
||||
state := store.TracearrImportState{LastIncrementalAt: &stale, LastFullAt: &stale}
|
||||
full, due := importDue(state, now, 5*time.Minute, 0)
|
||||
if !due || full {
|
||||
t.Fatalf("full=%v due=%v, want an incremental pass with full reconciliation off",
|
||||
full, due)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNextDailyRebuildUsesConfiguredLocalHour(t *testing.T) {
|
||||
location := time.FixedZone("NZST", 12*60*60)
|
||||
now := time.Date(2026, 7, 31, 5, 30, 0, 0, location)
|
||||
|
||||
Reference in New Issue
Block a user