DLV-I19, I20 [i]: the indexer's whole-module test keeps a verdict's and a trunk build's out-of-step files and reads a pull request again by hand

Cases in TestAMeshSDKMergeMovesOnlyTheModulesImportingAChangedPackage: the checker's verdict event keeps a pull request's
files, a trunk build end raises generated-types-out-of-step and a clean one clears it, as indexer_out_of_step reads them;
indexer_seat_definitions_again, asked through takeins, reads a pull request's head and indexer_seat_definition answers it.

Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
This commit is contained in:
2026-11-04 14:39:32 +01:00
parent d15d66fc47
commit f7a6118e61
@@ -17,6 +17,8 @@ import (
"git.novox.be/novox/mesh-sdk/go/buscompose"
"git.novox.be/novox/mesh-sdk/go/delivery"
"git.novox.be/novox/mesh-contracts/go/seats/meshdeliverychecker"
"mesh-delivery-indexer/internal/index"
)
@@ -51,7 +53,7 @@ func TestAMeshSDKMergeMovesOnlyTheModulesImportingAChangedPackage(t *testing.T)
m1: {"go.mod": "f1", "go.sum": "f2", "stdio.go": "f3", "announce/announce.go": "f4", "buildstep/step.go": "f5"},
m2: {"go.mod": "f1", "go.sum": "f2", "stdio.go": "f3", "announce/announce.go": "f4", "buildstep/step.go": "f6"},
}
var packages, seatDefs jetstream.KeyValue
var packages, seatDefs, findings, takeIns jetstream.KeyValue
js, ctx, _, modules := startIndexer(t, func(context.Context, buildLog) {}, func(ctx context.Context, js jetstream.JetStream) {
var err error
if packages, err = js.CreateKeyValue(ctx, jetstream.KeyValueConfig{Bucket: delivery.PackagesBucket, History: delivery.PackagesHistory}); err != nil {
@@ -81,6 +83,20 @@ func TestAMeshSDKMergeMovesOnlyTheModulesImportingAChangedPackage(t *testing.T)
Subjects: []string{"mesh.stream.mesh-delivery-indexer.event." + index.SeatDefinitionChangedEvent}}); err != nil {
t.Fatal(err)
}
// DLV-I19, I20: the indexer's findings and takeins states, and the checker's stream asks with the indexer's durable
// consumer, which carries the checker's verdict event.
if findings, err = js.CreateKeyValue(ctx, jetstream.KeyValueConfig{Bucket: findingsBucket, History: 1}); err != nil {
t.Fatal(err)
}
if takeIns, err = js.CreateKeyValue(ctx, jetstream.KeyValueConfig{Bucket: index.TakeInsBucket, History: 1}); err != nil {
t.Fatal(err)
}
if _, err := js.CreateStream(ctx, jetstream.StreamConfig{Name: checkerAsksStream, Subjects: []string{meshdeliverychecker.HolderSubjectVerdict(delivery.CheckerModule)}}); err != nil {
t.Fatal(err)
}
if _, err := js.CreateOrUpdateConsumer(ctx, checkerAsksStream, jetstream.ConsumerConfig{Durable: "n1_mesh-delivery-indexer", AckPolicy: jetstream.AckExplicitPolicy}); err != nil {
t.Fatal(err)
}
})
merged := func(repo string, number int, merge string, f delivery.Forge) {
t.Helper()
@@ -246,6 +262,69 @@ func TestAMeshSDKMergeMovesOnlyTheModulesImportingAChangedPackage(t *testing.T)
if n := info.CachedInfo().State.Msgs; n != 2 {
t.Errorf("seat-definition-changed said %d times, want 2", n)
}
// DLV-I20 [i]: a pull request's check verdict naming out-of-step files keeps them; a trunk build end of the builder's log
// naming them raises generated-types-out-of-step, and only a clean build end of the same module clears it. DLV-I19 [i]:
// indexer_out_of_step answers both, from the states the indexer wrote.
verdict, _ := json.Marshal(meshdeliverychecker.VerdictHolderEvent{Repository: "novox/mesh-contracts", Pull: 82, Head: badHead, Verdict: "fail", OutOfStep: []string{"go/seats/git/types.go"}})
if _, err := js.Publish(ctx, meshdeliverychecker.HolderSubjectVerdict(delivery.CheckerModule), verdict); err != nil {
t.Fatal(err)
}
logEnd := func(outcome string, files ...string) {
t.Helper()
raw, err := delivery.EncodeBuildLogEntry(delivery.BuildLogEntry{Event: delivery.BuildEndedEvent, Module: "mesh-contracts", FP: "src2:mesh-contracts",
Repository: "novox/mesh-contracts", Directory: delivery.RootPath, Commit: contractsMerge, Node: "n1", At: time.Now().UTC(), Outcome: outcome})
if err != nil {
t.Fatal(err)
}
var e map[string]any
_ = json.Unmarshal(raw, &e)
if len(files) > 0 {
e["out-of-step"] = files // BuildLogEntry.OutOfStep, the builder's field (J3), written by its name here
}
raw, _ = json.Marshal(e)
if _, err := js.Publish(ctx, buscompose.LogSubject(delivery.BuilderModule, delivery.BuilderLog)+".mesh-contracts", raw); err != nil {
t.Fatal(err)
}
}
logEnd(delivery.BuildFailed, "go/seats/git/types.go")
outOfStep := func(want int) []index.OutOfStepRow {
t.Helper()
var rows []index.OutOfStepRow
for deadline := time.Now().Add(20 * time.Second); time.Now().Before(deadline); time.Sleep(50 * time.Millisecond) {
if rows, err = index.OutOfStepOf(jsSource{ctx, seatDefs}, jsSource{ctx, findings}); err == nil && len(rows) == want {
return rows
}
}
t.Fatalf("indexer_out_of_step = %+v (%v) within 20 s, want %d rows", rows, err, want)
return nil
}
if rows := outOfStep(2); rows[0].Module != "mesh-contracts" || !strings.Contains(rows[0].Summary, "types.go") || rows[1].Pull != "novox/mesh-contracts#82" {
t.Errorf("indexer_out_of_step = %+v, want the trunk's finding and the pull request's files", rows)
}
logEnd(delivery.BuildDone)
if rows := outOfStep(1); rows[0].Source != index.SourcePull {
t.Errorf("after a clean build end indexer_out_of_step = %+v, want the pull request's files alone", rows)
}
// DLV-I19 [i]: indexer_seat_definitions_again for a pull request, asked through the takeins state as the tool asks it,
// reads the head with its own manifest; indexer_seat_definition then answers the pull request's entry beside the trunk's.
const goodHead = "7777777777777777777777777777777777777777"
seatFiles[goodHead] = map[string]string{"module.json": contracts, "seats/index.json": `{"format":1,"seats":["git"]}`,
"seats/git/seat.json": strings.Replace(git, "ADR 0111", "ADR 0200", 1)}
key, value, err := index.NewSeatDefinitionsAgain("mesh-contracts", 83, goodHead, "the forge did not answer", "person.op", time.Now())
if err != nil {
t.Fatal(err)
}
if _, err := takeIns.Put(ctx, key, value); err != nil {
t.Fatal(err)
}
p83 := index.SeatDefinitionKey("git", index.SourcePull, "novox/mesh-contracts", 83)
entry(p83, func(e index.SeatDefinitionEntry) bool { return e.Commit == goodHead && e.Digest != "" })
if a, err := index.SeatDefinitionOf(jsSource{ctx, seatDefs}, nil, "git", "novox/mesh-contracts", 83); err != nil || a.Answered != "novox/mesh-contracts#83" ||
a.Entry.Commit != goodHead || a.Trunk == nil || a.Trunk.Digest != trunk.Digest {
t.Errorf("indexer_seat_definition of the pull request = %+v, %v", a, err)
}
}
// seatFiles are mesh-contracts' files by commit, as gitea_get_file answers them.