The gate judged a module by what the mesh saw from outside, so a container that crash-looped after it applied passed it. Each machine's node-engine now states the health of every long-running resource it runs; the controller keeps the newest statement per machine, raises module.<module>.<machine>.unhealthy on the second statement in a row, clears it on the first that does not say it, and the gate passes a module only when every long-running resource of it is stated healthy since the send. An engine that states nothing is judged as before.
85 lines
2.5 KiB
Go
85 lines
2.5 KiB
Go
package link
|
|
|
|
import (
|
|
"go/parser"
|
|
"go/token"
|
|
"io/fs"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/novox/mesh-controller/internal/broker"
|
|
)
|
|
|
|
// Every subject the controller consumes is a kind with a contract, and every test a contract names
|
|
// exists (novox/hq to-be 45 Phase 2, ADR 0227 rule 2).
|
|
func TestEveryConsumedKindHasAContract(t *testing.T) {
|
|
// What the controller can be handed, from the subjects it is granted and the ones it derives.
|
|
subjects := []string{EnrolSubject, BuiltSubject, ReportSubject("anchor"), AliveSubject("anchor"),
|
|
ToolsAliveSubject("anchor"), HealthSubject("anchor"), "mesh.mod.postgres.event.provisioner.failing"}
|
|
subjects = append(subjects, broker.ControllerFollows...)
|
|
kinds := map[string]bool{}
|
|
for _, s := range subjects {
|
|
kind, known := kindOfSubject(s)
|
|
if !known {
|
|
if strings.Contains(s, "*") {
|
|
continue // a pattern among the follows; its concrete subject is listed above
|
|
}
|
|
t.Errorf("the controller follows %s and has no kind for it", s)
|
|
continue
|
|
}
|
|
kinds[kind] = true
|
|
}
|
|
for kind := range kinds {
|
|
c, ok := Contracts[kind]
|
|
switch {
|
|
case !ok:
|
|
t.Errorf("the controller consumes %s and no contract says how an older one is told from a newer", kind)
|
|
case (c.Ordered == "") == (c.Unordered == ""):
|
|
t.Errorf("%s's contract says neither, or both, how it is ordered and why it need not be: %+v", kind, c)
|
|
case c.Ordered != "" && len(c.Tests) == 0:
|
|
t.Errorf("%s is ordered and no test delivers the newer and then the older", kind)
|
|
}
|
|
}
|
|
for kind := range Contracts {
|
|
if !kinds[kind] {
|
|
t.Errorf("a contract for %s, which the controller does not consume", kind)
|
|
}
|
|
}
|
|
|
|
// Every test named exists in this repository.
|
|
exists := map[string]bool{}
|
|
fset := token.NewFileSet()
|
|
err := filepath.WalkDir("../..", func(path string, d fs.DirEntry, err error) error {
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if d.IsDir() && (d.Name() == "vendor" || d.Name() == ".git") {
|
|
return filepath.SkipDir
|
|
}
|
|
if d.IsDir() || !strings.HasSuffix(path, "_test.go") {
|
|
return nil
|
|
}
|
|
f, err := parser.ParseFile(fset, path, nil, 0)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for name, obj := range f.Scope.Objects {
|
|
if obj.Kind.String() == "func" && strings.HasPrefix(name, "Test") {
|
|
exists[name] = true
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for kind, c := range Contracts {
|
|
for _, name := range c.Tests {
|
|
if !exists[name] {
|
|
t.Errorf("%s's contract names %s, which no test in this repository is", kind, name)
|
|
}
|
|
}
|
|
}
|
|
}
|