mesh/merge-gate head 35c7662f895f merged into trunk dc36536e199e — pass: the change touches no module of the mesh's graph
mesh/repo-check head 35c7662f895f merged into trunk dc36536e199e — fail: its merge-check.sh failed: --- FAIL: TestTheInstallersFirstUserListIsWhatTheContro…
mesh/delivery superseded: a newer head of the same pull request
Reviews 251 of mesh-controller#315 and ADR 0356 v4 (hq issue 652): a removal without the lease removes nothing; a module no longer registered loses its declared-config key with its event; a listed mirror is never reported as undeclared state; only the audit and a mirror's own writer name a mirror's bucket; and the mirrors' list and the writers table agree. The store test's line moves where it merges with the integration branch's own new lines. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
83 lines
2.9 KiB
Go
83 lines
2.9 KiB
Go
package recordmirror
|
|
|
|
import (
|
|
"go/ast"
|
|
"go/parser"
|
|
"go/token"
|
|
"io/fs"
|
|
"path/filepath"
|
|
"slices"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/novox/mesh-controller/internal/broker"
|
|
)
|
|
|
|
// mayNameAMirror are the files of the controller that may name a record mirror's bucket outside their tests:
|
|
// where the buckets are defined, asserted and granted (internal/broker), the list a reader names in `reads`
|
|
// (internal/catalogue/state.go), and each mirror's own writer (this package and the loop that runs it). The
|
|
// audit of a mirror against its store (ADR 0289 §4, issue 419) joins this list when it is built.
|
|
var mayNameAMirror = []string{
|
|
"cmd/mesh-controller/record_mirrors.go",
|
|
"internal/broker/controller_buckets.go",
|
|
"internal/broker/writers.go",
|
|
"internal/catalogue/state.go",
|
|
}
|
|
|
|
// **Nothing in the controller reads a mirror to decide anything** (ADR 0289 §19 as ADR 0356 §2 changes it): no
|
|
// file of the controller's packages outside its tests names a mirror's bucket, by its Go name or its bus name,
|
|
// but the audit and a mirror's own writer. A reader elsewhere fails here, naming the file and what it named.
|
|
func TestOnlyTheAuditAndAMirrorsWriterReadAMirror(t *testing.T) {
|
|
names := []string{"AssignmentsBucket", "DeclaredConfigBucket", "MirrorAssignments", "MirrorDeclaredConfig",
|
|
"ControllerMirrors", "Assignments", "DeclaredConfig", "Mirrors"}
|
|
var buckets []string
|
|
for _, m := range broker.ControllerMirrors() {
|
|
buckets = append(buckets, broker.BucketName(broker.ControllerSeat, m))
|
|
}
|
|
root := filepath.Join("..", "..")
|
|
var found []string
|
|
for _, dir := range []string{"cmd", "internal"} {
|
|
err := filepath.WalkDir(filepath.Join(root, dir), func(path string, e fs.DirEntry, err error) error {
|
|
if err != nil || e.IsDir() || !strings.HasSuffix(path, ".go") || strings.HasSuffix(path, "_test.go") {
|
|
return err
|
|
}
|
|
rel, err := filepath.Rel(root, path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
rel = filepath.ToSlash(rel)
|
|
if strings.HasPrefix(rel, "internal/recordmirror/") || slices.Contains(mayNameAMirror, rel) {
|
|
return nil
|
|
}
|
|
f, err := parser.ParseFile(token.NewFileSet(), path, nil, 0)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
ast.Inspect(f, func(n ast.Node) bool {
|
|
switch n := n.(type) {
|
|
case *ast.SelectorExpr:
|
|
pkg, ok := n.X.(*ast.Ident)
|
|
if ok && (pkg.Name == "broker" || pkg.Name == "recordmirror") && slices.Contains(names, n.Sel.Name) {
|
|
found = append(found, rel+": "+pkg.Name+"."+n.Sel.Name)
|
|
}
|
|
case *ast.BasicLit:
|
|
for _, b := range buckets {
|
|
if n.Kind == token.STRING && strings.Contains(n.Value, b) {
|
|
found = append(found, rel+": "+n.Value)
|
|
}
|
|
}
|
|
}
|
|
return true
|
|
})
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
if len(found) > 0 {
|
|
t.Fatalf("a package of the controller reads a record mirror, which only the audit and the mirror's "+
|
|
"writer may (ADR 0289 §19, ADR 0356 §2):\n %s", strings.Join(found, "\n "))
|
|
}
|
|
}
|