package main import ( "context" "fmt" "os" "path/filepath" "strings" "testing" "time" ) // fake is a machine for a test: a tree standing in for /proc and /sys, a statfs answering from a table, // a runner answering from a table, and a wait that turns the tree into its second reading. type fake struct { t *testing.T root string later map[string]string gone []string space map[string]FSStat answers map[string]string calls []string waited time.Duration } func newFake(t *testing.T) *fake { t.Helper() return &fake{t: t, root: t.TempDir(), later: map[string]string{}, space: map[string]FSStat{}, answers: map[string]string{}} } func (f *fake) machine() *Machine { return &Machine{ Root: f.root, Run: func(_ context.Context, name string, args ...string) (string, error) { line := strings.TrimSpace(name + " " + strings.Join(args, " ")) f.calls = append(f.calls, line) if out, ok := f.answers[line]; ok { return out, nil } return "", fmt.Errorf("%s: not found", name) }, Wait: func(d time.Duration) { f.waited += d for p, c := range f.later { f.file(p, c) } for _, p := range f.gone { os.RemoveAll(filepath.Join(f.root, p)) } }, Statfs: func(path string) (FSStat, error) { rel, _ := filepath.Rel(f.root, path) s, ok := f.space[filepath.Clean("/"+filepath.ToSlash(rel))] if !ok { return FSStat{}, fmt.Errorf("no such filesystem") } return s, nil }, } } // file writes a file under the fake root. func (f *fake) file(path, content string) { f.t.Helper() full := filepath.Join(f.root, path) if err := os.MkdirAll(filepath.Dir(full), 0o755); err != nil { f.t.Fatal(err) } if err := os.WriteFile(full, []byte(content), 0o644); err != nil { f.t.Fatal(err) } } // dir makes a directory under the fake root: sysfs's entries that are links on a real machine are // directories here, because the module only lists their names. func (f *fake) dir(path string) { f.t.Helper() if err := os.MkdirAll(filepath.Join(f.root, path), 0o755); err != nil { f.t.Fatal(err) } } // then is a file's content at the second reading. func (f *fake) then(path, content string) { f.later[path] = content }