github.com/mendersoftware/go-lib-micro@v0.0.0-20240304135804-e8e39c59b148/testing/response.go (about)

     1  // Copyright 2023 Northern.tech AS
     2  //
     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
     6  //
     7  //	    http://www.apache.org/licenses/LICENSE-2.0
     8  //
     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 implied.
    12  //	See the License for the specific language governing permissions and
    13  //	limitations under the License.
    14  package testing
    15  
    16  import (
    17  	"encoding/json"
    18  	"mime"
    19  	"strings"
    20  	"testing"
    21  
    22  	"github.com/ant0ine/go-json-rest/rest/test"
    23  	"github.com/stretchr/testify/assert"
    24  )
    25  
    26  func CheckResponse(t *testing.T, want ResponseChecker, have *test.Recorded) {
    27  	want.CheckStatus(t, have)
    28  	want.CheckHeaders(t, have)
    29  	want.CheckContentType(t, have)
    30  	want.CheckBody(t, have)
    31  }
    32  
    33  // ResponseChecker is a generic response checker, regardless of content-type.
    34  type ResponseChecker interface {
    35  	CheckStatus(t *testing.T, recorded *test.Recorded)
    36  	CheckHeaders(t *testing.T, recorded *test.Recorded)
    37  	CheckContentType(t *testing.T, recorded *test.Recorded)
    38  	CheckBody(t *testing.T, recorded *test.Recorded)
    39  }
    40  
    41  // BaseResponse is used for testing any response with a selected content type.
    42  // Implements ResponseChecker, provides base methods for common tests.
    43  type BaseResponse struct {
    44  	Status      int
    45  	ContentType string
    46  	Headers     map[string]string
    47  	Body        interface{}
    48  }
    49  
    50  func (b *BaseResponse) CheckStatus(t *testing.T, recorded *test.Recorded) {
    51  	recorded.CodeIs(b.Status)
    52  }
    53  
    54  func (b *BaseResponse) CheckContentType(t *testing.T, recorded *test.Recorded) {
    55  	mediaType, params, _ := mime.ParseMediaType(recorded.Recorder.HeaderMap.Get("Content-Type"))
    56  	charset := params["charset"]
    57  
    58  	if mediaType != b.ContentType {
    59  		t.Errorf(
    60  			"Content-Type media type: %s expected, got: %s",
    61  			b.ContentType,
    62  			mediaType,
    63  		)
    64  	}
    65  
    66  	if charset != "" && strings.ToUpper(charset) != "UTF-8" {
    67  		t.Errorf(
    68  			"Content-Type charset: must be empty or UTF-8, got: %s",
    69  			charset,
    70  		)
    71  	}
    72  }
    73  
    74  func (b *BaseResponse) CheckHeaders(t *testing.T, recorded *test.Recorded) {
    75  	for name, value := range b.Headers {
    76  		assert.Equal(t, value, recorded.Recorder.HeaderMap.Get(name))
    77  	}
    78  }
    79  
    80  func (b *BaseResponse) CheckBody(t *testing.T, recorded *test.Recorded) {
    81  	if b.Body != nil {
    82  		recorded.BodyIs(b.Body.(string))
    83  	}
    84  }
    85  
    86  // JSONResponse is used for testing 'application/json' responses.
    87  // Embeds the BaseResponse (implements ResponseChecker), and overrides relevant methods.
    88  type JSONResponse struct {
    89  	BaseResponse
    90  }
    91  
    92  func NewJSONResponse(status int, headers map[string]string, body interface{}) *JSONResponse {
    93  	return &JSONResponse{
    94  		BaseResponse: BaseResponse{
    95  			Status:      status,
    96  			ContentType: "application/json",
    97  			Headers:     headers,
    98  			Body:        body,
    99  		},
   100  	}
   101  }
   102  
   103  func (j *JSONResponse) CheckBody(t *testing.T, recorded *test.Recorded) {
   104  	if j.Body != nil {
   105  		assert.NotEmpty(t, recorded.Recorder.Body.String())
   106  		expected, err := json.Marshal(j.Body)
   107  		assert.NoError(t, err)
   108  		assert.JSONEq(t, string(expected), recorded.Recorder.Body.String())
   109  	} else {
   110  		assert.Empty(t, recorded.Recorder.Body.String())
   111  	}
   112  }