H3 (review r2): the entries test waits on the refusal the composer says until the ghost's reason is entry-missing

Builds: design 47 G §421, §614 (test only)
This commit is contained in:
2026-11-12 22:24:38 +01:00
parent 302dcc098f
commit 1d409cd852
+26 -4
View File
@@ -7,6 +7,7 @@ import (
"strings"
"sync"
"testing"
"time"
"git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient"
"git.novox.be/novox/mesh-contracts/go/seats/meshmoduleassigner"
@@ -57,7 +58,16 @@ func composeFromEntries(t *testing.T) {
var held map[string]string
env := b.env()
env.Entry, env.ComposedState = EntryCall(ask), state
env.Refused = func(_ string, h map[string]string) { mu.Lock(); held = h; mu.Unlock() }
refused := make(chan struct{}, 1) // fed at each refusal the composer says, so a wait follows what it says, not a pause
env.Refused = func(_ string, h map[string]string) {
mu.Lock()
held = h
mu.Unlock()
select {
case refused <- struct{}{}:
default:
}
}
told := map[string]bool{}
env.EntryNotFound = func(fp string, notFound bool) { mu.Lock(); told[fp] = notFound; mu.Unlock() }
c := New(env)
@@ -93,9 +103,21 @@ func composeFromEntries(t *testing.T) {
}
b.mu.Unlock()
// A want whose entry the half holds none of is held, saying entry-missing and the fingerprint; the rest is composed.
mu.Lock()
why := held["ghost"]
mu.Unlock()
// The ghost's entry is asked first and answered not found after: wait until the refusal says entry-missing.
var why string
for deadline := time.After(10 * time.Second); !strings.HasPrefix(why, agent.EntryMissing); {
mu.Lock()
why = held["ghost"]
mu.Unlock()
if strings.HasPrefix(why, agent.EntryMissing) {
break
}
select {
case <-refused:
case <-deadline:
t.Fatalf("the ghost's reason is still %q after 10 s, want %s", why, agent.EntryMissing)
}
}
if !strings.HasPrefix(why, agent.EntryMissing) || !strings.Contains(why, ghost) || held["lemurs"] != "" {
t.Errorf("held %q, want ghost held with %s naming %s", held, agent.EntryMissing, ghost)
}