Files
mesh-delivery/modules/mesh-delivery-forge-bridge/cmd/mesh-delivery-forge-bridge/gate_test.go
T
jschoubben efca168c55
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…
Stop the forge bridge performing mesh/check: the forge module writes it (R2-1)
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.
2026-10-22 21:40:09 +02:00

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))
}
}