DEAD_LETTERS kept a message given up on MAIL forever and showed it whole to any caller of dead-letters, outside the grant and past MAIL's week. Per ADR 0376 §3-§6: the kept copy carries a per-message time to live of what is left of its stream's age (a copy already past it is kept without its body), DEAD_LETTERS and EVENTS allow per-message TTL, the list and show give no body or own headers for it, delivering it again needs a minute left and the copy keeps the time left, and its max-deliveries condition clears saying how many aged out undelivered and from which stream.
87 lines
2.9 KiB
Go
87 lines
2.9 KiB
Go
package broker
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/nats-io/nats.go"
|
|
|
|
"github.com/novox/mesh-controller/internal/testbus"
|
|
)
|
|
|
|
// **DEAD_LETTERS and EVENTS take a message's own time to live once updated in place** (novox/hq ADR 0376 §3, §5),
|
|
// on the pinned server: each made as it was before, without one, is brought to its definition by the controller's
|
|
// assertion, keeps what it held, and removes a message once its time to live passes. A restricted module stream says
|
|
// so in its metadata; one without a grant does not.
|
|
//
|
|
// go test ./internal/broker/ -run TestTheStreamsTakeAMessagesTimeToLive
|
|
func TestTheStreamsTakeAMessagesTimeToLive(t *testing.T) {
|
|
js, err := Dial(testbus.URL(t))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer js.Close()
|
|
for _, s := range MeshStreams() {
|
|
if s.Name != EventsStream && s.Name != DeadLettersStream {
|
|
if s.AllowMsgTTL {
|
|
t.Errorf("%s takes a time to live of a message's own, which nothing asks of it", s.Name)
|
|
}
|
|
continue
|
|
}
|
|
if !s.AllowMsgTTL {
|
|
t.Fatalf("%s is not defined to take a message's time to live", s.Name)
|
|
}
|
|
_ = js.js.DeleteStream(s.Name)
|
|
before := s
|
|
before.AllowMsgTTL = false
|
|
if err := js.EnsureStream(before); err != nil {
|
|
t.Fatalf("%s as it was: %v", s.Name, err)
|
|
}
|
|
subject := DeadLetterSubject("EVENTS", "ace_reader")
|
|
if s.Name == EventsStream {
|
|
subject = "mesh.mod.gitea.event.pull.merged"
|
|
}
|
|
if _, err := js.js.Publish(subject, []byte("held")); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := js.EnsureStream(s); err != nil {
|
|
t.Fatalf("%s updated in place: %v", s.Name, err)
|
|
}
|
|
info, err := js.js.StreamInfo(s.Name)
|
|
if err != nil || !info.Config.AllowMsgTTL || info.State.Msgs != 1 {
|
|
t.Fatalf("%s after the update: %+v (%v)", s.Name, info, err)
|
|
}
|
|
msg := &nats.Msg{Subject: subject, Data: []byte("brief"), Header: nats.Header{}}
|
|
msg.Header.Set(nats.MsgTTLHdr, "1s")
|
|
ack, err := js.js.PublishMsg(msg)
|
|
if err != nil {
|
|
t.Fatalf("%s refused a message's time to live: %v", s.Name, err)
|
|
}
|
|
deadline := time.Now().Add(8 * time.Second)
|
|
for {
|
|
if _, err := js.js.GetMsg(s.Name, ack.Sequence); err != nil {
|
|
break
|
|
}
|
|
if time.Now().After(deadline) {
|
|
t.Fatalf("%s still holds a message past its time to live", s.Name)
|
|
}
|
|
time.Sleep(200 * time.Millisecond)
|
|
}
|
|
if info, _ := js.js.StreamInfo(s.Name); info.State.Msgs != 1 {
|
|
t.Fatalf("%s holds %d, want only the message without an age", s.Name, info.State.Msgs)
|
|
}
|
|
_ = js.js.PurgeStream(s.Name)
|
|
}
|
|
if !mailStream.Stream().Restricted || newsStream.Stream().Restricted {
|
|
t.Fatal("a module stream does not say whether it is restricted")
|
|
}
|
|
_ = js.js.DeleteStream("MAIL")
|
|
if err := js.EnsureStream(mailStream.Stream()); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer func() { _ = js.js.DeleteStream("MAIL") }()
|
|
if info, _ := js.js.StreamInfo("MAIL"); info.Config.Metadata[RestrictedMetadata] != "true" {
|
|
t.Fatalf("MAIL's metadata: %v", info.Config.Metadata)
|
|
}
|
|
}
|