github.com/gozelle/afero@v0.0.0-20230510083704-09e2ff18f19e/composite_test.go (about)

     1  package afero
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io"
     7  	"io/ioutil"
     8  	"os"
     9  	"testing"
    10  	"time"
    11  )
    12  
    13  var tempDirs []string
    14  
    15  func NewTempOsBaseFs(t *testing.T) Fs {
    16  	name, err := TempDir(NewOsFs(), "", "")
    17  	if err != nil {
    18  		t.Error("error creating tempDir", err)
    19  	}
    20  
    21  	tempDirs = append(tempDirs, name)
    22  
    23  	return NewBasePathFs(NewOsFs(), name)
    24  }
    25  
    26  func CleanupTempDirs(t *testing.T) {
    27  	osfs := NewOsFs()
    28  	type ev struct {
    29  		path string
    30  		e    error
    31  	}
    32  
    33  	errs := []ev{}
    34  
    35  	for _, x := range tempDirs {
    36  		err := osfs.RemoveAll(x)
    37  		if err != nil {
    38  			errs = append(errs, ev{path: x, e: err})
    39  		}
    40  	}
    41  
    42  	for _, e := range errs {
    43  		fmt.Println("error removing tempDir", e.path, e.e)
    44  	}
    45  
    46  	if len(errs) > 0 {
    47  		t.Error("error cleaning up tempDirs")
    48  	}
    49  	tempDirs = []string{}
    50  }
    51  
    52  func TestUnionCreateExisting(t *testing.T) {
    53  	base := &MemMapFs{}
    54  	roBase := &ReadOnlyFs{source: base}
    55  	ufs := NewCopyOnWriteFs(roBase, &MemMapFs{})
    56  
    57  	base.MkdirAll("/home/test", 0o777)
    58  	fh, _ := base.Create("/home/test/file.txt")
    59  	fh.WriteString("This is a test")
    60  	fh.Close()
    61  
    62  	fh, err := ufs.OpenFile("/home/test/file.txt", os.O_RDWR, 0o666)
    63  	if err != nil {
    64  		t.Errorf("Failed to open file r/w: %s", err)
    65  	}
    66  
    67  	_, err = fh.Write([]byte("####"))
    68  	if err != nil {
    69  		t.Errorf("Failed to write file: %s", err)
    70  	}
    71  	fh.Seek(0, 0)
    72  	data, err := ioutil.ReadAll(fh)
    73  	if err != nil {
    74  		t.Errorf("Failed to read file: %s", err)
    75  	}
    76  	if string(data) != "#### is a test" {
    77  		t.Errorf("Got wrong data")
    78  	}
    79  	fh.Close()
    80  
    81  	fh, _ = base.Open("/home/test/file.txt")
    82  	data, _ = ioutil.ReadAll(fh)
    83  	if string(data) != "This is a test" {
    84  		t.Errorf("Got wrong data in base file")
    85  	}
    86  	fh.Close()
    87  
    88  	fh, err = ufs.Create("/home/test/file.txt")
    89  	switch err {
    90  	case nil:
    91  		if fi, _ := fh.Stat(); fi.Size() != 0 {
    92  			t.Errorf("Create did not truncate file")
    93  		}
    94  		fh.Close()
    95  	default:
    96  		t.Errorf("Create failed on existing file")
    97  	}
    98  }
    99  
   100  func TestUnionMergeReaddir(t *testing.T) {
   101  	base := &MemMapFs{}
   102  	roBase := &ReadOnlyFs{source: base}
   103  
   104  	ufs := &CopyOnWriteFs{base: roBase, layer: &MemMapFs{}}
   105  
   106  	base.MkdirAll("/home/test", 0o777)
   107  	fh, _ := base.Create("/home/test/file.txt")
   108  	fh.WriteString("This is a test")
   109  	fh.Close()
   110  
   111  	fh, _ = ufs.Create("/home/test/file2.txt")
   112  	fh.WriteString("This is a test")
   113  	fh.Close()
   114  
   115  	fh, _ = ufs.Open("/home/test")
   116  	files, err := fh.Readdirnames(-1)
   117  	if err != nil {
   118  		t.Errorf("Readdirnames failed")
   119  	}
   120  	if len(files) != 2 {
   121  		t.Errorf("Got wrong number of files: %v", files)
   122  	}
   123  }
   124  
   125  func TestExistingDirectoryCollisionReaddir(t *testing.T) {
   126  	base := &MemMapFs{}
   127  	roBase := &ReadOnlyFs{source: base}
   128  	overlay := &MemMapFs{}
   129  
   130  	ufs := &CopyOnWriteFs{base: roBase, layer: overlay}
   131  
   132  	base.MkdirAll("/home/test", 0o777)
   133  	fh, _ := base.Create("/home/test/file.txt")
   134  	fh.WriteString("This is a test")
   135  	fh.Close()
   136  
   137  	overlay.MkdirAll("home/test", 0o777)
   138  	fh, _ = overlay.Create("/home/test/file2.txt")
   139  	fh.WriteString("This is a test")
   140  	fh.Close()
   141  
   142  	fh, _ = ufs.Create("/home/test/file3.txt")
   143  	fh.WriteString("This is a test")
   144  	fh.Close()
   145  
   146  	fh, _ = ufs.Open("/home/test")
   147  	files, err := fh.Readdirnames(-1)
   148  	if err != nil {
   149  		t.Errorf("Readdirnames failed")
   150  	}
   151  	if len(files) != 3 {
   152  		t.Errorf("Got wrong number of files in union: %v", files)
   153  	}
   154  
   155  	fh, _ = overlay.Open("/home/test")
   156  	files, err = fh.Readdirnames(-1)
   157  	if err != nil {
   158  		t.Errorf("Readdirnames failed")
   159  	}
   160  	if len(files) != 2 {
   161  		t.Errorf("Got wrong number of files in overlay: %v", files)
   162  	}
   163  }
   164  
   165  func TestNestedDirBaseReaddir(t *testing.T) {
   166  	base := &MemMapFs{}
   167  	roBase := &ReadOnlyFs{source: base}
   168  	overlay := &MemMapFs{}
   169  
   170  	ufs := &CopyOnWriteFs{base: roBase, layer: overlay}
   171  
   172  	base.MkdirAll("/home/test/foo/bar", 0o777)
   173  	fh, _ := base.Create("/home/test/file.txt")
   174  	fh.WriteString("This is a test")
   175  	fh.Close()
   176  
   177  	fh, _ = base.Create("/home/test/foo/file2.txt")
   178  	fh.WriteString("This is a test")
   179  	fh.Close()
   180  	fh, _ = base.Create("/home/test/foo/bar/file3.txt")
   181  	fh.WriteString("This is a test")
   182  	fh.Close()
   183  
   184  	overlay.MkdirAll("/", 0o777)
   185  
   186  	// Opening something only in the base
   187  	fh, _ = ufs.Open("/home/test/foo")
   188  	list, err := fh.Readdir(-1)
   189  	if err != nil {
   190  		t.Errorf("Readdir failed %s", err)
   191  	}
   192  	if len(list) != 2 {
   193  		for _, x := range list {
   194  			fmt.Println(x.Name())
   195  		}
   196  		t.Errorf("Got wrong number of files in union: %v", len(list))
   197  	}
   198  }
   199  
   200  func TestNestedDirOverlayReaddir(t *testing.T) {
   201  	base := &MemMapFs{}
   202  	roBase := &ReadOnlyFs{source: base}
   203  	overlay := &MemMapFs{}
   204  
   205  	ufs := &CopyOnWriteFs{base: roBase, layer: overlay}
   206  
   207  	base.MkdirAll("/", 0o777)
   208  	overlay.MkdirAll("/home/test/foo/bar", 0o777)
   209  	fh, _ := overlay.Create("/home/test/file.txt")
   210  	fh.WriteString("This is a test")
   211  	fh.Close()
   212  	fh, _ = overlay.Create("/home/test/foo/file2.txt")
   213  	fh.WriteString("This is a test")
   214  	fh.Close()
   215  	fh, _ = overlay.Create("/home/test/foo/bar/file3.txt")
   216  	fh.WriteString("This is a test")
   217  	fh.Close()
   218  
   219  	// Opening nested dir only in the overlay
   220  	fh, _ = ufs.Open("/home/test/foo")
   221  	list, err := fh.Readdir(-1)
   222  	if err != nil {
   223  		t.Errorf("Readdir failed %s", err)
   224  	}
   225  	if len(list) != 2 {
   226  		for _, x := range list {
   227  			fmt.Println(x.Name())
   228  		}
   229  		t.Errorf("Got wrong number of files in union: %v", len(list))
   230  	}
   231  }
   232  
   233  func TestNestedDirOverlayOsFsReaddir(t *testing.T) {
   234  	defer CleanupTempDirs(t)
   235  	base := NewTempOsBaseFs(t)
   236  	roBase := &ReadOnlyFs{source: base}
   237  	overlay := NewTempOsBaseFs(t)
   238  
   239  	ufs := &CopyOnWriteFs{base: roBase, layer: overlay}
   240  
   241  	base.MkdirAll("/", 0o777)
   242  	overlay.MkdirAll("/home/test/foo/bar", 0o777)
   243  	fh, _ := overlay.Create("/home/test/file.txt")
   244  	fh.WriteString("This is a test")
   245  	fh.Close()
   246  	fh, _ = overlay.Create("/home/test/foo/file2.txt")
   247  	fh.WriteString("This is a test")
   248  	fh.Close()
   249  	fh, _ = overlay.Create("/home/test/foo/bar/file3.txt")
   250  	fh.WriteString("This is a test")
   251  	fh.Close()
   252  
   253  	// Opening nested dir only in the overlay
   254  	fh, _ = ufs.Open("/home/test/foo")
   255  	list, err := fh.Readdir(-1)
   256  	fh.Close()
   257  	if err != nil {
   258  		t.Errorf("Readdir failed %s", err)
   259  	}
   260  	if len(list) != 2 {
   261  		for _, x := range list {
   262  			fmt.Println(x.Name())
   263  		}
   264  		t.Errorf("Got wrong number of files in union: %v", len(list))
   265  	}
   266  }
   267  
   268  func TestCopyOnWriteFsWithOsFs(t *testing.T) {
   269  	defer CleanupTempDirs(t)
   270  	base := NewTempOsBaseFs(t)
   271  	roBase := &ReadOnlyFs{source: base}
   272  	overlay := NewTempOsBaseFs(t)
   273  
   274  	ufs := &CopyOnWriteFs{base: roBase, layer: overlay}
   275  
   276  	base.MkdirAll("/home/test", 0o777)
   277  	fh, _ := base.Create("/home/test/file.txt")
   278  	fh.WriteString("This is a test")
   279  	fh.Close()
   280  
   281  	overlay.MkdirAll("home/test", 0o777)
   282  	fh, _ = overlay.Create("/home/test/file2.txt")
   283  	fh.WriteString("This is a test")
   284  	fh.Close()
   285  
   286  	fh, _ = ufs.Create("/home/test/file3.txt")
   287  	fh.WriteString("This is a test")
   288  	fh.Close()
   289  
   290  	fh, _ = ufs.Open("/home/test")
   291  	files, err := fh.Readdirnames(-1)
   292  	fh.Close()
   293  	if err != nil {
   294  		t.Errorf("Readdirnames failed")
   295  	}
   296  	if len(files) != 3 {
   297  		t.Errorf("Got wrong number of files in union: %v", files)
   298  	}
   299  
   300  	fh, _ = overlay.Open("/home/test")
   301  	files, err = fh.Readdirnames(-1)
   302  	fh.Close()
   303  	if err != nil {
   304  		t.Errorf("Readdirnames failed")
   305  	}
   306  	if len(files) != 2 {
   307  		t.Errorf("Got wrong number of files in overlay: %v", files)
   308  	}
   309  }
   310  
   311  func TestUnionCacheWrite(t *testing.T) {
   312  	base := &MemMapFs{}
   313  	layer := &MemMapFs{}
   314  
   315  	ufs := NewCacheOnReadFs(base, layer, 0)
   316  
   317  	base.Mkdir("/data", 0o777)
   318  
   319  	fh, err := ufs.Create("/data/file.txt")
   320  	if err != nil {
   321  		t.Errorf("Failed to create file")
   322  	}
   323  	_, err = fh.Write([]byte("This is a test"))
   324  	if err != nil {
   325  		t.Errorf("Failed to write file")
   326  	}
   327  
   328  	fh.Seek(0, io.SeekStart)
   329  	buf := make([]byte, 4)
   330  	_, _ = fh.Read(buf)
   331  	fh.Write([]byte(" IS A"))
   332  	fh.Close()
   333  
   334  	baseData, _ := ReadFile(base, "/data/file.txt")
   335  	layerData, _ := ReadFile(layer, "/data/file.txt")
   336  	if string(baseData) != string(layerData) {
   337  		t.Errorf("Different data: %s <=> %s", baseData, layerData)
   338  	}
   339  }
   340  
   341  func TestUnionCacheExpire(t *testing.T) {
   342  	base := &MemMapFs{}
   343  	layer := &MemMapFs{}
   344  	ufs := &CacheOnReadFs{base: base, layer: layer, cacheTime: 1 * time.Second}
   345  
   346  	base.Mkdir("/data", 0o777)
   347  
   348  	fh, err := ufs.Create("/data/file.txt")
   349  	if err != nil {
   350  		t.Errorf("Failed to create file")
   351  	}
   352  	_, err = fh.Write([]byte("This is a test"))
   353  	if err != nil {
   354  		t.Errorf("Failed to write file")
   355  	}
   356  	fh.Close()
   357  
   358  	fh, _ = base.Create("/data/file.txt")
   359  	// sleep some time, so we really get a different time.Now() on write...
   360  	time.Sleep(2 * time.Second)
   361  	fh.WriteString("Another test")
   362  	fh.Close()
   363  
   364  	data, _ := ReadFile(ufs, "/data/file.txt")
   365  	if string(data) != "Another test" {
   366  		t.Errorf("cache time failed: <%s>", data)
   367  	}
   368  }
   369  
   370  func TestCacheOnReadFsNotInLayer(t *testing.T) {
   371  	base := NewMemMapFs()
   372  	layer := NewMemMapFs()
   373  	fs := NewCacheOnReadFs(base, layer, 0)
   374  
   375  	fh, err := base.Create("/file.txt")
   376  	if err != nil {
   377  		t.Fatal("unable to create file: ", err)
   378  	}
   379  
   380  	txt := []byte("This is a test")
   381  	fh.Write(txt)
   382  	fh.Close()
   383  
   384  	fh, err = fs.Open("/file.txt")
   385  	if err != nil {
   386  		t.Fatal("could not open file: ", err)
   387  	}
   388  
   389  	b, err := ReadAll(fh)
   390  	fh.Close()
   391  
   392  	if err != nil {
   393  		t.Fatal("could not read file: ", err)
   394  	} else if !bytes.Equal(txt, b) {
   395  		t.Fatalf("wanted file text %q, got %q", txt, b)
   396  	}
   397  
   398  	fh, err = layer.Open("/file.txt")
   399  	if err != nil {
   400  		t.Fatal("could not open file from layer: ", err)
   401  	}
   402  	fh.Close()
   403  }
   404  
   405  // #194
   406  func TestUnionFileReaddirEmpty(t *testing.T) {
   407  	osFs := NewOsFs()
   408  
   409  	base := NewMemMapFs()
   410  	overlay := NewMemMapFs()
   411  	ufs := &CopyOnWriteFs{base: base, layer: overlay}
   412  	mem := NewMemMapFs()
   413  
   414  	// The OS file will return io.EOF on end of directory.
   415  	for _, fs := range []Fs{osFs, ufs, mem} {
   416  		baseDir, err := TempDir(fs, "", "empty-dir")
   417  		if err != nil {
   418  			t.Fatal(err)
   419  		}
   420  
   421  		f, err := fs.Open(baseDir)
   422  		if err != nil {
   423  			t.Fatal(err)
   424  		}
   425  
   426  		names, err := f.Readdirnames(1)
   427  		if err != io.EOF {
   428  			t.Fatal(err)
   429  		}
   430  
   431  		if len(names) != 0 {
   432  			t.Fatal("should be empty")
   433  		}
   434  
   435  		f.Close()
   436  
   437  		fs.RemoveAll(baseDir)
   438  	}
   439  }
   440  
   441  // #197
   442  func TestUnionFileReaddirDuplicateEmpty(t *testing.T) {
   443  	base := NewMemMapFs()
   444  	dir, err := TempDir(base, "", "empty-dir")
   445  	if err != nil {
   446  		t.Fatal(err)
   447  	}
   448  
   449  	// Overlay shares same empty directory as base
   450  	overlay := NewMemMapFs()
   451  	err = overlay.Mkdir(dir, 0o700)
   452  	if err != nil {
   453  		t.Fatal(err)
   454  	}
   455  
   456  	ufs := &CopyOnWriteFs{base: base, layer: overlay}
   457  
   458  	f, err := ufs.Open(dir)
   459  	if err != nil {
   460  		t.Fatal(err)
   461  	}
   462  	defer f.Close()
   463  
   464  	names, err := f.Readdirnames(0)
   465  
   466  	if err == io.EOF {
   467  		t.Errorf("unexpected io.EOF error")
   468  	}
   469  
   470  	if len(names) != 0 {
   471  		t.Fatal("should be empty")
   472  	}
   473  }
   474  
   475  func TestUnionFileReaddirAskForTooMany(t *testing.T) {
   476  	base := &MemMapFs{}
   477  	overlay := &MemMapFs{}
   478  
   479  	const testFiles = 5
   480  	for i := 0; i < testFiles; i++ {
   481  		WriteFile(base, fmt.Sprintf("file%d.txt", i), []byte("afero"), 0o777)
   482  	}
   483  
   484  	ufs := &CopyOnWriteFs{base: base, layer: overlay}
   485  
   486  	f, err := ufs.Open("")
   487  	if err != nil {
   488  		t.Fatal(err)
   489  	}
   490  
   491  	defer f.Close()
   492  
   493  	// Read part of all files
   494  	wantNames := 3
   495  	names, err := f.Readdirnames(wantNames)
   496  	if err != nil {
   497  		t.Fatal(err)
   498  	}
   499  	if len(names) != wantNames {
   500  		t.Fatalf("got %d names %v, want %d", len(names), names, wantNames)
   501  	}
   502  
   503  	// Try to read more files than remaining
   504  	wantNames = testFiles - len(names)
   505  	names, err = f.Readdirnames(wantNames + 1)
   506  	if err != nil {
   507  		t.Fatal(err)
   508  	}
   509  	if len(names) != wantNames {
   510  		t.Fatalf("got %d names %v, want %d", len(names), names, wantNames)
   511  	}
   512  
   513  	// End of directory
   514  	_, err = f.Readdirnames(3)
   515  	if err != io.EOF {
   516  		t.Fatal(err)
   517  	}
   518  }