package buscompose import ( "slices" "testing" ) // A reader of a stream kept last per subject is granted what an ordered consumer of that stream uses, and a reader of // another stream only its own durable (design 47 G §556, A-4). func TestAReaderOfAStreamKeptLastPerSubjectIsGrantedItsOrderedConsumer(t *testing.T) { p := Principal{Module: "m", Node: "a"} ordered := []string{"$JS.API.CONSUMER.CREATE.S", "$JS.API.CONSUMER.MSG.NEXT.S.*", "$JS.API.CONSUMER.INFO.S.*", "$JS.API.CONSUMER.DELETE.S.*"} last := heardGrants(p, []Heard{{Stream: "S", Filters: []string{"f"}, LastPerSubject: true}}) for _, w := range ordered { if !slices.Contains(last, w) { t.Errorf("a last-per-subject reader is not granted %s: %v", w, last) } } plain := heardGrants(p, []Heard{{Stream: "S", Filters: []string{"f"}}}) if slices.Contains(plain, ordered[0]) { t.Errorf("a reader of another stream is granted an ordered consumer: %v", plain) } } // A reader of a seat's kept event is granted the info of that stream, which process.HearSeatEvents reads to see whether the // stream is kept last per subject, and no stream's info besides (design 47 G §641, A-19). func TestAReaderOfASeatsKeptEventIsGrantedItsStreamInfo(t *testing.T) { p := Principal{Module: "m", Node: "a"} kept := heardGrants(p, []Heard{{Stream: "SEAT_mesh-delivery_owed", Filters: []string{"f"}}}) if !slices.Contains(kept, "$JS.API.STREAM.INFO.SEAT_mesh-delivery_owed") { t.Errorf("a reader of a seat's kept event is not granted its stream's info: %v", kept) } own := heardGrants(p, []Heard{{Stream: "BUILDER_BUILDS", Filters: []string{"f"}, LastPerSubject: true}}) if !slices.Contains(own, "$JS.API.STREAM.INFO.BUILDER_BUILDS") { t.Errorf("a reader of a module's stream kept last per subject is not granted its info: %v", own) } other := heardGrants(p, []Heard{{Stream: "mesh-x-events", Filters: []string{"f"}}}) if slices.Contains(other, "$JS.API.STREAM.INFO.mesh-x-events") { t.Errorf("a reader of a module's stream is granted its info: %v", other) } }