101 lines
4.2 KiB
Go
101 lines
4.2 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// §16, §31 convergence table: a property at its value runs nothing; a set one is set and read back and
|
|
// said; `default` is ZFS's default for a pool property and an inherit for a dataset's; a read-back that
|
|
// differs is a failure.
|
|
func TestPropertiesConvergeFromWhatZFSSays(t *testing.T) {
|
|
cfg := func(j string) *Config {
|
|
c, ref := ParseConfig([]byte(j), 16000)
|
|
if len(ref) != 0 {
|
|
t.Fatal(ref)
|
|
}
|
|
return c
|
|
}
|
|
type step struct{ cmd, out string }
|
|
cases := []struct {
|
|
name string
|
|
conf string
|
|
reads []step // read answers
|
|
writes []string
|
|
after map[string]string // a read that changes once the write ran
|
|
events int
|
|
fails bool
|
|
}{
|
|
{"pool property at its value", `{"pool":"tank","pool-properties":{"autotrim":"on"}}`,
|
|
[]step{{"zpool get -Hp -o value autotrim -- tank", "on\n"}}, nil, nil, 0, false},
|
|
{"pool property set", `{"pool":"tank","pool-properties":{"autotrim":"on"}}`,
|
|
[]step{{"zpool get -Hp -o value autotrim -- tank", "off\n"}}, []string{"zpool set autotrim=on -- tank"},
|
|
map[string]string{"zpool get -Hp -o value autotrim -- tank": "on\n"}, 1, false},
|
|
{"pool property to ZFS's default", `{"pool":"tank","pool-properties":{"failmode":"default"}}`,
|
|
[]step{{"zpool get -Hp -o value failmode -- tank", "continue\n"}}, []string{"zpool set failmode=wait -- tank"},
|
|
map[string]string{"zpool get -Hp -o value failmode -- tank": "wait\n"}, 1, false},
|
|
{"pool property read back differs", `{"pool":"tank","pool-properties":{"autotrim":"on"}}`,
|
|
[]step{{"zpool get -Hp -o value autotrim -- tank", "off\n"}}, []string{"zpool set autotrim=on -- tank"}, nil, 0, true},
|
|
{"dataset size at its value in bytes", `{"pool":"tank","dataset-properties":{"tank/a":{"recordsize":"1M"}}}`,
|
|
[]step{{"zfs get -Hp -o value,source recordsize -- tank/a", "1048576\tlocal\n"}}, nil, nil, 0, false},
|
|
{"dataset compression set", `{"pool":"tank","dataset-properties":{"tank":{"compression":"zstd-3"}}}`,
|
|
[]step{{"zfs get -Hp -o value,source compression -- tank", "lz4\tlocal\n"}}, []string{"zfs set compression=zstd-3 -- tank"},
|
|
map[string]string{"zfs get -Hp -o value,source compression -- tank": "zstd-3\tlocal\n"}, 1, false},
|
|
{"dataset default of an inherited one", `{"pool":"tank","dataset-properties":{"tank/a":{"atime":"default"}}}`,
|
|
[]step{{"zfs get -Hp -o value,source atime -- tank/a", "on\tinherited from tank\n"}}, nil, nil, 0, false},
|
|
{"dataset default of a local one", `{"pool":"tank","dataset-properties":{"tank/a":{"atime":"default"}}}`,
|
|
[]step{{"zfs get -Hp -o value,source atime -- tank/a", "off\tlocal\n"}}, []string{"zfs inherit atime -- tank/a"},
|
|
map[string]string{"zfs get -Hp -o value,source atime -- tank/a": "on\tdefault\n"}, 1, false},
|
|
{"quota none at zero", `{"pool":"tank","dataset-properties":{"tank/a":{"quota":"none"}}}`,
|
|
[]step{{"zfs get -Hp -o value,source quota -- tank/a", "0\tdefault\n"}}, nil, nil, 0, false},
|
|
}
|
|
for _, c := range cases {
|
|
f := newFake(t)
|
|
f.uid = 0
|
|
for _, r := range c.reads {
|
|
f.on(r.cmd, r.out)
|
|
}
|
|
wrote := map[string]bool{}
|
|
for _, w := range c.writes {
|
|
w := w
|
|
f.on(w, "")
|
|
f.after[w] = func(f *fake) {
|
|
wrote[w] = true
|
|
for k, v := range c.after {
|
|
f.on(k, v)
|
|
}
|
|
}
|
|
}
|
|
m := f.machine()
|
|
m.States = memStates{}
|
|
err := m.ApplyProperties(context.Background(), cfg(c.conf))
|
|
if (err != nil) != c.fails {
|
|
t.Errorf("%s: error %v", c.name, err)
|
|
}
|
|
for _, w := range c.writes {
|
|
if !wrote[w] {
|
|
t.Errorf("%s: %q not run; ran %v", c.name, w, f.calls)
|
|
}
|
|
}
|
|
for _, call := range f.calls {
|
|
if (strings.Contains(call, " set ") || strings.Contains(call, " inherit ")) && !contains(c.writes, call) {
|
|
t.Errorf("%s: ran %q", c.name, call)
|
|
}
|
|
}
|
|
if len(f.emitted) != c.events {
|
|
t.Errorf("%s: %d events, want %d: %v", c.name, len(f.emitted), c.events, f.emitted)
|
|
}
|
|
}
|
|
}
|
|
|
|
// §10: a dataset's sharenfs and sharesmb are never converged, never run: the parse refuses them, so the
|
|
// apply has no Config to run.
|
|
func TestSharenfsAndSharesmbAreNeverASetProperty(t *testing.T) {
|
|
for _, p := range []string{"sharenfs", "sharesmb"} {
|
|
if c, ref := ParseConfig([]byte(`{"pool":"tank","dataset-properties":{"tank":{"`+p+`":"on"}}}`), 16000); c != nil || len(ref) == 0 {
|
|
t.Errorf("%s accepted", p)
|
|
}
|
|
}
|
|
}
|