package catalogue import ( "strings" "testing" ) // A module declares its own object bucket and a stream that keeps its history (ADR 0592 §5, §6, §9): both are read with // their bounds, the bucket's grant names its readers through a trusted config value as a restricted stream's does, and // an unknown key in either is refused, not passed over. func TestAModuleDeclaresAnObjectBucketAndAHistoryStream(t *testing.T) { m, err := decodeForTest([]byte(`{"module":"mesh-knowledge","version":"1",` + `"streams":[{"name":"versions","events":["version.**"],"max-mib":2048,"retention":"history","grant":{"config":"readers","events":"{key}.**"}}],` + `"objects":[{"name":"sections","max-mib":4096,"grant":{"config":"readers"}},{"name":"own","max-mib":1}]}`)) if err != nil { t.Fatal(err) } s := m.Streams[0] if !s.KeepsHistory() || s.Days() != 0 || s.Cap() != 2048 { t.Fatalf("history stream read as %+v (days %d)", s, s.Days()) } o, ok := m.ObjectsNamed("sections") if !ok || o.MaxMiB != 4096 || o.Grant == nil || o.Grant.Config != "readers" || o.Bucket(m.Module) != "mesh-knowledge_sections" { t.Fatalf("object bucket read as %+v", o) } readers := []any{map[string]any{"records": []any{"knowledge-web", "ace.mesh-view"}}} if !o.ObjectsReader(readers, "knowledge-web", "g14") || !o.ObjectsReader(readers, "mesh-view", "ace") || o.ObjectsReader(readers, "mesh-view", "g14") || o.ObjectsReader(readers, "other", "ace") { t.Fatal("the bucket's grant does not name its readers as a restricted stream's does") } own, _ := m.ObjectsNamed("own") if own.ObjectsReader(readers, "knowledge-web", "g14") { t.Fatal("a bucket with no grant is read by another module") } for name, raw := range map[string]string{ "bucket": `{"module":"x","version":"1","objects":[{"name":"a","max-mib":1,"max-age-days":3}]}`, "bucket grant": `{"module":"x","version":"1","objects":[{"name":"a","max-mib":1,"grant":{"config":"r","events":"{key}"}}]}`, } { if _, err := decodeStrictObjects(raw); err == nil || !strings.Contains(err.Error(), "object bucket") { t.Errorf("%s: an unknown key was not refused in the object bucket's words: %v", name, err) } } } func decodeStrictObjects(raw string) (Manifest, error) { m, err := decodeForTest([]byte(raw)) if err == nil && m.SetAside() != "" { return m, errString(m.SetAside()) } return m, err } type errString string func (e errString) Error() string { return string(e) }