github.com/ncw/rclone@v1.48.1-0.20190724201158-a35aa1360e3e/backend/local/local_internal_test.go (about)

     1  package local
     2  
     3  import (
     4  	"context"
     5  	"io/ioutil"
     6  	"os"
     7  	"path"
     8  	"path/filepath"
     9  	"runtime"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/ncw/rclone/fs"
    14  	"github.com/ncw/rclone/fs/config/configmap"
    15  	"github.com/ncw/rclone/fs/hash"
    16  	"github.com/ncw/rclone/fstest"
    17  	"github.com/ncw/rclone/lib/file"
    18  	"github.com/ncw/rclone/lib/readers"
    19  	"github.com/stretchr/testify/assert"
    20  	"github.com/stretchr/testify/require"
    21  )
    22  
    23  // TestMain drives the tests
    24  func TestMain(m *testing.M) {
    25  	fstest.TestMain(m)
    26  }
    27  
    28  func TestMapper(t *testing.T) {
    29  	m := newMapper()
    30  	assert.Equal(t, m.m, map[string]string{})
    31  	assert.Equal(t, "potato", m.Save("potato", "potato"))
    32  	assert.Equal(t, m.m, map[string]string{})
    33  	assert.Equal(t, "-r'áö", m.Save("-r?'a´o¨", "-r'áö"))
    34  	assert.Equal(t, m.m, map[string]string{
    35  		"-r'áö": "-r?'a´o¨",
    36  	})
    37  	assert.Equal(t, "potato", m.Load("potato"))
    38  	assert.Equal(t, "-r?'a´o¨", m.Load("-r'áö"))
    39  }
    40  
    41  // Test copy with source file that's updating
    42  func TestUpdatingCheck(t *testing.T) {
    43  	r := fstest.NewRun(t)
    44  	defer r.Finalise()
    45  	filePath := "sub dir/local test"
    46  	r.WriteFile(filePath, "content", time.Now())
    47  
    48  	fd, err := file.Open(path.Join(r.LocalName, filePath))
    49  	if err != nil {
    50  		t.Fatalf("failed opening file %q: %v", filePath, err)
    51  	}
    52  	defer func() {
    53  		require.NoError(t, fd.Close())
    54  	}()
    55  
    56  	fi, err := fd.Stat()
    57  	require.NoError(t, err)
    58  	o := &Object{size: fi.Size(), modTime: fi.ModTime(), fs: &Fs{}}
    59  	wrappedFd := readers.NewLimitedReadCloser(fd, -1)
    60  	hash, err := hash.NewMultiHasherTypes(hash.Supported)
    61  	require.NoError(t, err)
    62  	in := localOpenFile{
    63  		o:    o,
    64  		in:   wrappedFd,
    65  		hash: hash,
    66  		fd:   fd,
    67  	}
    68  
    69  	buf := make([]byte, 1)
    70  	_, err = in.Read(buf)
    71  	require.NoError(t, err)
    72  
    73  	r.WriteFile(filePath, "content updated", time.Now())
    74  	_, err = in.Read(buf)
    75  	require.Errorf(t, err, "can't copy - source file is being updated")
    76  
    77  	// turn the checking off and try again
    78  	in.o.fs.opt.NoCheckUpdated = true
    79  
    80  	r.WriteFile(filePath, "content updated", time.Now())
    81  	_, err = in.Read(buf)
    82  	require.NoError(t, err)
    83  
    84  }
    85  
    86  func TestSymlink(t *testing.T) {
    87  	ctx := context.Background()
    88  	r := fstest.NewRun(t)
    89  	defer r.Finalise()
    90  	f := r.Flocal.(*Fs)
    91  	dir := f.root
    92  
    93  	// Write a file
    94  	modTime1 := fstest.Time("2001-02-03T04:05:10.123123123Z")
    95  	file1 := r.WriteFile("file.txt", "hello", modTime1)
    96  
    97  	// Write a symlink
    98  	modTime2 := fstest.Time("2002-02-03T04:05:10.123123123Z")
    99  	symlinkPath := filepath.Join(dir, "symlink.txt")
   100  	require.NoError(t, os.Symlink("file.txt", symlinkPath))
   101  	require.NoError(t, lChtimes(symlinkPath, modTime2, modTime2))
   102  
   103  	// Object viewed as symlink
   104  	file2 := fstest.NewItem("symlink.txt"+linkSuffix, "file.txt", modTime2)
   105  	if runtime.GOOS == "windows" {
   106  		file2.Size = 0 // symlinks are 0 length under Windows
   107  	}
   108  
   109  	// Object viewed as destination
   110  	file2d := fstest.NewItem("symlink.txt", "hello", modTime1)
   111  
   112  	// Check with no symlink flags
   113  	fstest.CheckItems(t, r.Flocal, file1)
   114  	fstest.CheckItems(t, r.Fremote)
   115  
   116  	// Set fs into "-L" mode
   117  	f.opt.FollowSymlinks = true
   118  	f.opt.TranslateSymlinks = false
   119  	f.lstat = os.Stat
   120  
   121  	fstest.CheckItems(t, r.Flocal, file1, file2d)
   122  	fstest.CheckItems(t, r.Fremote)
   123  
   124  	// Set fs into "-l" mode
   125  	f.opt.FollowSymlinks = false
   126  	f.opt.TranslateSymlinks = true
   127  	f.lstat = os.Lstat
   128  
   129  	fstest.CheckListingWithPrecision(t, r.Flocal, []fstest.Item{file1, file2}, nil, fs.ModTimeNotSupported)
   130  	if haveLChtimes {
   131  		fstest.CheckItems(t, r.Flocal, file1, file2)
   132  	}
   133  
   134  	// Create a symlink
   135  	modTime3 := fstest.Time("2002-03-03T04:05:10.123123123Z")
   136  	file3 := r.WriteObjectTo(ctx, r.Flocal, "symlink2.txt"+linkSuffix, "file.txt", modTime3, false)
   137  	if runtime.GOOS == "windows" {
   138  		file3.Size = 0 // symlinks are 0 length under Windows
   139  	}
   140  	fstest.CheckListingWithPrecision(t, r.Flocal, []fstest.Item{file1, file2, file3}, nil, fs.ModTimeNotSupported)
   141  	if haveLChtimes {
   142  		fstest.CheckItems(t, r.Flocal, file1, file2, file3)
   143  	}
   144  
   145  	// Check it got the correct contents
   146  	symlinkPath = filepath.Join(dir, "symlink2.txt")
   147  	fi, err := os.Lstat(symlinkPath)
   148  	require.NoError(t, err)
   149  	assert.False(t, fi.Mode().IsRegular())
   150  	linkText, err := os.Readlink(symlinkPath)
   151  	require.NoError(t, err)
   152  	assert.Equal(t, "file.txt", linkText)
   153  
   154  	// Check that NewObject gets the correct object
   155  	o, err := r.Flocal.NewObject(ctx, "symlink2.txt"+linkSuffix)
   156  	require.NoError(t, err)
   157  	assert.Equal(t, "symlink2.txt"+linkSuffix, o.Remote())
   158  	if runtime.GOOS != "windows" {
   159  		assert.Equal(t, int64(8), o.Size())
   160  	}
   161  
   162  	// Check that NewObject doesn't see the non suffixed version
   163  	_, err = r.Flocal.NewObject(ctx, "symlink2.txt")
   164  	require.Equal(t, fs.ErrorObjectNotFound, err)
   165  
   166  	// Check reading the object
   167  	in, err := o.Open(ctx)
   168  	require.NoError(t, err)
   169  	contents, err := ioutil.ReadAll(in)
   170  	require.NoError(t, err)
   171  	require.Equal(t, "file.txt", string(contents))
   172  	require.NoError(t, in.Close())
   173  
   174  	// Check reading the object with range
   175  	in, err = o.Open(ctx, &fs.RangeOption{Start: 2, End: 5})
   176  	require.NoError(t, err)
   177  	contents, err = ioutil.ReadAll(in)
   178  	require.NoError(t, err)
   179  	require.Equal(t, "file.txt"[2:5+1], string(contents))
   180  	require.NoError(t, in.Close())
   181  }
   182  
   183  func TestSymlinkError(t *testing.T) {
   184  	m := configmap.Simple{
   185  		"links":      "true",
   186  		"copy_links": "true",
   187  	}
   188  	_, err := NewFs("local", "/", m)
   189  	assert.Equal(t, errLinksAndCopyLinks, err)
   190  }