github.com/cloudreve/Cloudreve/v3@v3.0.0-20240224133659-3edb00a6484c/pkg/request/request_test.go (about) 1 package request 2 3 import ( 4 "context" 5 "errors" 6 "github.com/cloudreve/Cloudreve/v3/pkg/cache" 7 "io" 8 "io/ioutil" 9 "net/http" 10 "strings" 11 "testing" 12 "time" 13 14 "github.com/cloudreve/Cloudreve/v3/pkg/auth" 15 "github.com/stretchr/testify/assert" 16 testMock "github.com/stretchr/testify/mock" 17 ) 18 19 type ClientMock struct { 20 testMock.Mock 21 } 22 23 func (m ClientMock) Request(method, target string, body io.Reader, opts ...Option) *Response { 24 args := m.Called(method, target, body, opts) 25 return args.Get(0).(*Response) 26 } 27 28 func TestWithTimeout(t *testing.T) { 29 asserts := assert.New(t) 30 options := newDefaultOption() 31 WithTimeout(time.Duration(5) * time.Second).apply(options) 32 asserts.Equal(time.Duration(5)*time.Second, options.timeout) 33 } 34 35 func TestWithHeader(t *testing.T) { 36 asserts := assert.New(t) 37 options := newDefaultOption() 38 WithHeader(map[string][]string{"Origin": []string{"123"}}).apply(options) 39 asserts.Equal(http.Header{"Origin": []string{"123"}}, options.header) 40 } 41 42 func TestWithContentLength(t *testing.T) { 43 asserts := assert.New(t) 44 options := newDefaultOption() 45 WithContentLength(10).apply(options) 46 asserts.EqualValues(10, options.contentLength) 47 } 48 49 func TestWithContext(t *testing.T) { 50 asserts := assert.New(t) 51 options := newDefaultOption() 52 WithContext(context.Background()).apply(options) 53 asserts.NotNil(options.ctx) 54 } 55 56 func TestHTTPClient_Request(t *testing.T) { 57 asserts := assert.New(t) 58 client := NewClient(WithSlaveMeta("test")) 59 60 // 正常 61 { 62 resp := client.Request( 63 "POST", 64 "/test", 65 strings.NewReader(""), 66 WithContentLength(0), 67 WithEndpoint("http://cloudreveisnotexist.com"), 68 WithTimeout(time.Duration(1)*time.Microsecond), 69 WithCredential(auth.HMACAuth{SecretKey: []byte("123")}, 10), 70 WithoutHeader([]string{"origin", "origin"}), 71 ) 72 asserts.Error(resp.Err) 73 asserts.Nil(resp.Response) 74 } 75 76 // 正常 带有ctx 77 { 78 resp := client.Request( 79 "GET", 80 "http://cloudreveisnotexist.com", 81 strings.NewReader(""), 82 WithTimeout(time.Duration(1)*time.Microsecond), 83 WithCredential(auth.HMACAuth{SecretKey: []byte("123")}, 10), 84 WithContext(context.Background()), 85 WithoutHeader([]string{"s s", "s s"}), 86 WithMasterMeta(), 87 ) 88 asserts.Error(resp.Err) 89 asserts.Nil(resp.Response) 90 } 91 92 } 93 94 func TestResponse_GetResponse(t *testing.T) { 95 asserts := assert.New(t) 96 97 // 直接返回错误 98 { 99 resp := Response{ 100 Err: errors.New("error"), 101 } 102 content, err := resp.GetResponse() 103 asserts.Empty(content) 104 asserts.Error(err) 105 } 106 107 // 正常 108 { 109 resp := Response{ 110 Response: &http.Response{Body: ioutil.NopCloser(strings.NewReader("123"))}, 111 } 112 content, err := resp.GetResponse() 113 asserts.Equal("123", content) 114 asserts.NoError(err) 115 } 116 } 117 118 func TestResponse_CheckHTTPResponse(t *testing.T) { 119 asserts := assert.New(t) 120 121 // 直接返回错误 122 { 123 resp := Response{ 124 Err: errors.New("error"), 125 } 126 res := resp.CheckHTTPResponse(200) 127 asserts.Error(res.Err) 128 } 129 130 // 404错误 131 { 132 resp := Response{ 133 Response: &http.Response{StatusCode: 404}, 134 } 135 res := resp.CheckHTTPResponse(200) 136 asserts.Error(res.Err) 137 } 138 139 // 通过 140 { 141 resp := Response{ 142 Response: &http.Response{StatusCode: 200}, 143 } 144 res := resp.CheckHTTPResponse(200) 145 asserts.NoError(res.Err) 146 } 147 } 148 149 func TestResponse_GetRSCloser(t *testing.T) { 150 asserts := assert.New(t) 151 152 // 直接返回错误 153 { 154 resp := Response{ 155 Err: errors.New("error"), 156 } 157 res, err := resp.GetRSCloser() 158 asserts.Error(err) 159 asserts.Nil(res) 160 } 161 162 // 正常 163 { 164 resp := Response{ 165 Response: &http.Response{ContentLength: 3, Body: ioutil.NopCloser(strings.NewReader("123"))}, 166 } 167 res, err := resp.GetRSCloser() 168 asserts.NoError(err) 169 content, err := ioutil.ReadAll(res) 170 asserts.NoError(err) 171 asserts.Equal("123", string(content)) 172 offset, err := res.Seek(0, 0) 173 asserts.NoError(err) 174 asserts.Equal(int64(0), offset) 175 offset, err = res.Seek(0, 2) 176 asserts.NoError(err) 177 asserts.Equal(int64(3), offset) 178 _, err = res.Seek(1, 2) 179 asserts.Error(err) 180 asserts.NoError(res.Close()) 181 } 182 183 } 184 185 func TestResponse_DecodeResponse(t *testing.T) { 186 asserts := assert.New(t) 187 188 // 直接返回错误 189 { 190 resp := Response{Err: errors.New("error")} 191 response, err := resp.DecodeResponse() 192 asserts.Error(err) 193 asserts.Nil(response) 194 } 195 196 // 无法解析响应 197 { 198 resp := Response{ 199 Response: &http.Response{ 200 Body: ioutil.NopCloser(strings.NewReader("test")), 201 }, 202 } 203 response, err := resp.DecodeResponse() 204 asserts.Error(err) 205 asserts.Nil(response) 206 } 207 208 // 成功 209 { 210 resp := Response{ 211 Response: &http.Response{ 212 Body: ioutil.NopCloser(strings.NewReader("{\"code\":0}")), 213 }, 214 } 215 response, err := resp.DecodeResponse() 216 asserts.NoError(err) 217 asserts.NotNil(response) 218 asserts.Equal(0, response.Code) 219 } 220 } 221 222 func TestNopRSCloser_SetFirstFakeChunk(t *testing.T) { 223 asserts := assert.New(t) 224 rsc := NopRSCloser{ 225 status: &rscStatus{}, 226 } 227 rsc.SetFirstFakeChunk() 228 asserts.True(rsc.status.IgnoreFirst) 229 230 rsc.SetContentLength(20) 231 asserts.EqualValues(20, rsc.status.Size) 232 } 233 234 func TestBlackHole(t *testing.T) { 235 a := assert.New(t) 236 cache.Set("setting_reset_after_upload_failed", "true", 0) 237 a.NotPanics(func() { 238 BlackHole(strings.NewReader("TestBlackHole")) 239 }) 240 } 241 242 func TestHTTPClient_TPSLimit(t *testing.T) { 243 a := assert.New(t) 244 client := NewClient() 245 246 finished := make(chan struct{}) 247 go func() { 248 client.Request( 249 "POST", 250 "/test", 251 strings.NewReader(""), 252 WithTPSLimit("TestHTTPClient_TPSLimit", 1, 1), 253 ) 254 close(finished) 255 }() 256 select { 257 case <-finished: 258 case <-time.After(10 * time.Second): 259 a.Fail("Request should be finished instantly.") 260 } 261 262 finished = make(chan struct{}) 263 go func() { 264 client.Request( 265 "POST", 266 "/test", 267 strings.NewReader(""), 268 WithTPSLimit("TestHTTPClient_TPSLimit", 1, 1), 269 ) 270 close(finished) 271 }() 272 select { 273 case <-finished: 274 case <-time.After(2 * time.Second): 275 a.Fail("Request should be finished in 1 second.") 276 } 277 278 }