296 lines
9.9 KiB
Go
296 lines
9.9 KiB
Go
package service_test
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"testing"
|
|
"time"
|
|
|
|
roomv1 "hyapp.local/api/proto/room/v1"
|
|
walletv1 "hyapp.local/api/proto/wallet/v1"
|
|
"hyapp/pkg/appcode"
|
|
roomservice "hyapp/services/room-service/internal/room/service"
|
|
"hyapp/services/room-service/internal/testutil/mysqltest"
|
|
)
|
|
|
|
func TestListRoomOnlineUsersReturnsOwnerAdminRoleAndGiftValue(t *testing.T) {
|
|
ctx := context.Background()
|
|
repository := mysqltest.NewRepository(t)
|
|
wallet := &rocketTestWallet{debits: []*walletv1.DebitGiftResponse{{
|
|
BillingReceiptId: "receipt-online-users",
|
|
CoinSpent: 321,
|
|
GiftPointAdded: 321,
|
|
HeatValue: 321,
|
|
GiftTypeCode: "normal",
|
|
}}}
|
|
now := &fixedRoomRocketClock{now: time.Date(2026, 5, 27, 12, 0, 0, 0, time.UTC)}
|
|
svc := newRocketTestService(t, repository, wallet, now)
|
|
|
|
roomID := "room-online-users"
|
|
ownerID := int64(1001)
|
|
adminID := int64(1002)
|
|
normalID := int64(1003)
|
|
createRocketRoom(t, ctx, svc, roomID, ownerID, 9001)
|
|
joinRocketRoom(t, ctx, svc, roomID, adminID)
|
|
joinRocketRoom(t, ctx, svc, roomID, normalID)
|
|
|
|
if _, err := svc.SetRoomAdmin(ctx, &roomv1.SetRoomAdminRequest{
|
|
Meta: roomservice.NewRequestMeta(roomID, ownerID),
|
|
TargetUserId: adminID,
|
|
Enabled: true,
|
|
}); err != nil {
|
|
t.Fatalf("set admin failed: %v", err)
|
|
}
|
|
if _, err := svc.SetRoomAdmin(ctx, &roomv1.SetRoomAdminRequest{
|
|
Meta: roomservice.NewRequestMeta(roomID, ownerID),
|
|
TargetUserId: ownerID,
|
|
Enabled: true,
|
|
}); err == nil {
|
|
t.Fatalf("setting owner as admin must fail")
|
|
}
|
|
|
|
if _, err := svc.SendGift(ctx, &roomv1.SendGiftRequest{
|
|
Meta: rocketMeta(roomID, adminID, "online-users-gift"),
|
|
TargetType: "user",
|
|
TargetUserId: ownerID,
|
|
GiftId: "gift-online-users",
|
|
GiftCount: 1,
|
|
}); err != nil {
|
|
t.Fatalf("send gift failed: %v", err)
|
|
}
|
|
|
|
resp, err := svc.ListRoomOnlineUsers(ctx, &roomv1.ListRoomOnlineUsersRequest{
|
|
Meta: &roomv1.RequestMeta{AppCode: appcode.Default, RoomId: roomID},
|
|
RoomId: roomID,
|
|
ViewerUserId: ownerID,
|
|
Page: 1,
|
|
PageSize: 10,
|
|
Sort: "gift_value",
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("list online users failed: %v", err)
|
|
}
|
|
if len(resp.GetItems()) != 3 {
|
|
t.Fatalf("expected three online users, got %+v", resp.GetItems())
|
|
}
|
|
|
|
byID := make(map[int64]*roomv1.RoomOnlineUser, len(resp.GetItems()))
|
|
for _, item := range resp.GetItems() {
|
|
byID[item.GetUserId()] = item
|
|
}
|
|
if owner := byID[ownerID]; owner == nil || !owner.GetIsOwner() || owner.GetRoomRole() != "normal" {
|
|
t.Fatalf("owner must be is_owner=true and room_role=normal: %+v", owner)
|
|
}
|
|
if admin := byID[adminID]; admin == nil || admin.GetIsOwner() || admin.GetRoomRole() != "admin" || admin.GetGiftValue() != 321 {
|
|
t.Fatalf("admin gift value or role mismatch: %+v", admin)
|
|
}
|
|
if normal := byID[normalID]; normal == nil || normal.GetIsOwner() || normal.GetRoomRole() != "normal" || normal.GetGiftValue() != 0 {
|
|
t.Fatalf("normal user mismatch: %+v", normal)
|
|
}
|
|
payload, err := json.Marshal(resp.GetItems())
|
|
if err != nil {
|
|
t.Fatalf("marshal online users failed: %v", err)
|
|
}
|
|
t.Logf("online users response items: %s", payload)
|
|
}
|
|
|
|
func TestJoinLeaveRoomUpdatesPresenceIncrementally(t *testing.T) {
|
|
ctx := context.Background()
|
|
repository := mysqltest.NewRepository(t)
|
|
now := &fixedRoomRocketClock{now: time.Date(2026, 5, 27, 13, 0, 0, 0, time.UTC)}
|
|
svc := newRocketTestService(t, repository, &rocketTestWallet{}, now)
|
|
|
|
roomID := "room-presence-incremental"
|
|
ownerID := int64(1101)
|
|
viewerID := int64(1102)
|
|
createRocketRoom(t, ctx, svc, roomID, ownerID, 9001)
|
|
joinRocketRoom(t, ctx, svc, roomID, viewerID)
|
|
|
|
onlineResp, err := svc.ListRoomOnlineUsers(ctx, &roomv1.ListRoomOnlineUsersRequest{
|
|
Meta: &roomv1.RequestMeta{AppCode: appcode.Default, RoomId: roomID},
|
|
RoomId: roomID,
|
|
ViewerUserId: ownerID,
|
|
Page: 1,
|
|
PageSize: 10,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("list online users after join failed: %v", err)
|
|
}
|
|
if item := onlineUserItemByID(onlineResp.GetItems(), viewerID); item == nil || item.GetRole() != "audience" {
|
|
t.Fatalf("join must upsert viewer active presence: %+v", onlineResp.GetItems())
|
|
}
|
|
|
|
if _, err := svc.LeaveRoom(ctx, &roomv1.LeaveRoomRequest{Meta: rocketMeta(roomID, viewerID, "presence-incremental-leave")}); err != nil {
|
|
t.Fatalf("leave room failed: %v", err)
|
|
}
|
|
onlineResp, err = svc.ListRoomOnlineUsers(ctx, &roomv1.ListRoomOnlineUsersRequest{
|
|
Meta: &roomv1.RequestMeta{AppCode: appcode.Default, RoomId: roomID},
|
|
RoomId: roomID,
|
|
ViewerUserId: ownerID,
|
|
Page: 1,
|
|
PageSize: 10,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("list online users after leave failed: %v", err)
|
|
}
|
|
if item := onlineUserItemByID(onlineResp.GetItems(), viewerID); item != nil {
|
|
t.Fatalf("leave must mark only viewer presence left: %+v", onlineResp.GetItems())
|
|
}
|
|
}
|
|
|
|
func TestMarkRoomUserPresenceLeftDoesNotClearAnotherRoom(t *testing.T) {
|
|
ctx := appcode.WithContext(context.Background(), appcode.Default)
|
|
repository := mysqltest.NewRepository(t)
|
|
userID := int64(1201)
|
|
|
|
if err := repository.UpsertRoomUserPresence(ctx, roomservice.RoomPresence{
|
|
AppCode: appcode.Default,
|
|
UserID: userID,
|
|
RoomID: "room-current-active",
|
|
Role: "audience",
|
|
RoomVersion: 2,
|
|
JoinedAtMS: 1000,
|
|
LastSeenAtMS: 1000,
|
|
UpdatedAtMS: 1000,
|
|
}); err != nil {
|
|
t.Fatalf("upsert current room presence failed: %v", err)
|
|
}
|
|
if err := repository.MarkRoomUserPresenceLeft(ctx, roomservice.RoomPresence{
|
|
AppCode: appcode.Default,
|
|
UserID: userID,
|
|
RoomID: "room-old-left",
|
|
RoomVersion: 3,
|
|
UpdatedAtMS: 2000,
|
|
}); err != nil {
|
|
t.Fatalf("mark old room presence left failed: %v", err)
|
|
}
|
|
|
|
presence, exists, err := repository.GetCurrentRoomPresence(ctx, userID)
|
|
if err != nil {
|
|
t.Fatalf("get current room presence failed: %v", err)
|
|
}
|
|
if !exists || presence.RoomID != "room-current-active" || presence.Status != "active" {
|
|
t.Fatalf("old room leave projection must not clear newer room presence: exists=%v presence=%+v", exists, presence)
|
|
}
|
|
}
|
|
|
|
func onlineUserItemByID(items []*roomv1.RoomOnlineUser, userID int64) *roomv1.RoomOnlineUser {
|
|
for _, item := range items {
|
|
if item.GetUserId() == userID {
|
|
return item
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func TestSendGiftPassesHostPeriodScopeToWallet(t *testing.T) {
|
|
ctx := context.Background()
|
|
repository := mysqltest.NewRepository(t)
|
|
wallet := &rocketTestWallet{debits: []*walletv1.DebitGiftResponse{{
|
|
BillingReceiptId: "receipt-host-period",
|
|
CoinSpent: 14,
|
|
GiftPointAdded: 6,
|
|
HeatValue: 22,
|
|
GiftTypeCode: "normal",
|
|
HostPeriodDiamondAdded: 14,
|
|
HostPeriodCycleKey: "2026-05",
|
|
}}}
|
|
now := &fixedRoomRocketClock{now: time.Date(2026, 5, 27, 12, 0, 0, 0, time.UTC)}
|
|
svc := newRocketTestService(t, repository, wallet, now)
|
|
|
|
roomID := "room-host-period-scope"
|
|
senderID := int64(2001)
|
|
hostID := int64(2002)
|
|
createRocketRoom(t, ctx, svc, roomID, senderID, 9001)
|
|
joinRocketRoom(t, ctx, svc, roomID, hostID)
|
|
|
|
if _, err := svc.SendGift(ctx, &roomv1.SendGiftRequest{
|
|
Meta: rocketMeta(roomID, senderID, "host-period-scope"),
|
|
TargetType: "user",
|
|
TargetUserId: hostID,
|
|
GiftId: "gift-host-period",
|
|
GiftCount: 2,
|
|
TargetIsHost: true,
|
|
TargetHostRegionId: 8801,
|
|
TargetAgencyOwnerUserId: 30001,
|
|
}); err != nil {
|
|
t.Fatalf("send host period gift failed: %v", err)
|
|
}
|
|
|
|
if wallet.lastDebit == nil || !wallet.lastDebit.GetTargetIsHost() || wallet.lastDebit.GetTargetHostRegionId() != 8801 || wallet.lastDebit.GetTargetAgencyOwnerUserId() != 30001 {
|
|
t.Fatalf("room-service must pass host period scope to wallet: %+v", wallet.lastDebit)
|
|
}
|
|
}
|
|
|
|
func TestSendGiftPassesBagSourceToWallet(t *testing.T) {
|
|
ctx := context.Background()
|
|
repository := mysqltest.NewRepository(t)
|
|
wallet := &rocketTestWallet{debits: []*walletv1.DebitGiftResponse{
|
|
{
|
|
BillingReceiptId: "receipt-bag-single",
|
|
CoinSpent: 20,
|
|
ChargeAmount: 20,
|
|
ChargeAssetType: "BAG",
|
|
HeatValue: 20,
|
|
GiftTypeCode: "normal",
|
|
},
|
|
{
|
|
BillingReceiptId: "receipt-bag-batch-1",
|
|
CoinSpent: 10,
|
|
ChargeAmount: 10,
|
|
ChargeAssetType: "BAG",
|
|
HeatValue: 10,
|
|
GiftTypeCode: "normal",
|
|
},
|
|
{
|
|
BillingReceiptId: "receipt-bag-batch-2",
|
|
CoinSpent: 10,
|
|
ChargeAmount: 10,
|
|
ChargeAssetType: "BAG",
|
|
HeatValue: 10,
|
|
GiftTypeCode: "normal",
|
|
},
|
|
}}
|
|
now := &fixedRoomRocketClock{now: time.Date(2026, 5, 27, 12, 0, 0, 0, time.UTC)}
|
|
svc := newRocketTestService(t, repository, wallet, now)
|
|
|
|
roomID := "room-bag-source"
|
|
senderID := int64(2101)
|
|
targetOneID := int64(2102)
|
|
targetTwoID := int64(2103)
|
|
createRocketRoom(t, ctx, svc, roomID, senderID, 9001)
|
|
joinRocketRoom(t, ctx, svc, roomID, targetOneID)
|
|
joinRocketRoom(t, ctx, svc, roomID, targetTwoID)
|
|
|
|
if _, err := svc.SendGift(ctx, &roomv1.SendGiftRequest{
|
|
Meta: rocketMeta(roomID, senderID, "bag-single"),
|
|
TargetType: "user",
|
|
TargetUserId: targetOneID,
|
|
GiftId: "gift-bag-single",
|
|
GiftCount: 2,
|
|
EntitlementId: "ent-bag-single",
|
|
Source: "bag",
|
|
}); err != nil {
|
|
t.Fatalf("send single bag gift failed: %v", err)
|
|
}
|
|
if wallet.lastDebit == nil || wallet.lastDebit.GetEntitlementId() != "ent-bag-single" || wallet.lastDebit.GetChargeSource() != "bag" {
|
|
t.Fatalf("single bag gift must pass entitlement/source to wallet: %+v", wallet.lastDebit)
|
|
}
|
|
|
|
if _, err := svc.SendGift(ctx, &roomv1.SendGiftRequest{
|
|
Meta: rocketMeta(roomID, senderID, "bag-batch"),
|
|
TargetType: "user",
|
|
TargetUserId: targetOneID,
|
|
TargetUserIds: []int64{targetOneID, targetTwoID},
|
|
GiftId: "gift-bag-batch",
|
|
GiftCount: 1,
|
|
EntitlementId: "ent-bag-batch",
|
|
Source: "bag",
|
|
}); err != nil {
|
|
t.Fatalf("send batch bag gift failed: %v", err)
|
|
}
|
|
if wallet.lastBatch == nil || wallet.lastBatch.GetEntitlementId() != "ent-bag-batch" || wallet.lastBatch.GetChargeSource() != "bag" {
|
|
t.Fatalf("batch bag gift must pass entitlement/source to wallet: %+v", wallet.lastBatch)
|
|
}
|
|
}
|