Skip to content

refactor: 예약 취소 내 멱등성 구현 및 웨이팅 등록 유닛테스트 추가 #359

Merged
Jjiggu merged 10 commits intodevelopfrom
feature/#348-Waiting-Rebuild
Feb 8, 2026
Merged

refactor: 예약 취소 내 멱등성 구현 및 웨이팅 등록 유닛테스트 추가 #359
Jjiggu merged 10 commits intodevelopfrom
feature/#348-Waiting-Rebuild

Conversation

@Jjiggu
Copy link
Contributor

@Jjiggu Jjiggu commented Feb 8, 2026

작업 요약

  • 예약 취소 내 멱등성 구현
  • 웨이팅 등록 유닛테스트 추가

Issue Link

#348

문제점 및 어려움

  • 멱등성 동시성 처리 추가

해결 방안

Reference

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능
    • 대기 목록 등록 및 취소 작업에 멱등성 지원이 추가되었습니다. 네트워크 오류로 인한 재시도 시 동일한 요청이 중복으로 처리되지 않으며, 이전 응답을 캐시하여 제공합니다. 이를 통해 시스템 안정성과 사용자 경험이 개선되었습니다.

@Jjiggu Jjiggu self-assigned this Feb 8, 2026
@Jjiggu Jjiggu added enhancement New feature or request refactor 리팩토링 labels Feb 8, 2026
@github-actions github-actions bot requested a review from HyemIin February 8, 2026 06:14
@coderabbitai
Copy link

coderabbitai bot commented Feb 8, 2026

개요

대기 등록 및 취소 작업을 위한 중앙화된 멱등성(idempotency) 처리 메커니즘을 도입합니다. HttpServletRequest를 컨트롤러와 서비스에 전파하여 멱등성 키 검증을 수행하고, 전용 DTO 및 저장소 메서드를 통해 Redis에 응답을 캐싱합니다.

변경 사항

코호트 / 파일(s) 요약
컨트롤러 업데이트
src/main/java/com/nowait/applicationuser/waiting/controller/WaitingController.java
cancelWaiting 메서드 시그니처에 HttpServletRequest 파라미터 추가 및 서비스 호출 시 전파
멱등성 DTO
src/main/java/com/nowait/applicationuser/waiting/dto/WaitingCancelIdempotencyValue.java
취소 작업용 멱등성 값을 저장하는 새로운 DTO 클래스 (state, response 필드 포함)
저장소 확장
src/main/java/com/nowait/applicationuser/waiting/redis/WaitingIdempotencyRepository.java
findByCancelKey() 및 saveCancelIdempotencyValue() 메서드 추가로 Redis 기반 취소 멱등성 관리 지원
서비스 리팩토링
src/main/java/com/nowait/applicationuser/waiting/service/WaitingService.java
validateIdempotency, validateCancelIdempotency, saveIdempotencyResponse 헬퍼 메서드 도입 및 generateIdempotentKey 제거. cancelWaiting에 HttpServletRequest 파라미터 추가
테스트 확대
src/test/java/com/nowait/applicationuser/waiting/service/WaitingServiceTest.java
HttpServletRequest, WaitingIdempotencyRepository 모킹 추가 및 멱등성 키 검증, DB 저장, 예외 처리에 대한 7개 테스트 케이스 신규 작성
저장소 정리
src/main/java/com/nowait/domaincoreredis/reservation/repository/WaitingRedisRepository.java
idempotentKeyKeyExists 메서드 제거

시퀀스 다이어그램

sequenceDiagram
    participant Client
    participant Controller as WaitingController
    participant Service as WaitingService
    participant Repo as WaitingIdempotencyRepository
    participant Redis
    participant DB

    Client->>Controller: cancelWaiting(request, HttpServletRequest)
    Controller->>Service: cancelWaiting(..., HttpServletRequest)
    
    Service->>Service: validateCancelIdempotency(HttpServletRequest)
    Service->>Repo: findByCancelKey(idempotencyKey)
    Repo->>Redis: 멱등성 키 조회
    alt 캐시된 응답 존재
        Redis-->>Repo: WaitingCancelIdempotencyValue
        Repo-->>Service: Optional<response>
        Service-->>Controller: CachedResponse (로깅)
    else 캐시 미존재
        Redis-->>Repo: null
        Repo-->>Service: Optional.empty()
        Service->>DB: 취소 처리 로직
        DB-->>Service: CancelWaitingResponse
        Service->>Repo: saveCancelIdempotencyValue(key, response)
        Repo->>Redis: 응답 저장 (TTL 포함)
        Service-->>Controller: CancelWaitingResponse
    end
    
    Controller-->>Client: ResponseEntity
Loading

예상 코드 리뷰 소요 시간

🎯 3 (보통) | ⏱️ ~20분

관련 PR

제안 검토자

  • HyemIin
🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목은 예약 취소 멱등성 구현과 웨이팅 등록 유닛테스트 추가라는 주요 변경사항을 명확하게 요약하고 있으며, 실제 코드 변경과 일치합니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/#348-Waiting-Rebuild

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Fix all issues with AI agents
In
`@nowait-app-user-api/src/main/java/com/nowait/applicationuser/waiting/service/WaitingService.java`:
- Around line 59-67: The idempotency race between validateIdempotency and saving
the response must be eliminated by atomically claiming the idempotency key
before doing work in registerWaiting: update registerWaiting to attempt an
atomic "claim" (e.g., Redis SETNX with a short TTL or acquire a distributed lock
via Redisson) using the incoming idempotency key; if the claim fails,
immediately return the existing response or an appropriate in-flight/duplicate
response; if the claim succeeds, proceed with the operation, then call
saveIdempotencyValue to persist the final response and release the claim (or let
TTL expire) and ensure failures always release the lock/clean the claim so other
requests may proceed; keep references to registerWaiting, validateIdempotency,
and saveIdempotencyValue when applying the change.
- Around line 149-153: The cancel path calls
waitingIdempotencyRepository.saveCancelIdempotencyValue(...) without guarding
the Idempotency-Key header, causing Redis errors when the key is null/blank; in
WaitingService's cancelWaiting method either replicate the null/blank check used
by registerWaiting (only call saveCancelIdempotencyValue when
httpServletRequest.getHeader("Idempotency-Key") is non-null and not blank) or
add a helper method (e.g., saveCancelIdempotencyResponse) that encapsulates the
same guard logic as saveIdempotencyResponse and use it from cancelWaiting to
ensure consistent idempotency-key handling.
- Around line 156-175: In validateIdempotency and validateCancelIdempotency,
guard against a missing or blank Idempotency-Key by reading
httpServletRequest.getHeader("Idempotency-Key"), checking for null or blank
(trimmed) and returning null immediately if absent; only call
waitingIdempotencyRepository.findByKey(idempotentKey) and
waitingIdempotencyRepository.findByCancelKey(idempotentKey) when the key is
non-empty to avoid passing null to the repository (and prevent
IllegalArgumentException/NullPointerException).

In
`@nowait-app-user-api/src/test/java/com/nowait/applicationuser/waiting/service/WaitingServiceTest.java`:
- Around line 144-188: Add unit tests for cancelWaiting in WaitingServiceTest
covering: (1) when httpServletRequest.getHeader("Idempotency-Key") returns an
existing key and waitingIdempotencyRepository.findByKey(...) returns a cached
CancelWaitingResponse, assert waitingService.cancelWaiting(...) returns that
cached CancelWaitingResponse and no cancellation logic runs; (2) when
idempotency key is absent or blank, exercise waitingService.cancelWaiting(...)
normal cancel flow, stub repositories (reservationRepository,
waitingRedisRepository) and verify reservation state changes and
eventPublisher.publishEvent(...) is called; (3) on successful cancel verify
waitingIdempotencyRepository.saveIdempotencyValue(anyString(),
any(CancelWaitingResponse.class)) is invoked to persist the idempotent response.
Reference waitingService.cancelWaiting, CancelWaitingResponse,
waitingIdempotencyRepository.findByKey/saveIdempotencyValue,
httpServletRequest.getHeader("Idempotency-Key"), reservationRepository and
eventPublisher to locate code under test.
🧹 Nitpick comments (4)
nowait-app-user-api/src/main/java/com/nowait/applicationuser/waiting/dto/WaitingCancelIdempotencyValue.java (1)

7-13: WaitingIdempotencyValue와 구조가 중복됩니다 — 제네릭 기반 클래스로 통합을 고려해 보세요.

WaitingIdempotencyValueWaitingCancelIdempotencyValue는 동일한 state + response 패턴을 사용합니다. 제네릭 클래스 하나로 통합하면 향후 새로운 멱등성 타입 추가 시에도 DTO를 추가하지 않아도 됩니다.

♻️ 제네릭 기반 통합 예시
`@Getter`
`@NoArgsConstructor`
`@AllArgsConstructor`
public class IdempotencyValue<T> {
    private String state;
    private T response;
}

사용 시:

IdempotencyValue<RegisterWaitingResponse>   // 등록용
IdempotencyValue<CancelWaitingResponse>     // 취소용

단, Jackson 역직렬화 시 TypeReference 사용이 필요할 수 있습니다.

nowait-app-user-api/src/main/java/com/nowait/applicationuser/waiting/redis/WaitingIdempotencyRepository.java (1)

27-58: findByKeyfindByCancelKey는 역직렬화 대상 클래스만 다릅니다 — 제네릭 메서드로 통합 가능합니다.

두 메서드는 동일한 Redis 조회 → null 체크 → ObjectMapper.readValue 흐름을 반복하고 있습니다. 제네릭 private 헬퍼로 추출하면 중복을 제거할 수 있습니다.

♻️ 제네릭 헬퍼 추출 예시
+	private <T> Optional<T> findByKey(String key, Class<T> clazz) {
+		String value = redisTemplate.opsForValue().get(key);
+		if (value == null) {
+			return Optional.empty();
+		}
+		try {
+			return Optional.of(objectMapper.readValue(value, clazz));
+		} catch (Exception e) {
+			throw new IllegalArgumentException("Failed to deserialize value from Redis", e);
+		}
+	}
+
 	public Optional<WaitingIdempotencyValue> findByKey(String key) {
-		String idempotencyValue = redisTemplate.opsForValue().get(key);
-		if (idempotencyValue == null) {
-			return Optional.empty();
-		}
-		try {
-			return Optional.of(
-				objectMapper.readValue(idempotencyValue, WaitingIdempotencyValue.class)
-			);
-		} catch (Exception e) {
-			throw new IllegalArgumentException("Failed to deserialize value from Redis", e);
-		}
+		return findByKey(key, WaitingIdempotencyValue.class);
 	}
 
 	public Optional<WaitingCancelIdempotencyValue> findByCancelKey(String key) {
-		...
+		return findByKey(key, WaitingCancelIdempotencyValue.class);
 	}

save 메서드 쌍도 동일한 패턴으로 통합 가능합니다.

nowait-app-user-api/src/test/java/com/nowait/applicationuser/waiting/service/WaitingServiceTest.java (1)

60-63: @BeforeEach에서 설정한 stub이 일부 테스트에서 중복 설정되거나 무시됩니다.

  • registerWaiting_success (Line 151)에서 httpServletRequest.getHeader("Idempotency-Key")를 다시 stub하고 있지만, @BeforeEach에서 이미 동일한 값으로 설정되어 있어 불필요합니다.
  • registerWaiting_idempotentKeyNotExists, registerWaiting_success, registerWaiting_exceedWaitingLimit에서 customOAuth2User를 로컬로 다시 mock()하여 클래스 레벨 @Mock 필드를 가리고(shadow) 있습니다. 일관성을 위해 클래스 레벨 @Mock을 사용하거나 @BeforeEach에서 초기화하는 방식으로 통일하는 것이 좋습니다.
nowait-app-user-api/src/main/java/com/nowait/applicationuser/waiting/service/WaitingService.java (1)

76-78: 대기 제한 수 3L이 하드코딩되어 있습니다.

향후 주점별 정책에 따라 제한 수가 달라질 수 있으므로, 설정 값이나 Store 엔티티의 속성으로 관리하는 것이 좋습니다.

Comment on lines 59 to 67
@Transactional
public RegisterWaitingResponse registerWaiting(CustomOAuth2User oAuth2User, String publicCode, RegisterWaitingRequest waitingRequest, HttpServletRequest httpServletRequest) {

String idempotentKey = httpServletRequest.getHeader("Idempotency-Key");

// TODO 멱등성 검증 로직 점검 필요
Optional<WaitingIdempotencyValue> existingIdempotencyValue = waitingIdempotencyRepository.findByKey(idempotentKey);
if (existingIdempotencyValue.isPresent()) {
log.info("Existing idempotency key found: {}", idempotentKey);
return existingIdempotencyValue.get().getResponse();
// TODO 멱등키 동시성 처리 로직 고려 필요 (분산락 등)
RegisterWaitingResponse registerWaitingResponse = validateIdempotency(httpServletRequest);
if (registerWaitingResponse != null) {
log.info("Idempotent request detected. Returning existing response.");
return registerWaitingResponse;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

멱등성 검증과 저장 사이의 경합 조건(Race Condition)에 대해.

TODO 주석(Line 62)에 언급된 대로, 멱등키 검증(validateIdempotency)과 응답 저장(saveIdempotencyValue) 사이에 경합 조건이 존재합니다. 동일한 멱등키를 가진 두 요청이 동시에 도달하면 둘 다 검증을 통과하여 중복 처리가 발생할 수 있습니다.

일반적인 해결 방안:

  1. Redis SETNX(SET if Not eXists)를 활용하여 멱등키를 "PROCESSING" 상태로 먼저 선점한 후 작업 수행
  2. 분산 락(Redisson 등) 사용

현재 TODO로 인지하고 계신 것으로 보이지만, 프로덕션 배포 전에 반드시 해결이 필요한 사항입니다.

🤖 Prompt for AI Agents
In
`@nowait-app-user-api/src/main/java/com/nowait/applicationuser/waiting/service/WaitingService.java`
around lines 59 - 67, The idempotency race between validateIdempotency and
saving the response must be eliminated by atomically claiming the idempotency
key before doing work in registerWaiting: update registerWaiting to attempt an
atomic "claim" (e.g., Redis SETNX with a short TTL or acquire a distributed lock
via Redisson) using the incoming idempotency key; if the claim fails,
immediately return the existing response or an appropriate in-flight/duplicate
response; if the claim succeeds, proceed with the operation, then call
saveIdempotencyValue to persist the final response and release the claim (or let
TTL expire) and ensure failures always release the lock/clean the claim so other
requests may proceed; keep references to registerWaiting, validateIdempotency,
and saveIdempotencyValue when applying the change.

Comment on lines +149 to +153

// 멱등키가 있다면 멱등 응답 저장
waitingIdempotencyRepository.saveCancelIdempotencyValue(httpServletRequest.getHeader("Idempotency-Key"), response);

return response;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

취소 경로에서 멱등키 null/blank 검사 없이 saveCancelIdempotencyValue를 호출합니다.

registerWaitingsaveIdempotencyResponse (Line 178-181)는 키가 null이거나 blank인지 확인한 후 저장하지만, cancelWaiting에서는 (Line 151) 아무 검사 없이 saveCancelIdempotencyValue를 직접 호출하고 있습니다.

멱등키 없이 취소 요청이 들어오면 null 키로 Redis에 저장을 시도하여 예외가 발생합니다. saveIdempotencyResponse와 동일한 가드를 추가하거나, 취소용 saveCancelIdempotencyResponse 헬퍼를 만들어 일관성을 유지하세요.

🐛 수정 제안
-		// 멱등키가 있다면 멱등 응답 저장
-		waitingIdempotencyRepository.saveCancelIdempotencyValue(httpServletRequest.getHeader("Idempotency-Key"), response);
+		// 멱등키가 있다면 멱등 응답 저장
+		String idempotentKey = httpServletRequest.getHeader("Idempotency-Key");
+		if (idempotentKey != null && !idempotentKey.isBlank()) {
+			waitingIdempotencyRepository.saveCancelIdempotencyValue(idempotentKey, response);
+		}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// 멱등키가 있다면 멱등 응답 저장
waitingIdempotencyRepository.saveCancelIdempotencyValue(httpServletRequest.getHeader("Idempotency-Key"), response);
return response;
// 멱등키가 있다면 멱등 응답 저장
String idempotentKey = httpServletRequest.getHeader("Idempotency-Key");
if (idempotentKey != null && !idempotentKey.isBlank()) {
waitingIdempotencyRepository.saveCancelIdempotencyValue(idempotentKey, response);
}
return response;
🤖 Prompt for AI Agents
In
`@nowait-app-user-api/src/main/java/com/nowait/applicationuser/waiting/service/WaitingService.java`
around lines 149 - 153, The cancel path calls
waitingIdempotencyRepository.saveCancelIdempotencyValue(...) without guarding
the Idempotency-Key header, causing Redis errors when the key is null/blank; in
WaitingService's cancelWaiting method either replicate the null/blank check used
by registerWaiting (only call saveCancelIdempotencyValue when
httpServletRequest.getHeader("Idempotency-Key") is non-null and not blank) or
add a helper method (e.g., saveCancelIdempotencyResponse) that encapsulates the
same guard logic as saveIdempotencyResponse and use it from cancelWaiting to
ensure consistent idempotency-key handling.

Comment on lines +156 to 175
// 멱등키 검증 메서드
private RegisterWaitingResponse validateIdempotency(HttpServletRequest httpServletRequest) {
String idempotentKey = httpServletRequest.getHeader("Idempotency-Key");

// 멱등키 검증 - 이미 동일한 멱등키로 등록된 웨이팅이 있는지 확인
// TODO 멱등성 검증 로직 점검 필요
return waitingIdempotencyRepository.findByKey(idempotentKey)
.map(WaitingIdempotencyValue::getResponse)
.orElse(null);
}

private CancelWaitingResponse validateCancelIdempotency(HttpServletRequest httpServletRequest) {
String idempotentKey = httpServletRequest.getHeader("Idempotency-Key");

// 멱등키 검증 - 이미 동일한 멱등키로 등록된 웨이팅이 있는지 확인
// TODO 멱등성 검증 로직 점검 필요
return waitingIdempotencyRepository.findByCancelKey(idempotentKey)
.map(WaitingCancelIdempotencyValue::getResponse)
.orElse(null);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Idempotency-Key 헤더가 없으면(null) NullPointerException 또는 IllegalArgumentException이 발생합니다.

validateIdempotencyvalidateCancelIdempotency 모두 httpServletRequest.getHeader("Idempotency-Key")의 결과를 검증 없이 바로 findByKey(null) / findByCancelKey(null)에 전달합니다. Spring Data Redis의 opsForValue().get(null)IllegalArgumentException을 throw합니다.

멱등키가 선택적(optional)이라면, null/blank 체크 후 바로 null을 반환해야 합니다.

🐛 수정 제안
 private RegisterWaitingResponse validateIdempotency(HttpServletRequest httpServletRequest) {
     String idempotentKey = httpServletRequest.getHeader("Idempotency-Key");
+    if (idempotentKey == null || idempotentKey.isBlank()) {
+        return null;
+    }
     return waitingIdempotencyRepository.findByKey(idempotentKey)
         .map(WaitingIdempotencyValue::getResponse)
         .orElse(null);
 }

 private CancelWaitingResponse validateCancelIdempotency(HttpServletRequest httpServletRequest) {
     String idempotentKey = httpServletRequest.getHeader("Idempotency-Key");
+    if (idempotentKey == null || idempotentKey.isBlank()) {
+        return null;
+    }
     return waitingIdempotencyRepository.findByCancelKey(idempotentKey)
         .map(WaitingCancelIdempotencyValue::getResponse)
         .orElse(null);
 }
🤖 Prompt for AI Agents
In
`@nowait-app-user-api/src/main/java/com/nowait/applicationuser/waiting/service/WaitingService.java`
around lines 156 - 175, In validateIdempotency and validateCancelIdempotency,
guard against a missing or blank Idempotency-Key by reading
httpServletRequest.getHeader("Idempotency-Key"), checking for null or blank
(trimmed) and returning null immediately if absent; only call
waitingIdempotencyRepository.findByKey(idempotentKey) and
waitingIdempotencyRepository.findByCancelKey(idempotentKey) when the key is
non-empty to avoid passing null to the repository (and prevent
IllegalArgumentException/NullPointerException).

Comment on lines +144 to +188
@Test
@DisplayName("웨이팅 정상 등록 시 DB 저장, 이벤트 발생, 멱등 응답 저장 수행")
void registerWaiting_success() {
// given
CustomOAuth2User customOAuth2User = mock(CustomOAuth2User.class);
RegisterWaitingRequest request = new RegisterWaitingRequest(4);

when(httpServletRequest.getHeader("Idempotency-Key")).thenReturn(IDEMPOTENCY_KEY);
when(waitingIdempotencyRepository.findByKey(IDEMPOTENCY_KEY))
.thenReturn(Optional.empty());

Long userId = 10L;
String publicCode = "ZiVXAD1vVr5b";

Store store = Store.builder().publicCode(publicCode).build();
User user = User.builder().id(userId).build();

when(storeRepository.findByPublicCodeAndDeletedFalse(publicCode)).thenReturn(java.util.Optional.of(store));
when(customOAuth2User.getUserId()).thenReturn(userId);
when(customOAuth2User.getUserId()).thenReturn(10L);
when(userRepository.findById(userId)).thenReturn(java.util.Optional.of(user));
RegisterWaitingResponse response = waitingService.registerWaiting(customOAuth2User, publicCode, request, httpServletRequest);

doNothing()
.when(waitingRedisRepository)
.incrementAndCheckWaitingLimit(userId, 3L);

when(waitingRedisRepository.incrementDailySequence(anyString())).thenReturn(1L);

// when
RegisterWaitingResponse response = waitingService.registerWaiting(
customOAuth2User,
publicCode,
request,
httpServletRequest
);

// then
verify(waitingIdempotencyRepository).findByKey(anyString());
assertThat(response).isNotNull();
assertThat(response.getPartySize()).isEqualTo(4);
assertThat(response.getWaitingNumber()).isNotBlank();

verify(waitingRedisRepository).incrementAndCheckWaitingLimit(userId, 3L);
verify(reservationRepository).save(any(Reservation.class));
verify(eventPublisher).publishEvent(any(AddWaitingRegisterEvent.class));
verify(waitingIdempotencyRepository).saveIdempotencyValue(anyString(), any(RegisterWaitingResponse.class));
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

취소 대기(cancelWaiting) 멱등성에 대한 테스트가 누락되었습니다.

PR 목표가 "예약 취소 내 멱등성 구현"인데, cancelWaiting에 대한 테스트가 전혀 없습니다. 최소한 다음 시나리오에 대한 테스트를 추가해야 합니다:

  • 멱등키가 이미 존재하여 캐시된 CancelWaitingResponse가 반환되는 경우
  • 멱등키가 없거나 blank인 경우의 정상 취소 흐름
  • 취소 성공 시 멱등 응답이 Redis에 저장되는지 검증
🤖 Prompt for AI Agents
In
`@nowait-app-user-api/src/test/java/com/nowait/applicationuser/waiting/service/WaitingServiceTest.java`
around lines 144 - 188, Add unit tests for cancelWaiting in WaitingServiceTest
covering: (1) when httpServletRequest.getHeader("Idempotency-Key") returns an
existing key and waitingIdempotencyRepository.findByKey(...) returns a cached
CancelWaitingResponse, assert waitingService.cancelWaiting(...) returns that
cached CancelWaitingResponse and no cancellation logic runs; (2) when
idempotency key is absent or blank, exercise waitingService.cancelWaiting(...)
normal cancel flow, stub repositories (reservationRepository,
waitingRedisRepository) and verify reservation state changes and
eventPublisher.publishEvent(...) is called; (3) on successful cancel verify
waitingIdempotencyRepository.saveIdempotencyValue(anyString(),
any(CancelWaitingResponse.class)) is invoked to persist the idempotent response.
Reference waitingService.cancelWaiting, CancelWaitingResponse,
waitingIdempotencyRepository.findByKey/saveIdempotencyValue,
httpServletRequest.getHeader("Idempotency-Key"), reservationRepository and
eventPublisher to locate code under test.

@Jjiggu Jjiggu merged commit cbca76a into develop Feb 8, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request refactor 리팩토링

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant