spark-server/internal/infrastructure/objectstore/store_test.go
DESKTOP-L8OUL9F\gfl0034 ade98eef4d feat(music): 曲目增加背景图字段与管理端上传
新增 migration 0021(background_key/url)、playlist/CRUD 返回 backgroundUrl、
POST .../music/{id}/background,并热更 popadmin 音乐列表背景上传;公读策略放行 perm/music/*。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-24 09:17:21 +08:00

150 lines
4.2 KiB
Go

package objectstore
import (
"errors"
"os"
"strings"
"testing"
"time"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/aws/aws-sdk-go-v2/service/s3/types"
"go.uber.org/zap"
"spark-server/internal/pkg/errs"
)
func TestParseEndpoint(t *testing.T) {
host, secure, err := parseEndpoint("http://47.236.66.9:9000", true)
if err != nil || host != "47.236.66.9:9000" || secure {
t.Fatalf("%s %v %v", host, secure, err)
}
host, secure, err = parseEndpoint("47.236.66.9:9000", false)
if err != nil || host != "47.236.66.9:9000" || secure {
t.Fatalf("plain %s %v %v", host, secure, err)
}
host, secure, err = parseEndpoint("https://fs.example.com", false)
if err != nil || host != "fs.example.com" || !secure {
t.Fatalf("https %s %v %v", host, secure, err)
}
}
func TestOpenEmpty(t *testing.T) {
s, err := Open(&Options{})
if err != nil || s.Ready() {
t.Fatalf("ready=%v err=%v", s.Ready(), err)
}
}
func TestPresignLocal(t *testing.T) {
client := newS3Client(defaultRegion, "http://127.0.0.1:9000", "ak", "sk")
s := &Store{client: client, presign: s3.NewPresignClient(client), bucket: "spark"}
u, err := s.PresignPut(t.Context(), "chat/a.jpg", "image/jpeg", 1024, time.Hour)
if err != nil {
t.Fatal(err)
}
if !strings.Contains(u, "127.0.0.1:9000/spark/chat/a.jpg") {
t.Fatalf("%s", u)
}
signed := strings.ToLower(u)
if !strings.Contains(signed, "content-length") || !strings.Contains(signed, "if-none-match") {
t.Fatalf("unsigned size/overwrite headers: %s", u)
}
g, err := s.PresignGet(t.Context(), "perm/avatar/1.jpg", time.Minute)
if err != nil {
t.Fatal(err)
}
if !strings.Contains(g, "perm/avatar/1.jpg") {
t.Fatalf("%s", g)
}
}
func TestPresignPutRejectsZeroSize(t *testing.T) {
client := newS3Client(defaultRegion, "http://127.0.0.1:9000", "ak", "sk")
s := &Store{client: client, presign: s3.NewPresignClient(client), bucket: "spark"}
if _, err := s.PresignPut(t.Context(), "chat/a.jpg", "image/jpeg", 0, time.Hour); !errors.Is(err, errs.ErrInvalidArgument) {
t.Fatalf("%v", err)
}
}
func TestPresignPublicEndpoint(t *testing.T) {
internal, public, err := newClients(&Options{
Endpoint: "http://rustfs:9000",
PublicEndpoint: "https://sparkr.wyrs365.com/",
AccessKey: "ak",
SecretKey: "sk",
})
if err != nil {
t.Fatal(err)
}
s := &Store{client: internal, presign: s3.NewPresignClient(public), bucket: "spark"}
u, err := s.PresignPut(t.Context(), "chat/a.jpg", "image/jpeg", 1024, time.Hour)
if err != nil {
t.Fatal(err)
}
if !strings.Contains(u, "https://sparkr.wyrs365.com/spark/chat/a.jpg") {
t.Fatalf("%s", u)
}
if strings.Contains(u, "rustfs:9000") {
t.Fatalf("internal host leaked: %s", u)
}
}
func TestGetPutNotReady(t *testing.T) {
s, err := Open(&Options{})
if err != nil {
t.Fatal(err)
}
if _, err := s.Get(t.Context(), "perm/a"); !errors.Is(err, errs.ErrAvailable) {
t.Fatalf("get %v", err)
}
if err := s.Put(t.Context(), "perm/a", []byte("x"), "image/jpeg"); !errors.Is(err, errs.ErrAvailable) {
t.Fatalf("put %v", err)
}
}
func TestPublicReadPolicyCoversAvatarsAndMusic(t *testing.T) {
p := publicReadPolicy("spark")
if !strings.Contains(p, "spark/perm/avatar/*") || !strings.Contains(p, "spark/perm/group/*") || !strings.Contains(p, "spark/perm/music/*") {
t.Fatalf("%s", p)
}
if strings.Contains(p, "chat/") || strings.Contains(p, "perm/fav") || strings.Contains(p, "perm/moment") {
t.Fatalf("chat/fav/moment must stay private: %s", p)
}
}
func TestMapObjectErr(t *testing.T) {
err := mapObjectErr(&types.NoSuchKey{Message: aws.String("gone")})
if !errors.Is(err, errs.ErrMediaExpired) {
t.Fatalf("%v", err)
}
err = mapObjectErr(errors.New("boom"))
if !errors.Is(err, errs.ErrOperatFail) {
t.Fatalf("%v", err)
}
}
func TestOpenLive(t *testing.T) {
if os.Getenv("SPARK_S3_LIVE") == "" {
t.Skip("set SPARK_S3_LIVE=1 to hit RustFS")
}
s, err := Open(&Options{
Endpoint: "47.236.66.9:9000",
AccessKey: os.Getenv("SPARK_S3_ACCESS_KEY"),
SecretKey: os.Getenv("SPARK_S3_SECRET_KEY"),
Bucket: "spark",
ChatExpireDays: 365,
Log: zap.NewNop(),
})
if err != nil {
t.Fatal(err)
}
if !s.Ready() {
t.Fatal("not ready")
}
if err := s.Ping(t.Context()); err != nil {
t.Fatal(err)
}
}