github.com/swiftstack/ProxyFS@v0.0.0-20210203235616-4017c267d62f/pfsagentd/unit_test.go (about) 1 // Copyright (c) 2015-2021, NVIDIA CORPORATION. 2 // SPDX-License-Identifier: Apache-2.0 3 4 package main 5 6 import ( 7 "bytes" 8 "encoding/json" 9 "fmt" 10 "io/ioutil" 11 "net/http" 12 "strings" 13 "testing" 14 "time" 15 16 "github.com/swiftstack/ProxyFS/jrpcfs" 17 ) 18 19 const ( 20 testMaxAccountNameLength = 256 21 testMaxContainerNameLength = 512 22 testMaxObjectNameLength = 1024 23 testAccountListingLimit = 10000 24 testContainerListingLimit = 20000 25 ) 26 27 type testSwiftInfoInnerStruct struct { 28 MaxAccountNameLength uint64 `json:"max_account_name_length"` 29 MaxContainerNameLength uint64 `json:"max_container_name_length"` 30 MaxObjectNameLength uint64 `json:"max_object_name_length"` 31 AccountListingLimit uint64 `json:"account_listing_limit"` 32 ContainerListingLimit uint64 `json:"container_listing_limit"` 33 } 34 35 type testSwiftInfoOuterStruct struct { 36 Swift testSwiftInfoInnerStruct `json:"swift"` 37 } 38 39 func TestJRPCRequest(t *testing.T) { 40 var ( 41 err error 42 pingReply *jrpcfs.PingReply 43 pingReq *jrpcfs.PingReq 44 ) 45 46 testSetup(t) 47 48 pingReq = &jrpcfs.PingReq{ 49 Message: "TestMessage", 50 } 51 52 pingReply = &jrpcfs.PingReply{} 53 54 err = doJRPCRequest("Server.RpcPing", pingReq, pingReply) 55 56 if nil != err { 57 t.Fatalf("doJRPCRequest(\"Server.RpcPing\",,) failed: %v", err) 58 } 59 if fmt.Sprintf("pong %d bytes", len("TestMessage")) != pingReply.Message { 60 t.Fatalf("doJRPCRequest(\"Server.RpcPing\",,) returned unexpected response: %s", pingReply.Message) 61 } 62 63 testTeardown(t) 64 } 65 66 func TestSwiftProxyEmulation(t *testing.T) { 67 var ( 68 authRequest *http.Request 69 authResponse *http.Response 70 authURL string 71 err error 72 getBuf []byte 73 getObjectRequest *http.Request 74 getObjectResponse *http.Response 75 infoBuf []byte 76 infoResponse *http.Response 77 infoURL string 78 pingReq *jrpcfs.PingReq 79 pingReqBuf []byte 80 pingReqMessageID uint64 81 pingRequest *http.Request 82 pingReply *jrpcfs.PingReply 83 pingReplyBuf []byte 84 pingReplyMessageID uint64 85 pingResponse *http.Response 86 putContainerRequest *http.Request 87 putContainerResponse *http.Response 88 putObjectRequest *http.Request 89 putObjectResponse *http.Response 90 responseErr error 91 swiftAccountURLSplit []string 92 swiftInfo *testSwiftInfoOuterStruct 93 unmarshalErr error 94 ) 95 96 testSetup(t) 97 98 for { 99 swiftAccountURLSplit = strings.Split(globals.swiftStorageURL, "/") 100 if len(swiftAccountURLSplit) >= 3 { 101 infoURL = strings.Join(append(strings.Split(globals.swiftStorageURL, "/")[:3], "info"), "/") 102 break 103 } 104 time.Sleep(100 * time.Millisecond) 105 } 106 107 infoResponse, err = http.Get(infoURL) 108 if nil != err { 109 t.Fatalf("GET /info failed: %v", err) 110 } 111 if http.StatusOK != infoResponse.StatusCode { 112 t.Fatalf("GET /info returned bad status: %v", infoResponse.Status) 113 } 114 115 infoBuf, err = ioutil.ReadAll(infoResponse.Body) 116 if nil != err { 117 t.Fatalf("GET /info returned unreadable Body: %v", err) 118 } 119 120 err = infoResponse.Body.Close() 121 if nil != err { 122 t.Fatalf("GET /info returned uncloseable Body: %v", err) 123 } 124 125 swiftInfo = &testSwiftInfoOuterStruct{} 126 127 err = json.Unmarshal(infoBuf, swiftInfo) 128 if nil != err { 129 t.Fatalf("GET /info returned unparseable Body: %v", err) 130 } 131 132 if (testMaxAccountNameLength != swiftInfo.Swift.MaxAccountNameLength) || 133 (testMaxContainerNameLength != swiftInfo.Swift.MaxContainerNameLength) || 134 (testMaxObjectNameLength != swiftInfo.Swift.MaxObjectNameLength) || 135 (testAccountListingLimit != swiftInfo.Swift.AccountListingLimit) || 136 (testContainerListingLimit != swiftInfo.Swift.ContainerListingLimit) { 137 t.Fatalf("GET /info returned unexpected swiftInfo") 138 } 139 140 authURL = strings.Join(append(strings.Split(globals.swiftStorageURL, "/")[:3], "auth", "v1.0"), "/") 141 142 authRequest, err = http.NewRequest("GET", authURL, nil) 143 if nil != err { 144 t.Fatalf("Creating GET /auth/v1.0 http.Request failed: %v", err) 145 } 146 147 authRequest.Header.Add("X-Auth-User", testAuthUser) 148 authRequest.Header.Add("X-Auth-Key", testAuthKey) 149 150 authResponse, err = testSwiftProxyEmulatorGlobals.httpClient.Do(authRequest) 151 if nil != err { 152 t.Fatalf("GET /auth/v1.0 failed: %v", err) 153 } 154 if http.StatusOK != authResponse.StatusCode { 155 t.Fatalf("GET /auth/v1.0 returned bad status: %v", authResponse.Status) 156 } 157 158 err = authResponse.Body.Close() 159 if nil != err { 160 t.Fatalf("GET /auth/v1.0 returned uncloseable Body: %v", err) 161 } 162 163 if testAuthToken != authResponse.Header.Get("X-Auth-Token") { 164 t.Fatalf("GET /auth/v1.0 returned incorrect X-Auth-Token") 165 } 166 167 if "http://"+testSwiftProxyAddr+"/v1/"+testAccountName != authResponse.Header.Get("X-Storage-Url") { 168 t.Fatalf("GET /auth/v1.0 returned incorrect X-Storage-Url") 169 } 170 171 putContainerRequest, err = http.NewRequest("PUT", globals.swiftStorageURL+"/TestContainer", nil) 172 if nil != err { 173 t.Fatalf("Creating PUT .../TestContainer failed: %v", err) 174 } 175 176 putContainerRequest.Header.Add("X-Auth-Token", testAuthToken) 177 178 putContainerResponse, err = testSwiftProxyEmulatorGlobals.httpClient.Do(putContainerRequest) 179 if nil != err { 180 t.Fatalf("PUT .../TestContainer failed: %v", err) 181 } 182 if http.StatusCreated != putContainerResponse.StatusCode { 183 t.Fatalf("PUT .../TestContainer returned bad status: %v", putContainerResponse.Status) 184 } 185 186 putObjectRequest, err = http.NewRequest("PUT", globals.swiftStorageURL+"/TestContainer/TestObject", bytes.NewReader([]byte{0x00, 0x01, 0x02, 0x03, 0x04})) 187 if nil != err { 188 t.Fatalf("Creating PUT .../TestContainer/TestObject failed: %v", err) 189 } 190 191 putObjectRequest.Header.Add("X-Auth-Token", testAuthToken) 192 193 putObjectResponse, err = testSwiftProxyEmulatorGlobals.httpClient.Do(putObjectRequest) 194 if nil != err { 195 t.Fatalf("PUT .../TestContainer/TestObject failed: %v", err) 196 } 197 if http.StatusCreated != putObjectResponse.StatusCode { 198 t.Fatalf("PUT .../TestContainer/TestObject returned bad status: %v", putObjectResponse.Status) 199 } 200 201 getObjectRequest, err = http.NewRequest("GET", globals.swiftStorageURL+"/TestContainer/TestObject", nil) 202 if nil != err { 203 t.Fatalf("Creating GET .../TestContainer/TestObject failed: %v", err) 204 } 205 206 getObjectRequest.Header.Add("X-Auth-Token", testAuthToken) 207 208 getObjectRequest.Header.Add("Range", "bytes=1-3") 209 210 getObjectResponse, err = testSwiftProxyEmulatorGlobals.httpClient.Do(getObjectRequest) 211 if nil != err { 212 t.Fatalf("GET .../TestContainer/TestObject failed: %v", err) 213 } 214 if http.StatusPartialContent != getObjectResponse.StatusCode { 215 t.Fatalf("GET .../TestContainer/TestObject returned bad status: %v", getObjectResponse.Status) 216 } 217 218 getBuf, err = ioutil.ReadAll(getObjectResponse.Body) 219 if nil != err { 220 t.Fatalf("GET .../TestContainer/TestObject returned unreadable Body: %v", err) 221 } 222 223 err = getObjectResponse.Body.Close() 224 if nil != err { 225 t.Fatalf("GET .../TestContainer/TestObject returned uncloseable Body: %v", err) 226 } 227 228 if (3 != len(getBuf)) || 229 (0x01 != getBuf[0]) || 230 (0x02 != getBuf[1]) || 231 (0x03 != getBuf[2]) { 232 t.Fatalf("GET .../TestContainer/TestObject returned unexpected contents") 233 } 234 235 pingReq = &jrpcfs.PingReq{ 236 Message: "TestMessage", 237 } 238 239 pingReqMessageID, pingReqBuf, err = jrpcMarshalRequest("Server.RpcPing", pingReq) 240 if nil != err { 241 t.Fatalf("Marshaling pingReq failed: %v", err) 242 } 243 244 pingRequest, err = http.NewRequest("PROXYFS", globals.swiftStorageURL, bytes.NewReader(pingReqBuf)) 245 if nil != err { 246 t.Fatalf("Creating PROXYFS pingReq failed: %v", err) 247 } 248 249 pingRequest.Header.Add("X-Auth-Token", testAuthToken) 250 pingRequest.Header.Add("Content-Type", "application/json") 251 252 pingResponse, err = testSwiftProxyEmulatorGlobals.httpClient.Do(pingRequest) 253 if nil != err { 254 t.Fatalf("PROXYFS pingReq failed: %v", err) 255 } 256 if http.StatusOK != pingResponse.StatusCode { 257 t.Fatalf("PROXYFS pingReq returned bad status: %v", pingResponse.Status) 258 } 259 260 pingReplyBuf, err = ioutil.ReadAll(pingResponse.Body) 261 if nil != err { 262 t.Fatalf("PROXYFS pingReq returned unreadable Body: %v", err) 263 } 264 265 err = pingResponse.Body.Close() 266 if nil != err { 267 t.Fatalf("PROXYFS pingReq returned uncloseable Body: %v", err) 268 } 269 270 pingReplyMessageID, responseErr, unmarshalErr = jrpcUnmarshalResponseForIDAndError(pingReplyBuf) 271 if nil != unmarshalErr { 272 t.Fatalf("Unmarshaling ID & Error failed: %v", unmarshalErr) 273 } 274 if nil != responseErr { 275 t.Fatalf("Unmarshaling ID & Error returned unexpected Error") 276 } 277 if pingReqMessageID != pingReplyMessageID { 278 t.Fatal("Unmarshaling ID & Error returned unexpected ID") 279 } 280 281 pingReply = &jrpcfs.PingReply{} 282 283 err = jrpcUnmarshalResponse(pingReqMessageID, pingReplyBuf, pingReply) 284 if nil != err { 285 t.Fatalf("Unmarshaling pingReply failed: %v", err) 286 } 287 if fmt.Sprintf("pong %d bytes", len("TestMessage")) != pingReply.Message { 288 t.Fatalf("PROXYFS pingReply returned unexpected Message") 289 } 290 291 testTeardown(t) 292 } 293 294 func TestJRPCMarshaling(t *testing.T) { 295 var ( 296 marshalErr error 297 pingReplyBuf []byte 298 pingReplyInput *jrpcfs.PingReply 299 pingReplyInputRequestID uint64 300 pingReplyOutput *jrpcfs.PingReply 301 pingReplyOutputRequestID uint64 302 pingReqBuf []byte 303 pingReqInput *jrpcfs.PingReq 304 pingReqInputRequestID uint64 305 pingReqOutput *jrpcfs.PingReq 306 pingReqOutputRequestID uint64 307 requestMethod string 308 responseErr error 309 unmarshalErr error 310 ) 311 312 pingReqInput = &jrpcfs.PingReq{ 313 Message: "TestMessage", 314 } 315 316 pingReqInputRequestID, pingReqBuf, marshalErr = jrpcMarshalRequest("Server.RpcPing", pingReqInput) 317 if nil != marshalErr { 318 t.Fatalf("jrpcMarshalRequest() failed: %v", marshalErr) 319 } 320 321 requestMethod, pingReqOutputRequestID, unmarshalErr = jrpcUnmarshalRequestForMethodAndID(pingReqBuf) 322 if nil != unmarshalErr { 323 t.Fatalf("jrpcUnmarshalRequestForMethod() failed: %v", unmarshalErr) 324 } 325 if "Server.RpcPing" != requestMethod { 326 t.Fatalf("jrpcUnmarshalRequestForMethod() returned unexpected requestMethod") 327 } 328 if pingReqInputRequestID != pingReqOutputRequestID { 329 t.Fatalf("jrpcUnmarshalRequest() returned unexpected requestID") 330 } 331 332 pingReqOutput = &jrpcfs.PingReq{} 333 334 unmarshalErr = jrpcUnmarshalRequest(pingReqOutputRequestID, pingReqBuf, pingReqOutput) 335 if nil != unmarshalErr { 336 t.Fatalf("jrpcUnmarshalRequest() failed: %v", unmarshalErr) 337 } 338 if "TestMessage" != pingReqOutput.Message { 339 t.Fatalf("jrpcUnmarshalRequest() returned unexpected jrpcfs.PingReq.Message") 340 } 341 342 pingReplyInputRequestID = pingReqOutputRequestID 343 344 pingReplyInput = &jrpcfs.PingReply{ 345 Message: "TestMessage", 346 } 347 348 pingReplyBuf, marshalErr = jrpcMarshalResponse(pingReplyInputRequestID, nil, pingReplyInput) 349 if nil != marshalErr { 350 t.Fatalf("jrpcMarshalResponse(,nil-responseErr,non-nil-response) failed: %v", marshalErr) 351 } 352 353 pingReplyOutputRequestID, responseErr, unmarshalErr = jrpcUnmarshalResponseForIDAndError(pingReplyBuf) 354 if nil != unmarshalErr { 355 t.Fatalf("jrpcUnmarshalResponseForIDAndError() failed: %v", unmarshalErr) 356 } 357 if nil != responseErr { 358 t.Fatalf("jrpcUnmarshalResponseForIDAndError() returned unexpected responseErr") 359 } 360 if pingReplyInputRequestID != pingReplyOutputRequestID { 361 t.Fatalf("jrpcUnmarshalResponseForIDAndError() returned unexpected requestID") 362 } 363 364 pingReplyOutput = &jrpcfs.PingReply{} 365 366 unmarshalErr = jrpcUnmarshalResponse(pingReplyOutputRequestID, pingReplyBuf, pingReplyOutput) 367 if nil != unmarshalErr { 368 t.Fatalf("jrpcUnmarshalResponse() failed: %v", unmarshalErr) 369 } 370 if "TestMessage" != pingReplyOutput.Message { 371 t.Fatalf("jrpcUnmarshalRequest() returned unexpected jrpcfs.PingReply.Message") 372 } 373 374 pingReplyBuf, marshalErr = jrpcMarshalResponse(pingReplyInputRequestID, nil, nil) 375 if nil != marshalErr { 376 t.Fatalf("jrpcMarshalResponse(,nil-responseErr,nil-response) failed: %v", marshalErr) 377 } 378 379 pingReplyBuf, marshalErr = jrpcMarshalResponse(pingReplyInputRequestID, fmt.Errorf("TestError"), nil) 380 if nil != marshalErr { 381 t.Fatalf("jrpcMarshalResponse(,non-nil-responseErr,nil-response) failed: %v", marshalErr) 382 } 383 384 pingReplyOutputRequestID, responseErr, unmarshalErr = jrpcUnmarshalResponseForIDAndError(pingReplyBuf) 385 if nil != unmarshalErr { 386 t.Fatalf("jrpcUnmarshalResponseForIDAndError() failed: %v", unmarshalErr) 387 } 388 if (nil == responseErr) || ("TestError" != responseErr.Error()) { 389 t.Fatalf("jrpcUnmarshalResponseForIDAndError() returned unexpected responseErr") 390 } 391 if pingReplyInputRequestID != pingReplyOutputRequestID { 392 t.Fatalf("jrpcUnmarshalResponseForIDAndError() returned unexpected requestID") 393 } 394 395 pingReplyBuf, marshalErr = jrpcMarshalResponse(pingReplyInputRequestID, fmt.Errorf("TestError"), pingReplyOutput) 396 if nil != marshalErr { 397 t.Fatalf("jrpcMarshalResponse(,non-nil-responseErr,non-nil-response) failed: %v", marshalErr) 398 } 399 }