diff --git a/README.md b/README.md index b9d04dd2..00b2da30 100644 --- a/README.md +++ b/README.md @@ -1 +1,42 @@ -# moabam-BE +## ๐Ÿฅ MOABAM ์„œ๋น„์Šค + +![img.png](readme-image/img.png) + +![img_1.png](readme-image/img_1.png) + +

+ +## ๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘ง Backend Team ์†Œ๊ฐœ + +| ๊น€์˜๋ช… | ๊น€ํฌ๋นˆ | ๋ฐ•์„ธ์—ฐ(PO) | ์‹ ์žฌ์œค | ํ™ํ˜์ค€(SM) | +|:------------------------------------------------------------------------------:|:------------------------------------------------------------------------------:|:------------------------------------------------------------------------------:|:------------------------------------------------------------------------------:|:------------------------------------------------------------------------------:| +| DEVELOPER | DEVELOPER | DEVELOPER | DEVELOPER | DEVELOPER | +| | | | | | +| [ymkim97](https://github.com/ymkim97) | [kmebin](https://github.com/kmebin) | [parksey](https://github.com/parksey) | [DevUni](https://github.com/Shin-Jae-Yoon) | [HongDosan](https://github.com/HyuckJuneHong) | +| ๋ฐฉ ๋„๋ฉ”์ธ, ๋ฃจํ‹ด ์ธ์ฆ(๋ฉ”์ธ) | ์ƒํ’ˆ ๋„๋ฉ”์ธ, ๊ฒฐ์ œ, ์—๋Ÿฌ ์•Œ๋ฆผ, BE ํŒ€์žฅ | ํšŒ์› ๋„๋ฉ”์ธ, ๋žญํ‚น ์–ด๋“œ๋ฏผ ํŽ˜์ด์ง€ | ๋ฐฉ ๋„๋ฉ”์ธ, ๋ฃจํ‹ด ์ธ์ฆ(์„œ๋ธŒ), ์ธํ”„๋ผ (AWS, CI/CD) | ์ฟ ํฐ ๋„๋ฉ”์ธ, ์•Œ๋ฆผ, ์„ ์ฐฉ์ˆœ ์ด๋ฒคํŠธ, ์บ์‹ฑ | + +

+ +## ๊ณตํ†ต ํ˜‘์—… ๋ฐฉ์‹ + +![img.png](readme-image/ํ˜‘์—….png) + +## ์„œ๋น„์Šค ์•„ํ‚คํ…์ฒ˜ + +![img.png](readme-image/์„œ๋น„์Šค-์•„ํ‚คํ…์ฒ˜.png) + +## CI/CD ํŒŒ์ดํ”„๋ผ์ธ + +![img.png](readme-image/ํŒŒ์ดํ”„๋ผ์ธ.png) + +## ์ปจ๋ฒค์…˜ + +![img_1.png](readme-image/์ปจ๋ฒค์…˜.png) + +## Config ๊ด€๋ฆฌ + +![img.png](readme-image/์ฝ˜ํ”ผ๊ทธ.png) + +## Test + +![img.png](readme-image/ํ…Œ์ŠคํŠธ.png) diff --git a/build.gradle b/build.gradle index c7f8c37e..63b52fa7 100644 --- a/build.gradle +++ b/build.gradle @@ -15,14 +15,26 @@ java { sourceCompatibility = '17' } +compileJava { + options.compilerArgs << '-parameters' + options.encoding = 'UTF-8' +} + +compileTestJava { + options.compilerArgs << '-parameters' + options.encoding = 'UTF-8' +} + ext { snippetsDir = file('build/generated-snippets') } def querydslSrcDir = 'src/main/generated' + clean { delete file(querydslSrcDir) } + tasks.withType(JavaCompile) { options.generatedSourceOutputDirectory = file(querydslSrcDir) } @@ -75,6 +87,9 @@ dependencies { // Apache Commons Lang 3 implementation 'org.apache.commons:commons-lang3:3.13.0' + // Cache + implementation 'org.springframework.boot:spring-boot-starter-cache' + // Redis implementation 'org.springframework.boot:spring-boot-starter-data-redis' @@ -134,28 +149,25 @@ jacocoTestReport { afterEvaluate { classDirectories.setFrom( - files(classDirectories.files.collect { - fileTree(dir: it, excludes: [ - "**/*Application*", - "**/*Config*", - "**/*Request*", - "**/*Response*", - "**/*Exception*", - "**/*Mapper*", - "**/*ErrorMessage*", - "**/*DynamicQuery*", - "**/*BaseTimeEntity*", - "**/*HealthCheckController*", - "**/*S3Manager*", - ] + Qdomains) - }) + files(classDirectories.files.collect { + fileTree(dir: it, excludes: [ + "**/*Application*", + "**/*Config*", + "**/*Request*", + "**/*Response*", + "**/*Exception*", + "**/*Mapper*", + "**/*ErrorMessage*", + "**/*DynamicQuery*", + "**/*BaseTimeEntity*", + "**/*HealthCheckController*", + "**/*S3Manager*", + ] + Qdomains) + }) ) } } -compileJava.options.encoding = 'UTF-8' -compileTestJava.options.encoding = 'UTF-8' - tasks.withType(Checkstyle).configureEach { reports { xml.required = true @@ -177,9 +189,9 @@ sonar { property "sonar.host.url", "https://sonarcloud.io" property 'sonar.coverage.jacoco.xmlReportPaths', 'build/reports/jacoco/test/jacocoTestReport.xml' property 'sonar.coverage.exclusions', '**/test/**, **/Q*.java, **/*Doc*.java, **/resources/** ' + - ',**/*Application*.java , **/*Config*.java, **/*Request*.java, **/*Response*.java ,**/*Exception*.java ' + - ',**/*ErrorMessage*.java, **/*Mapper*.java, **/*DynamicQuery*, **/*BaseTimeEntity*, **/*HealthCheckController* ' + - ', **/*S3Manager*.java' + ',**/*Application*.java , **/*Config*.java, **/*Request*.java, **/*Response*.java ,**/*Exception*.java ' + + ',**/*ErrorMessage*.java, **/*Mapper*.java, **/*DynamicQuery*, **/*BaseTimeEntity*, **/*HealthCheckController* ' + + ', **/*S3Manager*.java' property 'sonar.java.checkstyle.reportPaths', 'build/reports/checkstyle/main.xml' } } diff --git a/readme-image/img.png b/readme-image/img.png new file mode 100644 index 00000000..42fda84d Binary files /dev/null and b/readme-image/img.png differ diff --git a/readme-image/img_1.png b/readme-image/img_1.png new file mode 100644 index 00000000..911a57d3 Binary files /dev/null and b/readme-image/img_1.png differ diff --git "a/readme-image/\354\204\234\353\271\204\354\212\244-\354\225\204\355\202\244\355\205\215\354\262\230.png" "b/readme-image/\354\204\234\353\271\204\354\212\244-\354\225\204\355\202\244\355\205\215\354\262\230.png" new file mode 100644 index 00000000..a8400b13 Binary files /dev/null and "b/readme-image/\354\204\234\353\271\204\354\212\244-\354\225\204\355\202\244\355\205\215\354\262\230.png" differ diff --git "a/readme-image/\354\273\250\353\262\244\354\205\230.png" "b/readme-image/\354\273\250\353\262\244\354\205\230.png" new file mode 100644 index 00000000..c2b6cb3f Binary files /dev/null and "b/readme-image/\354\273\250\353\262\244\354\205\230.png" differ diff --git "a/readme-image/\354\275\230\355\224\274\352\267\270.png" "b/readme-image/\354\275\230\355\224\274\352\267\270.png" new file mode 100644 index 00000000..c0cc64a9 Binary files /dev/null and "b/readme-image/\354\275\230\355\224\274\352\267\270.png" differ diff --git "a/readme-image/\355\205\214\354\212\244\355\212\270.png" "b/readme-image/\355\205\214\354\212\244\355\212\270.png" new file mode 100644 index 00000000..fb9929d1 Binary files /dev/null and "b/readme-image/\355\205\214\354\212\244\355\212\270.png" differ diff --git "a/readme-image/\355\214\214\354\235\264\355\224\204\353\235\274\354\235\270.png" "b/readme-image/\355\214\214\354\235\264\355\224\204\353\235\274\354\235\270.png" new file mode 100644 index 00000000..b18d2356 Binary files /dev/null and "b/readme-image/\355\214\214\354\235\264\355\224\204\353\235\274\354\235\270.png" differ diff --git "a/readme-image/\355\230\221\354\227\205.png" "b/readme-image/\355\230\221\354\227\205.png" new file mode 100644 index 00000000..37d8cc3c Binary files /dev/null and "b/readme-image/\355\230\221\354\227\205.png" differ diff --git a/src/main/java/com/moabam/api/application/coupon/CouponCacheService.java b/src/main/java/com/moabam/api/application/coupon/CouponCacheService.java new file mode 100644 index 00000000..0880a42e --- /dev/null +++ b/src/main/java/com/moabam/api/application/coupon/CouponCacheService.java @@ -0,0 +1,34 @@ +package com.moabam.api.application.coupon; + +import java.time.LocalDate; +import java.util.Optional; + +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; + +import com.moabam.api.domain.coupon.Coupon; +import com.moabam.api.domain.coupon.repository.CouponRepository; +import com.moabam.global.error.exception.NotFoundException; +import com.moabam.global.error.model.ErrorMessage; + +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +@CacheConfig(cacheNames = "coupons") +public class CouponCacheService { + + private final CouponRepository couponRepository; + + @Cacheable(key = "#couponName + #now") + public Coupon getByNameAndStartAt(String couponName, LocalDate now) { + return couponRepository.findByNameAndStartAt(couponName, now) + .orElseThrow(() -> new NotFoundException(ErrorMessage.INVALID_COUPON_PERIOD)); + } + + @Cacheable(key = "#now") + public Optional getByStartAt(LocalDate now) { + return couponRepository.findByStartAt(now); + } +} diff --git a/src/main/java/com/moabam/api/application/coupon/CouponManageService.java b/src/main/java/com/moabam/api/application/coupon/CouponManageService.java index 3cda6f9a..cadf613c 100644 --- a/src/main/java/com/moabam/api/application/coupon/CouponManageService.java +++ b/src/main/java/com/moabam/api/application/coupon/CouponManageService.java @@ -11,12 +11,10 @@ import com.moabam.api.domain.coupon.Coupon; import com.moabam.api.domain.coupon.CouponWallet; import com.moabam.api.domain.coupon.repository.CouponManageRepository; -import com.moabam.api.domain.coupon.repository.CouponRepository; import com.moabam.api.domain.coupon.repository.CouponWalletRepository; import com.moabam.global.common.util.ClockHolder; import com.moabam.global.error.exception.BadRequestException; import com.moabam.global.error.exception.ConflictException; -import com.moabam.global.error.exception.NotFoundException; import com.moabam.global.error.model.ErrorMessage; import lombok.RequiredArgsConstructor; @@ -34,14 +32,14 @@ public class CouponManageService { private final ClockHolder clockHolder; private final NotificationService notificationService; - private final CouponRepository couponRepository; + private final CouponCacheService couponCacheService; private final CouponManageRepository couponManageRepository; private final CouponWalletRepository couponWalletRepository; @Scheduled(fixedDelay = 1000) public void issue() { LocalDate now = clockHolder.date(); - Optional optionalCoupon = couponRepository.findByStartAt(now); + Optional optionalCoupon = couponCacheService.getByStartAt(now); if (optionalCoupon.isEmpty()) { return; @@ -70,21 +68,20 @@ public void issue() { couponManageRepository.increase(couponName, membersId.size()); } + public void delete(String couponName) { + couponManageRepository.deleteQueue(couponName); + couponManageRepository.deleteCount(couponName); + } + public void registerQueue(String couponName, Long memberId) { double registerTime = System.currentTimeMillis(); validateRegisterQueue(couponName, memberId); couponManageRepository.addIfAbsentQueue(couponName, memberId, registerTime); } - public void delete(String couponName) { - couponManageRepository.deleteQueue(couponName); - couponManageRepository.deleteCount(couponName); - } - private void validateRegisterQueue(String couponName, Long memberId) { LocalDate now = clockHolder.date(); - Coupon coupon = couponRepository.findByNameAndStartAt(couponName, now) - .orElseThrow(() -> new NotFoundException(ErrorMessage.INVALID_COUPON_PERIOD)); + Coupon coupon = couponCacheService.getByNameAndStartAt(couponName, now); if (couponManageRepository.hasValue(couponName, memberId)) { throw new ConflictException(ErrorMessage.CONFLICT_COUPON_ISSUE); diff --git a/src/main/java/com/moabam/api/application/member/MemberService.java b/src/main/java/com/moabam/api/application/member/MemberService.java index ef3a761c..7c900af5 100644 --- a/src/main/java/com/moabam/api/application/member/MemberService.java +++ b/src/main/java/com/moabam/api/application/member/MemberService.java @@ -89,7 +89,7 @@ public void delete(Member member) { throw new BadRequestException(NEED_TO_EXIT_ALL_ROOMS); } - member.delete(clockHolder.times()); + member.delete(clockHolder.dateTime()); memberRepository.flush(); memberRepository.delete(member); rankingService.removeRanking(MemberMapper.toRankingInfo(member)); diff --git a/src/main/java/com/moabam/api/application/notification/NotificationService.java b/src/main/java/com/moabam/api/application/notification/NotificationService.java index 3d8c859b..ab5ef937 100644 --- a/src/main/java/com/moabam/api/application/notification/NotificationService.java +++ b/src/main/java/com/moabam/api/application/notification/NotificationService.java @@ -64,7 +64,7 @@ public void sendCouponIssueResult(Long memberId, String couponName, String body) @Scheduled(cron = "0 55 * * * *") public void sendCertificationTime() { - int certificationTime = (clockHolder.times().getHour() + ONE_HOUR) % HOURS_IN_A_DAY; + int certificationTime = (clockHolder.dateTime().getHour() + ONE_HOUR) % HOURS_IN_A_DAY; List participants = participantSearchRepository.findAllByRoomCertifyTime(certificationTime); participants.parallelStream().forEach(participant -> { diff --git a/src/main/java/com/moabam/api/application/room/CertificationService.java b/src/main/java/com/moabam/api/application/room/CertificationService.java index c4e86434..d65f0081 100644 --- a/src/main/java/com/moabam/api/application/room/CertificationService.java +++ b/src/main/java/com/moabam/api/application/room/CertificationService.java @@ -70,7 +70,7 @@ public CertifiedMemberInfo getCertifiedMemberInfo(Long memberId, Long roomId, Li case NIGHT -> BugType.NIGHT; }; - validateCertifyTime(clockHolder.times(), room.getCertifyTime()); + validateCertifyTime(clockHolder.dateTime(), room.getCertifyTime()); validateAlreadyCertified(memberId, roomId, today); certifyMember(memberId, roomId, participant, member, imageUrls); diff --git a/src/main/java/com/moabam/api/application/room/RoomService.java b/src/main/java/com/moabam/api/application/room/RoomService.java index 1f2ccdce..e274a560 100644 --- a/src/main/java/com/moabam/api/application/room/RoomService.java +++ b/src/main/java/com/moabam/api/application/room/RoomService.java @@ -216,7 +216,7 @@ private void validateEnteredRoomCount(Long memberId, RoomType roomType) { } private void validateCertifyTime(Room room) { - LocalDateTime now = clockHolder.times(); + LocalDateTime now = clockHolder.dateTime(); LocalTime targetTime = LocalTime.of(room.getCertifyTime(), 0); LocalDateTime targetDateTime = LocalDateTime.of(now.toLocalDate(), targetTime); diff --git a/src/main/java/com/moabam/api/application/room/SearchService.java b/src/main/java/com/moabam/api/application/room/SearchService.java index 91ec3410..1e60f0e8 100644 --- a/src/main/java/com/moabam/api/application/room/SearchService.java +++ b/src/main/java/com/moabam/api/application/room/SearchService.java @@ -384,7 +384,7 @@ private double calculateCompletePercentage(int certifiedMembersCount, Room room, return 0; } - LocalDateTime now = clockHolder.times(); + LocalDateTime now = clockHolder.dateTime(); LocalTime targetTime = LocalTime.of(room.getCertifyTime(), 0); LocalDateTime targetDateTime = LocalDateTime.of(now.toLocalDate(), targetTime); diff --git a/src/main/java/com/moabam/api/domain/coupon/repository/CouponRepository.java b/src/main/java/com/moabam/api/domain/coupon/repository/CouponRepository.java index f236858d..a4ed3c5f 100644 --- a/src/main/java/com/moabam/api/domain/coupon/repository/CouponRepository.java +++ b/src/main/java/com/moabam/api/domain/coupon/repository/CouponRepository.java @@ -16,6 +16,4 @@ public interface CouponRepository extends JpaRepository { Optional findByStartAt(LocalDate startAt); Optional findByNameAndStartAt(String couponName, LocalDate startAt); - - boolean existsByNameAndStartAt(String couponName, LocalDate startAt); } diff --git a/src/main/java/com/moabam/global/common/util/ClockHolder.java b/src/main/java/com/moabam/global/common/util/ClockHolder.java index 1ba7a0c5..4afc579b 100644 --- a/src/main/java/com/moabam/global/common/util/ClockHolder.java +++ b/src/main/java/com/moabam/global/common/util/ClockHolder.java @@ -2,10 +2,15 @@ import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.LocalTime; public interface ClockHolder { - LocalDateTime times(); + LocalDateTime dateTime(); LocalDate date(); + + LocalTime time(); + + LocalTime endOfDay(); } diff --git a/src/main/java/com/moabam/global/common/util/SystemClockHolder.java b/src/main/java/com/moabam/global/common/util/SystemClockHolder.java index 8804769c..756457bc 100644 --- a/src/main/java/com/moabam/global/common/util/SystemClockHolder.java +++ b/src/main/java/com/moabam/global/common/util/SystemClockHolder.java @@ -2,6 +2,7 @@ import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.LocalTime; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Component; @@ -11,7 +12,7 @@ public class SystemClockHolder implements ClockHolder { @Override - public LocalDateTime times() { + public LocalDateTime dateTime() { return LocalDateTime.now(); } @@ -19,4 +20,14 @@ public LocalDateTime times() { public LocalDate date() { return LocalDate.now(); } + + @Override + public LocalTime time() { + return LocalTime.now(); + } + + @Override + public LocalTime endOfDay() { + return LocalTime.of(23, 59, 59, 999_999_999); + } } diff --git a/src/main/java/com/moabam/global/config/CacheConfig.java b/src/main/java/com/moabam/global/config/CacheConfig.java new file mode 100644 index 00000000..974f1bf3 --- /dev/null +++ b/src/main/java/com/moabam/global/config/CacheConfig.java @@ -0,0 +1,62 @@ +package com.moabam.global.config; + +import static org.springframework.data.redis.serializer.RedisSerializationContext.*; + +import java.time.Duration; +import java.time.LocalTime; + +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.cache.RedisCacheConfiguration; +import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.databind.json.JsonMapper; +import com.fasterxml.jackson.databind.jsontype.BasicPolymorphicTypeValidator; +import com.fasterxml.jackson.databind.jsontype.PolymorphicTypeValidator; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import com.moabam.global.common.util.ClockHolder; + +import lombok.RequiredArgsConstructor; + +@EnableCaching +@Configuration +@RequiredArgsConstructor +public class CacheConfig { + + private final ClockHolder clockHolder; + + @Bean + public RedisCacheConfiguration redisCacheConfiguration() { + var strSerializePair = SerializationPair.fromSerializer(new StringRedisSerializer()); + var objSerializePair = SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer(objectMapper())); + + return RedisCacheConfiguration.defaultCacheConfig() + .entryTtl(getTtl()) + .serializeKeysWith(strSerializePair) + .serializeValuesWith(objSerializePair); + } + + private Duration getTtl() { + LocalTime now = clockHolder.time(); + LocalTime end = clockHolder.endOfDay(); + + return Duration.between(now, end); + } + + private ObjectMapper objectMapper() { + PolymorphicTypeValidator polymorphicTypeValidator = BasicPolymorphicTypeValidator.builder() + .allowIfSubType(Object.class) + .build(); + + return JsonMapper.builder() + .polymorphicTypeValidator(polymorphicTypeValidator) + .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) + .addModule(new JavaTimeModule()) + .activateDefaultTyping(polymorphicTypeValidator, ObjectMapper.DefaultTyping.NON_FINAL) + .build(); + } +} diff --git a/src/test/java/com/moabam/api/application/coupon/CouponManageServiceTest.java b/src/test/java/com/moabam/api/application/coupon/CouponManageServiceTest.java index d209cdfe..881842b1 100644 --- a/src/test/java/com/moabam/api/application/coupon/CouponManageServiceTest.java +++ b/src/test/java/com/moabam/api/application/coupon/CouponManageServiceTest.java @@ -21,11 +21,9 @@ import com.moabam.api.domain.coupon.Coupon; import com.moabam.api.domain.coupon.CouponWallet; import com.moabam.api.domain.coupon.repository.CouponManageRepository; -import com.moabam.api.domain.coupon.repository.CouponRepository; import com.moabam.api.domain.coupon.repository.CouponWalletRepository; import com.moabam.global.common.util.ClockHolder; import com.moabam.global.error.exception.NotFoundException; -import com.moabam.global.error.model.ErrorMessage; import com.moabam.support.common.FilterProcessExtension; import com.moabam.support.fixture.CouponFixture; @@ -39,7 +37,7 @@ class CouponManageServiceTest { NotificationService notificationService; @Mock - CouponRepository couponRepository; + CouponCacheService couponCacheService; @Mock CouponManageRepository couponManageRepository; @@ -58,7 +56,7 @@ void issue_all_success(Set values) { Coupon coupon = CouponFixture.coupon(1000, 100); given(clockHolder.date()).willReturn(LocalDate.now()); - given(couponRepository.findByStartAt(any(LocalDate.class))).willReturn(Optional.of(coupon)); + given(couponCacheService.getByStartAt(any(LocalDate.class))).willReturn(Optional.of(coupon)); given(couponManageRepository.rangeQueue(any(String.class), any(long.class), any(long.class))) .willReturn(values); given(couponManageRepository.getCount(any(String.class))).willReturn(coupon.getMaxCount() - 1); @@ -77,7 +75,7 @@ void issue_all_success(Set values) { void issue_notStartAt() { // Given given(clockHolder.date()).willReturn(LocalDate.now()); - given(couponRepository.findByStartAt(any(LocalDate.class))).willReturn(Optional.empty()); + given(couponCacheService.getByStartAt(any(LocalDate.class))).willReturn(Optional.empty()); // When couponManageService.issue(); @@ -98,7 +96,7 @@ void issue_stockEnd() { Coupon coupon = CouponFixture.coupon(1000, 100); given(clockHolder.date()).willReturn(LocalDate.now()); - given(couponRepository.findByStartAt(any(LocalDate.class))).willReturn(Optional.of(coupon)); + given(couponCacheService.getByStartAt(any(LocalDate.class))).willReturn(Optional.of(coupon)); given(couponManageRepository.getCount(any(String.class))).willReturn(coupon.getMaxCount()); // When @@ -120,8 +118,7 @@ void registerQueue_success() { given(clockHolder.date()).willReturn(LocalDate.now()); given(couponManageRepository.sizeQueue(any(String.class))).willReturn(coupon.getMaxCount() - 1); - given(couponRepository.findByNameAndStartAt(any(String.class), any(LocalDate.class))) - .willReturn(Optional.of(coupon)); + given(couponCacheService.getByNameAndStartAt(any(String.class), any(LocalDate.class))).willReturn(coupon); // When couponManageService.registerQueue(coupon.getName(), 1L); @@ -135,13 +132,12 @@ void registerQueue_success() { void registerQueue_No_BadRequestException() { // Given given(clockHolder.date()).willReturn(LocalDate.now()); - given(couponRepository.findByNameAndStartAt(any(String.class), any(LocalDate.class))) - .willReturn(Optional.empty()); + given(couponCacheService.getByNameAndStartAt(any(String.class), any(LocalDate.class))) + .willThrow(NotFoundException.class); // When & Then assertThatThrownBy(() -> couponManageService.registerQueue("couponName", 1L)) - .isInstanceOf(NotFoundException.class) - .hasMessage(ErrorMessage.INVALID_COUPON_PERIOD.getMessage()); + .isInstanceOf(NotFoundException.class); } @DisplayName("์ฟ ํฐ ๋Œ€๊ธฐ์—ด๊ณผ ๋ฐœํ–‰๋œ ์žฌ๊ณ ๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์‚ญ์ œ๋œ๋‹ค.") diff --git a/src/test/java/com/moabam/api/application/member/MemberServiceTest.java b/src/test/java/com/moabam/api/application/member/MemberServiceTest.java index 5bb68977..dc28bb72 100644 --- a/src/test/java/com/moabam/api/application/member/MemberServiceTest.java +++ b/src/test/java/com/moabam/api/application/member/MemberServiceTest.java @@ -129,7 +129,7 @@ void signUp_success() { void undo_delete_member(@WithMember AuthMember authMember) { // given Member member = MemberFixture.member(); - given(clockHolder.times()).willReturn(LocalDateTime.now()); + given(clockHolder.dateTime()).willReturn(LocalDateTime.now()); // When memberService.delete(member); diff --git a/src/test/java/com/moabam/api/application/notification/NotificationServiceTest.java b/src/test/java/com/moabam/api/application/notification/NotificationServiceTest.java index a08d2b06..2cb980ee 100644 --- a/src/test/java/com/moabam/api/application/notification/NotificationServiceTest.java +++ b/src/test/java/com/moabam/api/application/notification/NotificationServiceTest.java @@ -169,7 +169,7 @@ void sendCertificationTime_success(List participants) { // Given given(participantSearchRepository.findAllByRoomCertifyTime(any(Integer.class))).willReturn(participants); given(fcmService.findTokenByMemberId(any(Long.class))).willReturn(Optional.of("FCM-TOKEN")); - given(clockHolder.times()).willReturn(LocalDateTime.now()); + given(clockHolder.dateTime()).willReturn(LocalDateTime.now()); // When notificationService.sendCertificationTime(); @@ -186,7 +186,7 @@ void sendCertificationTime_NoFirebaseMessaging(List participants) { // Given given(participantSearchRepository.findAllByRoomCertifyTime(any(Integer.class))).willReturn(participants); given(fcmService.findTokenByMemberId(any(Long.class))).willReturn(Optional.empty()); - given(clockHolder.times()).willReturn(LocalDateTime.now()); + given(clockHolder.dateTime()).willReturn(LocalDateTime.now()); // When notificationService.sendCertificationTime(); diff --git a/src/test/java/com/moabam/api/application/room/CertificationServiceTest.java b/src/test/java/com/moabam/api/application/room/CertificationServiceTest.java index e02eac44..ad8b6579 100644 --- a/src/test/java/com/moabam/api/application/room/CertificationServiceTest.java +++ b/src/test/java/com/moabam/api/application/room/CertificationServiceTest.java @@ -131,7 +131,7 @@ void get_certified_member_info_success() { imageUrls.add("https://image.moabam.com/certifications/20231108/1_asdfsdfxcv-4815vcx-asfd"); imageUrls.add("https://image.moabam.com/certifications/20231108/2_asdfsdfxcv-4815vcx-asfd"); - given(clockHolder.times()).willReturn(LocalDateTime.now().withHour(10).withMinute(6)); + given(clockHolder.dateTime()).willReturn(LocalDateTime.now().withHour(10).withMinute(6)); given(clockHolder.date()).willReturn(today); given(participantSearchRepository.findOne(memberId, roomId)).willReturn(Optional.of(participant)); given(memberService.findMember(memberId)).willReturn(member1); diff --git a/src/test/java/com/moabam/api/presentation/CouponControllerTest.java b/src/test/java/com/moabam/api/presentation/CouponControllerTest.java index 65f25723..3f85f40c 100644 --- a/src/test/java/com/moabam/api/presentation/CouponControllerTest.java +++ b/src/test/java/com/moabam/api/presentation/CouponControllerTest.java @@ -20,6 +20,7 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.boot.test.mock.mockito.SpyBean; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; import org.springframework.transaction.annotation.Transactional; @@ -68,7 +69,7 @@ class CouponControllerTest extends WithoutFilterSupporter { @Autowired CouponWalletRepository couponWalletRepository; - @MockBean + @SpyBean ClockHolder clockHolder; @MockBean diff --git a/src/test/java/com/moabam/support/common/TestClockHolder.java b/src/test/java/com/moabam/support/common/TestClockHolder.java index aa75977d..3b21a0cd 100644 --- a/src/test/java/com/moabam/support/common/TestClockHolder.java +++ b/src/test/java/com/moabam/support/common/TestClockHolder.java @@ -2,6 +2,7 @@ import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.LocalTime; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Component; @@ -13,7 +14,7 @@ public class TestClockHolder implements ClockHolder { @Override - public LocalDateTime times() { + public LocalDateTime dateTime() { return LocalDateTime.of(2023, 12, 3, 14, 30, 0); } @@ -21,4 +22,14 @@ public LocalDateTime times() { public LocalDate date() { return LocalDateTime.now().toLocalDate(); } + + @Override + public LocalTime time() { + return LocalTime.of(23, 50, 50); + } + + @Override + public LocalTime endOfDay() { + return LocalTime.of(23, 59, 59, 999_999_999); + } }