mesh/repo-check head efca168c5522 merged into trunk 0e372c87f1df beside mesh-catalog#457@896bd883 +1 more — pass: its merge-check.sh passed
mesh/merge-gate head efca168c5522 merged into trunk 0e372c87f1df — pass: group feat/r4e composed: every machine composes with the change as it did without …
mesh/delivery covered after its stop: a later walk that contains it was delivered: plan-1792707174627079192 (novox/mesh-delivery at b714eab9 into main, d…
mesh/delivery-group group feat/r4e closed: a member was closed before the group merged
mesh/check failed: unit: ..test: node:internal/modules/esm/resolve:989 | efca168c5522 on b714eab995a5 | unit 2092 run, 0 kept, 3 skipped | integration…
R4e round 2 finding R2-1, ADR 0521: nothing in the delivery plan orders the forge module before the bridge, and the forge module's durable consumer keeps its deliver policy when its filters change, so a check.status emitted before it consumed the event was lost. The forge module now watches the checker's owed state and writes mesh/check itself, once per revision. The bridge emits no check.status, declares no emits, and neither reads the checker's owed nor hears its stream; OwedAct still refuses mesh/check. The integration test shows the bridge calls no tool and publishes nothing of its own when the checker owes mesh/check.
211 lines
7.9 KiB
Go
211 lines
7.9 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"log"
|
|
"strings"
|
|
"testing"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/delivery"
|
|
)
|
|
|
|
const (
|
|
headA = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
headB = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
|
|
)
|
|
|
|
type memRevisions map[string]uint64
|
|
|
|
func (m memRevisions) Get(_ context.Context, key string) (uint64, bool, error) {
|
|
r, ok := m[key]
|
|
return r, ok, nil
|
|
}
|
|
func (m memRevisions) Put(_ context.Context, key string, rev uint64) error { m[key] = rev; return nil }
|
|
|
|
type tcall struct {
|
|
key string
|
|
body string
|
|
}
|
|
|
|
// forgeFake records the calls and answers each from refuse, a map from a tool to its refusal.
|
|
type forgeFake struct {
|
|
calls []tcall
|
|
refuse map[string]string
|
|
}
|
|
|
|
func (f *forgeFake) call(_ context.Context, key string, body any) (json.RawMessage, error) {
|
|
b, _ := json.Marshal(body)
|
|
f.calls = append(f.calls, tcall{key, string(b)})
|
|
if w, ok := f.refuse[key]; ok {
|
|
return nil, errors.New(w)
|
|
}
|
|
return json.RawMessage(`{}`), nil
|
|
}
|
|
|
|
func newPerformer(f *forgeFake) (*performer, *fakePub, memRevisions, *bytes.Buffer) {
|
|
pub, done, logs := &fakePub{}, memRevisions{}, &bytes.Buffer{}
|
|
return &performer{call: f.call, pub: pub, done: done, logger: log.New(logs, "", 0)}, pub, done, logs
|
|
}
|
|
|
|
// The values are the SDK's own encoding (mesh-sdk go/delivery EncodeOwed, EncodeMerge), the keys its OwedKey.
|
|
func owedKV(t *testing.T, repository string, number int, act string, o delivery.Owed) (string, []byte) {
|
|
t.Helper()
|
|
key, err := delivery.OwedKey(repository, number, headA, act)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
v, err := delivery.EncodeOwed(o)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return key, v
|
|
}
|
|
|
|
func TestAnOwedStatusIsSetOnceForARevision(t *testing.T) { // 1341/AC1
|
|
f := &forgeFake{}
|
|
p, _, _, _ := newPerformer(f)
|
|
key, v := owedKV(t, "novox/mesh-delivery", 12, "status=mesh/merge-gate",
|
|
delivery.Owed{Act: delivery.OwedStatus, Context: "mesh/merge-gate", State: "success", Text: "all green", Target: "https://forge.example/p/12"})
|
|
p.owed(context.Background(), key, 7, v)
|
|
if len(f.calls) != 1 || f.calls[0].key != "gitea.gitea_commit_status" ||
|
|
f.calls[0].body != `{"context":"mesh/merge-gate","description":"all green","owner":"novox","repo":"mesh-delivery","sha":"`+headA+`","state":"success","target_url":"https://forge.example/p/12"}` {
|
|
t.Fatalf("calls = %+v", f.calls)
|
|
}
|
|
p.owed(context.Background(), key, 7, v) // the same revision seen again (a restart's replay)
|
|
if len(f.calls) != 1 {
|
|
t.Errorf("the same revision called the tool again: %+v", f.calls)
|
|
}
|
|
p.owed(context.Background(), key, 8, v) // a new revision of the key is a new act
|
|
if len(f.calls) != 2 {
|
|
t.Errorf("a new revision was not performed: %+v", f.calls)
|
|
}
|
|
}
|
|
|
|
func TestViewNoteAndCommentEachCallTheirToolOnce(t *testing.T) { // 1341/AC2
|
|
f := &forgeFake{}
|
|
p, _, _, _ := newPerformer(f)
|
|
for _, c := range []struct {
|
|
act string
|
|
o delivery.Owed
|
|
}{
|
|
{"view", delivery.Owed{Act: delivery.OwedView, Text: "the view"}},
|
|
{"note", delivery.Owed{Act: delivery.OwedNote, Text: "a line", Ref: "mesh-plan"}},
|
|
{"comment.1", delivery.Owed{Act: delivery.OwedComment, Text: "hello"}},
|
|
} {
|
|
key, v := owedKV(t, "novox/mesh-delivery", 12, c.act, c.o)
|
|
p.owed(context.Background(), key, 1, v)
|
|
p.owed(context.Background(), key, 1, v)
|
|
}
|
|
var tools []string
|
|
for _, c := range f.calls {
|
|
tools = append(tools, c.key)
|
|
}
|
|
if got := strings.Join(tools, " "); got != "gitea.gitea_delivery_view gitea.gitea_note_append gitea.gitea_add_comment" {
|
|
t.Errorf("calls = %s", got)
|
|
}
|
|
}
|
|
|
|
func TestARefusedActIsWrittenOnForgeOnceAndNotRetried(t *testing.T) { // 1341/AC3
|
|
f := &forgeFake{refuse: map[string]string{"gitea.gitea_add_comment": "the pull request is locked"}}
|
|
p, pub, _, _ := newPerformer(f)
|
|
key, v := owedKV(t, "novox/mesh-delivery", 12, "comment.1", delivery.Owed{Act: delivery.OwedComment, Text: "hello"})
|
|
p.owed(context.Background(), key, 3, v)
|
|
p.owed(context.Background(), key, 3, v)
|
|
if len(f.calls) != 1 {
|
|
t.Errorf("the refused act was tried %d times at one revision", len(f.calls))
|
|
}
|
|
if len(pub.subjects) != 1 || pub.subjects[0] != "mesh.stream.mesh-delivery-forge-bridge.event.forge.novox.mesh-delivery.refused" {
|
|
t.Fatalf("published on %v", pub.subjects)
|
|
}
|
|
m, err := delivery.DecodeForge(pub.data[0])
|
|
if err != nil || m.Kind != delivery.ForgeRefused || m.Act != "comment.1" || m.Number != 12 || m.Head != headA || m.Words != "the pull request is locked" {
|
|
t.Errorf("message %+v err %v", m, err)
|
|
}
|
|
f.refuse = nil
|
|
p.owed(context.Background(), key, 4, v) // only a new revision tries again
|
|
if len(f.calls) != 2 {
|
|
t.Errorf("a new revision was not tried: %d calls", len(f.calls))
|
|
}
|
|
}
|
|
|
|
func TestAnOwedValueThatCannotBeReadIsLoggedAndNotRetried(t *testing.T) {
|
|
f := &forgeFake{}
|
|
p, pub, done, logs := newPerformer(f)
|
|
p.owed(context.Background(), "not-a-key", 2, []byte(`{}`))
|
|
if len(f.calls) != 0 || len(pub.subjects) != 0 {
|
|
t.Errorf("calls %v published %v", f.calls, pub.subjects)
|
|
}
|
|
if !strings.Contains(logs.String(), "not-a-key") {
|
|
t.Errorf("log %q does not name the key", logs.String())
|
|
}
|
|
if rev, ok := done["owed.not-a-key"]; !ok || rev != 2 {
|
|
t.Errorf("revision kept = %v %v", rev, ok)
|
|
}
|
|
}
|
|
|
|
func mergeKV(t *testing.T, m delivery.Merge) []byte {
|
|
t.Helper()
|
|
v, err := delivery.EncodeMerge(m)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return v
|
|
}
|
|
|
|
func twoMembers(a, b delivery.MergeState) delivery.Merge {
|
|
return delivery.Merge{Group: "g", Ask: "merge.g.0123456789ab",
|
|
Approved: map[string]string{delivery.ApprovedKey("novox/mesh-sdk", 4): headB, delivery.ApprovedKey("novox/mesh-delivery", 12): headA},
|
|
Pulls: []delivery.MergePull{
|
|
{Head: delivery.Head{Repository: "novox/mesh-delivery", Number: 12, Head: headA}, State: a, Commit: map[bool]string{true: "c1"}[a == delivery.MergeMerged]},
|
|
{Head: delivery.Head{Repository: "novox/mesh-sdk", Number: 4, Head: headB}, State: b, Commit: map[bool]string{true: "c2"}[b == delivery.MergeMerged]},
|
|
}}
|
|
}
|
|
|
|
func TestAMergeRevisionMergesOnlyTheMemberHanded(t *testing.T) { // 1342/AC1
|
|
f := &forgeFake{}
|
|
p, _, _, _ := newPerformer(f)
|
|
m := twoMembers(delivery.MergeMerging, delivery.MergeMerged)
|
|
p.merges(context.Background(), "g", 5, mergeKV(t, m))
|
|
want := `{"approved_heads":["novox/mesh-delivery@` + headA + `","novox/mesh-sdk@` + headB + `"],"head":"` + headA + `","number":12,"owner":"novox","repo":"mesh-delivery"}`
|
|
if len(f.calls) != 1 || f.calls[0].key != "gitea.gitea_merge_pull_request" || f.calls[0].body != want {
|
|
t.Fatalf("calls = %+v", f.calls)
|
|
}
|
|
p.merges(context.Background(), "g", 5, mergeKV(t, m))
|
|
if len(f.calls) != 1 {
|
|
t.Errorf("a revision merged twice: %+v", f.calls)
|
|
}
|
|
}
|
|
|
|
func TestARefusedMergeIsWrittenOnForgeOnceAndNotRetried(t *testing.T) { // 1342/AC2
|
|
f := &forgeFake{refuse: map[string]string{"gitea.gitea_merge_pull_request": "novox/mesh-delivery#12 is not merged: its head moved"}}
|
|
p, pub, _, _ := newPerformer(f)
|
|
v := mergeKV(t, twoMembers(delivery.MergeMerging, delivery.MergeMerged))
|
|
p.merges(context.Background(), "g", 5, v)
|
|
p.merges(context.Background(), "g", 5, v)
|
|
if len(f.calls) != 1 || len(pub.data) != 1 {
|
|
t.Fatalf("calls %d messages %d, want one each", len(f.calls), len(pub.data))
|
|
}
|
|
m, err := delivery.DecodeForge(pub.data[0])
|
|
if err != nil || m.Kind != delivery.ForgeRefused || m.Repository != "novox/mesh-delivery" || m.Number != 12 || m.Head != headA ||
|
|
m.Act != "merge" || m.Words != "novox/mesh-delivery#12 is not merged: its head moved" {
|
|
t.Errorf("message %+v err %v", m, err)
|
|
}
|
|
f.refuse = nil
|
|
p.merges(context.Background(), "g", 6, v)
|
|
if len(f.calls) != 2 {
|
|
t.Errorf("a new revision was not tried: %d calls", len(f.calls))
|
|
}
|
|
}
|
|
|
|
func TestAMergeWithTwoHandedStopsAtTheFirstRefusal(t *testing.T) { // ADR 0441 §3
|
|
f := &forgeFake{refuse: map[string]string{"gitea.gitea_merge_pull_request": "no"}}
|
|
p, pub, _, _ := newPerformer(f)
|
|
p.merges(context.Background(), "g", 1, mergeKV(t, twoMembers(delivery.MergeMerging, delivery.MergeMerging)))
|
|
if len(f.calls) != 1 || len(pub.data) != 1 {
|
|
t.Errorf("calls %d messages %d, want the first refusal to stop the pass", len(f.calls), len(pub.data))
|
|
}
|
|
}
|