| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165 |
- package minio
- import (
- "bytes"
- "encoding/json"
- "mime/multipart"
- "net/http"
- "net/http/httptest"
- "testing"
- "perms-system-server/internal/config"
- "perms-system-server/internal/response"
- "perms-system-server/internal/svc"
- "perms-system-server/internal/testutil"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
- )
- func init() {
- response.Setup()
- }
- func newMinioTestSvcCtx() *svc.ServiceContext {
- cfg := testutil.GetTestConfig()
- cfg.Minio = config.MinioConf{
- Name: "test-minio",
- AccessKeyId: "test",
- AccessKeySecret: "test",
- Endpoint: "",
- Domain: "https://minio.test.com",
- UseSSL: false,
- FileType: map[string]config.MinioFileTypeConf{
- "avatar": {
- Bucket: "perms-system",
- Dir: "avatar/{yyyy}/{mm}/{dd}",
- AllowedContentTypes: []string{"image/jpeg", "image/png"},
- },
- "any": {
- Bucket: "perms-system",
- Dir: "any",
- AllowedContentTypes: []string{},
- },
- },
- }
- return svc.NewServiceContext(cfg)
- }
- func createMultipartRequest(t *testing.T, fileType, contentType, fileName string, fileContent []byte) *http.Request {
- t.Helper()
- body := &bytes.Buffer{}
- writer := multipart.NewWriter(body)
- if fileType != "" {
- writer.WriteField("fileType", fileType)
- }
- if fileName != "" {
- part, err := writer.CreateFormFile("file", fileName)
- require.NoError(t, err)
- _, err = part.Write(fileContent)
- require.NoError(t, err)
- }
- writer.Close()
- req := httptest.NewRequest(http.MethodPost, "/api/minio/upload", body)
- req.Header.Set("Content-Type", writer.FormDataContentType())
- if contentType != "" && fileName != "" {
- // multipart Content-Type is set in the part header by CreateFormFile;
- // to override it, we need to use CreatePart directly
- // For simplicity, handler reads Content-Type from the fileHeader which defaults to application/octet-stream
- // So we rebuild with explicit content type
- body2 := &bytes.Buffer{}
- writer2 := multipart.NewWriter(body2)
- if fileType != "" {
- writer2.WriteField("fileType", fileType)
- }
- h := make(map[string][]string)
- h["Content-Disposition"] = []string{`form-data; name="file"; filename="` + fileName + `"`}
- h["Content-Type"] = []string{contentType}
- part2, err := writer2.CreatePart(h)
- require.NoError(t, err)
- _, err = part2.Write(fileContent)
- require.NoError(t, err)
- writer2.Close()
- req = httptest.NewRequest(http.MethodPost, "/api/minio/upload", body2)
- req.Header.Set("Content-Type", writer2.FormDataContentType())
- }
- return req
- }
- // TC-1249: handler 缺少 file 字段
- func TestMinioUploadHandler_MissingFile(t *testing.T) {
- svcCtx := newMinioTestSvcCtx()
- handler := MinioUploadHandler(svcCtx)
- body := &bytes.Buffer{}
- writer := multipart.NewWriter(body)
- writer.WriteField("fileType", "avatar")
- writer.Close()
- req := httptest.NewRequest(http.MethodPost, "/api/minio/upload", body)
- req.Header.Set("Content-Type", writer.FormDataContentType())
- rr := httptest.NewRecorder()
- handler.ServeHTTP(rr, req)
- var respBody response.Body
- err := json.Unmarshal(rr.Body.Bytes(), &respBody)
- require.NoError(t, err)
- assert.False(t, respBody.Success)
- }
- // TC-1242: fileType 为空 → 400
- func TestMinioUploadHandler_EmptyFileType(t *testing.T) {
- svcCtx := newMinioTestSvcCtx()
- handler := MinioUploadHandler(svcCtx)
- req := createMultipartRequest(t, "", "image/png", "test.png", []byte("fake png content"))
- rr := httptest.NewRecorder()
- handler.ServeHTTP(rr, req)
- var respBody response.Body
- err := json.Unmarshal(rr.Body.Bytes(), &respBody)
- require.NoError(t, err)
- assert.False(t, respBody.Success)
- assert.Equal(t, 400, respBody.ErrorCode)
- assert.Contains(t, respBody.ErrorMessage, "fileType is required")
- }
- // TC-1243: fileType 不在配置中 → 400
- func TestMinioUploadHandler_UnknownFileType(t *testing.T) {
- svcCtx := newMinioTestSvcCtx()
- handler := MinioUploadHandler(svcCtx)
- req := createMultipartRequest(t, "unknown_type", "image/png", "test.png", []byte("fake content"))
- rr := httptest.NewRecorder()
- handler.ServeHTTP(rr, req)
- var respBody response.Body
- err := json.Unmarshal(rr.Body.Bytes(), &respBody)
- require.NoError(t, err)
- assert.False(t, respBody.Success)
- assert.Equal(t, 400, respBody.ErrorCode)
- assert.Contains(t, respBody.ErrorMessage, "fileType not configured")
- }
- // TC-1244: Content-Type 不在白名单中 → 400
- func TestMinioUploadHandler_InvalidContentType(t *testing.T) {
- svcCtx := newMinioTestSvcCtx()
- handler := MinioUploadHandler(svcCtx)
- req := createMultipartRequest(t, "avatar", "application/zip", "test.zip", []byte("fake zip content"))
- rr := httptest.NewRecorder()
- handler.ServeHTTP(rr, req)
- var respBody response.Body
- err := json.Unmarshal(rr.Body.Bytes(), &respBody)
- require.NoError(t, err)
- assert.False(t, respBody.Success)
- assert.Equal(t, 400, respBody.ErrorCode)
- assert.Contains(t, respBody.ErrorMessage, "invalid contentType")
- }
|