diff --git a/modules/distribution/internal/holder/holder_test.go b/modules/distribution/internal/holder/holder_test.go index 444760bd4..1e202aab9 100644 --- a/modules/distribution/internal/holder/holder_test.go +++ b/modules/distribution/internal/holder/holder_test.go @@ -224,6 +224,7 @@ const builder = "ace.mesh-build-go" // TestTheHolderOfTheTwoImageSeats holds design 51's holder cases at the unit level (CAT-D1, D2, D3, D3b, D4, D4b, D5): // one table or case per rule, the store front's. func TestTheHolderOfTheTwoImageSeats(t *testing.T) { + t.Run("a publish is checked against the builder's reservation", reservedChecksAPublishAgainstTheReservation) blob := []byte(strings.Repeat("a", 3000)) part := Part{Digest: digestOf(blob), Size: int64(len(blob))} req := func(id string) PublishRequest { @@ -243,14 +244,14 @@ func TestTheHolderOfTheTwoImageSeats(t *testing.T) { if a, _ := b.h.Publish(ArtifactSeat, builder, req("t1")); !reflect.DeepEqual(a.Missing, []string{part.Digest}) { t.Errorf("resumed publish = %+v", a) } - // A chunk that is neither the cursor nor 0 is refused; a chunk 0 again is a part lacked travelling whole again - // (mesh-delivery's parts.Receiver.Take, 1966/AC203-1, AC203-2): its earlier chunks are dropped and it is taken. + // A chunk 0 again starts the part afresh (it travels whole again, design 51 Publishing); a chunk that is neither the + // cursor nor 0 is refused, naming the cursor. + if _, err := b.h.PublishPart(ArtifactSeat, builder, PartRequest{Transfer: "t1", Digest: part.Digest, Sequence: 0, Data: blob[:1000]}); err != nil { + t.Errorf("a chunk 0 sent again was refused: %v", err) + } if _, err := b.h.PublishPart(ArtifactSeat, builder, PartRequest{Transfer: "t1", Digest: part.Digest, Sequence: 2, Data: blob[:1000]}); err == nil { t.Error("a chunk out of sequence was taken: the transfer goes on from the chunks held") } - if _, err := b.h.PublishPart(ArtifactSeat, builder, PartRequest{Transfer: "t1", Digest: part.Digest, Sequence: 0, Data: blob[:1000]}); err != nil { - t.Errorf("a chunk 0 again was refused: %v", err) - } a, err = b.h.PublishPart(ArtifactSeat, builder, PartRequest{Transfer: "t1", Digest: part.Digest, Sequence: 1, Last: true, Data: blob[1000:]}) if err != nil || !a.Ended || len(b.said) != 1 || b.said[0].event != EventPublished || b.said[0].body.Reference == "" { t.Fatalf("last chunk = %+v, %v; said %+v", a, err, b.said) @@ -290,12 +291,12 @@ func TestTheHolderOfTheTwoImageSeats(t *testing.T) { _, err := b.h.Publish(ArtifactSeat, builder, req("t")) return err }, "at their cap"}, - {"a version the builder did not number", func(b *bed) error { + {"a version the builder did not reserve", func(b *bed) error { b.h.Builder = fakeBuilder{ok: false} b.store.has[part.Digest] = true // held already: the publish ends at once _, err := b.h.Publish(ArtifactSeat, builder, req("t")) return err - }, "the builder did not number it"}, + }, "the builder did not reserve it"}, {"an image on the artifact seat", func(b *bed) error { r := req("t") r.Kind = KindImage @@ -847,9 +848,9 @@ func TestTheHolderOfTheTwoImageSeats(t *testing.T) { if err := json.Unmarshal(raw, &m); err != nil { t.Fatal(err) } - // The builder's question is its published package, taken by its series (ADR 0634 §1). - if m.Packages["git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds"] != "0.1" { - t.Errorf("packages %v: want builds of series 0.1", m.Packages) + // The reservation is asked through the seat mesh-builds, so the manifest takes no package of the builder (design 47 §381). + if len(m.Packages) != 0 { + t.Errorf("packages %v: want none", m.Packages) } // E15: the provision artifact-store retires (ADR 0632 §3); the bootstrap keeps it as an alias on port 5100 while // the running node-engines still find the store by it (issue 1966), and nothing else is provided or served. @@ -915,19 +916,34 @@ func TestTheHolderOfTheTwoImageSeats(t *testing.T) { // Running review F2: incoming asks the bus 8 GiB, the most the objects template allows, equal to IncomingCap // (said only where no binding is read); transfers keeps for good, the holder dropping an idle one by its key // in idle, a state of keys with their own time to live. + // The image registry is a foundation part (design 47 G §584): its bus state is in its old sections, incoming in + // `objects`, the others in `state`. var req struct { - Requires []struct { - Name string `json:"name"` - Options map[string]any `json:"options"` - } `json:"requires"` + Objects []struct { + Name string `json:"name"` + MaxMiB uint64 `json:"max-mib"` + } `json:"objects"` + State []json.RawMessage `json:"state"` } _ = json.Unmarshal(raw, &req) opts := map[string]map[string]any{} - for _, r := range req.Requires { - opts[r.Name] = r.Options + for _, e := range req.State { + var o map[string]any + if json.Unmarshal(e, &o) != nil { + var name string + _ = json.Unmarshal(e, &name) + o = map[string]any{"name": name} + } + opts[fmt.Sprint(o["name"])] = o } - if mib, _ := opts[IncomingObjects]["max-mib"].(float64); uint64(mib)<<20 != IncomingCap { - t.Errorf("incoming asks %v MiB, IncomingCap is %d bytes: want them equal", opts[IncomingObjects]["max-mib"], uint64(IncomingCap)) + var incoming uint64 + for _, o := range req.Objects { + if o.Name == IncomingObjects { + incoming = o.MaxMiB + } + } + if incoming<<20 != IncomingCap { + t.Errorf("incoming asks %v MiB, IncomingCap is %d bytes: want them equal", incoming, uint64(IncomingCap)) } if _, ok := opts[TransfersState]["ttl-seconds"]; ok { t.Errorf("transfers has a lifetime %v: the bus would drop a transfer's key and leave its parts", opts[TransfersState])