github.com/rclone/rclone@v1.66.1-0.20240517100346-7b89735ae726/fs/rc/config_test.go (about)

     1  package rc
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"errors"
     7  	"fmt"
     8  	"testing"
     9  
    10  	"github.com/rclone/rclone/fs"
    11  	"github.com/stretchr/testify/assert"
    12  	"github.com/stretchr/testify/require"
    13  )
    14  
    15  func clearOptionBlock() func() {
    16  	oldOptionBlock := optionBlock
    17  	optionBlock = map[string]interface{}{}
    18  	return func() {
    19  		optionBlock = oldOptionBlock
    20  	}
    21  }
    22  
    23  var testOptions = struct {
    24  	String string
    25  	Int    int
    26  }{
    27  	String: "hello",
    28  	Int:    42,
    29  }
    30  
    31  func TestAddOption(t *testing.T) {
    32  	defer clearOptionBlock()()
    33  	assert.Equal(t, len(optionBlock), 0)
    34  	AddOption("potato", &testOptions)
    35  	assert.Equal(t, len(optionBlock), 1)
    36  	assert.Equal(t, len(optionReload), 0)
    37  	assert.Equal(t, &testOptions, optionBlock["potato"])
    38  }
    39  
    40  func TestAddOptionReload(t *testing.T) {
    41  	defer clearOptionBlock()()
    42  	assert.Equal(t, len(optionBlock), 0)
    43  	reload := func(ctx context.Context) error { return nil }
    44  	AddOptionReload("potato", &testOptions, reload)
    45  	assert.Equal(t, len(optionBlock), 1)
    46  	assert.Equal(t, len(optionReload), 1)
    47  	assert.Equal(t, &testOptions, optionBlock["potato"])
    48  	assert.Equal(t, fmt.Sprintf("%p", reload), fmt.Sprintf("%p", optionReload["potato"]))
    49  }
    50  
    51  func TestOptionsBlocks(t *testing.T) {
    52  	defer clearOptionBlock()()
    53  	AddOption("potato", &testOptions)
    54  	call := Calls.Get("options/blocks")
    55  	require.NotNil(t, call)
    56  	in := Params{}
    57  	out, err := call.Fn(context.Background(), in)
    58  	require.NoError(t, err)
    59  	require.NotNil(t, out)
    60  	assert.Equal(t, Params{"options": []string{"potato"}}, out)
    61  }
    62  
    63  func TestOptionsGet(t *testing.T) {
    64  	defer clearOptionBlock()()
    65  	AddOption("potato", &testOptions)
    66  	call := Calls.Get("options/get")
    67  	require.NotNil(t, call)
    68  	in := Params{}
    69  	out, err := call.Fn(context.Background(), in)
    70  	require.NoError(t, err)
    71  	require.NotNil(t, out)
    72  	assert.Equal(t, Params{"potato": &testOptions}, out)
    73  }
    74  
    75  func TestOptionsGetMarshal(t *testing.T) {
    76  	defer clearOptionBlock()()
    77  	ctx := context.Background()
    78  	ci := fs.GetConfig(ctx)
    79  
    80  	// Add some real options
    81  	AddOption("main", ci)
    82  	AddOption("rc", &DefaultOpt)
    83  
    84  	// get them
    85  	call := Calls.Get("options/get")
    86  	require.NotNil(t, call)
    87  	in := Params{}
    88  	out, err := call.Fn(context.Background(), in)
    89  	require.NoError(t, err)
    90  	require.NotNil(t, out)
    91  
    92  	// Check that they marshal
    93  	_, err = json.Marshal(out)
    94  	require.NoError(t, err)
    95  }
    96  
    97  func TestOptionsSet(t *testing.T) {
    98  	defer clearOptionBlock()()
    99  	var reloaded int
   100  	AddOptionReload("potato", &testOptions, func(ctx context.Context) error {
   101  		if reloaded > 0 {
   102  			return errors.New("error while reloading")
   103  		}
   104  		reloaded++
   105  		return nil
   106  	})
   107  	call := Calls.Get("options/set")
   108  	require.NotNil(t, call)
   109  
   110  	in := Params{
   111  		"potato": Params{
   112  			"Int": 50,
   113  		},
   114  	}
   115  	out, err := call.Fn(context.Background(), in)
   116  	require.NoError(t, err)
   117  	require.Nil(t, out)
   118  	assert.Equal(t, 50, testOptions.Int)
   119  	assert.Equal(t, "hello", testOptions.String)
   120  	assert.Equal(t, 1, reloaded)
   121  
   122  	// error from reload
   123  	_, err = call.Fn(context.Background(), in)
   124  	require.Error(t, err)
   125  	assert.Contains(t, err.Error(), "error while reloading")
   126  
   127  	// unknown option block
   128  	in = Params{
   129  		"sausage": Params{
   130  			"Int": 50,
   131  		},
   132  	}
   133  	_, err = call.Fn(context.Background(), in)
   134  	require.Error(t, err)
   135  	assert.Contains(t, err.Error(), "unknown option block")
   136  
   137  	// bad shape
   138  	in = Params{
   139  		"potato": []string{"a", "b"},
   140  	}
   141  	_, err = call.Fn(context.Background(), in)
   142  	require.Error(t, err)
   143  	assert.Contains(t, err.Error(), "failed to write options")
   144  
   145  }