spark-server/internal/module/favorite/logic/favorite_test.go
2026-09-18 17:14:38 +08:00

141 lines
3.9 KiB
Go

package logic
import (
"context"
"errors"
"strings"
"testing"
"time"
"spark-server/internal/infrastructure/id"
convlogic "spark-server/internal/module/conversation/logic"
convmodel "spark-server/internal/module/conversation/model"
favmodel "spark-server/internal/module/favorite/model"
msgentity "spark-server/internal/module/message/entity"
msgmodel "spark-server/internal/module/message/model"
"spark-server/internal/pkg/errs"
"spark-server/internal/pkg/reqctx"
)
type memObjects struct {
keys map[string]bool
}
func (m *memObjects) Copy(_ context.Context, src, dst string) error {
if m.keys == nil || !m.keys[src] {
return errs.ErrMediaExpired
}
m.keys[dst] = true
return nil
}
func (m *memObjects) Delete(_ context.Context, key string) error {
delete(m.keys, key)
return nil
}
func testFav(t *testing.T) (*Service, *msgmodel.MemoryRepo, *convmodel.MemoryP2P, *memObjects, *id.Generator) {
t.Helper()
ids, err := id.New(1)
if err != nil {
t.Fatal(err)
}
msgs := msgmodel.NewMemoryRepo()
convs := convmodel.NewMemoryP2P()
objs := &memObjects{keys: map[string]bool{}}
svc := NewService(favmodel.NewMemoryRepo(), msgs, convs, objs, ids)
return svc, msgs, convs, objs, ids
}
func TestFavoriteCopiesMediaAndExpires(t *testing.T) {
svc, msgs, convs, objs, ids := testFav(t)
ctx := reqctx.With(t.Context(), &reqctx.RequestContext{UserID: 1, Language: "zh-CN"})
p2p := convlogic.NewP2PService(convs, ids)
convID, err := p2p.EnsureP2P(ctx, 1, 2)
if err != nil {
t.Fatal(err)
}
src := "chat/20260917/1/99.jpg"
thumb := "chat/20260917/1/t.jpg"
orig := "chat/20260917/1/o.jpg"
objs.keys[src] = true
objs.keys[thumb] = true
objs.keys[orig] = true
raw, err := msgentity.NewImage(&msgentity.Image{Key: src, ThumbKey: thumb, OrigKey: orig, Mime: "image/jpeg"}).Marshal()
if err != nil {
t.Fatal(err)
}
msgID, err := ids.NextID()
if err != nil {
t.Fatal(err)
}
if err := msgs.Create(ctx, &msgentity.Message{
ID: msgID, ConversationID: convID, SenderID: 1, ClientMsgID: "c1",
Type: msgentity.TypeImage, Content: raw, Status: msgentity.StatusNormal,
CreatedAtMS: time.Now().UnixMilli(),
}); err != nil {
t.Fatal(err)
}
item, err := svc.Create(ctx, 1, &CreateInput{MsgID: msgID})
if err != nil {
t.Fatal(err)
}
if item.MsgID != msgID || !strings.Contains(string(item.Content), "perm/fav/") {
t.Fatalf("%+v", item)
}
if strings.Contains(string(item.Content), src) || strings.Contains(string(item.Content), orig) {
t.Fatal("still points at chat key")
}
again, err := svc.Create(ctx, 1, &CreateInput{MsgID: msgID})
if err != nil || again.ID != item.ID {
t.Fatalf("idempotent %+v %v", again, err)
}
expiredID, err := ids.NextID()
if err != nil {
t.Fatal(err)
}
gone := "chat/20260917/1/gone.jpg"
raw2, err := msgentity.NewImage(&msgentity.Image{Key: gone, Mime: "image/jpeg"}).Marshal()
if err != nil {
t.Fatal(err)
}
if err := msgs.Create(ctx, &msgentity.Message{
ID: expiredID, ConversationID: convID, SenderID: 1, ClientMsgID: "c2",
Type: msgentity.TypeImage, Content: raw2, Status: msgentity.StatusNormal,
}); err != nil {
t.Fatal(err)
}
_, err = svc.Create(ctx, 1, &CreateInput{MsgID: expiredID})
if !errors.Is(err, errs.ErrMediaExpired) {
t.Fatalf("expired %v", err)
}
}
func TestFavoriteForbidsNonMember(t *testing.T) {
svc, msgs, convs, _, ids := testFav(t)
ctx := t.Context()
p2p := convlogic.NewP2PService(convs, ids)
convID, err := p2p.EnsureP2P(ctx, 1, 2)
if err != nil {
t.Fatal(err)
}
raw, err := msgentity.NewText("hi").Marshal()
if err != nil {
t.Fatal(err)
}
msgID, err := ids.NextID()
if err != nil {
t.Fatal(err)
}
if err := msgs.Create(ctx, &msgentity.Message{
ID: msgID, ConversationID: convID, SenderID: 1, ClientMsgID: "t1",
Type: msgentity.TypeText, Content: raw, Status: msgentity.StatusNormal,
}); err != nil {
t.Fatal(err)
}
if _, err := svc.Create(ctx, 9, &CreateInput{MsgID: msgID}); !errors.Is(err, errs.ErrForbidden) {
t.Fatalf("member %v", err)
}
}