a9c1997fbc
gates / gates (push) Successful in 1m17s
internal/upwatch: exact per-container counters from the Docker Engine API, per-app judging (upload >= max(5 Mbit/s, 25% of the line) for 15 min; CPU >= max(150%, 50% x cores) for 30 min), explainers qBittorrent / Transmission / Plex, app_unexplained_upload / app_unexplained_cpu + _cleared (hub 0.169.0). The off-site push is sampled once a second for the line (a lower bound). qBittorrent limit = 50% of the line, the household's limit always wins. 20 red-proofs. Spike + design: felhom.eu audits/SPIKE-upload-watch-2026-10-23.md, architecture/08 section 9. Not released.
37 lines
1.2 KiB
Go
37 lines
1.2 KiB
Go
package metrics
|
|
|
|
import (
|
|
"io"
|
|
"log"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// The upload watch's baseline: per-minute sums across the app's containers, p95, only the named containers.
|
|
// RED-PROOF: take the p95 per container instead of the per-minute SUM → 2 + 1 = 3 reads as 2 → fails.
|
|
func TestStackTxP95Mbps_SumsContainersPerMinute(t *testing.T) {
|
|
st, err := NewMetricsStore(filepath.Join(t.TempDir(), "m.db"), log.New(io.Discard, "", 0))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer st.Close()
|
|
t0 := time.Date(2026, 10, 1, 0, 0, 0, 0, time.UTC).Unix()
|
|
var a, b, other int64
|
|
for i := int64(0); i < 200; i++ {
|
|
ts := t0 + i*60
|
|
st.InsertContainerMetrics([]ContainerSample{
|
|
{Timestamp: ts, ContainerName: "nextcloud", NetTxBytes: a},
|
|
{Timestamp: ts, ContainerName: "nextcloud-db", NetTxBytes: b},
|
|
{Timestamp: ts, ContainerName: "qbittorrent", NetTxBytes: other},
|
|
})
|
|
a += 2e6 / 8 * 60 // 2 Mbit/s
|
|
b += 1e6 / 8 * 60 // 1 Mbit/s
|
|
other += 500e6 / 8 * 60
|
|
}
|
|
p95, minutes, err := st.StackTxP95Mbps([]string{"nextcloud", "nextcloud-db"}, time.Unix(t0, 0))
|
|
if err != nil || minutes != 199 || p95 < 2.99 || p95 > 3.01 {
|
|
t.Fatalf("p95 = %v over %d minutes, err %v — want 3 Mbit/s over 199", p95, minutes, err)
|
|
}
|
|
}
|