Holds operator-channel's decided to the shared stream's 7 days (the lead's ruling of 12:5x), and each registry seat's family with it. Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
77 lines
3.6 KiB
Go
77 lines
3.6 KiB
Go
package buscompose
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"git.novox.be/novox/mesh-contracts/go/seats/containerimageregistry"
|
|
"git.novox.be/novox/mesh-contracts/go/seats/gopackageregistry"
|
|
"git.novox.be/novox/mesh-contracts/go/seats/meshbroker"
|
|
"git.novox.be/novox/mesh-contracts/go/seats/npmpackageregistry"
|
|
"git.novox.be/novox/mesh-contracts/go/seats/ociartifactregistry"
|
|
"git.novox.be/novox/mesh-contracts/go/seats/operatorchannel"
|
|
"git.novox.be/novox/mesh-sdk/go/membership"
|
|
)
|
|
|
|
// The names this package keeps for the grants part's composer (mesh-grants internal/buscompose, ADR 0593 §1) agree with
|
|
// what the runtime reads: the memberships bucket, and a log's stream and subject.
|
|
func TestTheBusNamesAgree(t *testing.T) {
|
|
if GrantsMembershipsBucket != membership.GrantsBucket {
|
|
t.Fatalf("the memberships bucket is %q here and %q in membership", GrantsMembershipsBucket, membership.GrantsBucket)
|
|
}
|
|
if MembershipKey("ace", "netcheck") != "ace.netcheck" {
|
|
t.Fatal("a membership's key is not <node>.<module>")
|
|
}
|
|
if LogStreamName("mesh-delivery-builder", "build-log") == "" || LogSubject("mesh-delivery-builder", "build-log") == "" {
|
|
t.Fatal("a log has no stream or subject")
|
|
}
|
|
// 1966/AC20: a ledger's history and snapshot subjects are one contract, which the grants part grants a ledger
|
|
// account its publish on.
|
|
if h, sn := LedgerHistorySubject("m", "records"), LedgerSnapshotSubject("m", "records"); h != "mesh.ledger.m.records.history" ||
|
|
sn != "mesh.ledger.m.records.snapshot" {
|
|
t.Fatalf("a ledger's subjects are %q and %q", h, sn)
|
|
}
|
|
// 1966/AC23: a wanted account of kind ledger for m on a names the user ledger.a.m and the own secret ledgers.
|
|
ledger := WantedAccount{User: "ledger.a.m", Kind: KindLedger, Node: "a", Module: "m", URL: "nats://10.0.0.1:4222"}
|
|
if got := (Principal{Kind: KindLedger, Node: "a", Module: "m"}).Username(); got != "ledger.a.m" {
|
|
t.Fatalf("a ledger account is named %q", got)
|
|
}
|
|
if err := ledger.Valid(); err != nil || ledger.OwnSecret() != "ledgers" {
|
|
t.Fatalf("a wanted ledger account: %v, held in %q", err, ledger.OwnSecret())
|
|
}
|
|
// mesh-broker's events are the bus module's own stream (design 25 § 12.3, 30 days): no subject of the shared
|
|
// streams may take them, or the bus refuses the two streams as overlapping.
|
|
for _, st := range MeshStreams() {
|
|
for _, pattern := range st.Subjects {
|
|
if subjectTakes(pattern, meshbroker.SubjectCreated) {
|
|
t.Errorf("the stream %s takes mesh-broker's %s by %s", st.Name, meshbroker.SubjectCreated, pattern)
|
|
}
|
|
}
|
|
}
|
|
// A seat family on the shared events stream is kept as long as the stream keeps it: its contract says no more.
|
|
for family, days := range map[string]int{operatorchannel.Family: operatorchannel.FamilyMaxAgeDays,
|
|
npmpackageregistry.Family: npmpackageregistry.FamilyMaxAgeDays, gopackageregistry.Family: gopackageregistry.FamilyMaxAgeDays,
|
|
containerimageregistry.Family: containerimageregistry.FamilyMaxAgeDays,
|
|
ociartifactregistry.Family: ociartifactregistry.FamilyMaxAgeDays} {
|
|
for _, st := range MeshStreams() {
|
|
if st.Name == EventsStream && int64(days)*24*60*60 != int64(st.MaxAge) {
|
|
t.Errorf("the family %s says %d days, the shared events stream keeps %d s", family, days, st.MaxAge)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// subjectTakes says whether a subject pattern (`*` one token, `>` the rest) takes a subject.
|
|
func subjectTakes(pattern, subject string) bool {
|
|
p, s := strings.Split(pattern, "."), strings.Split(subject, ".")
|
|
for i, tok := range p {
|
|
switch {
|
|
case tok == ">":
|
|
return len(s) > i
|
|
case i >= len(s) || (tok != "*" && tok != s[i]):
|
|
return false
|
|
}
|
|
}
|
|
return len(p) == len(s)
|
|
}
|