[FIX] 그룹 채팅 퇴장/강퇴 unread 집계 보정 및 테스트 안정화#87
Hidden character warning
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yml Review profile: ASSERTIVE Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
그룹 채팅에서 멤버가 퇴장/강퇴될 때 남아 있던 unreadCount를 정리해 지표 왜곡을 방지하고, 읽음 처리 시 read-receipt 브로드캐스트 및 Docker 없는 환경에서의 통합 테스트 안정화를 함께 다루는 PR입니다.
Changes:
- 퇴장/강퇴 시
decreaseUnreadCount(...)를 선행 호출하도록 순서 보장(기준 시각은lastReadAt→ 없으면joinedAt) - WebSocket 응답 모델에
unreadCount포함 및 읽음 처리 read-receipt 브로드캐스트 추가 - Docker/Testcontainers 감지 유틸 및 CI 워크플로우/테스트 보강(스킵 로직 포함)
Reviewed changes
Copilot reviewed 15 out of 16 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/main/java/com/project/dorumdorum/domain/chat/application/usecase/LeaveChatRoomUseCase.java | 퇴장 시 unread 감소를 멤버 삭제보다 먼저 수행하도록 로직 순서 보정, WS 응답에 unreadCount 포함 |
| src/main/java/com/project/dorumdorum/domain/chat/application/event/RoommateKickedEventListener.java | 강퇴 시 unread 감소 후 멤버 삭제로 순서 보정, WS 응답에 unreadCount 포함 |
| src/main/java/com/project/dorumdorum/domain/chat/application/usecase/MarkChatRoomReadUseCase.java | 읽음 처리 후 read-receipt를 WebSocket으로 브로드캐스트 |
| src/main/java/com/project/dorumdorum/domain/chat/application/usecase/SendGroupChatMessageUseCase.java | 메시지 WS 응답에 unreadCount 포함 |
| src/main/java/com/project/dorumdorum/domain/chat/application/usecase/JoinChatRoomUseCase.java | 시스템 메시지 WS 응답에 unreadCount 포함 |
| src/main/java/com/project/dorumdorum/domain/chat/application/dto/response/ChatMessageResponse.java | WS 메시지 응답 record에 unreadCount 필드 추가 |
| src/main/java/com/project/dorumdorum/domain/chat/application/dto/response/ChatReadReceiptResponse.java | 읽음 브로드캐스트용 DTO 추가 |
| src/test/java/com/project/dorumdorum/domain/chat/unit/usecase/LeaveChatRoomUseCaseTest.java | unread 감소 → leave 호출 순서 및 분기 테스트 보강(InOrder 포함) |
| src/test/java/com/project/dorumdorum/domain/chat/unit/usecase/RoommateKickedEventListenerTest.java | 강퇴 시 unread 감소 → leave 순서 검증(InOrder) |
| src/test/java/com/project/dorumdorum/domain/chat/unit/usecase/MarkChatRoomReadUseCaseTest.java | read-receipt 브로드캐스트 검증 추가 |
| src/test/java/com/project/dorumdorum/testsupport/TestcontainersSupport.java | Docker 가용성 1회 감지 헬퍼 추가 |
| src/test/java/com/project/dorumdorum/domain/chat/integration/ChatTransactionAtomicityIntegrationTest.java | Docker 미가용 시 스킵 의도 로직 추가(현재 방식에는 이슈 존재) |
| src/test/java/com/project/dorumdorum/domain/chat/integration/ChatRoomSchemaInitializationTest.java | Docker 미가용 시 스킵 의도 로직 추가(현재 방식에는 이슈 존재) |
| .github/workflows/cicd.yml | CI에서 Docker daemon 확인 단계 추가 |
| src/main/resources/application-dev.yml | dev 환경에서 devtools restart 비활성화 |
| .gitignore | .env 정리 및 macOS .DS_Store 추가 |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| @BeforeAll | ||
| static void requireDocker() { | ||
| Assumptions.assumeTrue( | ||
| TestcontainersSupport.requireDockerOrSkip("ChatTransactionAtomicityIntegrationTest"), | ||
| "Docker is required for ChatTransactionAtomicityIntegrationTest" | ||
| ); | ||
| } |
There was a problem hiding this comment.
@SpringBootTest 컨텍스트가 JUnit @BeforeAll 실행 전에 먼저 로드되기 때문에, 여기의 Assumptions.assumeTrue(...)는 Docker 없는 환경에서 Testcontainers JDBC 드라이버가 컨텍스트 초기화 중 컨테이너를 띄우다 실패하는 것을 막지 못합니다. Docker 감지는 클래스 실행 전에 평가되는 조건(예: JUnit5 ExecutionCondition 확장, 또는 Testcontainers JUnit의 @Testcontainers(disabledWithoutDocker = true)/Spring test의 조건부 실행 애너테이션)으로 옮겨서 컨텍스트 자체가 로드되지 않도록 해주세요.
| @BeforeAll | ||
| static void requireDocker() { | ||
| Assumptions.assumeTrue( | ||
| TestcontainersSupport.requireDockerOrSkip("ChatRoomSchemaInitializationTest"), | ||
| "Docker is required for ChatRoomSchemaInitializationTest" | ||
| ); | ||
| } |
There was a problem hiding this comment.
@SpringBootTest는 JUnit @BeforeAll보다 먼저 Spring 컨텍스트를 초기화하므로, 이 Assumptions.assumeTrue(...)로는 Docker 없는 환경에서 Testcontainers datasource 초기화 실패를 방지할 수 없습니다. Docker 필요 여부를 컨텍스트 로딩 이전에 평가되는 방식(예: JUnit5 ExecutionCondition 확장/조건부 실행 애너테이션, 또는 @Testcontainers(disabledWithoutDocker = true) 등)으로 전환해 테스트 클래스 자체가 스킵되도록 해주세요.
| try { | ||
| DockerClientFactory.instance().client(); | ||
| return true; | ||
| } catch (Throwable ignored) { |
There was a problem hiding this comment.
Docker 감지 로직에서 catch (Throwable ...)는 Error(예: OutOfMemoryError)까지 삼켜 디버깅을 어렵게 만들 수 있습니다. Docker 미가용 판별이 목적이라면 Exception(또는 Testcontainers가 던지는 구체 예외 타입)만 잡도록 범위를 좁혀주세요.
| } catch (Throwable ignored) { | |
| } catch (Exception ignored) { |
| ChatRoomMember member = ChatRoomMember.builder().chatRoom(chatRoom).userNo("user-kicked").build(); | ||
| User mockUser = mock(User.class); | ||
| ChatMessage mockMessage = mock(ChatMessage.class); | ||
| when(chatRoomService.findByRoomNo("room-1")).thenReturn(Optional.of(chatRoom)); | ||
| when(chatRoomMemberService.isMember(chatRoom, "user-kicked")).thenReturn(true); | ||
| when(chatRoomMemberService.findByChatRoomAndUserNo(chatRoom, "user-kicked")).thenReturn(member); | ||
| when(userService.findById("user-kicked")).thenReturn(mockUser); |
There was a problem hiding this comment.
이 테스트에서 ChatRoomMember를 builder로 생성하면서 joinedAt/lastReadAt가 모두 null인 상태입니다. 실제 엔티티는 @PrePersist로 joinedAt이 항상 채워지므로, 여기서도 joinedAt을 명시적으로 세팅하고 decreaseUnreadCount의 fromTime이 해당 값으로 계산되는지까지 함께 검증하면 테스트 신뢰도가 올라갑니다.
📝 Pull Request Template
📌 제목
📢 요약
구현/수정 사항
1. 퇴장/강퇴 시 unreadCount 정합성 보장
ChatMessageService.decreaseUnreadCount()를 먼저 호출한 뒤 멤버를 삭제하도록 순서를 보장했습니다.
2. 단위 테스트 보강
되는지, lastReadAt/최소 참여 인원 조건이 만족되는지 확인합니다.
3. Testcontainers 테스트 안정화
Assumptions.assumeTrue(...)를 호출해 Docker가 없으면 테스트를 자동 스킵하도록 만들었습니다. 로컬/CI에서 Docker가
있을 때는 기존과 동일하게 실행됩니다.
🔗 연관 이슈: Resolves #86
🚀 PR 유형
✅ PR 체크리스트
📜 기타