github.com/olivere/camlistore@v0.0.0-20140121221811-1b7ac2da0199/third_party/code.google.com/p/rsc/fuse/fuse_test.go (about) 1 // Copyright 2012 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package fuse 6 7 import ( 8 "flag" 9 "fmt" 10 "io/ioutil" 11 "log" 12 "os" 13 "os/exec" 14 "runtime" 15 "syscall" 16 "testing" 17 "time" 18 ) 19 20 var fuseRun = flag.String("fuserun", "", "which fuse test to run. runs all if empty.") 21 22 // umount tries its best to unmount dir. 23 func umount(dir string) { 24 err := exec.Command("umount", dir).Run() 25 if err != nil && runtime.GOOS == "linux" { 26 exec.Command("/bin/fusermount", "-u", dir).Run() 27 } 28 } 29 30 func TestFuse(t *testing.T) { 31 Debugf = log.Printf 32 dir, err := ioutil.TempDir("", "fusetest") 33 if err != nil { 34 t.Fatal(err) 35 } 36 os.MkdirAll(dir, 0777) 37 38 c, err := Mount(dir) 39 if err != nil { 40 t.Fatal(err) 41 } 42 defer umount(dir) 43 44 go func() { 45 err := c.Serve(testFS{}) 46 if err != nil { 47 fmt.Println("SERVE ERROR: %v\n", err) 48 } 49 }() 50 51 waitForMount(t, dir) 52 53 for _, tt := range fuseTests { 54 if *fuseRun == "" || *fuseRun == tt.name { 55 t.Logf("running %T", tt.node) 56 tt.node.test(dir+"/"+tt.name, t) 57 } 58 } 59 } 60 61 func waitForMount(t *testing.T, dir string) { 62 // Filename to wait for in dir: 63 probeEntry := *fuseRun 64 if probeEntry == "" { 65 probeEntry = fuseTests[0].name 66 } 67 for tries := 0; tries < 100; tries++ { 68 _, err := os.Stat(dir + "/" + probeEntry) 69 if err == nil { 70 return 71 } 72 time.Sleep(10 * time.Millisecond) 73 } 74 t.Fatalf("mount did not work") 75 } 76 77 var fuseTests = []struct { 78 name string 79 node interface { 80 Node 81 test(string, *testing.T) 82 } 83 }{ 84 {"readAll", readAll{}}, 85 {"readAll1", &readAll1{}}, 86 {"write", &write{}}, 87 {"writeAll", &writeAll{}}, 88 {"writeAll2", &writeAll2{}}, 89 {"release", &release{}}, 90 {"mkdir1", &mkdir1{}}, 91 {"create1", &create1{}}, 92 {"create2", &create2{}}, 93 {"symlink1", &symlink1{}}, 94 {"link1", &link1{}}, 95 {"rename1", &rename1{}}, 96 {"mknod1", &mknod1{}}, 97 } 98 99 // TO TEST: 100 // Statfs 101 // Lookup(*LookupRequest, *LookupResponse) 102 // Getattr(*GetattrRequest, *GetattrResponse) 103 // Attr with explicit inode 104 // Setattr(*SetattrRequest, *SetattrResponse) 105 // Access(*AccessRequest) 106 // Open(*OpenRequest, *OpenResponse) 107 // Getxattr, Setxattr, Listxattr, Removexattr 108 // Write(*WriteRequest, *WriteResponse) 109 // Flush(*FlushRequest, *FlushResponse) 110 111 // Test Read calling ReadAll. 112 113 type readAll struct{ file } 114 115 const hi = "hello, world" 116 117 func (readAll) ReadAll(intr Intr) ([]byte, Error) { 118 return []byte(hi), nil 119 } 120 121 func (readAll) test(path string, t *testing.T) { 122 data, err := ioutil.ReadFile(path) 123 if err != nil { 124 t.Errorf("readAll: %v", err) 125 return 126 } 127 if string(data) != hi { 128 t.Errorf("readAll = %q, want %q", data, hi) 129 } 130 } 131 132 // Test Read. 133 134 type readAll1 struct{ file } 135 136 func (readAll1) Read(req *ReadRequest, resp *ReadResponse, intr Intr) Error { 137 HandleRead(req, resp, []byte(hi)) 138 return nil 139 } 140 141 func (readAll1) test(path string, t *testing.T) { 142 readAll{}.test(path, t) 143 } 144 145 // Test Write calling basic Write, with an fsync thrown in too. 146 147 type write struct { 148 file 149 data []byte 150 gotfsync bool 151 } 152 153 func (w *write) Write(req *WriteRequest, resp *WriteResponse, intr Intr) Error { 154 w.data = append(w.data, req.Data...) 155 resp.Size = len(req.Data) 156 return nil 157 } 158 159 func (w *write) Fsync(r *FsyncRequest, intr Intr) Error { 160 w.gotfsync = true 161 return nil 162 } 163 164 func (w *write) test(path string, t *testing.T) { 165 log.Printf("pre-write Create") 166 f, err := os.Create(path) 167 if err != nil { 168 t.Fatalf("Create: %v", err) 169 } 170 log.Printf("pre-write Write") 171 n, err := f.Write([]byte(hi)) 172 if err != nil { 173 t.Fatalf("Write: %v", err) 174 } 175 if n != len(hi) { 176 t.Fatalf("short write; n=%d; hi=%d", n, len(hi)) 177 } 178 179 err = syscall.Fsync(int(f.Fd())) 180 if err != nil { 181 t.Fatalf("Fsync = %v", err) 182 } 183 if !w.gotfsync { 184 t.Errorf("never received expected fsync call") 185 } 186 187 log.Printf("pre-write Close") 188 err = f.Close() 189 if err != nil { 190 t.Fatalf("Close: %v", err) 191 } 192 log.Printf("post-write Close") 193 if string(w.data) != hi { 194 t.Errorf("writeAll = %q, want %q", w.data, hi) 195 } 196 } 197 198 // Test Write calling WriteAll. 199 200 type writeAll struct { 201 file 202 data []byte 203 gotfsync bool 204 } 205 206 func (w *writeAll) Fsync(r *FsyncRequest, intr Intr) Error { 207 w.gotfsync = true 208 return nil 209 } 210 211 func (w *writeAll) WriteAll(data []byte, intr Intr) Error { 212 w.data = data 213 return nil 214 } 215 216 func (w *writeAll) test(path string, t *testing.T) { 217 err := ioutil.WriteFile(path, []byte(hi), 0666) 218 if err != nil { 219 t.Fatalf("WriteFile: %v", err) 220 return 221 } 222 if string(w.data) != hi { 223 t.Errorf("writeAll = %q, want %q", w.data, hi) 224 } 225 } 226 227 // Test Write calling Setattr+Write+Flush. 228 229 type writeAll2 struct { 230 file 231 data []byte 232 setattr bool 233 flush bool 234 } 235 236 func (w *writeAll2) Setattr(req *SetattrRequest, resp *SetattrResponse, intr Intr) Error { 237 w.setattr = true 238 return nil 239 } 240 241 func (w *writeAll2) Flush(req *FlushRequest, intr Intr) Error { 242 w.flush = true 243 return nil 244 } 245 246 func (w *writeAll2) Write(req *WriteRequest, resp *WriteResponse, intr Intr) Error { 247 w.data = append(w.data, req.Data...) 248 resp.Size = len(req.Data) 249 return nil 250 } 251 252 func (w *writeAll2) test(path string, t *testing.T) { 253 err := ioutil.WriteFile(path, []byte(hi), 0666) 254 if err != nil { 255 t.Errorf("WriteFile: %v", err) 256 return 257 } 258 if !w.setattr || string(w.data) != hi || !w.flush { 259 t.Errorf("writeAll = %v, %q, %v, want %v, %q, %v", w.setattr, string(w.data), w.flush, true, hi, true) 260 } 261 } 262 263 // Test Mkdir. 264 265 type mkdir1 struct { 266 dir 267 name string 268 } 269 270 func (f *mkdir1) Mkdir(req *MkdirRequest, intr Intr) (Node, Error) { 271 f.name = req.Name 272 return &mkdir1{}, nil 273 } 274 275 func (f *mkdir1) test(path string, t *testing.T) { 276 f.name = "" 277 err := os.Mkdir(path+"/foo", 0777) 278 if err != nil { 279 t.Error(err) 280 return 281 } 282 if f.name != "foo" { 283 t.Error(err) 284 return 285 } 286 } 287 288 // Test Create (and fsync) 289 290 type create1 struct { 291 dir 292 name string 293 f *writeAll 294 } 295 296 func (f *create1) Create(req *CreateRequest, resp *CreateResponse, intr Intr) (Node, Handle, Error) { 297 f.name = req.Name 298 f.f = &writeAll{} 299 return f.f, f.f, nil 300 } 301 302 func (f *create1) test(path string, t *testing.T) { 303 f.name = "" 304 ff, err := os.Create(path + "/foo") 305 if err != nil { 306 t.Errorf("create1 WriteFile: %v", err) 307 return 308 } 309 310 err = syscall.Fsync(int(ff.Fd())) 311 if err != nil { 312 t.Fatalf("Fsync = %v", err) 313 } 314 315 if !f.f.gotfsync { 316 t.Errorf("never received expected fsync call") 317 } 318 319 ff.Close() 320 if f.name != "foo" { 321 t.Errorf("create1 name=%q want foo", f.name) 322 } 323 } 324 325 // Test Create + WriteAll + Remove 326 327 type create2 struct { 328 dir 329 name string 330 f *writeAll 331 fooExists bool 332 } 333 334 func (f *create2) Create(req *CreateRequest, resp *CreateResponse, intr Intr) (Node, Handle, Error) { 335 f.name = req.Name 336 f.f = &writeAll{} 337 return f.f, f.f, nil 338 } 339 340 func (f *create2) Lookup(name string, intr Intr) (Node, Error) { 341 if f.fooExists && name == "foo" { 342 return file{}, nil 343 } 344 return nil, ENOENT 345 } 346 347 func (f *create2) Remove(r *RemoveRequest, intr Intr) Error { 348 if f.fooExists && r.Name == "foo" && !r.Dir { 349 f.fooExists = false 350 return nil 351 } 352 return ENOENT 353 } 354 355 func (f *create2) test(path string, t *testing.T) { 356 f.name = "" 357 err := ioutil.WriteFile(path+"/foo", []byte(hi), 0666) 358 if err != nil { 359 t.Fatalf("create2 WriteFile: %v", err) 360 } 361 if string(f.f.data) != hi { 362 t.Fatalf("create2 writeAll = %q, want %q", f.f.data, hi) 363 } 364 365 f.fooExists = true 366 log.Printf("pre-Remove") 367 err = os.Remove(path + "/foo") 368 if err != nil { 369 t.Fatalf("Remove: %v", err) 370 } 371 err = os.Remove(path + "/foo") 372 if err == nil { 373 t.Fatalf("second Remove = nil; want some error") 374 } 375 } 376 377 // Test symlink + readlink 378 379 type symlink1 struct { 380 dir 381 newName, target string 382 } 383 384 func (f *symlink1) Symlink(req *SymlinkRequest, intr Intr) (Node, Error) { 385 f.newName = req.NewName 386 f.target = req.Target 387 return symlink{target: req.Target}, nil 388 } 389 390 func (f *symlink1) test(path string, t *testing.T) { 391 const target = "/some-target" 392 393 err := os.Symlink(target, path+"/symlink.file") 394 if err != nil { 395 t.Errorf("os.Symlink: %v", err) 396 return 397 } 398 399 if f.newName != "symlink.file" { 400 t.Errorf("symlink newName = %q; want %q", f.newName, "symlink.file") 401 } 402 if f.target != target { 403 t.Errorf("symlink target = %q; want %q", f.target, target) 404 } 405 406 gotName, err := os.Readlink(path + "/symlink.file") 407 if err != nil { 408 t.Errorf("os.Readlink: %v", err) 409 return 410 } 411 if gotName != target { 412 t.Errorf("os.Readlink = %q; want %q", gotName, target) 413 } 414 } 415 416 // Test link 417 418 type link1 struct { 419 dir 420 newName string 421 } 422 423 func (f *link1) Lookup(name string, intr Intr) (Node, Error) { 424 if name == "old" { 425 return file{}, nil 426 } 427 return nil, ENOENT 428 } 429 430 func (f *link1) Link(r *LinkRequest, old Node, intr Intr) (Node, Error) { 431 f.newName = r.NewName 432 return file{}, nil 433 } 434 435 func (f *link1) test(path string, t *testing.T) { 436 err := os.Link(path+"/old", path+"/new") 437 if err != nil { 438 t.Fatalf("Link: %v", err) 439 } 440 if f.newName != "new" { 441 t.Fatalf("saw Link for newName %q; want %q", f.newName, "new") 442 } 443 } 444 445 // Test Rename 446 447 type rename1 struct { 448 dir 449 renames int 450 } 451 452 func (f *rename1) Lookup(name string, intr Intr) (Node, Error) { 453 if name == "old" { 454 return file{}, nil 455 } 456 return nil, ENOENT 457 } 458 459 func (f *rename1) Rename(r *RenameRequest, newDir Node, intr Intr) Error { 460 if r.OldName == "old" && r.NewName == "new" && newDir == f { 461 f.renames++ 462 return nil 463 } 464 return EIO 465 } 466 467 func (f *rename1) test(path string, t *testing.T) { 468 err := os.Rename(path+"/old", path+"/new") 469 if err != nil { 470 t.Fatalf("Rename: %v", err) 471 } 472 if f.renames != 1 { 473 t.Fatalf("expected rename didn't happen") 474 } 475 err = os.Rename(path+"/old2", path+"/new2") 476 if err == nil { 477 t.Fatal("expected error on second Rename; got nil") 478 } 479 } 480 481 // Test Release. 482 483 type release struct { 484 file 485 did bool 486 } 487 488 func (r *release) Release(*ReleaseRequest, Intr) Error { 489 r.did = true 490 return nil 491 } 492 493 func (r *release) test(path string, t *testing.T) { 494 r.did = false 495 f, err := os.Open(path) 496 if err != nil { 497 t.Error(err) 498 return 499 } 500 f.Close() 501 time.Sleep(1 * time.Second) 502 if !r.did { 503 t.Error("Close did not Release") 504 } 505 } 506 507 // Test mknod 508 509 type mknod1 struct { 510 dir 511 gotr *MknodRequest 512 } 513 514 func (f *mknod1) Mknod(r *MknodRequest, intr Intr) (Node, Error) { 515 f.gotr = r 516 return fifo{}, nil 517 } 518 519 func (f *mknod1) test(path string, t *testing.T) { 520 if os.Getuid() != 0 { 521 t.Logf("skipping unless root") 522 return 523 } 524 defer syscall.Umask(syscall.Umask(0)) 525 err := syscall.Mknod(path+"/node", syscall.S_IFIFO|0666, 123) 526 if err != nil { 527 t.Fatalf("Mknod: %v", err) 528 } 529 if f.gotr == nil { 530 t.Fatalf("no recorded MknodRequest") 531 } 532 if g, e := f.gotr.Name, "node"; g != e { 533 t.Errorf("got Name = %q; want %q", g, e) 534 } 535 if g, e := f.gotr.Rdev, uint32(123); g != e { 536 if runtime.GOOS == "linux" { 537 // Linux fuse doesn't echo back the rdev if the node 538 // isn't a device (we're using a FIFO here, as that 539 // bit is portable.) 540 } else { 541 t.Errorf("got Rdev = %v; want %v", g, e) 542 } 543 } 544 if g, e := f.gotr.Mode, os.FileMode(os.ModeNamedPipe|0666); g != e { 545 t.Errorf("got Mode = %v; want %v", g, e) 546 } 547 t.Logf("Got request: %#v", f.gotr) 548 } 549 550 type file struct{} 551 type dir struct{} 552 type fifo struct{} 553 type symlink struct { 554 target string 555 } 556 557 func (f file) Attr() Attr { return Attr{Mode: 0666} } 558 func (f dir) Attr() Attr { return Attr{Mode: os.ModeDir | 0777} } 559 func (f fifo) Attr() Attr { return Attr{Mode: os.ModeNamedPipe | 0666} } 560 func (f symlink) Attr() Attr { return Attr{Mode: os.ModeSymlink | 0666} } 561 562 func (f symlink) Readlink(*ReadlinkRequest, Intr) (string, Error) { 563 return f.target, nil 564 } 565 566 type testFS struct{} 567 568 func (testFS) Root() (Node, Error) { 569 return testFS{}, nil 570 } 571 572 func (testFS) Attr() Attr { 573 return Attr{Mode: os.ModeDir | 0555} 574 } 575 576 func (testFS) Lookup(name string, intr Intr) (Node, Error) { 577 for _, tt := range fuseTests { 578 if tt.name == name { 579 return tt.node, nil 580 } 581 } 582 return nil, ENOENT 583 } 584 585 func (testFS) ReadDir(intr Intr) ([]Dirent, Error) { 586 var dirs []Dirent 587 for _, tt := range fuseTests { 588 if *fuseRun == "" || *fuseRun == tt.name { 589 log.Printf("Readdir; adding %q", tt.name) 590 dirs = append(dirs, Dirent{Name: tt.name}) 591 } 592 } 593 return dirs, nil 594 }