mesh/delivery-group group feat/774-l3-reland rejected: composed together: the checker's verdict at the members' heads (b48c90fea31f): integration: mesh-self-ch…
mesh/delivery closed: a newer head of the same pull request
mesh/check failed: integration: mesh-self-check/cmd/mesh-self-check.TestTheSelfCheckWholeRunsOnTheBus: the run answered {Run:doctor-1793351737-1 At:20…
One commit with exactly the tree of the reviewed head35b4509c0a, on main12c2574c9d, so two compiled programs added and removed on the branch leave no trace in history (issue 1577).
176 lines
7.7 KiB
Go
176 lines
7.7 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/nats-io/nats.go/jetstream"
|
|
)
|
|
|
|
// scriptedSecrets answers each Get from the next of its errors, then with a value, counting the asks.
|
|
type scriptedSecrets struct {
|
|
errs []error
|
|
asked int
|
|
}
|
|
|
|
func (f *scriptedSecrets) Get(context.Context, string) (string, int, error) {
|
|
f.asked++
|
|
if f.asked <= len(f.errs) {
|
|
return "", 0, f.errs[f.asked-1]
|
|
}
|
|
return "tok", 1, nil
|
|
}
|
|
|
|
// Issue 928: a refusal is asked again after RefusedFor, and a not-yet on every pass, so a vault that was down or
|
|
// that holds the value later fills the file with no change of the plan.
|
|
func TestARefusedSecretIsAskedAgainAfterRefusedForAndFilledWhenTheVaultHasIt(t *testing.T) {
|
|
now := time.Date(2026, 10, 16, 16, 20, 0, 0, time.UTC)
|
|
fake := &scriptedSecrets{errs: []error{errors.New("the vault refused it: the assignment g14.claude-code could not be read")}}
|
|
c := &Client{Node: "g14", Secrets: fake, Now: func() time.Time { return now }}
|
|
s := &state{secrets: map[string]heldSecret{}}
|
|
n := Need{Kind: "secret", Name: "gitea-read"}
|
|
name := "provision/novox/gitea-read/g14/claude-code"
|
|
|
|
if _, _, fail := c.vaultValue(context.Background(), s, n, name); fail == "" {
|
|
t.Fatal("a refusal did not fail the need")
|
|
}
|
|
now = now.Add(RefusedFor - time.Second)
|
|
if _, _, fail := c.vaultValue(context.Background(), s, n, name); fail == "" || fake.asked != 1 {
|
|
t.Fatalf("within RefusedFor the vault was asked again (%d asks) or the refusal was dropped", fake.asked)
|
|
}
|
|
now = now.Add(time.Second)
|
|
v, wait, fail := c.vaultValue(context.Background(), s, n, name)
|
|
if fake.asked != 2 || v != "tok" || wait != "" || fail != "" {
|
|
t.Fatalf("after RefusedFor: %d asks, value %q, waits %q, fails %q; want asked again and filled", fake.asked, v, wait, fail)
|
|
}
|
|
|
|
// What ends a refusal before RefusedFor asks again at once (ace, 2026-10-25 21:17: refused before the declaration
|
|
// named the module's files): the node-engine touching its write socket after an apply, which fills every module
|
|
// again, and the module's own assignment changing. Another module's assignment does not.
|
|
own := VaultName("g14", "claude-code", "token")
|
|
for _, row := range []struct {
|
|
name string
|
|
end func(c *Client, s *state) []string
|
|
asked bool
|
|
filled []string // the modules a wake fills again
|
|
}{
|
|
{name: "the socket touched", asked: true, filled: []string{"claude-code", "gitea", "waited"},
|
|
end: func(c *Client, s *state) []string { return c.woken(s) }},
|
|
{name: "its assignment changed", asked: true,
|
|
end: func(c *Client, s *state) []string { c.forgetRefusals(s, "claude-code"); return nil }},
|
|
{name: "another module's assignment changed", asked: false,
|
|
end: func(c *Client, s *state) []string { c.forgetRefusals(s, "gitea"); return nil }},
|
|
} {
|
|
t.Run(row.name, func(t *testing.T) {
|
|
refused := errors.New("the vault refused it: g14's declaration names no such secret")
|
|
fake := &scriptedSecrets{errs: []error{refused, refused}}
|
|
c := &Client{Node: "g14", Secrets: fake, Now: func() time.Time { return now }}
|
|
s := &state{secrets: map[string]heldSecret{}, plans: map[string]Plan{"claude-code": {}, "gitea": {}},
|
|
unplaced: map[string]bool{"waited": true}}
|
|
for _, name := range []string{name, own} {
|
|
if _, _, fail := c.vaultValue(context.Background(), s, n, name); fail == "" {
|
|
t.Fatal("a refusal did not fail the need")
|
|
}
|
|
}
|
|
fake.asked = 0
|
|
fake.errs = nil
|
|
if got := row.end(c, s); row.filled != nil && fmt.Sprint(got) != fmt.Sprint(row.filled) {
|
|
t.Errorf("filled again %v, want %v", got, row.filled)
|
|
}
|
|
for _, name := range []string{name, own} {
|
|
v, _, _ := c.vaultValue(context.Background(), s, n, name)
|
|
if (v == "tok") != row.asked {
|
|
t.Errorf("%s: value %q after %d asks; asked again at once: want %v", name, v, fake.asked, row.asked)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestANotYetSecretIsAskedAgainOnEveryPass(t *testing.T) {
|
|
now := time.Date(2026, 10, 16, 16, 20, 0, 0, time.UTC)
|
|
notYet := fmt.Errorf("%w: the vault holds no secret named x yet", errNotYet)
|
|
fake := &scriptedSecrets{errs: []error{notYet, notYet}}
|
|
c := &Client{Node: "g14", Secrets: fake, Now: func() time.Time { return now }}
|
|
s := &state{secrets: map[string]heldSecret{}}
|
|
n := Need{Kind: "secret", Name: "gitea-read"}
|
|
for i := 0; i < 2; i++ {
|
|
if _, wait, fail := c.vaultValue(context.Background(), s, n, "x"); wait == "" || fail != "" {
|
|
t.Fatalf("pass %d: waits %q fails %q, want a wait", i, wait, fail)
|
|
}
|
|
}
|
|
if v, _, _ := c.vaultValue(context.Background(), s, n, "x"); v != "tok" || fake.asked != 3 {
|
|
t.Fatalf("value %q after %d asks, want filled on the third", v, fake.asked)
|
|
}
|
|
}
|
|
|
|
// fakeEntry is one watched key's update, as far as take reads it.
|
|
type fakeEntry struct {
|
|
jetstream.KeyValueEntry
|
|
key string
|
|
val []byte
|
|
op jetstream.KeyValueOp
|
|
}
|
|
|
|
func (f fakeEntry) Key() string { return f.key }
|
|
func (f fakeEntry) Value() []byte { return f.val }
|
|
func (f fakeEntry) Operation() jetstream.KeyValueOp { return f.op }
|
|
|
|
// Issue 1945 (ace, 2026-10-25 23:51): a module that leaves the machine and is placed on it again asks the vault
|
|
// afresh, whichever way it left or returned, so it is never filled with a generation held from before; a module
|
|
// that stays placed keeps using what it holds.
|
|
func TestAModulePlacedAgainAsksTheVaultAfreshAndAModuleThatStaysDoesNot(t *testing.T) {
|
|
const assignment = `{"v":1,"node":"g14","module":"build","plan":{}}` // the seat's plan (ADR 0570 clause 2)
|
|
own := VaultName("g14", "build", "bus-password")
|
|
pair := PairName("g14", "db", "g14", "build", "")
|
|
other := VaultName("g14", "gitea", "token")
|
|
for _, row := range []struct {
|
|
name string
|
|
steps func(c *Client, s *state)
|
|
again int // asks of the vault after the first three: the module's own secret once more, or none
|
|
}{
|
|
{name: "it stays placed: the assignment is put again", again: 0, steps: func(c *Client, s *state) {
|
|
c.take(s, update{bucket: PlansBucket, entry: fakeEntry{key: "g14.build", val: []byte(assignment)}})
|
|
}},
|
|
{name: "its assignment is deleted and put again", again: 1, steps: func(c *Client, s *state) {
|
|
c.take(s, update{bucket: PlansBucket, entry: fakeEntry{key: "g14.build", op: jetstream.KeyValueDelete}})
|
|
c.take(s, update{bucket: PlansBucket, entry: fakeEntry{key: "g14.build", val: []byte(assignment)}})
|
|
}},
|
|
{name: "it left and the client was away: only the later assignment arrives", again: 1, steps: func(c *Client, s *state) {
|
|
delete(s.assigned, "build")
|
|
c.take(s, update{bucket: PlansBucket, entry: fakeEntry{key: "g14.build", val: []byte(assignment)}})
|
|
}},
|
|
{name: "it leaves the machine", again: 1, steps: func(c *Client, s *state) {
|
|
c.leave(context.Background(), nil, s, "build")
|
|
}},
|
|
} {
|
|
t.Run(row.name, func(t *testing.T) {
|
|
fake := &scriptedSecrets{}
|
|
c := &Client{Node: "g14", Secrets: fake, Now: time.Now}
|
|
s := &state{secrets: map[string]heldSecret{}, plans: map[string]Plan{}, refused: map[string]string{},
|
|
assigned: map[string]bool{"build": true}, binds: map[string]binding{}, providing: map[string]bool{},
|
|
leftOut: map[string]string{}, applied: map[string]bool{},
|
|
reported: map[string][]byte{}, items: map[string]map[string]itemValue{}, recorded: map[string][]byte{},
|
|
unplaced: map[string]bool{}}
|
|
n := Need{Kind: "secret", Name: "bus-password"}
|
|
ask := func(name string) { c.vaultValue(context.Background(), s, n, name) }
|
|
ask(own)
|
|
ask(pair)
|
|
ask(other)
|
|
row.steps(c, s)
|
|
ask(own)
|
|
ask(other)
|
|
if got := fake.asked - 3; got != row.again {
|
|
t.Errorf("%d asks after the first three, want %d (the module's own once more, if it was placed again)",
|
|
got, row.again)
|
|
}
|
|
if _, held := s.secrets[other]; !held {
|
|
t.Error("another module's secret was dropped")
|
|
}
|
|
})
|
|
}
|
|
}
|