Read a node's adoption from every declaration, so the host knows which modules are untaken (hq ADR 0100)
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
package declaration
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Defends novox/hq ADR 0100: every declaration says whether the node is adopted and which of its
|
||||
// modules are taken, and the host refuses one it cannot read that from unambiguously.
|
||||
|
||||
const adoptedResources = `"resources":[
|
||||
{"id":"hello-web.page","type":"file","path":"/var/lib/hello-web/index.html","content":"a\n"},
|
||||
{"id":"hello-web.server","type":"container","name":"hello-web","image":"sha256:` + sixtyFour + `"},
|
||||
{"id":"hello-web.data","type":"directory","path":"/var/lib/hello-web"}
|
||||
]`
|
||||
|
||||
const sixtyFour = "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
|
||||
func TestAnAdoptionIsReadWithTheDeclaration(t *testing.T) {
|
||||
d, err := Parse([]byte(`{"adoption":{"taken":["postgres"],"untaken":{"hello-web":["hello-web.page","hello-web.server"]}},
|
||||
"declaration":1,` + adoptedResources + `}`))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if d.Adoption == nil {
|
||||
t.Fatal("the adoption was dropped")
|
||||
}
|
||||
if len(d.Adoption.Taken) != 1 || d.Adoption.Taken[0] != "postgres" {
|
||||
t.Errorf("taken read as %v", d.Adoption.Taken)
|
||||
}
|
||||
if module, ok := d.Adoption.UntakenModuleOf("hello-web.server"); !ok || module != "hello-web" {
|
||||
t.Errorf("the container's untaken module read as %q, %v", module, ok)
|
||||
}
|
||||
if _, ok := d.Adoption.UntakenModuleOf("hello-web.data"); ok {
|
||||
t.Error("a resource the adoption does not name was said to be untaken")
|
||||
}
|
||||
}
|
||||
|
||||
func TestADeclarationWithNoAdoptionIsConverged(t *testing.T) {
|
||||
d, err := Parse([]byte(`{"declaration":1,` + adoptedResources + `}`))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if d.Adoption != nil {
|
||||
t.Errorf("a declaration saying nothing about adoption read as adopted: %+v", d.Adoption)
|
||||
}
|
||||
if _, ok := d.Adoption.UntakenModuleOf("hello-web.page"); ok {
|
||||
t.Error("a converged node has an untaken module")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAnAdoptionNamingAnUnknownIDIsRefused(t *testing.T) {
|
||||
refusal := refusalFor(t, `{"adoption":{"taken":[],"untaken":{"hello-web":["hello-web.missing"]}},
|
||||
"declaration":1,`+adoptedResources+`}`)
|
||||
if !strings.Contains(strings.Join(refusal.Problems, "\n"), "hello-web.missing") {
|
||||
t.Errorf("the unknown id was not named: %v", refusal.Problems)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAnAdoptionMayOnlyHoldFilesAndContainers(t *testing.T) {
|
||||
refusal := refusalFor(t, `{"adoption":{"taken":[],"untaken":{"hello-web":["hello-web.data"]}},
|
||||
"declaration":1,`+adoptedResources+`}`)
|
||||
if !strings.Contains(strings.Join(refusal.Problems, "\n"), "only a file or a container") {
|
||||
t.Errorf("a directory was accepted as holdable: %v", refusal.Problems)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAnIDUnderTwoModulesIsRefused(t *testing.T) {
|
||||
refusal := refusalFor(t, `{"adoption":{"taken":[],"untaken":{"a":["hello-web.page"],"b":["hello-web.page"]}},
|
||||
"declaration":1,`+adoptedResources+`}`)
|
||||
if !strings.Contains(strings.Join(refusal.Problems, "\n"), "both") {
|
||||
t.Errorf("an id under two modules was accepted: %v", refusal.Problems)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAModuleBothTakenAndUntakenIsRefused(t *testing.T) {
|
||||
refusal := refusalFor(t, `{"adoption":{"taken":["hello-web"],"untaken":{"hello-web":["hello-web.page"]}},
|
||||
"declaration":1,`+adoptedResources+`}`)
|
||||
if !strings.Contains(strings.Join(refusal.Problems, "\n"), "both taken and untaken") {
|
||||
t.Errorf("a module both taken and untaken was accepted: %v", refusal.Problems)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTheMeshsOwnResourcesAreNeverUntaken(t *testing.T) {
|
||||
refusal := refusalFor(t, `{"adoption":{"taken":[],"untaken":{"x":["adoption.guard"]}},
|
||||
"declaration":1,"resources":[
|
||||
{"id":"adoption.guard","type":"file","path":"/etc/mesh/guard.nft","content":"x"}]}`)
|
||||
if !strings.Contains(strings.Join(refusal.Problems, "\n"), "belongs to no module") {
|
||||
t.Errorf("an adoption. id was accepted as untaken: %v", refusal.Problems)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAnAdoptionWithAnUnknownFieldIsRefused(t *testing.T) {
|
||||
refusalFor(t, `{"adoption":{"taken":[],"held":["x"]},"declaration":1,`+adoptedResources+`}`)
|
||||
}
|
||||
|
||||
func TestACarriedBundleCannotSayTheNodeIsAdopted(t *testing.T) {
|
||||
_, err := ParseTrusted([]byte(`{"adoption":{"taken":[]},"declaration":1,` + adoptedResources + `}`))
|
||||
if err == nil || !strings.Contains(err.Error(), "only the mesh can say") {
|
||||
t.Fatalf("a bundle claiming adoption was not refused: %v", err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user