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" ) func TestRoomPasswordControlsJoinAndListLockedFlag(t *testing.T) { ctx := context.Background() repository := mysqltest.NewRepository(t) svc := roomservice.New(roomservice.Config{ NodeID: "node-lock-test", LeaseTTL: 10 * time.Second, RankLimit: 20, SnapshotEveryN: 1, }, router.NewMemoryDirectory(), repository, followTestWallet{}, integration.NewNoopRoomEventPublisher(), integration.NewNoopOutboxPublisher()) roomID := "room-lock-flow" ownerID := int64(5101) viewerID := int64(5201) if _, err := svc.CreateRoom(ctx, &roomv1.CreateRoomRequest{ Meta: roomservice.NewRequestMeta(roomID, ownerID), SeatCount: 10, Mode: "voice", VisibleRegionId: 6101, RoomName: "Locked Room", RoomAvatar: testRoomCoverURL, RoomShortId: "lock-flow", }); err != nil { t.Fatalf("create locked room fixture failed: %v", err) } lockMeta := roomservice.NewRequestMeta(roomID, ownerID) lockResp, err := svc.SetRoomPassword(ctx, &roomv1.SetRoomPasswordRequest{ Meta: lockMeta, Locked: true, Password: "1234", }) if err != nil { t.Fatalf("set room password failed: %v", err) } if _, err := svc.SetRoomPassword(ctx, &roomv1.SetRoomPasswordRequest{ Meta: lockMeta, Locked: true, Password: "1234", }); err != nil { t.Fatalf("same command id and same password should be idempotent: %v", err) } if _, err := svc.SetRoomPassword(ctx, &roomv1.SetRoomPasswordRequest{ Meta: lockMeta, Locked: true, Password: "9999", }); err == nil { t.Fatalf("same command id must reject a different room password") } if !lockResp.GetRoom().GetLocked() { t.Fatalf("password response must expose locked snapshot: %+v", lockResp.GetRoom()) } meta, exists, err := repository.GetRoomMeta(ctx, roomID) if err != nil || !exists || meta.RoomPasswordHash == "" || meta.RoomPasswordHash == "1234" { t.Fatalf("room meta must persist only password hash: meta=%+v exists=%t err=%v", meta, exists, err) } listResp, err := svc.ListRooms(ctx, &roomv1.ListRoomsRequest{ Meta: &roomv1.RequestMeta{AppCode: appcode.Default}, ViewerUserId: viewerID, VisibleRegionId: 6101, Tab: "hot", Limit: 20, Query: "lock-flow", }) if err != nil { t.Fatalf("list locked room failed: %v", err) } if len(listResp.GetRooms()) != 1 || !listResp.GetRooms()[0].GetLocked() { t.Fatalf("list/search must return locked flag: %+v", listResp.GetRooms()) } if _, err := svc.JoinRoom(ctx, &roomv1.JoinRoomRequest{ Meta: roomservice.NewRequestMeta(roomID, viewerID), Role: "audience", Password: "wrong", }); err == nil { t.Fatalf("wrong password must not join locked room") } joinResp, err := svc.JoinRoom(ctx, &roomv1.JoinRoomRequest{ Meta: roomservice.NewRequestMeta(roomID, viewerID), Role: "audience", Password: "1234", }) if err != nil { t.Fatalf("correct password should join locked room: %v", err) } if joinResp.GetUser().GetUserId() != viewerID || !joinResp.GetRoom().GetLocked() { t.Fatalf("join response mismatch: user=%+v room=%+v", joinResp.GetUser(), joinResp.GetRoom()) } if _, err := svc.SetRoomPassword(ctx, &roomv1.SetRoomPasswordRequest{ Meta: roomservice.NewRequestMeta(roomID, ownerID), Locked: true, Password: "5678", }); err != nil { t.Fatalf("change room password after viewer joined failed: %v", err) } if _, err := svc.JoinRoom(ctx, &roomv1.JoinRoomRequest{ Meta: roomservice.NewRequestMeta(roomID, viewerID), Role: "audience", Password: "1234", }); err == nil { t.Fatalf("existing online user must not bypass changed room password") } if _, err := svc.JoinRoom(ctx, &roomv1.JoinRoomRequest{ Meta: roomservice.NewRequestMeta(roomID, viewerID), Role: "audience", Password: "5678", }); err != nil { t.Fatalf("existing online user should reconnect with latest room password: %v", err) } }