1
// Copyright 2022 The CubeFS Authors.
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
7
// http://www.apache.org/licenses/LICENSE-2.0
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12
// implied. See the License for the specific language governing
13
// permissions and limitations under the License.
25
"github.com/julienschmidt/httprouter"
26
"github.com/stretchr/testify/require"
28
"github.com/cubefs/cubefs/blobstore/util/log"
31
func TestArgumentRegister(t *testing.T) {
32
log.SetOutputLevel(log.Linfo)
35
registeredParsers = make(map[parserKey]parserVal)
38
RegisterArgsParser(nil)
39
RegisterArgsParser(struct{ Parser }{})
43
require.Panics(t, func() {
44
RegisterArgsParser(args{})
46
require.Panics(t, func() {
47
RegisterArgsParser(make(map[int]int))
49
require.Panics(t, func() {
51
RegisterArgsParser(&i)
53
RegisterArgsParser(&args{})
57
F1 string `taglv3:"f1-3" taglv2:"f1-2" taglv1:"f1-1"`
58
F2 string `taglv2:"f2-2" taglv1:"f2-1"`
59
F3 string `taglv1:"f3-1,omitempty"`
60
F4 []byte `taglv1:"f4-1,base64"`
62
F6 string `taglv3:"-"`
64
RegisterArgsParser(&Args{}, "taglv3", "taglv2", "taglv1")
66
byteVal := base64.URLEncoding.EncodeToString([]byte("f4-1"))
69
c.opts = new(serverOptions)
70
c.Param = httprouter.Params{
71
httprouter.Param{Key: "f1-3", Value: "f1-3"},
72
httprouter.Param{Key: "f1-2", Value: "f1-2"},
73
httprouter.Param{Key: "f1-1", Value: "f1-1"},
74
httprouter.Param{Key: "f2-2", Value: "f2-2"},
75
httprouter.Param{Key: "f2-1", Value: "f2-1"},
76
httprouter.Param{Key: "f4-1", Value: byteVal},
77
httprouter.Param{Key: "f5", Value: "f5"},
78
httprouter.Param{Key: "f6", Value: "f6"},
80
parseArgs(c, args, OptArgsURI())
82
require.Equal(t, "f1-3", args.F1)
83
require.Equal(t, "f2-2", args.F2)
84
require.Equal(t, "", args.F3)
85
require.Equal(t, []byte("f4-1"), args.F4)
86
require.Equal(t, "f5", args.F5)
87
require.Equal(t, "", args.F6)
91
func TestArgumentBase64(t *testing.T) {
92
log.SetOutputLevel(log.Linfo)
95
registeredParsers = make(map[parserKey]parserVal)
98
Base64 []byte `tag:"base64,base64"`
100
RegisterArgsParser(&Args{}, "tag")
102
// "ZjQtMQ==" == []byte("f4-1")
113
for _, cs := range cases {
116
c.opts = new(serverOptions)
117
c.Param = httprouter.Params{
118
httprouter.Param{Key: "base64", Value: cs.val},
120
err := parseArgs(c, args, OptArgsURI())
122
require.Error(t, err)
124
require.Equal(t, []byte("f4-1"), args.Base64)
125
require.NoError(t, err)
130
type unmarshalerArgs struct {
134
func (args *unmarshalerArgs) Unmarshal([]byte) error {
139
type unmarshalerFromArgs struct {
143
func (args *unmarshalerFromArgs) UnmarshalFrom(body io.Reader) error {
144
r := body.(*io.LimitedReader)
145
buf := make([]byte, r.N)
146
_, err := io.ReadFull(r, buf)
151
arg, err := strconv.Atoi(string(buf))
159
type normalArgs struct {
184
type parserArgs struct {
189
func (args *parserArgs) Parse(getter ValueGetter) error {
190
args.getter = "getter"
194
func TestArgumentParser(t *testing.T) {
196
err := parseArgs(nil, nil)
197
require.NoError(t, err)
200
c.opts = new(serverOptions)
201
err = parseArgs(c, struct{}{}, OptArgsURI())
202
require.Error(t, err)
204
err = parseArgs(c, &i, OptArgsURI())
205
require.Error(t, err)
207
args := new(unmarshalerArgs)
208
err = parseArgs(c, args, OptArgsURI())
209
require.Error(t, err)
213
c.opts = new(serverOptions)
214
c.Param = httprouter.Params{
215
httprouter.Param{Key: "slice", Value: "[]"},
216
httprouter.Param{Key: "map", Value: "{}"},
222
err := parseArgs(c, &args, OptArgsURI())
223
require.Error(t, err)
228
err = parseArgs(c, &argsx, OptArgsURI())
229
require.Error(t, err)
233
c.opts = new(serverOptions)
234
c.Request, _ = http.NewRequest("", "", nil)
236
args := new(unmarshalerArgs)
237
err := parseArgs(c, args, OptArgsBody())
238
require.NoError(t, err)
239
require.Equal(t, 111, args.I)
241
args = new(unmarshalerArgs)
242
err = parseArgs(c, args)
243
require.NoError(t, err)
244
require.Equal(t, 0, args.I)
248
c.opts = new(serverOptions)
250
c.Request, _ = http.NewRequest("", "", strings.NewReader(""))
251
args := new(unmarshalerFromArgs)
252
err := parseArgs(c, args, OptArgsBody())
253
require.Error(t, err)
256
c.Request, _ = http.NewRequest("", "", strings.NewReader("999"))
257
args := new(unmarshalerFromArgs)
258
err := parseArgs(c, args, OptArgsBody())
259
require.NoError(t, err)
260
require.Equal(t, 999, args.IFrom)
263
c.Request, _ = http.NewRequest("", "", strings.NewReader("not-a-number"))
264
args := new(unmarshalerFromArgs)
265
err := parseArgs(c, args, OptArgsBody())
266
require.Error(t, err)
267
require.Equal(t, 0, args.IFrom)
272
c.opts = new(serverOptions)
273
c.Param = httprouter.Params{
274
httprouter.Param{Key: "bool", Value: "true"},
275
httprouter.Param{Key: "int", Value: "-1111"},
276
httprouter.Param{Key: "int8", Value: "-1"},
277
httprouter.Param{Key: "int16", Value: "-1111"},
278
httprouter.Param{Key: "int32", Value: "-1111"},
279
httprouter.Param{Key: "int64", Value: "-1111"},
280
httprouter.Param{Key: "uint", Value: "1111"},
281
httprouter.Param{Key: "uint8", Value: "1"},
282
httprouter.Param{Key: "uint16", Value: "1111"},
283
httprouter.Param{Key: "uint32", Value: "1111"},
284
httprouter.Param{Key: "uint64", Value: "1111"},
285
httprouter.Param{Key: "float32", Value: "1e-3"},
286
httprouter.Param{Key: "float64", Value: "1e-32"},
287
httprouter.Param{Key: "string", Value: "string"},
288
httprouter.Param{Key: "uintptr", Value: "1111"},
289
httprouter.Param{Key: "ptr", Value: "string"},
290
httprouter.Param{Key: "slice", Value: "slice"},
293
args := new(normalArgs)
294
err := parseArgs(c, args, OptArgsURI())
295
require.NoError(t, err)
297
require.True(t, args.Bool)
298
require.Equal(t, -1111, args.Int)
299
require.Equal(t, int8(-1), args.Int8)
300
require.Equal(t, int16(-1111), args.Int16)
301
require.Equal(t, int32(-1111), args.Int32)
302
require.Equal(t, int64(-1111), args.Int64)
303
require.Equal(t, uint(1111), args.Uint)
304
require.Equal(t, uint8(1), args.Uint8)
305
require.Equal(t, uint16(1111), args.Uint16)
306
require.Equal(t, uint32(1111), args.Uint32)
307
require.Equal(t, uint64(1111), args.Uint64)
308
require.Equal(t, float32(0.001), args.Float32)
309
require.Equal(t, float64(1e-32), args.Float64)
310
require.Equal(t, "string", args.String)
311
require.Equal(t, uintptr(1111), args.Uintptr)
312
require.Equal(t, "string", *args.Ptr)
313
require.Equal(t, []byte("slice"), args.Slice)
317
c.opts = new(serverOptions)
318
c.Param = httprouter.Params{
319
httprouter.Param{Key: "bool", Value: "true"},
322
args := new(parserArgs)
323
err := parseArgs(c, args, OptArgsURI())
324
require.NoError(t, err)
326
require.False(t, args.Bool)
327
require.Equal(t, "getter", args.getter)
331
func BenchmarkArgumentParse(b *testing.B) {
332
b.Run("ArgsBodyJson", func(b *testing.B) {
333
type jsonArgs struct {
337
c.opts = new(serverOptions)
338
c.Request, _ = http.NewRequest("", "", nil)
340
for ii := 0; ii <= b.N; ii++ {
341
args := new(jsonArgs)
342
parseArgs(c, args, OptArgsBody())
345
b.Run("ArgsBodyMarshaler", func(b *testing.B) {
347
c.opts = new(serverOptions)
348
c.Request, _ = http.NewRequest("", "", nil)
350
for ii := 0; ii <= b.N; ii++ {
351
args := new(unmarshalerArgs)
352
parseArgs(c, args, OptArgsBody())
355
b.Run("ArgsURISimple", func(b *testing.B) {
356
type simpleURI struct {
360
c.opts = new(serverOptions)
361
c.Param = httprouter.Params{
362
httprouter.Param{Key: "bool", Value: "true"},
365
for ii := 0; ii <= b.N; ii++ {
366
args := new(simpleURI)
367
parseArgs(c, args, OptArgsURI())
370
b.Run("ArgsURIComplex", func(b *testing.B) {
372
c.opts = new(serverOptions)
373
c.Param = httprouter.Params{
374
httprouter.Param{Key: "bool", Value: "true"},
375
httprouter.Param{Key: "int", Value: "-1111"},
376
httprouter.Param{Key: "int8", Value: "-1"},
377
httprouter.Param{Key: "int16", Value: "-1111"},
378
httprouter.Param{Key: "int32", Value: "-1111"},
379
httprouter.Param{Key: "int64", Value: "-1111"},
380
httprouter.Param{Key: "uint", Value: "1111"},
381
httprouter.Param{Key: "uint8", Value: "1"},
382
httprouter.Param{Key: "uint16", Value: "1111"},
383
httprouter.Param{Key: "uint32", Value: "1111"},
384
httprouter.Param{Key: "uint64", Value: "1111"},
385
httprouter.Param{Key: "float32", Value: "1e-3"},
386
httprouter.Param{Key: "float64", Value: "1e-32"},
387
httprouter.Param{Key: "string", Value: "string"},
388
httprouter.Param{Key: "uintptr", Value: "1111"},
389
httprouter.Param{Key: "ptr", Value: "string"},
390
httprouter.Param{Key: "slice", Value: "slice"},
393
for ii := 0; ii <= b.N; ii++ {
394
args := new(normalArgs)
395
parseArgs(c, args, OptArgsURI())
398
b.Run("ArgsURIParser", func(b *testing.B) {
400
c.opts = new(serverOptions)
401
c.Param = httprouter.Params{
402
httprouter.Param{Key: "bool", Value: "true"},
405
for ii := 0; ii <= b.N; ii++ {
406
args := new(parserArgs)
407
parseArgs(c, args, OptArgsURI())