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  }