2026-05-22 16:05:12 +08:00

334 lines
9.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package regionimgroup
import (
"context"
"strings"
"testing"
"time"
"chatapp3-golang/internal/config"
"chatapp3-golang/internal/model"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
func TestCreateRegionIMGroupSavesActiveGroup(t *testing.T) {
service, db := newRegionIMGroupTestService(t)
fakeIM := &fakeIMGateway{}
service.im = fakeIM
resp, err := service.CreateRegionIMGroup(context.Background(), RegionIMGroupRequest{
SysOrigin: "LIKEI",
RegionCode: "AR",
RegionName: "Arab",
})
if err != nil {
t.Fatalf("CreateRegionIMGroup() error = %v", err)
}
if resp.Status != imGroupStatusActive || resp.GroupID != defaultRegionIMGroupID("LIKEI", "AR") {
t.Fatalf("CreateRegionIMGroup() response = %+v", resp)
}
if len(fakeIM.created) != 1 || fakeIM.created[0].groupID != resp.GroupID {
t.Fatalf("created groups = %+v, want one %s", fakeIM.created, resp.GroupID)
}
var row model.VoiceRoomRegionIMGroup
if err := db.Where("sys_origin = ? AND region_code = ?", "LIKEI", "AR").First(&row).Error; err != nil {
t.Fatalf("load im group: %v", err)
}
if row.Status != imGroupStatusActive || row.GroupID != resp.GroupID {
t.Fatalf("stored im group = %+v", row)
}
}
func TestDefaultRegionIMGroupIDKeepsASCIIRegionReadable(t *testing.T) {
got := defaultRegionIMGroupID("LIKEI", "IR")
if got != "VRRP_LIKEI_IR" {
t.Fatalf("defaultRegionIMGroupID() = %s, want VRRP_LIKEI_IR", got)
}
}
func TestDefaultRegionIMGroupIDKeepsNonASCIIRegionsDistinct(t *testing.T) {
middleEast := defaultRegionIMGroupID("LIKEI", "\u4e2d\u4e1c")
southAsia := defaultRegionIMGroupID("LIKEI", "\u5357\u4e9a\u533a\u57df")
if middleEast == southAsia {
t.Fatalf("non-ascii regions share group id %s", middleEast)
}
if middleEast == "VRRP_LIKEI" || southAsia == "VRRP_LIKEI" {
t.Fatalf("non-ascii region group ids must not collapse: %s %s", middleEast, southAsia)
}
if !strings.HasPrefix(middleEast, "VRRP_LIKEI_REGION_") ||
!strings.HasPrefix(southAsia, "VRRP_LIKEI_REGION_") {
t.Fatalf("group ids = %s %s, want hashed region suffix", middleEast, southAsia)
}
}
func TestDefaultRegionIMGroupNameIsGeneric(t *testing.T) {
got := defaultRegionIMGroupName("LIKEI", "IR", "Iran")
if got != "region-im-group-LIKEI-Iran" {
t.Fatalf("defaultRegionIMGroupName() = %s, want generic region name", got)
}
if strings.Contains(got, "red-packet") {
t.Fatalf("defaultRegionIMGroupName() contains red-packet: %s", got)
}
}
func TestSendRegionBroadcastResolvesRegionAndEnrichesGiftPayload(t *testing.T) {
service, db := newRegionIMGroupTestService(t)
fakeIM := &fakeIMGateway{}
service.im = fakeIM
ctx := context.Background()
now := time.Now()
if err := db.Create(&model.VoiceRoomRegionIMGroup{
ID: 3002,
SysOrigin: "LIKEI",
RegionCode: "AR",
RegionName: "Arab",
GroupID: "@region-ar",
GroupName: "region-ar",
Status: imGroupStatusActive,
CreateTime: now,
UpdateTime: now,
}).Error; err != nil {
t.Fatalf("seed im group: %v", err)
}
resp, err := service.SendRegionBroadcast(ctx, RegionBroadcastRequest{
SysOrigin: "LIKEI",
SenderUserID: flexibleInt64(1001),
Type: "SEND_GIFT",
Data: map[string]any{
"roomId": "9001",
"giftId": "5001",
"giftQuantity": 2,
"acceptUserIds": []any{"1002"},
},
})
if err != nil {
t.Fatalf("SendRegionBroadcast() error = %v", err)
}
if resp.RegionCode != "AR" || resp.GroupID != "@region-ar" || resp.Type != "SEND_GIFT" {
t.Fatalf("SendRegionBroadcast() response = %+v", resp)
}
if len(fakeIM.sent) != 1 {
t.Fatalf("sent messages = %+v, want one region message", fakeIM.sent)
}
if fakeIM.sent[0].groupID != "@region-ar" {
t.Fatalf("sent group = %s, want @region-ar", fakeIM.sent[0].groupID)
}
body, ok := fakeIM.sent[0].body.(map[string]any)
if !ok {
t.Fatalf("sent body type = %T", fakeIM.sent[0].body)
}
if body["type"] != "SEND_GIFT" {
t.Fatalf("sent type = %v, want SEND_GIFT", body["type"])
}
data, ok := body["data"].(map[string]any)
if !ok {
t.Fatalf("sent data type = %T", body["data"])
}
if data["regionCode"] != "AR" || data["actualAccount"] != "1001" ||
data["userNickname"] != "sender" || data["acceptNickname"] != "claimer" {
t.Fatalf("sent data = %+v", data)
}
}
func TestSendRegionBroadcastRefreshesHighWinMessageWithProfile(t *testing.T) {
service, db := newRegionIMGroupTestService(t)
fakeIM := &fakeIMGateway{}
service.im = fakeIM
now := time.Now()
if err := db.Create(&model.VoiceRoomRegionIMGroup{
ID: 3010,
SysOrigin: "LIKEI",
RegionCode: "AR",
RegionName: "Arab",
GroupID: "@region-ar",
GroupName: "region-ar",
Status: imGroupStatusActive,
CreateTime: now,
UpdateTime: now,
}).Error; err != nil {
t.Fatalf("seed im group: %v", err)
}
_, err := service.SendRegionBroadcast(context.Background(), RegionBroadcastRequest{
SysOrigin: "LIKEI",
Type: "GAME_BAISHUN_WIN",
Data: map[string]any{
"userId": "1001",
"roomId": "9001",
"multiple": 10,
"winAmount": 1000,
"msg": "1001 play game get x 10 win 1000 coins",
},
})
if err != nil {
t.Fatalf("SendRegionBroadcast() error = %v", err)
}
body, ok := fakeIM.sent[0].body.(map[string]any)
if !ok {
t.Fatalf("sent body type = %T", fakeIM.sent[0].body)
}
data, ok := body["data"].(map[string]any)
if !ok {
t.Fatalf("sent data type = %T", body["data"])
}
if data["msg"] != "sender play game get x 10 win 1000 coins" {
t.Fatalf("msg = %v", data["msg"])
}
}
func TestSendRegionBroadcastRefreshesCPRelationMessageWithProfiles(t *testing.T) {
service, db := newRegionIMGroupTestService(t)
fakeIM := &fakeIMGateway{}
service.im = fakeIM
now := time.Now()
if err := db.Create(&model.VoiceRoomRegionIMGroup{
ID: 3011,
SysOrigin: "LIKEI",
RegionCode: "AR",
RegionName: "Arab",
GroupID: "@region-ar",
GroupName: "region-ar",
Status: imGroupStatusActive,
CreateTime: now,
UpdateTime: now,
}).Error; err != nil {
t.Fatalf("seed im group: %v", err)
}
_, err := service.SendRegionBroadcast(context.Background(), RegionBroadcastRequest{
SysOrigin: "LIKEI",
Type: "CP_RELATION_BROADCAST",
Data: map[string]any{
"userId": "1001",
"acceptUserId": "1002",
"relationType": "SISTERS",
"msg": "1001与1002结为姐妹",
},
})
if err != nil {
t.Fatalf("SendRegionBroadcast() error = %v", err)
}
body, ok := fakeIM.sent[0].body.(map[string]any)
if !ok {
t.Fatalf("sent body type = %T", fakeIM.sent[0].body)
}
data, ok := body["data"].(map[string]any)
if !ok {
t.Fatalf("sent data type = %T", body["data"])
}
if data["msg"] != "sender与claimer结为姐妹" {
t.Fatalf("msg = %v", data["msg"])
}
}
func TestSendRegionBroadcastPrefersJavaRegionResolver(t *testing.T) {
service, db := newRegionIMGroupTestService(t)
service.regionResolver = fakeRegionResolver{
regions: map[string]string{"LIKEI|SA": "中东区"},
}
fakeIM := &fakeIMGateway{}
service.im = fakeIM
now := time.Now()
if err := db.Create(&model.VoiceRoomRegionIMGroup{
ID: 3003,
SysOrigin: "LIKEI",
RegionCode: "中东区",
RegionName: "Middle East",
GroupID: "@region-middle-east",
GroupName: "region-middle-east",
Status: imGroupStatusActive,
CreateTime: now,
UpdateTime: now,
}).Error; err != nil {
t.Fatalf("seed im group: %v", err)
}
resp, err := service.SendRegionBroadcast(context.Background(), RegionBroadcastRequest{
SysOrigin: "LIKEI",
SenderUserID: flexibleInt64(1001),
Type: "SEND_GIFT",
Data: map[string]any{"roomId": "9001"},
})
if err != nil {
t.Fatalf("SendRegionBroadcast() error = %v", err)
}
if resp.RegionCode != "中东区" || resp.GroupID != "@region-middle-east" {
t.Fatalf("SendRegionBroadcast() response = %+v, want Java region group", resp)
}
}
func newRegionIMGroupTestService(t *testing.T) (*Service, *gorm.DB) {
t.Helper()
db, err := gorm.Open(sqlite.Open("file:"+t.Name()+"?mode=memory&cache=shared"), &gorm.Config{})
if err != nil {
t.Fatalf("open sqlite: %v", err)
}
if err := db.AutoMigrate(
&model.UserBaseInfo{},
&model.VoiceRoomRegionCountry{},
&model.VoiceRoomRegionIMGroup{},
); err != nil {
t.Fatalf("auto migrate: %v", err)
}
now := time.Now()
if err := db.Create(&[]model.UserBaseInfo{
{ID: 1001, Account: "1001", UserNickname: "sender", UserAvatar: "sender.png", OriginSys: "LIKEI", CountryCode: "SA", CountryName: "Saudi Arabia", CreateTime: now},
{ID: 1002, Account: "1002", UserNickname: "claimer", UserAvatar: "claimer.png", OriginSys: "LIKEI", CountryCode: "SA", CountryName: "Saudi Arabia", CreateTime: now},
}).Error; err != nil {
t.Fatalf("seed users: %v", err)
}
if err := db.Create(&model.VoiceRoomRegionCountry{
ID: 1,
SysOrigin: "LIKEI",
RegionCode: "AR",
CountryCode: "SA",
Enabled: true,
CreateTime: now,
UpdateTime: now,
}).Error; err != nil {
t.Fatalf("seed region: %v", err)
}
return NewService(config.Config{}, db), db
}
type fakeIMCreateRecord struct {
groupID string
groupName string
}
type fakeIMSendRecord struct {
groupID string
body any
}
type fakeIMGateway struct {
created []fakeIMCreateRecord
sent []fakeIMSendRecord
}
func (g *fakeIMGateway) CreateAVChatRoom(_ context.Context, groupID string, groupName string) (string, error) {
g.created = append(g.created, fakeIMCreateRecord{groupID: groupID, groupName: groupName})
return groupID, nil
}
func (g *fakeIMGateway) SendCustomGroupMessage(_ context.Context, groupID string, body any) error {
g.sent = append(g.sent, fakeIMSendRecord{groupID: groupID, body: body})
return nil
}
type fakeRegionResolver struct {
regions map[string]string
err error
}
func (g fakeRegionResolver) ResolveRegionCodeByCountryCode(_ context.Context, sysOrigin string, countryCode string) (string, error) {
if g.err != nil {
return "", g.err
}
key := strings.ToUpper(strings.TrimSpace(sysOrigin)) + "|" + strings.ToUpper(strings.TrimSpace(countryCode))
return strings.TrimSpace(g.regions[key]), nil
}