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)