github.com/shoshinnikita/budget-manager@v0.7.1-0.20220131195411-8c46ff1c6778/tests/request.go (about)

     1  package tests
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"io"
     7  	"io/ioutil"
     8  	"net/http"
     9  	"net/url"
    10  	"reflect"
    11  	"testing"
    12  
    13  	"github.com/stretchr/testify/require"
    14  
    15  	"github.com/ShoshinNikita/budget-manager/internal/web/api/models"
    16  	"github.com/ShoshinNikita/budget-manager/internal/web/utils/schema"
    17  )
    18  
    19  type Path string
    20  
    21  const (
    22  	IncomesPath         Path = "/api/incomes"
    23  	MonthlyPaymentsPath Path = "/api/monthly-payments"
    24  	SpendsPath          Path = "/api/spends"
    25  	SpendTypesPath      Path = "/api/spend-types"
    26  	SearchSpendsPath    Path = "/api/search/spends"
    27  	MonthsPath          Path = "/api/months/date"
    28  )
    29  
    30  type Method string
    31  
    32  const (
    33  	GET    Method = http.MethodGet
    34  	HEAD   Method = http.MethodHead
    35  	POST   Method = http.MethodPost
    36  	PUT    Method = http.MethodPut
    37  	DELETE Method = http.MethodDelete
    38  )
    39  
    40  type RequestOK struct {
    41  	Method  Method
    42  	Path    Path
    43  	Request interface{}
    44  }
    45  
    46  func (r RequestOK) Send(t *testing.T, host string, resp interface{}) {
    47  	Request{r.Method, r.Path, r.Request, http.StatusOK, ""}.Send(t, host, resp)
    48  }
    49  
    50  type RequestCreated struct {
    51  	Method  Method
    52  	Path    Path
    53  	Request interface{}
    54  }
    55  
    56  func (r RequestCreated) Send(t *testing.T, host string, resp interface{}) {
    57  	Request{r.Method, r.Path, r.Request, http.StatusCreated, ""}.Send(t, host, resp)
    58  }
    59  
    60  type Request struct {
    61  	Method  Method
    62  	Path    Path
    63  	Request interface{}
    64  
    65  	StatusCode int
    66  	Err        string
    67  }
    68  
    69  func (r Request) Send(t *testing.T, host string, resp interface{}) {
    70  	statusCode, body := r.send(t, http.DefaultClient, host)
    71  
    72  	r.checkResponse(t, statusCode, body, resp)
    73  }
    74  
    75  func (r Request) send(t *testing.T, client *http.Client, host string) (statusCode int, respBody []byte) {
    76  	require := require.New(t)
    77  
    78  	u := &url.URL{
    79  		Scheme: "http",
    80  		Host:   host,
    81  		Path:   string(r.Path),
    82  	}
    83  
    84  	var body io.Reader
    85  	if r.Request != nil {
    86  		switch r.Method {
    87  		case GET, HEAD:
    88  			query := url.Values{}
    89  
    90  			err := schema.Encode(r.Request, query)
    91  			require.NoError(err, "couldn't prepare query")
    92  
    93  			u.RawQuery = query.Encode()
    94  
    95  		default:
    96  			buf := &bytes.Buffer{}
    97  
    98  			err := json.NewEncoder(buf).Encode(r.Request)
    99  			require.NoError(err, "couldn't prepare body")
   100  
   101  			body = buf
   102  		}
   103  	}
   104  
   105  	req, cancel := newRequest(t, r.Method, u.String(), body)
   106  	defer cancel()
   107  
   108  	resp, err := client.Do(req)
   109  	require.NoError(err, "request failed")
   110  	defer resp.Body.Close()
   111  
   112  	contentTypeHeader := resp.Header.Get("Content-Type")
   113  	require.Equal("application/json", contentTypeHeader, "wrong Content-Type header")
   114  
   115  	respBody, err = ioutil.ReadAll(resp.Body)
   116  	require.NoError(err, "couldn't read body")
   117  
   118  	return resp.StatusCode, respBody
   119  }
   120  
   121  func (r Request) checkResponse(t *testing.T, statusCode int, body []byte, customResp interface{}) {
   122  	require := require.New(t)
   123  
   124  	var basicResp models.BaseResponse
   125  
   126  	err := json.Unmarshal(body, &basicResp)
   127  	require.NoError(err, "couldn't decode basic response")
   128  	require.NotEqual("", basicResp.RequestID)
   129  	require.Equal(r.Err, basicResp.Error)
   130  	require.Equal(r.Err == "", basicResp.Success)
   131  	require.Equal(r.StatusCode, statusCode)
   132  
   133  	if customResp != nil {
   134  		err = json.Unmarshal(body, customResp)
   135  		require.NoErrorf(err, "couldn't decode passed response of type %T", customResp)
   136  
   137  		resetRequestID(customResp)
   138  	}
   139  }
   140  
   141  func resetRequestID(resp interface{}) {
   142  	value := reflect.ValueOf(resp)
   143  	if value.Kind() == reflect.Ptr {
   144  		value = value.Elem()
   145  	}
   146  	if value.Kind() != reflect.Struct {
   147  		return
   148  	}
   149  
   150  	reqID := value.FieldByName("RequestID")
   151  	if !reqID.IsValid() {
   152  		return
   153  	}
   154  	if reqID.Kind() != reflect.String {
   155  		return
   156  	}
   157  
   158  	reqID.SetString("")
   159  }