From 7b5409311139c652a681fab4b7ad068dce80cb43 Mon Sep 17 00:00:00 2001 From: seungtaekhong Date: Tue, 2 Jul 2024 16:33:13 +0900 Subject: [PATCH 1/3] =?UTF-8?q?refactor:=20=EC=9D=B8=EC=8B=9D=20=EA=B1=B0?= =?UTF-8?q?=EB=A6=AC=20=EB=B0=98=EA=B2=BD=20=ED=8C=90=EB=8B=A8=EC=9D=84=20?= =?UTF-8?q?=EB=8F=84=EB=A9=94=EC=9D=B8=20=EA=B0=9D=EC=B2=B4=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/AdventureService.java | 10 +++--- .../adventure/dao/AdventureRepository.java | 32 +++++++++---------- .../domain/landmark/domain/Landmark.java | 9 ++++++ 3 files changed, 28 insertions(+), 23 deletions(-) diff --git a/src/main/java/com/playkuround/playkuroundserver/domain/adventure/application/AdventureService.java b/src/main/java/com/playkuround/playkuroundserver/domain/adventure/application/AdventureService.java index 655a4c9..0afb147 100644 --- a/src/main/java/com/playkuround/playkuroundserver/domain/adventure/application/AdventureService.java +++ b/src/main/java/com/playkuround/playkuroundserver/domain/adventure/application/AdventureService.java @@ -16,7 +16,6 @@ import com.playkuround.playkuroundserver.domain.user.domain.User; import com.playkuround.playkuroundserver.global.util.DateTimeUtils; import com.playkuround.playkuroundserver.global.util.Location; -import com.playkuround.playkuroundserver.global.util.LocationDistanceUtils; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -49,16 +48,15 @@ public NewlyRegisteredBadge saveAdventure(AdventureSaveDto adventureSaveDto) { } private void validateLocation(Landmark landmark, Location location) { - Location locationOfLandmark = new Location(landmark.getLatitude(), landmark.getLongitude()); - double distance = LocationDistanceUtils.distance(locationOfLandmark, location); - if (distance > landmark.getRecognitionRadius()) { + if (!landmark.isInRecognitionRadius(location)) { throw new InvalidLandmarkLocationException(); } } private void updateUserScore(User user, ScoreType scoreType, long score) { totalScoreService.incrementTotalScore(user, score); - user.getHighestScore().updateGameHighestScore(scoreType, score); + user.getHighestScore() + .updateGameHighestScore(scoreType, score); userRepository.save(user); } @@ -69,7 +67,7 @@ private void saveAdventure(User user, Landmark landmark, ScoreType scoreType, lo private void updateLandmarkHighestScore(User user, Landmark landmark) { LocalDateTime monthStartDateTime = DateTimeUtils.getMonthStartDateTime(dateTimeService.getLocalDateNow()); - long sumScore = adventureRepository.getSumScoreByUserAndLandmark(user, landmark, monthStartDateTime); + long sumScore = adventureRepository.getSumScoreByUserAndLandmarkAfter(user, landmark, monthStartDateTime); landmark.updateFirstUser(user, sumScore); } } diff --git a/src/main/java/com/playkuround/playkuroundserver/domain/adventure/dao/AdventureRepository.java b/src/main/java/com/playkuround/playkuroundserver/domain/adventure/dao/AdventureRepository.java index a7e6463..10c2ce2 100644 --- a/src/main/java/com/playkuround/playkuroundserver/domain/adventure/dao/AdventureRepository.java +++ b/src/main/java/com/playkuround/playkuroundserver/domain/adventure/dao/AdventureRepository.java @@ -15,22 +15,20 @@ public interface AdventureRepository extends JpaRepository { - @Query(value = - "SELECT new com.playkuround.playkuroundserver.domain.score.dto.NicknameAndScore(a.user.nickname, cast(SUM(a.score) as integer)) " + - "FROM Adventure a " + - "where a.landmark.id=:landmark AND a.createdAt >= :from " + - "GROUP BY a.user.id " + - "ORDER BY SUM(a.score) DESC, a.user.nickname DESC " + - "LIMIT 100") + @Query("SELECT new com.playkuround.playkuroundserver.domain.score.dto.NicknameAndScore(a.user.nickname, cast(SUM(a.score) as integer)) " + + "FROM Adventure a " + + "where a.landmark.id=:landmark AND a.createdAt >= :from " + + "GROUP BY a.user.id " + + "ORDER BY SUM(a.score) DESC, a.user.nickname DESC " + + "LIMIT 100") List findRankTop100DescByLandmarkId(@Param(value = "landmark") Long landmarkId, @Param(value = "from") LocalDateTime from); - @Query(value = - "SELECT new com.playkuround.playkuroundserver.domain.score.dto.RankAndScore(cast(user_rank as integer), cast(score as integer)) FROM " + - "(SELECT a.user.id as user_id, (RANK() over (order by SUM(a.score) desc)) as user_rank, SUM(a.score) as score " + - "FROM Adventure a " + - "where a.landmark.id=:landmark AND a.createdAt >= :from " + - "GROUP BY a.user.id) " + - "where user_id=:#{#user.id}") + @Query("SELECT new com.playkuround.playkuroundserver.domain.score.dto.RankAndScore(cast(user_rank as integer), cast(score as integer)) FROM " + + "(SELECT a.user.id as user_id, (RANK() over (order by SUM(a.score) desc)) as user_rank, SUM(a.score) as score " + + "FROM Adventure a " + + "where a.landmark.id=:landmark AND a.createdAt >= :from " + + "GROUP BY a.user.id) " + + "where user_id=:#{#user.id}") Optional findMyRankByLandmarkId(@Param(value = "user") User user, @Param(value = "landmark") Long landmarkId, @Param(value = "from") LocalDateTime from); @@ -38,9 +36,9 @@ Optional findMyRankByLandmarkId(@Param(value = "user") User user, @Query("SELECT SUM(a.score) " + "FROM Adventure a " + "WHERE a.user.id=:#{#user.id} AND a.landmark.id=:#{#landmark.id} AND a.createdAt >= :from") - long getSumScoreByUserAndLandmark(@Param(value = "user") User user, - @Param(value = "landmark") Landmark landmark, - @Param(value = "from") LocalDateTime from); + long getSumScoreByUserAndLandmarkAfter(@Param(value = "user") User user, + @Param(value = "landmark") Landmark landmark, + @Param(value = "from") LocalDateTime from); long countByUserAndLandmark(User user, Landmark requestSaveLandmark); } diff --git a/src/main/java/com/playkuround/playkuroundserver/domain/landmark/domain/Landmark.java b/src/main/java/com/playkuround/playkuroundserver/domain/landmark/domain/Landmark.java index 27a30bf..c898c4d 100644 --- a/src/main/java/com/playkuround/playkuroundserver/domain/landmark/domain/Landmark.java +++ b/src/main/java/com/playkuround/playkuroundserver/domain/landmark/domain/Landmark.java @@ -1,6 +1,8 @@ package com.playkuround.playkuroundserver.domain.landmark.domain; import com.playkuround.playkuroundserver.domain.user.domain.User; +import com.playkuround.playkuroundserver.global.util.Location; +import com.playkuround.playkuroundserver.global.util.LocationDistanceUtils; import jakarta.persistence.*; import lombok.AccessLevel; import lombok.Getter; @@ -46,4 +48,11 @@ public void deleteRank() { this.firstUser = null; this.highestScore = 0; } + + public boolean isInRecognitionRadius(Location location) { + Location locationOfLandmark = new Location(latitude, longitude); + double distance = LocationDistanceUtils.distance(locationOfLandmark, location); + + return distance <= recognitionRadius; + } } From 0d3c52b726fb9fb85de579cb0c0d15708231e5b1 Mon Sep 17 00:00:00 2001 From: seungtaekhong Date: Tue, 2 Jul 2024 16:33:46 +0900 Subject: [PATCH 2/3] test: AdventureService integration test --- .../IntegrationServiceTest.java | 17 ++ .../application/AdventureServiceTest.java | 157 ++++++++++++++++++ 2 files changed, 174 insertions(+) create mode 100644 src/test/java/com/playkuround/playkuroundserver/IntegrationServiceTest.java create mode 100644 src/test/java/com/playkuround/playkuroundserver/domain/adventure/application/AdventureServiceTest.java diff --git a/src/test/java/com/playkuround/playkuroundserver/IntegrationServiceTest.java b/src/test/java/com/playkuround/playkuroundserver/IntegrationServiceTest.java new file mode 100644 index 0000000..4c8f07d --- /dev/null +++ b/src/test/java/com/playkuround/playkuroundserver/IntegrationServiceTest.java @@ -0,0 +1,17 @@ +package com.playkuround.playkuroundserver; + +import org.springframework.boot.autoconfigure.domain.EntityScan; +import org.springframework.boot.test.context.SpringBootTest; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@SpringBootTest(properties = "spring.profiles.active=test") +@EntityScan(basePackages = {"com.playkuround.playkuroundserver.domain"}) +public @interface IntegrationServiceTest { +} + diff --git a/src/test/java/com/playkuround/playkuroundserver/domain/adventure/application/AdventureServiceTest.java b/src/test/java/com/playkuround/playkuroundserver/domain/adventure/application/AdventureServiceTest.java new file mode 100644 index 0000000..2d59584 --- /dev/null +++ b/src/test/java/com/playkuround/playkuroundserver/domain/adventure/application/AdventureServiceTest.java @@ -0,0 +1,157 @@ +package com.playkuround.playkuroundserver.domain.adventure.application; + +import com.playkuround.playkuroundserver.IntegrationServiceTest; +import com.playkuround.playkuroundserver.TestUtil; +import com.playkuround.playkuroundserver.domain.adventure.dao.AdventureRepository; +import com.playkuround.playkuroundserver.domain.adventure.domain.Adventure; +import com.playkuround.playkuroundserver.domain.adventure.dto.AdventureSaveDto; +import com.playkuround.playkuroundserver.domain.adventure.exception.InvalidLandmarkLocationException; +import com.playkuround.playkuroundserver.domain.badge.dao.BadgeRepository; +import com.playkuround.playkuroundserver.domain.badge.dto.NewlyRegisteredBadge; +import com.playkuround.playkuroundserver.domain.landmark.dao.LandmarkRepository; +import com.playkuround.playkuroundserver.domain.landmark.domain.Landmark; +import com.playkuround.playkuroundserver.domain.landmark.exception.LandmarkNotFoundException; +import com.playkuround.playkuroundserver.domain.score.domain.ScoreType; +import com.playkuround.playkuroundserver.domain.user.dao.UserRepository; +import com.playkuround.playkuroundserver.domain.user.domain.Major; +import com.playkuround.playkuroundserver.domain.user.domain.User; +import com.playkuround.playkuroundserver.global.util.Location; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.test.context.jdbc.Sql; + +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.*; + +@IntegrationServiceTest +@Sql(scripts = {"/data-mysql.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) +class AdventureServiceTest { + + private final String redisSetKey = "ranking"; + @Autowired + private BadgeRepository badgeRepository; + @Autowired + private UserRepository userRepository; + @Autowired + private AdventureRepository adventureRepository; + @Autowired + private RedisTemplate redisTemplate; + @Autowired + private LandmarkRepository landmarkRepository; + @Autowired + private AdventureService adventureService; + + @AfterEach + void clean() { + badgeRepository.deleteAllInBatch(); + adventureRepository.deleteAllInBatch(); + landmarkRepository.deleteAllInBatch(); + userRepository.deleteAllInBatch(); + redisTemplate.delete(redisSetKey); + } + + @Test + @DisplayName("탐험을 하게 되면 total score 증가, adventure 저장, 랜드마크별 최고기록과 유저별 게임 최고기록이 업데이트 된다.") + void saveAdventure_1() { + // given + User user = TestUtil.createUser(); + + Landmark landmark = landmarkRepository.findById(3L).get(); + Location location = new Location(landmark.getLatitude(), landmark.getLongitude()); + AdventureSaveDto adventureSaveDto = new AdventureSaveDto(user, landmark.getId(), location, 100, ScoreType.BOOK); + + // when + NewlyRegisteredBadge newlyRegisteredBadge = adventureService.saveAdventure(adventureSaveDto); + + // then + // Total Score 저장 및 최고 점수 갱신 + List users = userRepository.findAll(); + assertThat(users).hasSize(1) + .extracting("highestScore.highestCardScore") + .containsExactly(adventureSaveDto.score()); + + // adventure 저장 + List adventures = adventureRepository.findAll(); + assertThat(adventures).hasSize(1) + .extracting("score", "scoreType", "user.id", "landmark.id") + .containsOnly(tuple(adventureSaveDto.score(), adventureSaveDto.scoreType(), users.get(0).getId(), landmark.getId())); + + // 랜드마크 최고 점수 갱신 + Optional optionalLandmark = landmarkRepository.findById(landmark.getId()); + assertThat(optionalLandmark).isPresent() + .get() + .extracting("highestScore", "firstUser.id") + .contains(adventureSaveDto.score(), users.get(0).getId()); + } + + @Test + @DisplayName("랜드마크가 존재하지 않으면 에러가 발생한다.") + void saveAdventure_2() { + // given + User user = TestUtil.createUser(); + + Landmark landmark = landmarkRepository.findById(3L).get(); + Location location = new Location(landmark.getLatitude(), landmark.getLongitude()); + AdventureSaveDto adventureSaveDto = new AdventureSaveDto(user, -1L, location, 100, ScoreType.BOOK); + + // expected + assertThatThrownBy(() -> adventureService.saveAdventure(adventureSaveDto)) + .isInstanceOf(LandmarkNotFoundException.class) + .hasMessage("-1의 랜드마크 조회에 실패하였습니다."); + + List adventures = adventureRepository.findAll(); + assertThat(adventures).isEmpty(); + } + + @Test + @DisplayName("인식 거리 밖에 있으면 에러가 발생한다.") + void saveAdventure_3() { + // given + User user = TestUtil.createUser(); + + Landmark landmark = landmarkRepository.findById(3L).get(); + Location location = new Location(0, 0); + AdventureSaveDto adventureSaveDto = new AdventureSaveDto(user, landmark.getId(), location, 100, ScoreType.BOOK); + + // when + assertThatThrownBy(() -> adventureService.saveAdventure(adventureSaveDto)) + .isInstanceOf(InvalidLandmarkLocationException.class) + .hasMessage("현재 위치와 랜드마크 위치가 너무 멉니다."); + + List adventures = adventureRepository.findAll(); + assertThat(adventures).isEmpty(); + } + + @Test + @DisplayName("랜드마크 최고 기록자가 아니라면, 랜드마크 랭킹 1위는 업데이트 되지 않는다.") + void saveAdventure_4() { + // given + User user = TestUtil.createUser(); + User otherUser = TestUtil.createUser("other@test.com", "other", Major.건축학부); + userRepository.saveAll(List.of(user, otherUser)); + + long highestScore = 1000; + Landmark landmark = landmarkRepository.findById(3L).get(); + landmark.updateFirstUser(otherUser, highestScore); + landmarkRepository.save(landmark); // update + + Location location = new Location(landmark.getLatitude(), landmark.getLongitude()); + AdventureSaveDto adventureSaveDto = new AdventureSaveDto(user, landmark.getId(), location, 100, ScoreType.BOOK); + + // when + NewlyRegisteredBadge newlyRegisteredBadge = adventureService.saveAdventure(adventureSaveDto); + + // then + Optional optionalLandmark = landmarkRepository.findById(landmark.getId()); + assertThat(optionalLandmark).isPresent() + .get() + .extracting("highestScore", "firstUser.id") + .contains(highestScore, otherUser.getId()); + } + +} \ No newline at end of file From 7c5745afb1a16945241e837d95eb7b216f62984e Mon Sep 17 00:00:00 2001 From: seungtaekhong Date: Tue, 2 Jul 2024 16:34:04 +0900 Subject: [PATCH 3/3] =?UTF-8?q?test:=20AuthEmailVerifyServiceTest=20?= =?UTF-8?q?=ED=86=B5=EA=B3=BC=EB=90=98=EB=8F=84=EB=A1=9D=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/email/application/AuthEmailVerifyServiceTest.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/playkuround/playkuroundserver/domain/auth/email/application/AuthEmailVerifyServiceTest.java b/src/test/java/com/playkuround/playkuroundserver/domain/auth/email/application/AuthEmailVerifyServiceTest.java index e815f3a..e92dc21 100644 --- a/src/test/java/com/playkuround/playkuroundserver/domain/auth/email/application/AuthEmailVerifyServiceTest.java +++ b/src/test/java/com/playkuround/playkuroundserver/domain/auth/email/application/AuthEmailVerifyServiceTest.java @@ -142,11 +142,12 @@ void authEmailInvalidate() { @DisplayName("authEmail이 만료되면 AuthCodeExpiredException 발생") void authEmailExpired() { // given - AuthEmail authEmail = AuthEmail.createAuthEmail("target", "code", LocalDateTime.now().minusDays(1)); + LocalDateTime now = LocalDateTime.of(2024, 7, 1, 0, 0); + AuthEmail authEmail = AuthEmail.createAuthEmail("target", "code", now.minusDays(1)); when(authEmailRepository.findFirstByTargetOrderByCreatedAtDesc(any(String.class))) .thenReturn(Optional.of(authEmail)); when(dateTimeService.getLocalDateTimeNow()) - .thenReturn(LocalDateTime.of(2024, 7, 1, 0, 0)); + .thenReturn(now); // expected assertThatThrownBy(() -> authEmailVerifyService.verifyAuthEmail("code", "target"))