90 lines
3.8 KiB
Go
90 lines
3.8 KiB
Go
package main
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// 774/AC9 (novox/hq ADR 0561 §2, ADR 0230 §15, §18): a wanted account whose key is deleted is retired (its hash taken
|
|
// out of bus-accounts, its value kept, marked) only once the same set has stood for five passes and ten minutes, and never
|
|
// more than three, or more than half of those held, at once: past that it waits for a person (account_retire). Wanted
|
|
// again, it is re-enabled at once; and a retired account is not hashed again at a start.
|
|
func TestAWantGoneRetiresItsAccountOnlyWithinTheBounds(t *testing.T) {
|
|
v, accounts, _ := mintingVault(t, true)
|
|
clock := time.Date(2026, 10, 28, 9, 0, 0, 0, time.UTC)
|
|
v.Now = func() time.Time { return clock }
|
|
modules := []string{"m1", "m2", "m3", "m4", "m5", "m6", "m7", "m8"}
|
|
for _, m := range modules {
|
|
w := aWant(m)
|
|
v.WantHeard(w.User, wantRaw(t, w), false)
|
|
}
|
|
v.WantsRead()
|
|
if len(accounts.keys) != 8 {
|
|
t.Fatalf("minted %d", len(accounts.keys))
|
|
}
|
|
pass := func(n int, every time.Duration) {
|
|
for i := 0; i < n; i++ {
|
|
clock = clock.Add(every)
|
|
v.RetirePass()
|
|
}
|
|
}
|
|
v.WantHeard("ace.m1", nil, true)
|
|
pass(5, time.Second)
|
|
if _, ok := accounts.keys["ace.m1"]; !ok {
|
|
t.Fatal("retired after five passes in five seconds: ADR 0230 waits ten minutes too")
|
|
}
|
|
pass(1, 10*time.Minute)
|
|
if _, ok := accounts.keys["ace.m1"]; ok {
|
|
t.Fatalf("not retired after five passes and ten minutes: %+v", v.RetireState())
|
|
}
|
|
if rec, held, _ := v.Store.Read("own/ace/m1/broker"); !held || rec.Retired == nil {
|
|
t.Fatalf("the retired account's value is %+v (held %v): kept, and marked", rec, held)
|
|
}
|
|
if written, _ := v.HashHeld(); len(written) != 0 {
|
|
t.Errorf("a start hashed a retired account again: %+v", written)
|
|
}
|
|
// Wanted again: re-enabled at once.
|
|
w := aWant("m1")
|
|
v.WantHeard(w.User, wantRaw(t, w), false)
|
|
if rec, _, _ := v.Store.Read("own/ace/m1/broker"); rec.Retired != nil || accounts.keys["ace.m1"].Hash == "" {
|
|
t.Fatalf("wanted again, ace.m1 is %+v with hash %v", rec.Retired, accounts.keys["ace.m1"])
|
|
}
|
|
// Four gone at once is over the bound: it waits for a person, who retires them by hand.
|
|
for _, m := range modules[4:] {
|
|
v.WantHeard("ace."+m, nil, true)
|
|
}
|
|
pass(6, 3*time.Minute)
|
|
st := v.RetireState()
|
|
if len(accounts.keys) != 8 || len(st.Waiting) != 4 || !strings.Contains(st.Why, "more than 3") {
|
|
t.Fatalf("over the bound: %d keys, %+v", len(accounts.keys), st)
|
|
}
|
|
if _, err := v.RetireAccounts("person.jochen", []string{"ace.m5"}, ""); err == nil {
|
|
t.Error("retired by hand with no why")
|
|
}
|
|
if _, err := v.RetireAccounts("person.jochen", []string{"ace.m2"}, "test"); err == nil {
|
|
t.Error("retired by hand an account still wanted")
|
|
}
|
|
// Never while the controller holds the lease, nor before the wants are read whole.
|
|
held := v.LeaseRead
|
|
v.LeaseRead = func() ([]byte, bool, error) { return []byte(`{"instance":"novox/1","epoch":57}`), true, nil }
|
|
if _, err := v.RetireAccounts("person.jochen", []string{"ace.m5"}, "the modules left"); err == nil || !strings.Contains(err.Error(), "controller holds the lease") {
|
|
t.Errorf("retired by hand under the controller's lease: %v", err)
|
|
}
|
|
v.LeaseRead = held
|
|
v.LeaseHeard([]byte(`{"handed-to":"the operator's hand-over"}`), true, nil)
|
|
v.minting.mu.Lock()
|
|
v.minting.retiring.wantsRead = false
|
|
v.minting.mu.Unlock()
|
|
if _, err := v.RetireAccounts("person.jochen", []string{"ace.m5"}, "the modules left"); err == nil || !strings.Contains(err.Error(), "not read whole") {
|
|
t.Errorf("retired by hand before the wants were read: %v", err)
|
|
}
|
|
v.WantsRead()
|
|
if _, err := v.RetireAccounts("person.jochen", []string{"ace.m5", "ace.m6"}, "the modules left"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, ok := accounts.keys["ace.m5"]; ok || len(accounts.keys) != 6 {
|
|
t.Errorf("after a person's retirement %d keys remain", len(accounts.keys))
|
|
}
|
|
}
|