diff --git a/src/main/java/com/back/domain/studyroom/service/RoomService.java b/src/main/java/com/back/domain/studyroom/service/RoomService.java index 93a7ecdc..fb4b582e 100644 --- a/src/main/java/com/back/domain/studyroom/service/RoomService.java +++ b/src/main/java/com/back/domain/studyroom/service/RoomService.java @@ -719,8 +719,22 @@ public void kickMember(Long roomId, Long targetUserId, Long requesterId) { // 4. Redis에서 제거 (강제 퇴장) - VISITOR 포함 모든 사용자 roomParticipantService.exitRoom(targetUserId, roomId); + + // 5. 추방당한 유저에게 개인 WebSocket 메시지 전송 + java.util.Map kickNotification = new java.util.HashMap<>(); + kickNotification.put("type", "MEMBER_KICKED"); + kickNotification.put("roomId", roomId); + kickNotification.put("message", "방에서 추방되었습니다"); + + messagingTemplate.convertAndSendToUser( + targetUserId.toString(), + "/queue/kick", + kickNotification + ); + + log.info("추방 알림 전송 완료 - RoomId: {}, TargetUserId: {}", roomId, targetUserId); - // 5. 멤버 추방 이벤트 발행 + // 6. 멤버 추방 이벤트 발행 (알림 시스템용) Room room = roomRepository.findById(roomId) .orElseThrow(() -> new CustomException(ErrorCode.ROOM_NOT_FOUND)); diff --git a/src/test/java/com/back/domain/studyroom/service/RoomServiceTest.java b/src/test/java/com/back/domain/studyroom/service/RoomServiceTest.java index e0541567..6577c0b0 100644 --- a/src/test/java/com/back/domain/studyroom/service/RoomServiceTest.java +++ b/src/test/java/com/back/domain/studyroom/service/RoomServiceTest.java @@ -64,6 +64,9 @@ class RoomServiceTest { @Mock private RoomThumbnailService roomThumbnailService; + + @Mock + private org.springframework.messaging.simp.SimpMessagingTemplate messagingTemplate; @InjectMocks private RoomService roomService; @@ -400,13 +403,15 @@ void kickMember_Success() { given(roomMemberRepository.findByRoomIdAndUserId(1L, 1L)).willReturn(Optional.of(hostMember)); given(roomParticipantService.getParticipants(1L)).willReturn(java.util.Set.of(2L)); // 온라인 사용자 목록 given(roomMemberRepository.findByRoomIdAndUserId(1L, 2L)).willReturn(Optional.empty()); // VISITOR는 DB에 없음 - given(roomRepository.findById(1L)).willReturn(Optional.of(testRoom)); + given(roomRepository.findById(1L)).willReturn(Optional.of(testRoom)); // Room 조회 추가 // when roomService.kickMember(1L, 2L, 1L); // then verify(roomParticipantService, times(1)).exitRoom(2L, 1L); // Redis 퇴장 확인 + verify(messagingTemplate, times(1)).convertAndSendToUser(eq("2"), eq("/queue/kick"), any()); // WebSocket 메시지 전송 확인 + verify(eventPublisher, times(1)).publishEvent(any(com.back.domain.notification.event.studyroom.MemberKickedEvent.class)); // 이벤트 발행 확인 } @Test @@ -418,13 +423,15 @@ void kickMember_VisitorSuccess() { given(roomMemberRepository.findByRoomIdAndUserId(1L, 1L)).willReturn(Optional.of(hostMember)); given(roomParticipantService.getParticipants(1L)).willReturn(java.util.Set.of(2L)); // VISITOR가 온라인 상태 given(roomMemberRepository.findByRoomIdAndUserId(1L, 2L)).willReturn(Optional.empty()); // DB에 없음 - given(roomRepository.findById(1L)).willReturn(Optional.of(testRoom)); + given(roomRepository.findById(1L)).willReturn(Optional.of(testRoom)); // Room 조회 추가 // when roomService.kickMember(1L, 2L, 1L); // then verify(roomParticipantService, times(1)).exitRoom(2L, 1L); + verify(messagingTemplate, times(1)).convertAndSendToUser(eq("2"), eq("/queue/kick"), any()); // WebSocket 메시지 전송 확인 + verify(eventPublisher, times(1)).publishEvent(any(com.back.domain.notification.event.studyroom.MemberKickedEvent.class)); // 이벤트 발행 확인 } @Test @@ -448,13 +455,15 @@ void kickMember_MemberSuccess() { given(roomMemberRepository.findByRoomIdAndUserId(1L, 1L)).willReturn(Optional.of(hostMember)); given(roomParticipantService.getParticipants(1L)).willReturn(java.util.Set.of(2L)); // MEMBER가 온라인 상태 given(roomMemberRepository.findByRoomIdAndUserId(1L, 2L)).willReturn(Optional.of(targetMember)); // DB에 있음 - given(roomRepository.findById(1L)).willReturn(Optional.of(testRoom)); + given(roomRepository.findById(1L)).willReturn(Optional.of(testRoom)); // Room 조회 추가 // when roomService.kickMember(1L, 2L, 1L); // then verify(roomParticipantService, times(1)).exitRoom(2L, 1L); + verify(messagingTemplate, times(1)).convertAndSendToUser(eq("2"), eq("/queue/kick"), any()); // WebSocket 메시지 전송 확인 + verify(eventPublisher, times(1)).publishEvent(any(com.back.domain.notification.event.studyroom.MemberKickedEvent.class)); // 이벤트 발행 확인 } @Test