github.com/artpar/rclone@v1.67.3/backend/ftp/ftp_internal_test.go (about) 1 package ftp 2 3 import ( 4 "context" 5 "fmt" 6 "strings" 7 "testing" 8 "time" 9 10 "github.com/artpar/rclone/fs" 11 "github.com/artpar/rclone/fs/config/configmap" 12 "github.com/artpar/rclone/fs/object" 13 "github.com/artpar/rclone/fstest" 14 "github.com/artpar/rclone/fstest/fstests" 15 "github.com/artpar/rclone/lib/readers" 16 "github.com/stretchr/testify/assert" 17 "github.com/stretchr/testify/require" 18 ) 19 20 type settings map[string]interface{} 21 22 func deriveFs(ctx context.Context, t *testing.T, f fs.Fs, opts settings) fs.Fs { 23 fsName := strings.Split(f.Name(), "{")[0] // strip off hash 24 configMap := configmap.Simple{} 25 for key, val := range opts { 26 configMap[key] = fmt.Sprintf("%v", val) 27 } 28 remote := fmt.Sprintf("%s,%s:%s", fsName, configMap.String(), f.Root()) 29 fixFs, err := fs.NewFs(ctx, remote) 30 require.NoError(t, err) 31 return fixFs 32 } 33 34 // test that big file uploads do not cause network i/o timeout 35 func (f *Fs) testUploadTimeout(t *testing.T) { 36 const ( 37 fileSize = 100000000 // 100 MiB 38 idleTimeout = 1 * time.Second // small because test server is local 39 maxTime = 10 * time.Second // prevent test hangup 40 ) 41 42 if testing.Short() { 43 t.Skip("not running with -short") 44 } 45 46 ctx := context.Background() 47 ci := fs.GetConfig(ctx) 48 saveLowLevelRetries := ci.LowLevelRetries 49 saveTimeout := ci.Timeout 50 defer func() { 51 ci.LowLevelRetries = saveLowLevelRetries 52 ci.Timeout = saveTimeout 53 }() 54 ci.LowLevelRetries = 1 55 ci.Timeout = idleTimeout 56 57 upload := func(concurrency int, shutTimeout time.Duration) (obj fs.Object, err error) { 58 fixFs := deriveFs(ctx, t, f, settings{ 59 "concurrency": concurrency, 60 "shut_timeout": shutTimeout, 61 }) 62 63 // Make test object 64 fileTime := fstest.Time("2020-03-08T09:30:00.000000000Z") 65 meta := object.NewStaticObjectInfo("upload-timeout.test", fileTime, int64(fileSize), true, nil, nil) 66 data := readers.NewPatternReader(int64(fileSize)) 67 68 // Run upload and ensure maximum time 69 done := make(chan bool) 70 deadline := time.After(maxTime) 71 go func() { 72 obj, err = fixFs.Put(ctx, data, meta) 73 done <- true 74 }() 75 select { 76 case <-done: 77 case <-deadline: 78 t.Fatalf("Upload got stuck for %v !", maxTime) 79 } 80 81 return obj, err 82 } 83 84 // non-zero shut_timeout should fix i/o errors 85 obj, err := upload(f.opt.Concurrency, time.Second) 86 assert.NoError(t, err) 87 assert.NotNil(t, obj) 88 if obj != nil { 89 _ = obj.Remove(ctx) 90 } 91 } 92 93 // rclone must support precise time with ProFtpd and PureFtpd out of the box. 94 // The VsFtpd server does not support the MFMT command to set file time like 95 // other servers but by default supports the MDTM command in the non-standard 96 // two-argument form for the same purpose. 97 // See "mdtm_write" in https://security.appspot.com/vsftpd/vsftpd_conf.html 98 func (f *Fs) testTimePrecision(t *testing.T) { 99 name := f.Name() 100 if pos := strings.Index(name, "{"); pos != -1 { 101 name = name[:pos] 102 } 103 switch name { 104 case "TestFTPProftpd", "TestFTPPureftpd", "TestFTPVsftpd": 105 assert.LessOrEqual(t, f.Precision(), time.Second) 106 } 107 } 108 109 // InternalTest dispatches all internal tests 110 func (f *Fs) InternalTest(t *testing.T) { 111 t.Run("UploadTimeout", f.testUploadTimeout) 112 t.Run("TimePrecision", f.testTimePrecision) 113 } 114 115 var _ fstests.InternalTester = (*Fs)(nil)