DLV-C3, DLV-C6 (tag-wanted): the checker's whole-module test hears tag-wanted at the definition's subject and builds on the published
A case of the existing group test (no new integration test): the bed's streams are the manifest's (checks with preview.written, asks with verdict and tag-wanted at the mesh-delivery-checker definition's subjects) and the shared events stream with the registry seats' published. A group whose mesh-sdk member has no preview yet is read at its head, says tag-wanted whose body decodes strictly into the definition's type, is not judged before the Go seat's published, and then builds mesh-delivery against v0.1.15-feat-x.1. The verdict half of DLV-C6 follows DLV-C2. Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
@@ -22,6 +23,9 @@ import (
|
||||
"github.com/nats-io/nats.go/jetstream"
|
||||
|
||||
gobuild "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep"
|
||||
"git.novox.be/novox/mesh-contracts/go/seats/gopackageregistry"
|
||||
"git.novox.be/novox/mesh-contracts/go/seats/meshdeliverychecker"
|
||||
"git.novox.be/novox/mesh-contracts/go/seats/npmpackageregistry"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/buildrun"
|
||||
"git.novox.be/novox/mesh-sdk/go/announce"
|
||||
"git.novox.be/novox/mesh-sdk/go/delivery"
|
||||
@@ -91,6 +95,8 @@ type fakeBuildModules struct {
|
||||
beside map[string][]string
|
||||
// names are the nodes' names the last check ask carried, for the names check (ADR 0567 §12).
|
||||
names []string
|
||||
// packages are, by repository, the package versions the last Go check ask of it carried (StepAsk.Packages).
|
||||
packages map[string]delivery.PackageVersions
|
||||
}
|
||||
|
||||
func (f *fakeBuildModules) count(tool string) int {
|
||||
@@ -197,6 +203,12 @@ func (f *fakeBuildModules) serve(t *testing.T, module string, kept jetstream.Key
|
||||
if a.Check != nil {
|
||||
f.mu.Lock()
|
||||
f.names = a.Check.NodeNames
|
||||
if repository, _ := a.Check.Fetch["repository"].(string); a.Language == delivery.AskGo {
|
||||
if f.packages == nil {
|
||||
f.packages = map[string]delivery.PackageVersions{}
|
||||
}
|
||||
f.packages[repository] = a.Packages
|
||||
}
|
||||
f.mu.Unlock()
|
||||
}
|
||||
return gobuild.RunAsk(ctx, steps, a)
|
||||
@@ -220,6 +232,15 @@ func (b *bed) serveForge(t *testing.T, nc *nats.Conn) {
|
||||
var a map[string]string
|
||||
_ = json.Unmarshal(m.Data, &a)
|
||||
switch {
|
||||
case tool == "gitea_get_file" && strings.HasSuffix(a["path"], "module.json"):
|
||||
// A manifest at a member's head (design 51 *Tagged versions*): the bed's own, else the forge's 404.
|
||||
if content, ok := b.heads.Load(a["owner"] + "/" + a["repo"] + " " + a["path"] + " " + a["ref"]); ok {
|
||||
answer, _ := json.Marshal(map[string]any{"result": map[string]any{"file": map[string]any{"content": content}}, "error": "", "node": "n0"})
|
||||
_ = m.Respond(answer)
|
||||
return
|
||||
}
|
||||
answer, _ := json.Marshal(map[string]any{"result": nil, "error": "Gitea API /repos/x/contents/" + a["path"] + ": 404 Not Found", "node": "n0"})
|
||||
_ = m.Respond(answer)
|
||||
case tool == "gitea_get_file" && b.stalePin.Load():
|
||||
content := strings.Replace(string(mustRead(t, "forge-get-file-go-mod")), "cb54756c3865", "9aaa5c80ac5c", 1)
|
||||
var result map[string]any
|
||||
@@ -252,6 +273,8 @@ func mustRead(t *testing.T, name string) []byte {
|
||||
|
||||
type bed struct {
|
||||
stalePin atomic.Bool
|
||||
// heads are the manifests the forge holds at a member's head, by "<repository> <path> <ref>".
|
||||
heads sync.Map
|
||||
ctx context.Context
|
||||
js jetstream.JetStream
|
||||
buckets map[string]jetstream.KeyValue
|
||||
@@ -390,8 +413,20 @@ func startBed(t *testing.T) *bed {
|
||||
if _, err := js.CreateStream(ctx, jetstream.StreamConfig{Name: buildrun.DeadLettersStream, Subjects: []string{"mesh.events.dead.>"}}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// The checker's stream of events, which the indexer and the forge bridge hear.
|
||||
if _, err := js.CreateStream(ctx, jetstream.StreamConfig{Name: "CHECKS", Subjects: []string{"mesh.stream.mesh-delivery-checker.event.>"}}); err != nil {
|
||||
// The checker's streams as its manifest declares them (ADR 0619, ADR 0620): checks, which the indexer and the forge
|
||||
// bridge hear, and asks, with verdict and tag-wanted at the subjects the mesh-delivery-checker definition names.
|
||||
if _, err := js.CreateStream(ctx, jetstream.StreamConfig{Name: "CHECKS", Subjects: []string{meshdeliverychecker.HolderSubjectPreviewWritten(delivery.CheckerModule)}}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := js.CreateStream(ctx, jetstream.StreamConfig{Name: "ASKS", Subjects: []string{meshdeliverychecker.HolderSubjectVerdict(delivery.CheckerModule),
|
||||
meshdeliverychecker.HolderSubjectTagWanted(delivery.CheckerModule)}}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// The shared events stream with the package registry seats' published, and the checker's durable consumer of it.
|
||||
if _, err := js.CreateStream(ctx, jetstream.StreamConfig{Name: process.EventsStream, Subjects: []string{gopackageregistry.SubjectPublished, npmpackageregistry.SubjectPublished}}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := js.CreateOrUpdateConsumer(ctx, process.EventsStream, jetstream.ConsumerConfig{Durable: "n1_mesh-delivery-checker", AckPolicy: jetstream.AckExplicitPolicy}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for name, history := range map[string]int{delivery.CheckerVerdictsBucket: delivery.CheckerVerdictsHistory, delivery.CheckerKeptBucket: delivery.CheckerKeptHistory,
|
||||
@@ -830,6 +865,51 @@ func TestAMemberNamingAMeshSDKCommitOffTheTrunkIsJudgedAndNotRefused(t *testing.
|
||||
if v := b.verdict(t, key, ended); v.State != delivery.VerdictPass {
|
||||
t.Fatalf("verdict = %+v", v)
|
||||
}
|
||||
|
||||
// DLV-C3, DLV-C6 (design 51 *Tagged versions*, ADR 0607 §3, §5, ADR 0620): a group whose mesh-sdk member declares a Go
|
||||
// package, read at its head with no preview yet, says tag-wanted on the checker's stream asks, at the subject and in the body the mesh-delivery-checker
|
||||
// definition names; once the Go seat's published of the tagged version is heard, the other member is built against it.
|
||||
const sdkRepo = "novox/mesh-sdk"
|
||||
b.setTrunk(t, map[string]string{repo: trunk, sdkRepo: trunk})
|
||||
// The member carries no preview of its merge yet, so its manifest is read at its head (the package new in the group).
|
||||
b.heads.Store(sdkRepo+" module.json "+head2, `{"module":"mesh-sdk","build":{"artifacts":[{"name":"go","kind":"package","language":"go","paths":["go"]}]}}`)
|
||||
asks, err := b.js.OrderedConsumer(b.ctx, "ASKS", jetstream.OrderedConsumerConfig{FilterSubjects: []string{meshdeliverychecker.HolderSubjectTagWanted(delivery.CheckerModule)}})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sdk := pull(sdkRepo, 12, head2)
|
||||
sdk.Modules, sdk.Fps = []string{"mesh-sdk"}, map[string]delivery.CandidateModule{"mesh-sdk": {FP2: "src2:" + strings.Repeat("e", 64)}}
|
||||
key = b.candidate(t, "feat/x", pull(repo, 8, head1), sdk)
|
||||
msg, err := asks.Next(jetstream.FetchMaxWait(20 * time.Second))
|
||||
if err != nil {
|
||||
t.Fatalf("no tag-wanted on the stream asks: %v", err)
|
||||
}
|
||||
var wanted meshdeliverychecker.TagWantedHolderEvent
|
||||
dec := json.NewDecoder(bytes.NewReader(msg.Data()))
|
||||
dec.DisallowUnknownFields()
|
||||
if err := dec.Decode(&wanted); err != nil {
|
||||
t.Fatalf("tag-wanted %s is not the definition's body: %v", msg.Data(), err)
|
||||
}
|
||||
if want := (meshdeliverychecker.TagWantedHolderEvent{Repository: sdkRepo, Branch: "feat/x", Head: head2, Module: "mesh-sdk", Package: "go", Pull: 12}); wanted != want {
|
||||
t.Errorf("tag-wanted = %+v, want %+v", wanted, want)
|
||||
}
|
||||
if v, err := b.buckets[delivery.CheckerVerdictsBucket].Get(b.ctx, key); err == nil && !strings.Contains(string(v.Value()), `"running"`) {
|
||||
t.Fatalf("the group was judged before its tagged version was published: %s", v.Value())
|
||||
}
|
||||
published, _ := json.Marshal(gopackageregistry.PublishedEvent{Holder: "gitea", Kind: "package", Name: "mesh-sdk/go", Commit: head2, Tag: "feat-x", Version: "0.1.15-feat-x.1",
|
||||
Digest: "sha256:" + strings.Repeat("0", 64)})
|
||||
if _, err := b.js.Publish(b.ctx, gopackageregistry.SubjectPublished, published); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if v := b.verdict(t, key, ended); v.State != delivery.VerdictPass {
|
||||
t.Fatalf("the group's verdict = %+v", v)
|
||||
}
|
||||
b.fake.mu.Lock()
|
||||
got := b.fake.packages[repo]
|
||||
b.fake.mu.Unlock()
|
||||
if got[check.SDKModulePath] != "v0.1.15-feat-x.1" {
|
||||
t.Errorf("mesh-delivery was built against %v, want mesh-sdk's Go module at the group's tagged version v0.1.15-feat-x.1", got)
|
||||
}
|
||||
}
|
||||
|
||||
// triesStore is the tries bucket as the tools write it.
|
||||
@@ -938,7 +1018,9 @@ func TestATryIsJudgedAndItsEndWrittenWithNoStatusOwed(t *testing.T) {
|
||||
// the readable ones, which is what grants the forge module its read of owed (ADR 0495 §2-§3, ADR 0521; R4e finding R2-1).
|
||||
func TestTheCheckerSaysOwedReadableOnTheBus(t *testing.T) { // R2-1
|
||||
b := startBed(t)
|
||||
if _, err := b.js.CreateStream(b.ctx, jetstream.StreamConfig{Name: "EVENTS", Subjects: []string{"mesh.mod.*.event.>"}}); err != nil {
|
||||
// The bed's shared events stream carries the registry seats' published; the module events go on it too.
|
||||
if _, err := b.js.UpdateStream(b.ctx, jetstream.StreamConfig{Name: process.EventsStream, Subjects: []string{"mesh.mod.*.event.>",
|
||||
gopackageregistry.SubjectPublished, npmpackageregistry.SubjectPublished}}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
b.start(t, nil)
|
||||
|
||||
Reference in New Issue
Block a user