106 lines
3.4 KiB
Go
106 lines
3.4 KiB
Go
package main
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// Issue 1507: an ask was taken and queued for its burst window, the process was replaced before the flush, and
|
|
// the new process never offered it: the outbox is in memory, and an ask is offered only when it is taken. An
|
|
// open ask no channel has been sent is offered again, once, by the minute tick; one already sent is not.
|
|
|
|
// restarted is a new holder over the same stores and channels, as a replaced process is.
|
|
func restarted(t *testing.T, old *Holder, c *clock, st *memStore) *Holder {
|
|
t.Helper()
|
|
h := &Holder{Away: old.Away, Desk: old.Desk, Store: st, Now: c.now, Logf: t.Logf, Emit: old.Emit,
|
|
Bench: old.Bench, Asks: old.Asks, Node: old.Node, RootFree: old.RootFree, Zone: old.Zone, Publish: old.Publish}
|
|
h.init()
|
|
if err := h.Load(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
h.Start()
|
|
return h
|
|
}
|
|
|
|
func TestAnAskQueuedWhenTheProcessStoppedIsOfferedByTheNextProcess(t *testing.T) {
|
|
h, tg, dt, c, store, _ := newRouter(t)
|
|
st := h.Store.(*memStore)
|
|
link(h, store, c, "42", c.now().Add(-2*time.Hour))
|
|
submit(t, h, "mesh-config", heldAsk(c, "cfg-1"))
|
|
if len(tg.sends)+len(dt.sends) != 0 {
|
|
t.Fatalf("sent before the burst window")
|
|
}
|
|
// The process stops here, before the flush.
|
|
h2 := restarted(t, h, c, st)
|
|
for i := 0; i < 5; i++ {
|
|
c.pass(time.Minute)
|
|
stand(h2, c)
|
|
h2.Tick()
|
|
h2.Flush()
|
|
}
|
|
if n := len(tg.sends); n != 1 {
|
|
t.Fatalf("the ask was sent %d times on telegram, want once", n)
|
|
}
|
|
if n := len(dt.sends); n != 0 {
|
|
t.Fatalf("an approval ask was sent on the desk: %d", n)
|
|
}
|
|
}
|
|
|
|
func TestAnAskAlreadySentIsNotSentAgainAfterARestart(t *testing.T) {
|
|
h, tg, _, c, store, _ := newRouter(t)
|
|
st := h.Store.(*memStore)
|
|
link(h, store, c, "42", c.now().Add(-2*time.Hour))
|
|
submit(t, h, "mesh-config", heldAsk(c, "cfg-1"))
|
|
settle(h, c)
|
|
if len(tg.sends) != 1 {
|
|
t.Fatalf("not sent: %d", len(tg.sends))
|
|
}
|
|
h2 := restarted(t, h, c, st)
|
|
for i := 0; i < 5; i++ {
|
|
c.pass(time.Minute)
|
|
stand(h2, c)
|
|
h2.Tick()
|
|
h2.Flush()
|
|
}
|
|
if len(tg.sends) != 1 {
|
|
t.Fatalf("sent again after a restart: %d", len(tg.sends))
|
|
}
|
|
}
|
|
|
|
// Issue 1507, read again 2026-10-28: three asks taken at 08:50:03-08:50:14 went out together at 08:50:33, at the
|
|
// end of the first one's burst window; a reading of the history in between showed no send and no refusal, and the
|
|
// asks read as lost. What waits in an outbox is in the history, with when its window ends, until it is sent.
|
|
func TestTheHistorySaysAnAskWaitingForItsBurstWindow(t *testing.T) {
|
|
h, tg, _, c, store, _ := newRouter(t)
|
|
link(h, store, c, "42", c.now().Add(-2*time.Hour))
|
|
submit(t, h, "mesh-config", heldAsk(c, "cfg-1"))
|
|
waiting := func() []Waiting { return h.History(20)["waiting"].([]Waiting) }
|
|
for _, step := range []struct {
|
|
name string
|
|
pass time.Duration
|
|
want int
|
|
}{
|
|
{"taken, inside its window", 0, 1},
|
|
{"its window passed and it was sent", BurstWindow + time.Second, 0},
|
|
} {
|
|
c.pass(step.pass)
|
|
stand(h, c)
|
|
h.Flush()
|
|
w := waiting()
|
|
if len(w) != step.want {
|
|
t.Fatalf("%s: %d waiting, want %d: %+v", step.name, len(w), step.want, w)
|
|
}
|
|
if step.want == 1 {
|
|
if w[0].Key != "ask.mesh-config.cfg-1" || w[0].Channel != tg.Name() || w[0].Due == "" {
|
|
t.Fatalf("%s: waiting %+v, want the ask on %s with when its window ends", step.name, w[0], tg.Name())
|
|
}
|
|
if len(tg.sends) != 0 {
|
|
t.Fatalf("%s: sent before its window ended", step.name)
|
|
}
|
|
}
|
|
}
|
|
if len(tg.sends) != 1 {
|
|
t.Fatalf("sent %d times, want once", len(tg.sends))
|
|
}
|
|
}
|