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  }