From 62c834d28f0d142e81f2d303273eb1220cab0611 Mon Sep 17 00:00:00 2001 From: Klaus Date: Mon, 14 Sep 2026 14:50:54 +0900 Subject: [PATCH] =?UTF-8?q?test(user-creator-chat):=20=ED=81=AC=EB=A6=AC?= =?UTF-8?q?=EC=97=90=EC=9D=B4=ED=84=B0=20=EC=8B=9C=EC=9E=91=20DM=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=EC=9D=84=20=EA=B2=80=EC=A6=9D=ED=95=9C?= =?UTF-8?q?=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/UserCreatorChatService.kt | 10 ++--- .../UserCreatorChatServiceIntegrationTest.kt | 36 ++++++++++++++++++ .../UserCreatorChatServiceTest.kt | 38 +++++++++++++++++++ 3 files changed, 79 insertions(+), 5 deletions(-) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/v2/usercreatorchat/service/UserCreatorChatService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/v2/usercreatorchat/service/UserCreatorChatService.kt index 7150767c..86e2be85 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/v2/usercreatorchat/service/UserCreatorChatService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/v2/usercreatorchat/service/UserCreatorChatService.kt @@ -59,20 +59,20 @@ class UserCreatorChatService( private val cloudFrontHost: String ) { @Transactional - fun createOrGetRoom(member: Member, creatorId: Long): CreateUserCreatorChatRoomResponse { - val creator = memberRepository.findById(creatorId).orElseThrow { + fun createOrGetRoom(member: Member, recipientId: Long): CreateUserCreatorChatRoomResponse { + val recipient = memberRepository.findById(recipientId).orElseThrow { SodaException(messageKey = "message.error.recipient_not_found") } - validateRecipient(member, creator) + validateRecipient(member, recipient) - val existingRoom = roomRepository.findActiveRoomByParticipantMemberIds(member.id!!, creator.id!!) + val existingRoom = roomRepository.findActiveRoomByParticipantMemberIds(member.id!!, recipient.id!!) if (existingRoom != null) { return CreateUserCreatorChatRoomResponse(roomId = existingRoom.id!!) } val room = roomRepository.save(UserCreatorChatRoom()) participantRepository.save(UserCreatorChatParticipant(room, member)) - participantRepository.save(UserCreatorChatParticipant(room, creator)) + participantRepository.save(UserCreatorChatParticipant(room, recipient)) return CreateUserCreatorChatRoomResponse(roomId = room.id!!) } diff --git a/src/test/kotlin/kr/co/vividnext/sodalive/v2/usercreatorchat/UserCreatorChatServiceIntegrationTest.kt b/src/test/kotlin/kr/co/vividnext/sodalive/v2/usercreatorchat/UserCreatorChatServiceIntegrationTest.kt index 339dd17b..cff277d0 100644 --- a/src/test/kotlin/kr/co/vividnext/sodalive/v2/usercreatorchat/UserCreatorChatServiceIntegrationTest.kt +++ b/src/test/kotlin/kr/co/vividnext/sodalive/v2/usercreatorchat/UserCreatorChatServiceIntegrationTest.kt @@ -31,6 +31,42 @@ class UserCreatorChatServiceIntegrationTest @Autowired constructor( private val messageRepository: UserCreatorChatMessageRepository, private val entityManager: EntityManager ) { + @Test + @DisplayName("기존 리스너 시작 DM 방 생성 흐름은 계속 동작한다") + fun shouldCreateRoomWhenListenerStartsDmToCreator() { + val user = memberRepository.save(Member(email = "listener-start@test.com", password = "pw", nickname = "listener")) + val creator = memberRepository.save( + Member(email = "creator-target@test.com", password = "pw", nickname = "creator", role = MemberRole.CREATOR) + ) + entityManager.flush() + entityManager.clear() + + val response = service.createOrGetRoom(user, creator.id!!) + + assertEquals(1, roomRepository.findAll().size) + assertEquals(roomRepository.findAll().single().id, response.roomId) + assertEquals(2, participantRepository.findAll().size) + assertEquals(0, messageRepository.findAll().size) + } + + @Test + @DisplayName("크리에이터도 일반 회원에게 DM 방을 먼저 생성할 수 있다") + fun shouldCreateRoomWhenCreatorStartsDmToListener() { + val creator = memberRepository.save( + Member(email = "creator-start@test.com", password = "pw", nickname = "creator", role = MemberRole.CREATOR) + ) + val listener = memberRepository.save(Member(email = "listener-target@test.com", password = "pw", nickname = "listener")) + entityManager.flush() + entityManager.clear() + + val response = service.createOrGetRoom(creator, listener.id!!) + + assertEquals(1, roomRepository.findAll().size) + assertEquals(roomRepository.findAll().single().id, response.roomId) + assertEquals(2, participantRepository.findAll().size) + assertEquals(0, messageRepository.findAll().size) + } + @Test @DisplayName("AI 캐릭터용 Member와는 유저-크리에이터 DM 방을 생성할 수 없다") fun shouldRejectCreateRoomWhenCreatorIsAiCharacterMember() { diff --git a/src/test/kotlin/kr/co/vividnext/sodalive/v2/usercreatorchat/UserCreatorChatServiceTest.kt b/src/test/kotlin/kr/co/vividnext/sodalive/v2/usercreatorchat/UserCreatorChatServiceTest.kt index fd564faa..5ef9bd4b 100644 --- a/src/test/kotlin/kr/co/vividnext/sodalive/v2/usercreatorchat/UserCreatorChatServiceTest.kt +++ b/src/test/kotlin/kr/co/vividnext/sodalive/v2/usercreatorchat/UserCreatorChatServiceTest.kt @@ -8,6 +8,7 @@ import kr.co.vividnext.sodalive.fcm.FcmEvent import kr.co.vividnext.sodalive.fcm.FcmEventType import kr.co.vividnext.sodalive.member.Member import kr.co.vividnext.sodalive.member.MemberRepository +import kr.co.vividnext.sodalive.member.MemberRole import kr.co.vividnext.sodalive.member.block.BlockMemberRepository import kr.co.vividnext.sodalive.v2.usercreatorchat.dto.UserCreatorChatMessageItemDto import kr.co.vividnext.sodalive.v2.usercreatorchat.repository.UserCreatorChatMessageRepository @@ -93,6 +94,43 @@ class UserCreatorChatServiceTest { Mockito.verify(participantRepository, Mockito.times(2)).save(Mockito.any(UserCreatorChatParticipant::class.java)) } + @Test + @DisplayName("크리에이터도 일반 회원에게 DM 방을 먼저 생성할 수 있고 메시지는 생성하지 않는다") + fun shouldCreateRoomWhenCreatorStartsDmToUser() { + val creator = member(1L, "creator").apply { role = MemberRole.CREATOR } + val user = member(2L, "user") + Mockito.`when`(memberRepository.findById(2L)).thenReturn(Optional.of(user)) + Mockito.`when`(roomRepository.findActiveRoomByParticipantMemberIds(1L, 2L)).thenReturn(null) + Mockito.`when`(roomRepository.save(Mockito.any(UserCreatorChatRoom::class.java))).thenAnswer { invocation -> + (invocation.arguments[0] as UserCreatorChatRoom).apply { id = 10L } + } + + val response = service.createOrGetRoom(creator, 2L) + + assertEquals(10L, response.roomId) + val participantCaptor = ArgumentCaptor.forClass(UserCreatorChatParticipant::class.java) + Mockito.verify(participantRepository, Mockito.times(2)).save(participantCaptor.capture()) + assertEquals(listOf(creator, user), participantCaptor.allValues.map { it.member }) + Mockito.verifyNoInteractions(messageRepository) + } + + @Test + @DisplayName("기존 활성 방이 있으면 새 방과 메시지를 생성하지 않고 기존 roomId를 반환한다") + fun shouldReturnExistingRoomWithoutCreatingMessage() { + val creator = member(1L, "creator").apply { role = MemberRole.CREATOR } + val user = member(2L, "user") + val existingRoom = room(10L) + Mockito.`when`(memberRepository.findById(2L)).thenReturn(Optional.of(user)) + Mockito.`when`(roomRepository.findActiveRoomByParticipantMemberIds(1L, 2L)).thenReturn(existingRoom) + + val response = service.createOrGetRoom(creator, 2L) + + assertEquals(10L, response.roomId) + Mockito.verify(roomRepository, Mockito.never()).save(Mockito.any(UserCreatorChatRoom::class.java)) + Mockito.verifyNoInteractions(participantRepository) + Mockito.verifyNoInteractions(messageRepository) + } + @Test @DisplayName("방 입장 응답은 상대방 닉네임과 프로필 이미지 URL을 포함한다") fun shouldOpenRoomWithOpponentProfileWhenOpponentHasProfileImage() {