package inventory import ( "slices" "testing" "time" ) // The assignment generation and the record of every send (novox/hq issue 234). On 2026-10-04 a declaration // newer in sequence than every other named four fewer modules than the assignments held, a machine applied // it, and nothing the mesh kept could say who sent it or from what view. func generationNow(t *testing.T, inv *Inventory) int64 { t.Helper() g, err := inv.AssignmentGeneration(t.Context()) if err != nil { t.Fatal(err) } return g } // **Every change to what is assigned where raises the generation, in its own transaction** — an // assignment, an unassignment, and one taken by the machine's removal, which no writer in Go makes — and // a repeated assignment, which changes nothing, does not. func TestEveryAssignmentChangeRaisesTheGeneration(t *testing.T) { inv, node := aNodeWithModules(t, "postgres", "web") ctx := t.Context() start := generationNow(t, inv) if start < 1 { t.Fatalf("the generation starts at %d; zero is \"none claimed\" on the wire", start) } if _, err := inv.Assign(ctx, node, "postgres"); err != nil { t.Fatal(err) } assigned := generationNow(t, inv) if assigned <= start { t.Fatalf("an assignment left the generation at %d", assigned) } if _, err := inv.Assign(ctx, node, "postgres"); err != nil { t.Fatal(err) } if again := generationNow(t, inv); again != assigned { t.Errorf("an assignment repeated, which changed nothing, moved the generation from %d to %d", assigned, again) } if err := inv.Unassign(ctx, node, "postgres"); err != nil { t.Fatal(err) } unassigned := generationNow(t, inv) if unassigned <= assigned { t.Fatalf("an unassignment left the generation at %d", unassigned) } if _, err := inv.Assign(ctx, node, "web"); err != nil { t.Fatal(err) } before := generationNow(t, inv) if _, err := inv.RemoveNodeForTest(ctx, node); err != nil { t.Fatal(err) } if removed := generationNow(t, inv); removed <= before { t.Errorf("a machine's removal took its assignments and left the generation at %d", removed) } } // **The generation never goes down, and is raised past what a machine applied when the mesh's own counter // is behind it** — a store put back from a backup — so the next send is not refused for ever. func TestTheGenerationIsRaisedPastWhatAMachineApplied(t *testing.T) { inv, _ := aNodeWithModules(t) now := generationNow(t, inv) if raised, err := inv.RaiseAssignmentGeneration(t.Context(), now+40); err != nil || raised != now+41 { t.Fatalf("raised past %d to %d (%v)", now+40, raised, err) } if raised, err := inv.RaiseAssignmentGeneration(t.Context(), 2); err != nil || raised != now+41 { t.Fatalf("a raise below the counter moved it to %d (%v)", raised, err) } } // **Every send is recorded: its sequence, its sender, the generation it came from and the modules it // named** — and the machine's last send is what `plan` reads, the would-send is stamped with its // generation and put-back mark, and a refusal is kept on the send it refused, naming its sender. func TestASendIsRecordedWithItsSenderGenerationAndModules(t *testing.T) { inv, node := aNodeWithModules(t) ctx := t.Context() record, err := inv.NodeByName(ctx, node) if err != nil { t.Fatal(err) } first := Send{Node: record.ID, Sequence: 11, Epoch: 57, Sender: "the controller's daemon (pid 7 on anchor)", Generation: 40, Digest: "d11", Modules: []string{"docker", "pacman", "sudo"}} if err := inv.RecordSend(ctx, first); err != nil { t.Fatal(err) } stale := Send{Node: record.ID, Sequence: 12, Epoch: 57, Sender: "a one-shot push by jochen at a shell on anchor", Generation: 38, ToldGeneration: 38, Digest: "d12", Modules: []string{"docker"}} if err := inv.RecordSend(ctx, stale); err != nil { t.Fatal(err) } last, found, err := inv.LastSend(ctx, node) if err != nil || !found { t.Fatalf("the last send is not kept: %v", err) } if last.Sequence != 12 || last.Sender != stale.Sender || last.Generation != 38 || !slices.Equal(last.Modules, []string{"docker"}) || last.SentAt.IsZero() { t.Fatalf("the last send reads %+v", last) } generation, putBack, err := inv.SentGeneration(ctx, record.ID) if err != nil || generation != 38 || putBack { t.Fatalf("what the machine was last sent of it reads %d, %v (%v)", generation, putBack, err) } refused, found, err := inv.RefusedSend(ctx, record.ID, 12, 40) if err != nil || !found || refused.Sender != stale.Sender || refused.RefusedApplied != 40 { t.Fatalf("the refusal is not kept on the send it refused: %+v, %v, %v", refused, found, err) } since, err := inv.RefusedSendsSince(ctx, time.Now().Add(-time.Hour)) if err != nil || len(since) != 1 || since[0].NodeName != node || since[0].Sequence != 12 { t.Fatalf("the refused sends within the hour read %+v (%v)", since, err) } if _, found, err := inv.RefusedSend(ctx, record.ID, 99, 40); err != nil || found { t.Errorf("a refusal of a send never recorded was found: %v, %v", found, err) } } // **A machine that reads a generation is recorded from its reports**, and one rolled back says so no longer. func TestWhetherAMachineReadsAGenerationIsItsLatestWord(t *testing.T) { inv, node := aNodeWithModules(t) record, err := inv.NodeByName(t.Context(), node) if err != nil { t.Fatal(err) } for _, reads := range []bool{false, true, false} { if err := inv.RecordReadsGeneration(t.Context(), record.ID, reads); err != nil { t.Fatal(err) } if got, err := inv.ReadsGeneration(t.Context(), record.ID); err != nil || got != reads { t.Fatalf("recorded %v, read %v (%v)", reads, got, err) } } }