github.com/hanwen/go-fuse@v1.0.0/unionfs/autounion_test.go (about)

     1  // Copyright 2016 the Go-FUSE 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 unionfs
     6  
     7  import (
     8  	"io/ioutil"
     9  	"os"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/hanwen/go-fuse/fuse"
    14  	"github.com/hanwen/go-fuse/fuse/nodefs"
    15  	"github.com/hanwen/go-fuse/fuse/pathfs"
    16  	"github.com/hanwen/go-fuse/internal/testutil"
    17  )
    18  
    19  const entryTTL = 100 * time.Millisecond
    20  
    21  var testAOpts = AutoUnionFsOptions{
    22  	UnionFsOptions: testOpts,
    23  	Options: nodefs.Options{
    24  		EntryTimeout:        entryTTL,
    25  		AttrTimeout:         entryTTL,
    26  		NegativeTimeout:     0,
    27  		Debug:               testutil.VerboseTest(),
    28  		LookupKnownChildren: true,
    29  	},
    30  	HideReadonly: true,
    31  	Version:      "version",
    32  }
    33  
    34  func init() {
    35  	testAOpts.Options.Debug = testutil.VerboseTest()
    36  }
    37  
    38  func WriteFile(t *testing.T, name string, contents string) {
    39  	err := ioutil.WriteFile(name, []byte(contents), 0644)
    40  	if err != nil {
    41  		t.Fatalf("WriteFile failed: %v", err)
    42  	}
    43  }
    44  
    45  func setup(t *testing.T) (workdir string, server *fuse.Server, cleanup func()) {
    46  	wd := testutil.TempDir()
    47  	err := os.Mkdir(wd+"/mnt", 0700)
    48  	if err != nil {
    49  		t.Fatalf("Mkdir failed: %v", err)
    50  	}
    51  
    52  	err = os.Mkdir(wd+"/store", 0700)
    53  	if err != nil {
    54  		t.Fatalf("Mkdir failed: %v", err)
    55  	}
    56  
    57  	os.Mkdir(wd+"/ro", 0700)
    58  	if err != nil {
    59  		t.Fatalf("Mkdir failed: %v", err)
    60  	}
    61  	WriteFile(t, wd+"/ro/file1", "file1")
    62  	WriteFile(t, wd+"/ro/file2", "file2")
    63  
    64  	fs := NewAutoUnionFs(wd+"/store", testAOpts)
    65  
    66  	nfs := pathfs.NewPathNodeFs(fs, nil)
    67  	state, _, err := nodefs.MountRoot(wd+"/mnt", nfs.Root(), &testAOpts.Options)
    68  	if err != nil {
    69  		t.Fatalf("MountNodeFileSystem failed: %v", err)
    70  	}
    71  	go state.Serve()
    72  	state.WaitMount()
    73  
    74  	return wd, state, func() {
    75  		state.Unmount()
    76  		os.RemoveAll(wd)
    77  	}
    78  }
    79  
    80  func TestDebug(t *testing.T) {
    81  	wd, _, clean := setup(t)
    82  	defer clean()
    83  
    84  	c, err := ioutil.ReadFile(wd + "/mnt/status/debug")
    85  	if err != nil {
    86  		t.Fatalf("ReadFile failed: %v", err)
    87  	}
    88  	if len(c) == 0 {
    89  		t.Fatal("No debug found.")
    90  	}
    91  }
    92  
    93  func TestVersion(t *testing.T) {
    94  	wd, _, clean := setup(t)
    95  	defer clean()
    96  
    97  	c, err := ioutil.ReadFile(wd + "/mnt/status/gounionfs_version")
    98  	if err != nil {
    99  		t.Fatalf("ReadFile failed: %v", err)
   100  	}
   101  	if len(c) == 0 {
   102  		t.Fatal("No version found.")
   103  	}
   104  }
   105  
   106  func TestAutoFsSymlink(t *testing.T) {
   107  	wd, server, clean := setup(t)
   108  	defer clean()
   109  
   110  	err := os.Mkdir(wd+"/store/backing1", 0755)
   111  	if err != nil {
   112  		t.Fatalf("Mkdir failed: %v", err)
   113  	}
   114  
   115  	err = os.Symlink(wd+"/ro", wd+"/store/backing1/READONLY")
   116  	if err != nil {
   117  		t.Fatalf("Symlink failed: %v", err)
   118  	}
   119  
   120  	err = os.Symlink(wd+"/store/backing1", wd+"/mnt/config/manual1")
   121  	if err != nil {
   122  		t.Fatalf("Symlink failed: %v", err)
   123  	}
   124  
   125  	fi, err := os.Lstat(wd + "/mnt/manual1/file1")
   126  	if err != nil {
   127  		t.Fatalf("Lstat failed: %v", err)
   128  	}
   129  
   130  	entries, err := ioutil.ReadDir(wd + "/mnt")
   131  	if err != nil {
   132  		t.Fatalf("ReadDir failed: %v", err)
   133  	}
   134  	if len(entries) != 3 {
   135  		t.Error("readdir mismatch", entries)
   136  	}
   137  
   138  	err = os.Remove(wd + "/mnt/config/manual1")
   139  	if err != nil {
   140  		t.Fatalf("Remove failed: %v", err)
   141  	}
   142  
   143  	scan := wd + "/mnt/config/" + _SCAN_CONFIG
   144  	err = ioutil.WriteFile(scan, []byte("something"), 0644)
   145  	if err != nil {
   146  		t.Error("error writing:", err)
   147  	}
   148  
   149  	// If FUSE supports invalid inode notifications we expect this node to be gone. Otherwise we'll just make sure that it's not reachable.
   150  	if server.KernelSettings().SupportsNotify(fuse.NOTIFY_INVAL_INODE) {
   151  		fi, _ = os.Lstat(wd + "/mnt/manual1")
   152  		if fi != nil {
   153  			t.Error("Should not have file:", fi)
   154  		}
   155  	} else {
   156  		entries, err = ioutil.ReadDir(wd + "/mnt")
   157  		if err != nil {
   158  			t.Fatalf("ReadDir failed: %v", err)
   159  		}
   160  		for _, e := range entries {
   161  			if e.Name() == "manual1" {
   162  				t.Error("Should not have entry: ", e)
   163  			}
   164  		}
   165  	}
   166  
   167  	_, err = os.Lstat(wd + "/mnt/backing1/file1")
   168  	if err != nil {
   169  		t.Fatalf("Lstat failed: %v", err)
   170  	}
   171  }
   172  
   173  func TestDetectSymlinkedDirectories(t *testing.T) {
   174  	wd, _, clean := setup(t)
   175  	defer clean()
   176  
   177  	err := os.Mkdir(wd+"/backing1", 0755)
   178  	if err != nil {
   179  		t.Fatalf("Mkdir failed: %v", err)
   180  	}
   181  
   182  	err = os.Symlink(wd+"/ro", wd+"/backing1/READONLY")
   183  	if err != nil {
   184  		t.Fatalf("Symlink failed: %v", err)
   185  	}
   186  
   187  	err = os.Symlink(wd+"/backing1", wd+"/store/backing1")
   188  	if err != nil {
   189  		t.Fatalf("Symlink failed: %v", err)
   190  	}
   191  
   192  	scan := wd + "/mnt/config/" + _SCAN_CONFIG
   193  	err = ioutil.WriteFile(scan, []byte("something"), 0644)
   194  	if err != nil {
   195  		t.Error("error writing:", err)
   196  	}
   197  
   198  	_, err = os.Lstat(wd + "/mnt/backing1")
   199  	if err != nil {
   200  		t.Fatalf("Lstat failed: %v", err)
   201  	}
   202  }
   203  
   204  func TestExplicitScan(t *testing.T) {
   205  	wd, _, clean := setup(t)
   206  	defer clean()
   207  
   208  	err := os.Mkdir(wd+"/store/backing1", 0755)
   209  	if err != nil {
   210  		t.Fatalf("Mkdir failed: %v", err)
   211  	}
   212  	os.Symlink(wd+"/ro", wd+"/store/backing1/READONLY")
   213  	if err != nil {
   214  		t.Fatalf("Symlink failed: %v", err)
   215  	}
   216  
   217  	fi, _ := os.Lstat(wd + "/mnt/backing1")
   218  	if fi != nil {
   219  		t.Error("Should not have file:", fi)
   220  	}
   221  
   222  	scan := wd + "/mnt/config/" + _SCAN_CONFIG
   223  	_, err = os.Lstat(scan)
   224  	if err != nil {
   225  		t.Error(".scan_config missing:", err)
   226  	}
   227  
   228  	err = ioutil.WriteFile(scan, []byte("something"), 0644)
   229  	if err != nil {
   230  		t.Error("error writing:", err)
   231  	}
   232  
   233  	_, err = os.Lstat(wd + "/mnt/backing1")
   234  	if err != nil {
   235  		t.Error("Should have workspace backing1:", err)
   236  	}
   237  }
   238  
   239  func TestCreationChecks(t *testing.T) {
   240  	wd, _, clean := setup(t)
   241  	defer clean()
   242  
   243  	err := os.Mkdir(wd+"/store/foo", 0755)
   244  	if err != nil {
   245  		t.Fatalf("Mkdir failed: %v", err)
   246  	}
   247  	os.Symlink(wd+"/ro", wd+"/store/foo/READONLY")
   248  	if err != nil {
   249  		t.Fatalf("Symlink failed: %v", err)
   250  	}
   251  
   252  	err = os.Mkdir(wd+"/store/ws2", 0755)
   253  	if err != nil {
   254  		t.Fatalf("Mkdir failed: %v", err)
   255  	}
   256  	os.Symlink(wd+"/ro", wd+"/store/ws2/READONLY")
   257  	if err != nil {
   258  		t.Fatalf("Symlink failed: %v", err)
   259  	}
   260  
   261  	err = os.Symlink(wd+"/store/foo", wd+"/mnt/config/bar")
   262  	if err != nil {
   263  		t.Fatalf("Symlink failed: %v", err)
   264  	}
   265  
   266  	err = os.Symlink(wd+"/store/foo", wd+"/mnt/config/foo")
   267  	code := fuse.ToStatus(err)
   268  	if code != fuse.EBUSY {
   269  		t.Error("Should return EBUSY", err)
   270  	}
   271  
   272  	err = os.Symlink(wd+"/store/ws2", wd+"/mnt/config/config")
   273  	code = fuse.ToStatus(err)
   274  	if code != fuse.EINVAL {
   275  		t.Error("Should return EINVAL", err)
   276  	}
   277  }