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") }