package service_test import ( "context" "errors" "testing" "time" roomv1 "hyapp.local/api/proto/room/v1" "hyapp/pkg/tencentim" "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 createRoomIMPublisher struct { err error roomID string ownerUserID int64 callCount int } func (p *createRoomIMPublisher) EnsureRoomGroup(_ context.Context, roomID string, ownerUserID int64) error { p.callCount++ p.roomID = roomID p.ownerUserID = ownerUserID return p.err } func (p *createRoomIMPublisher) PublishRoomEvent(context.Context, tencentim.RoomEvent) error { return nil } func TestCreateRoomSynchronouslyEnsuresIMGroup(t *testing.T) { ctx := context.Background() repository := mysqltest.NewRepository(t) publisher := &createRoomIMPublisher{} svc := roomservice.New(roomservice.Config{ NodeID: "node-create-room-im-test", LeaseTTL: 10 * time.Second, RankLimit: 20, SnapshotEveryN: 1, }, router.NewMemoryDirectory(), repository, followTestWallet{}, publisher, integration.NewNoopOutboxPublisher()) roomID := "room-sync-im-ok" ownerID := int64(7001) resp, err := svc.CreateRoom(ctx, &roomv1.CreateRoomRequest{ Meta: roomservice.NewRequestMeta(roomID, ownerID), SeatCount: 10, Mode: "voice", VisibleRegionId: 1001, RoomName: "Sync IM Room", RoomShortId: "sync-im-ok", }) if err != nil { t.Fatalf("create room failed: %v", err) } if publisher.callCount != 1 || publisher.roomID != roomID || publisher.ownerUserID != ownerID { t.Fatalf("IM group must be ensured once before create returns: %+v", publisher) } if resp.GetRoom().GetRoomId() != roomID || !resp.GetResult().GetApplied() { t.Fatalf("create response mismatch: %+v", resp) } } func TestCreateRoomDoesNotPersistWhenIMGroupEnsureFails(t *testing.T) { ctx := context.Background() repository := mysqltest.NewRepository(t) publisher := &createRoomIMPublisher{err: errors.New("tencent im unavailable")} svc := roomservice.New(roomservice.Config{ NodeID: "node-create-room-im-fail-test", LeaseTTL: 10 * time.Second, RankLimit: 20, SnapshotEveryN: 1, }, router.NewMemoryDirectory(), repository, followTestWallet{}, publisher, integration.NewNoopOutboxPublisher()) roomID := "room-sync-im-fail" ownerID := int64(7002) if _, err := svc.CreateRoom(ctx, &roomv1.CreateRoomRequest{ Meta: roomservice.NewRequestMeta(roomID, ownerID), SeatCount: 10, Mode: "voice", VisibleRegionId: 1001, RoomName: "Sync IM Failure", RoomShortId: "sync-im-fail", }); err == nil { t.Fatalf("create room must fail when IM group cannot be created") } if publisher.callCount != 1 || publisher.roomID != roomID || publisher.ownerUserID != ownerID { t.Fatalf("IM group ensure call mismatch: %+v", publisher) } if meta, exists, err := repository.GetRoomMeta(ctx, roomID); err != nil || exists { t.Fatalf("room meta must not persist after IM failure: meta=%+v exists=%t err=%v", meta, exists, err) } }