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"), ¬Supported) 85 testLink(overlayFs2, pathFileMem, filepath.Join(workDir, "overlay2/link2.txt"), nil) 86 testLink(overlayFsMemOnly, pathFileMem, filepath.Join(memWorkDir, "overlay3/link.txt"), ¬Supported) 87 testLink(basePathFs, "fsgoo.txt", "basepath/link.txt", nil) 88 testLink(basePathFsMem, pathFileMem, "link/file.txt", ¬Supported) 89 testLink(roFs, osPath, filepath.Join(workDir, "ro/link.txt"), ¬Supported) 90 testLink(roFsMem, pathFileMem, filepath.Join(memWorkDir, "ro/link.txt"), ¬Supported) 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, ¬Supported) 160 testRead(basePathFs, "os/link.txt", nil) 161 testRead(basePathFsMem, pathFileMem, ¬Supported) 162 testRead(roFs, filepath.Join(workDir, "os/link.txt"), nil) 163 testRead(roFsMem, pathFileMem, ¬Supported) 164 }