75 lines
3.2 KiB
Go
75 lines
3.2 KiB
Go
package handacts
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// ADR 0565 clauses 10 and 11 (issue 1953 L5-S2, S4): an act reads the controller's entries unchanged, and a recorder
|
|
// records through the seat, through the controller's verb only while the seat has no holder and the lease is the
|
|
// controller's, saying which log took it, and refuses to record nowhere.
|
|
func TestAnActIsRecordedInTheLogThatAnswers(t *testing.T) {
|
|
// The shape of mesh-controller internal/link HandAct, as its bucket keeps an entry (handacts.go at 0fbb5ef3).
|
|
raw := `{"id":"act-1","at":"2026-10-28T09:00:00Z","by":"person.jochen","verb":"hand-act record","why":"a stuck consumer",` +
|
|
`"cause":"consumer-lost","condition":"bus.EVENTS.x.consumer-lost","via":"telegram","ask":"a-1","proofs":["P1"],` +
|
|
`"requested-by":"bus.EVENTS.x.consumer-lost","outcome":"done"}`
|
|
var a Act
|
|
if err := json.Unmarshal([]byte(raw), &a); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
again, _ := json.Marshal(a)
|
|
var want, got map[string]any
|
|
_ = json.Unmarshal([]byte(raw), &want)
|
|
_ = json.Unmarshal(again, &got)
|
|
if !reflect.DeepEqual(want, got) || !a.Repair() || (Act{Cause: CauseDrill}).Repair() || (Act{Verb: VerbDrill}).Repair() {
|
|
t.Errorf("the controller's entry reads back as %s", again)
|
|
}
|
|
noResponders := errors.New("nats: no responders available for request")
|
|
for _, c := range []struct {
|
|
name string
|
|
seat error
|
|
ctrl error
|
|
away bool
|
|
log string
|
|
refused string
|
|
asked string
|
|
warrants bool
|
|
}{
|
|
{name: "the seat answers", log: LogSeat, asked: "seat:mesh-hand-acts.hand-act"},
|
|
{name: "no holder yet", seat: noResponders, log: LogController, asked: "seat:mesh-hand-acts.hand-act,seat:mesh-controller.hand-act"},
|
|
{name: "no holder, the lease handed away", seat: noResponders, away: true, refused: "handed its lease away",
|
|
asked: "seat:mesh-hand-acts.hand-act"},
|
|
{name: "the seat refuses", seat: errors.New("why is required"), refused: "refused", asked: "seat:mesh-hand-acts.hand-act"},
|
|
{name: "neither answers", seat: noResponders, ctrl: noResponders, refused: "refused too",
|
|
asked: "seat:mesh-hand-acts.hand-act,seat:mesh-controller.hand-act"},
|
|
{name: "a warrant without a holder", seat: noResponders, warrants: true, log: LogController,
|
|
asked: "seat:mesh-hand-acts.warranted,seat:mesh-controller.warranted"},
|
|
} {
|
|
var asked []string
|
|
r := Recorder{LeaseAway: func() bool { return c.away }, Ask: func(key string, body any) (json.RawMessage, error) {
|
|
asked = append(asked, key)
|
|
if strings.HasPrefix(key, "seat:mesh-hand-acts.") {
|
|
return json.RawMessage(`{}`), c.seat
|
|
}
|
|
return json.RawMessage(`{}`), c.ctrl
|
|
}}
|
|
var taken Taken
|
|
var err error
|
|
if c.warrants {
|
|
taken, err = r.RecordWarrant("mesh-config", "ask-1")
|
|
} else {
|
|
taken, err = r.Record(Request{What: "silenced", Why: "known", Cause: "silent", Verb: "conditions silence"})
|
|
}
|
|
if (c.refused != "") != (err != nil) || (err != nil && !strings.Contains(err.Error(), c.refused)) || taken.Log != c.log ||
|
|
strings.Join(asked, ",") != c.asked {
|
|
t.Errorf("%s: took %q, %v, asked %v", c.name, taken.Log, err, asked)
|
|
}
|
|
}
|
|
if _, err := (Recorder{}).Record(Request{What: "x"}); err == nil {
|
|
t.Error("an act with no why was recorded")
|
|
}
|
|
}
|