github.com/artisanhe/tools@v1.0.1-0.20210607022958-19a8fef2eb04/httplib/trans_to_req_test.go (about) 1 package httplib 2 3 import ( 4 "io/ioutil" 5 "mime/multipart" 6 "testing" 7 8 "github.com/stretchr/testify/assert" 9 10 "github.com/artisanhe/tools/courier/status_error" 11 "github.com/artisanhe/tools/courier/transport_http/transform" 12 "github.com/artisanhe/tools/httplib/testify" 13 "github.com/artisanhe/tools/timelib" 14 "github.com/artisanhe/tools/validate" 15 ) 16 17 func v_ok(v interface{}) (bool, string) { 18 return v.(bool), "not ok" 19 } 20 21 func v_data(v interface{}) (bool, string) { 22 return v.(int32) == int32(1), "invalid data" 23 } 24 25 func init() { 26 validate.AddValidateFunc("v_ok", v_ok) 27 validate.AddValidateFunc("v_data", v_data) 28 } 29 30 type SimpleModel struct { 31 Data int32 `json:"data" validate:"v_data"` 32 } 33 34 type SimpleReqBodyBasic struct { 35 Name string `json:"name" default:""` 36 ID uint64 `json:"id"` 37 } 38 39 type SimpleReqBody struct { 40 SimpleReqBodyBasic 41 Price float32 `json:"price" default:"0.1"` 42 OK bool `json:"ok" validate:"v_ok" default:"false"` 43 Models []SimpleModel `json:"models"` 44 V int32 `json:"v" default:"1"` 45 D string `json:"d" default:"abc"` 46 G uint32 `json:"g" default:"2"` 47 Time *timelib.MySQLTimestamp `json:"time" default:""` 48 } 49 50 type CommonReq struct { 51 ObjID uint64 `name:"obj_id" in:"path"` 52 ObjName string `name:"obj_name" in:"query"` 53 } 54 55 type Ctx struct { 56 C string 57 } 58 59 type SimpleReq struct { 60 CommonReq 61 Ctx *Ctx `name:"ctx" in:"context"` 62 Body SimpleReqBody `in:"body"` 63 ID uint `name:"id" in:"query"` 64 IntSlice []uint64 `name:"int_slice" in:"query" default:""` 65 StrSlice []string `name:"str_slice" in:"query" default:""` 66 FloatSlice []float64 `name:"float_slice" in:"query" default:""` 67 ObjFloat float32 `name:"obj_float" in:"path"` 68 ObjBool bool `name:"obj_bool" in:"path"` 69 HID uint `name:"h_id" in:"header" default:"0"` 70 HName string `name:"h_name" in:"header" default:""` 71 HFloat float64 `name:"h_float" in:"header" default:"0.0"` 72 HBool bool `name:"h_bool" in:"header" default:"false"` 73 } 74 75 func TestTrans(t *testing.T) { 76 tt := assert.New(t) 77 78 expectedReq := SimpleReq{ 79 Ctx: &Ctx{ 80 C: "12123", 81 }, 82 Body: SimpleReqBody{ 83 SimpleReqBodyBasic: SimpleReqBodyBasic{ 84 Name: "a", 85 ID: 1, 86 }, 87 Price: 0.2, 88 OK: true, 89 V: 1, 90 D: "abc", 91 G: 2, 92 Models: []SimpleModel{ 93 { 94 Data: 1, 95 }, 96 { 97 Data: 1, 98 }, 99 { 100 Data: 1, 101 }, 102 }, 103 }, 104 CommonReq: CommonReq{ 105 ObjID: 123, 106 ObjName: "aaa", 107 }, 108 ID: 1, 109 IntSlice: []uint64{1, 2, 3}, 110 StrSlice: []string{"a", "b", "c"}, 111 FloatSlice: []float64{1.1, 1.2, 1.3}, 112 ObjFloat: 12.2, 113 ObjBool: true, 114 HID: 1, 115 HName: "bc", 116 HBool: true, 117 HFloat: 1.2, 118 } 119 120 { 121 c := testify.NewContext("POST", "/:obj_id/:obj_float/:obj_bool/", expectedReq) 122 123 req := SimpleReq{} 124 err := TransToReq(c, &req) 125 tt.NoError(err) 126 tt.Equal(expectedReq, req) 127 } 128 129 { 130 expectedReq.Body.ID = 0 131 expectedReq.Body.Models[1].Data = 2 132 expectedReq.ObjFloat = 0 133 expectedReq.Body.OK = false 134 135 c := testify.NewContext("POST", "/:obj_id/:obj_float/:obj_bool/", expectedReq) 136 137 req := SimpleReq{} 138 err := TransToReq(c, &req) 139 140 tt.Equal(status_error.ErrorFields{ 141 { 142 Field: "id", 143 Msg: "缺失必填字段", 144 In: "body", 145 }, 146 { 147 Field: "models[1].data", 148 Msg: "invalid data", 149 In: "body", 150 }, 151 { 152 Field: "obj_float", 153 Msg: "缺失必填字段", 154 In: "path", 155 }, 156 { 157 Field: "ok", 158 Msg: "not ok", 159 In: "body", 160 }, 161 }, status_error.FromError(err).ErrorFields.Sort()) 162 } 163 } 164 165 type Counter struct { 166 Total int32 `json:"total" in:"query" default:"0"` 167 } 168 169 func (c Counter) ValidateTotal() string { 170 if c.Total > 1 { 171 return "total too large" 172 } 173 return "" 174 } 175 176 type Req struct { 177 Counter 178 Pager 179 CreateTimeRange 180 Body Counter `in:"body"` 181 } 182 183 func (r Req) ValidateCreateStartTime() string { 184 return "CreateStartTime Error" 185 } 186 187 func TestTransToReqWithValidateHook(t *testing.T) { 188 tt := assert.New(t) 189 190 expectedReq := Req{} 191 expectedReq.Total = 4 192 expectedReq.Body.Total = 4 193 expectedReq.CreateStartTime, _ = timelib.ParseMySQLTimestampFromString("2017-01-01T20:00:00.000Z") 194 expectedReq.CreateEndTime, _ = timelib.ParseMySQLTimestampFromString("2017-01-01T09:00:00.000Z") 195 196 c := testify.NewContext("POST", "/", expectedReq) 197 198 reqWithReqGroupForValid := Req{} 199 200 err := TransToReq(c, &reqWithReqGroupForValid) 201 202 if err != nil { 203 tt.Equal(status_error.ErrorFields{ 204 { 205 Field: "createEndTime", 206 Msg: "终止时间不得小于开始时间", 207 In: "query", 208 }, 209 { 210 Field: "createStartTime", 211 Msg: "CreateStartTime Error", 212 In: "query", 213 }, 214 { 215 Field: "total", 216 Msg: "total too large", 217 In: "query", 218 }, 219 { 220 Field: "total", 221 Msg: "total too large", 222 In: "body", 223 }, 224 }, status_error.FromError(err).ErrorFields.Sort()) 225 } 226 } 227 228 type SingleFormFile struct { 229 FormData struct { 230 SingleFile *multipart.FileHeader `name:"singleFile"` 231 } `in:"formData,multipart"` 232 } 233 234 func TestTransSingleFormFile(t *testing.T) { 235 tt := assert.New(t) 236 237 req := SingleFormFile{} 238 req.FormData.SingleFile, _ = transform.NewFileHeader("singleFile", "SingleFile", []byte("1,2,3,4")) 239 240 c := testify.NewContext("POST", "/", req) 241 r := SingleFormFile{} 242 err := TransToReq(c, &r) 243 tt.Nil(err) 244 245 actualFile, _ := r.FormData.SingleFile.Open() 246 actualBytes, _ := ioutil.ReadAll(actualFile) 247 tt.Equal([]byte("1,2,3,4"), actualBytes) 248 } 249 250 type MultiFormFile struct { 251 FormData struct { 252 FirstFile *multipart.FileHeader `json:"firstFile"` 253 SecondFile *multipart.FileHeader `json:"secondFile"` 254 } `in:"formData,multipart"` 255 } 256 257 func TestTransMultiFormFile(t *testing.T) { 258 tt := assert.New(t) 259 260 req := MultiFormFile{} 261 req.FormData.FirstFile, _ = transform.NewFileHeader("firstFile", "SingleFile", []byte("1")) 262 req.FormData.SecondFile, _ = transform.NewFileHeader("secondFile", "SecondFile", []byte("2")) 263 264 c := testify.NewContext("POST", "/", req) 265 r := MultiFormFile{} 266 err := TransToReq(c, &r) 267 tt.Nil(err) 268 269 { 270 actualFile, _ := r.FormData.FirstFile.Open() 271 actualBytes, _ := ioutil.ReadAll(actualFile) 272 tt.Equal([]byte("1"), actualBytes) 273 } 274 275 { 276 actualFile, _ := r.FormData.SecondFile.Open() 277 actualBytes, _ := ioutil.ReadAll(actualFile) 278 tt.Equal([]byte("2"), actualBytes) 279 } 280 }