From 30bc779e85f88346432f421c1ac20e141993625e Mon Sep 17 00:00:00 2001 From: "Choi, Minwoo" Date: Wed, 12 Nov 2025 20:59:36 +0900 Subject: [PATCH] =?UTF-8?q?refactor:=20=EC=97=AC=ED=96=89,=20=EC=8A=A4?= =?UTF-8?q?=ED=83=AC=ED=94=84,=20=EB=AF=B8=EC=85=98=20=EC=A1=B0=ED=9A=8C?= =?UTF-8?q?=20=EB=B9=84=EC=A6=88=EB=8B=88=EC=8A=A4=20=EB=A1=9C=EC=A7=81?= =?UTF-8?q?=EC=97=90=20=EC=99=84=EB=A3=8C=20=EC=97=AC=EB=B6=80=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=20=EC=A0=95=EC=B1=85=20=EC=B6=94=EA=B0=80(#116)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: TripQueryService.getValidTrip()에 완료 여부 검증 정책 추가 * refactor: StampQueryService.getValidStamp()에 완료 여부 검증 정책 추가 * refactor: MissionQueryService.getValidMission()에 완료 여부 검증 정책 추가 * refactor: MemberFacade.confirmImage()에 멤버 캐시 무효화 로직 추가 * refactor: StudyLogFacade.confirmImage()에 학습 로그 캐시 무효화 로직 추가 * test: TripQueryServiceTest에서 GetValidTrip 단위 테스트 수정 * test: StampQueryServiceTest에서 GetValidStamp 단위 테스트 수정 * test: MissionQueryServiceTest에서 GetValidMission 단위 테스트 수정 --- .../application/facade/MemberFacade.java | 3 +++ .../service/MissionQueryService.java | 1 + .../service/StampQueryService.java | 1 + .../application/facade/StudyLogFacade.java | 1 + .../application/service/TripQueryService.java | 1 + .../service/MissionQueryServiceTest.java | 15 ++++++++++++ .../service/StampQueryServiceTest.java | 24 +++++++++++++++---- .../service/TripQueryServiceTest.java | 14 +++++++++++ 8 files changed, 55 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/ject/studytrip/member/application/facade/MemberFacade.java b/src/main/java/com/ject/studytrip/member/application/facade/MemberFacade.java index f1edfbf..976c3c8 100644 --- a/src/main/java/com/ject/studytrip/member/application/facade/MemberFacade.java +++ b/src/main/java/com/ject/studytrip/member/application/facade/MemberFacade.java @@ -102,6 +102,9 @@ public PresignedProfileImageInfo issuePresignedUrl( return PresignedProfileImageInfo.of(member.getId(), info.tmpKey(), info.presignedUrl()); } + @CacheEvict( + cacheNames = MEMBER, + key = "T(com.ject.studytrip.global.common.factory.CacheKeyFactory).member(#memberId)") @Transactional public void confirmImage(Long memberId, ConfirmProfileImageRequest request) { Member member = memberQueryService.getValidMember(memberId); diff --git a/src/main/java/com/ject/studytrip/mission/application/service/MissionQueryService.java b/src/main/java/com/ject/studytrip/mission/application/service/MissionQueryService.java index d7c7bec..82eaaf5 100644 --- a/src/main/java/com/ject/studytrip/mission/application/service/MissionQueryService.java +++ b/src/main/java/com/ject/studytrip/mission/application/service/MissionQueryService.java @@ -24,6 +24,7 @@ public Mission getValidMission(Long stampId, Long missionId) { MissionPolicy.validateMissionBelongsToStamp(stampId, mission); MissionPolicy.validateNotDeleted(mission); + MissionPolicy.validateCompleted(mission); return mission; } diff --git a/src/main/java/com/ject/studytrip/stamp/application/service/StampQueryService.java b/src/main/java/com/ject/studytrip/stamp/application/service/StampQueryService.java index 71b0588..e2a22d4 100644 --- a/src/main/java/com/ject/studytrip/stamp/application/service/StampQueryService.java +++ b/src/main/java/com/ject/studytrip/stamp/application/service/StampQueryService.java @@ -30,6 +30,7 @@ public Stamp getValidStamp(Long tripId, Long stampId) { StampPolicy.validateStampBelongsToTrip(tripId, stamp); StampPolicy.validateNotDeleted(stamp); + StampPolicy.validateCompleted(stamp); return stamp; } diff --git a/src/main/java/com/ject/studytrip/studylog/application/facade/StudyLogFacade.java b/src/main/java/com/ject/studytrip/studylog/application/facade/StudyLogFacade.java index 338d489..4b0f660 100644 --- a/src/main/java/com/ject/studytrip/studylog/application/facade/StudyLogFacade.java +++ b/src/main/java/com/ject/studytrip/studylog/application/facade/StudyLogFacade.java @@ -119,6 +119,7 @@ public PresignedStudyLogImageInfo issuePresignedUrl( return PresignedStudyLogImageInfo.of(studyLog.getId(), info.tmpKey(), info.presignedUrl()); } + @CacheEvict(cacheNames = STUDY_LOGS, allEntries = true) @Transactional public void confirmImage(Long studyLogId, ConfirmStudyLogImageRequest request) { StudyLog studyLog = studyLogQueryService.getValidStudyLog(studyLogId); diff --git a/src/main/java/com/ject/studytrip/trip/application/service/TripQueryService.java b/src/main/java/com/ject/studytrip/trip/application/service/TripQueryService.java index caaaf83..841ac34 100644 --- a/src/main/java/com/ject/studytrip/trip/application/service/TripQueryService.java +++ b/src/main/java/com/ject/studytrip/trip/application/service/TripQueryService.java @@ -33,6 +33,7 @@ public Trip getValidTrip(Long memberId, Long tripId) { TripPolicy.validateOwner(memberId, trip); TripPolicy.validateNotDeleted(trip); + TripPolicy.validateCompleted(trip); return trip; } diff --git a/src/test/java/com/ject/studytrip/mission/application/service/MissionQueryServiceTest.java b/src/test/java/com/ject/studytrip/mission/application/service/MissionQueryServiceTest.java index d8b036c..17b9d71 100644 --- a/src/test/java/com/ject/studytrip/mission/application/service/MissionQueryServiceTest.java +++ b/src/test/java/com/ject/studytrip/mission/application/service/MissionQueryServiceTest.java @@ -99,6 +99,21 @@ void shouldThrowExceptionWhenMissionIsDeleted() { .hasMessage(MissionErrorCode.MISSION_ALREADY_DELETED.getMessage()); } + @Test + @DisplayName("미션이 이미 완료된 경우 예외가 발생한다.") + void shouldThrowExceptionWhenMissionIsCompleted() { + // given + exploreMission1.updateCompleted(); + Long stampId = exploreStamp.getId(); + Long missionId = exploreMission1.getId(); + given(missionRepository.findById(missionId)).willReturn(Optional.of(exploreMission1)); + + // when & then + assertThatThrownBy(() -> missionQueryService.getValidMission(stampId, missionId)) + .isInstanceOf(CustomException.class) + .hasMessage(MissionErrorCode.MISSION_ALREADY_COMPLETED.getMessage()); + } + @Test @DisplayName("특정 스탬프에 속하고 삭제되지 않은 미션이 존재하면, 해당 미션을 반환한다.") void shouldReturnValidMission() { diff --git a/src/test/java/com/ject/studytrip/stamp/application/service/StampQueryServiceTest.java b/src/test/java/com/ject/studytrip/stamp/application/service/StampQueryServiceTest.java index 07dfc42..ef6dbf3 100644 --- a/src/test/java/com/ject/studytrip/stamp/application/service/StampQueryServiceTest.java +++ b/src/test/java/com/ject/studytrip/stamp/application/service/StampQueryServiceTest.java @@ -85,17 +85,31 @@ void shouldThrowExceptionWhenStampDoesNotBelongToTrip() { void shouldThrowExceptionWhenStampAlreadyDeleted() { // given courseStamp1.updateDeletedAt(); - given(stampRepository.findById(any())).willReturn(Optional.ofNullable(courseStamp1)); + Long tripId = courseTrip.getId(); + Long stampId = courseStamp1.getId(); + given(stampRepository.findById(stampId)).willReturn(Optional.ofNullable(courseStamp1)); // when & then - assertThatThrownBy( - () -> - stampQueryService.getValidStamp( - courseStamp1.getId(), courseStamp1.getId())) + assertThatThrownBy(() -> stampQueryService.getValidStamp(tripId, stampId)) .isInstanceOf(CustomException.class) .hasMessage(StampErrorCode.STAMP_ALREADY_DELETED.getMessage()); } + @Test + @DisplayName("완료된 스탬프일 경우 예외가 발생한다.") + void shouldThrowExceptionWhenStampAlreadyCompleted() { + // given + courseStamp1.updateCompleted(); + Long tripId = courseTrip.getId(); + Long stampId = courseStamp1.getId(); + given(stampRepository.findById(stampId)).willReturn(Optional.ofNullable(courseStamp1)); + + // when & then + assertThatThrownBy(() -> stampQueryService.getValidStamp(tripId, stampId)) + .isInstanceOf(CustomException.class) + .hasMessage(StampErrorCode.STAMP_ALREADY_COMPLETED.getMessage()); + } + @Test @DisplayName("스탬프 ID로 스탬프를 조회하고, 여행 소속 및 삭제 여부를 검증하고 반환한다") void shouldGetStampReturnValidStamp() { diff --git a/src/test/java/com/ject/studytrip/trip/application/service/TripQueryServiceTest.java b/src/test/java/com/ject/studytrip/trip/application/service/TripQueryServiceTest.java index e80c3d7..6785706 100644 --- a/src/test/java/com/ject/studytrip/trip/application/service/TripQueryServiceTest.java +++ b/src/test/java/com/ject/studytrip/trip/application/service/TripQueryServiceTest.java @@ -112,6 +112,20 @@ void shouldThrowExceptionWhenAlreadyTrip() { .hasMessage(TripErrorCode.TRIP_ALREADY_DELETED.getMessage()); } + @Test + @DisplayName("이미 완료된 여행일 경우 예외가 발생한다") + void shouldThrowExceptionWhenTripAlreadyCompleted() { + // given + trip.updateCompleted(); + Long tripId = trip.getId(); + given(tripRepository.findById(tripId)).willReturn(Optional.of(trip)); + + // when & then + assertThatThrownBy(() -> tripQueryService.getValidTrip(member.getId(), tripId)) + .isInstanceOf(CustomException.class) + .hasMessage(TripErrorCode.TRIP_ALREADY_COMPLETED.getMessage()); + } + @Test @DisplayName("특정 여행 ID로 DB에서 조회한 후 유효한 여행을 반환한다") void shouldGetTripByTripIdReturnValidTrip() {