78 lines
2.6 KiB
Go
78 lines
2.6 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"sort"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
type memStates map[string]json.RawMessage
|
|
|
|
func (s memStates) Put(state, key string, v any) error {
|
|
b, _ := json.Marshal(v)
|
|
s[state+"/"+key] = b
|
|
return nil
|
|
}
|
|
func (s memStates) Delete(state, key string) error { delete(s, state+"/"+key); return nil }
|
|
func (s memStates) Keys(state string) ([]string, error) {
|
|
var out []string
|
|
for k := range s {
|
|
if rest, ok := strings.CutPrefix(k, state+"/"); ok {
|
|
out = append(out, rest)
|
|
}
|
|
}
|
|
sort.Strings(out)
|
|
return out, nil
|
|
}
|
|
func (s memStates) Get(state, key string) (json.RawMessage, bool, error) {
|
|
b, ok := s[state+"/"+key]
|
|
return b, ok, nil
|
|
}
|
|
|
|
// §25, §26: each change emits its event with before and after and keeps its key of the state `applied`, a
|
|
// refusal and a wait too, a wait keeping its first since, and a value back to not managed leaves the state.
|
|
func TestEachChangeIsSaidAndKeptAndANotManagedValueLeavesTheState(t *testing.T) {
|
|
f := newFake(t)
|
|
m := f.machine()
|
|
st := memStates{}
|
|
m.States = st
|
|
if err := m.Changed("pool", "pool-properties.autotrim", "off", "on", "on"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
e := f.emitted[0]
|
|
if e["_type"] != "config.applied" || e["target"] != "pool" || e["key"] != "pool-properties.autotrim" ||
|
|
e["before"] != "off" || e["after"] != "on" || e["read-back"] != "on" {
|
|
t.Errorf("event: %v", e)
|
|
}
|
|
var got AppliedEntry
|
|
json.Unmarshal(st["applied/pool-properties.autotrim"], &got)
|
|
if got.Before != "off" || got.After != "on" || got.Outcome != OutcomeApplied || !got.At.Equal(f.now.UTC()) {
|
|
t.Errorf("state: %+v", got)
|
|
}
|
|
if err := m.Refused(Refusal{Key: "hostid", Value: "zzz", Reason: "is not eight hexadecimal digits"}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if f.emitted[1]["_type"] != "config.refused" || f.emitted[1]["reason"] == "" || !strings.Contains(string(st["applied/hostid"]), `"refused"`) {
|
|
t.Errorf("refusal: %v %s", f.emitted[1], st["applied/hostid"])
|
|
}
|
|
m.Waiting("log-devices", "the pool's scrub")
|
|
first := f.now
|
|
f.now = f.now.Add(time.Hour)
|
|
m.Waiting("log-devices", "the pool's scrub")
|
|
var w AppliedEntry
|
|
json.Unmarshal(st["applied/log-devices"], &w)
|
|
if f.emitted[3]["_type"] != "config.waiting" || !w.Since.Equal(first.UTC()) || !w.At.Equal(f.now.UTC()) || w.Outcome != OutcomeWaiting {
|
|
t.Errorf("wait: %v %+v", f.emitted[3], w)
|
|
}
|
|
m.NotManaged("log-devices")
|
|
if _, ok := st["applied/log-devices"]; ok {
|
|
t.Error("the key stays after the value went back to not managed")
|
|
}
|
|
m.Emit = nil
|
|
if err := m.Changed("pool", "k", "a", "b", "b"); err == nil {
|
|
t.Error("an event that cannot be said is said as done")
|
|
}
|
|
}
|