github.com/tetratelabs/wazero@v1.2.1/internal/sysfs/adapter_test.go (about) 1 package sysfs 2 3 import ( 4 "errors" 5 "io/fs" 6 "os" 7 "path/filepath" 8 "runtime" 9 "syscall" 10 "testing" 11 12 "github.com/tetratelabs/wazero/internal/fsapi" 13 "github.com/tetratelabs/wazero/internal/fstest" 14 "github.com/tetratelabs/wazero/internal/testing/require" 15 ) 16 17 func TestAdapt_nil(t *testing.T) { 18 testFS := Adapt(nil) 19 _, ok := testFS.(fsapi.UnimplementedFS) 20 require.True(t, ok) 21 } 22 23 func TestAdapt_String(t *testing.T) { 24 testFS := Adapt(os.DirFS(".")) 25 require.Equal(t, ".", testFS.String()) 26 } 27 28 func TestAdapt_MkDir(t *testing.T) { 29 testFS := Adapt(os.DirFS(t.TempDir())) 30 31 err := testFS.Mkdir("mkdir", fs.ModeDir) 32 require.EqualErrno(t, syscall.ENOSYS, err) 33 } 34 35 func TestAdapt_Chmod(t *testing.T) { 36 testFS := Adapt(os.DirFS(t.TempDir())) 37 38 err := testFS.Chmod("chmod", fs.ModeDir) 39 require.EqualErrno(t, syscall.ENOSYS, err) 40 } 41 42 func TestAdapt_Rename(t *testing.T) { 43 tmpDir := t.TempDir() 44 testFS := Adapt(os.DirFS(tmpDir)) 45 46 file1 := "file1" 47 file1Path := joinPath(tmpDir, file1) 48 file1Contents := []byte{1} 49 err := os.WriteFile(file1Path, file1Contents, 0o600) 50 require.NoError(t, err) 51 52 file2 := "file2" 53 file2Path := joinPath(tmpDir, file2) 54 file2Contents := []byte{2} 55 err = os.WriteFile(file2Path, file2Contents, 0o600) 56 require.NoError(t, err) 57 58 err = testFS.Rename(file1, file2) 59 require.EqualErrno(t, syscall.ENOSYS, err) 60 } 61 62 func TestAdapt_Rmdir(t *testing.T) { 63 tmpDir := t.TempDir() 64 testFS := Adapt(os.DirFS(tmpDir)) 65 66 path := "rmdir" 67 realPath := joinPath(tmpDir, path) 68 require.NoError(t, os.Mkdir(realPath, 0o700)) 69 70 err := testFS.Rmdir(path) 71 require.EqualErrno(t, syscall.ENOSYS, err) 72 } 73 74 func TestAdapt_Unlink(t *testing.T) { 75 tmpDir := t.TempDir() 76 testFS := Adapt(os.DirFS(tmpDir)) 77 78 path := "unlink" 79 realPath := joinPath(tmpDir, path) 80 require.NoError(t, os.WriteFile(realPath, []byte{}, 0o600)) 81 82 err := testFS.Unlink(path) 83 require.EqualErrno(t, syscall.ENOSYS, err) 84 } 85 86 func TestAdapt_UtimesNano(t *testing.T) { 87 tmpDir := t.TempDir() 88 testFS := Adapt(os.DirFS(tmpDir)) 89 90 path := "utimes" 91 realPath := joinPath(tmpDir, path) 92 require.NoError(t, os.WriteFile(realPath, []byte{}, 0o600)) 93 94 err := testFS.Utimens(path, nil, true) 95 require.EqualErrno(t, syscall.ENOSYS, err) 96 } 97 98 func TestAdapt_Open_Read(t *testing.T) { 99 // Create a subdirectory, so we can test reads outside the fsapi.FS root. 100 tmpDir := t.TempDir() 101 tmpDir = joinPath(tmpDir, t.Name()) 102 require.NoError(t, os.Mkdir(tmpDir, 0o700)) 103 require.NoError(t, fstest.WriteTestFiles(tmpDir)) 104 testFS := Adapt(os.DirFS(tmpDir)) 105 106 // We can't correct operating system portability issues with os.DirFS on 107 // windows. Use syscall.DirFS instead! 108 if runtime.GOOS != "windows" { 109 testOpen_Read(t, testFS, true) 110 } 111 112 t.Run("path outside root invalid", func(t *testing.T) { 113 _, err := testFS.OpenFile("../foo", os.O_RDONLY, 0) 114 115 // fsapi.FS doesn't allow relative path lookups 116 require.EqualErrno(t, syscall.EINVAL, err) 117 }) 118 } 119 120 func TestAdapt_Lstat(t *testing.T) { 121 tmpDir := t.TempDir() 122 require.NoError(t, fstest.WriteTestFiles(tmpDir)) 123 testFS := Adapt(os.DirFS(tmpDir)) 124 125 for _, path := range []string{"animals.txt", "sub", "sub-link"} { 126 fullPath := joinPath(tmpDir, path) 127 linkPath := joinPath(tmpDir, path+"-link") 128 require.NoError(t, os.Symlink(fullPath, linkPath)) 129 130 _, errno := testFS.Lstat(filepath.Base(linkPath)) 131 require.EqualErrno(t, 0, errno) 132 } 133 } 134 135 func TestAdapt_Stat(t *testing.T) { 136 tmpDir := t.TempDir() 137 require.NoError(t, fstest.WriteTestFiles(tmpDir)) 138 139 testFS := Adapt(os.DirFS(tmpDir)) 140 testStat(t, testFS) 141 } 142 143 // hackFS cheats the api.FS contract by opening for write (os.O_RDWR). 144 // 145 // Until we have an alternate public interface for filesystems, some users will 146 // rely on this. Via testing, we ensure we don't accidentally break them. 147 type hackFS string 148 149 func (dir hackFS) Open(name string) (fs.File, error) { 150 path := ensureTrailingPathSeparator(string(dir)) + name 151 152 if f, err := os.OpenFile(path, os.O_RDWR, 0); err == nil { 153 return f, nil 154 } else if errors.Is(err, syscall.EISDIR) { 155 return os.OpenFile(path, os.O_RDONLY, 0) 156 } else if errors.Is(err, syscall.ENOENT) { 157 return os.OpenFile(path, os.O_RDONLY|os.O_CREATE, 0o444) 158 } else { 159 return nil, err 160 } 161 } 162 163 // TestAdapt_HackedWrites ensures we allow writes even if they violate the 164 // api.FS contract. 165 func TestAdapt_HackedWrites(t *testing.T) { 166 tmpDir := t.TempDir() 167 testFS := Adapt(hackFS(tmpDir)) 168 169 testOpen_O_RDWR(t, tmpDir, testFS) 170 }