Files
mesh-sdk/go/catalogue/naming_test.go
T

76 lines
3.4 KiB
Go

package catalogue
import (
"strings"
"testing"
)
// A provision names what the consumer is coupled to (novox/hq ADR 0027).
//
// The fault this defends against does not look like a fault: resolution succeeds, the module
// deploys, and the first query fails somewhere else entirely. Every earlier test had exactly one
// provider of each name, so no mismatch was expressible and none was caught.
func TestAModuleMayNotProvideAGenericDatabase(t *testing.T) {
for _, hidden := range []string{"database", "db", "sql", "sql-database"} {
_, err := ParseManifest([]byte(`{"module":"postgres","version":"1",
"provides":[{"name":"` + hidden + `","scope":"mesh"}]}`))
if err == nil {
t.Fatalf("providing %q was accepted; a requirement for it matches any engine", hidden)
}
for _, want := range []string{hidden, "postgres-database", "first query"} {
if !strings.Contains(err.Error(), want) {
t.Errorf("refusing %q did not mention %q, so nobody learns what to write:\n%v",
hidden, want, err)
}
}
}
}
// The rule is about coupling, not about specificity everywhere. Naming `route` after a particular
// proxy would be the same error in the other direction.
func TestARoleNameIsFineWhereTheConsumerCannotTellTheDifference(t *testing.T) {
for _, role := range []string{"route", "resolver", "artifact-store", "postgres-database"} {
if _, err := ParseManifest([]byte(`{"module":"m","version":"1",
"provides":[{"name":"` + role + `","scope":"mesh"}]}`)); err != nil {
t.Errorf("providing %q was refused, and it names what a consumer actually gets: %v",
role, err)
}
}
}
// A module may not declare an action, and it is refused where it was written.
//
// The host refuses one arriving over the link, which is the bound the whole security argument
// rests on (novox/hq ADR 0005) and is enforced in the right place. But a module's resources reach
// a machine *over* the link, so a manifest carrying an action used to be accepted here, stored,
// resolved and pushed — and then refused on the machine, in a log, with nothing tying it back to
// the manifest. Enforced at the far end only is enforced and not usable.
func TestAModuleMayNotDeclareAnAction(t *testing.T) {
_, err := ParseManifest([]byte(`{"module":"probe","version":"1","resources":[
{"id":"migrate","type":"action","command":["/bin/true"],"verify":["/bin/true"]}]}`))
if err == nil {
t.Fatal("a manifest declaring an action was accepted, and the machine would refuse it")
}
if !strings.Contains(err.Error(), "may not") || !strings.Contains(err.Error(), "0005") {
t.Errorf("the refusal does not say what rule it is: %v", err)
}
// And it says what to do instead, because "you may not" without an alternative is where a
// module author stops.
if !strings.Contains(err.Error(), "ships a program") {
t.Errorf("the refusal names no alternative: %v", err)
}
}
// Every other shape a module may declare still passes, so the check above bounds one thing.
func TestTheOtherShapesAreStillAccepted(t *testing.T) {
_, err := ParseManifest([]byte(`{"module":"probe","version":"1","resources":[
{"id":"d","type":"directory","path":"/var/lib/probe","mode":"0700"},
{"id":"f","type":"file","path":"/var/lib/probe/x","content":"x\n"},
{"id":"n","type":"network","name":"probe"},
{"id":"c","type":"container","name":"probe","image":"probe@sha256:` +
`0000000000000000000000000000000000000000000000000000000000000000"}]}`))
if err != nil {
t.Fatalf("an ordinary manifest was refused: %v", err)
}
}