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.
26
"github.com/stretchr/testify/require"
28
"github.com/cubefs/cubefs/blobstore/common/crc32block"
29
"github.com/cubefs/cubefs/blobstore/common/rpc/auth"
33
testServer *httptest.Server
39
func (s *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
40
uri := r.URL.RequestURI()
43
b, err := ioutil.ReadAll(r.Body)
44
if err != nil || int64(len(b)) != r.ContentLength || first {
45
ReplyErr(w, 500, "test retry")
51
w.Header().Set(HeaderAckCrcEncoded, "1")
58
ReplyWith(w, 404, "", []byte("404 page not found"))
61
marshal, err := json.Marshal(ret{Name: "Test_GetWith"})
70
type testTimeoutReader struct{}
72
func (t *testTimeoutReader) Read(p []byte) (n int, err error) {
73
time.Sleep(time.Millisecond * 20)
77
func doAfterCrc(w http.ResponseWriter, req *http.Request) {
78
dec := crc32block.NewBodyDecoder(req.Body)
80
dataByte := make([]byte, 1024)
81
read, err := dec.Read(dataByte)
82
w.Header().Set(HeaderAckCrcEncoded, "1")
86
w.Write(dataByte[:read])
89
func callWithJSON(w http.ResponseWriter, req *http.Request) {
91
err := json.NewDecoder(req.Body).Decode(r)
93
w.WriteHeader(http.StatusBadRequest)
96
r.Name = r.Name + "+Test"
97
marshal, err := json.Marshal(r)
99
w.WriteHeader(http.StatusGatewayTimeout)
105
func timeout(w http.ResponseWriter, req *http.Request) {
107
err := json.NewDecoder(req.Body).Decode(r)
111
for i := 0; i < 10*1024*1024*1024; i++ {
112
w.Write([]byte("time out"))
116
var simpleCfg = &Config{
117
ClientTimeoutMs: 10000,
120
ResponseHeaderTimeoutMs: 3000,
121
MaxConnsPerHost: 100,
123
MaxIdleConnsPerHost: 10,
124
IdleConnTimeoutMs: 60000,
125
DisableCompression: true,
132
var simpleClient = NewClient(simpleCfg)
135
testServer = httptest.NewServer(&handler{})
138
func TestClient_NewClient(t *testing.T) {
143
require.Equal(t, 10, cfg.Tc.MaxConnsPerHost)
144
require.Equal(t, int64(0), cfg.Tc.DialTimeoutMs)
145
require.False(t, cfg.Tc.Auth.EnableAuth)
149
cfg.Tc.Auth.EnableAuth = true
150
cfg.Tc.Auth.Secret = "true"
152
require.Equal(t, 10, cfg.Tc.MaxConnsPerHost)
153
require.Equal(t, int64(0), cfg.Tc.DialTimeoutMs)
154
require.True(t, cfg.Tc.Auth.EnableAuth)
155
require.Equal(t, "true", cfg.Tc.Auth.Secret)
159
cfg.Tc.MaxConnsPerHost = 4
161
require.Equal(t, 4, cfg.Tc.MaxConnsPerHost)
162
require.Equal(t, 0, cfg.Tc.MaxIdleConnsPerHost)
163
require.Equal(t, int64(0), cfg.Tc.DialTimeoutMs)
164
require.False(t, cfg.Tc.Auth.EnableAuth)
168
func TestClient_GetWith(t *testing.T) {
169
ctx := context.Background()
171
err := simpleClient.GetWith(ctx, testServer.URL, result)
172
require.NoError(t, err)
173
require.NotNil(t, result)
176
func TestClient_PostWithCrc(t *testing.T) {
177
ctx := context.Background()
179
err := simpleClient.PostWith(ctx, testServer.URL+"/crc", result,
180
&ret{Name: "TestClient_PostWithCrc"}, WithCrcEncode())
181
require.NoError(t, err)
182
require.NotNil(t, result)
183
require.Equal(t, "TestClient_PostWithCrc", result.Name)
186
func TestClient_PostWithNoCrc(t *testing.T) {
187
ctx := context.Background()
189
err := simpleClient.PostWith(ctx, testServer.URL+"/json", result, &ret{Name: "TestClient_PostWithNoCrc"})
190
require.NoError(t, err)
191
require.NotNil(t, result)
192
require.Equal(t, "TestClient_PostWithNoCrc+Test", result.Name)
195
func TestClient_PostWithNoneBody(t *testing.T) {
196
ctx := context.Background()
197
err := simpleClient.PostWith(ctx, testServer.URL+"/json", nil, NoneBody)
198
require.Equal(t, DetectStatusCode(err), http.StatusBadRequest)
201
func TestClient_Delete(t *testing.T) {
202
ctx := context.Background()
203
resp, err := simpleClient.Delete(ctx, testServer.URL)
204
require.NoError(t, err)
206
require.Equal(t, http.StatusOK, resp.StatusCode)
209
func TestClient_PutWithNoCrc(t *testing.T) {
210
ctx := context.Background()
212
err := simpleClient.PutWith(ctx, testServer.URL+"/json", result, &ret{Name: "TestClient_PutWithNoCrc"})
213
require.NoError(t, err)
214
require.NotNil(t, result)
215
require.Equal(t, "TestClient_PutWithNoCrc+Test", result.Name)
218
func TestClient_PutWithCrc(t *testing.T) {
219
ctx := context.Background()
221
err := simpleClient.PostWith(ctx, testServer.URL+"/crc", result,
222
&ret{Name: "TestClient_PutWithCrc"}, WithCrcEncode())
223
require.NoError(t, err)
224
require.NotNil(t, result)
225
require.Equal(t, "TestClient_PutWithCrc", result.Name)
228
func TestClient_Post(t *testing.T) {
229
ctx := context.Background()
231
resp, err := simpleClient.Post(ctx, testServer.URL+"/json", &ret{Name: "TestClient_Post"})
232
require.NoError(t, err)
233
err = parseData(resp, result)
234
require.NoError(t, err)
235
require.NotNil(t, result)
236
require.Equal(t, "TestClient_Post+Test", result.Name)
239
func TestClient_PostWithReadResponseTimeout(t *testing.T) {
240
simpleCfg.BodyBaseTimeoutMs = 50
241
simpleCfg.BodyBandwidthMBPs = 1
242
simpleCli := NewClient(simpleCfg)
243
ctx := context.Background()
244
resp, err := simpleCli.Post(ctx, testServer.URL+"/timeout", &ret{Name: "TestClient_Post"})
245
require.NoError(t, err)
246
defer resp.Body.Close()
247
cache := make([]byte, 128)
248
_, err = resp.Body.Read(cache)
250
_, err = resp.Body.Read(cache)
252
require.Equal(t, ErrBodyReadTimeout, err)
255
func TestTimeoutReadCloser_Read(t *testing.T) {
256
// test for read data for input buffer timeout
257
readCloser := timeoutReadCloser{
259
body: ioutil.NopCloser(&testTimeoutReader{}),
261
res := make([]byte, 30)
262
_, err := readCloser.Read(res)
263
require.Equal(t, ErrBodyReadTimeout, err)
266
func TestClient_Put(t *testing.T) {
267
ctx := context.Background()
269
resp, err := simpleClient.Put(ctx, testServer.URL+"/json", &ret{Name: "TestClient_Put"})
270
require.NoError(t, err)
271
err = parseData(resp, result)
272
require.NoError(t, err)
273
require.NotNil(t, result)
274
require.Equal(t, "TestClient_Put+Test", result.Name)
277
func TestClient_Close(t *testing.T) {
281
func TestClient_Head(t *testing.T) {
282
ctx := context.Background()
283
resp, err := simpleClient.Head(ctx, testServer.URL)
284
require.NoError(t, err)
286
require.Equal(t, http.StatusOK, resp.StatusCode)
289
func TestClient_DoWithNoCrc(t *testing.T) {
290
ctx := context.Background()
292
request, err := http.NewRequest(http.MethodPost, testServer.URL, nil)
293
require.NoError(t, err)
294
err = simpleClient.DoWith(ctx, request, result)
295
require.NoError(t, err)
296
require.NotNil(t, result)
299
func TestClient_DoWithCrc(t *testing.T) {
300
ctx := context.Background()
302
request, err := http.NewRequest(http.MethodPost, testServer.URL+"/crc", nil)
303
require.NoError(t, err)
304
err = simpleClient.DoWith(ctx, request, result, WithCrcEncode())
305
require.NoError(t, err)
306
require.NotNil(t, result)
309
func TestClient_Form(t *testing.T) {
310
m := make(map[string][]string)
311
m["test"] = []string{"test_lb_Form"}
312
ctx := context.Background()
313
resp, err := simpleClient.Form(ctx, http.MethodPost, testServer.URL, m)
314
require.NoError(t, err)
316
require.Equal(t, http.StatusOK, resp.StatusCode)
319
func TestClient_ParseDataWithContentLengthZero(t *testing.T) {
320
m := make(map[string][]string)
321
m["test"] = []string{"yest_lb_Form"}
322
ctx := context.Background()
324
resp, err := simpleClient.Form(ctx, http.MethodPost, testServer.URL, m)
325
require.NoError(t, err)
326
resp.StatusCode = 400
327
resp.ContentLength = 0
328
err = parseData(resp, result)
329
require.Error(t, err)
332
func TestClient_ParseData(t *testing.T) {
333
m := make(map[string][]string)
334
m["test"] = []string{"yest_lb_Form"}
335
ctx := context.Background()
337
resp, err := simpleClient.Form(ctx, http.MethodPost, testServer.URL, m)
338
require.NoError(t, err)
339
resp.StatusCode = 400
340
resp.ContentLength = 12
341
err = parseData(resp, result)
342
require.Error(t, err)
345
func TestClient_DoContextCancel(t *testing.T) {
346
ctx := context.Background()
348
cancel, cancelFunc := context.WithCancel(ctx)
349
request, err := http.NewRequest(http.MethodPost, testServer.URL, nil)
350
require.NoError(t, err)
352
err = simpleClient.DoWith(cancel, request, result)
353
require.Error(t, err)
356
func TestClient_ResponseClose(t *testing.T) {
357
ctx := context.Background()
359
resp, err := simpleClient.Post(ctx, testServer.URL+"/json",
360
&ret{Name: "TestClient_ResponseClose"})
361
require.NoError(t, err)
363
err = parseData(resp, result)
364
require.Error(t, err)
367
func TestClient_PostWithOnServerNotAck(t *testing.T) {
368
request, err := http.NewRequest(http.MethodPost, testServer.URL, nil)
369
require.NoError(t, err)
370
request.Header.Set(HeaderCrcEncoded, "1")
371
response, err := simpleClient.Do(context.Background(), request)
372
require.NoError(t, err)
373
err = serverCrcEncodeCheck(context.Background(), request, response)
374
response.Body.Close()
375
require.NotNil(t, err)
378
func TestClient_PageNotFound(t *testing.T) {
379
ctx := context.Background()
381
err := simpleClient.GetWith(ctx, testServer.URL+"/notfound", result)
382
require.Error(t, err)
383
require.Equal(t, "", result.Name)