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 }