Files
goauto/server/app/goauto/sybinnercode/handler_test.go
T

111 lines
4.0 KiB
Go

package sybinnercode
import (
"bytes"
"encoding/json"
"mime/multipart"
"net/http"
"net/http/httptest"
"testing"
"github.com/gin-gonic/gin"
jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
"github.com/google/uuid"
)
func importRequest(t *testing.T, field, filename string, content []byte) (*http.Request, string) {
t.Helper()
var body bytes.Buffer
writer := multipart.NewWriter(&body)
part, err := writer.CreateFormFile(field, filename)
if err != nil {
t.Fatal(err)
}
if _, err := part.Write(content); err != nil {
t.Fatal(err)
}
if err := writer.WriteField("requestId", uuid.NewString()); err != nil {
t.Fatal(err)
}
if err := writer.Close(); err != nil {
t.Fatal(err)
}
request := httptest.NewRequest(http.MethodPost, "/import", &body)
request.Header.Set("Content-Type", writer.FormDataContentType())
return request, writer.FormDataContentType()
}
func performImport(t *testing.T, request *http.Request) *httptest.ResponseRecorder {
t.Helper()
gin.SetMode(gin.TestMode)
recorder := httptest.NewRecorder()
router := gin.New()
router.POST("/import", func(c *gin.Context) {
c.Set(jwt.JwtPayloadKey, jwt.MapClaims{"identity": float64(1)})
Handler{DB: testDB(t)}.Import(c)
})
router.ServeHTTP(recorder, request)
return recorder
}
func responsePayload(t *testing.T, recorder *httptest.ResponseRecorder) map[string]any {
t.Helper()
var payload map[string]any
if err := json.Unmarshal(recorder.Body.Bytes(), &payload); err != nil {
t.Fatalf("decode response %q: %v", recorder.Body.String(), err)
}
return payload
}
func TestImportHandlerAcceptsBrowserMultipartBoundary(t *testing.T) {
content := workbook(t, [][]any{{"2026-08-28", "ORDER-1", "店铺", "A#1", "SKU-1", "黑色,L", "IC-01", 1}})
request, contentType := importRequest(t, "file", "mapping_20260828.xlsx", content)
if contentType == "multipart/form-data" || !bytes.Contains([]byte(contentType), []byte("boundary=")) {
t.Fatalf("browser multipart boundary missing: %s", contentType)
}
recorder := performImport(t, request)
if recorder.Code != http.StatusOK || responsePayload(t, recorder)["code"] != float64(200) {
t.Fatalf("unexpected response: status=%d body=%s", recorder.Code, recorder.Body.String())
}
}
func TestImportHandlerDistinguishesMalformedAndOversizedBodies(t *testing.T) {
t.Run("wrong content type", func(t *testing.T) {
request := httptest.NewRequest(http.MethodPost, "/import", bytes.NewBufferString(`{"file":"not-multipart"}`))
request.Header.Set("Content-Type", "application/json")
recorder := performImport(t, request)
payload := responsePayload(t, recorder)
if recorder.Code != http.StatusUnprocessableEntity || payload["message"] != "上传格式无效,请重新选择 Excel 后重试" {
t.Fatalf("unexpected response: status=%d body=%s", recorder.Code, recorder.Body.String())
}
})
t.Run("wrong field", func(t *testing.T) {
request, _ := importRequest(t, "wrong", "mapping_20260828.xlsx", []byte("content"))
recorder := performImport(t, request)
payload := responsePayload(t, recorder)
if recorder.Code != http.StatusUnprocessableEntity || payload["message"] != "上传格式无效,请重新选择 Excel 后重试" {
t.Fatalf("unexpected response: status=%d body=%s", recorder.Code, recorder.Body.String())
}
})
t.Run("request body over hard limit", func(t *testing.T) {
request, _ := importRequest(t, "file", "mapping_20260828.xlsx", make([]byte, MaxUploadBytes+(2<<20)))
recorder := performImport(t, request)
payload := responsePayload(t, recorder)
if recorder.Code != http.StatusUnprocessableEntity || payload["message"] != "Excel 超过 10MB 上限" {
t.Fatalf("unexpected response: status=%d body=%s", recorder.Code, recorder.Body.String())
}
})
}
func TestValidateUploadKeepsTenMegabyteLimit(t *testing.T) {
if MaxUploadBytes != 10<<20 {
t.Fatalf("unexpected upload limit: %d", MaxUploadBytes)
}
err := ValidateUpload("mapping.xlsx", MaxUploadBytes+1, []byte{'P', 'K', 0x03, 0x04})
if err == nil || err.Error() != "Excel 超过 10MB 上限" {
t.Fatalf("unexpected validation result: %v", err)
}
}