package buscompose import ( "encoding/json" "os" "path/filepath" "reflect" "strings" "testing" ) // Defends issue 1377 and novox/hq ADR 0547 §5: this is the controller's bus composer copied, and it composes byte for // byte what the controller's composes. testdata/controller-user-lists.json was written by the controller's own // internal/broker (mesh-controller branch fix/1945-mesh-grants-publishes-memberships), lists and memberships, from fixtures_test.go compiled there unchanged; composed.conf is the // controller's golden of the whole server configuration. A row that differs is the copy drifting from the controller, // which is a fault while both compose (until the controller loses its lease, ADR 0547 §13). func TestTheCopiedComposerComposesAsTheControllers(t *testing.T) { raw, err := os.ReadFile(filepath.Join("testdata", "controller-user-lists.json")) if err != nil { t.Fatal(err) } var want []struct { Name, List string Missing []string Err string Memberships json.RawMessage } if err := json.Unmarshal(raw, &want); err != nil { t.Fatal(err) } fixtures := UserListFixtures() if len(want) != len(fixtures) { t.Fatalf("%d fixtures, %d lists the controller composed", len(fixtures), len(want)) } for i, f := range fixtures { t.Run(f.Name, func(t *testing.T) { if want[i].Name != f.Name { t.Fatalf("fixture %q against the controller's %q", f.Name, want[i].Name) } list, missing, err := ComposedFor(f) got := "" if err != nil { got = err.Error() } if got != want[i].Err { t.Fatalf("error %q, the controller's %q", got, want[i].Err) } if strings.Join(missing, ",") != strings.Join(want[i].Missing, ",") { t.Errorf("left out %v, the controller %v", missing, want[i].Missing) } if list != want[i].List { t.Errorf("the list differs from the controller's:\n%s", list) } // And every membership the records issue, as the controller's MembershipFor makes it (ADR 0547 §5): the // grants part publishes them. raw, err := json.Marshal(MembershipsFor(f)) if err != nil { t.Fatal(err) } var gotM, wasM any if err := json.Unmarshal(raw, &gotM); err != nil { t.Fatal(err) } if err := json.Unmarshal(want[i].Memberships, &wasM); err != nil { t.Fatal(err) } if !reflect.DeepEqual(gotM, wasM) { t.Errorf("the memberships differ from the controller's:\n%s", raw) } }) } t.Run("the controller's golden server configuration", func(t *testing.T) { seat := Seat{Name: "telegram-sender", Accepts: []string{"send"}, Emits: []string{"delivered", "failed"}} got, err := Compose( Server{ClientPort: 4222, MonitoringPort: 8222, StoreDir: "/data", TLSCert: "/tls/tls.crt", TLSKey: "/tls/tls.key", TLSCA: "/tls/ca.crt"}, []Principal{ {Kind: KindController, PasswordHash: "$2a$11$cccccccccccccccccccccc"}, {Kind: KindEnrolment, Node: "one", PasswordHash: "$2a$11$eeeeeeeeeeeeeeeeeeeeee"}, {Kind: KindNode, Node: "one", PasswordHash: "$2a$11$nnnnnnnnnnnnnnnnnnnnnn"}, {Kind: KindModule, Node: "one", Module: "telegram", Holds: []Seat{seat}, Serves: []string{"status"}, PasswordHash: "$2a$11$tttttttttttttttttttttt"}, {Kind: KindModule, Node: "two", Module: "shop", Uses: []Seat{seat}, Emits: []string{"order.placed"}, PasswordHash: "$2a$11$ssssssssssssssssssssss"}, {Kind: KindModule, Node: "two", Module: "audit", Consumes: []string{"shop.order.placed"}, PasswordHash: "$2a$11$aaaaaaaaaaaaaaaaaaaaaa"}, {Kind: KindModule, Node: "one", Module: WatchmanModule, PasswordHash: "$2a$11$wwwwwwwwwwwwwwwwwwwwww"}, {Kind: KindModule, Node: "one", Module: "nats", SnapshotsTheBus: true, Serves: []string{"nats_streams"}, PasswordHash: "$2a$11$bbbbbbbbbbbbbbbbbbbbbb"}, }) if err != nil { t.Fatal(err) } want, err := os.ReadFile(filepath.Join("testdata", "composed.conf")) if err != nil { t.Fatal(err) } if got != string(want) { t.Errorf("the configuration differs from the controller's golden:\n%s", got) } }) }