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  }