Bind a stream consumer again when the bus ends its loop, so a module is not left deaf when the controller deletes and makes again a consumer it cannot narrow (hq issue 725)
mesh/merge-gate head d3b0330ed1cb merged into trunk d0dcae53a8c0 — pass, with a note: builds mesh-tools, node-tools (+39 dependent(s)) → ace, g14, novox, s…
mesh/repo-check head d3b0330ed1cb merged into trunk d0dcae53a8c0 — pass: its merge-check.sh passed
mesh/delivery covered after its failure: a later walk that contains it was delivered: plan-1792008849869252364 (novox/mesh-tools at 5d70eb3e into main, d…
mesh/merge-gate head d3b0330ed1cb merged into trunk d0dcae53a8c0 — pass, with a note: builds mesh-tools, node-tools (+39 dependent(s)) → ace, g14, novox, s…
mesh/repo-check head d3b0330ed1cb merged into trunk d0dcae53a8c0 — pass: its merge-check.sh passed
mesh/delivery covered after its failure: a later walk that contains it was delivered: plan-1792008849869252364 (novox/mesh-tools at 5d70eb3e into main, d…
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -196,3 +197,84 @@ func TestAConsumerNamedBeforeItExistsIsBoundOnceItDoes(t *testing.T) {
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// novox/hq ADR 0363 §6 (issue 725): a consumer the controller deletes and makes again under the same name, its
|
||||
// membership unchanged, is bound again, and what is published after is heard — the module does not go deaf.
|
||||
func TestAConsumerDeletedAndMadeAgainIsHeardAgain(t *testing.T) {
|
||||
restore := bus.RebindEvery
|
||||
bus.RebindEvery = 200 * time.Millisecond
|
||||
t.Cleanup(func() { bus.RebindEvery = restore })
|
||||
reader := mt.MembershipOf("reader", "anchor", false, nil)
|
||||
reader.Hears = []bus.HeardIssued{{Stream: "MAIL", Consumer: "anchor_reader"}}
|
||||
mesh, conn := streamMesh(t, reader)
|
||||
mesh.Consumer(t, "anchor", "reader", []string{"mesh.mod.alpha.event.>"}, 5*time.Second)
|
||||
mesh.ConsumerOn(t, "MAIL", "anchor", "reader", []string{"mesh.stream.mail.event.>"}, 5*time.Second)
|
||||
logs := &syncLogs{}
|
||||
conn.Logf = logs.Logf
|
||||
|
||||
var mu sync.Mutex
|
||||
heard := 0
|
||||
stop, err := conn.ConsumeAs("reader", func(env bus.Envelope) error {
|
||||
if env.Key == "mail.mail.home.message.added" {
|
||||
mu.Lock()
|
||||
heard++
|
||||
mu.Unlock()
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(stop)
|
||||
count := func() int {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
return heard
|
||||
}
|
||||
mesh.Emit(t, "mesh.stream.mail.event.mail.home.message.added", map[string]any{"n": 1})
|
||||
mt.Until(t, func() error {
|
||||
if count() != 1 {
|
||||
return errors.New("the first event on MAIL was not heard")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
mesh.RemoveConsumer(t, "MAIL", "anchor", "reader")
|
||||
mt.Until(t, func() error {
|
||||
if !logs.Has("stopped hearing MAIL") {
|
||||
return errors.New("the end of the loop was not said")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
mesh.ConsumerOn(t, "MAIL", "anchor", "reader", []string{"mesh.stream.mail.event.>"}, 5*time.Second)
|
||||
mesh.Emit(t, "mesh.stream.mail.event.mail.home.message.added", map[string]any{"n": 2})
|
||||
mt.Until(t, func() error {
|
||||
if count() != 2 {
|
||||
return fmt.Errorf("heard %d events on MAIL after its consumer was made again, want 2", count())
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// syncLogs keeps what the runtime says, from any goroutine.
|
||||
type syncLogs struct {
|
||||
mu sync.Mutex
|
||||
lines []string
|
||||
}
|
||||
|
||||
func (l *syncLogs) Logf(format string, args ...any) {
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
l.lines = append(l.lines, fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
func (l *syncLogs) Has(fragment string) bool {
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
for _, line := range l.lines {
|
||||
if strings.Contains(line, fragment) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user