diff --git a/modules/mesh-delivery-indexer/cmd/mesh-delivery-indexer/packages_integration_test.go b/modules/mesh-delivery-indexer/cmd/mesh-delivery-indexer/packages_integration_test.go index cac7840e..26ab6b14 100644 --- a/modules/mesh-delivery-indexer/cmd/mesh-delivery-indexer/packages_integration_test.go +++ b/modules/mesh-delivery-indexer/cmd/mesh-delivery-indexer/packages_integration_test.go @@ -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.