github.com/xhghs/rclone@v1.51.1-0.20200430155106-e186a28cced8/fs/fs_test.go (about)

     1  package fs
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"os"
     8  	"strings"
     9  	"sync"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/stretchr/testify/require"
    14  
    15  	"github.com/pkg/errors"
    16  	"github.com/rclone/rclone/fs/config/configmap"
    17  	"github.com/rclone/rclone/fs/fserrors"
    18  	"github.com/rclone/rclone/lib/pacer"
    19  	"github.com/spf13/pflag"
    20  	"github.com/stretchr/testify/assert"
    21  )
    22  
    23  func TestFeaturesDisable(t *testing.T) {
    24  	ft := new(Features)
    25  	ft.Copy = func(ctx context.Context, src Object, remote string) (Object, error) {
    26  		return nil, nil
    27  	}
    28  	ft.CaseInsensitive = true
    29  
    30  	assert.NotNil(t, ft.Copy)
    31  	assert.Nil(t, ft.Purge)
    32  	ft.Disable("copy")
    33  	assert.Nil(t, ft.Copy)
    34  	assert.Nil(t, ft.Purge)
    35  
    36  	assert.True(t, ft.CaseInsensitive)
    37  	assert.False(t, ft.DuplicateFiles)
    38  	ft.Disable("caseinsensitive")
    39  	assert.False(t, ft.CaseInsensitive)
    40  	assert.False(t, ft.DuplicateFiles)
    41  }
    42  
    43  func TestFeaturesList(t *testing.T) {
    44  	ft := new(Features)
    45  	names := strings.Join(ft.List(), ",")
    46  	assert.True(t, strings.Contains(names, ",Copy,"))
    47  }
    48  
    49  func TestFeaturesEnabled(t *testing.T) {
    50  	ft := new(Features)
    51  	ft.CaseInsensitive = true
    52  	ft.Purge = func(ctx context.Context) error { return nil }
    53  	enabled := ft.Enabled()
    54  
    55  	flag, ok := enabled["CaseInsensitive"]
    56  	assert.Equal(t, true, ok)
    57  	assert.Equal(t, true, flag, enabled)
    58  
    59  	flag, ok = enabled["Purge"]
    60  	assert.Equal(t, true, ok)
    61  	assert.Equal(t, true, flag, enabled)
    62  
    63  	flag, ok = enabled["DuplicateFiles"]
    64  	assert.Equal(t, true, ok)
    65  	assert.Equal(t, false, flag, enabled)
    66  
    67  	flag, ok = enabled["Copy"]
    68  	assert.Equal(t, true, ok)
    69  	assert.Equal(t, false, flag, enabled)
    70  
    71  	assert.Equal(t, len(ft.List()), len(enabled))
    72  }
    73  
    74  func TestFeaturesDisableList(t *testing.T) {
    75  	ft := new(Features)
    76  	ft.Copy = func(ctx context.Context, src Object, remote string) (Object, error) {
    77  		return nil, nil
    78  	}
    79  	ft.CaseInsensitive = true
    80  
    81  	assert.NotNil(t, ft.Copy)
    82  	assert.Nil(t, ft.Purge)
    83  	assert.True(t, ft.CaseInsensitive)
    84  	assert.False(t, ft.DuplicateFiles)
    85  
    86  	ft.DisableList([]string{"copy", "caseinsensitive"})
    87  
    88  	assert.Nil(t, ft.Copy)
    89  	assert.Nil(t, ft.Purge)
    90  	assert.False(t, ft.CaseInsensitive)
    91  	assert.False(t, ft.DuplicateFiles)
    92  }
    93  
    94  // Check it satisfies the interface
    95  var _ pflag.Value = (*Option)(nil)
    96  
    97  func TestOption(t *testing.T) {
    98  	d := &Option{
    99  		Name:  "potato",
   100  		Value: SizeSuffix(17 << 20),
   101  	}
   102  	assert.Equal(t, "17M", d.String())
   103  	assert.Equal(t, "SizeSuffix", d.Type())
   104  	err := d.Set("18M")
   105  	assert.NoError(t, err)
   106  	assert.Equal(t, SizeSuffix(18<<20), d.Value)
   107  	err = d.Set("sdfsdf")
   108  	assert.Error(t, err)
   109  }
   110  
   111  var errFoo = errors.New("foo")
   112  
   113  type dummyPaced struct {
   114  	retry  bool
   115  	called int
   116  	wait   *sync.Cond
   117  }
   118  
   119  func (dp *dummyPaced) fn() (bool, error) {
   120  	if dp.wait != nil {
   121  		dp.wait.L.Lock()
   122  		dp.wait.Wait()
   123  		dp.wait.L.Unlock()
   124  	}
   125  	dp.called++
   126  	return dp.retry, errFoo
   127  }
   128  
   129  func TestPacerCall(t *testing.T) {
   130  	expectedCalled := Config.LowLevelRetries
   131  	if expectedCalled == 0 {
   132  		expectedCalled = 20
   133  		Config.LowLevelRetries = expectedCalled
   134  		defer func() {
   135  			Config.LowLevelRetries = 0
   136  		}()
   137  	}
   138  	p := NewPacer(pacer.NewDefault(pacer.MinSleep(1*time.Millisecond), pacer.MaxSleep(2*time.Millisecond)))
   139  
   140  	dp := &dummyPaced{retry: true}
   141  	err := p.Call(dp.fn)
   142  	require.Equal(t, expectedCalled, dp.called)
   143  	require.Implements(t, (*fserrors.Retrier)(nil), err)
   144  }
   145  
   146  func TestPacerCallNoRetry(t *testing.T) {
   147  	p := NewPacer(pacer.NewDefault(pacer.MinSleep(1*time.Millisecond), pacer.MaxSleep(2*time.Millisecond)))
   148  
   149  	dp := &dummyPaced{retry: true}
   150  	err := p.CallNoRetry(dp.fn)
   151  	require.Equal(t, 1, dp.called)
   152  	require.Implements(t, (*fserrors.Retrier)(nil), err)
   153  }
   154  
   155  // Test options
   156  var (
   157  	nouncOption = Option{
   158  		Name: "nounc",
   159  	}
   160  	copyLinksOption = Option{
   161  		Name:     "copy_links",
   162  		Default:  false,
   163  		NoPrefix: true,
   164  		ShortOpt: "L",
   165  		Advanced: true,
   166  	}
   167  	caseInsensitiveOption = Option{
   168  		Name:     "case_insensitive",
   169  		Default:  false,
   170  		Value:    true,
   171  		Advanced: true,
   172  	}
   173  	testOptions = Options{nouncOption, copyLinksOption, caseInsensitiveOption}
   174  )
   175  
   176  func TestOptionsSetValues(t *testing.T) {
   177  	assert.Nil(t, testOptions[0].Default)
   178  	assert.Equal(t, false, testOptions[1].Default)
   179  	assert.Equal(t, false, testOptions[2].Default)
   180  	testOptions.setValues()
   181  	assert.Equal(t, "", testOptions[0].Default)
   182  	assert.Equal(t, false, testOptions[1].Default)
   183  	assert.Equal(t, false, testOptions[2].Default)
   184  }
   185  
   186  func TestOptionsGet(t *testing.T) {
   187  	opt := testOptions.Get("copy_links")
   188  	assert.Equal(t, &copyLinksOption, opt)
   189  	opt = testOptions.Get("not_found")
   190  	assert.Nil(t, opt)
   191  }
   192  
   193  func TestOptionMarshalJSON(t *testing.T) {
   194  	out, err := json.MarshalIndent(&caseInsensitiveOption, "", "")
   195  	assert.NoError(t, err)
   196  	require.Equal(t, `{
   197  "Name": "case_insensitive",
   198  "Help": "",
   199  "Provider": "",
   200  "Default": false,
   201  "Value": true,
   202  "ShortOpt": "",
   203  "Hide": 0,
   204  "Required": false,
   205  "IsPassword": false,
   206  "NoPrefix": false,
   207  "Advanced": true,
   208  "DefaultStr": "false",
   209  "ValueStr": "true",
   210  "Type": "bool"
   211  }`, string(out))
   212  }
   213  
   214  func TestOptionGetValue(t *testing.T) {
   215  	assert.Equal(t, "", nouncOption.GetValue())
   216  	assert.Equal(t, false, copyLinksOption.GetValue())
   217  	assert.Equal(t, true, caseInsensitiveOption.GetValue())
   218  }
   219  
   220  func TestOptionString(t *testing.T) {
   221  	assert.Equal(t, "", nouncOption.String())
   222  	assert.Equal(t, "false", copyLinksOption.String())
   223  	assert.Equal(t, "true", caseInsensitiveOption.String())
   224  }
   225  
   226  func TestOptionSet(t *testing.T) {
   227  	o := caseInsensitiveOption
   228  	assert.Equal(t, true, o.Value)
   229  	err := o.Set("FALSE")
   230  	assert.NoError(t, err)
   231  	assert.Equal(t, false, o.Value)
   232  
   233  	o = copyLinksOption
   234  	assert.Equal(t, nil, o.Value)
   235  	err = o.Set("True")
   236  	assert.NoError(t, err)
   237  	assert.Equal(t, true, o.Value)
   238  
   239  	err = o.Set("INVALID")
   240  	assert.Error(t, err)
   241  	assert.Equal(t, true, o.Value)
   242  }
   243  
   244  func TestOptionType(t *testing.T) {
   245  	assert.Equal(t, "string", nouncOption.Type())
   246  	assert.Equal(t, "bool", copyLinksOption.Type())
   247  	assert.Equal(t, "bool", caseInsensitiveOption.Type())
   248  }
   249  
   250  func TestOptionFlagName(t *testing.T) {
   251  	assert.Equal(t, "local-nounc", nouncOption.FlagName("local"))
   252  	assert.Equal(t, "copy-links", copyLinksOption.FlagName("local"))
   253  	assert.Equal(t, "local-case-insensitive", caseInsensitiveOption.FlagName("local"))
   254  }
   255  
   256  func TestOptionEnvVarName(t *testing.T) {
   257  	assert.Equal(t, "RCLONE_LOCAL_NOUNC", nouncOption.EnvVarName("local"))
   258  	assert.Equal(t, "RCLONE_LOCAL_COPY_LINKS", copyLinksOption.EnvVarName("local"))
   259  	assert.Equal(t, "RCLONE_LOCAL_CASE_INSENSITIVE", caseInsensitiveOption.EnvVarName("local"))
   260  }
   261  
   262  func TestOptionGetters(t *testing.T) {
   263  	// Set up env vars
   264  	envVars := [][2]string{
   265  		{"RCLONE_CONFIG_LOCAL_POTATO_PIE", "yes"},
   266  		{"RCLONE_COPY_LINKS", "TRUE"},
   267  		{"RCLONE_LOCAL_NOUNC", "NOUNC"},
   268  	}
   269  	for _, ev := range envVars {
   270  		assert.NoError(t, os.Setenv(ev[0], ev[1]))
   271  	}
   272  	defer func() {
   273  		for _, ev := range envVars {
   274  			assert.NoError(t, os.Unsetenv(ev[0]))
   275  		}
   276  	}()
   277  
   278  	fsInfo := &RegInfo{
   279  		Name:    "local",
   280  		Prefix:  "local",
   281  		Options: testOptions,
   282  	}
   283  
   284  	oldConfigFileGet := ConfigFileGet
   285  	ConfigFileGet = func(section, key string) (string, bool) {
   286  		if section == "sausage" && key == "key1" {
   287  			return "value1", true
   288  		}
   289  		return "", false
   290  	}
   291  	defer func() {
   292  		ConfigFileGet = oldConfigFileGet
   293  	}()
   294  
   295  	// set up getters
   296  
   297  	// A configmap.Getter to read from the environment RCLONE_CONFIG_backend_option_name
   298  	configEnvVarsGetter := configEnvVars("local")
   299  
   300  	// A configmap.Getter to read from the environment RCLONE_option_name
   301  	optionEnvVarsGetter := optionEnvVars{fsInfo}
   302  
   303  	// A configmap.Getter to read either the default value or the set
   304  	// value from the RegInfo.Options
   305  	regInfoValuesGetterFalse := &regInfoValues{
   306  		fsInfo:     fsInfo,
   307  		useDefault: false,
   308  	}
   309  	regInfoValuesGetterTrue := &regInfoValues{
   310  		fsInfo:     fsInfo,
   311  		useDefault: true,
   312  	}
   313  
   314  	// A configmap.Setter to read from the config file
   315  	configFileGetter := getConfigFile("sausage")
   316  
   317  	for i, test := range []struct {
   318  		get       configmap.Getter
   319  		key       string
   320  		wantValue string
   321  		wantOk    bool
   322  	}{
   323  		{configEnvVarsGetter, "not_found", "", false},
   324  		{configEnvVarsGetter, "potato_pie", "yes", true},
   325  		{optionEnvVarsGetter, "not_found", "", false},
   326  		{optionEnvVarsGetter, "copy_links", "TRUE", true},
   327  		{optionEnvVarsGetter, "nounc", "NOUNC", true},
   328  		{optionEnvVarsGetter, "case_insensitive", "", false},
   329  		{regInfoValuesGetterFalse, "not_found", "", false},
   330  		{regInfoValuesGetterFalse, "case_insensitive", "true", true},
   331  		{regInfoValuesGetterFalse, "copy_links", "", false},
   332  		{regInfoValuesGetterTrue, "not_found", "", false},
   333  		{regInfoValuesGetterTrue, "case_insensitive", "true", true},
   334  		{regInfoValuesGetterTrue, "copy_links", "false", true},
   335  		{configFileGetter, "not_found", "", false},
   336  		{configFileGetter, "key1", "value1", true},
   337  	} {
   338  		what := fmt.Sprintf("%d: %+v: %q", i, test.get, test.key)
   339  		gotValue, gotOk := test.get.Get(test.key)
   340  		assert.Equal(t, test.wantValue, gotValue, what)
   341  		assert.Equal(t, test.wantOk, gotOk, what)
   342  	}
   343  
   344  }