2026-05-14 00:25:02 +08:00

109 lines
3.2 KiB
Go

package service_test
import (
"context"
"testing"
"time"
roomv1 "hyapp.local/api/proto/room/v1"
"hyapp/pkg/appcode"
"hyapp/services/room-service/internal/integration"
roomservice "hyapp/services/room-service/internal/room/service"
"hyapp/services/room-service/internal/router"
"hyapp/services/room-service/internal/testutil/mysqltest"
)
type fakeRTCUserRemover struct {
roomID string
userID int64
}
func (r *fakeRTCUserRemover) RemoveUserByStrRoomID(_ context.Context, roomID string, userID int64) error {
r.roomID = roomID
r.userID = userID
return nil
}
func TestKickUserRemovesPresenceBanAndRTCConnection(t *testing.T) {
ctx := context.Background()
repository := mysqltest.NewRepository(t)
rtc := &fakeRTCUserRemover{}
svc := roomservice.New(roomservice.Config{
NodeID: "node-kick-test",
LeaseTTL: 10 * time.Second,
RankLimit: 20,
SnapshotEveryN: 1,
RTCUserRemover: rtc,
}, router.NewMemoryDirectory(), repository, followTestWallet{}, integration.NewNoopRoomEventPublisher(), integration.NewNoopOutboxPublisher())
roomID := "room-kick-flow"
ownerID := int64(7101)
viewerID := int64(7201)
if _, err := svc.CreateRoom(ctx, &roomv1.CreateRoomRequest{
Meta: roomservice.NewRequestMeta(roomID, ownerID),
SeatCount: 10,
Mode: "voice",
VisibleRegionId: 8101,
RoomName: "Kick Flow",
RoomShortId: "kick-flow",
}); err != nil {
t.Fatalf("create kick room fixture failed: %v", err)
}
if _, err := svc.JoinRoom(ctx, &roomv1.JoinRoomRequest{
Meta: roomservice.NewRequestMeta(roomID, viewerID),
Role: "audience",
}); err != nil {
t.Fatalf("join kick target failed: %v", err)
}
kickResp, err := svc.KickUser(ctx, &roomv1.KickUserRequest{
Meta: roomservice.NewRequestMeta(roomID, ownerID),
TargetUserId: viewerID,
})
if err != nil {
t.Fatalf("kick user failed: %v", err)
}
if !kickResp.GetRtcKicked() || kickResp.GetRtcKickError() != "" || rtc.roomID != roomID || rtc.userID != viewerID {
t.Fatalf("kick must remove RTC user after Room Cell commit: resp=%+v rtc=%+v", kickResp, rtc)
}
if !containsInt64(kickResp.GetRoom().GetBanUserIds(), viewerID) || findRoomUser(kickResp.GetRoom(), viewerID) != nil {
t.Fatalf("kick response must ban and remove target presence: %+v", kickResp.GetRoom())
}
presenceResp, err := svc.VerifyRoomPresence(ctx, &roomv1.VerifyRoomPresenceRequest{
AppCode: appcode.Default,
RoomId: roomID,
UserId: viewerID,
})
if err != nil {
t.Fatalf("verify room presence after kick failed: %v", err)
}
if presenceResp.GetPresent() || presenceResp.GetReason() != "user_banned" {
t.Fatalf("kicked user must not pass IM presence guard: %+v", presenceResp)
}
if _, err := svc.JoinRoom(ctx, &roomv1.JoinRoomRequest{
Meta: roomservice.NewRequestMeta(roomID, viewerID),
Role: "audience",
}); err == nil {
t.Fatalf("kicked user must not join before unban")
}
}
func findRoomUser(snapshot *roomv1.RoomSnapshot, userID int64) *roomv1.RoomUser {
for _, user := range snapshot.GetOnlineUsers() {
if user.GetUserId() == userID {
return user
}
}
return nil
}
func containsInt64(values []int64, target int64) bool {
for _, value := range values {
if value == target {
return true
}
}
return false
}