Mercurial > go > multipass
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 } |
