mesh/merge-gate pass: builds gitea, mesh-delivery → novox; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery superseded: a newer delivery to the same trunk took over its walk
mesh/delivery-group group feat/delivery-checks-verb closed: a member was closed before the group merged
Reading a pull request's mesh/merge-gate and mesh/repo-check meant scraping the controller's journal: the forge clips each status to 140 characters and nothing returned the verdict whole. mesh-delivery already keeps the verdict; it now keeps the machine that ran it, the layers' modules and the report, and its checks verb joins that to the forge's statuses, read through a new gitea_commit_statuses tool that also says whether the base's protection lets the commit merge. after: novox/mesh-controller
123 lines
3.9 KiB
Go
123 lines
3.9 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"os"
|
|
"path/filepath"
|
|
"reflect"
|
|
"sort"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// The manifest says what the code does: the seat it claims and the verbs it serves, the events it follows
|
|
// and says, the tools it calls, its state — and names nothing of one installation.
|
|
|
|
type manifest struct {
|
|
Module string `json:"module"`
|
|
Claims []struct {
|
|
Name string `json:"name"`
|
|
Scope string `json:"scope"`
|
|
Serves []string `json:"serves"`
|
|
} `json:"claims"`
|
|
Seats []any `json:"seats"`
|
|
Consumes []string `json:"consumes"`
|
|
Emits []string `json:"emits"`
|
|
Invokes []string `json:"invokes"`
|
|
State []string `json:"state"`
|
|
Tools []string `json:"tools"`
|
|
}
|
|
|
|
func readManifest(t *testing.T) (manifest, string) {
|
|
t.Helper()
|
|
raw, err := os.ReadFile(filepath.Join("..", "..", "module.json"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var m manifest
|
|
if err := json.Unmarshal(raw, &m); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return m, string(raw)
|
|
}
|
|
|
|
func TestItClaimsTheDeliverySeatAndFollowsWhatItHandles(t *testing.T) {
|
|
m, raw := readManifest(t)
|
|
if m.Module != "mesh-delivery" || len(m.Claims) != 1 || m.Claims[0].Name != "mesh-delivery" || m.Claims[0].Scope != "mesh" {
|
|
t.Fatalf("claims %+v", m.Claims)
|
|
}
|
|
// The seat is the mesh's own (mesh-*): a module claims it and never declares it.
|
|
if len(m.Seats) != 0 {
|
|
t.Fatal("the manifest declares a seat; mesh-delivery is the mesh's own")
|
|
}
|
|
if !reflect.DeepEqual(m.Consumes, followed) {
|
|
t.Fatalf("consumes %v, follows %v", m.Consumes, followed)
|
|
}
|
|
if !reflect.DeepEqual(m.Emits, []string{"transition", "group"}) {
|
|
t.Fatalf("emits %v", m.Emits)
|
|
}
|
|
if !reflect.DeepEqual(m.State, []string{"deliveries", "groups"}) {
|
|
t.Fatalf("state %v", m.State)
|
|
}
|
|
// It calls exactly what its ports ask: the controller's six verbs and the forge's four tools.
|
|
want := []string{}
|
|
for _, v := range []string{"delivery-plan", "delivery-order", "delivery-check", "deliver", "delivery-stop", "delivery-walks"} {
|
|
want = append(want, "seat:"+ControllerSeat+"."+v)
|
|
}
|
|
want = append(want, "gitea.gitea_note_append", "gitea.gitea_delivery_view", "gitea.gitea_commit_status",
|
|
"gitea.gitea_commit_statuses")
|
|
if !reflect.DeepEqual(m.Invokes, want) {
|
|
t.Fatalf("invokes %v, wanted %v", m.Invokes, want)
|
|
}
|
|
for _, never := range []string{"/home/", "jochen", "g14", "shanks", "novox", "zurag", "anchor"} {
|
|
if strings.Contains(strings.ToLower(raw), never) {
|
|
t.Errorf("module.json names %q", never)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestTheToolsAgreeWithTheManifest(t *testing.T) {
|
|
m, _ := readManifest(t)
|
|
var own, verbs []string
|
|
for _, tool := range tools(&Holder{}, &listening{}) {
|
|
if strings.TrimSpace(tool.Description) == "" {
|
|
t.Errorf("%s has no description", tool.Name)
|
|
}
|
|
if seat, verb, ok := strings.Cut(tool.Name, "."); ok {
|
|
if seat != "mesh-delivery" {
|
|
t.Errorf("%s is a verb of a seat this does not hold", tool.Name)
|
|
}
|
|
verbs = append(verbs, verb)
|
|
continue
|
|
}
|
|
own = append(own, tool.Name)
|
|
}
|
|
sort.Strings(own)
|
|
if !reflect.DeepEqual(own, m.Tools) {
|
|
t.Fatalf("serves %v, lists %v", own, m.Tools)
|
|
}
|
|
if !reflect.DeepEqual(verbs, m.Claims[0].Serves) {
|
|
t.Fatalf("verbs %v, claim %v", verbs, m.Claims[0].Serves)
|
|
}
|
|
}
|
|
|
|
// The forge's and the controller's answers are read whatever wraps them.
|
|
func TestAnAnswerIsReadWhateverWrapsIt(t *testing.T) {
|
|
for _, c := range []struct {
|
|
raw string
|
|
ok bool
|
|
answer string
|
|
}{
|
|
{`{"output":"x","ok":true,"answer":{"held":true}}`, true, `{"held":true}`},
|
|
{`{"output":"refused: no plan","ok":false}`, false, ``},
|
|
{`"{\"output\":\"x\",\"ok\":true,\"answer\":[1]}"`, true, `[1]`},
|
|
{`{"content":[{"type":"text","text":"{\"output\":\"x\",\"ok\":true,\"answer\":2}"}]}`, true, `2`},
|
|
{`{"content":[{"type":"text","text":"boom"}],"isError":true}`, false, ``},
|
|
} {
|
|
answer, _, ok := answerOf(json.RawMessage(c.raw))
|
|
if ok != c.ok || (c.ok && string(answer) != c.answer) {
|
|
t.Errorf("%s → %s %v", c.raw, answer, ok)
|
|
}
|
|
}
|
|
}
|