From b58e5481f3fc227a0cd36168749d1fab3fa0fc40 Mon Sep 17 00:00:00 2001 From: Joel Unzain Date: Tue, 13 Feb 2018 16:52:47 -0800 Subject: [PATCH 1/3] remove unnecessary abstractions, fix unit tests and remove unnecessary context timeout code --- src/tr1d1um/communication.go | 94 ++++-------- src/tr1d1um/communication_test.go | 213 +++++++++++---------------- src/tr1d1um/conversion_utils.go | 62 +++----- src/tr1d1um/conversion_utils_test.go | 76 +--------- src/tr1d1um/http.go | 32 ++-- src/tr1d1um/http_test.go | 44 ++---- src/tr1d1um/mocks_test.go | 44 +----- src/tr1d1um/retries.go | 7 +- src/tr1d1um/retries_test.go | 17 ++- src/tr1d1um/tr1d1um.go | 22 +-- src/tr1d1um/tr1d1um_response.go | 7 +- src/tr1d1um/tr1d1um_test.go | 3 - 12 files changed, 198 insertions(+), 423 deletions(-) diff --git a/src/tr1d1um/communication.go b/src/tr1d1um/communication.go index 5cc38e03..2c85b952 100644 --- a/src/tr1d1um/communication.go +++ b/src/tr1d1um/communication.go @@ -32,7 +32,7 @@ import ( //SendAndHandle wraps the methods to communicate both back to a requester and to a target server type SendAndHandle interface { - MakeRequest(requestArgs ...interface{}) (tr1Resp interface{}, err error) + MakeRequest(context.Context, ...interface{}) (tr1Resp interface{}, err error) HandleResponse(error, *http.Response, *Tr1d1umResponse, bool) GetRespTimeout() time.Duration } @@ -40,38 +40,20 @@ type SendAndHandle interface { //SendAndHandleFactory serves as a fool-proof (you must provide all needed values for struct) initializer for SendAndHandle type SendAndHandleFactory struct{} -//New does the initialization of a SendAndHandle (of actual type Tr1SendAndHandle) -func (factory SendAndHandleFactory) New(respTimeout time.Duration, requester Requester, encoding EncodingTool, - logger log.Logger) SendAndHandle { - return &Tr1SendAndHandle{ - RespTimeout: respTimeout, - Requester: requester, - EncodingTool: encoding, - Logger: logger, - } -} - //Tr1SendAndHandle provides one implementation of SendAndHandle type Tr1SendAndHandle struct { RespTimeout time.Duration - Requester - EncodingTool log.Logger -} - -type clientResponse struct { - resp *http.Response - err error + client *http.Client } //Tr1d1umRequest provides a clean way to store information needed to make some request (in our case, it is http but it is not // limited to that). type Tr1d1umRequest struct { - ancestorCtx context.Context - method string - URL string - body []byte - headers http.Header + method string + URL string + body []byte + headers http.Header } //GetBody is a handy function to provide the payload (body) of Tr1d1umRequest as a fresh reader @@ -84,7 +66,7 @@ func (tr1Req *Tr1d1umRequest) GetBody() (body io.Reader) { //MakeRequest contains all the logic that actually performs an http request //It is tightly coupled with HandleResponse -func (tr1 *Tr1SendAndHandle) MakeRequest(requestArgs ...interface{}) (interface{}, error) { +func (tr1 *Tr1SendAndHandle) MakeRequest(ctx context.Context, requestArgs ...interface{}) (interface{}, error) { tr1Request := requestArgs[0].(Tr1d1umRequest) newRequest, newRequestErr := http.NewRequest(tr1Request.method, tr1Request.URL, tr1Request.GetBody()) tr1Response := Tr1d1umResponse{}.New() @@ -101,12 +83,10 @@ func (tr1 *Tr1SendAndHandle) MakeRequest(requestArgs ...interface{}) (interface{ } } - ctx, cancel := context.WithTimeout(tr1Request.ancestorCtx, tr1.GetRespTimeout()) + timeoutCtx, cancel := context.WithTimeout(ctx, tr1.GetRespTimeout()) defer cancel() - newRequest = newRequest.WithContext(ctx) - - httpResp, responseErr := tr1.PerformRequest(newRequest) + httpResp, responseErr := tr1.client.Do(newRequest.WithContext(timeoutCtx)) tr1.HandleResponse(responseErr, httpResp, tr1Response, tr1Request.method == http.MethodGet) return tr1Response, responseErr } @@ -118,30 +98,40 @@ func (tr1 *Tr1SendAndHandle) HandleResponse(err error, respFromServer *http.Resp if err != nil { ReportError(err, tr1Resp) - errorLogger.Log(logging.ErrorKey(), err) + errorLogger.Log(logging.MessageKey(), "got an error instead of an http.Response", logging.ErrorKey(), err) return } //as a client, we are responsible to close the body after it gets read below defer respFromServer.Body.Close() + bodyBytes, errReading := ioutil.ReadAll(respFromServer.Body) + + if errReading != nil { + ReportError(errReading, tr1Resp) + errorLogger.Log(logging.MessageKey(), "error reading http.Response body", logging.ErrorKey(), errReading) + return + } if respFromServer.StatusCode != http.StatusOK || wholeBody { - tr1Resp.Body, tr1Resp.err = ioutil.ReadAll(respFromServer.Body) - tr1Resp.Code = respFromServer.StatusCode + tr1Resp.Body, tr1Resp.Code = bodyBytes, respFromServer.StatusCode - ReportError(tr1Resp.err, tr1Resp) debugLogger.Log(logging.MessageKey(), "non-200 response from server", logging.ErrorKey(), respFromServer.Status) return } - if RDKResponse, encodingErr := tr1.ExtractPayload(respFromServer.Body, wrp.Msgpack); encodingErr == nil { + ResponseData := &wrp.Message{Type: wrp.SimpleRequestResponseMessageType} + + if errDecoding := wrp.NewDecoder(bytes.NewBuffer(bodyBytes), wrp.Msgpack).Decode(ResponseData); errDecoding == nil { + RDKResponse := ResponseData.Payload + if RDKRespCode, RDKErr := GetStatusCodeFromRDKResponse(RDKResponse); RDKErr == nil && RDKRespCode != http.StatusInternalServerError { tr1Resp.Code = RDKRespCode } + tr1Resp.Body = RDKResponse } else { - ReportError(encodingErr, tr1Resp) - errorLogger.Log(logging.MessageKey(), "could not extract payload from wrp body", logging.ErrorKey(), encodingErr) + ReportError(errDecoding, tr1Resp) + errorLogger.Log(logging.MessageKey(), "could not extract payload from wrp body", logging.ErrorKey(), errDecoding) } ForwardHeadersByPrefix("X", respFromServer, tr1Resp) @@ -153,35 +143,3 @@ func (tr1 *Tr1SendAndHandle) HandleResponse(err error, respFromServer *http.Resp func (tr1 *Tr1SendAndHandle) GetRespTimeout() time.Duration { return tr1.RespTimeout } - -//Requester has the main functionality of taking a request, performing such request based on some internal client and -// simply returning the response and potential err when applicable -type Requester interface { - PerformRequest(*http.Request) (*http.Response, error) -} - -//ContextTimeoutRequester is a Requester realization that executes an http request respecting any context deadlines (or -// cancellations) -type ContextTimeoutRequester struct { - client *http.Client -} - -//PerformRequest makes its client execute the request asynchronously and guarantees that the cancellations or -// timeouts of the request's context is respected -func (c *ContextTimeoutRequester) PerformRequest(request *http.Request) (resp *http.Response, err error) { - responseReady := make(chan clientResponse, 1) // capacity of 1 helps avoid goroutine blocking in timeout situations - ctx := request.Context() - - go func() { - respObj, respErr := c.client.Do(request) - responseReady <- clientResponse{respObj, respErr} - }() - - select { - case cResponse := <-responseReady: - resp, err = cResponse.resp, cResponse.err - return - case <-ctx.Done(): - return nil, ctx.Err() - } -} diff --git a/src/tr1d1um/communication_test.go b/src/tr1d1um/communication_test.go index e667079a..0b7f7c96 100644 --- a/src/tr1d1um/communication_test.go +++ b/src/tr1d1um/communication_test.go @@ -24,36 +24,29 @@ import ( "io" "net/http" "net/http/httptest" - "sync" + "strings" "testing" "time" - "github.com/Comcast/webpa-common/logging" "github.com/Comcast/webpa-common/wrp" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" -) -var ( - mockRequester = &MockRequester{} + "github.com/Comcast/webpa-common/logging" + "github.com/stretchr/testify/assert" ) func TestMakeRequest(t *testing.T) { - validURL := "http://someValidURL.com" - t.Run("BadNewRequest", func(t *testing.T) { assert := assert.New(t) tr1Req := Tr1d1umRequest{ - ancestorCtx: context.TODO(), - method: "字", //make http.NewRequest fail with this awesome Chinese character. - URL: validURL, - headers: http.Header{}, - body: []byte("d"), + method: "字", //make http.NewRequest fail with this awesome Chinese character. + URL: "http://someValidURL.com", + headers: http.Header{}, + body: []byte("d"), } tr1 := NewTR1() - resp, err := tr1.MakeRequest(tr1Req) + resp, err := tr1.MakeRequest(context.TODO(), tr1Req) assert.NotNil(resp) tr1Resp := resp.(*Tr1d1umResponse) @@ -62,43 +55,75 @@ func TestMakeRequest(t *testing.T) { assert.EqualValues(http.StatusInternalServerError, tr1Resp.Code) }) - t.Run("InternalError", func(t *testing.T) { + t.Run("RequestContextTimetout", func(t *testing.T) { assert := assert.New(t) + + slowServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + time.Sleep(time.Minute) // time out will for sure be triggered + })) + tr1Req := Tr1d1umRequest{ - ancestorCtx: context.TODO(), - method: "GET", - URL: validURL, - headers: http.Header{"key": []string{"value"}}, + method: http.MethodGet, + URL: slowServer.URL, + headers: http.Header{}, + body: nil, } tr1 := NewTR1() - someErr := errors.New("something went wrong") - mockRequester.On("PerformRequest", mock.AnythingOfType("*http.Request")).Return(&http.Response{}, - someErr).Once() + ctx, cancel := context.WithCancel(context.TODO()) + + go cancel() //fake an a quick timeout + + resp, err := tr1.MakeRequest(ctx, tr1Req) - resp, err := tr1.MakeRequest(tr1Req) assert.NotNil(resp) + assert.NotNil(err) + assert.True(strings.HasSuffix(err.Error(), "context canceled")) tr1Resp := resp.(*Tr1d1umResponse) + assert.EqualValues(http.StatusServiceUnavailable, tr1Resp.Code) + }) - assert.EqualValues(someErr, err) - assert.EqualValues(http.StatusInternalServerError, tr1Resp.Code) + t.Run("RequestContextNoTimetout", func(t *testing.T) { + assert := assert.New(t) + + body := []byte(`aqua`) - mockRequester.AssertExpectations(t) + fastServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Write(body) + })) + + tr1Req := Tr1d1umRequest{ + method: http.MethodGet, + URL: fastServer.URL, + headers: http.Header{}, + body: nil, + } + + tr1 := NewTR1() + + ctx, cancel := context.WithCancel(context.TODO()) + + defer cancel() + + resp, err := tr1.MakeRequest(ctx, tr1Req) + + assert.NotNil(resp) + assert.Nil(err) + + tr1Resp := resp.(*Tr1d1umResponse) + + assert.EqualValues(body, tr1Resp.Body) + assert.EqualValues(http.StatusOK, tr1Resp.Code) }) + } func TestHandleResponse(t *testing.T) { assert := assert.New(t) tr1 := NewTR1() - t.Run("IncomingTimeoutErr", func(t *testing.T) { - recorder := Tr1d1umResponse{}.New() - tr1.HandleResponse(context.DeadlineExceeded, nil, recorder, false) - assert.EqualValues(Tr1StatusTimeout, recorder.Code) - }) - t.Run("IncomingErr", func(t *testing.T) { recorder := Tr1d1umResponse{}.New() tr1.HandleResponse(errors.New(errMsg), nil, recorder, false) @@ -127,27 +152,11 @@ func TestHandleResponse(t *testing.T) { t.Run("ExtractPayloadFail", func(t *testing.T) { fakeResponse := newTestingHTTPResponse(http.StatusOK, "") - mockEncoding.On("ExtractPayload", fakeResponse.Body, wrp.Msgpack).Return([]byte(""), - errors.New(errMsg)).Once() recorder := Tr1d1umResponse{}.New() tr1.HandleResponse(nil, fakeResponse, recorder, false) assert.EqualValues(http.StatusInternalServerError, recorder.Code) assert.True(bodyIsClosed(fakeResponse)) - mockEncoding.AssertExpectations(t) - }) - - t.Run("ExtractPayloadTimeout", func(t *testing.T) { - fakeResponse := newTestingHTTPResponse(http.StatusOK, "") - - mockEncoding.On("ExtractPayload", fakeResponse.Body, wrp.Msgpack).Return([]byte(""), - context.Canceled).Once() - recorder := Tr1d1umResponse{}.New() - tr1.HandleResponse(nil, fakeResponse, recorder, false) - - assert.EqualValues(Tr1StatusTimeout, recorder.Code) - assert.True(bodyIsClosed(fakeResponse)) - mockEncoding.AssertExpectations(t) }) t.Run("IdealReadEntireBody", func(t *testing.T) { @@ -162,99 +171,55 @@ func TestHandleResponse(t *testing.T) { }) t.Run("GoodRDKResponse", func(t *testing.T) { - fakeResponse := newTestingHTTPResponse(http.StatusOK, "") //these arguments are irrelevant as we mock RDK response below - extractedData := []byte(`{"statusCode": 202}`) + RDKResponse := []byte(`{"statusCode": 202}`) + wrpMsg := wrp.Message{ + Type: wrp.SimpleRequestResponseMessageType, + Payload: RDKResponse} + + var encodedData []byte + errEncoding := wrp.NewEncoderBytes(&encodedData, wrp.Msgpack).Encode(wrpMsg) + if errEncoding != nil { + t.Fatalf("test depency failed: %v\n", errEncoding) + } + + fakeResponse := newTestingHTTPResponse(http.StatusOK, string(encodedData)) - mockEncoding.On("ExtractPayload", fakeResponse.Body, wrp.Msgpack).Return(extractedData, nil).Once() recorder := Tr1d1umResponse{}.New() tr1.HandleResponse(nil, fakeResponse, recorder, false) assert.EqualValues(202, recorder.Code) - assert.EqualValues(extractedData, string(recorder.Body)) + assert.EqualValues(RDKResponse, string(recorder.Body)) assert.True(bodyIsClosed(fakeResponse)) - mockEncoding.AssertExpectations(t) }) - t.Run("BadRDKResponse", func(t *testing.T) { - fakeResponse := newTestingHTTPResponse(http.StatusOK, "") //these arguments are irrelevant as we mock RDK response below - extractedData := []byte(`{"statusCode": 500}`) + t.Run("IgnoredRDKResponseStatusCode", func(t *testing.T) { + RDKResponse := []byte(`{"statusCode": 500}`) //status 500 is ignored to avoid ambiguities (server vs RDK device internal error) + wrpMsg := wrp.Message{ + Type: wrp.SimpleRequestResponseMessageType, + Payload: RDKResponse} + + var encodedData []byte + errEncoding := wrp.NewEncoderBytes(&encodedData, wrp.Msgpack).Encode(wrpMsg) + if errEncoding != nil { + t.Fatalf("test depency failed: %v\n", errEncoding) + } + + fakeResponse := newTestingHTTPResponse(http.StatusOK, string(encodedData)) - mockEncoding.On("ExtractPayload", fakeResponse.Body, wrp.Msgpack).Return(extractedData, nil).Once() recorder := Tr1d1umResponse{}.New() tr1.HandleResponse(nil, fakeResponse, recorder, false) - assert.EqualValues(http.StatusOK, recorder.Code) // reflect transaction instead of device status - assert.EqualValues(extractedData, string(recorder.Body)) + assert.EqualValues(200, recorder.Code) + assert.EqualValues(RDKResponse, string(recorder.Body)) assert.True(bodyIsClosed(fakeResponse)) - mockEncoding.AssertExpectations(t) - }) -} - -func TestPerformRequest(t *testing.T) { - testWaitGroup := &sync.WaitGroup{} - testWaitGroup.Add(1) - - t.Run("RequestTimeout", func(t *testing.T) { - defer testWaitGroup.Done() - assert := assert.New(t) - - slowTS := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - time.Sleep(time.Minute) // time out will for sure be triggered - })) - - defer slowTS.Close() - - req, _ := http.NewRequest(http.MethodGet, slowTS.URL, nil) - ctx, cancel := context.WithCancel(req.Context()) - - requester := &ContextTimeoutRequester{&http.Client{}} - - wg := sync.WaitGroup{} - wg.Add(1) - - errChan := make(chan error) - - go func() { - wg.Done() - _, err := requester.PerformRequest(req.WithContext(ctx)) - errChan <- err - }() - - wg.Wait() //Wait until we have high chance that PerformRequest() has begun running to call cancel() - cancel() - - assert.NotNil(<-errChan) - }) - - t.Run("RequestNoTimeout", func(t *testing.T) { - testWaitGroup.Wait() - - assert := assert.New(t) - - requester := &ContextTimeoutRequester{&http.Client{}} - - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusAccepted) // write a status code we can assert on - })) - - defer ts.Close() - - req, _ := http.NewRequest(http.MethodGet, ts.URL, nil) - - resp, err := requester.PerformRequest(req) - - assert.Nil(err) - assert.NotNil(resp) - assert.EqualValues(http.StatusAccepted, resp.StatusCode) }) } func NewTR1() (tr1 *Tr1SendAndHandle) { tr1 = &Tr1SendAndHandle{ - Logger: logging.DefaultLogger(), - Requester: mockRequester, - EncodingTool: mockEncoding, - RespTimeout: time.Minute, + Logger: logging.DefaultLogger(), + RespTimeout: time.Minute, + client: &http.Client{}, } return tr1 } diff --git a/src/tr1d1um/conversion_utils.go b/src/tr1d1um/conversion_utils.go index ab7c37e5..5f897205 100644 --- a/src/tr1d1um/conversion_utils.go +++ b/src/tr1d1um/conversion_utils.go @@ -58,20 +58,12 @@ type ConversionTool interface { GetConfiguredWRP([]byte, Vars, http.Header) *wrp.Message } -//EncodingTool lays out the definition of methods used for encoding/decoding between WDMP and WRP -type EncodingTool interface { - DecodeJSON(io.Reader, interface{}) error - EncodeJSON(interface{}) ([]byte, error) - ExtractPayload(io.Reader, wrp.Format) ([]byte, error) -} - //EncodingHelper implements the definitions defined in EncodingTool type EncodingHelper struct{} //ConversionWDMP implements the definitions defined in ConversionTool type ConversionWDMP struct { - encodingHelper EncodingTool - WRPSource string + WRPSource string } //The following functions with names of the form {command}FlavorFormat serve as the low level builders of WDMP objects @@ -101,9 +93,13 @@ func (cw *ConversionWDMP) GetFlavorFormat(req *http.Request, pathVars Vars, attr func (cw *ConversionWDMP) SetFlavorFormat(req *http.Request) (wdmp *SetWDMP, err error) { wdmp = new(SetWDMP) - if err = cw.encodingHelper.DecodeJSON(req.Body, wdmp); err == nil { - err = cw.ValidateAndDeduceSET(req.Header, wdmp) + var payload []byte + if payload, err = ioutil.ReadAll(req.Body); err == nil && len(payload) > 0 { + if err = json.Unmarshal(payload, wdmp); err == nil { + err = cw.ValidateAndDeduceSET(req.Header, wdmp) + } } + return } @@ -131,10 +127,12 @@ func (cw *ConversionWDMP) AddFlavorFormat(input io.Reader, urlVars Vars, tableNa return } - if err = cw.encodingHelper.DecodeJSON(input, &wdmp.Row); err == nil { - err = validation.Validate(wdmp.Row, validation.NotNil) + var payload []byte + if payload, err = ioutil.ReadAll(input); err == nil && len(payload) > 0 { + if err = json.Unmarshal(payload, &wdmp.Row); err == nil { + err = validation.Validate(wdmp.Row, validation.NotNil) + } } - return } @@ -149,8 +147,11 @@ func (cw *ConversionWDMP) ReplaceFlavorFormat(input io.Reader, urlVars Vars, tab return } - if err = cw.encodingHelper.DecodeJSON(input, &wdmp.Rows); err == nil { - err = validation.Validate(wdmp.Rows, validation.NotNil) + var payload []byte + if payload, err = ioutil.ReadAll(input); err == nil && len(payload) > 0 { + if err = json.Unmarshal(payload, &wdmp.Rows); err == nil { + err = validation.Validate(wdmp.Rows, validation.NotNil) + } } return @@ -265,35 +266,6 @@ func (cw *ConversionWDMP) GetWRPSource() string { return cw.WRPSource } -/* Encoding Helper methods below */ - -//DecodeJSON decodes data from the input into v. It uses json.Unmarshall to perform actual decoding -//Note: if nothing is read from input, Unmarshalling is not attempted. -func (helper *EncodingHelper) DecodeJSON(input io.Reader, v interface{}) (err error) { - var payload []byte - if payload, err = ioutil.ReadAll(input); err == nil && len(payload) > 0 { - err = json.Unmarshal(payload, v) - } - return -} - -//EncodeJSON wraps the json.Marshall method -func (helper *EncodingHelper) EncodeJSON(v interface{}) (data []byte, err error) { - data, err = json.Marshal(v) - return -} - -//ExtractPayload decodes an encoded wrp message and returns its payload -func (helper *EncodingHelper) ExtractPayload(input io.Reader, format wrp.Format) (payload []byte, err error) { - wrpResponse := &wrp.Message{Type: wrp.SimpleRequestResponseMessageType} - - if err = wrp.NewDecoder(input, format).Decode(wrpResponse); err == nil { - payload = wrpResponse.Payload - } - - return -} - //GetOrGenTID returns a Transaction ID for a given request. //If a TID was provided in the headers, such is used. Otherwise, //a new TID is generated and returned diff --git a/src/tr1d1um/conversion_utils_test.go b/src/tr1d1um/conversion_utils_test.go index 5e710ddf..84c4fd40 100644 --- a/src/tr1d1um/conversion_utils_test.go +++ b/src/tr1d1um/conversion_utils_test.go @@ -82,7 +82,7 @@ func TestGetFlavorFormat(t *testing.T) { } func TestSetFlavorFormat(t *testing.T) { - c := ConversionWDMP{encodingHelper: &EncodingHelper{}, WRPSource: "dns:machineDNS"} + c := ConversionWDMP{WRPSource: "dns:machineDNS"} commonURL := "http://device/config?k=v" var req *http.Request @@ -290,11 +290,10 @@ func TestIsValidSetWDMP(t *testing.T) { assert.True(isValidSetWDMP(wdmp)) }) } - func TestDeleteFlavorFormat(t *testing.T) { assert := assert.New(t) commonVars := Vars{"param": "rowName", "emptyParam": ""} - c := ConversionWDMP{encodingHelper: &EncodingHelper{}, WRPSource: "dns:machineDNS"} + c := ConversionWDMP{WRPSource: "dns:machineDNS"} t.Run("NoRowName", func(t *testing.T) { _, err := c.DeleteFlavorFormat(Vars{}, "param") @@ -318,7 +317,7 @@ func TestDeleteFlavorFormat(t *testing.T) { func TestReplaceFlavorFormat(t *testing.T) { commonVars := Vars{"uThere?": "yes!"} emptyVars := Vars{} - c := ConversionWDMP{encodingHelper: &EncodingHelper{}, WRPSource: "dns:machineDNS"} + c := ConversionWDMP{WRPSource: "dns:machineDNS"} t.Run("TableNotProvided", func(t *testing.T) { assert := assert.New(t) @@ -359,7 +358,7 @@ func TestReplaceFlavorFormat(t *testing.T) { func TestAddFlavorFormat(t *testing.T) { emptyVars := Vars{} - c := ConversionWDMP{encodingHelper: &EncodingHelper{}, WRPSource: "dns:machineDNS"} + c := ConversionWDMP{WRPSource: "dns:machineDNS"} t.Run("TableNotProvided", func(t *testing.T) { assert := assert.New(t) @@ -430,72 +429,6 @@ func TestGetFromURLPath(t *testing.T) { }) } -func TestDecodeJSON(t *testing.T) { - assert := assert.New(t) - e := EncodingHelper{} - - t.Run("IdealPath", func(t *testing.T) { - input := bytes.NewBufferString(`{"0":"zero","1":"one"}`) - - expected := map[string]string{"0": "zero", "1": "one"} - actual := make(map[string]string) - - err := e.DecodeJSON(input, &actual) - - assert.Nil(err) - assert.EqualValues(expected, actual) - }) - - t.Run("JsonErr", func(t *testing.T) { - actual := make(map[string]string) - - err := e.DecodeJSON(bytes.NewBufferString("{"), &actual) - assert.NotNil(err) - }) - - t.Run("EmptyInput", func(t *testing.T) { - actual := make(map[string]string) - - err := e.DecodeJSON(bytes.NewBufferString(""), &actual) - assert.Nil(err) - }) -} - -func TestEncodeJSON(t *testing.T) { - e := EncodingHelper{} - assert := assert.New(t) - expected := []byte(`{"command":"GET","names":["p1","p2"]}`) - actual, err := e.EncodeJSON(wdmpGet) - assert.Nil(err) - assert.EqualValues(expected, actual) -} - -func TestExtractPayloadFromWrp(t *testing.T) { - assert := assert.New(t) - e := EncodingHelper{} - - t.Run("IdealScenario", func(t *testing.T) { - expectedPayload := []byte("expectMe") - wrpMsg := wrp.Message{Payload: expectedPayload} - var inputBuffer bytes.Buffer - - wrp.NewEncoder(&inputBuffer, wrp.JSON).Encode(wrpMsg) - - payload, err := e.ExtractPayload(&inputBuffer, wrp.JSON) - - assert.Nil(err) - assert.EqualValues(expectedPayload, payload) - }) - - t.Run("DecodingErr", func(t *testing.T) { - badInput := bytes.NewBufferString("{") - - _, err := e.ExtractPayload(badInput, wrp.JSON) - - assert.NotNil(err) - }) -} - func TestGetConfiguredWRP(t *testing.T) { assert := assert.New(t) deviceID := "mac:112233445566" @@ -523,7 +456,6 @@ func TestGetConfiguredWRP(t *testing.T) { assert.EqualValues(expectedSource, wrpMsg.Source) assert.EqualValues(tid, wrpMsg.TransactionUUID) } - func TestGetOrGenTID(t *testing.T) { assert := assert.New(t) t.Run("UseGivenTID", func(t *testing.T) { diff --git a/src/tr1d1um/http.go b/src/tr1d1um/http.go index 3fd16f6c..bee4a8a0 100644 --- a/src/tr1d1um/http.go +++ b/src/tr1d1um/http.go @@ -19,6 +19,7 @@ package main import ( "bytes" + "encoding/json" "fmt" "net/http" "strings" @@ -35,11 +36,10 @@ const contentTypeKey = "Content-Type" //ConversionHandler is the main arm of the operations supported by this server type ConversionHandler struct { - TargetURL string - WRPRequestURL string - WdmpConvert ConversionTool - Sender SendAndHandle - EncodingHelper EncodingTool + TargetURL string + WRPRequestURL string + WdmpConvert ConversionTool + Sender SendAndHandle RequestValidator RetryStrategy log.Logger @@ -90,7 +90,7 @@ func (ch *ConversionHandler) ServeHTTP(origin http.ResponseWriter, req *http.Req return } - wdmpPayload, err := ch.EncodingHelper.EncodeJSON(wdmp) + wdmpPayload, err := json.Marshal(wdmp) if err != nil { origin.WriteHeader(http.StatusInternalServerError) @@ -114,17 +114,16 @@ func (ch *ConversionHandler) ServeHTTP(origin http.ResponseWriter, req *http.Req } tr1Request := Tr1d1umRequest{ - ancestorCtx: req.Context(), - method: http.MethodPost, - URL: ch.WRPRequestURL, - headers: http.Header{}, - body: wrpPayloadBuffer.Bytes(), + method: http.MethodPost, + URL: ch.WRPRequestURL, + headers: http.Header{}, + body: wrpPayloadBuffer.Bytes(), } tr1Request.headers.Set(contentTypeKey, wrp.Msgpack.ContentType()) tr1Request.headers.Set("Authorization", req.Header.Get("Authorization")) - tr1Resp, err := ch.Execute(ch.Sender.MakeRequest, tr1Request) + tr1Resp, err := ch.Execute(req.Context(), ch.Sender.MakeRequest, tr1Request) if err != nil { errorLogger.Log(logging.MessageKey(), "error in retry execution", logging.ErrorKey(), err) @@ -143,15 +142,14 @@ func (ch *ConversionHandler) HandleStat(origin http.ResponseWriter, req *http.Re var errorLogger = logging.Error(ch) tr1Request := Tr1d1umRequest{ - ancestorCtx: req.Context(), - method: http.MethodGet, - URL: ch.TargetURL + req.URL.RequestURI(), - headers: http.Header{}, + method: http.MethodGet, + URL: ch.TargetURL + req.URL.RequestURI(), + headers: http.Header{}, } tr1Request.headers.Set("Authorization", req.Header.Get("Authorization")) - tr1Resp, err := ch.Execute(ch.Sender.MakeRequest, tr1Request) + tr1Resp, err := ch.Execute(req.Context(), ch.Sender.MakeRequest, tr1Request) if err != nil { errorLogger.Log(logging.MessageKey(), "error in retry execution", logging.ErrorKey(), err) diff --git a/src/tr1d1um/http_test.go b/src/tr1d1um/http_test.go index 51a7148c..21fc3940 100644 --- a/src/tr1d1um/http_test.go +++ b/src/tr1d1um/http_test.go @@ -34,15 +34,14 @@ import ( const errMsg = "shared failure" var ( - payload, body = []byte("SomePayload"), bytes.NewBufferString("body") - resp = Tr1d1umResponse{}.New() - mockConversion, mockEncoding, mockSender = &MockConversionTool{}, &MockEncodingTool{}, &MockSendAndHandle{} - mockRequestValidator = &MockRequestValidator{} - mockRetryStrategy = &MockRetry{} - ch = &ConversionHandler{ + payload, body = []byte("SomePayload"), bytes.NewBufferString("body") + resp = Tr1d1umResponse{}.New() + mockConversion, mockSender = &MockConversionTool{}, &MockSendAndHandle{} + mockRequestValidator = &MockRequestValidator{} + mockRetryStrategy = &MockRetry{} + ch = &ConversionHandler{ WdmpConvert: mockConversion, Sender: mockSender, - EncodingHelper: mockEncoding, Logger: logging.DefaultLogger(), RequestValidator: mockRequestValidator, RetryStrategy: mockRetryStrategy, @@ -81,20 +80,6 @@ func TestConversionHandler(t *testing.T) { mockConversion.AssertExpectations(t) }) - t.Run("ErrEncode", func(testing *testing.T) { - mockEncoding.On("EncodeJSON", wdmpGet).Return([]byte(""), errors.New(errMsg)).Once() - mockConversion.On("GetFlavorFormat", commonRequest, vars, "attributes", "names", ","). - Return(wdmpGet, nil).Once() - mockRequestValidator.On("isValidRequest", mock.Anything, mock.Anything).Return(true).Once() - - recorder := httptest.NewRecorder() - ch.ServeHTTP(recorder, commonRequest) - - mockEncoding.AssertExpectations(t) - mockConversion.AssertExpectations(t) - mockRequestValidator.AssertExpectations(t) - }) - t.Run("IdealGet", func(t *testing.T) { mockConversion.On("GetFlavorFormat", commonRequest, vars, "attributes", "names", ","). Return(wdmpGet, nil).Once() @@ -153,11 +138,9 @@ func TestConversionHandler(t *testing.T) { recorder := httptest.NewRecorder() wrpMsg := &wrp.Message{} - payload := []byte("") mockRequestValidator.On("isValidRequest", mock.Anything, mock.Anything).Return(true).Once() - mockEncoding.On("EncodeJSON", wdmpDel).Return(payload, nil).Once() - mockConversion.On("GetConfiguredWRP", payload, mock.Anything, commonRequest.Header).Return(wrpMsg).Once() - mockRetryStrategy.On("Execute", mock.Anything, mock.Anything).Return(resp, errors.New("some internal "+ + mockConversion.On("GetConfiguredWRP", mock.AnythingOfType("[]uint8"), mock.Anything, commonRequest.Header).Return(wrpMsg).Once() + mockRetryStrategy.On("Execute", commonRequest.Context(), mock.Anything, mock.Anything).Return(resp, errors.New("some internal "+ "error")).Once() ch.ServeHTTP(recorder, commonRequest) @@ -228,7 +211,7 @@ func TestHandleStat(t *testing.T) { req := httptest.NewRequest(http.MethodGet, "http://ThisMachineURL.com", nil) tr1Resp := Tr1d1umResponse{}.New() - mockRetryStrategy.On("Execute", mock.Anything, mock.Anything).Return(tr1Resp, nil).Once() + mockRetryStrategy.On("Execute", req.Context(), mock.Anything, mock.Anything).Return(tr1Resp, nil).Once() ch.HandleStat(recorder, req) mockRetryStrategy.AssertExpectations(t) @@ -240,7 +223,7 @@ func TestHandleStat(t *testing.T) { req := httptest.NewRequest(http.MethodGet, "http://ThisMachineURL.com", nil) tr1Resp := Tr1d1umResponse{}.New() - mockRetryStrategy.On("Execute", mock.Anything, mock.Anything).Return(tr1Resp, errors.New("internal"+ + mockRetryStrategy.On("Execute", req.Context(), mock.Anything, mock.Anything).Return(tr1Resp, errors.New("internal"+ " error")).Once() ch.HandleStat(recorder, req) @@ -325,18 +308,15 @@ func SetUpTest(encodeArg interface{}, req *http.Request) { recorder := httptest.NewRecorder() wrpMsg := &wrp.Message{} - payload := []byte("") mockRequestValidator.On("isValidRequest", mock.Anything, mock.Anything).Return(true).Once() - mockEncoding.On("EncodeJSON", encodeArg).Return(payload, nil).Once() - mockConversion.On("GetConfiguredWRP", payload, mock.Anything, req.Header).Return(wrpMsg).Once() - mockRetryStrategy.On("Execute", mock.Anything, mock.Anything).Return(resp, nil).Once() + mockConversion.On("GetConfiguredWRP", mock.AnythingOfType("[]uint8"), mock.Anything, req.Header).Return(wrpMsg).Once() + mockRetryStrategy.On("Execute", req.Context(), mock.Anything, mock.Anything).Return(resp, nil).Once() ch.ServeHTTP(recorder, req) } func AssertCommonCalls(t *testing.T) { mockConversion.AssertExpectations(t) - mockEncoding.AssertExpectations(t) mockSender.AssertExpectations(t) mockRequestValidator.AssertExpectations(t) mockRetryStrategy.AssertExpectations(t) diff --git a/src/tr1d1um/mocks_test.go b/src/tr1d1um/mocks_test.go index 265684a2..51b1aaae 100644 --- a/src/tr1d1um/mocks_test.go +++ b/src/tr1d1um/mocks_test.go @@ -18,6 +18,7 @@ package main import ( + "context" "io" "net/http" "time" @@ -72,39 +73,14 @@ func (m *MockConversionTool) GetConfiguredWRP(wdmp []byte, pathVars Vars, header return args.Get(0).(*wrp.Message) } -/* Mocks for EncodingTool */ -type MockEncodingTool struct { - mock.Mock -} - -func (m *MockEncodingTool) GenericEncode(v interface{}, f wrp.Format) ([]byte, error) { - args := m.Called(v, f) - return args.Get(0).([]byte), args.Error(1) -} - -func (m *MockEncodingTool) DecodeJSON(input io.Reader, v interface{}) error { - args := m.Called(input, v) - return args.Error(0) -} - -func (m *MockEncodingTool) EncodeJSON(v interface{}) ([]byte, error) { - args := m.Called(v) - return args.Get(0).([]byte), args.Error(1) -} - -func (m *MockEncodingTool) ExtractPayload(input io.Reader, format wrp.Format) ([]byte, error) { - args := m.Called(input, format) - return args.Get(0).([]byte), args.Error(1) -} - /* Mocks for SendAndHandle */ type MockSendAndHandle struct { mock.Mock } -func (m *MockSendAndHandle) MakeRequest(request ...interface{}) (interface{}, error) { - args := m.Called(request...) +func (m *MockSendAndHandle) MakeRequest(ctx context.Context, request ...interface{}) (interface{}, error) { + args := m.Called(ctx, request) return args.Get(0), args.Error(1) } func (m *MockSendAndHandle) HandleResponse(err error, resp *http.Response, tr1Resp *Tr1d1umResponse, wholeBody bool) { @@ -116,16 +92,6 @@ func (m *MockSendAndHandle) GetRespTimeout() time.Duration { return args.Get(0).(time.Duration) } -/* Mock functions for Requester */ -type MockRequester struct { - mock.Mock -} - -func (m *MockRequester) PerformRequest(req *http.Request) (*http.Response, error) { - args := m.Called(req) - return args.Get(0).(*http.Response), args.Error(1) -} - /* Mocks for RequestValidator */ type MockRequestValidator struct { @@ -149,7 +115,7 @@ type MockRetry struct { mock.Mock } -func (m *MockRetry) Execute(op func(...interface{}) (interface{}, error), opArgs ...interface{}) (interface{}, error) { - args := m.Called(op, opArgs) +func (m *MockRetry) Execute(ctx context.Context, op func(context.Context, ...interface{}) (interface{}, error), opArgs ...interface{}) (interface{}, error) { + args := m.Called(ctx, op, opArgs) return args.Get(0), args.Error(1) } diff --git a/src/tr1d1um/retries.go b/src/tr1d1um/retries.go index 6e91580b..6e5c1aa5 100644 --- a/src/tr1d1um/retries.go +++ b/src/tr1d1um/retries.go @@ -18,6 +18,7 @@ package main import ( + "context" "errors" "time" @@ -34,7 +35,7 @@ var ( //RetryStrategy defines type RetryStrategy interface { - Execute(func(...interface{}) (interface{}, error), ...interface{}) (interface{}, error) + Execute(context.Context, func(context.Context, ...interface{}) (interface{}, error), ...interface{}) (interface{}, error) } //Retry is the realization of RetryStrategy. @@ -64,7 +65,7 @@ func (r RetryStrategyFactory) NewRetryStrategy(logger log.Logger, interval time. //Execute is the core method of the RetryStrategy. It runs a given operation on provided inputs based on // pre-defined configurations -func (r *Retry) Execute(op func(...interface{}) (interface{}, error), arguments ...interface{}) (result interface{}, err error) { +func (r *Retry) Execute(ctx context.Context, op func(context.Context, ...interface{}) (interface{}, error), arguments ...interface{}) (result interface{}, err error) { var ( debugLogger = logging.Debug(r.Logger) ) @@ -82,7 +83,7 @@ func (r *Retry) Execute(op func(...interface{}) (interface{}, error), arguments for attempt := 0; attempt < r.MaxRetries; attempt++ { debugLogger.Log(logging.MessageKey(), "Attempting operation", "attempt", attempt) - result, err = op(arguments...) + result, err = op(ctx, arguments...) if !r.ShouldRetry(result, err) { break } diff --git a/src/tr1d1um/retries_test.go b/src/tr1d1um/retries_test.go index df81aed4..a1bf2cc6 100644 --- a/src/tr1d1um/retries_test.go +++ b/src/tr1d1um/retries_test.go @@ -18,6 +18,7 @@ package main import ( + "context" "testing" "time" @@ -40,11 +41,11 @@ func TestRetryExecute(t *testing.T) { } callCount := 0 - countOp := func(_ ...interface{}) (_ interface{}, _ error) { + countOp := func(_ context.Context, _ ...interface{}) (_ interface{}, _ error) { callCount++ return } - resp, err := retry.Execute(countOp, 0) + resp, err := retry.Execute(context.TODO(), countOp, 0) assert.Nil(err) assert.Nil(resp) assert.EqualValues(retry.MaxRetries, callCount) @@ -67,12 +68,12 @@ func TestRetryExecute(t *testing.T) { } callCount := 0 - countOp := func(_ ...interface{}) (resp interface{}, _ error) { + countOp := func(_ context.Context, _ ...interface{}) (resp interface{}, _ error) { callCount++ resp = callCount return } - resp, err := retry.Execute(countOp, 0) + resp, err := retry.Execute(context.TODO(), countOp, 0) assert.Nil(err) assert.EqualValues(1, resp) assert.EqualValues(retry.MaxRetries-1, callCount) @@ -91,7 +92,7 @@ func TestRetryCheckDependencies(t *testing.T) { }, } - result, err := retry.Execute(nil, "") + result, err := retry.Execute(context.TODO(), nil, "") assert.EqualValues(-1, result) assert.EqualValues(errUndefinedShouldRetry, err) }) @@ -108,7 +109,7 @@ func TestRetryCheckDependencies(t *testing.T) { }, } - result, err := retry.Execute(nil, "") + result, err := retry.Execute(context.TODO(), nil, "") assert.EqualValues(-1, result) assert.EqualValues(errInvalidMaxRetriesVal, err) }) @@ -124,7 +125,7 @@ func TestRetryCheckDependencies(t *testing.T) { }, } - result, err := retry.Execute(nil, "") + result, err := retry.Execute(context.TODO(), nil, "") assert.EqualValues(-1, result) assert.EqualValues(errUndefinedLogger, err) }) @@ -141,7 +142,7 @@ func TestRetryCheckDependencies(t *testing.T) { }, } - result, err := retry.Execute(nil, "") + result, err := retry.Execute(context.TODO(), nil, "") assert.EqualValues(-1, result) assert.EqualValues(errUndefinedRetryOp, err) }) diff --git a/src/tr1d1um/tr1d1um.go b/src/tr1d1um/tr1d1um.go index 9b06c6e6..416d00ba 100644 --- a/src/tr1d1um/tr1d1um.go +++ b/src/tr1d1um/tr1d1um.go @@ -216,25 +216,29 @@ func SetUpHandler(v *viper.Viper, logger log.Logger) (cHandler *ConversionHandle cHandler = &ConversionHandler{ WdmpConvert: &ConversionWDMP{ - encodingHelper: &EncodingHelper{}, - WRPSource: v.GetString("WRPSource")}, - Sender: SendAndHandleFactory{}.New(respTimeout, - &ContextTimeoutRequester{&http.Client{Timeout: clientTimeout, + WRPSource: v.GetString("WRPSource")}, + + Sender: &Tr1SendAndHandle{ + RespTimeout: respTimeout, + Logger: logger, + client: &http.Client{Timeout: clientTimeout, Transport: &http.Transport{ Dial: (&net.Dialer{ Timeout: dialerTimeout, - }).Dial}}, - }, &EncodingHelper{}, logger), - EncodingHelper: &EncodingHelper{}, - Logger: logger, + }).Dial}}}, + + Logger: logger, + RequestValidator: &TR1RequestValidator{ supportedServices: getSupportedServicesMap(v.GetStringSlice(supportedServicesKey)), Logger: logger, }, + RetryStrategy: RetryStrategyFactory{}.NewRetryStrategy(logger, retryInterval, maxRetries, ShouldRetryOnResponse, OnRetryInternalFailure), WRPRequestURL: fmt.Sprintf("%s%s/device", v.GetString(targetURLKey), apiBase), - TargetURL: v.GetString(targetURLKey), + + TargetURL: v.GetString(targetURLKey), } return diff --git a/src/tr1d1um/tr1d1um_response.go b/src/tr1d1um/tr1d1um_response.go index 042748b9..62aa3747 100644 --- a/src/tr1d1um/tr1d1um_response.go +++ b/src/tr1d1um/tr1d1um_response.go @@ -17,7 +17,6 @@ package main import ( - "context" "encoding/json" "errors" "fmt" @@ -80,8 +79,10 @@ func ReportError(err error, tr1Resp *Tr1d1umResponse) { return } message, statusCode := "", http.StatusInternalServerError - if err == context.Canceled || err == context.DeadlineExceeded || - strings.Contains(err.Error(), "Client.Timeout exceeded") { + + if errMsg := err.Error(); strings.HasSuffix(errMsg, "context canceled") || + strings.HasSuffix(errMsg, "deadline exceeded") || + strings.Contains(errMsg, "Client.Timeout exceeded") { message, statusCode = "Error Timeout", Tr1StatusTimeout } diff --git a/src/tr1d1um/tr1d1um_test.go b/src/tr1d1um/tr1d1um_test.go index 399eb5ba..6e85bf68 100644 --- a/src/tr1d1um/tr1d1um_test.go +++ b/src/tr1d1um/tr1d1um_test.go @@ -55,7 +55,6 @@ func TestSetUpHandler(t *testing.T) { AssertCommon(actualHandler, assert) }) } - func TestRouteConfigurations(t *testing.T) { r := mux.NewRouter() fakePreHandler := new(alice.Chain) @@ -103,7 +102,6 @@ func TestRouteConfigurations(t *testing.T) { } AssertConfiguredRoutes(r, t, testsCases) } - func TestGetSupportedDevices(t *testing.T) { t.Run("TypicalCase", func(t *testing.T) { assert := assert.New(t) @@ -143,7 +141,6 @@ func AssertCommon(actualHandler *ConversionHandler, assert *assert.Assertions) { assert.NotEmpty(actualHandler.WRPRequestURL) assert.NotNil(actualHandler.WdmpConvert) assert.NotNil(actualHandler.Sender) - assert.NotNil(actualHandler.EncodingHelper) assert.NotNil(actualHandler.RequestValidator) assert.NotNil(actualHandler.RetryStrategy) assert.NotNil(actualHandler.Logger) From d85e6a896ef29577a720baf40f0ac7ca134d6cce Mon Sep 17 00:00:00 2001 From: Joel Unzain Date: Wed, 14 Feb 2018 16:35:53 -0800 Subject: [PATCH 2/3] More cleaning and a comment --- src/tr1d1um/communication.go | 3 --- src/tr1d1um/tr1d1um_response.go | 6 ++---- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/tr1d1um/communication.go b/src/tr1d1um/communication.go index 2c85b952..e811d061 100644 --- a/src/tr1d1um/communication.go +++ b/src/tr1d1um/communication.go @@ -37,9 +37,6 @@ type SendAndHandle interface { GetRespTimeout() time.Duration } -//SendAndHandleFactory serves as a fool-proof (you must provide all needed values for struct) initializer for SendAndHandle -type SendAndHandleFactory struct{} - //Tr1SendAndHandle provides one implementation of SendAndHandle type Tr1SendAndHandle struct { RespTimeout time.Duration diff --git a/src/tr1d1um/tr1d1um_response.go b/src/tr1d1um/tr1d1um_response.go index 62aa3747..89db32bb 100644 --- a/src/tr1d1um/tr1d1um_response.go +++ b/src/tr1d1um/tr1d1um_response.go @@ -26,10 +26,8 @@ import ( "github.com/Comcast/webpa-common/wrp" ) -//Custom TR1 HTTP Status codes -const ( - Tr1StatusTimeout = 503 -) +//Tr1StatusTimeout is a custom status representing multiple webpa-specific timeout cases (context, http.client, service unavailable) +const Tr1StatusTimeout = 503 var errUnexpectedRKDResponse = errors.New("unexpectedRDKResponse") From 71409c50191f2433d3516a388eecd12930131f42 Mon Sep 17 00:00:00 2001 From: Joel Unzain Date: Thu, 22 Feb 2018 16:15:09 -0800 Subject: [PATCH 3/3] simplify test dependency metho --- src/tr1d1um/communication_test.go | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/tr1d1um/communication_test.go b/src/tr1d1um/communication_test.go index 0b7f7c96..289f7230 100644 --- a/src/tr1d1um/communication_test.go +++ b/src/tr1d1um/communication_test.go @@ -176,12 +176,7 @@ func TestHandleResponse(t *testing.T) { Type: wrp.SimpleRequestResponseMessageType, Payload: RDKResponse} - var encodedData []byte - errEncoding := wrp.NewEncoderBytes(&encodedData, wrp.Msgpack).Encode(wrpMsg) - if errEncoding != nil { - t.Fatalf("test depency failed: %v\n", errEncoding) - } - + encodedData := wrp.MustEncode(wrpMsg, wrp.Msgpack) fakeResponse := newTestingHTTPResponse(http.StatusOK, string(encodedData)) recorder := Tr1d1umResponse{}.New() @@ -198,11 +193,7 @@ func TestHandleResponse(t *testing.T) { Type: wrp.SimpleRequestResponseMessageType, Payload: RDKResponse} - var encodedData []byte - errEncoding := wrp.NewEncoderBytes(&encodedData, wrp.Msgpack).Encode(wrpMsg) - if errEncoding != nil { - t.Fatalf("test depency failed: %v\n", errEncoding) - } + encodedData := wrp.MustEncode(wrpMsg, wrp.Msgpack) fakeResponse := newTestingHTTPResponse(http.StatusOK, string(encodedData))