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 }