Files
mesh-controller/internal/inventory/collection_lately_test.go
T
jschoubben 0741880d31
mesh/delivery delivered
mesh/check checking 0741880d3137 on 760351b4ae1b
Keep a fresh build's archives from the controller's own sweep (issue 1933)
A sweep read what it keeps before what was ever recorded, so a take-in's
build recorded between the two reads, by a concurrent take-in off the
plans' hold, was eligible and let go of seconds after the take-in read
it; a new module's build is unkept until it is registered. Now the sweep
reads the records first and keeps what a build recorded within the hour
or an open plan names, and names every reference it lets go of; a take-in
holds every artifact in the store before recording, failing on one the
store lacks; and RecordBuild clears artifact_collected as RecordMirrored
does.
2026-10-24 02:44:20 +02:00

93 lines
3.6 KiB
Go

package inventory
import (
"context"
"testing"
"time"
)
// 1933/AC1: a build recorded while a sweep reads the records is never offered to let go of. The record lands between the
// sweep's two reads (what it keeps, and what was ever recorded), whichever it reads first: on 2026-10-24 01:51 a
// concurrent take-in's route-proxy build landed between them, read as recorded and not kept, and was let go of seconds
// after the take-in read its archive.
func TestABuildRecordedWhileTheRecordsAreReadIsNotOffered(t *testing.T) {
const old, fresh = "artifact-store://x/app@sha256:01", "artifact-store://y/files/blobs/sha256:02"
reads, landed := 0, false
// read answers what the records hold at the moment of the read; the take-in's RecordBuild lands just after the
// first read, before the second.
read := func(before, after func()) {
if landed {
after()
} else {
before()
}
reads++
if reads == 1 {
landed = true
}
}
recorded := func(context.Context) (out []string, _ error) {
read(func() { out = []string{old} }, func() { out = []string{old, fresh} })
return out, nil
}
keepSet := func(context.Context) (out map[string][]string, _ error) {
// Once recorded, the keep set keeps it as recorded lately.
read(func() { out = map[string][]string{} }, func() { out = map[string][]string{fresh: {KeptByRecentRecord}} })
return out, nil
}
collected := func(context.Context) (map[string]bool, error) { return map[string]bool{}, nil }
states, err := artifactStates(t.Context(), recorded, keepSet, collected)
if err != nil {
t.Fatal(err)
}
for _, s := range states {
if s.Reference == fresh && s.State == ArtifactEligible {
t.Fatalf("a build recorded between the sweep's reads is offered to let go of: %+v", states)
}
}
}
// 1933/AC1: an artifact a build recorded within the last hour, or a build a plan that has not ended names, is kept
// whatever else the records say: a new module's first build is not registered yet, and a definition naming it is not
// written yet, while its take-in runs.
func TestAFreshBuildOrOneAnOpenPlanNamesIsKept(t *testing.T) {
now := time.Date(2026, 10, 24, 1, 52, 0, 0, time.UTC)
made := func(id, reference string, at time.Time) Build {
return Build{ID: id, Module: "route-proxy", At: at,
Made: []Artifact{{Name: "files", Kind: "archive", Reference: reference}}}
}
const (
fresh = "artifact-store://route-proxy/files/blobs/sha256:58bd41dc"
planned = "artifact-store://route-proxy/files/blobs/sha256:0ld91a"
stale = "artifact-store://route-proxy/files/blobs/sha256:5ta1e"
)
builds := []Build{
made("key-ee3448e0-1", fresh, now.Add(-10*time.Second)),
made("key-planned-1", planned, now.Add(-3*time.Hour)),
made("key-stale-1", stale, now.Add(-2*time.Hour)),
{ID: "failed-1", Module: "route-proxy", At: now, Failed: "no", Made: []Artifact{{Reference: "artifact-store://f@sha256:ff"}}},
}
kept := keptLately(builds, map[string]bool{"key-planned-1": true}, now, KeptLately)
if !has(kept[fresh], KeptByRecentRecord) {
t.Errorf("an archive recorded 10 s ago is not kept as recorded lately: %v", kept)
}
if !has(kept[planned], KeptByOpenPlan) || has(kept[planned], KeptByRecentRecord) {
t.Errorf("an archive an open plan names is not kept by that plan alone: %v", kept)
}
if len(kept[stale]) > 0 {
t.Errorf("an archive recorded two hours ago and named by no open plan is kept: %v", kept[stale])
}
if len(kept["artifact-store://f@sha256:ff"]) > 0 {
t.Errorf("a failed build keeps what it names: %v", kept)
}
}
func has(whys []string, why string) bool {
for _, w := range whys {
if w == why {
return true
}
}
return false
}