Files
mesh-catalog/modules/zfs/cmd/zfs-tools/hand_test.go
T
jschoubben 58664eee60 zfs: the hand acts answer started at once and the manifest asks stream-publish, bus-state-calls and ledger-calls (A-43, A-44)
Removes streamHear, HandPoll, HandWait and the stream mark; keeps toolEmit.

Builds: design 42 zfs-owns-zfs §24, §25, lead answers A-43, A-44
2026-11-13 01:52:50 +01:00

71 lines
2.5 KiB
Go

package main
import (
"context"
"encoding/json"
"errors"
"strings"
"testing"
)
// §23, §24, A-12, A-17, A-18: a hand act writes its key and starts the run's unit with {scope, unit}; the tool
// answers "started" at once and never "done" (A-43); a failed start
// leaves no key; pause writes `paused`, resume deletes it.
func TestAHandActWritesItsKeyStartsTheRunAndAnswersStartedAtOnce(t *testing.T) {
cases := []struct {
name, act, why string
callErr error
outcome string
err string
keyLeft bool
}{
{name: "snapshots", act: ActSnapshots, why: "before the move", outcome: "started", keyLeft: true},
{name: "prune", act: ActPrune, why: "free space", outcome: "started", keyLeft: true},
{name: "apply", act: ActApply, why: "now", outcome: "started", keyLeft: true},
{name: "start refused", act: ActSnapshots, why: "x", callErr: errors.New("refused"), err: "did not start"},
{name: "no why", act: ActSnapshots, why: "", err: "say why"},
{name: "unknown act", act: "destroy", why: "x", err: "not an act"},
}
for _, c := range cases {
f := newFake(t)
m := f.machine()
st := memStates{}
m.States, m.Node = st, "ace"
var key string
var body any
m.Call = func(k string, b any) (json.RawMessage, error) { key, body = k, b; return nil, c.callErr }
a, err := m.HandAct(context.Background(), c.act, "caller@node", c.why)
if c.err != "" {
if err == nil || !strings.Contains(err.Error(), c.err) {
t.Errorf("%s: %v", c.name, err)
}
} else if err != nil || a.Outcome != c.outcome {
t.Errorf("%s: %+v %v", c.name, a, err)
}
if _, left := st["schedule/"+c.act]; left != c.keyLeft {
t.Errorf("%s: key left %v, want %v", c.name, left, c.keyLeft)
}
if c.err == "" || c.callErr != nil {
args, _ := body.(map[string]any)
if key != "seat:node-service-manager.start@ace" || args["unit"] != "zfs-mesh-run.service" || args["scope"] != "system" || len(args) != 2 {
t.Errorf("%s: called %s with %v", c.name, key, body)
}
}
if c.outcome == "started" && !strings.Contains(a.Said, "zfs_module_events") {
t.Errorf("%s: did not say where the outcome is read: %s", c.name, a.Said)
}
if c.outcome == "started" && strings.Contains(a.Said, "done") {
t.Errorf("%s: said done for what it did not see: %s", c.name, a.Said)
}
}
f := newFake(t)
m := f.machine()
m.States = memStates{}
if err := m.Pause("p@n", "maintenance"); err != nil || !m.Paused() {
t.Fatal(err, m.Paused())
}
if err := m.Resume(); err != nil || m.Paused() {
t.Fatal(err, m.Paused())
}
}