mesh/delivery delivered
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.
93 lines
3.6 KiB
Go
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
|
|
}
|