package inventory import ( "strings" "testing" "github.com/novox/mesh-controller/internal/catalogue" ) // A setting is judged where it is stored (novox/hq ADR 0163, rule 6): one that cannot compose with // the module's definition is refused naming the node, the module, the layer and the key, and is not // kept; one that reaches nothing is refused the same way. func TestASettingIsJudgedWhereItIsStored(t *testing.T) { inv := fresh(t) ctx := t.Context() if _, err := inv.AddNode(ctx, "anchor"); err != nil { t.Fatal(err) } web := catalogue.Manifest{Module: "web", Version: "1", Resources: []map[string]any{ {"id": "server", "type": "container", "name": "web", "image": "x", "ports": []any{"8080"}}, {"id": "conf", "type": "file", "path": "/etc/web.json", "content": "{}", "merge": "json"}, }} plain := catalogue.Manifest{Module: "plain", Version: "1", Resources: []map[string]any{{"id": "server", "type": "container", "name": "plain", "image": "x"}}} for _, m := range []catalogue.Manifest{web, plain} { if err := inv.RegisterModule(ctx, m, Source{}); err != nil { t.Fatal(err) } } err := inv.SetSettings(ctx, "anchor", "web", map[string]any{catalogue.PortsSetting: map[string]any{"9999": 10000}}) for _, want := range []string{"refused: web on anchor", `layer "anchor"`, "9999"} { if err == nil || !strings.Contains(err.Error(), want) { t.Errorf("a port the module does not publish: %v, want %q", err, want) } } if layers, _ := inv.SettingsFor(ctx, "anchor", "web"); len(layers) != 0 { t.Fatalf("the refused layer was stored: %v", layers) } // A key that reaches nothing is refused too, where the spelling can still be fixed; a module // with a mergeable file takes any key. err = inv.SetSettings(ctx, "", "plain", map[string]any{"colour": "blue"}) if err == nil || !strings.Contains(err.Error(), "reach nothing") || !strings.Contains(err.Error(), `"colour"`) { t.Fatalf("a stray key was stored: %v", err) } if err := inv.SetSettings(ctx, "", "web", map[string]any{"colour": "blue"}); err != nil { t.Fatal(err) } // The mesh-wide layer is under the node's when the node's is judged. if err := inv.SetSettings(ctx, "anchor", "web", map[string]any{catalogue.PortsSetting: map[string]any{"8080": 10000}}); err != nil { t.Fatal(err) } // A kept network is for an adopted machine only (rule 4). keep := map[string]any{catalogue.NetworksSetting: map[string]any{"server": []any{"predecessor_default"}}} err = inv.SetSettings(ctx, "anchor", "plain", keep) if err == nil || !strings.Contains(err.Error(), "anchor is converged") { t.Fatalf("a kept network on a converged machine was stored: %v", err) } if err := inv.SetAdopted(ctx, "anchor", true); err != nil { t.Fatal(err) } if err := inv.SetSettings(ctx, "anchor", "plain", keep); err != nil { t.Fatal(err) } if err := inv.SetSettings(ctx, "anchor", "nothing", keep); err == nil { t.Fatal("a setting for a module the mesh does not know was stored") } }