Fold three tests into existing ones, drive the marker test by channels, keep the last view through set(nil) and drop it once the node is held

Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
This commit is contained in:
2026-11-05 23:09:00 +01:00
parent c55672ce5e
commit 015304f4a3
6 changed files with 66 additions and 16 deletions
+1
View File
@@ -27,6 +27,7 @@ func TestAnApplyOutlivesTheLinksContext(t *testing.T) {
// An apply is bounded all the same: a step that hangs (a docker call that never returns) cannot hold the node agent for
// ever (the review of issue 1945).
func TestAnApplyIsBounded(t *testing.T) {
t.Run("the marks of the haves never hold the pass", marksOfTheHavesNeverHoldThePass)
ctx, done := applyContext(context.Background())
defer done()
at, ok := ctx.Deadline()
+8 -8
View File
@@ -8,15 +8,16 @@ import (
// Issue 1965 (shanks 2026-11-05 22:22): the marks of the haves never hold the composition pass. A mark that stalls on the
// bus is cut at markWithin, a mark set while one runs replaces the pending one of its name, and set itself never waits.
func TestMarksOfTheHavesNeverHoldThePass(t *testing.T) {
setMarkWithin(t, 30*time.Millisecond)
func marksOfTheHavesNeverHoldThePass(t *testing.T) {
// The bound is the test's own: the stalled mark is released by a channel, never by a real wait.
setMarkWithin(t, time.Hour)
m := newMarker(context.Background())
release := make(chan struct{})
var ran []string
stalled := make(chan struct{})
began := time.Now()
m.set("refused", func(ctx context.Context) { // a have write that stalls until its bound
m.set("refused", func(ctx context.Context) { // a have write that stalls until the test lets it go
close(stalled)
<-ctx.Done()
<-release
ran = append(ran, "refused-stalled")
})
<-stalled
@@ -24,9 +25,8 @@ func TestMarksOfTheHavesNeverHoldThePass(t *testing.T) {
m.set("kept", func(context.Context) { ran = append(ran, "kept-old") })
m.set("kept", func(context.Context) { ran = append(ran, "kept-new") })
m.set("refused", func(context.Context) { ran = append(ran, "refused-new") })
if took := time.Since(began); took > 20*time.Millisecond {
t.Errorf("setting marks took %v; it must not wait on the stalled one", took)
}
// All four sets above returned while the first mark still stalled: set never waits on it.
close(release)
m.wait()
want := []string{"refused-stalled", "kept-new", "refused-new"}
if len(ran) != len(want) {
+29 -2
View File
@@ -703,8 +703,12 @@ type agentNow struct {
// read no haves yet, what runs is this and never the retired kept declaration (a bus link that drops restarts the
// agent, and every fill in that window was refused; issue 924).
last *runsView
// view reads an agent's view; viewOf unless a test stands in for an agent that holds the node.
view func(*agent.Agent) *runsView
}
func viewOf(a *agent.Agent) *runsView { return &runsView{a.Everything(), a.HoldsNode()} }
// runsView is what an agent said runs, to be read after the agent stopped.
type runsView struct {
everything []compositions.Composed
@@ -714,7 +718,11 @@ type runsView struct {
func (c *agentNow) set(a *agent.Agent) {
c.mu.Lock()
if a == nil && c.ag != nil {
if v := (&runsView{c.ag.Everything(), c.ag.HoldsNode()}); len(v.everything) > 0 || v.holdsNode {
read := c.view
if read == nil {
read = viewOf
}
if v := read(c.ag); len(v.everything) > 0 || v.holdsNode {
c.last = v
}
}
@@ -722,6 +730,22 @@ func (c *agentNow) set(a *agent.Agent) {
c.mu.Unlock()
}
func (c *agentNow) viewFn() func(*agent.Agent) *runsView {
c.mu.Lock()
defer c.mu.Unlock()
if c.view == nil {
return viewOf
}
return c.view
}
// holdsNode drops the kept view once the agent in hand holds the node: its own view is complete from then on.
func (c *agentNow) holdsNode() {
c.mu.Lock()
c.last = nil
c.mu.Unlock()
}
// lastView is the view the last agent held when it stopped, nil when none held any.
func (c *agentNow) lastView() *runsView {
c.mu.Lock()
@@ -914,7 +938,10 @@ func runsFromAgent(current *agentNow) func(string, ed25519.PublicKey) (*declarat
kept := func() (*declaration.Declaration, error) { return keptDeclaration(statePath, signer) }
var view *runsView
if ag := current.get(); ag != nil {
view = &runsView{ag.Everything(), ag.HoldsNode()}
view = current.viewFn()(ag)
if view.holdsNode {
current.holdsNode()
}
}
// An agent that has read no haves yet, or none: the last view held, never the retired kept declaration.
if view == nil || (len(view.everything) == 0 && !view.holdsNode) {
+26 -5
View File
@@ -63,6 +63,7 @@ func TestWhatRunsIsTheAgentsCompositionsAndTheKeptRest(t *testing.T) {
// What the take act, the judgement of directories and the filling read is what runs, not the frozen kept declaration.
func TestDeclaredNowReadsWhatRunsWhenTheAgentIsRunning(t *testing.T) {
t.Run("a fill while the agent restarts", aFillWhileTheAgentRestartsIsWrittenAfterwards)
setRunsHere(func(string, ed25519.PublicKey) (*declaration.Declaration, error) {
return &declaration.Declaration{Version: 1, Resources: nil, Provisioner: "from-agent"}, nil
})
@@ -243,7 +244,7 @@ func TestASharedTargetWithAnotherIDIsNotDropped(t *testing.T) {
// Issue 924: the bus link drops, the agent restarts, and the filling is asked while it holds nothing yet. What runs is
// then the last view the node held, never the retired kept declaration; and a fill refused for want of any is owed and
// told once the agent holds the node again, so every file is written afterwards.
func TestAFillWhileTheAgentRestartsIsWrittenAfterwards(t *testing.T) {
func aFillWhileTheAgentRestartsIsWrittenAfterwards(t *testing.T) {
keptRetired.Store(true)
defer keptRetired.Store(false)
node := engcomp.Composed{Node: "n1", Own: engcomp.NodeOwn{Provisioner: "mesh-node-provisioner"}}
@@ -251,7 +252,15 @@ func TestAFillWhileTheAgentRestartsIsWrittenAfterwards(t *testing.T) {
view := &runsView{everything: append(files, node), holdsNode: true}
var placed []string
current := &agentNow{}
// The agent holds the node, then the link drops and it stops: set(nil) keeps its view.
holding := true
current := &agentNow{view: func(*agent.Agent) *runsView {
if holding {
return view
}
return &runsView{}
}}
current.set(agent.New(agent.Env{}))
e := &filling.Engine{
Declared: func() (*declaration.Declaration, error) { return runsFromAgent(current)("/nowhere", nil) },
UIDOf: func(string) (uint32, error) { return 4242, nil },
@@ -269,16 +278,28 @@ func TestAFillWhileTheAgentRestartsIsWrittenAfterwards(t *testing.T) {
t.Fatal(err)
}
// The node never held a view (a cold start): refused, and owed.
// The next agent has read no haves and the previous one's view is gone (a cold start): refused, and owed.
cold := &agentNow{}
cold.set(agent.New(agent.Env{}))
cold.set(nil)
e.Declared = func() (*declaration.Declaration, error) { return runsFromAgent(cold)("/nowhere", nil) }
if a := fill(); a.Failed == "" && a.Refused == "" {
t.Fatalf("a fill with nothing read was accepted: %+v", a)
}
// The agent stopped holding the node: the last view it held answers, and the fill is written.
current.last = view
// The link drops: set(nil) keeps the view the agent held, and the fill during the restart is written.
e.Declared = func() (*declaration.Declaration, error) { return runsFromAgent(current)("/nowhere", nil) }
current.set(nil)
if told, err := e.Knock(socket); err != nil || told == "" {
t.Fatalf("the refused fill was not owed and told: %q, %v", told, err)
}
if a := fill(); a.Failed != "" || a.Refused != "" || len(placed) != 1 {
t.Fatalf("the fill during the restart was not written: %+v, placed %v", a, placed)
}
// The new agent holds the node: its own view answers and the kept one is dropped.
next := agent.New(agent.Env{})
current.set(next)
holding = true
if _, err := runsFromAgent(current)("/nowhere", nil); err != nil || current.lastView() != nil {
t.Fatalf("the kept view stays after the new agent holds the node: %v, %v", err, current.lastView())
}
}