Conversation
- 통화 시작 이벤트 -> 녹음 시작 체인
- 매칭 성공 -> WebSocket 알림, Agora 채널 오케스트레이션
- 유예 기간 만료 처리 스케줄러
- enqueue, dequeue, 큐 상태 조회, 차단 등
- GitHub Actions CI 워크플로우 추가 (.github/workflows/ci.yml) - 멀티스테이지 Dockerfile 추가 (CD 단계 대비)
WalkthroughGitHub Actions CI 워크플로우와 멀티스테이지 Dockerfile이 추가되었고, 이벤트 리스너·스케줄러·Redis 매칭 큐 관련의 여러 JUnit 5 단위 테스트 및 테스트 환경 설정 변경이 포함되었습니다. Changes
Sequence Diagram(s)(생략) Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (7)
src/test/java/com/ldsilver/chingoohaja/service/RedisMatchingQueueServiceOperationTest.java (1)
225-270: Redis 키 패턴이 하드코딩되어 있습니다.
"user:blocked:1","user:blocked:2"등의 키 패턴이 테스트에 직접 작성되어 있습니다. 구현체의 키 형식이 변경되면 테스트가 실패할 수 있습니다.RedisMatchingConstants의 키 빌더를 사용하는 것을 고려하세요.💡 제안된 수정 예시
+import static com.ldsilver.chingoohaja.infrastructure.redis.RedisMatchingConstants.KeyBuilder.blockedUsersKey; + `@Test` `@DisplayName`("차단 목록에 추가 후 isBlocked가 true를 반환한다") void givenBlockedUser_whenIsBlocked_thenReturnsTrue() { // given when(redisTemplate.opsForSet()).thenReturn(setOperations); when(redisTemplate.expire(anyString(), any())).thenReturn(true); - when(setOperations.isMember("user:blocked:1", "2")).thenReturn(true); - when(setOperations.isMember("user:blocked:2", "1")).thenReturn(false); + when(setOperations.isMember(blockedUsersKey(1L), "2")).thenReturn(true); + when(setOperations.isMember(blockedUsersKey(2L), "1")).thenReturn(false);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/test/java/com/ldsilver/chingoohaja/service/RedisMatchingQueueServiceOperationTest.java` around lines 225 - 270, Tests in RedisMatchingQueueServiceOperationTest hardcode Redis keys like "user:blocked:1"/"user:blocked:2", making them brittle; replace hardcoded strings with the same key-building helper used by production (e.g., RedisMatchingConstants or the service's key builder) so the tests follow implementation changes. Update the test setup in methods testing isBlocked and saveBlockedUsers to call the key builder (referencing RedisMatchingConstants or redisMatchingQueueService's key generation method) to produce keys for setOperations.isMember and any expire stubbing, and use those generated keys when stubbing redisTemplate.opsForSet()/setOperations behavior.src/test/java/com/ldsilver/chingoohaja/listener/CallEventListenerTest.java (1)
77-87: 예외 비전파 테스트에 명시적 검증 추가를 고려하세요.현재 테스트는 예외가 전파되지 않음을 암묵적으로 확인합니다.
assertDoesNotThrow를 사용하면 테스트 의도가 더 명확해집니다.💡 제안된 수정
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + `@Test` `@DisplayName`("녹음 서비스에서 예외가 발생해도 통화는 계속 진행된다") void givenRecordingServiceThrows_whenCallStarted_thenDoesNotPropagate() { // given when(recordingProperties.isAutoStart()).thenReturn(true); doThrow(new RuntimeException("Agora 오류")).when(agoraRecordingService).startRecording(any()); CallStartedEvent event = new CallStartedEvent(1L, "channel-abc"); - // when & then (예외가 전파되지 않아야 함) - callEventListener.handleCallStarted(event); + // when & then + assertDoesNotThrow(() -> callEventListener.handleCallStarted(event)); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/test/java/com/ldsilver/chingoohaja/listener/CallEventListenerTest.java` around lines 77 - 87, Update the test givenRecordingServiceThrows_whenCallStarted_thenDoesNotPropagate to explicitly assert that no exception is thrown: wrap the call to callEventListener.handleCallStarted(event) with JUnit's assertDoesNotThrow (import from org.junit.jupiter.api.Assertions) so the test intent is clear; leave the existing stubbing of recordingProperties.isAutoStart() and doThrow(...) on agoraRecordingService unchanged and only change the assertion around handleCallStarted(event).src/test/java/com/ldsilver/chingoohaja/scheduler/GracePeriodSchedulerTest.java (1)
122-137: 테스트 설명과 검증 내용이 일치하지 않습니다.
@DisplayName이 "상태를 로그에 남긴다"라고 명시하지만, 실제로 로깅 동작을 검증하지 않습니다. 테스트 설명을 수정하거나 로그 검증을 추가하는 것을 고려하세요.💡 제안된 수정 - 테스트 설명 변경
`@Test` - `@DisplayName`("두 사용자 모두 유예 기간이면 상태를 로그에 남긴다") - void givenBothUsersInGrace_whenCheck_thenLogsStatus() { + `@DisplayName`("두 사용자 모두 유예 기간이면 유예 기간 체크를 수행한다") + void givenBothUsersInGrace_whenCheck_thenChecksGracePeriod() {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/test/java/com/ldsilver/chingoohaja/scheduler/GracePeriodSchedulerTest.java` around lines 122 - 137, The test method givenBothUsersInGrace_whenCheck_thenLogsStatus in GracePeriodSchedulerTest has a DisplayName claiming it verifies logging but only asserts calls to gracePeriodService; either update the DisplayName to reflect current behavior (e.g., "...thenChecksGracePeriodForBothUsers") or add verification of the logging side-effect: mock or capture the logger used by GracePeriodScheduler (or attach a test appender) and after calling gracePeriodScheduler.checkExpiredGracePeriods() assert that the expected log message was emitted; modify the test accordingly to reference the method under test (gracePeriodScheduler.checkExpiredGracePeriods()) and the mocks (callRepository, gracePeriodService) so the intent matches implementation.src/test/java/com/ldsilver/chingoohaja/listener/MatchingEventListenerTest.java (2)
146-169: 이벤트 발행 검증이 너무 일반적입니다.
any(Object.class)로 검증하면 어떤 타입의 이벤트든 발행되면 통과합니다.CallStartedEvent타입을 명시적으로 검증하면 테스트가 더 강력해집니다.💡 제안된 수정
+import com.ldsilver.chingoohaja.event.CallStartedEvent; +import org.mockito.ArgumentCaptor; + // then - verify(eventPublisher).publishEvent(any(Object.class)); + ArgumentCaptor<CallStartedEvent> eventCaptor = ArgumentCaptor.forClass(CallStartedEvent.class); + verify(eventPublisher).publishEvent(eventCaptor.capture()); + assertThat(eventCaptor.getValue().callId()).isEqualTo(100L);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/test/java/com/ldsilver/chingoohaja/listener/MatchingEventListenerTest.java` around lines 146 - 169, The test MatchingEventListenerTest currently verifies eventPublication with verify(eventPublisher).publishEvent(any(Object.class)), which is too loose; change the assertion in the given test (method givenAutoRecordingEnabled_whenMatchingSuccess_thenPublishesCallStartedEvent) to assert the specific event type published—i.e., replace the any(Object.class) matcher with a type-specific matcher like isA(CallStartedEvent.class) or argThat(e -> e instanceof CallStartedEvent && /* optional checks */) when verifying eventPublisher.publishEvent after calling matchingEventListener.handleMatchingSuccess(event); this ensures the test verifies a CallStartedEvent is published rather than any object.
42-53: Mock 의존성이 많습니다 (10개 이상).MatchingEventListener가 많은 의존성을 가지고 있어 단일 책임 원칙(SRP) 관점에서 향후 리팩토링을 고려해볼 수 있습니다. 현재 테스트 작성에는 문제가 없으나, 프로덕션 코드의 복잡도가 높을 수 있음을 시사합니다.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/test/java/com/ldsilver/chingoohaja/listener/MatchingEventListenerTest.java` around lines 42 - 53, MatchingEventListener currently depends on many collaborators (RedisMatchingQueueService, WebSocketEventService, CallRepository, CallChannelService, AgoraTokenService, AgoraService, MatchingService, CallSessionRepository, RecordingProperties, ApplicationEventPublisher), indicating a SRP violation; to fix, analyze MatchingEventListener to group related responsibilities (e.g., queueing/dispatch, call/session management, agora/token/recording concerns), extract those groups into cohesive classes or facades (e.g., MatchingQueueFacade, CallManagementService, AgoraFacade) and update MatchingEventListener to depend on those fewer abstractions, then update tests to mock the new facades (reducing the number of `@Mock` fields) and adjust existing interaction tests to verify facade calls instead of many low-level collaborators.Dockerfile (1)
27-27: JAR 파일 glob 패턴이 여러 파일을 복사할 수 있음.
*.jar패턴은build/libs/디렉토리에 여러 JAR 파일이 존재할 경우 예측 불가능한 동작을 유발할 수 있습니다. 명시적인 파일 이름 패턴 사용을 권장합니다.💡 제안된 수정
-COPY --from=builder /app/build/libs/*.jar app.jar +COPY --from=builder /app/build/libs/*-SNAPSHOT.jar app.jar또는 빌드 시
-Pversion을 사용하여 버전을 고정하고 해당 패턴을 사용하는 것을 고려하세요.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Dockerfile` at line 27, The Dockerfile line using a glob COPY --from=builder /app/build/libs/*.jar app.jar can match multiple JARs and cause unpredictable builds; change the build to produce a single predictable artifact (e.g., set archiveFileName or use -Pversion in Gradle) and then replace the COPY with the explicit filename from the builder stage (e.g., COPY --from=builder /app/build/libs/my-app-<version>.jar app.jar) or ensure the build writes a consistent fixed name so the COPY references that exact JAR rather than *.jar..github/workflows/ci.yml (1)
48-53: 테스트 실패 시 디버깅을 위해--stacktrace옵션 추가를 고려하세요.CI에서 테스트 실패 시 상세한 스택 트레이스가 있으면 문제 해결이 더 쉬워집니다.
💡 제안된 수정
- name: 테스트 실행 - run: ./gradlew test --no-daemon + run: ./gradlew test --no-daemon --stacktrace env: SPRING_PROFILES_ACTIVE: test SPRING_DATA_REDIS_HOST: localhost SPRING_DATA_REDIS_PORT: 6379🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/ci.yml around lines 48 - 53, The CI test step named "테스트 실행" currently runs "./gradlew test --no-daemon"; update that run command to include the Gradle "--stacktrace" flag (e.g., "./gradlew test --no-daemon --stacktrace") so failing tests produce full stack traces for debugging; modify the workflow step where the "테스트 실행" name and the run command are defined to include this flag.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In @.github/workflows/ci.yml:
- Around line 48-53: The CI test step named "테스트 실행" currently runs "./gradlew
test --no-daemon"; update that run command to include the Gradle "--stacktrace"
flag (e.g., "./gradlew test --no-daemon --stacktrace") so failing tests produce
full stack traces for debugging; modify the workflow step where the "테스트 실행"
name and the run command are defined to include this flag.
In `@Dockerfile`:
- Line 27: The Dockerfile line using a glob COPY --from=builder
/app/build/libs/*.jar app.jar can match multiple JARs and cause unpredictable
builds; change the build to produce a single predictable artifact (e.g., set
archiveFileName or use -Pversion in Gradle) and then replace the COPY with the
explicit filename from the builder stage (e.g., COPY --from=builder
/app/build/libs/my-app-<version>.jar app.jar) or ensure the build writes a
consistent fixed name so the COPY references that exact JAR rather than *.jar.
In `@src/test/java/com/ldsilver/chingoohaja/listener/CallEventListenerTest.java`:
- Around line 77-87: Update the test
givenRecordingServiceThrows_whenCallStarted_thenDoesNotPropagate to explicitly
assert that no exception is thrown: wrap the call to
callEventListener.handleCallStarted(event) with JUnit's assertDoesNotThrow
(import from org.junit.jupiter.api.Assertions) so the test intent is clear;
leave the existing stubbing of recordingProperties.isAutoStart() and
doThrow(...) on agoraRecordingService unchanged and only change the assertion
around handleCallStarted(event).
In
`@src/test/java/com/ldsilver/chingoohaja/listener/MatchingEventListenerTest.java`:
- Around line 146-169: The test MatchingEventListenerTest currently verifies
eventPublication with verify(eventPublisher).publishEvent(any(Object.class)),
which is too loose; change the assertion in the given test (method
givenAutoRecordingEnabled_whenMatchingSuccess_thenPublishesCallStartedEvent) to
assert the specific event type published—i.e., replace the any(Object.class)
matcher with a type-specific matcher like isA(CallStartedEvent.class) or
argThat(e -> e instanceof CallStartedEvent && /* optional checks */) when
verifying eventPublisher.publishEvent after calling
matchingEventListener.handleMatchingSuccess(event); this ensures the test
verifies a CallStartedEvent is published rather than any object.
- Around line 42-53: MatchingEventListener currently depends on many
collaborators (RedisMatchingQueueService, WebSocketEventService, CallRepository,
CallChannelService, AgoraTokenService, AgoraService, MatchingService,
CallSessionRepository, RecordingProperties, ApplicationEventPublisher),
indicating a SRP violation; to fix, analyze MatchingEventListener to group
related responsibilities (e.g., queueing/dispatch, call/session management,
agora/token/recording concerns), extract those groups into cohesive classes or
facades (e.g., MatchingQueueFacade, CallManagementService, AgoraFacade) and
update MatchingEventListener to depend on those fewer abstractions, then update
tests to mock the new facades (reducing the number of `@Mock` fields) and adjust
existing interaction tests to verify facade calls instead of many low-level
collaborators.
In
`@src/test/java/com/ldsilver/chingoohaja/scheduler/GracePeriodSchedulerTest.java`:
- Around line 122-137: The test method
givenBothUsersInGrace_whenCheck_thenLogsStatus in GracePeriodSchedulerTest has a
DisplayName claiming it verifies logging but only asserts calls to
gracePeriodService; either update the DisplayName to reflect current behavior
(e.g., "...thenChecksGracePeriodForBothUsers") or add verification of the
logging side-effect: mock or capture the logger used by GracePeriodScheduler (or
attach a test appender) and after calling
gracePeriodScheduler.checkExpiredGracePeriods() assert that the expected log
message was emitted; modify the test accordingly to reference the method under
test (gracePeriodScheduler.checkExpiredGracePeriods()) and the mocks
(callRepository, gracePeriodService) so the intent matches implementation.
In
`@src/test/java/com/ldsilver/chingoohaja/service/RedisMatchingQueueServiceOperationTest.java`:
- Around line 225-270: Tests in RedisMatchingQueueServiceOperationTest hardcode
Redis keys like "user:blocked:1"/"user:blocked:2", making them brittle; replace
hardcoded strings with the same key-building helper used by production (e.g.,
RedisMatchingConstants or the service's key builder) so the tests follow
implementation changes. Update the test setup in methods testing isBlocked and
saveBlockedUsers to call the key builder (referencing RedisMatchingConstants or
redisMatchingQueueService's key generation method) to produce keys for
setOperations.isMember and any expire stubbing, and use those generated keys
when stubbing redisTemplate.opsForSet()/setOperations behavior.
- ci.yml: ./gradlew test에 --stacktrace 플래그 추가 - Dockerfile: 와일드카드 *.jar → app.jar로 명시 (build.gradle에 bootJar 블록 추가) - CallEventListenerTest: 예외 전파 차단 검증에 assertDoesNotThrow 추가 - MatchingEventListenerTest: publishEvent 검증을 ArgumentCaptor로 교체하여 publishEvent(Object) 오버로드와의 타입 불일치 해소 - GracePeriodSchedulerTest: givenBothUsersInGrace 테스트 DisplayName 명확화 - RedisMatchingQueueServiceOperationTest: 하드코딩된 Redis 키 문자열을 blockedKey(Long) 헬퍼 메서드로 추출하여 중복 제거
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (4)
.github/workflows/ci.yml (1)
55-60: 테스트 결과 업로드에 JUnit XML도 포함하는 것을 고려해 주세요.
현재 HTML 리포트만 업로드됩니다.build/test-results/test/(JUnit XML)을 함께 업로드하면 다른 CI 도구와 연동·가공이 쉬워집니다.💡 제안 변경
with: name: test-results - path: build/reports/tests/test/ + path: | + build/reports/tests/test/ + build/test-results/test/ retention-days: 7🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/ci.yml around lines 55 - 60, Update the "테스트 결과 업로드" upload-artifact step that uses actions/upload-artifact@v4 to include the JUnit XML output path in addition to the HTML report; include both build/reports/tests/test/ and build/test-results/test/ (the JUnit XML directory) in the "path" so the artifact contains HTML and JUnit XML results for downstream CI tools and reporting.src/test/java/com/ldsilver/chingoohaja/scheduler/GracePeriodSchedulerTest.java (1)
60-68:setId헬퍼 메서드가 여러 테스트 파일에 중복됩니다.이 헬퍼 메서드가
MatchingEventListenerTest와 동일하게 존재합니다. 공통 테스트 유틸리티 클래스로 추출하면 중복을 줄일 수 있습니다.♻️ 공통 유틸리티 추출 제안
// src/test/java/com/ldsilver/chingoohaja/support/TestEntityUtils.java public final class TestEntityUtils { private TestEntityUtils() {} public static void setId(Object entity, Long id) { try { Field field = entity.getClass().getDeclaredField("id"); field.setAccessible(true); field.set(entity, id); } catch (Exception e) { throw new RuntimeException(e); } } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/test/java/com/ldsilver/chingoohaja/scheduler/GracePeriodSchedulerTest.java` around lines 60 - 68, Extract the duplicated private helper setId method into a shared test utility: create a final utility class TestEntityUtils with a public static setId(Object entity, Long id) method (matching the implementation in GracePeriodSchedulerTest and MatchingEventListenerTest), remove the private setId from both test classes, and update both GracePeriodSchedulerTest and MatchingEventListenerTest to call TestEntityUtils.setId(...) so the reflection logic is centralized and duplication is eliminated.src/test/java/com/ldsilver/chingoohaja/service/RedisMatchingQueueServiceOperationTest.java (1)
94-127: dequeueUser에 Redis 예외 처리 테스트가 누락되었습니다.
EnqueueUser테스트에서는 Redis 예외 발생 시REDIS_ERROR메시지와 함께 실패를 반환하는지 검증하지만,DequeueUser에는 동일한 테스트가 없습니다. 일관성을 위해 추가를 고려해 주세요.♻️ 추가 테스트 제안
`@Test` `@DisplayName`("Redis 오류 발생 시 DequeueResult(success=false)를 반환한다") void givenRedisException_whenDequeue_thenReturnsFailure() { // given when(redisTemplate.execute(any(RedisScript.class), anyList(), any(Object[].class))) .thenThrow(new RuntimeException("Redis 연결 실패")); // when RedisMatchingQueueService.DequeueResult result = redisMatchingQueueService.dequeueUser(100L, 1L); // then assertThat(result.success()).isFalse(); assertThat(result.message()).isEqualTo(RedisMatchingConstants.ResponseMessage.REDIS_ERROR); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/test/java/com/ldsilver/chingoohaja/service/RedisMatchingQueueServiceOperationTest.java` around lines 94 - 127, Add a test that verifies Redis exceptions during dequeue are handled like enqueue: stub redisTemplate.execute to throw (e.g., new RuntimeException("Redis 연결 실패")) and call RedisMatchingQueueService.dequeueUser(100L, 1L); assert the returned DequeueResult has success() == false and message() equals RedisMatchingConstants.ResponseMessage.REDIS_ERROR; place the test alongside the other DequeueUser tests and use the same mocking pattern (when(redisTemplate.execute(...)).thenThrow(...)) so dequeueUser properly maps Redis failures to a failure result.src/test/java/com/ldsilver/chingoohaja/listener/MatchingEventListenerTest.java (1)
171-173: ArgumentCaptor 타입을 더 구체적으로 지정할 수 있습니다.
Object.class대신CallStartedEvent.class를 사용하면 타입 안전성이 향상됩니다. 단,publishEvent의 오버로드된 메서드 때문에 현재 방식도 동작합니다.♻️ 타입 안전성 개선 제안
// then -ArgumentCaptor<Object> captor = ArgumentCaptor.forClass(Object.class); -verify(eventPublisher).publishEvent(captor.capture()); -assertThat(captor.getValue()).isInstanceOf(CallStartedEvent.class); +ArgumentCaptor<CallStartedEvent> captor = ArgumentCaptor.forClass(CallStartedEvent.class); +verify(eventPublisher).publishEvent(captor.capture()); +CallStartedEvent capturedEvent = captor.getValue(); +assertThat(capturedEvent.callId()).isEqualTo(100L);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/test/java/com/ldsilver/chingoohaja/listener/MatchingEventListenerTest.java` around lines 171 - 173, In MatchingEventListenerTest replace the generic ArgumentCaptor<Object> with a type-specific ArgumentCaptor<CallStartedEvent> and call ArgumentCaptor.forClass(CallStartedEvent.class) so the captured value from eventPublisher.publishEvent(...) is type-safe; update the captor variable declaration and the forClass argument to CallStartedEvent.class while keeping the verify(eventPublisher).publishEvent(captor.capture()) and the assertThat(captor.getValue()).isInstanceOf(CallStartedEvent.class).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@src/test/java/com/ldsilver/chingoohaja/listener/MatchingEventListenerTest.java`:
- Around line 191-214: The test MatchingEventListenerTest has a DisplayName
claiming it "schedules a rematch" but it never verifies any interaction with
matchingService; either add an assertion that matchingService was invoked (for
example verify(matchingService, times(1)).scheduleRematch(...) or
verify(matchingService).enqueueRematch(anyLong(), anyList()) matching the actual
method used by matchingEventListener.handleMatchingSuccess), or change the
DisplayName to remove the rematch claim; update the test to reference the exact
matchingService method name and expected arguments (e.g., call id or user list)
so the rematch scheduling behavior is explicitly verified.
---
Nitpick comments:
In @.github/workflows/ci.yml:
- Around line 55-60: Update the "테스트 결과 업로드" upload-artifact step that uses
actions/upload-artifact@v4 to include the JUnit XML output path in addition to
the HTML report; include both build/reports/tests/test/ and
build/test-results/test/ (the JUnit XML directory) in the "path" so the artifact
contains HTML and JUnit XML results for downstream CI tools and reporting.
In
`@src/test/java/com/ldsilver/chingoohaja/listener/MatchingEventListenerTest.java`:
- Around line 171-173: In MatchingEventListenerTest replace the generic
ArgumentCaptor<Object> with a type-specific ArgumentCaptor<CallStartedEvent> and
call ArgumentCaptor.forClass(CallStartedEvent.class) so the captured value from
eventPublisher.publishEvent(...) is type-safe; update the captor variable
declaration and the forClass argument to CallStartedEvent.class while keeping
the verify(eventPublisher).publishEvent(captor.capture()) and the
assertThat(captor.getValue()).isInstanceOf(CallStartedEvent.class).
In
`@src/test/java/com/ldsilver/chingoohaja/scheduler/GracePeriodSchedulerTest.java`:
- Around line 60-68: Extract the duplicated private helper setId method into a
shared test utility: create a final utility class TestEntityUtils with a public
static setId(Object entity, Long id) method (matching the implementation in
GracePeriodSchedulerTest and MatchingEventListenerTest), remove the private
setId from both test classes, and update both GracePeriodSchedulerTest and
MatchingEventListenerTest to call TestEntityUtils.setId(...) so the reflection
logic is centralized and duplication is eliminated.
In
`@src/test/java/com/ldsilver/chingoohaja/service/RedisMatchingQueueServiceOperationTest.java`:
- Around line 94-127: Add a test that verifies Redis exceptions during dequeue
are handled like enqueue: stub redisTemplate.execute to throw (e.g., new
RuntimeException("Redis 연결 실패")) and call
RedisMatchingQueueService.dequeueUser(100L, 1L); assert the returned
DequeueResult has success() == false and message() equals
RedisMatchingConstants.ResponseMessage.REDIS_ERROR; place the test alongside the
other DequeueUser tests and use the same mocking pattern
(when(redisTemplate.execute(...)).thenThrow(...)) so dequeueUser properly maps
Redis failures to a failure result.
⭐️ Issue Number
🚩 Summary
생성된 테스트 파일
각 파일의 주요 검증 포인트
CallEventListenerTest
isAutoStart=false/channelName=null→ 녹음 스킵MatchingEventListenerTest
createChannel미호출isAutoStart=true→CallStartedEvent발행 확인 (publishEvent(Object.class))GracePeriodSchedulerTest
isInGracePeriod미호출callStatusService미호출RedisMatchingQueueServiceOperationTest
isBlocked)GitHub Actions CI 파이프라인 및 Dockerfile 추가
ci.yml핵심 구조 설명Redis 연동 방식: GitHub Actions의
services블록으로 Redis 컨테이너를testjob과 동일한 네트워크에서 실행합니다.SPRING_DATA_REDIS_HOST=localhost환경변수가application-test.yml의 하드코딩된localhost를 Spring Boot가 자동으로 오버라이드합니다.yml파일 수정 없이 동작합니다.Dockerfile설계 포인트appuser로 실행 → 보안 강화COPY src전에dependencies다운로드 → Docker 캐시 효율 향상📋 To Do
나중에 CD 구축 시
ci.yml에 아래 job을 추가하면 됩니다:Summary by CodeRabbit
Tests
Chores