Files
mesh-catalog/checks/requiredmodules/main_test.go
T
jschoubben 62fe1cc36d
mesh/check failed (4): unit: git.novox.be/novox/m…; and 3 more | 62fe1cc36d30 on f2b332de73d6 | judged by the candidate's mesh-build-go at e8757a23634d
mesh/delivery-group group feat/registry-milestone rejected: composed together: the checker's verdict at the members' heads (8a80e8e86858): unit: git.novox.be/n…
mesh/delivery closed: a newer head of the same pull request
mesh-build-go requires the checker client it imports; a check refuses any module importing a mesh module its go.mod does not require (issue 1921, issue 1966)
Quick fix: add the one require to mesh-build-go's go.mod (a minute). Thorough fix, chosen because the kind was met twice (a
local go.work resolving what go.mod never names) and hides itself from every local build: checks/requiredmodules reads every
go.mod and Go source (tests and tagged files included), finds the owning module by the longest module line among the
repositories beside, and fails in go test and the repository check before any push. The scan over the seven group heads
found this one instance.

Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
2026-11-07 04:23:47 +01:00

79 lines
3.4 KiB
Go

package main
import (
"os"
"path/filepath"
"strings"
"testing"
)
func tree(t *testing.T, files map[string]string) string {
t.Helper()
root := t.TempDir()
for p, c := range files {
full := filepath.Join(root, p)
if err := os.MkdirAll(filepath.Dir(full), 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(full, []byte(c), 0o644); err != nil {
t.Fatal(err)
}
}
return root
}
const aMod = "module git.novox.be/novox/r/a\n\ngo 1.22\n"
const bMod = "module git.novox.be/novox/r/b/sub\n\ngo 1.22\n"
// A module that imports a package of a mesh module its go.mod does not require is refused, in a test file and behind a
// build tag too; the module's own packages, a required module's and a nested module's (only when required) are not.
func TestAModuleImportsOnlyWhatItRequires(t *testing.T) {
src := func(imp string) string { return "package x\n\nimport _ \"" + imp + "\"\n" }
for _, row := range []struct {
name string
files map[string]string
want string
}{
{"its own package", map[string]string{"a/go.mod": aMod, "a/x.go": src("git.novox.be/novox/r/a/other")}, ""},
{"a required module", map[string]string{"a/go.mod": aMod + "\nrequire git.novox.be/novox/r/b/sub v0.0.0\n", "a/x.go": src("git.novox.be/novox/r/b/sub/pkg"), "b/go.mod": bMod}, ""},
{"a required module in a block", map[string]string{"a/go.mod": aMod + "\nrequire (\n\tgit.novox.be/novox/r/b/sub v0.0.0 // indirect\n)\n", "a/x.go": src("git.novox.be/novox/r/b/sub/pkg"), "b/go.mod": bMod}, ""},
{"a module not required", map[string]string{"a/go.mod": aMod, "a/x.go": src("git.novox.be/novox/r/b/sub/pkg"), "b/go.mod": bMod}, "x.go imports git.novox.be/novox/r/b/sub/pkg"},
{"a test file", map[string]string{"a/go.mod": aMod, "a/x_test.go": src("git.novox.be/novox/r/b/sub/pkg"), "b/go.mod": bMod}, "x_test.go imports"},
{"an integration file", map[string]string{"a/go.mod": aMod, "a/x.go": "//go:build integration\n\n" + src("git.novox.be/novox/r/b/sub/pkg"), "b/go.mod": bMod}, "x.go imports"},
{"a module the longest owner is not", map[string]string{"a/go.mod": aMod + "\nrequire git.novox.be/novox/r/b v0.0.0\n", "a/x.go": src("git.novox.be/novox/r/b/sub/pkg"), "b/go.mod": "module git.novox.be/novox/r/b\n", "b/sub/go.mod": bMod}, "does not require"},
{"a testdata fixture", map[string]string{"a/go.mod": aMod, "a/testdata/x.go": src("git.novox.be/novox/r/b/sub/pkg"), "a/x.go": "package x\n"}, ""},
{"an outside module", map[string]string{"a/go.mod": aMod, "a/x.go": src("github.com/x/y")}, ""},
} {
t.Run(row.name, func(t *testing.T) {
got, err := Findings([]string{tree(t, row.files)}, nil)
if err != nil {
t.Fatal(err)
}
if all := strings.Join(got, "\n"); (row.want == "") != (all == "") || !strings.Contains(all, row.want) {
t.Fatalf("findings = %q, want one containing %q", all, row.want)
}
})
}
}
// The script's run of this check over the real tree (novox/hq ADR 0529 clause 2): the repositories cloned beside it, when
// the check says where, tell which module owns a path.
func TestEveryCatalogueModuleRequiresWhatItImports(t *testing.T) {
var known []string
if beside := os.Getenv("MESH_CHECK_BESIDE"); beside != "" {
es, _ := os.ReadDir(beside)
for _, e := range es {
if e.IsDir() && e.Name() != "mesh-catalog" {
known = append(known, filepath.Join(beside, e.Name()))
}
}
}
got, err := Findings([]string{filepath.Join("..", "..")}, known)
if err != nil {
t.Fatal(err)
}
for _, f := range got {
t.Error(f)
}
}