实现文件上传
This commit is contained in:
144
web/services/article_upload_test.go
Normal file
144
web/services/article_upload_test.go
Normal file
@@ -0,0 +1,144 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"platform/pkg/env"
|
||||
)
|
||||
|
||||
func TestArticleUploadImageSuccess(t *testing.T) {
|
||||
restore := snapshotUploadEnv()
|
||||
defer restore()
|
||||
|
||||
env.UploadDir = t.TempDir()
|
||||
env.ArticleUploadMaxBytes = 5 * 1024 * 1024
|
||||
|
||||
fileHeader := newMultipartFileHeader(t, "file", "pixel.png", mustDecodeBase64(t, onePixelPNGBase64))
|
||||
|
||||
result, err := Article.UploadImage(fileHeader, "https://example.com")
|
||||
if err != nil {
|
||||
t.Fatalf("UploadImage returned error: %v", err)
|
||||
}
|
||||
|
||||
if result.MimeType != "image/png" {
|
||||
t.Fatalf("unexpected mime type: %s", result.MimeType)
|
||||
}
|
||||
if !strings.HasPrefix(result.Path, "/uploads/article/") {
|
||||
t.Fatalf("unexpected path: %s", result.Path)
|
||||
}
|
||||
if result.URL != "https://example.com"+result.Path {
|
||||
t.Fatalf("unexpected url: %s", result.URL)
|
||||
}
|
||||
if result.OriginalName != "pixel.png" {
|
||||
t.Fatalf("unexpected original name: %s", result.OriginalName)
|
||||
}
|
||||
|
||||
savedPath := filepath.Join(env.UploadDir, filepath.FromSlash(strings.TrimPrefix(result.Path, "/uploads/")))
|
||||
info, err := os.Stat(savedPath)
|
||||
if err != nil {
|
||||
t.Fatalf("saved file not found: %v", err)
|
||||
}
|
||||
if info.Size() != result.Size {
|
||||
t.Fatalf("unexpected saved size: got %d want %d", info.Size(), result.Size)
|
||||
}
|
||||
}
|
||||
|
||||
func TestArticleUploadImageRejectsUnsupportedType(t *testing.T) {
|
||||
restore := snapshotUploadEnv()
|
||||
defer restore()
|
||||
|
||||
env.UploadDir = t.TempDir()
|
||||
env.ArticleUploadMaxBytes = 5 * 1024 * 1024
|
||||
|
||||
fileHeader := newMultipartFileHeader(t, "file", "note.txt", []byte("not an image"))
|
||||
|
||||
_, err := Article.UploadImage(fileHeader, "https://example.com")
|
||||
if err == nil {
|
||||
t.Fatal("expected error, got nil")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "仅支持 JPG、PNG、WEBP、GIF 图片") {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestArticleUploadImageRejectsOversizeFile(t *testing.T) {
|
||||
restore := snapshotUploadEnv()
|
||||
defer restore()
|
||||
|
||||
env.UploadDir = t.TempDir()
|
||||
env.ArticleUploadMaxBytes = 8
|
||||
|
||||
fileHeader := newMultipartFileHeader(t, "file", "large.png", bytes.Repeat([]byte("a"), 9))
|
||||
|
||||
_, err := Article.UploadImage(fileHeader, "https://example.com")
|
||||
if err == nil {
|
||||
t.Fatal("expected error, got nil")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "图片大小不能超过") {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func newMultipartFileHeader(t *testing.T, fieldName string, fileName string, content []byte) *multipart.FileHeader {
|
||||
t.Helper()
|
||||
|
||||
var body bytes.Buffer
|
||||
writer := multipart.NewWriter(&body)
|
||||
|
||||
part, err := writer.CreateFormFile(fieldName, fileName)
|
||||
if err != nil {
|
||||
t.Fatalf("CreateFormFile failed: %v", err)
|
||||
}
|
||||
if _, err := part.Write(content); err != nil {
|
||||
t.Fatalf("Write content failed: %v", err)
|
||||
}
|
||||
if err := writer.Close(); err != nil {
|
||||
t.Fatalf("Close multipart writer failed: %v", err)
|
||||
}
|
||||
|
||||
req := httptest.NewRequest(http.MethodPost, "/", &body)
|
||||
req.Header.Set("Content-Type", writer.FormDataContentType())
|
||||
if err := req.ParseMultipartForm(int64(body.Len()) + 1024); err != nil {
|
||||
t.Fatalf("ParseMultipartForm failed: %v", err)
|
||||
}
|
||||
|
||||
file, fileHeader, err := req.FormFile(fieldName)
|
||||
if err != nil {
|
||||
t.Fatalf("FormFile failed: %v", err)
|
||||
}
|
||||
_ = file.Close()
|
||||
|
||||
return fileHeader
|
||||
}
|
||||
|
||||
func mustDecodeBase64(t *testing.T, value string) []byte {
|
||||
t.Helper()
|
||||
|
||||
data, err := base64.StdEncoding.DecodeString(value)
|
||||
if err != nil {
|
||||
t.Fatalf("DecodeString failed: %v", err)
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
func snapshotUploadEnv() func() {
|
||||
uploadDir := env.UploadDir
|
||||
uploadPublicBaseURL := env.UploadPublicBaseURL
|
||||
articleUploadMaxBytes := env.ArticleUploadMaxBytes
|
||||
|
||||
return func() {
|
||||
env.UploadDir = uploadDir
|
||||
env.UploadPublicBaseURL = uploadPublicBaseURL
|
||||
env.ArticleUploadMaxBytes = articleUploadMaxBytes
|
||||
}
|
||||
}
|
||||
|
||||
const onePixelPNGBase64 = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+a7KQAAAAASUVORK5CYII="
|
||||
Reference in New Issue
Block a user