1
16
17 package fstest
18
19 import (
20 "context"
21 "os"
22 "testing"
23 )
24
25
26 type TestApplier interface {
27 TestContext(context.Context) (context.Context, func(), error)
28 Apply(context.Context, Applier) (string, func(), error)
29 }
30
31
32 func FSSuite(t *testing.T, a TestApplier) {
33 t.Run("Basic", makeTest(t, a, basicTest))
34 t.Run("Deletion", makeTest(t, a, deletionTest))
35 t.Run("Update", makeTest(t, a, updateTest))
36 t.Run("DirectoryPermission", makeTest(t, a, directoryPermissionsTest))
37 t.Run("ParentDirectoryPermission", makeTest(t, a, parentDirectoryPermissionsTest))
38 t.Run("HardlinkUnmodified", makeTest(t, a, hardlinkUnmodified))
39 t.Run("HardlinkBeforeUnmodified", makeTest(t, a, hardlinkBeforeUnmodified))
40 t.Run("HardlinkBeforeModified", makeTest(t, a, hardlinkBeforeModified))
41 }
42
43 func makeTest(t *testing.T, ta TestApplier, as []Applier) func(t *testing.T) {
44 return func(t *testing.T) {
45 ctx, cleanup, err := ta.TestContext(context.Background())
46 if err != nil {
47 t.Fatalf("Unable to get test context: %+v", err)
48 }
49 defer cleanup()
50
51 applyDir, err := os.MkdirTemp("", "test-expected-")
52 if err != nil {
53 t.Fatalf("Unable to make temp directory: %+v", err)
54 }
55 defer os.RemoveAll(applyDir)
56
57 for i, a := range as {
58 testDir, c, err := ta.Apply(ctx, a)
59 if err != nil {
60 t.Fatalf("Apply failed at %d: %+v", i, err)
61 }
62 if err := a.Apply(applyDir); err != nil {
63 if c != nil {
64 c()
65 }
66 t.Fatalf("Error applying change to apply directory: %+v", err)
67 }
68
69 err = CheckDirectoryEqual(applyDir, testDir)
70 if c != nil {
71 c()
72 }
73 if err != nil {
74 t.Fatalf("Directories not equal at %d (expected <> tested): %+v", i, err)
75 }
76 }
77 }
78 }
79
80 var (
81
82
83 baseApplier = Apply(
84 CreateDir("/etc/", 0o755),
85 CreateFile("/etc/hosts", []byte("127.0.0.1 localhost"), 0o644),
86 Link("/etc/hosts", "/etc/hosts.allow"),
87 CreateDir("/usr/local/lib", 0o755),
88 CreateFile("/usr/local/lib/libnothing.so", []byte{0x00, 0x00}, 0o755),
89 Symlink("libnothing.so", "/usr/local/lib/libnothing.so.2"),
90 CreateDir("/home", 0o755),
91 CreateDir("/home/derek", 0o700),
92
93 )
94
95
96 basicTest = []Applier{
97 baseApplier,
98 Apply(
99 CreateFile("/etc/hosts", []byte("127.0.0.1 localhost.localdomain"), 0o644),
100 CreateFile("/etc/fstab", []byte("/dev/sda1\t/\text4\tdefaults 1 1\n"), 0o600),
101 CreateFile("/etc/badfile", []byte(""), 0o666),
102 CreateFile("/home/derek/.zshrc", []byte("#ZSH is just better\n"), 0o640),
103 ),
104 Apply(
105 Remove("/etc/badfile"),
106 Rename("/home/derek", "/home/notderek"),
107 ),
108 Apply(
109 RemoveAll("/usr"),
110 Remove("/etc/hosts.allow"),
111 ),
112 Apply(
113 RemoveAll("/home"),
114 CreateDir("/home/derek", 0o700),
115 CreateFile("/home/derek/.bashrc", []byte("#not going away\n"), 0o640),
116 Link("/etc/hosts", "/etc/hosts.allow"),
117 ),
118 }
119
120
121
122 deletionTest = []Applier{
123 Apply(
124 CreateDir("/test/somedir", 0o755),
125 CreateDir("/lib", 0o700),
126 CreateFile("/lib/hidden", []byte{}, 0o644),
127 ),
128 Apply(
129 CreateFile("/test/a", []byte{}, 0o644),
130 CreateFile("/test/b", []byte{}, 0o644),
131 CreateDir("/test/otherdir", 0o755),
132 CreateFile("/test/otherdir/.empty", []byte{}, 0o644),
133 RemoveAll("/lib"),
134 CreateDir("/lib", 0o700),
135 CreateFile("/lib/not-hidden", []byte{}, 0o644),
136 ),
137 Apply(
138 Remove("/test/a"),
139 Remove("/test/b"),
140 RemoveAll("/test/otherdir"),
141 CreateFile("/lib/newfile", []byte{}, 0o644),
142 ),
143 }
144
145
146 updateTest = []Applier{
147 Apply(
148 CreateDir("/d1", 0o755),
149 CreateDir("/d2", 0o700),
150 CreateFile("/d1/f1", []byte("something..."), 0o644),
151 CreateFile("/d1/f2", []byte("else..."), 0o644),
152 CreateFile("/d1/f3", []byte("entirely..."), 0o644),
153 ),
154 Apply(
155 CreateFile("/d1/f1", []byte("file content of a different length"), 0o664),
156 Remove("/d1/f3"),
157 CreateFile("/d1/f3", []byte("updated content"), 0o664),
158 Chmod("/d1/f2", 0o766),
159 Chmod("/d2", 0o777),
160 ),
161 }
162
163
164 directoryPermissionsTest = []Applier{
165 Apply(
166 CreateDir("/d1", 0o700),
167 CreateDir("/d2", 0o751),
168 CreateDir("/d3", 0o777),
169 ),
170 Apply(
171 CreateFile("/d1/f", []byte("irrelevant"), 0o644),
172 CreateDir("/d1/d", 0o700),
173 CreateFile("/d1/d/f", []byte("irrelevant"), 0o644),
174 CreateFile("/d2/f", []byte("irrelevant"), 0o644),
175 CreateFile("/d3/f", []byte("irrelevant"), 0o644),
176 ),
177 }
178
179
180
181 parentDirectoryPermissionsTest = []Applier{
182 Apply(
183 CreateDir("/d1", 0o700),
184 CreateDir("/d1/a", 0o700),
185 CreateDir("/d1/a/b", 0o700),
186 CreateDir("/d1/a/b/c", 0o700),
187 CreateFile("/d1/a/b/f", []byte("content1"), 0o644),
188 CreateDir("/d2", 0o751),
189 CreateDir("/d2/a/b", 0o751),
190 CreateDir("/d2/a/b/c", 0o751),
191 CreateFile("/d2/a/b/f", []byte("content1"), 0o644),
192 ),
193 Apply(
194 CreateFile("/d1/a/b/f", []byte("content1"), 0o644),
195 Chmod("/d1/a/b/c", 0o700),
196 CreateFile("/d2/a/b/f", []byte("content2"), 0o644),
197 Chmod("/d2/a/b/c", 0o751),
198 ),
199 }
200
201 hardlinkUnmodified = []Applier{
202 baseApplier,
203 Apply(
204 CreateFile("/etc/hosts", []byte("127.0.0.1 localhost.localdomain"), 0o644),
205 ),
206 Apply(
207 Link("/etc/hosts", "/etc/hosts.deny"),
208 ),
209 }
210
211
212
213 hardlinkBeforeUnmodified = []Applier{
214 baseApplier,
215 Apply(
216 CreateFile("/etc/hosts", []byte("127.0.0.1 localhost.localdomain"), 0o644),
217 ),
218 Apply(
219 Link("/etc/hosts", "/etc/before-hosts"),
220 ),
221 }
222
223
224
225 hardlinkBeforeModified = []Applier{
226 baseApplier,
227 Apply(
228 CreateFile("/etc/hosts", []byte("127.0.0.1 localhost.localdomain"), 0o644),
229 ),
230 Apply(
231 Remove("/etc/hosts"),
232 CreateFile("/etc/hosts", []byte("127.0.0.1 localhost"), 0o644),
233 Link("/etc/hosts", "/etc/before-hosts"),
234 ),
235 }
236 )
237
View as plain text