mirror of
https://github.com/rclone/rclone.git
synced 2025-07-26 00:05:53 +02:00
All user visible Durations should be fs.Duration rather than time.Duration. Suffix is then optional and defaults to s. Additional suffices d, w, M and y are supported, in addition to ms, s, m and h - which are the only ones supported by time.Duration. Absolute times can also be specified, and will be interpreted as duration relative to now.
116 lines
3.2 KiB
Go
116 lines
3.2 KiB
Go
package ftp
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/rclone/rclone/fs"
|
|
"github.com/rclone/rclone/fs/config/configmap"
|
|
"github.com/rclone/rclone/fs/object"
|
|
"github.com/rclone/rclone/fstest"
|
|
"github.com/rclone/rclone/fstest/fstests"
|
|
"github.com/rclone/rclone/lib/readers"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
type settings map[string]any
|
|
|
|
func deriveFs(ctx context.Context, t *testing.T, f fs.Fs, opts settings) fs.Fs {
|
|
fsName := strings.Split(f.Name(), "{")[0] // strip off hash
|
|
configMap := configmap.Simple{}
|
|
for key, val := range opts {
|
|
configMap[key] = fmt.Sprintf("%v", val)
|
|
}
|
|
remote := fmt.Sprintf("%s,%s:%s", fsName, configMap.String(), f.Root())
|
|
fixFs, err := fs.NewFs(ctx, remote)
|
|
require.NoError(t, err)
|
|
return fixFs
|
|
}
|
|
|
|
// test that big file uploads do not cause network i/o timeout
|
|
func (f *Fs) testUploadTimeout(t *testing.T) {
|
|
const (
|
|
fileSize = 100000000 // 100 MiB
|
|
idleTimeout = 1 * time.Second // small because test server is local
|
|
maxTime = 10 * time.Second // prevent test hangup
|
|
)
|
|
|
|
if testing.Short() {
|
|
t.Skip("not running with -short")
|
|
}
|
|
|
|
ctx := context.Background()
|
|
ci := fs.GetConfig(ctx)
|
|
saveLowLevelRetries := ci.LowLevelRetries
|
|
saveTimeout := ci.Timeout
|
|
defer func() {
|
|
ci.LowLevelRetries = saveLowLevelRetries
|
|
ci.Timeout = saveTimeout
|
|
}()
|
|
ci.LowLevelRetries = 1
|
|
ci.Timeout = fs.Duration(idleTimeout)
|
|
|
|
upload := func(concurrency int, shutTimeout time.Duration) (obj fs.Object, err error) {
|
|
fixFs := deriveFs(ctx, t, f, settings{
|
|
"concurrency": concurrency,
|
|
"shut_timeout": shutTimeout,
|
|
})
|
|
|
|
// Make test object
|
|
fileTime := fstest.Time("2020-03-08T09:30:00.000000000Z")
|
|
meta := object.NewStaticObjectInfo("upload-timeout.test", fileTime, int64(fileSize), true, nil, nil)
|
|
data := readers.NewPatternReader(int64(fileSize))
|
|
|
|
// Run upload and ensure maximum time
|
|
done := make(chan bool)
|
|
deadline := time.After(maxTime)
|
|
go func() {
|
|
obj, err = fixFs.Put(ctx, data, meta)
|
|
done <- true
|
|
}()
|
|
select {
|
|
case <-done:
|
|
case <-deadline:
|
|
t.Fatalf("Upload got stuck for %v !", maxTime)
|
|
}
|
|
|
|
return obj, err
|
|
}
|
|
|
|
// non-zero shut_timeout should fix i/o errors
|
|
obj, err := upload(f.opt.Concurrency, time.Second)
|
|
assert.NoError(t, err)
|
|
assert.NotNil(t, obj)
|
|
if obj != nil {
|
|
_ = obj.Remove(ctx)
|
|
}
|
|
}
|
|
|
|
// rclone must support precise time with ProFtpd and PureFtpd out of the box.
|
|
// The VsFtpd server does not support the MFMT command to set file time like
|
|
// other servers but by default supports the MDTM command in the non-standard
|
|
// two-argument form for the same purpose.
|
|
// See "mdtm_write" in https://security.appspot.com/vsftpd/vsftpd_conf.html
|
|
func (f *Fs) testTimePrecision(t *testing.T) {
|
|
name := f.Name()
|
|
if pos := strings.Index(name, "{"); pos != -1 {
|
|
name = name[:pos]
|
|
}
|
|
switch name {
|
|
case "TestFTPProftpd", "TestFTPPureftpd", "TestFTPVsftpd":
|
|
assert.LessOrEqual(t, f.Precision(), time.Second)
|
|
}
|
|
}
|
|
|
|
// InternalTest dispatches all internal tests
|
|
func (f *Fs) InternalTest(t *testing.T) {
|
|
t.Run("UploadTimeout", f.testUploadTimeout)
|
|
t.Run("TimePrecision", f.testTimePrecision)
|
|
}
|
|
|
|
var _ fstests.InternalTester = (*Fs)(nil)
|