F-tools: the runner's views consumer is proven on the real bus; the heartbeat is asked of the bus only when a bundle wants it, with no race; a seat record says when the bus wrote it; the beat test counts ticks, not sleeps
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -68,6 +69,13 @@ func TestAConsumerSaysItIsBoundWhileIdleAndOnceWhenTheBusEndedIt(t *testing.T) {
|
||||
restore := bus.IdleHeartbeat
|
||||
bus.IdleHeartbeat = 200 * time.Millisecond
|
||||
t.Cleanup(func() { bus.IdleHeartbeat = restore })
|
||||
ticks := make(chan struct{}, 64)
|
||||
t.Cleanup(bus.SetTickHook(func() {
|
||||
select {
|
||||
case ticks <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
}))
|
||||
mesh.Consumer(t, "anchor", "quiet", []string{"mesh.mod.alpha.event.>"}, time.Second)
|
||||
c, err := bus.Connect(bus.Credential{URL: mt.URL(t), Module: "node-tools", Node: "anchor"})
|
||||
if err != nil {
|
||||
@@ -87,6 +95,14 @@ func TestAConsumerSaysItIsBoundWhileIdleAndOnceWhenTheBusEndedIt(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(stop)
|
||||
// A consume nobody asked a heartbeat of says nothing and asks the bus nothing, however many intervals pass.
|
||||
var unaskedBeats atomic.Int32
|
||||
unasked, err := c.ConsumeAsBeatingWhen("quiet", func(bus.Envelope) error { return nil },
|
||||
func(bus.Beat) { unaskedBeats.Add(1) }, func() bool { return false })
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(unasked)
|
||||
last := func() (bus.Beat, int) {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
@@ -116,7 +132,13 @@ func TestAConsumerSaysItIsBoundWhileIdleAndOnceWhenTheBusEndedIt(t *testing.T) {
|
||||
}
|
||||
}
|
||||
mu.Unlock()
|
||||
time.Sleep(600 * time.Millisecond)
|
||||
for n := 0; n < 3; n++ { // three more intervals pass, counted by the loop's own tick
|
||||
select {
|
||||
case <-ticks:
|
||||
case <-time.After(10 * time.Second):
|
||||
t.Fatal("the heartbeat loop handled no more intervals")
|
||||
}
|
||||
}
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
after := 0
|
||||
@@ -125,6 +147,9 @@ func TestAConsumerSaysItIsBoundWhileIdleAndOnceWhenTheBusEndedIt(t *testing.T) {
|
||||
after++
|
||||
}
|
||||
}
|
||||
if unaskedBeats.Load() != 0 {
|
||||
t.Errorf("a consume with no heartbeat asked said %d words", unaskedBeats.Load())
|
||||
}
|
||||
if after != missed || missed != 1 {
|
||||
t.Errorf("Missed is said once, not at every beat: %d then %d", missed, after)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user