spark-server/internal/module/admin/logic/service_test.go
zhr 13b42cef7b chore: 合并本地改动与 main(t_ 表名、lint、音乐分类)
在 fast-forward 到 origin/main 后解决 music logic/repo 冲突,SQL 与模型统一 t_* 表名;Makefile 修正 golangci-lint 变量并令 test/deploy 依赖 lint;补齐 admin/transport 等 lint 修复与 music logic 单测以满足覆盖率门禁。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-24 10:56:59 +08:00

323 lines
9.8 KiB
Go

package logic
import (
"context"
"errors"
"testing"
"time"
adminentity "spark-server/internal/module/admin/entity"
adminmodel "spark-server/internal/module/admin/model"
friendentity "spark-server/internal/module/friend/entity"
groupentity "spark-server/internal/module/group/entity"
msgentity "spark-server/internal/module/message/entity"
userentity "spark-server/internal/module/user/entity"
"spark-server/internal/pkg/errs"
)
type seqID struct{ n int64 }
func (s *seqID) NextID() (int64, error) {
s.n++
return s.n, nil
}
type memoryAdmin struct {
users []adminmodel.UserRow
emails map[string]int64
groups map[int64]adminmodel.GroupRow
members map[int64][]adminmodel.GroupMemberRow
groupMsgs map[int64][]adminmodel.MessageRow
msgs []adminmodel.MessageRow
convs []adminmodel.ConversationRow
complaints []adminmodel.ComplaintRow
stats *adminentity.ImStats
ips []adminmodel.SameIPRankRow
owners map[int64]int64
}
func (m *memoryAdmin) ListUsers(_ context.Context, emailLike string, page, size int) ([]adminmodel.UserRow, int64, error) {
start := page * size
if start >= len(m.users) {
return nil, int64(len(m.users)), nil
}
end := start + size
if end > len(m.users) {
end = len(m.users)
}
_ = emailLike
return m.users[start:end], int64(len(m.users)), nil
}
func (m *memoryAdmin) UsersByEmail(_ context.Context, email string) ([]adminmodel.UserRow, error) {
out := make([]adminmodel.UserRow, 0)
for i := range m.users {
if m.users[i].Email == email {
out = append(out, m.users[i])
}
}
return out, nil
}
func (m *memoryAdmin) UserByID(_ context.Context, id int64) (*adminmodel.UserRow, error) {
for i := range m.users {
if m.users[i].ID == id {
cp := m.users[i]
return &cp, nil
}
}
return nil, errs.ErrNotFound
}
func (m *memoryAdmin) UsersByNickname(_ context.Context, nickname string) ([]adminmodel.UserRow, error) {
out := make([]adminmodel.UserRow, 0)
for i := range m.users {
if m.users[i].Nickname == nickname {
out = append(out, m.users[i])
}
}
return out, nil
}
func (m *memoryAdmin) UsersByDevice(_ context.Context, _ string, deviceIDNum uint64) ([]adminmodel.UserRow, error) {
out := make([]adminmodel.UserRow, 0)
for i := range m.users {
if m.users[i].DeviceID == deviceIDNum {
out = append(out, m.users[i])
}
}
return out, nil
}
func (m *memoryAdmin) UsersByIP(_ context.Context, _ string) ([]adminmodel.UserRow, error) {
return m.users, nil
}
func (m *memoryAdmin) SetUserStatusByEmail(_ context.Context, email string, status userentity.Status) error {
for i := range m.users {
if m.users[i].Email == email {
m.users[i].Status = int(status)
return nil
}
}
return errs.ErrNotFound
}
func (m *memoryAdmin) SetNicknameByEmail(_ context.Context, email, nickname string) error {
for i := range m.users {
if m.users[i].Email == email {
m.users[i].Nickname = nickname
return nil
}
}
return errs.ErrNotFound
}
func (m *memoryAdmin) ClearAvatarByEmail(_ context.Context, email string) error {
for i := range m.users {
if m.users[i].Email == email {
m.users[i].Avatar = ""
return nil
}
}
return errs.ErrNotFound
}
func (m *memoryAdmin) SameIPRank(_ context.Context, _ int) ([]adminmodel.SameIPRankRow, error) {
return m.ips, nil
}
func (m *memoryAdmin) LookupUserIDByEmail(_ context.Context, email string) (int64, error) {
if m.emails == nil {
return 0, nil
}
return m.emails[email], nil
}
func (m *memoryAdmin) ListGroups(_ context.Context, _ string) ([]adminmodel.GroupRow, error) {
out := make([]adminmodel.GroupRow, 0, len(m.groups))
for id := range m.groups {
out = append(out, m.groups[id])
}
return out, nil
}
func (m *memoryAdmin) GroupByID(_ context.Context, groupID int64) (*adminmodel.GroupRow, error) {
g, ok := m.groups[groupID]
if !ok {
return nil, errs.ErrNotFound
}
return &g, nil
}
func (m *memoryAdmin) ActiveGroupOwner(_ context.Context, groupID int64) (int64, error) {
id, ok := m.owners[groupID]
if !ok {
return 0, errs.ErrNotFound
}
return id, nil
}
func (m *memoryAdmin) ListGroupMembers(_ context.Context, groupID int64) ([]adminmodel.GroupMemberRow, error) {
return m.members[groupID], nil
}
func (m *memoryAdmin) ListGroupMessages(_ context.Context, groupID int64, _ int) ([]adminmodel.MessageRow, error) {
return m.groupMsgs[groupID], nil
}
func (m *memoryAdmin) ListComplaints(_ context.Context, _ int) ([]adminmodel.ComplaintRow, error) {
return m.complaints, nil
}
func (m *memoryAdmin) InsertComplaint(_ context.Context, r *friendentity.Report) error {
if r == nil {
return errs.ErrInvalidArgument
}
m.complaints = append(m.complaints, adminmodel.ComplaintRow{
ID: r.ID, UserID: r.UserID, TargetID: r.TargetID, Reason: int(r.Reason), Detail: r.Detail, CreatedAt: r.CreatedAt,
})
return nil
}
func (m *memoryAdmin) ImStats(context.Context) (*adminentity.ImStats, error) {
return m.stats, nil
}
func (m *memoryAdmin) ListRecentMessages(_ context.Context, _ int) ([]adminmodel.MessageRow, error) {
return m.msgs, nil
}
func (m *memoryAdmin) ListUserConversations(_ context.Context, _ int64) ([]adminmodel.ConversationRow, error) {
return m.convs, nil
}
func TestAdminServiceNotReady(t *testing.T) {
s := &Service{}
if _, _, err := s.ListUsers(t.Context(), "", 0, 0); !errors.Is(err, ErrNotReady) {
t.Fatalf("list %v", err)
}
}
func TestAdminServiceOps(t *testing.T) {
now := time.Unix(1_700_000_000, 0).UTC()
active := now
repo := &memoryAdmin{
users: []adminmodel.UserRow{{
ID: 11, Email: "a@spark.com", Nickname: "Ada", SparkID: "ada_ok01", Status: 1,
DeviceID: 7, Platform: "ios", CreatedAt: now, LastActiveAt: &active,
}},
emails: map[string]int64{"a@spark.com": 11, "b@spark.com": 12},
groups: map[int64]adminmodel.GroupRow{
3: {ID: 3, Name: "g", OwnerID: 11, Status: int(groupentity.StatusActive), MemberCount: 2, CreatedAt: now, UpdatedAt: now},
},
members: map[int64][]adminmodel.GroupMemberRow{
3: {{UserID: 11, Role: int(groupentity.RoleOwner), Nickname: "", UNick: "Ada", Email: "a@spark.com"}},
},
groupMsgs: map[int64][]adminmodel.MessageRow{
3: {{ID: 99, SenderID: 11, MessageType: int16(msgentity.TypeText), CreatedAt: now}},
},
msgs: []adminmodel.MessageRow{
{ID: 1, SenderID: 11, ReceiverID: 12, MessageType: int16(msgentity.TypeText), Content: []byte(`{"t":1,"text":{"body":"hi"}}`), CreatedAt: now, ChatType: "private"},
},
convs: []adminmodel.ConversationRow{
{ID: 4, Type: 1, UserSmall: 11, UserBig: 12, LastMsgID: 1, LastMsgAt: now},
{ID: 5, Type: 2, GroupID: 3, LastMsgID: 99, LastMsgAt: now},
},
complaints: []adminmodel.ComplaintRow{{ID: 1, Email: "a@spark.com", TargetID: 12, Reason: 1, CreatedAt: now}},
stats: &adminentity.ImStats{MessageCount: 2},
ips: []adminmodel.SameIPRankRow{{IP: "1.1.1.1", UserCount: 2, DeviceCount: 3}},
owners: map[int64]int64{3: 11},
}
svc := NewService(repo, nil, &seqID{n: 100})
ctx := t.Context()
list, total, err := svc.ListUsers(ctx, "", -1, 0)
if err != nil || total != 1 || len(list) != 1 || list[0].Email != "a@spark.com" {
t.Fatalf("list %+v %d %v", list, total, err)
}
byMail, err := svc.UserByEmail(ctx, "A@spark.com")
if err != nil || byMail["email"] != "a@spark.com" {
t.Fatalf("email %+v %v", byMail, err)
}
if _, err := svc.UserByEmail(ctx, " "); !errors.Is(err, errs.ErrInvalidArgument) {
t.Fatalf("empty email %v", err)
}
u, err := svc.UserByID(ctx, 11)
if err != nil || u.ID != 11 || u.DeviceID != "7" {
t.Fatalf("by id %+v %v", u, err)
}
nicks, err := svc.UsersByNickname(ctx, "Ada")
if err != nil || len(nicks) != 1 {
t.Fatalf("nick %+v %v", nicks, err)
}
devs, err := svc.UsersByDevice(ctx, "7")
if err != nil || len(devs) != 1 {
t.Fatalf("dev %+v %v", devs, err)
}
ips, err := svc.UsersByIP(ctx, "1.1.1.1")
if err != nil || len(ips) != 1 {
t.Fatalf("ip %+v %v", ips, err)
}
if err := svc.BanByEmail(ctx, "a@spark.com", true); err != nil {
t.Fatal(err)
}
if repo.users[0].Status != int(userentity.StatusDisabled) {
t.Fatal("ban")
}
if err := svc.ResetNicknameByEmail(ctx, "a@spark.com", ""); err != nil || repo.users[0].Nickname != "用户" {
t.Fatalf("nick %v %s", err, repo.users[0].Nickname)
}
if err := svc.ResetAvatarByEmail(ctx, "a@spark.com"); err != nil || repo.users[0].Avatar != "" {
t.Fatal(err)
}
rank, err := svc.SameIPRank(ctx, 0)
if err != nil || len(rank) != 1 || rank[0].Count != 2 {
t.Fatalf("rank %+v %v", rank, err)
}
groups, err := svc.ListGroups(ctx, "")
if err != nil || len(groups) != 1 || groups[0].GroupID != "3" {
t.Fatalf("groups %+v %v", groups, err)
}
detail, err := svc.GroupDetail(ctx, "3")
if err != nil || detail == nil || len(detail.Members) != 1 || detail.Members[0].Role != "owner" {
t.Fatalf("detail %+v %v", detail, err)
}
if _, err := svc.GroupDetail(ctx, "x"); !errors.Is(err, errs.ErrNotFound) {
t.Fatalf("bad gid %v", err)
}
if err := svc.DissolveGroup(ctx, "3"); !errors.Is(err, ErrNotReady) {
t.Fatalf("dissolve %v", err)
}
stats, err := svc.ImStats(ctx)
if err != nil || stats.MessageCount != 2 {
t.Fatalf("stats %+v %v", stats, err)
}
msgs, err := svc.ListMessages(ctx, "hi", 0)
if err != nil || len(msgs) != 1 {
t.Fatalf("msgs %+v %v", msgs, err)
}
convs, gviews, st, err := svc.ListConversations(ctx, 11)
if err != nil || st != nil || len(convs) != 2 || len(gviews) != 1 {
t.Fatalf("convs %+v %+v %v", convs, gviews, err)
}
_, _, st, err = svc.ListConversations(ctx, 0)
if err != nil || st == nil {
t.Fatalf("global stats %v", err)
}
cs, err := svc.ListComplaints(ctx)
if err != nil || len(cs) != 1 || cs[0].Target != "12" {
t.Fatalf("complaints %+v %v", cs, err)
}
added, err := svc.AddComplaint(ctx, "a@spark.com", "b@spark.com", "spam", "ads")
if err != nil || added == nil || added.Reason != "spam" {
t.Fatalf("add %+v %v", added, err)
}
if _, err := svc.AddComplaint(ctx, "", "12", "other", ""); !errors.Is(err, errs.ErrInvalidArgument) {
t.Fatalf("bad complaint %v", err)
}
}