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

     1  package fs
     2  
     3  import (
     4  	"fmt"
     5  	"net/http"
     6  	"testing"
     7  
     8  	"github.com/rclone/rclone/fs/hash"
     9  	"github.com/stretchr/testify/assert"
    10  	"github.com/stretchr/testify/require"
    11  )
    12  
    13  func TestParseRangeOption(t *testing.T) {
    14  	for _, test := range []struct {
    15  		in   string
    16  		want RangeOption
    17  		err  string
    18  	}{
    19  		{in: "", err: "doesn't start with bytes="},
    20  		{in: "bytes=1-2,3-4", err: "contains multiple ranges"},
    21  		{in: "bytes=100", err: "contains no '-'"},
    22  		{in: "bytes=x-8", err: "bad start"},
    23  		{in: "bytes=8-x", err: "bad end"},
    24  		{in: "bytes=1-2", want: RangeOption{Start: 1, End: 2}},
    25  		{in: "bytes=-123456789123456789", want: RangeOption{Start: -1, End: 123456789123456789}},
    26  		{in: "bytes=123456789123456789-", want: RangeOption{Start: 123456789123456789, End: -1}},
    27  		{in: "bytes=  1  -  2  ", want: RangeOption{Start: 1, End: 2}},
    28  		{in: "bytes=-", want: RangeOption{Start: -1, End: -1}},
    29  		{in: "bytes=  -  ", want: RangeOption{Start: -1, End: -1}},
    30  	} {
    31  		got, err := ParseRangeOption(test.in)
    32  		what := fmt.Sprintf("parsing %q", test.in)
    33  		if test.err != "" {
    34  			require.Contains(t, err.Error(), test.err)
    35  			require.Nil(t, got, what)
    36  		} else {
    37  			require.NoError(t, err, what)
    38  			assert.Equal(t, test.want, *got, what)
    39  		}
    40  	}
    41  }
    42  
    43  func TestRangeOptionDecode(t *testing.T) {
    44  	for _, test := range []struct {
    45  		in         RangeOption
    46  		size       int64
    47  		wantOffset int64
    48  		wantLimit  int64
    49  	}{
    50  		{in: RangeOption{Start: 1, End: 10}, size: 100, wantOffset: 1, wantLimit: 10},
    51  		{in: RangeOption{Start: 10, End: 10}, size: 100, wantOffset: 10, wantLimit: 1},
    52  		{in: RangeOption{Start: 10, End: 9}, size: 100, wantOffset: 10, wantLimit: 0},
    53  		{in: RangeOption{Start: 1, End: -1}, size: 100, wantOffset: 1, wantLimit: -1},
    54  		{in: RangeOption{Start: -1, End: 90}, size: 100, wantOffset: 10, wantLimit: -1},
    55  		{in: RangeOption{Start: -1, End: -1}, size: 100, wantOffset: 0, wantLimit: -1},
    56  	} {
    57  		gotOffset, gotLimit := test.in.Decode(test.size)
    58  		what := fmt.Sprintf("%+v size=%d", test.in, test.size)
    59  		assert.Equal(t, test.wantOffset, gotOffset, "offset "+what)
    60  		assert.Equal(t, test.wantLimit, gotLimit, "limit "+what)
    61  	}
    62  }
    63  
    64  func TestRangeOption(t *testing.T) {
    65  	opt := &RangeOption{Start: 1, End: 10}
    66  	var _ OpenOption = opt // check interface
    67  	assert.Equal(t, "RangeOption(1,10)", opt.String())
    68  	key, value := opt.Header()
    69  	assert.Equal(t, "Range", key)
    70  	assert.Equal(t, "bytes=1-10", value)
    71  	assert.Equal(t, true, opt.Mandatory())
    72  
    73  	opt = &RangeOption{Start: -1, End: 10}
    74  	assert.Equal(t, "RangeOption(-1,10)", opt.String())
    75  	key, value = opt.Header()
    76  	assert.Equal(t, "Range", key)
    77  	assert.Equal(t, "bytes=-10", value)
    78  	assert.Equal(t, true, opt.Mandatory())
    79  
    80  	opt = &RangeOption{Start: 1, End: -1}
    81  	assert.Equal(t, "RangeOption(1,-1)", opt.String())
    82  	key, value = opt.Header()
    83  	assert.Equal(t, "Range", key)
    84  	assert.Equal(t, "bytes=1-", value)
    85  	assert.Equal(t, true, opt.Mandatory())
    86  
    87  	opt = &RangeOption{Start: -1, End: -1}
    88  	assert.Equal(t, "RangeOption(-1,-1)", opt.String())
    89  	key, value = opt.Header()
    90  	assert.Equal(t, "Range", key)
    91  	assert.Equal(t, "bytes=-", value)
    92  	assert.Equal(t, true, opt.Mandatory())
    93  }
    94  
    95  func TestSeekOption(t *testing.T) {
    96  	opt := &SeekOption{Offset: 1}
    97  	var _ OpenOption = opt // check interface
    98  	assert.Equal(t, "SeekOption(1)", opt.String())
    99  	key, value := opt.Header()
   100  	assert.Equal(t, "Range", key)
   101  	assert.Equal(t, "bytes=1-", value)
   102  	assert.Equal(t, true, opt.Mandatory())
   103  }
   104  
   105  func TestHTTPOption(t *testing.T) {
   106  	opt := &HTTPOption{Key: "k", Value: "v"}
   107  	var _ OpenOption = opt // check interface
   108  	assert.Equal(t, `HTTPOption("k","v")`, opt.String())
   109  	key, value := opt.Header()
   110  	assert.Equal(t, "k", key)
   111  	assert.Equal(t, "v", value)
   112  	assert.Equal(t, false, opt.Mandatory())
   113  }
   114  
   115  func TestHashesOption(t *testing.T) {
   116  	opt := &HashesOption{hash.Set(hash.MD5 | hash.SHA1)}
   117  	var _ OpenOption = opt // check interface
   118  	assert.Equal(t, `HashesOption([md5, sha1])`, opt.String())
   119  	key, value := opt.Header()
   120  	assert.Equal(t, "", key)
   121  	assert.Equal(t, "", value)
   122  	assert.Equal(t, false, opt.Mandatory())
   123  }
   124  
   125  func TestNullOption(t *testing.T) {
   126  	opt := NullOption{}
   127  	var _ OpenOption = opt // check interface
   128  	assert.Equal(t, "NullOption()", opt.String())
   129  	key, value := opt.Header()
   130  	assert.Equal(t, "", key)
   131  	assert.Equal(t, "", value)
   132  	assert.Equal(t, false, opt.Mandatory())
   133  }
   134  
   135  func TestMetadataOption(t *testing.T) {
   136  	opt := MetadataOption{"onion": "ice cream"}
   137  	var _ OpenOption = opt // check interface
   138  	assert.Equal(t, "MetadataOption(map[onion:ice cream])", opt.String())
   139  	key, value := opt.Header()
   140  	assert.Equal(t, "", key)
   141  	assert.Equal(t, "", value)
   142  	assert.Equal(t, false, opt.Mandatory())
   143  }
   144  
   145  func TestFixRangeOptions(t *testing.T) {
   146  	for _, test := range []struct {
   147  		name string
   148  		in   []OpenOption
   149  		size int64
   150  		want []OpenOption
   151  	}{
   152  		{
   153  			name: "Nil options",
   154  			in:   nil,
   155  			want: nil,
   156  		},
   157  		{
   158  			name: "Empty options",
   159  			in:   []OpenOption{},
   160  			want: []OpenOption{},
   161  		},
   162  		{
   163  			name: "Unknown size -1",
   164  			in: []OpenOption{
   165  				&RangeOption{Start: 1, End: -1},
   166  			},
   167  			want: []OpenOption{
   168  				&RangeOption{Start: 1, End: -1},
   169  			},
   170  			size: -1,
   171  		},
   172  		{
   173  			name: "Fetch a range with size=0",
   174  			in: []OpenOption{
   175  				&HTTPOption{Key: "a", Value: "1"},
   176  				&RangeOption{Start: 1, End: 10},
   177  				&HTTPOption{Key: "b", Value: "2"},
   178  			},
   179  			want: []OpenOption{
   180  				&HTTPOption{Key: "a", Value: "1"},
   181  				NullOption{},
   182  				&HTTPOption{Key: "b", Value: "2"},
   183  			},
   184  			size: 0,
   185  		},
   186  		{
   187  			name: "Fetch a range",
   188  			in: []OpenOption{
   189  				&HTTPOption{Key: "a", Value: "1"},
   190  				&RangeOption{Start: 1, End: 10},
   191  				&HTTPOption{Key: "b", Value: "2"},
   192  			},
   193  			want: []OpenOption{
   194  				&HTTPOption{Key: "a", Value: "1"},
   195  				&RangeOption{Start: 1, End: 10},
   196  				&HTTPOption{Key: "b", Value: "2"},
   197  			},
   198  			size: 100,
   199  		},
   200  		{
   201  			name: "Fetch to end",
   202  			in: []OpenOption{
   203  				&RangeOption{Start: 1, End: -1},
   204  			},
   205  			want: []OpenOption{
   206  				&RangeOption{Start: 1, End: 99},
   207  			},
   208  			size: 100,
   209  		},
   210  		{
   211  			name: "Fetch the last 10 bytes",
   212  			in: []OpenOption{
   213  				&RangeOption{Start: -1, End: 10},
   214  			},
   215  			want: []OpenOption{
   216  				&RangeOption{Start: 90, End: 99},
   217  			},
   218  			size: 100,
   219  		},
   220  		{
   221  			name: "Fetch with end bigger than size",
   222  			in: []OpenOption{
   223  				&RangeOption{Start: 10, End: 200},
   224  			},
   225  			want: []OpenOption{
   226  				&RangeOption{Start: 10, End: 99},
   227  			},
   228  			size: 100,
   229  		},
   230  		{
   231  			name: "SeekOption",
   232  			in: []OpenOption{
   233  				&HTTPOption{Key: "a", Value: "1"},
   234  				&SeekOption{Offset: 10},
   235  				&HTTPOption{Key: "b", Value: "2"},
   236  			},
   237  			want: []OpenOption{
   238  				&HTTPOption{Key: "a", Value: "1"},
   239  				&RangeOption{Start: 10, End: 99},
   240  				&HTTPOption{Key: "b", Value: "2"},
   241  			},
   242  			size: 100,
   243  		},
   244  	} {
   245  		FixRangeOption(test.in, test.size)
   246  		assert.Equal(t, test.want, test.in, test.name)
   247  	}
   248  }
   249  
   250  var testOpenOptions = []OpenOption{
   251  	&HTTPOption{Key: "a", Value: "1"},
   252  	&RangeOption{Start: 1, End: 10},
   253  	&HTTPOption{Key: "b", Value: "2"},
   254  	NullOption{},
   255  	&HashesOption{hash.Set(hash.MD5 | hash.SHA1)},
   256  }
   257  
   258  func TestOpenOptionAddHeaders(t *testing.T) {
   259  	m := map[string]string{}
   260  	want := map[string]string{
   261  		"a":     "1",
   262  		"Range": "bytes=1-10",
   263  		"b":     "2",
   264  	}
   265  	OpenOptionAddHeaders(testOpenOptions, m)
   266  	assert.Equal(t, want, m)
   267  }
   268  
   269  func TestOpenOptionHeaders(t *testing.T) {
   270  	want := map[string]string{
   271  		"a":     "1",
   272  		"Range": "bytes=1-10",
   273  		"b":     "2",
   274  	}
   275  	m := OpenOptionHeaders(testOpenOptions)
   276  	assert.Equal(t, want, m)
   277  	assert.Nil(t, OpenOptionHeaders([]OpenOption{}))
   278  }
   279  
   280  func TestOpenOptionAddHTTPHeaders(t *testing.T) {
   281  	headers := http.Header{}
   282  	want := http.Header{
   283  		"A":     {"1"},
   284  		"Range": {"bytes=1-10"},
   285  		"B":     {"2"},
   286  	}
   287  	OpenOptionAddHTTPHeaders(headers, testOpenOptions)
   288  	assert.Equal(t, want, headers)
   289  
   290  }