github.com/IBM/fsgo@v0.0.0-20220920202152-e16fd2119d49/symlink_test.go (about)

     1  // Copyright 2022 IBM Inc. All rights reserved
     2  // Copyright © 2014 Steve Francia <spf@spf13.com>
     3  //
     4  // SPDX-License-Identifier: Apache2.0
     5  package fsgo
     6  
     7  import (
     8  	"os"
     9  	"path/filepath"
    10  	"strings"
    11  	"testing"
    12  )
    13  
    14  func TestSymlinkIfPossible(t *testing.T) {
    15  	wd, _ := os.Getwd()
    16  	defer func() {
    17  		os.Chdir(wd)
    18  	}()
    19  
    20  	osFs := &OsFs{}
    21  
    22  	workDir, err := TempDir(osFs, "", "fsgoo-symlink")
    23  	if err != nil {
    24  		t.Fatal(err)
    25  	}
    26  
    27  	defer func() {
    28  		osFs.RemoveAll(workDir)
    29  	}()
    30  
    31  	memWorkDir := "/sym"
    32  
    33  	memFs := NewMemMapFs()
    34  	overlayFs1 := &CopyOnWriteFs{base: osFs, layer: memFs}
    35  	overlayFs2 := &CopyOnWriteFs{base: memFs, layer: osFs}
    36  	overlayFsMemOnly := &CopyOnWriteFs{base: memFs, layer: NewMemMapFs()}
    37  	basePathFs := &BasePathFs{source: osFs, path: workDir}
    38  	basePathFsMem := &BasePathFs{source: memFs, path: memWorkDir}
    39  	roFs := &ReadOnlyFs{source: osFs}
    40  	roFsMem := &ReadOnlyFs{source: memFs}
    41  
    42  	pathFileMem := filepath.Join(memWorkDir, "fsgoom.txt")
    43  	osPath := filepath.Join(workDir, "fsgoo.txt")
    44  
    45  	WriteFile(osFs, osPath, []byte("Hi, Fsgo!"), 0777)
    46  	WriteFile(memFs, filepath.Join(pathFileMem), []byte("Hi, Fsgo!"), 0777)
    47  
    48  	testLink := func(l Linker, source, destination string, output *string) {
    49  		if fs, ok := l.(Fs); ok {
    50  			dir := filepath.Dir(destination)
    51  			if dir != "" {
    52  				fs.MkdirAll(dir, 0777)
    53  			}
    54  		}
    55  
    56  		err := l.SymlinkIfPossible(source, destination)
    57  		if (err == nil) && (output != nil) {
    58  			t.Fatalf("Error creating symlink, succeeded when expecting error %v", *output)
    59  		} else if (err != nil) && (output == nil) {
    60  			t.Fatalf("Error creating symlink, expected success, got %v", err)
    61  		} else if err != nil && err.Error() != *output && !strings.HasSuffix(err.Error(), *output) {
    62  			t.Fatalf("Error creating symlink, expected error '%v', instead got output '%v'", *output, err)
    63  		} else {
    64  			// test passed, if expecting a successful link, check the link with lstat if able
    65  			if output == nil {
    66  				if lst, ok := l.(Lstater); ok {
    67  					_, ok, err := lst.LstatIfPossible(destination)
    68  					if !ok {
    69  						if err != nil {
    70  							t.Fatalf("Error calling lstat on file after successful link, got: %v", err)
    71  						} else {
    72  							t.Fatalf("Error calling lstat on file after successful link, result didn't use lstat (not link)")
    73  						}
    74  						return
    75  					}
    76  				}
    77  			}
    78  		}
    79  	}
    80  
    81  	notSupported := ErrNoSymlink.Error()
    82  
    83  	testLink(osFs, osPath, filepath.Join(workDir, "os/link.txt"), nil)
    84  	testLink(overlayFs1, osPath, filepath.Join(workDir, "overlay/link1.txt"), &notSupported)
    85  	testLink(overlayFs2, pathFileMem, filepath.Join(workDir, "overlay2/link2.txt"), nil)
    86  	testLink(overlayFsMemOnly, pathFileMem, filepath.Join(memWorkDir, "overlay3/link.txt"), &notSupported)
    87  	testLink(basePathFs, "fsgoo.txt", "basepath/link.txt", nil)
    88  	testLink(basePathFsMem, pathFileMem, "link/file.txt", &notSupported)
    89  	testLink(roFs, osPath, filepath.Join(workDir, "ro/link.txt"), &notSupported)
    90  	testLink(roFsMem, pathFileMem, filepath.Join(memWorkDir, "ro/link.txt"), &notSupported)
    91  }
    92  
    93  func TestReadlinkIfPossible(t *testing.T) {
    94  	wd, _ := os.Getwd()
    95  	defer func() {
    96  		os.Chdir(wd)
    97  	}()
    98  
    99  	osFs := &OsFs{}
   100  
   101  	workDir, err := TempDir(osFs, "", "fsgoo-readlink")
   102  	if err != nil {
   103  		t.Fatal(err)
   104  	}
   105  
   106  	defer func() {
   107  		osFs.RemoveAll(workDir)
   108  	}()
   109  
   110  	memWorkDir := "/read"
   111  
   112  	memFs := NewMemMapFs()
   113  	overlayFs1 := &CopyOnWriteFs{base: osFs, layer: memFs}
   114  	overlayFs2 := &CopyOnWriteFs{base: memFs, layer: osFs}
   115  	overlayFsMemOnly := &CopyOnWriteFs{base: memFs, layer: NewMemMapFs()}
   116  	basePathFs := &BasePathFs{source: osFs, path: workDir}
   117  	basePathFsMem := &BasePathFs{source: memFs, path: memWorkDir}
   118  	roFs := &ReadOnlyFs{source: osFs}
   119  	roFsMem := &ReadOnlyFs{source: memFs}
   120  
   121  	pathFileMem := filepath.Join(memWorkDir, "fsgoom.txt")
   122  	osPath := filepath.Join(workDir, "fsgoo.txt")
   123  
   124  	WriteFile(osFs, osPath, []byte("Hi, Fsgo!"), 0777)
   125  	WriteFile(memFs, filepath.Join(pathFileMem), []byte("Hi, Fsgo!"), 0777)
   126  
   127  	createLink := func(l Linker, source, destination string) error {
   128  		if fs, ok := l.(Fs); ok {
   129  			dir := filepath.Dir(destination)
   130  			if dir != "" {
   131  				fs.MkdirAll(dir, 0777)
   132  			}
   133  		}
   134  
   135  		return l.SymlinkIfPossible(source, destination)
   136  	}
   137  
   138  	testRead := func(r LinkReader, name string, output *string) {
   139  		_, err := r.ReadlinkIfPossible(name)
   140  		if (err != nil) && (output == nil) {
   141  			t.Fatalf("Error reading link, expected success, got error: %v", err)
   142  		} else if (err == nil) && (output != nil) {
   143  			t.Fatalf("Error reading link, succeeded when expecting error: %v", *output)
   144  		} else if err != nil && err.Error() != *output && !strings.HasSuffix(err.Error(), *output) {
   145  			t.Fatalf("Error reading link, expected error '%v', instead received '%v'", *output, err)
   146  		}
   147  	}
   148  
   149  	notSupported := ErrNoReadlink.Error()
   150  
   151  	err = createLink(osFs, osPath, filepath.Join(workDir, "os/link.txt"))
   152  	if err != nil {
   153  		t.Fatal("Error creating test link: ", err)
   154  	}
   155  
   156  	testRead(osFs, filepath.Join(workDir, "os/link.txt"), nil)
   157  	testRead(overlayFs1, filepath.Join(workDir, "os/link.txt"), nil)
   158  	testRead(overlayFs2, filepath.Join(workDir, "os/link.txt"), nil)
   159  	testRead(overlayFsMemOnly, pathFileMem, &notSupported)
   160  	testRead(basePathFs, "os/link.txt", nil)
   161  	testRead(basePathFsMem, pathFileMem, &notSupported)
   162  	testRead(roFs, filepath.Join(workDir, "os/link.txt"), nil)
   163  	testRead(roFsMem, pathFileMem, &notSupported)
   164  }