github.com/wangyougui/gf/v2@v2.6.5/net/ghttp/ghttp_z_unit_feature_request_file_test.go (about) 1 // Copyright GoFrame Author(https://goframe.org). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/wangyougui/gf. 6 7 package ghttp_test 8 9 import ( 10 "context" 11 "fmt" 12 "strings" 13 "testing" 14 "time" 15 16 "github.com/wangyougui/gf/v2/internal/json" 17 18 "github.com/wangyougui/gf/v2/frame/g" 19 "github.com/wangyougui/gf/v2/net/ghttp" 20 "github.com/wangyougui/gf/v2/os/gfile" 21 "github.com/wangyougui/gf/v2/os/gtime" 22 "github.com/wangyougui/gf/v2/test/gtest" 23 "github.com/wangyougui/gf/v2/text/gstr" 24 "github.com/wangyougui/gf/v2/util/gmeta" 25 "github.com/wangyougui/gf/v2/util/guid" 26 ) 27 28 func Test_Params_File_Single(t *testing.T) { 29 dstDirPath := gfile.Temp(gtime.TimestampNanoStr()) 30 s := g.Server(guid.S()) 31 s.BindHandler("/upload/single", func(r *ghttp.Request) { 32 file := r.GetUploadFile("file") 33 if file == nil { 34 r.Response.WriteExit("upload file cannot be empty") 35 } 36 37 if name, err := file.Save(dstDirPath, r.Get("randomlyRename").Bool()); err == nil { 38 r.Response.WriteExit(name) 39 } 40 r.Response.WriteExit("upload failed") 41 }) 42 s.SetDumpRouterMap(false) 43 s.Start() 44 defer s.Shutdown() 45 time.Sleep(100 * time.Millisecond) 46 // normal name 47 gtest.C(t, func(t *gtest.T) { 48 client := g.Client() 49 client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort())) 50 51 srcPath := gtest.DataPath("upload", "file1.txt") 52 dstPath := gfile.Join(dstDirPath, "file1.txt") 53 content := client.PostContent(ctx, "/upload/single", g.Map{ 54 "file": "@file:" + srcPath, 55 }) 56 t.AssertNE(content, "") 57 t.AssertNE(content, "upload file cannot be empty") 58 t.AssertNE(content, "upload failed") 59 t.Assert(content, "file1.txt") 60 t.Assert(gfile.GetContents(dstPath), gfile.GetContents(srcPath)) 61 }) 62 // randomly rename. 63 gtest.C(t, func(t *gtest.T) { 64 client := g.Client() 65 client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort())) 66 67 srcPath := gtest.DataPath("upload", "file2.txt") 68 content := client.PostContent(ctx, "/upload/single", g.Map{ 69 "file": "@file:" + srcPath, 70 "randomlyRename": true, 71 }) 72 dstPath := gfile.Join(dstDirPath, content) 73 t.AssertNE(content, "") 74 t.AssertNE(content, "upload file cannot be empty") 75 t.AssertNE(content, "upload failed") 76 t.Assert(gfile.GetContents(dstPath), gfile.GetContents(srcPath)) 77 }) 78 } 79 80 func Test_Params_File_CustomName(t *testing.T) { 81 dstDirPath := gfile.Temp(gtime.TimestampNanoStr()) 82 s := g.Server(guid.S()) 83 s.BindHandler("/upload/single", func(r *ghttp.Request) { 84 file := r.GetUploadFile("file") 85 if file == nil { 86 r.Response.WriteExit("upload file cannot be empty") 87 } 88 file.Filename = "my.txt" 89 if name, err := file.Save(dstDirPath, r.Get("randomlyRename").Bool()); err == nil { 90 r.Response.WriteExit(name) 91 } 92 r.Response.WriteExit("upload failed") 93 }) 94 s.SetDumpRouterMap(false) 95 s.Start() 96 defer s.Shutdown() 97 time.Sleep(100 * time.Millisecond) 98 gtest.C(t, func(t *gtest.T) { 99 client := g.Client() 100 client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort())) 101 102 srcPath := gtest.DataPath("upload", "file1.txt") 103 dstPath := gfile.Join(dstDirPath, "my.txt") 104 content := client.PostContent(ctx, "/upload/single", g.Map{ 105 "file": "@file:" + srcPath, 106 }) 107 t.AssertNE(content, "") 108 t.AssertNE(content, "upload file cannot be empty") 109 t.AssertNE(content, "upload failed") 110 t.Assert(content, "my.txt") 111 t.Assert(gfile.GetContents(dstPath), gfile.GetContents(srcPath)) 112 }) 113 } 114 115 func Test_Params_File_Batch(t *testing.T) { 116 dstDirPath := gfile.Temp(gtime.TimestampNanoStr()) 117 s := g.Server(guid.S()) 118 s.BindHandler("/upload/batch", func(r *ghttp.Request) { 119 files := r.GetUploadFiles("file") 120 if files == nil { 121 r.Response.WriteExit("upload file cannot be empty") 122 } 123 if names, err := files.Save(dstDirPath, r.Get("randomlyRename").Bool()); err == nil { 124 r.Response.WriteExit(gstr.Join(names, ",")) 125 } 126 r.Response.WriteExit("upload failed") 127 }) 128 s.SetDumpRouterMap(false) 129 s.Start() 130 defer s.Shutdown() 131 time.Sleep(100 * time.Millisecond) 132 // normal name 133 gtest.C(t, func(t *gtest.T) { 134 client := g.Client() 135 client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort())) 136 137 srcPath1 := gtest.DataPath("upload", "file1.txt") 138 srcPath2 := gtest.DataPath("upload", "file2.txt") 139 dstPath1 := gfile.Join(dstDirPath, "file1.txt") 140 dstPath2 := gfile.Join(dstDirPath, "file2.txt") 141 content := client.PostContent(ctx, "/upload/batch", g.Map{ 142 "file[0]": "@file:" + srcPath1, 143 "file[1]": "@file:" + srcPath2, 144 }) 145 t.AssertNE(content, "") 146 t.AssertNE(content, "upload file cannot be empty") 147 t.AssertNE(content, "upload failed") 148 t.Assert(content, "file1.txt,file2.txt") 149 t.Assert(gfile.GetContents(dstPath1), gfile.GetContents(srcPath1)) 150 t.Assert(gfile.GetContents(dstPath2), gfile.GetContents(srcPath2)) 151 }) 152 // randomly rename. 153 gtest.C(t, func(t *gtest.T) { 154 client := g.Client() 155 client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort())) 156 157 srcPath1 := gtest.DataPath("upload", "file1.txt") 158 srcPath2 := gtest.DataPath("upload", "file2.txt") 159 content := client.PostContent(ctx, "/upload/batch", g.Map{ 160 "file[0]": "@file:" + srcPath1, 161 "file[1]": "@file:" + srcPath2, 162 "randomlyRename": true, 163 }) 164 t.AssertNE(content, "") 165 t.AssertNE(content, "upload file cannot be empty") 166 t.AssertNE(content, "upload failed") 167 168 array := gstr.SplitAndTrim(content, ",") 169 t.Assert(len(array), 2) 170 dstPath1 := gfile.Join(dstDirPath, array[0]) 171 dstPath2 := gfile.Join(dstDirPath, array[1]) 172 t.Assert(gfile.GetContents(dstPath1), gfile.GetContents(srcPath1)) 173 t.Assert(gfile.GetContents(dstPath2), gfile.GetContents(srcPath2)) 174 }) 175 } 176 177 func Test_Params_Strict_Route_File_Single_Ptr_Attrr(t *testing.T) { 178 type Req struct { 179 gmeta.Meta `method:"post" mime:"multipart/form-data"` 180 File *ghttp.UploadFile `type:"file"` 181 } 182 type Res struct{} 183 184 dstDirPath := gfile.Temp(gtime.TimestampNanoStr()) 185 s := g.Server(guid.S()) 186 s.BindHandler("/upload/single", func(ctx context.Context, req *Req) (res *Res, err error) { 187 var ( 188 r = g.RequestFromCtx(ctx) 189 file = req.File 190 ) 191 if file == nil { 192 r.Response.WriteExit("upload file cannot be empty") 193 } 194 name, err := file.Save(dstDirPath) 195 if err != nil { 196 r.Response.WriteExit(err) 197 } 198 r.Response.WriteExit(name) 199 return 200 }) 201 s.SetDumpRouterMap(false) 202 s.Start() 203 defer s.Shutdown() 204 time.Sleep(100 * time.Millisecond) 205 // normal name 206 gtest.C(t, func(t *gtest.T) { 207 client := g.Client() 208 client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort())) 209 210 srcPath := gtest.DataPath("upload", "file1.txt") 211 dstPath := gfile.Join(dstDirPath, "file1.txt") 212 content := client.PostContent(ctx, "/upload/single", g.Map{ 213 "file": "@file:" + srcPath, 214 }) 215 t.AssertNE(content, "") 216 t.AssertNE(content, "upload file cannot be empty") 217 t.AssertNE(content, "upload failed") 218 t.Assert(content, "file1.txt") 219 t.Assert(gfile.GetContents(dstPath), gfile.GetContents(srcPath)) 220 }) 221 } 222 223 func Test_Params_Strict_Route_File_Single_Struct_Attr(t *testing.T) { 224 type Req struct { 225 gmeta.Meta `method:"post" mime:"multipart/form-data"` 226 File ghttp.UploadFile `type:"file"` 227 } 228 type Res struct{} 229 230 dstDirPath := gfile.Temp(gtime.TimestampNanoStr()) 231 s := g.Server(guid.S()) 232 s.BindHandler("/upload/single", func(ctx context.Context, req *Req) (res *Res, err error) { 233 var ( 234 r = g.RequestFromCtx(ctx) 235 file = req.File 236 ) 237 name, err := file.Save(dstDirPath) 238 if err != nil { 239 r.Response.WriteExit(err) 240 } 241 r.Response.WriteExit(name) 242 return 243 }) 244 s.SetDumpRouterMap(false) 245 s.Start() 246 defer s.Shutdown() 247 time.Sleep(100 * time.Millisecond) 248 // normal name 249 gtest.C(t, func(t *gtest.T) { 250 client := g.Client() 251 client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort())) 252 253 srcPath := gtest.DataPath("upload", "file1.txt") 254 dstPath := gfile.Join(dstDirPath, "file1.txt") 255 content := client.PostContent(ctx, "/upload/single", g.Map{ 256 "file": "@file:" + srcPath, 257 }) 258 t.AssertNE(content, "") 259 t.AssertNE(content, "upload failed") 260 t.Assert(content, "file1.txt") 261 t.Assert(gfile.GetContents(dstPath), gfile.GetContents(srcPath)) 262 }) 263 } 264 265 func Test_Params_File_Upload_Required(t *testing.T) { 266 type Req struct { 267 gmeta.Meta `method:"post" mime:"multipart/form-data"` 268 File *ghttp.UploadFile `type:"file" v:"required#upload file is required"` 269 } 270 type Res struct{} 271 272 s := g.Server(guid.S()) 273 s.Use(ghttp.MiddlewareHandlerResponse) 274 s.BindHandler("/upload/required", func(ctx context.Context, req *Req) (res *Res, err error) { 275 return 276 }) 277 s.SetDumpRouterMap(false) 278 s.Start() 279 defer s.Shutdown() 280 time.Sleep(100 * time.Millisecond) 281 // file is empty 282 gtest.C(t, func(t *gtest.T) { 283 client := g.Client() 284 client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort())) 285 content := client.PostContent(ctx, "/upload/required") 286 t.Assert(content, `{"code":51,"message":"upload file is required","data":null}`) 287 }) 288 } 289 290 func Test_Params_File_MarshalJSON(t *testing.T) { 291 s := g.Server(guid.S()) 292 s.BindHandler("/upload/single", func(r *ghttp.Request) { 293 file := r.GetUploadFile("file") 294 if file == nil { 295 r.Response.WriteExit("upload file cannot be empty") 296 } 297 298 if bytes, err := json.Marshal(file); err != nil { 299 r.Response.WriteExit(err) 300 } else { 301 r.Response.WriteExit(bytes) 302 } 303 }) 304 s.SetDumpRouterMap(false) 305 s.Start() 306 defer s.Shutdown() 307 time.Sleep(100 * time.Millisecond) 308 // normal name 309 gtest.C(t, func(t *gtest.T) { 310 client := g.Client() 311 client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort())) 312 313 srcPath := gtest.DataPath("upload", "file1.txt") 314 content := client.PostContent(ctx, "/upload/single", g.Map{ 315 "file": "@file:" + srcPath, 316 }) 317 t.Assert(strings.Contains(content, "file1.txt"), true) 318 }) 319 } 320 321 // Select only one file when batch uploading 322 func Test_Params_Strict_Route_File_Batch_Up_One(t *testing.T) { 323 type Req struct { 324 gmeta.Meta `method:"post" mime:"multipart/form-data"` 325 Files ghttp.UploadFiles `type:"file"` 326 } 327 type Res struct{} 328 329 dstDirPath := gfile.Temp(gtime.TimestampNanoStr()) 330 s := g.Server(guid.S()) 331 s.BindHandler("/upload/batch", func(ctx context.Context, req *Req) (res *Res, err error) { 332 var ( 333 r = g.RequestFromCtx(ctx) 334 files = req.Files 335 ) 336 if len(files) == 0 { 337 r.Response.WriteExit("upload file cannot be empty") 338 } 339 names, err := files.Save(dstDirPath) 340 if err != nil { 341 r.Response.WriteExit(err) 342 } 343 r.Response.WriteExit(gstr.Join(names, ",")) 344 return 345 }) 346 s.SetDumpRouterMap(false) 347 s.Start() 348 defer s.Shutdown() 349 time.Sleep(100 * time.Millisecond) 350 // normal name 351 gtest.C(t, func(t *gtest.T) { 352 client := g.Client() 353 client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort())) 354 355 srcPath := gtest.DataPath("upload", "file1.txt") 356 dstPath := gfile.Join(dstDirPath, "file1.txt") 357 content := client.PostContent(ctx, "/upload/batch", g.Map{ 358 "files": "@file:" + srcPath, 359 }) 360 t.AssertNE(content, "") 361 t.AssertNE(content, "upload file cannot be empty") 362 t.AssertNE(content, "upload failed") 363 t.Assert(content, "file1.txt") 364 t.Assert(gfile.GetContents(dstPath), gfile.GetContents(srcPath)) 365 }) 366 } 367 368 // Select multiple files during batch upload 369 func Test_Params_Strict_Route_File_Batch_Up_Multiple(t *testing.T) { 370 type Req struct { 371 gmeta.Meta `method:"post" mime:"multipart/form-data"` 372 Files ghttp.UploadFiles `type:"file"` 373 } 374 type Res struct{} 375 376 dstDirPath := gfile.Temp(gtime.TimestampNanoStr()) 377 s := g.Server(guid.S()) 378 s.BindHandler("/upload/batch", func(ctx context.Context, req *Req) (res *Res, err error) { 379 var ( 380 r = g.RequestFromCtx(ctx) 381 files = req.Files 382 ) 383 if len(files) == 0 { 384 r.Response.WriteExit("upload file cannot be empty") 385 } 386 names, err := files.Save(dstDirPath) 387 if err != nil { 388 r.Response.WriteExit(err) 389 } 390 r.Response.WriteExit(gstr.Join(names, ",")) 391 return 392 }) 393 s.SetDumpRouterMap(false) 394 s.Start() 395 defer s.Shutdown() 396 time.Sleep(100 * time.Millisecond) 397 // normal name 398 gtest.C(t, func(t *gtest.T) { 399 client := g.Client() 400 client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort())) 401 402 srcPath1 := gtest.DataPath("upload", "file1.txt") 403 srcPath2 := gtest.DataPath("upload", "file2.txt") 404 dstPath1 := gfile.Join(dstDirPath, "file1.txt") 405 dstPath2 := gfile.Join(dstDirPath, "file2.txt") 406 content := client.PostContent(ctx, "/upload/batch", 407 "files=@file:"+srcPath1+ 408 "&files=@file:"+srcPath2, 409 ) 410 t.AssertNE(content, "") 411 t.AssertNE(content, "upload file cannot be empty") 412 t.AssertNE(content, "upload failed") 413 t.Assert(content, "file1.txt,file2.txt") 414 t.Assert(gfile.GetContents(dstPath1), gfile.GetContents(srcPath1)) 415 t.Assert(gfile.GetContents(dstPath2), gfile.GetContents(srcPath2)) 416 }) 417 }