Files
felhom.eu/hub/internal/store/r435_windows_between_test.go
T

59 lines
2.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package store
import (
"testing"
"time"
)
// R-435: RemovedByWindowsBetween sums only windows closed inside the interval (or still open), and each
// window explains at most its hub-set max_remove — a box's count_after cannot widen it, and a window with
// no usable count_after explains exactly its cap. Only a window with no cap makes the answer unknown.
// RED-PROOF (security review 2026-10-08): drop the max_remove cap → „lying box" returns 69, not 34 → FAILS.
func TestR435_RemovedByWindowsBetween(t *testing.T) {
s := newTestStore(t)
at := func(ts string) time.Time { v, _ := time.Parse("2006-01-02 15:04:05", ts); return v }
ins := func(cust, opened, closed string, before, after, maxRemove any) {
t.Helper()
var c any
if closed != "" {
c = closed
}
if _, err := s.db.Exec(`INSERT INTO offsite_windows (customer_id, opened_at, closes_by, closed_at, count_before, count_after, max_remove) VALUES (?, ?, ?, ?, ?, ?, ?)`,
cust, opened, opened, c, before, after, maxRemove); err != nil {
t.Fatal(err)
}
}
ins("a", "2026-10-01 03:00:00", "2026-10-01 03:10:00", 69, 60, 34) // inside → 9
ins("a", "2026-09-20 03:00:00", "2026-09-20 03:10:00", 80, 69, 40) // before the interval
ins("a", "2026-10-03 03:00:00", "2026-10-03 03:10:00", 60, 50, 30) // after the interval
ins("b", "2026-10-01 03:00:00", "2026-10-01 03:10:00", 50, 40, 25) // another customer
from, to := at("2026-09-30 00:00:00"), at("2026-10-02 00:00:00")
if n, unk := s.RemovedByWindowsBetween("a", from, to); n != 9 || unk {
t.Fatalf("a: want 9 known, got %d unknown=%v", n, unk)
}
if n, unk := s.RemovedByWindowsBetween("c", from, to); n != 0 || unk {
t.Fatalf("no window: want 0 known, got %d unknown=%v", n, unk)
}
// a box that claims it removed everything explains only the cap the hub granted
ins("l", "2026-10-01 03:00:00", "2026-10-01 03:10:00", 69, 0, 34)
if n, unk := s.RemovedByWindowsBetween("l", from, to); n != 34 || unk {
t.Fatalf("lying box: want the cap 34, got %d unknown=%v", n, unk)
}
// a timeout close (count_after −1) inside the interval → explains its cap
ins("d", "2026-10-01 03:00:00", "2026-10-01 03:40:00", 69, -1, 10)
if n, unk := s.RemovedByWindowsBetween("d", from, to); n != 10 || unk {
t.Fatalf("timeout-closed window: want its cap 10, got %d unknown=%v", n, unk)
}
// a window still open → explains its cap
ins("e", "2026-10-01 03:00:00", "", 69, nil, 10)
if n, unk := s.RemovedByWindowsBetween("e", from, to); n != 10 || unk {
t.Fatalf("open window: want its cap 10, got %d unknown=%v", n, unk)
}
// a window with no cap → unknown (the caller falls back to the half-rule)
ins("f", "2026-10-01 03:00:00", "2026-10-01 03:10:00", 69, 60, nil)
if _, unk := s.RemovedByWindowsBetween("f", from, to); !unk {
t.Fatal("a window with no cap must make the interval unknown")
}
}