cubefs

Форк
0
/
argument_test.go 
410 строк · 10.2 Кб
1
// Copyright 2022 The CubeFS Authors.
2
//
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
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
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.
14

15
package rpc
16

17
import (
18
	"encoding/base64"
19
	"io"
20
	"net/http"
21
	"strconv"
22
	"strings"
23
	"testing"
24

25
	"github.com/julienschmidt/httprouter"
26
	"github.com/stretchr/testify/require"
27

28
	"github.com/cubefs/cubefs/blobstore/util/log"
29
)
30

31
func TestArgumentRegister(t *testing.T) {
32
	log.SetOutputLevel(log.Linfo)
33
	defer setLogLevel()
34
	defer func() {
35
		registeredParsers = make(map[parserKey]parserVal)
36
	}()
37
	{
38
		RegisterArgsParser(nil)
39
		RegisterArgsParser(struct{ Parser }{})
40
	}
41
	{
42
		type args struct{}
43
		require.Panics(t, func() {
44
			RegisterArgsParser(args{})
45
		})
46
		require.Panics(t, func() {
47
			RegisterArgsParser(make(map[int]int))
48
		})
49
		require.Panics(t, func() {
50
			var i int
51
			RegisterArgsParser(&i)
52
		})
53
		RegisterArgsParser(&args{})
54
	}
55
	{
56
		type Args struct {
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"`
61
			F5 string
62
			F6 string `taglv3:"-"`
63
		}
64
		RegisterArgsParser(&Args{}, "taglv3", "taglv2", "taglv1")
65

66
		byteVal := base64.URLEncoding.EncodeToString([]byte("f4-1"))
67
		args := new(Args)
68
		c := new(Context)
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"},
79
		}
80
		parseArgs(c, args, OptArgsURI())
81

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)
88
	}
89
}
90

91
func TestArgumentBase64(t *testing.T) {
92
	log.SetOutputLevel(log.Linfo)
93
	defer setLogLevel()
94
	defer func() {
95
		registeredParsers = make(map[parserKey]parserVal)
96
	}()
97
	type Args struct {
98
		Base64 []byte `tag:"base64,base64"`
99
	}
100
	RegisterArgsParser(&Args{}, "tag")
101

102
	// "ZjQtMQ==" == []byte("f4-1")
103
	cases := []struct {
104
		hasErr bool
105
		val    string
106
	}{
107
		{false, "ZjQtMQ=="},
108
		{false, "ZjQtMQ="},
109
		{false, "ZjQtMQ"},
110
		{true, "ZjQtM==="},
111
		{true, "ZjQtM"},
112
	}
113
	for _, cs := range cases {
114
		args := new(Args)
115
		c := new(Context)
116
		c.opts = new(serverOptions)
117
		c.Param = httprouter.Params{
118
			httprouter.Param{Key: "base64", Value: cs.val},
119
		}
120
		err := parseArgs(c, args, OptArgsURI())
121
		if cs.hasErr {
122
			require.Error(t, err)
123
		} else {
124
			require.Equal(t, []byte("f4-1"), args.Base64)
125
			require.NoError(t, err)
126
		}
127
	}
128
}
129

130
type unmarshalerArgs struct {
131
	I int
132
}
133

134
func (args *unmarshalerArgs) Unmarshal([]byte) error {
135
	args.I = 111
136
	return nil
137
}
138

139
type unmarshalerFromArgs struct {
140
	IFrom int
141
}
142

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)
147
	if err != nil {
148
		return err
149
	}
150

151
	arg, err := strconv.Atoi(string(buf))
152
	if err != nil {
153
		return err
154
	}
155
	args.IFrom = arg
156
	return nil
157
}
158

159
type normalArgs struct {
160
	Bool bool
161

162
	Int   int
163
	Int8  int8
164
	Int16 int16
165
	Int32 int32
166
	Int64 int64
167

168
	Uint   uint
169
	Uint8  uint8
170
	Uint16 uint16
171
	Uint32 uint32
172
	Uint64 uint64
173

174
	Float32 float32
175
	Float64 float64
176

177
	String  string
178
	Uintptr uintptr
179
	Ptr     *string
180

181
	Slice []byte
182
}
183

184
type parserArgs struct {
185
	getter string
186
	normalArgs
187
}
188

189
func (args *parserArgs) Parse(getter ValueGetter) error {
190
	args.getter = "getter"
191
	return nil
192
}
193

194
func TestArgumentParser(t *testing.T) {
195
	{
196
		err := parseArgs(nil, nil)
197
		require.NoError(t, err)
198

199
		c := new(Context)
200
		c.opts = new(serverOptions)
201
		err = parseArgs(c, struct{}{}, OptArgsURI())
202
		require.Error(t, err)
203
		var i int
204
		err = parseArgs(c, &i, OptArgsURI())
205
		require.Error(t, err)
206

207
		args := new(unmarshalerArgs)
208
		err = parseArgs(c, args, OptArgsURI())
209
		require.Error(t, err)
210
	}
211
	{
212
		c := new(Context)
213
		c.opts = new(serverOptions)
214
		c.Param = httprouter.Params{
215
			httprouter.Param{Key: "slice", Value: "[]"},
216
			httprouter.Param{Key: "map", Value: "{}"},
217
		}
218

219
		args := struct {
220
			Slice []string
221
		}{}
222
		err := parseArgs(c, &args, OptArgsURI())
223
		require.Error(t, err)
224

225
		argsx := struct {
226
			Map map[int]string
227
		}{}
228
		err = parseArgs(c, &argsx, OptArgsURI())
229
		require.Error(t, err)
230
	}
231
	{
232
		c := new(Context)
233
		c.opts = new(serverOptions)
234
		c.Request, _ = http.NewRequest("", "", nil)
235

236
		args := new(unmarshalerArgs)
237
		err := parseArgs(c, args, OptArgsBody())
238
		require.NoError(t, err)
239
		require.Equal(t, 111, args.I)
240

241
		args = new(unmarshalerArgs)
242
		err = parseArgs(c, args)
243
		require.NoError(t, err)
244
		require.Equal(t, 0, args.I)
245
	}
246
	{
247
		c := new(Context)
248
		c.opts = new(serverOptions)
249
		{
250
			c.Request, _ = http.NewRequest("", "", strings.NewReader(""))
251
			args := new(unmarshalerFromArgs)
252
			err := parseArgs(c, args, OptArgsBody())
253
			require.Error(t, err)
254
		}
255
		{
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)
261
		}
262
		{
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)
268
		}
269
	}
270
	{
271
		c := new(Context)
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"},
291
		}
292

293
		args := new(normalArgs)
294
		err := parseArgs(c, args, OptArgsURI())
295
		require.NoError(t, err)
296

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)
314
	}
315
	{
316
		c := new(Context)
317
		c.opts = new(serverOptions)
318
		c.Param = httprouter.Params{
319
			httprouter.Param{Key: "bool", Value: "true"},
320
		}
321

322
		args := new(parserArgs)
323
		err := parseArgs(c, args, OptArgsURI())
324
		require.NoError(t, err)
325

326
		require.False(t, args.Bool)
327
		require.Equal(t, "getter", args.getter)
328
	}
329
}
330

331
func BenchmarkArgumentParse(b *testing.B) {
332
	b.Run("ArgsBodyJson", func(b *testing.B) {
333
		type jsonArgs struct {
334
			I int
335
		}
336
		c := new(Context)
337
		c.opts = new(serverOptions)
338
		c.Request, _ = http.NewRequest("", "", nil)
339
		b.ResetTimer()
340
		for ii := 0; ii <= b.N; ii++ {
341
			args := new(jsonArgs)
342
			parseArgs(c, args, OptArgsBody())
343
		}
344
	})
345
	b.Run("ArgsBodyMarshaler", func(b *testing.B) {
346
		c := new(Context)
347
		c.opts = new(serverOptions)
348
		c.Request, _ = http.NewRequest("", "", nil)
349
		b.ResetTimer()
350
		for ii := 0; ii <= b.N; ii++ {
351
			args := new(unmarshalerArgs)
352
			parseArgs(c, args, OptArgsBody())
353
		}
354
	})
355
	b.Run("ArgsURISimple", func(b *testing.B) {
356
		type simpleURI struct {
357
			Bool bool
358
		}
359
		c := new(Context)
360
		c.opts = new(serverOptions)
361
		c.Param = httprouter.Params{
362
			httprouter.Param{Key: "bool", Value: "true"},
363
		}
364
		b.ResetTimer()
365
		for ii := 0; ii <= b.N; ii++ {
366
			args := new(simpleURI)
367
			parseArgs(c, args, OptArgsURI())
368
		}
369
	})
370
	b.Run("ArgsURIComplex", func(b *testing.B) {
371
		c := new(Context)
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"},
391
		}
392
		b.ResetTimer()
393
		for ii := 0; ii <= b.N; ii++ {
394
			args := new(normalArgs)
395
			parseArgs(c, args, OptArgsURI())
396
		}
397
	})
398
	b.Run("ArgsURIParser", func(b *testing.B) {
399
		c := new(Context)
400
		c.opts = new(serverOptions)
401
		c.Param = httprouter.Params{
402
			httprouter.Param{Key: "bool", Value: "true"},
403
		}
404
		b.ResetTimer()
405
		for ii := 0; ii <= b.N; ii++ {
406
			args := new(parserArgs)
407
			parseArgs(c, args, OptArgsURI())
408
		}
409
	})
410
}
411

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.