comparison file/file_test.go @ 15:9b4ec6b5c23e

Add tests for multipass files.
author Paul Fisher <paul@pfish.zone>
date Thu, 29 Oct 2015 23:56:53 -0400
parents
children bfc035bd5132
comparison
equal deleted inserted replaced
14:4368a377ff64 15:9b4ec6b5c23e
1 package file
2
3 import (
4 "fmt"
5 "io/ioutil"
6 "os"
7 "path"
8 "testing"
9 "time"
10
11 "pfish.zone/go/multipass/auth"
12 )
13
14 var tempdir string
15
16 const (
17 filemode = 0644
18
19 shadowSpooky = "123:bogushash:c3Bvb2t5"
20 shadowWhatever = "456:anotherhash:d2hhdGV2ZXI="
21 )
22
23 var (
24 aSpooky *auth.Entry
25 aWhatever *auth.Entry
26 )
27
28 func init() {
29 s, err := auth.EntryFromShadow(shadowSpooky)
30 if err != nil {
31 panic(err.Error())
32 }
33 aSpooky = s
34 w, err := auth.EntryFromShadow(shadowWhatever)
35 if err != nil {
36 panic(err.Error())
37 }
38 aWhatever = w
39 }
40
41 func TestMain(m *testing.M) {
42 dir, err := ioutil.TempDir(os.TempDir(), "multipass-")
43 maxDelay = 2 * time.Second
44 tempdir = dir
45 if err != nil {
46 panic("couldn't create temp dir")
47 }
48 m.Run()
49 os.RemoveAll(tempdir)
50 }
51
52 type testfile struct {
53 t *testing.T
54 dir string
55 }
56
57 func mktest(t *testing.T, dir string) *testfile {
58 f := &testfile{t, dir}
59 os.Mkdir(f.dirpath(), 0700)
60 return f
61 }
62
63 func (f *testfile) dirpath() string {
64 return path.Join(tempdir, f.dir)
65 }
66
67 func (f *testfile) filepath() string {
68 return path.Join(f.dirpath(), "file")
69 }
70
71 func (f *testfile) read() string {
72 contents, err := ioutil.ReadFile(f.filepath())
73 if err != nil {
74 f.t.Fatalf("couldn't read output file: %q", err.Error())
75 }
76 return string(contents)
77 }
78
79 func (f *testfile) write(data string) {
80 err := ioutil.WriteFile(f.filepath(), []byte(data), filemode)
81 if err != nil {
82 f.t.Fatalf("couldn't write output file: %q", err)
83 }
84 }
85
86 func (f *testfile) perms() os.FileMode {
87 stat, err := os.Stat(f.filepath())
88 if err != nil {
89 f.t.Fatalf("couldn't stat output file: %q", err)
90 }
91 return stat.Mode().Perm()
92 }
93
94 func (f *testfile) cleanup() {
95 os.RemoveAll(f.dirpath())
96 }
97
98 func TestCreate(t *testing.T) {
99 f := mktest(t, "create")
100 defer f.cleanup()
101 s := New(f.filepath())
102 err := s.Add(aSpooky)
103 if err != nil {
104 t.Fatal(err.Error())
105 }
106 if f.perms() != filemode {
107 t.Errorf("want perms %q; got %q", filemode, f.perms())
108 }
109 want := fmt.Sprintf("%s\n%s\n", Banner, shadowSpooky)
110 got := f.read()
111 if want != got {
112 t.Errorf("bad file contents: want %q; got %q", want, got)
113 }
114 }
115
116 func TestAppend(t *testing.T) {
117 f := mktest(t, "append")
118 defer f.cleanup()
119 f.write(fmt.Sprintf("%s\n%s\n", Banner, shadowSpooky))
120 s := New(f.filepath())
121 err := s.Add(aWhatever)
122 if err != nil {
123 t.Fatal(err.Error())
124 }
125 want := fmt.Sprintf("%s\n%s\n%s\n", Banner, shadowWhatever, shadowSpooky)
126 got := f.read()
127 if want != got {
128 t.Errorf("bad file contents: want %q; got %q", want, got)
129 }
130 }
131
132 func TestRemove(t *testing.T) {
133 f := mktest(t, "remove")
134 defer f.cleanup()
135 f.write(fmt.Sprintf("%s\n%s\n%s\n", Banner, shadowWhatever, shadowSpooky))
136 s := New(f.filepath())
137 err := s.Remove(456)
138 if err != nil {
139 t.Fatal(err.Error())
140 }
141 want := fmt.Sprintf("%s\n%s\n", Banner, shadowSpooky)
142 got := f.read()
143 if want != got {
144 t.Errorf("bad file contents: want %q; got %q", want, got)
145 }
146
147 // Removing a nonexistent entry is idempotent.
148 err = s.Remove(456)
149 if err != nil {
150 t.Fatal(err.Error())
151 }
152 got = f.read()
153 if want != got {
154 t.Errorf("bad file contents: want %q; got %q", want, got)
155 }
156
157 // Removing the remaining entry leaves an empty file.
158 err = s.Remove(123)
159 if err != nil {
160 t.Fatal(err.Error())
161 }
162 want = fmt.Sprintf("%s\n", Banner)
163 got = f.read()
164 if want != got {
165 t.Errorf("bad file contents: want %q; got %q", want, got)
166 }
167 }
168
169 func TestList(t *testing.T) {
170 f := mktest(t, "list")
171 defer f.cleanup()
172 s := New(f.filepath())
173 entries, err := s.AllEntries()
174 if len(entries) != 0 {
175 t.Errorf("want 0 entries; got %q", entries)
176 }
177
178 f.write(fmt.Sprintf("%s\n%s\n%s\n", Banner, shadowWhatever, shadowSpooky))
179 entries, err = s.AllEntries()
180 if err != nil {
181 t.Fatal(err.Error())
182 }
183 if len(entries) != 2 {
184 t.Fatalf("want len(entries) == 2; got entries = %q", entries)
185 }
186 if *entries[0] != *aWhatever || *entries[1] != *aSpooky {
187 t.Fatalf("want {aWhatever, aSpooky}; got %q", entries)
188 }
189 }
190
191 func TestAuthenticate(t *testing.T) {
192 f := mktest(t, "auth")
193 defer f.cleanup()
194 s := New(f.filepath())
195 eA, passA, err := auth.NewEntry("a")
196 if err != nil {
197 t.Fatalf(err.Error())
198 }
199 eB, passB, err := auth.NewEntry("b")
200 if err != nil {
201 t.Fatalf(err.Error())
202 }
203 err = s.Add(eA)
204 if err != nil {
205 t.Fatalf(err.Error())
206 }
207 err = s.Add(eB)
208 if err != nil {
209 t.Fatalf(err.Error())
210 }
211 good, err := s.Authenticate(passA)
212 if !good {
213 t.Errorf("couldn't authenticate password A")
214 }
215 good, err = s.Authenticate(passB)
216 if !good {
217 t.Errorf("couldn't authenticate password B")
218 }
219 bad, err := s.Authenticate("boo")
220 if bad {
221 t.Errorf("authenticated bad password")
222 }
223 }
224
225 type clobberEvent int
226
227 const (
228 unlocked clobberEvent = iota
229 written
230 failed
231 )
232
233 func TestNoClobber(t *testing.T) {
234 f := mktest(t, "clobber")
235 defer f.cleanup()
236 f.write(fmt.Sprintf("%s\n", Banner))
237 s := New(f.filepath())
238 // put a file in the system's new-file so it won't overwrite it.
239 err := ioutil.WriteFile(s.newFilename(), nil, filemode)
240 if err != nil {
241 t.Fatalf(err.Error())
242 }
243 events := make(chan clobberEvent, 10)
244 go func() {
245 err := s.Add(aWhatever)
246 if err != nil {
247 events <- failed
248 return
249 }
250 events <- written
251 }()
252 time.Sleep(time.Second)
253 events <- unlocked
254 err = os.Remove(s.newFilename())
255 if err != nil {
256 t.Fatalf(err.Error())
257 }
258 ev := <-events
259 if unlocked != ev {
260 t.Errorf("event 0: %q; got %q", unlocked, ev)
261 }
262 ev = <-events
263 if written != ev {
264 t.Errorf("event 1: %q; got %q", written, ev)
265 }
266
267 want := fmt.Sprintf("%s\n%s\n", Banner, shadowWhatever)
268 got := f.read()
269 if want != got {
270 t.Errorf("bad contents: want %q; got %q", want, got)
271 }
272 }
273
274 func TestGiveUp(t *testing.T) {
275 f := mktest(t, "giveup")
276 defer f.cleanup()
277 f.write(fmt.Sprintf("%s\n", Banner))
278 s := New(f.filepath())
279 // put a file in the system's new-file so it won't overwrite it.
280 err := ioutil.WriteFile(s.newFilename(), nil, filemode)
281 if err != nil {
282 t.Fatalf(err.Error())
283 }
284 events := make(chan clobberEvent, 10)
285 go func() {
286 err := s.Add(aWhatever)
287 if err != nil {
288 events <- failed
289 return
290 }
291 events <- written
292 }()
293 time.Sleep(5 * time.Second)
294 events <- unlocked
295 err = os.Remove(s.newFilename())
296 if err != nil {
297 t.Fatalf(err.Error())
298 }
299 ev := <-events
300 if failed != ev {
301 t.Errorf("event 0: want %q; got %q", failed, ev)
302 }
303 ev = <-events
304 if unlocked != ev {
305 t.Errorf("event 1: want %q; got %q", unlocked, ev)
306 }
307
308 want := fmt.Sprintf("%s\n", Banner)
309 got := f.read()
310 if want != got {
311 t.Errorf("bad contents: want %q; got %q", want, got)
312 }
313 }