github.com/databricks/cli@v0.203.0/libs/filer/fs_test.go (about)

     1  package filer
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"io"
     7  	"io/fs"
     8  	"path"
     9  	"sort"
    10  	"strings"
    11  	"testing"
    12  	"time"
    13  
    14  	"github.com/stretchr/testify/assert"
    15  	"github.com/stretchr/testify/require"
    16  )
    17  
    18  type fakeDirEntry struct {
    19  	fakeFileInfo
    20  }
    21  
    22  func (entry fakeDirEntry) Type() fs.FileMode {
    23  	typ := fs.ModePerm
    24  	if entry.dir {
    25  		typ |= fs.ModeDir
    26  	}
    27  	return typ
    28  }
    29  
    30  func (entry fakeDirEntry) Info() (fs.FileInfo, error) {
    31  	return entry.fakeFileInfo, nil
    32  }
    33  
    34  type fakeFileInfo struct {
    35  	name string
    36  	size int64
    37  	dir  bool
    38  	mode fs.FileMode
    39  }
    40  
    41  func (info fakeFileInfo) Name() string {
    42  	return info.name
    43  }
    44  
    45  func (info fakeFileInfo) Size() int64 {
    46  	return info.size
    47  }
    48  
    49  func (info fakeFileInfo) Mode() fs.FileMode {
    50  	return info.mode
    51  }
    52  
    53  func (info fakeFileInfo) ModTime() time.Time {
    54  	return time.Now()
    55  }
    56  
    57  func (info fakeFileInfo) IsDir() bool {
    58  	return info.dir
    59  }
    60  
    61  func (info fakeFileInfo) Sys() any {
    62  	return nil
    63  }
    64  
    65  type fakeFiler struct {
    66  	entries map[string]fakeFileInfo
    67  }
    68  
    69  func (f *fakeFiler) Write(ctx context.Context, p string, reader io.Reader, mode ...WriteMode) error {
    70  	return fmt.Errorf("not implemented")
    71  }
    72  
    73  func (f *fakeFiler) Read(ctx context.Context, p string) (io.ReadCloser, error) {
    74  	_, ok := f.entries[p]
    75  	if !ok {
    76  		return nil, fs.ErrNotExist
    77  	}
    78  
    79  	return io.NopCloser(strings.NewReader("foo")), nil
    80  }
    81  
    82  func (f *fakeFiler) Delete(ctx context.Context, p string, mode ...DeleteMode) error {
    83  	return fmt.Errorf("not implemented")
    84  }
    85  
    86  func (f *fakeFiler) ReadDir(ctx context.Context, p string) ([]fs.DirEntry, error) {
    87  	entry, ok := f.entries[p]
    88  	if !ok {
    89  		return nil, fs.ErrNotExist
    90  	}
    91  
    92  	if !entry.dir {
    93  		return nil, fs.ErrInvalid
    94  	}
    95  
    96  	// Find all entries contained in the specified directory `p`.
    97  	var out []fs.DirEntry
    98  	for k, v := range f.entries {
    99  		if k == p || path.Dir(k) != p {
   100  			continue
   101  		}
   102  
   103  		out = append(out, fakeDirEntry{v})
   104  	}
   105  
   106  	sort.Slice(out, func(i, j int) bool { return out[i].Name() < out[j].Name() })
   107  	return out, nil
   108  }
   109  
   110  func (f *fakeFiler) Mkdir(ctx context.Context, path string) error {
   111  	return fmt.Errorf("not implemented")
   112  }
   113  
   114  func (f *fakeFiler) Stat(ctx context.Context, path string) (fs.FileInfo, error) {
   115  	entry, ok := f.entries[path]
   116  	if !ok {
   117  		return nil, fs.ErrNotExist
   118  	}
   119  
   120  	return entry, nil
   121  }
   122  
   123  func TestFsImplementsFS(t *testing.T) {
   124  	var _ fs.FS = &filerFS{}
   125  }
   126  
   127  func TestFsImplementsReadDirFS(t *testing.T) {
   128  	var _ fs.ReadDirFS = &filerFS{}
   129  }
   130  
   131  func TestFsImplementsReadFileFS(t *testing.T) {
   132  	var _ fs.ReadDirFS = &filerFS{}
   133  }
   134  
   135  func TestFsImplementsStatFS(t *testing.T) {
   136  	var _ fs.StatFS = &filerFS{}
   137  }
   138  
   139  func TestFsFileImplementsFsFile(t *testing.T) {
   140  	var _ fs.File = &fsFile{}
   141  }
   142  
   143  func TestFsDirImplementsFsReadDirFile(t *testing.T) {
   144  	var _ fs.ReadDirFile = &fsDir{}
   145  }
   146  
   147  func fakeFS() fs.FS {
   148  	fakeFiler := &fakeFiler{
   149  		entries: map[string]fakeFileInfo{
   150  			".":     {name: "root", dir: true},
   151  			"dirA":  {dir: true},
   152  			"dirB":  {dir: true},
   153  			"fileA": {size: 3},
   154  		},
   155  	}
   156  
   157  	for k, v := range fakeFiler.entries {
   158  		if v.name != "" {
   159  			continue
   160  		}
   161  		v.name = path.Base(k)
   162  		fakeFiler.entries[k] = v
   163  	}
   164  
   165  	return NewFS(context.Background(), fakeFiler)
   166  }
   167  
   168  func TestFsGlob(t *testing.T) {
   169  	fakeFS := fakeFS()
   170  	matches, err := fs.Glob(fakeFS, "*")
   171  	require.NoError(t, err)
   172  	assert.Equal(t, []string{"dirA", "dirB", "fileA"}, matches)
   173  }
   174  
   175  func TestFsOpenFile(t *testing.T) {
   176  	fakeFS := fakeFS()
   177  	fakeFile, err := fakeFS.Open("fileA")
   178  	require.NoError(t, err)
   179  
   180  	info, err := fakeFile.Stat()
   181  	require.NoError(t, err)
   182  	assert.Equal(t, "fileA", info.Name())
   183  	assert.Equal(t, int64(3), info.Size())
   184  	assert.Equal(t, fs.FileMode(0), info.Mode())
   185  	assert.Equal(t, false, info.IsDir())
   186  
   187  	// Read until closed.
   188  	b := make([]byte, 3)
   189  	n, err := fakeFile.Read(b)
   190  	require.NoError(t, err)
   191  	assert.Equal(t, 3, n)
   192  	assert.Equal(t, []byte{'f', 'o', 'o'}, b)
   193  	_, err = fakeFile.Read(b)
   194  	assert.ErrorIs(t, err, io.EOF)
   195  
   196  	// Close.
   197  	err = fakeFile.Close()
   198  	assert.NoError(t, err)
   199  
   200  	// Close again.
   201  	err = fakeFile.Close()
   202  	assert.ErrorIs(t, err, fs.ErrClosed)
   203  }
   204  
   205  func TestFsOpenDir(t *testing.T) {
   206  	fakeFS := fakeFS()
   207  	fakeFile, err := fakeFS.Open(".")
   208  	require.NoError(t, err)
   209  
   210  	info, err := fakeFile.Stat()
   211  	require.NoError(t, err)
   212  	assert.Equal(t, "root", info.Name())
   213  	assert.Equal(t, true, info.IsDir())
   214  
   215  	de, ok := fakeFile.(fs.ReadDirFile)
   216  	require.True(t, ok)
   217  
   218  	// Read all entries in one shot.
   219  	reference, err := de.ReadDir(-1)
   220  	require.NoError(t, err)
   221  
   222  	// Read entries one at a time.
   223  	{
   224  		var tmp, entries []fs.DirEntry
   225  		var err error
   226  
   227  		de.Close()
   228  
   229  		for i := 0; i < 3; i++ {
   230  			tmp, err = de.ReadDir(1)
   231  			require.NoError(t, err)
   232  			entries = append(entries, tmp...)
   233  		}
   234  
   235  		_, err = de.ReadDir(1)
   236  		require.ErrorIs(t, err, io.EOF, err)
   237  
   238  		// Compare to reference.
   239  		assert.Equal(t, reference, entries)
   240  	}
   241  
   242  	// Read entries and overshoot at the end.
   243  	{
   244  		var tmp, entries []fs.DirEntry
   245  		var err error
   246  
   247  		de.Close()
   248  
   249  		tmp, err = de.ReadDir(1)
   250  		require.NoError(t, err)
   251  		entries = append(entries, tmp...)
   252  
   253  		tmp, err = de.ReadDir(20)
   254  		require.NoError(t, err)
   255  		entries = append(entries, tmp...)
   256  
   257  		_, err = de.ReadDir(1)
   258  		require.ErrorIs(t, err, io.EOF, err)
   259  
   260  		// Compare to reference.
   261  		assert.Equal(t, reference, entries)
   262  	}
   263  }
   264  
   265  func TestFsReadDir(t *testing.T) {
   266  	fakeFS := fakeFS().(fs.ReadDirFS)
   267  	entries, err := fakeFS.ReadDir(".")
   268  	require.NoError(t, err)
   269  	assert.Len(t, entries, 3)
   270  	assert.Equal(t, "dirA", entries[0].Name())
   271  	assert.Equal(t, "dirB", entries[1].Name())
   272  	assert.Equal(t, "fileA", entries[2].Name())
   273  }
   274  
   275  func TestFsReadFile(t *testing.T) {
   276  	fakeFS := fakeFS().(fs.ReadFileFS)
   277  	buf, err := fakeFS.ReadFile("fileA")
   278  	require.NoError(t, err)
   279  	assert.Equal(t, []byte("foo"), buf)
   280  }
   281  
   282  func TestFsStat(t *testing.T) {
   283  	fakeFS := fakeFS().(fs.StatFS)
   284  	info, err := fakeFS.Stat("fileA")
   285  	require.NoError(t, err)
   286  	assert.Equal(t, "fileA", info.Name())
   287  	assert.Equal(t, int64(3), info.Size())
   288  }