diff --git a/.github/workflows/deploy-be-ci-cd-push.yml b/.github/workflows/deploy-be-ci-cd-push.yml index c30277920..01e58b0a7 100644 --- a/.github/workflows/deploy-be-ci-cd-push.yml +++ b/.github/workflows/deploy-be-ci-cd-push.yml @@ -53,13 +53,9 @@ jobs: - name: Pull Latest Docker Image run: | sudo docker login --username ${{ secrets.DOCKERHUB_DEPLOY_USERNAME }} --password ${{ secrets.DOCKERHUB_DEPLOY_TOKEN }} - if sudo docker inspect spring-baton &>/dev/null; then - sudo docker stop spring-baton - sudo docker rm -f spring-baton - sudo docker image prune -af - fi sudo docker pull 2023batondeploy/2023-baton-deploy:latest - name: Docker Compose run: | - sudo docker run --name spring-baton -v /home/ubuntu/logs:/app/logs -p 8080:8080 -e TZ=Asia/Seoul 2023batondeploy/2023-baton-deploy:latest 1>> build.log 2>> error.log & + /home/ubuntu/zero-downtime-deploy.sh + sudo docker image prune -af diff --git a/backend/baton/src/docs/asciidoc/RunnerPostReadApi.adoc b/backend/baton/src/docs/asciidoc/RunnerPostReadApi.adoc index 301113d89..6a427755c 100644 --- a/backend/baton/src/docs/asciidoc/RunnerPostReadApi.adoc +++ b/backend/baton/src/docs/asciidoc/RunnerPostReadApi.adoc @@ -54,6 +54,28 @@ include::{snippets}/../../build/generated-snippets/runner-post-read-with-logined include::{snippets}/../../build/generated-snippets/runner-post-read-with-logined-runner-api-test/read-runner-post-by-logined-runner-and-review-status/response-fields.adoc[] +==== *러너 마이페이지 게시글 개수 조회 API* + +===== *Http Request* + +include::{snippets}/../../build/generated-snippets/runner-post-count-with-logined-runner-api-test/count-runner-post-by-logined-runner-and-review-status/http-request.adoc[] + +===== *Http Request Headers* + +include::{snippets}/../../build/generated-snippets/runner-post-count-with-logined-runner-api-test/count-runner-post-by-logined-runner-and-review-status/request-headers.adoc[] + +===== *Http Request Query Parameters* + +include::{snippets}/../../build/generated-snippets/runner-post-count-with-logined-runner-api-test/count-runner-post-by-logined-runner-and-review-status/query-parameters.adoc[] + +===== *Http Response* + +include::{snippets}/../../build/generated-snippets/runner-post-count-with-logined-runner-api-test/count-runner-post-by-logined-runner-and-review-status/http-response.adoc[] + +===== *Http Response Fields* + +include::{snippets}/../../build/generated-snippets/runner-post-count-with-logined-runner-api-test/count-runner-post-by-logined-runner-and-review-status/response-fields.adoc[] + ==== *리뷰 지원한 서포터 조회 API* ===== *Http Request* @@ -94,7 +116,29 @@ include::{snippets}/../../build/generated-snippets/runner-post-read-with-logined include::{snippets}/../../build/generated-snippets/runner-post-read-with-logined-supporter-api-test/read-runner-post-by-logined-supporter-and-review-status/response-fields.adoc[] -==== *서포터 리뷰 완료한 게시글 조회 API* +==== *서포터 마이페이지 게시글 개수 조회 API* + +===== *Http Request* + +include::{snippets}/../../build/generated-snippets/runner-post-count-with-logined-supporter-api-test/count-runner-post-by-logined-supporter-and-review-status/http-request.adoc[] + +===== *Http Request Headers* + +include::{snippets}/../../build/generated-snippets/runner-post-count-with-logined-supporter-api-test/count-runner-post-by-logined-supporter-and-review-status/request-headers.adoc[] + +===== *Http Request Query Parameters* + +include::{snippets}/../../build/generated-snippets/runner-post-count-with-logined-supporter-api-test/count-runner-post-by-logined-supporter-and-review-status/query-parameters.adoc[] + +===== *Http Response* + +include::{snippets}/../../build/generated-snippets/runner-post-count-with-logined-supporter-api-test/count-runner-post-by-logined-supporter-and-review-status/http-response.adoc[] + +===== *Http Response Fields* + +include::{snippets}/../../build/generated-snippets/runner-post-count-with-logined-supporter-api-test/count-runner-post-by-logined-supporter-and-review-status/response-fields.adoc[] + +==== *서포터의 리뷰 완료한 게시글 조회 API* ===== *Http Request* @@ -112,6 +156,24 @@ include::{snippets}/../../build/generated-snippets/runner-post-read-of-supporter include::{snippets}/../../build/generated-snippets/runner-post-read-of-supporter-by-guest-api-test/read-runner-post-by-supporter-id-and-review-status/response-fields.adoc[] +==== *서포터의 리뷰 완료한 게시글 개수 조회 API* + +===== *Http Request* + +include::{snippets}/../../build/generated-snippets/runner-post-count-of-supporter-by-guest-api-test/count-runner-post-by-supporter-id-and-review-status/http-request.adoc[] + +===== *Http Request Query Parameters* + +include::{snippets}/../../build/generated-snippets/runner-post-count-of-supporter-by-guest-api-test/count-runner-post-by-supporter-id-and-review-status/query-parameters.adoc[] + +===== *Http Response* + +include::{snippets}/../../build/generated-snippets/runner-post-count-of-supporter-by-guest-api-test/count-runner-post-by-supporter-id-and-review-status/http-response.adoc[] + +===== *Http Response Fields* + +include::{snippets}/../../build/generated-snippets/runner-post-count-of-supporter-by-guest-api-test/count-runner-post-by-supporter-id-and-review-status/response-fields.adoc[] + ==== *태그 이름과 리뷰 상태를 조건으로 러너 게시글 페이징 조회 API* ===== *Http Request* diff --git a/backend/baton/src/main/java/touch/baton/config/filter/FilterConfig.java b/backend/baton/src/main/java/touch/baton/config/filter/FilterConfig.java index f40bb5064..4328e9c8f 100644 --- a/backend/baton/src/main/java/touch/baton/config/filter/FilterConfig.java +++ b/backend/baton/src/main/java/touch/baton/config/filter/FilterConfig.java @@ -15,7 +15,7 @@ public class FilterConfig implements WebMvcConfigurer { public FilterRegistrationBean getFilterRegistrationBean() { final FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(new MDCLoggingFilter()); registrationBean.setOrder(Integer.MIN_VALUE); - registrationBean.setUrlPatterns(List.of("/api/**")); + registrationBean.setUrlPatterns(List.of("/api/*")); return registrationBean; } } diff --git a/backend/baton/src/main/java/touch/baton/config/filter/MDCLoggingFilter.java b/backend/baton/src/main/java/touch/baton/config/filter/MDCLoggingFilter.java index e7d46b854..7e287fbe5 100644 --- a/backend/baton/src/main/java/touch/baton/config/filter/MDCLoggingFilter.java +++ b/backend/baton/src/main/java/touch/baton/config/filter/MDCLoggingFilter.java @@ -5,6 +5,8 @@ import jakarta.servlet.ServletException; import jakarta.servlet.ServletRequest; import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.core.config.Order; import org.slf4j.MDC; import org.springframework.core.Ordered; @@ -17,8 +19,9 @@ class MDCLoggingFilter implements Filter { @Override public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException { - final UUID uuid = UUID.randomUUID(); - MDC.put("request_id", uuid.toString()); + final String requestId = ((HttpServletRequest) servletRequest).getHeader("X-Request-ID"); + + MDC.put("request_id", StringUtils.defaultString(requestId, UUID.randomUUID().toString())); filterChain.doFilter(servletRequest, servletResponse); MDC.clear(); } diff --git a/backend/baton/src/main/java/touch/baton/domain/member/command/repository/SupporterRunnerPostCommandRepository.java b/backend/baton/src/main/java/touch/baton/domain/member/command/repository/SupporterRunnerPostCommandRepository.java index 1306d5a21..5400c2d9b 100644 --- a/backend/baton/src/main/java/touch/baton/domain/member/command/repository/SupporterRunnerPostCommandRepository.java +++ b/backend/baton/src/main/java/touch/baton/domain/member/command/repository/SupporterRunnerPostCommandRepository.java @@ -1,22 +1,10 @@ package touch.baton.domain.member.command.repository; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; import touch.baton.domain.member.command.SupporterRunnerPost; -import java.util.Optional; - public interface SupporterRunnerPostCommandRepository extends JpaRepository { - @Query(""" - select count(1) - from SupporterRunnerPost srp - group by srp.runnerPost.id - having srp.runnerPost.id = :runnerPostId - """) - Optional countByRunnerPostId(@Param("runnerPostId") final Long runnerPostId); - boolean existsByRunnerPostId(final Long runnerPostId); boolean existsByRunnerPostIdAndSupporterId(final Long runnerPostId, final Long supporterId); diff --git a/backend/baton/src/main/java/touch/baton/domain/member/query/repository/SupporterRunnerPostQueryRepository.java b/backend/baton/src/main/java/touch/baton/domain/member/query/repository/SupporterRunnerPostQueryRepository.java index 8daa47299..171f19605 100644 --- a/backend/baton/src/main/java/touch/baton/domain/member/query/repository/SupporterRunnerPostQueryRepository.java +++ b/backend/baton/src/main/java/touch/baton/domain/member/query/repository/SupporterRunnerPostQueryRepository.java @@ -10,14 +10,6 @@ public interface SupporterRunnerPostQueryRepository extends JpaRepository { - @Query(""" - select count(1) - from SupporterRunnerPost srp - group by srp.runnerPost.id - having srp.runnerPost.id in (:runnerPostIds) - """) - List countByRunnerPostIdIn(@Param("runnerPostIds") final List runnerPostIds); - @Query(""" select count(1) from SupporterRunnerPost srp @@ -26,20 +18,6 @@ select count(1) """) Optional countByRunnerPostId(@Param("runnerPostId") final Long runnerPostId); - @Query(""" - select case when exists ( - select 1 from SupporterRunnerPost srp - where srp.runnerPost.id = rp.id) - then ( - select count(srp.id) from SupporterRunnerPost srp - where srp.runnerPost.id = rp.id - ) else 0 end - from RunnerPost rp - where rp.id in :runnerPostIds - order by rp.id desc - """) - List countByRunnerPostIds(@Param("runnerPostIds") final List runnerPostIds); - @Query(""" select (count(1) >= 1) from SupporterRunnerPost srp @@ -49,11 +27,13 @@ select count(srp.id) from SupporterRunnerPost srp """) boolean existsByRunnerPostIdAndMemberId(@Param("runnerPostId") final Long runnerPostId, @Param("memberId") final Long memberId); - boolean existsByRunnerPostId(final Long runnerPostId); - - void deleteBySupporterIdAndRunnerPostId(final Long supporterId, final Long runnerPostId); - - boolean existsByRunnerPostIdAndSupporterId(final Long runnerPostId, final Long supporterId); - List readByRunnerPostId(final Long runnerPostId); + + @Query(""" + select count(1) + from SupporterRunnerPost srp + join fetch RunnerPost rp on rp.id = srp.runnerPost.id + where rp.reviewStatus = 'NOT_STARTED' and srp.supporter.id = :supporterId + """) + long countRunnerPostBySupporterIdByReviewStatusNotStarted(@Param("supporterId") final Long supporterId); } diff --git a/backend/baton/src/main/java/touch/baton/domain/runnerpost/command/service/RunnerPostCommandService.java b/backend/baton/src/main/java/touch/baton/domain/runnerpost/command/service/RunnerPostCommandService.java index 10a7c7873..6d6d2a292 100644 --- a/backend/baton/src/main/java/touch/baton/domain/runnerpost/command/service/RunnerPostCommandService.java +++ b/backend/baton/src/main/java/touch/baton/domain/runnerpost/command/service/RunnerPostCommandService.java @@ -107,8 +107,7 @@ public Long createRunnerPostApplicant(final Supporter supporter, final Long runnerPostId ) { final RunnerPost foundRunnerPost = getRunnerPostOrThrowException(runnerPostId); - final boolean isApplicantHistoryExist = supporterRunnerPostCommandRepository.existsByRunnerPostIdAndSupporterId(runnerPostId, supporter.getId()); - if (isApplicantHistoryExist) { + if (isApplySupporter(foundRunnerPost, supporter)) { throw new RunnerPostBusinessException("Supporter 는 이미 해당 RunnerPost 에 리뷰 신청을 한 이력이 있습니다."); } @@ -160,7 +159,7 @@ public void updateRunnerPostAppliedSupporter(final Runner runner, final RunnerPost foundRunnerPost = runnerPostCommandRepository.findById(runnerPostId) .orElseThrow(() -> new RunnerPostBusinessException("RunnerPost 의 식별자값으로 러너 게시글을 조회할 수 없습니다.")); - if (isApplySupporter(runnerPostId, foundApplySupporter)) { + if (!isApplySupporter(foundRunnerPost, foundApplySupporter)) { throw new RunnerPostBusinessException("게시글에 리뷰를 제안한 서포터가 아닙니다."); } if (foundRunnerPost.isNotOwner(runner)) { @@ -172,7 +171,7 @@ public void updateRunnerPostAppliedSupporter(final Runner runner, eventPublisher.publishEvent(new RunnerPostAssignSupporterEvent(foundRunnerPost.getId())); } - private boolean isApplySupporter(final Long runnerPostId, final Supporter foundSupporter) { - return !supporterRunnerPostCommandRepository.existsByRunnerPostIdAndSupporterId(runnerPostId, foundSupporter.getId()); + private boolean isApplySupporter(final RunnerPost runnerPost, final Supporter supporter) { + return supporterRunnerPostCommandRepository.existsByRunnerPostIdAndSupporterId(runnerPost.getId(), supporter.getId()); } } diff --git a/backend/baton/src/main/java/touch/baton/domain/runnerpost/query/controller/RunnerPostQueryController.java b/backend/baton/src/main/java/touch/baton/domain/runnerpost/query/controller/RunnerPostQueryController.java index de7021365..8b2e376cd 100644 --- a/backend/baton/src/main/java/touch/baton/domain/runnerpost/query/controller/RunnerPostQueryController.java +++ b/backend/baton/src/main/java/touch/baton/domain/runnerpost/query/controller/RunnerPostQueryController.java @@ -48,7 +48,7 @@ public ResponseEntity readByRunnerPostId( @PathVariable final Long runnerPostId ) { final RunnerPost foundRunnerPost = runnerPostQueryService.readByRunnerPostId(runnerPostId); - final long applicantCount = runnerPostQueryService.readCountByRunnerPostId(foundRunnerPost.getId()); + final long applicantCount = runnerPostQueryService.countApplicantsByRunnerPostId(foundRunnerPost.getId()); final boolean isApplicantHistoryExist = runnerPostQueryService.existsRunnerPostApplicantByRunnerPostIdAndMemberId(runnerPostId, member.getId()); runnerPostQueryService.increaseWatchedCount(foundRunnerPost); @@ -70,6 +70,14 @@ public ResponseEntity> readRunnerPostByS return ResponseEntity.ok(runnerPostQueryService.pageRunnerPostBySupporterIdAndReviewStatus(pageParams, supporterId, ReviewStatus.DONE)); } + @GetMapping("/search/count") + public ResponseEntity countRunnerPostBySupporterIdAndReviewStatusDone( + @RequestParam final Long supporterId + ) { + final long count = runnerPostQueryService.countRunnerPostBySupporterIdAndReviewStatus(supporterId, ReviewStatus.DONE); + return ResponseEntity.ok(RunnerPostResponse.Count.from(count)); + } + @GetMapping("/{runnerPostId}/supporters") public ResponseEntity readSupporterRunnerPostsByRunnerPostId( @AuthRunnerPrincipal final Runner runner, @@ -91,11 +99,30 @@ public ResponseEntity> readRunnerPostByL return ResponseEntity.ok(runnerPostQueryService.pageRunnerPostBySupporterIdAndReviewStatus(pageParams, supporter.getId(), reviewStatus)); } - @GetMapping("/me/runner") public ResponseEntity> readRunnerPostByLoginedRunnerAndReviewStatus( + @GetMapping("/me/runner") + public ResponseEntity> readRunnerPostByLoginedRunnerAndReviewStatus( @AuthRunnerPrincipal final Runner runner, @Valid @ModelAttribute final PageParams pageParams, @RequestParam(required = false) final ReviewStatus reviewStatus ) { return ResponseEntity.ok(runnerPostQueryService.pageRunnerPostByRunnerIdAndReviewStatus(pageParams, runner.getId(), reviewStatus)); } + + @GetMapping("/me/supporter/count") + public ResponseEntity countRunnerPostByLoginedSupporterAndReviewStatus( + @AuthSupporterPrincipal final Supporter supporter, + @RequestParam final ReviewStatus reviewStatus + ) { + final long runnerPostCount = runnerPostQueryService.countRunnerPostBySupporterIdAndReviewStatus(supporter.getId(), reviewStatus); + return ResponseEntity.ok(RunnerPostResponse.Count.from(runnerPostCount)); + } + + @GetMapping("/me/runner/count") + public ResponseEntity countRunnerPostByLoginedRunnerAndReviewStatus( + @AuthRunnerPrincipal final Runner runner, + @RequestParam final ReviewStatus reviewStatus + ) { + final long runnerPostCount = runnerPostQueryService.countRunnerPostByRunnerIdAndReviewStatus(runner.getId(), reviewStatus); + return ResponseEntity.ok(RunnerPostResponse.Count.from(runnerPostCount)); + } } diff --git a/backend/baton/src/main/java/touch/baton/domain/runnerpost/query/controller/response/RunnerPostResponse.java b/backend/baton/src/main/java/touch/baton/domain/runnerpost/query/controller/response/RunnerPostResponse.java index f3dfadbbf..b6be711c4 100644 --- a/backend/baton/src/main/java/touch/baton/domain/runnerpost/query/controller/response/RunnerPostResponse.java +++ b/backend/baton/src/main/java/touch/baton/domain/runnerpost/query/controller/response/RunnerPostResponse.java @@ -126,6 +126,13 @@ public Long extractId() { } } + public record Count(Long count) { + + public static Count from(final long count) { + return new Count(count); + } + } + private static List convertToTags(final RunnerPost runnerPost) { return runnerPost.getRunnerPostTags() .getRunnerPostTags() diff --git a/backend/baton/src/main/java/touch/baton/domain/runnerpost/query/repository/RunnerPostQueryRepository.java b/backend/baton/src/main/java/touch/baton/domain/runnerpost/query/repository/RunnerPostQueryRepository.java index caf078fb6..962577ca5 100644 --- a/backend/baton/src/main/java/touch/baton/domain/runnerpost/query/repository/RunnerPostQueryRepository.java +++ b/backend/baton/src/main/java/touch/baton/domain/runnerpost/query/repository/RunnerPostQueryRepository.java @@ -5,6 +5,7 @@ import org.springframework.data.repository.query.Param; import touch.baton.domain.runnerpost.command.RunnerPost; import touch.baton.domain.runnerpost.command.repository.dto.RunnerPostApplicantCountDto; +import touch.baton.domain.runnerpost.command.vo.ReviewStatus; import java.util.List; import java.util.Optional; @@ -39,4 +40,18 @@ public interface RunnerPostQueryRepository extends JpaRepository countApplicantsByRunnerPostIds(@Param("runnerPostIds") final List runnerPostIds); + + @Query(""" + select count(1) + from RunnerPost rp + where rp.runner.id = :runnerId and rp.reviewStatus = :reviewStatus + """) + long countByRunnerIdAndReviewStatus(@Param("runnerId") final Long runnerId, @Param("reviewStatus") final ReviewStatus reviewStatus); + + @Query(""" + select count(1) + from RunnerPost rp + where rp.supporter.id = :supporterId and rp.reviewStatus = :reviewStatus + """) + long countBySupporterIdAndReviewStatus(@Param("supporterId") final Long supporterId, @Param("reviewStatus") final ReviewStatus reviewStatus); } diff --git a/backend/baton/src/main/java/touch/baton/domain/runnerpost/query/service/RunnerPostQueryService.java b/backend/baton/src/main/java/touch/baton/domain/runnerpost/query/service/RunnerPostQueryService.java index ec7db06f7..e711fea85 100644 --- a/backend/baton/src/main/java/touch/baton/domain/runnerpost/query/service/RunnerPostQueryService.java +++ b/backend/baton/src/main/java/touch/baton/domain/runnerpost/query/service/RunnerPostQueryService.java @@ -114,10 +114,21 @@ public boolean existsRunnerPostApplicantByRunnerPostIdAndMemberId(final Long run return supporterRunnerPostQueryRepository.existsByRunnerPostIdAndMemberId(runnerPostId, memberId); } - public long readCountByRunnerPostId(final Long runnerPostId) { + public long countApplicantsByRunnerPostId(final Long runnerPostId) { return supporterRunnerPostQueryRepository.countByRunnerPostId(runnerPostId).orElse(0L); } + public long countRunnerPostByRunnerIdAndReviewStatus(final Long runnerId, final ReviewStatus reviewStatus) { + return runnerPostQueryRepository.countByRunnerIdAndReviewStatus(runnerId, reviewStatus); + } + + public long countRunnerPostBySupporterIdAndReviewStatus(final Long supporterId, final ReviewStatus reviewStatus) { + if (reviewStatus.isNotStarted()) { + return supporterRunnerPostQueryRepository.countRunnerPostBySupporterIdByReviewStatusNotStarted(supporterId); + } + return runnerPostQueryRepository.countBySupporterIdAndReviewStatus(supporterId, reviewStatus); + } + @Transactional public void increaseWatchedCount(final RunnerPost runnerPost) { runnerPost.increaseWatchedCount(); diff --git a/backend/baton/src/main/java/touch/baton/domain/tag/command/repository/TagCommandRepository.java b/backend/baton/src/main/java/touch/baton/domain/tag/command/repository/TagCommandRepository.java index e4d1e077d..187d4b72a 100644 --- a/backend/baton/src/main/java/touch/baton/domain/tag/command/repository/TagCommandRepository.java +++ b/backend/baton/src/main/java/touch/baton/domain/tag/command/repository/TagCommandRepository.java @@ -1,25 +1,12 @@ package touch.baton.domain.tag.command.repository; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; import touch.baton.domain.common.vo.TagName; import touch.baton.domain.tag.command.Tag; -import touch.baton.domain.tag.command.vo.TagReducedName; -import java.util.List; import java.util.Optional; public interface TagCommandRepository extends JpaRepository { Optional findByTagName(final TagName tagName); - - @Query(""" - select t - from Tag t - where t.tagReducedName like :tagReducedName% - order by t.tagReducedName asc - limit 10 - """) - List readTagsByReducedName(@Param("tagReducedName") TagReducedName tagReducedName); } diff --git a/backend/baton/src/main/java/touch/baton/domain/tag/query/controller/TagQueryController.java b/backend/baton/src/main/java/touch/baton/domain/tag/query/controller/TagQueryController.java index 32fd148d3..d94506f47 100644 --- a/backend/baton/src/main/java/touch/baton/domain/tag/query/controller/TagQueryController.java +++ b/backend/baton/src/main/java/touch/baton/domain/tag/query/controller/TagQueryController.java @@ -7,11 +7,11 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import touch.baton.domain.tag.query.controller.response.TagSearchResponse; +import touch.baton.domain.tag.command.Tag; +import touch.baton.domain.tag.command.vo.TagReducedName; import touch.baton.domain.tag.query.controller.response.TagSearchResponses; import touch.baton.domain.tag.query.service.TagQueryService; -import java.util.Collections; import java.util.List; @RequiredArgsConstructor @@ -23,14 +23,9 @@ public class TagQueryController { @GetMapping("/search") public ResponseEntity readTagsByTagName(@Nullable @RequestParam(required = false) final String tagName) { - if (tagName == null || tagName.isBlank()) { - return ResponseEntity.ok().body(TagSearchResponses.Detail.from(Collections.emptyList())); - } + final TagReducedName tagReducedName = TagReducedName.nullableInstance(tagName); + final List foundTags = tagQueryService.readTagsByReducedName(tagReducedName, 10); - final List tagSearchResponses = tagQueryService.readTagsByReducedName(tagName).stream() - .map(TagSearchResponse.TagResponse::from) - .toList(); - - return ResponseEntity.ok(TagSearchResponses.Detail.from(tagSearchResponses)); + return ResponseEntity.ok(TagSearchResponses.Detail.from(foundTags)); } } diff --git a/backend/baton/src/main/java/touch/baton/domain/tag/query/controller/response/TagSearchResponses.java b/backend/baton/src/main/java/touch/baton/domain/tag/query/controller/response/TagSearchResponses.java index f58871384..5bd9be9ba 100644 --- a/backend/baton/src/main/java/touch/baton/domain/tag/query/controller/response/TagSearchResponses.java +++ b/backend/baton/src/main/java/touch/baton/domain/tag/query/controller/response/TagSearchResponses.java @@ -1,12 +1,19 @@ package touch.baton.domain.tag.query.controller.response; +import touch.baton.domain.tag.command.Tag; + import java.util.List; public record TagSearchResponses() { public record Detail(List data) { - public static Detail from(final List data) { - return new Detail(data); + + public static Detail from(final List tags) { + final List response = tags.stream() + .map(TagSearchResponse.TagResponse::from) + .toList(); + + return new Detail(response); } } } diff --git a/backend/baton/src/main/java/touch/baton/domain/tag/query/repository/TagQueryRepository.java b/backend/baton/src/main/java/touch/baton/domain/tag/query/repository/TagQueryRepository.java deleted file mode 100644 index eb01a4a7c..000000000 --- a/backend/baton/src/main/java/touch/baton/domain/tag/query/repository/TagQueryRepository.java +++ /dev/null @@ -1,25 +0,0 @@ -package touch.baton.domain.tag.query.repository; - -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; -import touch.baton.domain.common.vo.TagName; -import touch.baton.domain.tag.command.Tag; -import touch.baton.domain.tag.command.vo.TagReducedName; - -import java.util.List; -import java.util.Optional; - -public interface TagQueryRepository extends JpaRepository { - - Optional findByTagName(final TagName tagName); - - @Query(""" - select t - from Tag t - where t.tagReducedName like :tagReducedName% - order by t.tagReducedName asc - limit 10 - """) - List readTagsByReducedName(@Param("tagReducedName") final TagReducedName tagReducedName); -} diff --git a/backend/baton/src/main/java/touch/baton/domain/tag/query/repository/TagQuerydslRepository.java b/backend/baton/src/main/java/touch/baton/domain/tag/query/repository/TagQuerydslRepository.java new file mode 100644 index 000000000..d1e74cd8b --- /dev/null +++ b/backend/baton/src/main/java/touch/baton/domain/tag/query/repository/TagQuerydslRepository.java @@ -0,0 +1,26 @@ +package touch.baton.domain.tag.query.repository; + +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; +import touch.baton.domain.tag.command.Tag; +import touch.baton.domain.tag.command.vo.TagReducedName; + +import java.util.List; + +import static touch.baton.domain.tag.command.QTag.tag; + +@RequiredArgsConstructor +@Repository +public class TagQuerydslRepository { + + private final JPAQueryFactory queryFactory; + + public List findByTagReducedName(final TagReducedName tagReducedName, final int limit) { + return queryFactory.selectFrom(tag) + .where(tag.tagReducedName.value.startsWith(tagReducedName.getValue())) + .orderBy(tag.tagReducedName.value.asc(), tag.tagName.value.desc()) + .limit(limit) + .fetch(); + } +} diff --git a/backend/baton/src/main/java/touch/baton/domain/tag/query/service/TagQueryService.java b/backend/baton/src/main/java/touch/baton/domain/tag/query/service/TagQueryService.java index bb624ebd8..1fcee1ae1 100644 --- a/backend/baton/src/main/java/touch/baton/domain/tag/query/service/TagQueryService.java +++ b/backend/baton/src/main/java/touch/baton/domain/tag/query/service/TagQueryService.java @@ -5,8 +5,9 @@ import org.springframework.transaction.annotation.Transactional; import touch.baton.domain.tag.command.Tag; import touch.baton.domain.tag.command.vo.TagReducedName; -import touch.baton.domain.tag.query.repository.TagQueryRepository; +import touch.baton.domain.tag.query.repository.TagQuerydslRepository; +import java.util.Collections; import java.util.List; @RequiredArgsConstructor @@ -14,9 +15,13 @@ @Service public class TagQueryService { - private final TagQueryRepository tagQueryRepository; + private final TagQuerydslRepository tagQuerydslRepository; - public List readTagsByReducedName(final String tagName) { - return tagQueryRepository.readTagsByReducedName(TagReducedName.from(tagName)); + public List readTagsByReducedName(final TagReducedName tagReducedName, final int limit) { + if (tagReducedName == null || tagReducedName.getValue().isBlank()) { + return Collections.emptyList(); + } + + return tagQuerydslRepository.findByTagReducedName(tagReducedName, limit); } } diff --git a/backend/baton/src/main/resources/db/migration/V20231007_1__create_table_notification.sql b/backend/baton/src/main/resources/db/migration/V20231007_1__create_table_notification.sql index 2519d24f1..1015c6727 100644 --- a/backend/baton/src/main/resources/db/migration/V20231007_1__create_table_notification.sql +++ b/backend/baton/src/main/resources/db/migration/V20231007_1__create_table_notification.sql @@ -9,5 +9,5 @@ CREATE TABLE notification member_id BIGINT NOT NULL, created_at DATETIME(6) NOT NULL, updated_at DATETIME(6) NOT NULL, - deleted_at DATETIME(6), + deleted_at DATETIME(6) ); diff --git a/backend/baton/src/main/resources/db/migration/V20231011__create_review_status_index_on_runner_post.sql b/backend/baton/src/main/resources/db/migration/V20231011__create_review_status_index_on_runner_post.sql new file mode 100644 index 000000000..05fbc5f41 --- /dev/null +++ b/backend/baton/src/main/resources/db/migration/V20231011__create_review_status_index_on_runner_post.sql @@ -0,0 +1,2 @@ +create index idx_runner_post_review_status on runner_post (review_status); + diff --git a/backend/baton/src/test/java/touch/baton/assure/repository/TestSupporterRunnerPostQueryRepository.java b/backend/baton/src/test/java/touch/baton/assure/repository/TestSupporterRunnerPostQueryRepository.java index 376789f1d..a77e69712 100644 --- a/backend/baton/src/test/java/touch/baton/assure/repository/TestSupporterRunnerPostQueryRepository.java +++ b/backend/baton/src/test/java/touch/baton/assure/repository/TestSupporterRunnerPostQueryRepository.java @@ -4,7 +4,6 @@ import touch.baton.domain.member.query.repository.SupporterRunnerPostQueryRepository; @Profile("test") - public interface TestSupporterRunnerPostQueryRepository extends SupporterRunnerPostQueryRepository { default Long getApplicantCountByRunnerPostId(final Long runnerPostId) { diff --git a/backend/baton/src/test/java/touch/baton/assure/repository/TestTagQueryRepository.java b/backend/baton/src/test/java/touch/baton/assure/repository/TestTagQueryRepository.java deleted file mode 100644 index b67ad4b15..000000000 --- a/backend/baton/src/test/java/touch/baton/assure/repository/TestTagQueryRepository.java +++ /dev/null @@ -1,6 +0,0 @@ -package touch.baton.assure.repository; - -import touch.baton.domain.tag.query.repository.TagQueryRepository; - -public interface TestTagQueryRepository extends TagQueryRepository { -} diff --git a/backend/baton/src/test/java/touch/baton/assure/repository/TestTagQuerydslRepository.java b/backend/baton/src/test/java/touch/baton/assure/repository/TestTagQuerydslRepository.java new file mode 100644 index 000000000..d1f557b8f --- /dev/null +++ b/backend/baton/src/test/java/touch/baton/assure/repository/TestTagQuerydslRepository.java @@ -0,0 +1,13 @@ +package touch.baton.assure.repository; + +import com.querydsl.jpa.impl.JPAQueryFactory; +import org.springframework.stereotype.Repository; +import touch.baton.domain.tag.query.repository.TagQuerydslRepository; + +@Repository +public class TestTagQuerydslRepository extends TagQuerydslRepository { + + public TestTagQuerydslRepository(final JPAQueryFactory queryFactory) { + super(queryFactory); + } +} diff --git a/backend/baton/src/test/java/touch/baton/assure/runnerpost/query/count/runner/RunnerPostCountByRunnerAssuredTest.java b/backend/baton/src/test/java/touch/baton/assure/runnerpost/query/count/runner/RunnerPostCountByRunnerAssuredTest.java new file mode 100644 index 000000000..183eba4f8 --- /dev/null +++ b/backend/baton/src/test/java/touch/baton/assure/runnerpost/query/count/runner/RunnerPostCountByRunnerAssuredTest.java @@ -0,0 +1,60 @@ +package touch.baton.assure.runnerpost.query.count.runner; + +import org.junit.jupiter.api.Test; +import touch.baton.assure.runnerpost.support.command.RunnerPostCreateSupport; +import touch.baton.assure.runnerpost.support.query.count.runner.RunnerPostCountByRunnerSupport; +import touch.baton.config.AssuredTestConfig; +import touch.baton.config.infra.auth.oauth.authcode.FakeAuthCodes; +import touch.baton.domain.runnerpost.command.vo.ReviewStatus; +import touch.baton.domain.runnerpost.query.controller.response.RunnerPostResponse; + +import java.time.LocalDateTime; +import java.util.List; + +import static touch.baton.assure.runnerpost.support.command.RunnerPostCreateSupport.러너_게시글_생성_요청; +import static touch.baton.assure.runnerpost.support.query.count.runner.RunnerPostCountByRunnerSupport.러너_게시글_개수_응답; + +@SuppressWarnings("NonAsciiCharacters") +class RunnerPostCountByRunnerAssuredTest extends AssuredTestConfig { + + @Test + void 로그인한_러너와_연관된_러너_게시글_개수_조회에_성공한다() { + // given + final String 디투_액세스_토큰 = oauthLoginTestManager.소셜_회원가입을_진행한_후_액세스_토큰을_반환한다(FakeAuthCodes.ditooAuthCode()); + final String 헤나_액세스_토큰 = oauthLoginTestManager.소셜_회원가입을_진행한_후_액세스_토큰을_반환한다(FakeAuthCodes.hyenaAuthCode()); + 러너_게시글_생성에_성공한다(디투_액세스_토큰); + 러너_게시글_생성에_성공한다(헤나_액세스_토큰); + + // when + final RunnerPostResponse.Count 기대된_러너_게시글_개수 = 러너_게시글_개수_응답(1); + + // then + RunnerPostCountByRunnerSupport + .클라이언트_요청() + .액세스_토큰으로_로그인한다(디투_액세스_토큰) + .리뷰_상태로_로그인한_러너와_연관된_러너_게시글_개수를_조회한다(ReviewStatus.NOT_STARTED) + + .서버_응답() + .로그인한_러너와_연관된_러너_게시글_개수_조회_성공을_검증한다(기대된_러너_게시글_개수); + } + + private void 러너_게시글_생성에_성공한다(final String 액세스_토큰) { + RunnerPostCreateSupport + .클라이언트_요청() + .액세스_토큰으로_로그인한다(액세스_토큰) + .러너_게시글_등록_요청한다( + 러너_게시글_생성_요청( + "테스트용_러너_게시글_제목", + List.of("자바", "스프링"), + "https://test-pull-request.com", + LocalDateTime.now().plusHours(100), + "테스트용_러너_게시글_구현_내용", + "테스트용_러너_게시글_궁금한_내용", + "테스트용_러너_게시글_참고_사항" + ) + ) + + .서버_응답() + .러너_게시글_생성_성공을_검증한다(); + } +} diff --git a/backend/baton/src/test/java/touch/baton/assure/runnerpost/query/count/supporter/RunnerPostCountBySupporterAssuredTest.java b/backend/baton/src/test/java/touch/baton/assure/runnerpost/query/count/supporter/RunnerPostCountBySupporterAssuredTest.java new file mode 100644 index 000000000..94ee83049 --- /dev/null +++ b/backend/baton/src/test/java/touch/baton/assure/runnerpost/query/count/supporter/RunnerPostCountBySupporterAssuredTest.java @@ -0,0 +1,188 @@ +package touch.baton.assure.runnerpost.query.count.supporter; + +import org.junit.jupiter.api.Test; +import org.springframework.http.HttpStatus; +import touch.baton.assure.common.HttpStatusAndLocationHeader; +import touch.baton.assure.runnerpost.support.command.RunnerPostCreateSupport; +import touch.baton.assure.runnerpost.support.command.RunnerPostUpdateSupport; +import touch.baton.assure.runnerpost.support.query.count.supporter.RunnerPostCountBySupporterSupport; +import touch.baton.config.AssuredTestConfig; +import touch.baton.config.infra.auth.oauth.authcode.FakeAuthCodes; +import touch.baton.domain.member.command.Supporter; +import touch.baton.domain.member.command.vo.SocialId; +import touch.baton.domain.runnerpost.command.vo.ReviewStatus; +import touch.baton.domain.runnerpost.query.controller.response.RunnerPostResponse; + +import java.time.LocalDateTime; +import java.util.List; + +import static touch.baton.assure.runnerpost.support.command.RunnerPostCreateSupport.러너_게시글_생성_요청; +import static touch.baton.assure.runnerpost.support.command.applicant.RunnerPostApplicantCreateSupport.러너의_서포터_선택_요청; +import static touch.baton.assure.runnerpost.support.command.applicant.RunnerPostApplicantCreateSupport.클라이언트_요청; +import static touch.baton.assure.runnerpost.support.query.count.supporter.RunnerPostCountBySupporterSupport.러너_게시글_개수_응답; + +@SuppressWarnings("NonAsciiCharacters") + class RunnerPostCountBySupporterAssuredTest extends AssuredTestConfig { + + @Test + void 로그인한_서포터가_지원했으면서_아직_시작하지_않은_러너_게시글_개수_조회에_성공한다() { + // given + final String 디투_액세스_토큰 = oauthLoginTestManager.소셜_회원가입을_진행한_후_액세스_토큰을_반환한다(FakeAuthCodes.ditooAuthCode()); + final String 헤나_액세스_토큰 = oauthLoginTestManager.소셜_회원가입을_진행한_후_액세스_토큰을_반환한다(FakeAuthCodes.hyenaAuthCode()); + final String 서포터_에단_액세스_토큰 = oauthLoginTestManager.소셜_회원가입을_진행한_후_액세스_토큰을_반환한다(FakeAuthCodes.ethanAuthCode()); + final Long 디투_러너_게시글_식별자_값 = 러너_게시글_생성을_성공하고_러너_게시글_식별자값을_반환한다(디투_액세스_토큰); + + 러너_게시글_생성을_성공하고_러너_게시글_식별자값을_반환한다(헤나_액세스_토큰); + + 서포터가_러너_게시글에_리뷰_신청을_성공한다(서포터_에단_액세스_토큰, 디투_러너_게시글_식별자_값); + + // when + final RunnerPostResponse.Count 기대된_러너_게시글_개수 = 러너_게시글_개수_응답(1); + + // then + RunnerPostCountBySupporterSupport + .클라이언트_요청() + .액세스_토큰으로_로그인한다(서포터_에단_액세스_토큰) + .리뷰_상태로_로그인한_서포터와_연관된_러너_게시글_개수를_조회한다(ReviewStatus.NOT_STARTED) + + .서버_응답() + .서포터와_연관된_러너_게시글_개수_조회_성공을_검증한다(기대된_러너_게시글_개수); + } + + @Test + void 로그인한_서포터가_리뷰_중인_러너_게시글_개수_조회에_성공한다() { + // given + final String 디투_액세스_토큰 = oauthLoginTestManager.소셜_회원가입을_진행한_후_액세스_토큰을_반환한다(FakeAuthCodes.ditooAuthCode()); + final String 헤나_액세스_토큰 = oauthLoginTestManager.소셜_회원가입을_진행한_후_액세스_토큰을_반환한다(FakeAuthCodes.hyenaAuthCode()); + final String 서포터_에단_액세스_토큰 = oauthLoginTestManager.소셜_회원가입을_진행한_후_액세스_토큰을_반환한다(FakeAuthCodes.ethanAuthCode()); + final SocialId 서포터_에단_소셜_아이디 = jwtTestManager.parseToSocialId(서포터_에단_액세스_토큰); + final Supporter 서포터_에단 = supporterRepository.getBySocialId(서포터_에단_소셜_아이디); + + final Long 디투_러너_게시글_식별자_값 = 러너_게시글_생성을_성공하고_러너_게시글_식별자값을_반환한다(디투_액세스_토큰); + final Long 헤나_러너_게시글_식별자_값 = 러너_게시글_생성을_성공하고_러너_게시글_식별자값을_반환한다(헤나_액세스_토큰); + + 서포터가_러너_게시글에_리뷰_신청을_성공한다(서포터_에단_액세스_토큰, 헤나_러너_게시글_식별자_값); + + 서포터가_러너_게시글에_리뷰_신청을_성공한다(서포터_에단_액세스_토큰, 디투_러너_게시글_식별자_값); + 러너가_서포터의_리뷰_신청_선택에_성공한다(서포터_에단, 디투_액세스_토큰, 디투_러너_게시글_식별자_값); + + // when + final RunnerPostResponse.Count 기대된_러너_게시글_개수 = 러너_게시글_개수_응답(1); + + // then + RunnerPostCountBySupporterSupport + .클라이언트_요청() + .액세스_토큰으로_로그인한다(서포터_에단_액세스_토큰) + .리뷰_상태로_로그인한_서포터와_연관된_러너_게시글_개수를_조회한다(ReviewStatus.IN_PROGRESS) + + .서버_응답() + .서포터와_연관된_러너_게시글_개수_조회_성공을_검증한다(기대된_러너_게시글_개수); + } + + @Test + void 로그인한_서포터가_완료한_러너_게시글_개수_조회에_성공한다() { + // given + final String 디투_액세스_토큰 = oauthLoginTestManager.소셜_회원가입을_진행한_후_액세스_토큰을_반환한다(FakeAuthCodes.ditooAuthCode()); + final String 헤나_액세스_토큰 = oauthLoginTestManager.소셜_회원가입을_진행한_후_액세스_토큰을_반환한다(FakeAuthCodes.hyenaAuthCode()); + final String 서포터_에단_액세스_토큰 = oauthLoginTestManager.소셜_회원가입을_진행한_후_액세스_토큰을_반환한다(FakeAuthCodes.ethanAuthCode()); + final SocialId 서포터_에단_소셜_아이디 = jwtTestManager.parseToSocialId(서포터_에단_액세스_토큰); + final Supporter 서포터_에단 = supporterRepository.getBySocialId(서포터_에단_소셜_아이디); + + final Long 디투_러너_게시글_식별자_값 = 러너_게시글_생성을_성공하고_러너_게시글_식별자값을_반환한다(디투_액세스_토큰); + final Long 헤나_러너_게시글_식별자_값 = 러너_게시글_생성을_성공하고_러너_게시글_식별자값을_반환한다(헤나_액세스_토큰); + + 서포터가_러너_게시글에_리뷰_신청을_성공한다(서포터_에단_액세스_토큰, 헤나_러너_게시글_식별자_값); + + 서포터가_러너_게시글에_리뷰_신청을_성공한다(서포터_에단_액세스_토큰, 디투_러너_게시글_식별자_값); + 러너가_서포터의_리뷰_신청_선택에_성공한다(서포터_에단, 디투_액세스_토큰, 디투_러너_게시글_식별자_값); + 서포터가_러너_게시글의_리뷰를_완료로_변경하는_것을_성공한다(서포터_에단_액세스_토큰, 디투_러너_게시글_식별자_값); + + // when + final RunnerPostResponse.Count 기대된_러너_게시글_개수 = 러너_게시글_개수_응답(1); + + // then + RunnerPostCountBySupporterSupport + .클라이언트_요청() + .액세스_토큰으로_로그인한다(서포터_에단_액세스_토큰) + .리뷰_상태로_로그인한_서포터와_연관된_러너_게시글_개수를_조회한다(ReviewStatus.DONE) + + .서버_응답() + .서포터와_연관된_러너_게시글_개수_조회_성공을_검증한다(기대된_러너_게시글_개수); + } + + @Test + void 타인이_서포터가_완료한_러너_게시글_개수_조회에_성공한다() { + // given + final String 러너_액세스_토큰 = oauthLoginTestManager.소셜_회원가입을_진행한_후_액세스_토큰을_반환한다(FakeAuthCodes.ditooAuthCode()); + final String 서포터_액세스_토큰 = oauthLoginTestManager.소셜_회원가입을_진행한_후_액세스_토큰을_반환한다(FakeAuthCodes.ethanAuthCode()); + final SocialId 서포터_소셜_아이디 = jwtTestManager.parseToSocialId(서포터_액세스_토큰); + final Supporter 서포터 = supporterRepository.getBySocialId(서포터_소셜_아이디); + + final Long 러너_게시글_식별자_값 = 러너_게시글_생성을_성공하고_러너_게시글_식별자값을_반환한다(러너_액세스_토큰); + + 서포터가_러너_게시글에_리뷰_신청을_성공한다(서포터_액세스_토큰, 러너_게시글_식별자_값); + 러너가_서포터의_리뷰_신청_선택에_성공한다(서포터, 러너_액세스_토큰, 러너_게시글_식별자_값); + 서포터가_러너_게시글의_리뷰를_완료로_변경하는_것을_성공한다(서포터_액세스_토큰, 러너_게시글_식별자_값); + + // when + final RunnerPostResponse.Count 기대된_러너_게시글_개수 = 러너_게시글_개수_응답(1); + + // then + RunnerPostCountBySupporterSupport + .클라이언트_요청() + .서포터_식별자_값으로_서포터가_완료한_러너_게시글_개수를_조회한다(서포터.getId()) + + .서버_응답() + .서포터와_연관된_러너_게시글_개수_조회_성공을_검증한다(기대된_러너_게시글_개수); + } + + private Long 러너_게시글_생성을_성공하고_러너_게시글_식별자값을_반환한다(final String 러너_액세스_토큰) { + return RunnerPostCreateSupport + .클라이언트_요청() + .액세스_토큰으로_로그인한다(러너_액세스_토큰) + .러너_게시글_등록_요청한다( + 러너_게시글_생성_요청( + "테스트용_러너_게시글_제목", + List.of("자바", "스프링"), + "https://test-pull-request.com", + LocalDateTime.now().plusHours(100), + "테스트용_러너_게시글_구현_내용", + "테스트용_러너_게시글_궁금한_내용", + "테스트용_러너_게시글_참고_사항" + ) + ) + + .서버_응답() + .러너_게시글_생성_성공을_검증한다() + .생성한_러너_게시글의_식별자값을_반환한다(); + } + + private void 서포터가_러너_게시글에_리뷰_신청을_성공한다(final String 서포터_액세스_토큰, final Long 러너_게시글_식별자값) { + 클라이언트_요청() + .액세스_토큰으로_로그인한다(서포터_액세스_토큰) + .서포터가_러너_게시글에_리뷰를_신청한다(러너_게시글_식별자값, "안녕하세요. 서포터 헤나입니다.") + + .서버_응답() + .서포터가_러너_게시글에_리뷰_신청_성공을_검증한다(러너_게시글_식별자값); + } + + private void 러너가_서포터의_리뷰_신청_선택에_성공한다(final Supporter 서포터, final String 러너_액세스_토큰, final Long 러너_게시글_식별자값) { + RunnerPostUpdateSupport + .클라이언트_요청() + .액세스_토큰으로_로그인한다(러너_액세스_토큰) + .러너가_서포터를_선택한다(러너_게시글_식별자값, 러너의_서포터_선택_요청(서포터.getId())) + + .서버_응답() + .러너_게시글에_서포터가_성공적으로_선택되었는지_확인한다(new HttpStatusAndLocationHeader(HttpStatus.NO_CONTENT, "/api/v1/posts/runner")); + } + + private void 서포터가_러너_게시글의_리뷰를_완료로_변경하는_것을_성공한다(final String 서포터_액세스_토큰, final Long 러너_게시글_식별자값) { + RunnerPostUpdateSupport + .클라이언트_요청() + .액세스_토큰으로_로그인한다(서포터_액세스_토큰) + .서포터가_리뷰를_완료하고_리뷰완료_버튼을_누른다(러너_게시글_식별자값) + + .서버_응답() + .러너_게시글이_성공적으로_리뷰_완료_상태인지_확인한다(new HttpStatusAndLocationHeader(HttpStatus.NO_CONTENT, "/api/v1/posts/runner")); + } +} diff --git a/backend/baton/src/test/java/touch/baton/assure/runnerpost/support/query/count/runner/RunnerPostCountByRunnerSupport.java b/backend/baton/src/test/java/touch/baton/assure/runnerpost/support/query/count/runner/RunnerPostCountByRunnerSupport.java new file mode 100644 index 000000000..3f2dbaedc --- /dev/null +++ b/backend/baton/src/test/java/touch/baton/assure/runnerpost/support/query/count/runner/RunnerPostCountByRunnerSupport.java @@ -0,0 +1,68 @@ +package touch.baton.assure.runnerpost.support.query.count.runner; + +import io.restassured.response.ExtractableResponse; +import io.restassured.response.Response; +import org.springframework.http.HttpStatus; +import touch.baton.assure.common.AssuredSupport; +import touch.baton.assure.common.QueryParams; +import touch.baton.domain.runnerpost.command.vo.ReviewStatus; +import touch.baton.domain.runnerpost.query.controller.response.RunnerPostResponse; + +import java.util.Map; + +import static org.assertj.core.api.SoftAssertions.assertSoftly; + +@SuppressWarnings("NonAsciiCharacters") +public class RunnerPostCountByRunnerSupport { + + private RunnerPostCountByRunnerSupport() { + } + + public static RunnerPostCountByRunnerBuilder 클라이언트_요청() { + return new RunnerPostCountByRunnerBuilder(); + } + + public static RunnerPostResponse.Count 러너_게시글_개수_응답(final long 게시글_개수) { + return new RunnerPostResponse.Count(게시글_개수); + } + + public static class RunnerPostCountByRunnerBuilder { + + private ExtractableResponse response; + + private String accessToken; + + public RunnerPostCountByRunnerBuilder 액세스_토큰으로_로그인한다(final String 액세스_토큰) { + this.accessToken = 액세스_토큰; + return this; + } + + public RunnerPostCountByRunnerBuilder 리뷰_상태로_로그인한_러너와_연관된_러너_게시글_개수를_조회한다(final ReviewStatus 리뷰_상태) { + final Map queryParams = Map.of("reviewStatus", 리뷰_상태); + + response = AssuredSupport.get("/api/v1/posts/runner/me/runner/count", accessToken, new QueryParams(queryParams)); + return this; + } + + public RunnerPostCountByRunnerResponseBuilder 서버_응답() { + return new RunnerPostCountByRunnerResponseBuilder(response); + } + } + + public static class RunnerPostCountByRunnerResponseBuilder { + + private final ExtractableResponse response; + + public RunnerPostCountByRunnerResponseBuilder(final ExtractableResponse response) { + this.response = response; + } + + public void 로그인한_러너와_연관된_러너_게시글_개수_조회_성공을_검증한다(final RunnerPostResponse.Count 러너_게시글_개수_응답) { + final RunnerPostResponse.Count actual = this.response.as(RunnerPostResponse.Count.class); + assertSoftly(softly -> { + softly.assertThat(this.response.statusCode()).isEqualTo(HttpStatus.OK.value()); + softly.assertThat(actual).isEqualTo(러너_게시글_개수_응답); + }); + } + } +} diff --git a/backend/baton/src/test/java/touch/baton/assure/runnerpost/support/query/count/supporter/RunnerPostCountBySupporterSupport.java b/backend/baton/src/test/java/touch/baton/assure/runnerpost/support/query/count/supporter/RunnerPostCountBySupporterSupport.java new file mode 100644 index 000000000..20c4cf08b --- /dev/null +++ b/backend/baton/src/test/java/touch/baton/assure/runnerpost/support/query/count/supporter/RunnerPostCountBySupporterSupport.java @@ -0,0 +1,78 @@ +package touch.baton.assure.runnerpost.support.query.count.supporter; + +import io.restassured.response.ExtractableResponse; +import io.restassured.response.Response; +import org.springframework.http.HttpStatus; +import touch.baton.assure.common.AssuredSupport; +import touch.baton.assure.common.QueryParams; +import touch.baton.domain.runnerpost.command.vo.ReviewStatus; +import touch.baton.domain.runnerpost.query.controller.response.RunnerPostResponse; + +import java.util.Map; + +import static org.assertj.core.api.SoftAssertions.assertSoftly; + +@SuppressWarnings("NonAsciiCharacters") +public class RunnerPostCountBySupporterSupport { + + private RunnerPostCountBySupporterSupport() { + } + + public static RunnerPostCountBySupporterBuilder 클라이언트_요청() { + return new RunnerPostCountBySupporterBuilder(); + } + + public static RunnerPostResponse.Count 러너_게시글_개수_응답(final long 게시글_개수) { + return new RunnerPostResponse.Count(게시글_개수); + } + + public static class RunnerPostCountBySupporterBuilder { + + private ExtractableResponse response; + + private String accessToken; + + public RunnerPostCountBySupporterBuilder 액세스_토큰으로_로그인한다(final String 액세스_토큰) { + this.accessToken = 액세스_토큰; + return this; + } + + public RunnerPostCountBySupporterBuilder 리뷰_상태로_로그인한_서포터와_연관된_러너_게시글_개수를_조회한다(final ReviewStatus 리뷰_상태) { + final Map queryParams = Map.of("reviewStatus", 리뷰_상태); + + response = AssuredSupport.get("/api/v1/posts/runner/me/supporter/count", accessToken, new QueryParams(queryParams)); + return this; + } + + public RunnerPostCountBySupporterBuilder 서포터_식별자_값으로_서포터가_완료한_러너_게시글_개수를_조회한다(final Long 서포터_식별자_값) { + final Map queryParams = Map.of( + "reviewStatus", ReviewStatus.DONE, + "supporterId", 서포터_식별자_값 + ); + + response = AssuredSupport.get("/api/v1/posts/runner/search/count", new QueryParams(queryParams)); + return this; + } + + public RunnerPostCountBySupporterResponseBuilder 서버_응답() { + return new RunnerPostCountBySupporterResponseBuilder(response); + } + } + + public static class RunnerPostCountBySupporterResponseBuilder { + + private final ExtractableResponse response; + + public RunnerPostCountBySupporterResponseBuilder(final ExtractableResponse response) { + this.response = response; + } + + public void 서포터와_연관된_러너_게시글_개수_조회_성공을_검증한다(final RunnerPostResponse.Count 러너_게시글_개수_응답) { + final RunnerPostResponse.Count actual = this.response.as(RunnerPostResponse.Count.class); + assertSoftly(softly -> { + softly.assertThat(this.response.statusCode()).isEqualTo(HttpStatus.OK.value()); + softly.assertThat(actual).isEqualTo(러너_게시글_개수_응답); + }); + } + } +} diff --git a/backend/baton/src/test/java/touch/baton/assure/tag/query/TagReadAssuredTest.java b/backend/baton/src/test/java/touch/baton/assure/tag/query/TagReadAssuredTest.java index 12ba0db56..e491a3c53 100644 --- a/backend/baton/src/test/java/touch/baton/assure/tag/query/TagReadAssuredTest.java +++ b/backend/baton/src/test/java/touch/baton/assure/tag/query/TagReadAssuredTest.java @@ -2,57 +2,56 @@ import org.junit.jupiter.api.Test; import touch.baton.assure.runnerpost.support.command.RunnerPostCreateSupport; -import touch.baton.assure.tag.support.query.TagAssuredSupport; +import touch.baton.assure.tag.support.query.TagQuerySupport; import touch.baton.config.AssuredTestConfig; import touch.baton.config.infra.auth.oauth.authcode.FakeAuthCodes; import touch.baton.domain.tag.command.Tag; import touch.baton.domain.tag.command.vo.TagReducedName; +import touch.baton.domain.tag.query.controller.response.TagSearchResponses; import java.time.LocalDateTime; import java.util.List; import static touch.baton.assure.runnerpost.support.command.RunnerPostCreateSupport.러너_게시글_생성_요청; -import static touch.baton.assure.tag.support.query.TagAssuredSupport.태그_검색_Detail_응답; @SuppressWarnings("NonAsciiCharacters") class TagReadAssuredTest extends AssuredTestConfig { @Test - void 태그_검색에_성공한다() { + void 입력된_문자열로_태그_목록_검색에_성공한다() { // given final String 헤나_액세스_토큰 = oauthLoginTestManager.소셜_회원가입을_진행한_후_액세스_토큰을_반환한다(FakeAuthCodes.hyenaAuthCode()); - 러너_게시글_생성을_성공하고_러너_게시글_식별자값을_반환한다(헤나_액세스_토큰, List.of("java", "javascript", "script")); - final TagReducedName reducedName = TagReducedName.from("ja"); - final List 검색된_태그_목록 = tagRepository.readTagsByReducedName(reducedName); + 러너_게시글과_태그를_생성한다(헤나_액세스_토큰, List.of("java", "javascript", "script")); + + final TagReducedName 요청할_태그_이름 = TagReducedName.nullableInstance("ja"); // when, then - TagAssuredSupport + final List 검색된_태그_목록 = tagQueryRepository.findByTagReducedName(요청할_태그_이름, 10); + + TagQuerySupport .클라이언트_요청() - .액세스_토큰으로_로그인한다(헤나_액세스_토큰) - .태그_이름을_오름차순으로_10개_검색한다("ja") + .입력된_문자열로_태그_목록을_검색한다(요청할_태그_이름) .서버_응답() - .태그_검색_성공을_검증한다( - 태그_검색_Detail_응답(검색된_태그_목록) + .입력된_문자열로_태그_목록_검색_성공을_검증한다( + TagSearchResponses.Detail.from(검색된_태그_목록) ); } - private void 러너_게시글_생성을_성공하고_러너_게시글_식별자값을_반환한다(final String 헤나_액세스_토큰, final List 태그_목록) { + private void 러너_게시글과_태그를_생성한다(final String 액세스_토큰, final List 태그_목록) { RunnerPostCreateSupport .클라이언트_요청() - .액세스_토큰으로_로그인한다(헤나_액세스_토큰) - .러너_게시글_등록_요청한다( - 러너_게시글_생성_요청( - "테스트용_러너_게시글_제목", - 태그_목록, - "https://test-pull-request.com", - LocalDateTime.now().plusHours(100), - "테스트용_러너_게시글_구현_내용", - "테스트용_러너_게시글_궁금한_내용", - "테스트용_러너_게시글_참고_사항" - ) - ) + .액세스_토큰으로_로그인한다(액세스_토큰) + .러너_게시글_등록_요청한다(러너_게시글_생성_요청( + "테스트용_러너_게시글_제목", + 태그_목록, + "https://test-pull-request.com", + LocalDateTime.now().plusHours(100), + "테스트용_러너_게시글_구현_내용", + "테스트용_러너_게시글_궁금한_내용", + "테스트용_러너_게시글_참고_사항" + )) .서버_응답() .러너_게시글_생성_성공을_검증한다(); diff --git a/backend/baton/src/test/java/touch/baton/assure/tag/support/query/TagAssuredSupport.java b/backend/baton/src/test/java/touch/baton/assure/tag/support/query/TagAssuredSupport.java deleted file mode 100644 index ef774f0c7..000000000 --- a/backend/baton/src/test/java/touch/baton/assure/tag/support/query/TagAssuredSupport.java +++ /dev/null @@ -1,85 +0,0 @@ -package touch.baton.assure.tag.support.query; - -import io.restassured.common.mapper.TypeRef; -import io.restassured.response.ExtractableResponse; -import io.restassured.response.Response; -import org.springframework.http.HttpStatus; -import touch.baton.assure.common.AssuredSupport; -import touch.baton.assure.common.QueryParams; -import touch.baton.domain.runnerpost.command.service.dto.RunnerPostCreateRequest; -import touch.baton.domain.tag.command.Tag; -import touch.baton.domain.tag.query.controller.response.TagSearchResponse; -import touch.baton.domain.tag.query.controller.response.TagSearchResponses; - -import java.util.List; -import java.util.Map; - -import static org.assertj.core.api.SoftAssertions.assertSoftly; - -@SuppressWarnings("NonAsciiCharacters") -public class TagAssuredSupport { - - private TagAssuredSupport() { - } - - public static TagQueryBuilder 클라이언트_요청() { - return new TagQueryBuilder(); - } - - public static class TagQueryBuilder { - - private ExtractableResponse response; - - private String accessToken; - - public TagQueryBuilder 액세스_토큰으로_로그인한다(final String 액세스_토큰) { - this.accessToken = 액세스_토큰; - return this; - } - - public TagQueryBuilder 러너_게시글_등록_요청한다(final RunnerPostCreateRequest 게시글_생성_요청) { - response = AssuredSupport.post("/api/v1/posts/runner", accessToken, 게시글_생성_요청); - return this; - } - - public TagQueryBuilder 태그_이름을_오름차순으로_10개_검색한다(final String 태그_이름) { - response = AssuredSupport.get("/api/v1/tags/search", new QueryParams(Map.of("tagName", 태그_이름))); - return this; - } - - public TagQueryResponseBuilder 서버_응답() { - return new TagQueryResponseBuilder(response); - } - - } - - public static class TagQueryResponseBuilder { - - private final ExtractableResponse response; - - public TagQueryResponseBuilder(final ExtractableResponse response) { - this.response = response; - } - - public void 태그_검색_성공을_검증한다(final TagSearchResponses.Detail 검색된_태그_목록) { - final TagSearchResponses.Detail actual = this.response.as(new TypeRef<>() { - - }); - - assertSoftly(softly -> { - softly.assertThat(this.response.statusCode()).isEqualTo(HttpStatus.OK.value()); - softly.assertThat(actual.data()).isEqualTo(검색된_태그_목록.data()); - } - ); - } - } - - public static TagSearchResponses.Detail 태그_검색_Detail_응답(final List 검색된_태그_목록) { - List 태그_목록_응답 = 검색된_태그_목록.stream() - .map(TagSearchResponse.TagResponse::from) - .toList(); - final TagSearchResponses.Detail 검색된_태그_목록_응답들 = TagSearchResponses.Detail.from(태그_목록_응답); - - return 검색된_태그_목록_응답들; - } -} diff --git a/backend/baton/src/test/java/touch/baton/assure/tag/support/query/TagQuerySupport.java b/backend/baton/src/test/java/touch/baton/assure/tag/support/query/TagQuerySupport.java new file mode 100644 index 000000000..115fbde5b --- /dev/null +++ b/backend/baton/src/test/java/touch/baton/assure/tag/support/query/TagQuerySupport.java @@ -0,0 +1,58 @@ +package touch.baton.assure.tag.support.query; + +import io.restassured.common.mapper.TypeRef; +import io.restassured.response.ExtractableResponse; +import io.restassured.response.Response; +import org.springframework.http.HttpStatus; +import touch.baton.assure.common.AssuredSupport; +import touch.baton.assure.common.QueryParams; +import touch.baton.domain.tag.command.vo.TagReducedName; +import touch.baton.domain.tag.query.controller.response.TagSearchResponses; + +import java.util.Map; + +import static org.assertj.core.api.SoftAssertions.assertSoftly; + +@SuppressWarnings("NonAsciiCharacters") +public class TagQuerySupport { + + private TagQuerySupport() { + } + + public static TagQueryBuilder 클라이언트_요청() { + return new TagQueryBuilder(); + } + + public static class TagQueryBuilder { + + private ExtractableResponse response; + + public TagQueryBuilder 입력된_문자열로_태그_목록을_검색한다(final TagReducedName 요청할_태그_이름) { + response = AssuredSupport.get("/api/v1/tags/search", new QueryParams(Map.of("tagName", 요청할_태그_이름.getValue()))); + return this; + } + + public TagQueryResponseBuilder 서버_응답() { + return new TagQueryResponseBuilder(response); + } + } + + public static class TagQueryResponseBuilder { + + private final ExtractableResponse response; + + public TagQueryResponseBuilder(final ExtractableResponse response) { + this.response = response; + } + + public void 입력된_문자열로_태그_목록_검색_성공을_검증한다(final TagSearchResponses.Detail 검색된_태그_목록) { + final TagSearchResponses.Detail actual = this.response.as(new TypeRef<>() { + }); + + assertSoftly(softly -> { + softly.assertThat(this.response.statusCode()).isEqualTo(HttpStatus.OK.value()); + softly.assertThat(actual.data()).isEqualTo(검색된_태그_목록.data()); + }); + } + } +} diff --git a/backend/baton/src/test/java/touch/baton/config/AssuredTestConfig.java b/backend/baton/src/test/java/touch/baton/config/AssuredTestConfig.java index 2c7ee44b5..417005ffa 100644 --- a/backend/baton/src/test/java/touch/baton/config/AssuredTestConfig.java +++ b/backend/baton/src/test/java/touch/baton/config/AssuredTestConfig.java @@ -19,7 +19,7 @@ import touch.baton.assure.repository.TestRunnerQueryRepository; import touch.baton.assure.repository.TestSupporterQueryRepository; import touch.baton.assure.repository.TestSupporterRunnerPostQueryRepository; -import touch.baton.assure.repository.TestTagQueryRepository; +import touch.baton.assure.repository.TestTagQuerydslRepository; import touch.baton.config.converter.ConverterConfig; import touch.baton.config.infra.auth.MockBeanAuthTestConfig; import touch.baton.config.infra.github.MockGithubBranchServiceConfig; @@ -47,7 +47,7 @@ public abstract class AssuredTestConfig { protected TestSupporterRunnerPostQueryRepository supporterRunnerPostRepository; @Autowired - protected TestTagQueryRepository tagRepository; + protected TestTagQuerydslRepository tagQueryRepository; @Autowired protected TestNotificationCommandRepository notificationCommandRepository; diff --git a/backend/baton/src/test/java/touch/baton/config/QueryDslRepositoryTestConfig.java b/backend/baton/src/test/java/touch/baton/config/QueryDslRepositoryTestConfig.java index d46c842b0..a06536c83 100644 --- a/backend/baton/src/test/java/touch/baton/config/QueryDslRepositoryTestConfig.java +++ b/backend/baton/src/test/java/touch/baton/config/QueryDslRepositoryTestConfig.java @@ -7,6 +7,7 @@ import org.springframework.context.annotation.Bean; import touch.baton.domain.notification.query.repository.NotificationQuerydslRepository; import touch.baton.domain.runnerpost.query.repository.RunnerPostPageRepository; +import touch.baton.domain.tag.query.repository.TagQuerydslRepository; @TestConfiguration public class QueryDslRepositoryTestConfig { @@ -28,4 +29,9 @@ public RunnerPostPageRepository runnerPostPageRepository() { public NotificationQuerydslRepository notificationQuerydslRepository() { return new NotificationQuerydslRepository(jpaQueryFactory()); } + + @Bean + public TagQuerydslRepository tagQuerydslRepository() { + return new TagQuerydslRepository(jpaQueryFactory()); + } } diff --git a/backend/baton/src/test/java/touch/baton/config/ServiceTestConfig.java b/backend/baton/src/test/java/touch/baton/config/ServiceTestConfig.java index 84bfaa8f0..647434219 100644 --- a/backend/baton/src/test/java/touch/baton/config/ServiceTestConfig.java +++ b/backend/baton/src/test/java/touch/baton/config/ServiceTestConfig.java @@ -16,7 +16,7 @@ import touch.baton.domain.runnerpost.query.repository.RunnerPostQueryRepository; import touch.baton.domain.tag.command.repository.TagCommandRepository; import touch.baton.domain.tag.query.repository.RunnerPostTagQueryRepository; -import touch.baton.domain.tag.query.repository.TagQueryRepository; +import touch.baton.domain.tag.query.repository.TagQuerydslRepository; import touch.baton.domain.technicaltag.command.repository.RunnerTechnicalTagCommandRepository; import touch.baton.domain.technicaltag.command.repository.SupporterTechnicalTagCommandRepository; import touch.baton.domain.technicaltag.query.repository.TechnicalTagQueryRepository; @@ -45,7 +45,7 @@ public abstract class ServiceTestConfig extends RepositoryTestConfig { protected RunnerPostTagQueryRepository runnerPostTagQueryRepository; @Autowired - protected TagQueryRepository tagQueryRepository; + protected TagQuerydslRepository tagQuerydslRepository; @Autowired protected SupporterFeedbackCommandRepository supporterFeedbackCommandRepository; diff --git a/backend/baton/src/test/java/touch/baton/document/runnerpost/read/RunnerPostCountOfSupporterByGuestApiTest.java b/backend/baton/src/test/java/touch/baton/document/runnerpost/read/RunnerPostCountOfSupporterByGuestApiTest.java new file mode 100644 index 000000000..641c06d1f --- /dev/null +++ b/backend/baton/src/test/java/touch/baton/document/runnerpost/read/RunnerPostCountOfSupporterByGuestApiTest.java @@ -0,0 +1,72 @@ +package touch.baton.document.runnerpost.read; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import touch.baton.config.RestdocsConfig; +import touch.baton.domain.member.command.Runner; +import touch.baton.domain.member.command.Supporter; +import touch.baton.domain.runnerpost.command.RunnerPost; +import touch.baton.domain.runnerpost.command.vo.Deadline; +import touch.baton.domain.runnerpost.command.vo.ReviewStatus; +import touch.baton.fixture.domain.MemberFixture; +import touch.baton.fixture.domain.RunnerFixture; +import touch.baton.fixture.domain.RunnerPostFixture; +import touch.baton.fixture.domain.SupporterFixture; +import touch.baton.fixture.domain.SupporterRunnerPostFixture; + +import java.time.LocalDateTime; + +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; +import static org.springframework.http.MediaType.APPLICATION_JSON; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.payload.JsonFieldType.NUMBER; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.queryParameters; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static touch.baton.fixture.vo.DeadlineFixture.deadline; + +class RunnerPostCountOfSupporterByGuestApiTest extends RestdocsConfig { + + @DisplayName("서포터가 완료한 러너 게시글 개수 조회 API") + @Test + void countRunnerPostBySupporterIdAndReviewStatus() throws Exception { + // given + final Runner runner = RunnerFixture.createRunner(MemberFixture.createHyena()); + final Deadline deadline = deadline(LocalDateTime.now().plusHours(100)); + final RunnerPost runnerPost = RunnerPostFixture.create(runner, deadline); + + final Supporter supporter = SupporterFixture.create(MemberFixture.createDitoo()); + SupporterRunnerPostFixture.create(runnerPost, supporter); + runnerPost.assignSupporter(supporter); + + final Supporter spySupporter = spy(supporter); + given(spySupporter.getId()).willReturn(1L); + + // when + final long expectedCount = 1L; + when(runnerPostQueryService.countRunnerPostBySupporterIdAndReviewStatus(eq(1L), eq(ReviewStatus.DONE))) + .thenReturn(expectedCount); + + // then + mockMvc.perform(get("/api/v1/posts/runner/search/count") + .queryParam( + "supporterId", String.valueOf(spySupporter.getId()) + )) + .andExpect(status().isOk()) + .andExpect(content().contentType(APPLICATION_JSON)) + .andDo(restDocs.document( + queryParameters( + parameterWithName("supporterId").description("서포터 식별자 값") + ), + responseFields( + fieldWithPath("count").type(NUMBER).optional().description("게시글 개수") + )) + ); + } +} diff --git a/backend/baton/src/test/java/touch/baton/document/runnerpost/read/RunnerPostCountWithLoginedRunnerApiTest.java b/backend/baton/src/test/java/touch/baton/document/runnerpost/read/RunnerPostCountWithLoginedRunnerApiTest.java new file mode 100644 index 000000000..6782990c3 --- /dev/null +++ b/backend/baton/src/test/java/touch/baton/document/runnerpost/read/RunnerPostCountWithLoginedRunnerApiTest.java @@ -0,0 +1,80 @@ +package touch.baton.document.runnerpost.read; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import touch.baton.config.RestdocsConfig; +import touch.baton.domain.member.command.Member; +import touch.baton.domain.member.command.Runner; +import touch.baton.domain.runnerpost.command.vo.Deadline; +import touch.baton.domain.runnerpost.command.vo.ReviewStatus; +import touch.baton.domain.tag.command.Tag; +import touch.baton.fixture.domain.MemberFixture; +import touch.baton.fixture.domain.RunnerFixture; +import touch.baton.fixture.domain.RunnerPostFixture; +import touch.baton.fixture.domain.TagFixture; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Optional; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; +import static org.springframework.http.HttpHeaders.AUTHORIZATION; +import static org.springframework.http.MediaType.APPLICATION_JSON; +import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName; +import static org.springframework.restdocs.headers.HeaderDocumentation.requestHeaders; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.payload.JsonFieldType.NUMBER; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.queryParameters; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static touch.baton.fixture.vo.DeadlineFixture.deadline; +import static touch.baton.fixture.vo.TagNameFixture.tagName; + +class RunnerPostCountWithLoginedRunnerApiTest extends RestdocsConfig { + + @DisplayName("로그인한 러너와 관련된 러너 게시글 개수 조회 API") + @Test + void countRunnerPostByLoginedRunnerAndReviewStatus() throws Exception { + // given + final String socialId = "ditooSocialId"; + final Member loginedMember = MemberFixture.createWithSocialId(socialId); + final Runner loginedRunner = RunnerFixture.createRunner(loginedMember); + final String token = getAccessTokenBySocialId(socialId); + + final Tag javaTag = TagFixture.create(tagName("자바")); + final Deadline deadline = deadline(LocalDateTime.now().plusHours(100)); + RunnerPostFixture.create(loginedRunner, deadline, List.of(javaTag)); + final Runner spyLoginedRunner = spy(loginedRunner); + given(oauthRunnerCommandRepository.joinByMemberSocialId(any())).willReturn(Optional.ofNullable(spyLoginedRunner)); + + // when + final long expectedCount = 1L; + when(runnerPostQueryService.countRunnerPostByRunnerIdAndReviewStatus(eq(1L), eq(ReviewStatus.NOT_STARTED))) + .thenReturn(expectedCount); + + // then + mockMvc.perform(get("/api/v1/posts/runner/me/runner/count") + .header(AUTHORIZATION, "Bearer " + token) + .queryParam("reviewStatus", ReviewStatus.NOT_STARTED.name())) + .andExpect(status().isOk()) + .andExpect(content().contentType(APPLICATION_JSON)) + .andDo(restDocs.document( + requestHeaders( + headerWithName(AUTHORIZATION).description("Bearer JWT") + ), + queryParameters( + parameterWithName("reviewStatus").description("리뷰 상태") + ), + responseFields( + fieldWithPath("count").type(NUMBER).optional().description("게시글 개수") + )) + ); + } +} diff --git a/backend/baton/src/test/java/touch/baton/document/runnerpost/read/RunnerPostCountWithLoginedSupporterApiTest.java b/backend/baton/src/test/java/touch/baton/document/runnerpost/read/RunnerPostCountWithLoginedSupporterApiTest.java new file mode 100644 index 000000000..f607b1508 --- /dev/null +++ b/backend/baton/src/test/java/touch/baton/document/runnerpost/read/RunnerPostCountWithLoginedSupporterApiTest.java @@ -0,0 +1,84 @@ +package touch.baton.document.runnerpost.read; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import touch.baton.config.RestdocsConfig; +import touch.baton.domain.member.command.Member; +import touch.baton.domain.member.command.Runner; +import touch.baton.domain.member.command.Supporter; +import touch.baton.domain.runnerpost.command.RunnerPost; +import touch.baton.domain.runnerpost.command.vo.Deadline; +import touch.baton.domain.runnerpost.command.vo.ReviewStatus; +import touch.baton.fixture.domain.MemberFixture; +import touch.baton.fixture.domain.RunnerFixture; +import touch.baton.fixture.domain.RunnerPostFixture; +import touch.baton.fixture.domain.SupporterFixture; +import touch.baton.fixture.domain.SupporterRunnerPostFixture; + +import java.time.LocalDateTime; +import java.util.Optional; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; +import static org.springframework.http.HttpHeaders.AUTHORIZATION; +import static org.springframework.http.MediaType.APPLICATION_JSON; +import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName; +import static org.springframework.restdocs.headers.HeaderDocumentation.requestHeaders; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.payload.JsonFieldType.NUMBER; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.queryParameters; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static touch.baton.fixture.vo.DeadlineFixture.deadline; + +class RunnerPostCountWithLoginedSupporterApiTest extends RestdocsConfig { + + @DisplayName("로그인한 서포터와 관련된 러너 게시글 개수 조회 API") + @Test + void countRunnerPostByLoginedSupporterAndReviewStatus() throws Exception { + // given + final String socialId = "ditooSocialId"; + final Member loginedMember = MemberFixture.createWithSocialId(socialId); + final Supporter loginedSupporter = SupporterFixture.create(loginedMember); + final String token = getAccessTokenBySocialId(socialId); + + final Runner runner = RunnerFixture.createRunner(MemberFixture.createHyena()); + + final Deadline deadline = deadline(LocalDateTime.now().plusHours(100)); + final RunnerPost runnerPost = RunnerPostFixture.create(runner, deadline); + SupporterRunnerPostFixture.create(runnerPost, loginedSupporter); + runnerPost.assignSupporter(loginedSupporter); + + final Supporter spyLoginedSupporter = spy(loginedSupporter); + given(oauthSupporterCommandRepository.joinByMemberSocialId(any())).willReturn(Optional.ofNullable(spyLoginedSupporter)); + + // when + final long expectedCount = 1L; + when(runnerPostQueryService.countRunnerPostBySupporterIdAndReviewStatus(eq(1L), eq(ReviewStatus.NOT_STARTED))) + .thenReturn(expectedCount); + + // then + mockMvc.perform(get("/api/v1/posts/runner/me/supporter/count") + .header(AUTHORIZATION, "Bearer " + token) + .queryParam("reviewStatus", ReviewStatus.NOT_STARTED.name())) + .andExpect(status().isOk()) + .andExpect(content().contentType(APPLICATION_JSON)) + .andDo(restDocs.document( + requestHeaders( + headerWithName(AUTHORIZATION).description("Bearer JWT") + ), + queryParameters( + parameterWithName("reviewStatus").description("리뷰 상태") + ), + responseFields( + fieldWithPath("count").type(NUMBER).optional().description("게시글 개수") + )) + ); + } +} diff --git a/backend/baton/src/test/java/touch/baton/document/runnerpost/read/RunnerPostReadOneApiTest.java b/backend/baton/src/test/java/touch/baton/document/runnerpost/read/RunnerPostReadOneApiTest.java index 7941f8577..868ac7384 100644 --- a/backend/baton/src/test/java/touch/baton/document/runnerpost/read/RunnerPostReadOneApiTest.java +++ b/backend/baton/src/test/java/touch/baton/document/runnerpost/read/RunnerPostReadOneApiTest.java @@ -64,7 +64,7 @@ void readByRunnerPostId() throws Exception { when(runnerPostQueryService.readByRunnerPostId(any())) .thenReturn(spyRunnerPost); - when(runnerPostQueryService.readCountByRunnerPostId(any())) + when(runnerPostQueryService.countApplicantsByRunnerPostId(any())) .thenReturn(3L); final String token = getAccessTokenBySocialId(memberHyena.getSocialId().getValue()); diff --git a/backend/baton/src/test/java/touch/baton/document/runnerpost/read/TagReadApiTest.java b/backend/baton/src/test/java/touch/baton/document/runnerpost/read/TagReadApiTest.java index cdb8165ac..18e65d9b5 100644 --- a/backend/baton/src/test/java/touch/baton/document/runnerpost/read/TagReadApiTest.java +++ b/backend/baton/src/test/java/touch/baton/document/runnerpost/read/TagReadApiTest.java @@ -4,6 +4,7 @@ import org.junit.jupiter.api.Test; import touch.baton.config.RestdocsConfig; import touch.baton.domain.tag.command.Tag; +import touch.baton.domain.tag.command.vo.TagReducedName; import touch.baton.fixture.domain.TagFixture; import java.util.List; @@ -35,7 +36,7 @@ void readTagsByReducedName() throws Exception { final Tag javascriptTagSpy = spy(javascriptTag); // when - when(tagQueryService.readTagsByReducedName("java")) + when(tagQueryService.readTagsByReducedName(TagReducedName.nullableInstance("java"), 10)) .thenReturn(List.of(javaTagSpy, javascriptTagSpy)); when(javaTagSpy.getId()) .thenReturn(1L); diff --git a/backend/baton/src/test/java/touch/baton/domain/runnerpost/command/repository/SupporterRunnerPostQueryRepositoryReadTest.java b/backend/baton/src/test/java/touch/baton/domain/runnerpost/command/repository/SupporterRunnerPostQueryRepositoryReadTest.java deleted file mode 100644 index 5e17464b6..000000000 --- a/backend/baton/src/test/java/touch/baton/domain/runnerpost/command/repository/SupporterRunnerPostQueryRepositoryReadTest.java +++ /dev/null @@ -1,106 +0,0 @@ -package touch.baton.domain.runnerpost.command.repository; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import touch.baton.config.RepositoryTestConfig; -import touch.baton.domain.member.command.Member; -import touch.baton.domain.member.command.Runner; -import touch.baton.domain.member.command.Supporter; -import touch.baton.domain.member.command.repository.MemberCommandRepository; -import touch.baton.domain.member.query.repository.RunnerQueryRepository; -import touch.baton.domain.member.query.repository.SupporterQueryRepository; -import touch.baton.domain.member.query.repository.SupporterRunnerPostQueryRepository; -import touch.baton.domain.runnerpost.command.RunnerPost; -import touch.baton.domain.runnerpost.query.repository.RunnerPostQueryRepository; -import touch.baton.fixture.domain.MemberFixture; -import touch.baton.fixture.domain.RunnerFixture; -import touch.baton.fixture.domain.RunnerPostFixture; -import touch.baton.fixture.domain.SupporterFixture; -import touch.baton.fixture.domain.SupporterRunnerPostFixture; - -import java.time.LocalDateTime; -import java.util.List; - -import static org.assertj.core.api.SoftAssertions.assertSoftly; -import static touch.baton.fixture.vo.DeadlineFixture.deadline; - -class SupporterRunnerPostQueryRepositoryReadTest extends RepositoryTestConfig { - - @Autowired - private SupporterRunnerPostQueryRepository supporterRunnerPostRepository; - - @Autowired - private MemberCommandRepository memberCommandRepository; - - @Autowired - private RunnerQueryRepository runnerQueryRepository; - - @Autowired - private SupporterQueryRepository supporterQueryRepository; - - @Autowired - private RunnerPostQueryRepository runnerPostQueryRepository; - - @DisplayName("RunnerPostId 와 SupporterId 로 존재 유무를 확인할 수 있다.") - @Test - void existsByRunnerPostIdAndSupporterId() { - // given - final Member ehtanMember = memberCommandRepository.save(MemberFixture.createEthan()); - final Runner runnerPostOwner = runnerQueryRepository.save(RunnerFixture.createRunner(ehtanMember)); - final RunnerPost runner = runnerPostQueryRepository.save(RunnerPostFixture.create(runnerPostOwner, - deadline(LocalDateTime.now().plusDays(10)))); - - final Member hyenaMember = memberCommandRepository.save(MemberFixture.createHyena()); - final Supporter supporter = supporterQueryRepository.save(SupporterFixture.create(hyenaMember)); - supporterRunnerPostRepository.save(SupporterRunnerPostFixture.create(runner, supporter)); - - final Long notSavedRunnerPostId = -1L; - final Long notSavedSupporter = -1L; - - // when, then - assertSoftly(softly -> { - softly.assertThat(supporterRunnerPostRepository.existsByRunnerPostIdAndSupporterId(runner.getId(), supporter.getId())).isTrue(); - softly.assertThat(supporterRunnerPostRepository.existsByRunnerPostIdAndSupporterId(notSavedRunnerPostId, supporter.getId())).isFalse(); - softly.assertThat(supporterRunnerPostRepository.existsByRunnerPostIdAndSupporterId(runner.getId(), notSavedSupporter)).isFalse(); - } - ); - } - - @DisplayName("RunnerPostId 로 지원한 서포터의 수를 확인할 수 있다.") - @Test - void countByRunnerPostIds() { - // given - final Member ehtanMember = memberCommandRepository.save(MemberFixture.createEthan()); - final Runner runnerPostOwner = runnerQueryRepository.save(RunnerFixture.createRunner(ehtanMember)); - final RunnerPost firstRunnerPost = runnerPostQueryRepository.save(RunnerPostFixture.create(runnerPostOwner, - deadline(LocalDateTime.now().plusDays(10)))); - final RunnerPost twoRunnerPost = runnerPostQueryRepository.save(RunnerPostFixture.create(runnerPostOwner, - deadline(LocalDateTime.now().plusDays(10)))); - - final Member hyenaMember = memberCommandRepository.save(MemberFixture.createHyena()); - final Supporter hyenaSupporter = supporterQueryRepository.save(SupporterFixture.create(hyenaMember)); - supporterRunnerPostRepository.save(SupporterRunnerPostFixture.create(firstRunnerPost, hyenaSupporter)); - - final Member judyMember = memberCommandRepository.save(MemberFixture.createJudy()); - final Supporter judySupporter = supporterQueryRepository.save(SupporterFixture.create(judyMember)); - supporterRunnerPostRepository.save(SupporterRunnerPostFixture.create(firstRunnerPost, judySupporter)); - - // when - final List applicantCounts = supporterRunnerPostRepository.countByRunnerPostIds(List.of(firstRunnerPost.getId(), twoRunnerPost.getId())); - - final Long actualSecondRunnerPostApplicantsCount = applicantCounts.get(0); - final Long actualFirstRunnerPostApplicantsCount = applicantCounts.get(1); - final Long expectedSecondRunnerPostApplicantsCount = 0L; - final Long expectedFirstRunnerPostApplicantsCount = 2L; - final int expectedSize = 2; - - // when, then - assertSoftly(softly -> { - softly.assertThat(applicantCounts.size()).isEqualTo(expectedSize); - softly.assertThat(actualSecondRunnerPostApplicantsCount).isEqualTo(expectedSecondRunnerPostApplicantsCount); - softly.assertThat(actualFirstRunnerPostApplicantsCount).isEqualTo(expectedFirstRunnerPostApplicantsCount); - } - ); - } -} diff --git a/backend/baton/src/test/java/touch/baton/domain/runnerpost/query/repository/RunnerPostQueryRepositoryTest.java b/backend/baton/src/test/java/touch/baton/domain/runnerpost/query/repository/RunnerPostQueryRepositoryTest.java index e5c950559..f645ad6ba 100644 --- a/backend/baton/src/test/java/touch/baton/domain/runnerpost/query/repository/RunnerPostQueryRepositoryTest.java +++ b/backend/baton/src/test/java/touch/baton/domain/runnerpost/query/repository/RunnerPostQueryRepositoryTest.java @@ -8,6 +8,7 @@ import touch.baton.domain.member.command.Supporter; import touch.baton.domain.runnerpost.command.RunnerPost; import touch.baton.domain.runnerpost.command.repository.dto.RunnerPostApplicantCountDto; +import touch.baton.domain.runnerpost.command.vo.ReviewStatus; import touch.baton.fixture.domain.MemberFixture; import java.util.ArrayList; @@ -150,4 +151,47 @@ void joinSupporterByRunnerPostId() { softly.assertThat(actual).isEqualTo(runnerPost); }); } + + @DisplayName("러너 관련 게시글 개수를 조회하는데 성공한다.") + @Test + void countByRunnerIdAndReviewStatus() { + // given + final Runner runner = persistRunner(MemberFixture.createDitoo()); + final int expected = 5; + for (int i = 0; i < expected; i++) { + persistRunnerPost(runner); + } + + em.flush(); + em.close(); + + // when + final Long actual = runnerPostQueryRepository.countByRunnerIdAndReviewStatus(runner.getId(), ReviewStatus.NOT_STARTED); + + // then + assertThat(actual.intValue()).isEqualTo(expected); + } + + @DisplayName("서포터 관련 게시글 개수를 조회하는데 성공한다.") + @Test + void countBySupporterIdAndReviewStatus() { + // given + final Runner runner = persistRunner(MemberFixture.createEthan()); + final Supporter supporter = persistSupporter(MemberFixture.createDitoo()); + final int expected = 3; + for (int i = 0; i < expected; i++) { + final RunnerPost runnerPost = persistRunnerPost(runner); + runnerPost.assignSupporter(supporter); + runnerPost.finishReview(); + } + + em.flush(); + em.close(); + + // when + final Long actual = runnerPostQueryRepository.countBySupporterIdAndReviewStatus(supporter.getId(), ReviewStatus.DONE); + + // then + assertThat(actual.intValue()).isEqualTo(expected); + } } diff --git a/backend/baton/src/test/java/touch/baton/domain/runnerpost/query/service/RunnerPostQueryServiceTest.java b/backend/baton/src/test/java/touch/baton/domain/runnerpost/query/service/RunnerPostQueryServiceTest.java index a174ff026..be09c19ca 100644 --- a/backend/baton/src/test/java/touch/baton/domain/runnerpost/query/service/RunnerPostQueryServiceTest.java +++ b/backend/baton/src/test/java/touch/baton/domain/runnerpost/query/service/RunnerPostQueryServiceTest.java @@ -75,8 +75,8 @@ void readRunnerPostByPageInfoAndTagNameAndReviewStatus_firstPage() { final Member hyenaMember = memberCommandRepository.save(MemberFixture.createHyena()); final Runner hyenaRunner = runnerQueryRepository.save(RunnerFixture.createRunner(hyenaMember)); - final Tag javaTag = tagQueryRepository.save(TagFixture.create(tagName("자바"))); - final Tag springTag = tagQueryRepository.save(TagFixture.create(tagName("스프링"))); + final Tag javaTag = tagCommandRepository.save(TagFixture.create(tagName("자바"))); + final Tag springTag = tagCommandRepository.save(TagFixture.create(tagName("스프링"))); final RunnerPost expectedRunnerPostOne = runnerPostQueryRepository.save(RunnerPostFixture.create( hyenaRunner, @@ -136,8 +136,8 @@ void readRunnerPostByPageInfoAndTagNameAndReviewStatus_middlePage() { final Member hyenaMember = memberCommandRepository.save(MemberFixture.createHyena()); final Runner hyenaRunner = runnerQueryRepository.save(RunnerFixture.createRunner(hyenaMember)); - final Tag javaTag = tagQueryRepository.save(TagFixture.create(tagName("자바"))); - final Tag springTag = tagQueryRepository.save(TagFixture.create(tagName("스프링"))); + final Tag javaTag = tagCommandRepository.save(TagFixture.create(tagName("자바"))); + final Tag springTag = tagCommandRepository.save(TagFixture.create(tagName("스프링"))); final RunnerPost expectedRunnerPostOne = runnerPostQueryRepository.save(RunnerPostFixture.create( hyenaRunner, @@ -204,8 +204,8 @@ void readRunnerPostByPageInfoAndReviewStatus_firstPage() { final Member hyenaMember = memberCommandRepository.save(MemberFixture.createHyena()); final Runner hyenaRunner = runnerQueryRepository.save(RunnerFixture.createRunner(hyenaMember)); - final Tag javaTag = tagQueryRepository.save(TagFixture.create(tagName("자바"))); - final Tag springTag = tagQueryRepository.save(TagFixture.create(tagName("스프링"))); + final Tag javaTag = tagCommandRepository.save(TagFixture.create(tagName("자바"))); + final Tag springTag = tagCommandRepository.save(TagFixture.create(tagName("스프링"))); final RunnerPost expectedRunnerPostOne = runnerPostQueryRepository.save(RunnerPostFixture.create( hyenaRunner, @@ -267,8 +267,8 @@ void readRunnerPostByPageInfoAndReviewStatus_middlePage() { final Member hyenaMember = memberCommandRepository.save(MemberFixture.createHyena()); final Runner hyenaRunner = runnerQueryRepository.save(RunnerFixture.createRunner(hyenaMember)); - final Tag javaTag = tagQueryRepository.save(TagFixture.create(tagName("자바"))); - final Tag springTag = tagQueryRepository.save(TagFixture.create(tagName("스프링"))); + final Tag javaTag = tagCommandRepository.save(TagFixture.create(tagName("자바"))); + final Tag springTag = tagCommandRepository.save(TagFixture.create(tagName("스프링"))); final RunnerPost expectedRunnerPostOne = runnerPostQueryRepository.save(RunnerPostFixture.create( hyenaRunner, @@ -336,8 +336,8 @@ void readRunnerPostByPageInfoAndTagName_firstPage() { final Member hyenaMember = memberCommandRepository.save(MemberFixture.createHyena()); final Runner hyenaRunner = runnerQueryRepository.save(RunnerFixture.createRunner(hyenaMember)); - final Tag javaTag = tagQueryRepository.save(TagFixture.create(tagName("자바"))); - final Tag springTag = tagQueryRepository.save(TagFixture.create(tagName("스프링"))); + final Tag javaTag = tagCommandRepository.save(TagFixture.create(tagName("자바"))); + final Tag springTag = tagCommandRepository.save(TagFixture.create(tagName("스프링"))); final RunnerPost expectedRunnerPostOne = runnerPostQueryRepository.save(RunnerPostFixture.create( hyenaRunner, @@ -390,8 +390,8 @@ void readRunnerPostByPageInfoAndTagName_middlePage() { final Member hyenaMember = memberCommandRepository.save(MemberFixture.createHyena()); final Runner hyenaRunner = runnerQueryRepository.save(RunnerFixture.createRunner(hyenaMember)); - final Tag javaTag = tagQueryRepository.save(TagFixture.create(tagName("자바"))); - final Tag springTag = tagQueryRepository.save(TagFixture.create(tagName("스프링"))); + final Tag javaTag = tagCommandRepository.save(TagFixture.create(tagName("자바"))); + final Tag springTag = tagCommandRepository.save(TagFixture.create(tagName("스프링"))); final RunnerPost expectedRunnerPostOne = runnerPostQueryRepository.save(RunnerPostFixture.create( hyenaRunner, @@ -451,8 +451,8 @@ void readRunnerPostByPageInfo_firstPage() { final Member hyenaMember = memberCommandRepository.save(MemberFixture.createHyena()); final Runner hyenaRunner = runnerQueryRepository.save(RunnerFixture.createRunner(hyenaMember)); - final Tag javaTag = tagQueryRepository.save(TagFixture.create(tagName("자바"))); - final Tag springTag = tagQueryRepository.save(TagFixture.create(tagName("스프링"))); + final Tag javaTag = tagCommandRepository.save(TagFixture.create(tagName("자바"))); + final Tag springTag = tagCommandRepository.save(TagFixture.create(tagName("스프링"))); final RunnerPost expectedRunnerPostOne = runnerPostQueryRepository.save(RunnerPostFixture.create( hyenaRunner, @@ -507,8 +507,8 @@ void readRunnerPostByPageInfo_middlePage() { final Member hyenaMember = memberCommandRepository.save(MemberFixture.createHyena()); final Runner hyenaRunner = runnerQueryRepository.save(RunnerFixture.createRunner(hyenaMember)); - final Tag javaTag = tagQueryRepository.save(TagFixture.create(tagName("자바"))); - final Tag springTag = tagQueryRepository.save(TagFixture.create(tagName("스프링"))); + final Tag javaTag = tagCommandRepository.save(TagFixture.create(tagName("자바"))); + final Tag springTag = tagCommandRepository.save(TagFixture.create(tagName("스프링"))); final RunnerPost expectedRunnerPostOne = runnerPostQueryRepository.save(RunnerPostFixture.create( hyenaRunner, @@ -604,7 +604,7 @@ void success_findByRunnerPostId() { .tagName(new TagName("자바")) .tagReducedName(TagReducedName.from("자바")) .build(); - tagQueryRepository.save(tag); + tagCommandRepository.save(tag); final RunnerPostTag runnerPostTag = RunnerPostTag.builder() .runnerPost(runnerPost) @@ -794,4 +794,66 @@ void existsRunnerPostApplicantByRunnerPostIdAndMemberId_if_member_is_not_exist_t // then assertThat(isApplicantHistoryExist).isFalse(); } + + @DisplayName("RunnerId 와 ReviewStatus 로 러너 게시글 개수를 조회한다.") + @Test + void countRunnerPostByRunnerIdAndReviewStatus() { + // given + final Member member = memberCommandRepository.save(MemberFixture.createDitoo()); + final Runner runner = runnerQueryRepository.save(RunnerFixture.createRunner(member)); + + final long expected = 3L; + for (long i = 0; i < expected; i++) { + runnerPostCommandRepository.save(RunnerPostFixture.create(runner, new Deadline(now().plusHours(100)))); + } + + // when + final long actual = runnerPostQueryService.countRunnerPostByRunnerIdAndReviewStatus(runner.getId(), NOT_STARTED); + + // then + assertThat(actual).isEqualTo(expected); + } + + @DisplayName("SupporterId 로 ReviewStatus 가 NOT_STARTED 인 러너 게시글 개수를 조회한다.") + @Test + void countRunnerPostBySupporterIdAndReviewStatus_NOT_STARTED() { + // given + final Member member = memberCommandRepository.save(MemberFixture.createDitoo()); + final Runner runner = runnerQueryRepository.save(RunnerFixture.createRunner(member)); + final RunnerPost runnerPost = runnerPostCommandRepository.save(RunnerPostFixture.create(runner, new Deadline(now().plusHours(100)))); + + final Member supporterMember = memberCommandRepository.save(MemberFixture.createDitoo()); + final Supporter supporter = supporterQueryRepository.save(SupporterFixture.create(supporterMember)); + + supporterRunnerPostCommandRepository.save(SupporterRunnerPostFixture.create(runnerPost, supporter)); + + // when + final long expected = 1L; + final long actual = runnerPostQueryService.countRunnerPostBySupporterIdAndReviewStatus(supporter.getId(), NOT_STARTED); + + // then + assertThat(actual).isEqualTo(expected); + } + + @DisplayName("SupporterId 로 ReviewStatus 가 NOT_STARTED 이 아닌 러너 게시글 개수를 조회한다.") + @Test + void countRunnerPostBySupporterIdAndReviewStatus_except_NOT_STARTED() { + // given + final Member member = memberCommandRepository.save(MemberFixture.createDitoo()); + final Runner runner = runnerQueryRepository.save(RunnerFixture.createRunner(member)); + final RunnerPost runnerPost = runnerPostCommandRepository.save(RunnerPostFixture.create(runner, new Deadline(now().plusHours(100)))); + + final Member supporterMember = memberCommandRepository.save(MemberFixture.createDitoo()); + final Supporter supporter = supporterQueryRepository.save(SupporterFixture.create(supporterMember)); + + supporterRunnerPostCommandRepository.save(SupporterRunnerPostFixture.create(runnerPost, supporter)); + runnerPost.assignSupporter(supporter); + + // when + final long expected = 1L; + final long actual = runnerPostQueryService.countRunnerPostBySupporterIdAndReviewStatus(supporter.getId(), IN_PROGRESS); + + // then + assertThat(actual).isEqualTo(expected); + } } diff --git a/backend/baton/src/test/java/touch/baton/domain/supporter/SupporterFeedbackTest.java b/backend/baton/src/test/java/touch/baton/domain/supporter/command/SupporterFeedbackTest.java similarity index 99% rename from backend/baton/src/test/java/touch/baton/domain/supporter/SupporterFeedbackTest.java rename to backend/baton/src/test/java/touch/baton/domain/supporter/command/SupporterFeedbackTest.java index 98e9c7b47..067746f8c 100644 --- a/backend/baton/src/test/java/touch/baton/domain/supporter/SupporterFeedbackTest.java +++ b/backend/baton/src/test/java/touch/baton/domain/supporter/command/SupporterFeedbackTest.java @@ -1,4 +1,4 @@ -package touch.baton.domain.supporter; +package touch.baton.domain.supporter.command; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; diff --git a/backend/baton/src/test/java/touch/baton/domain/supporter/SupporterTest.java b/backend/baton/src/test/java/touch/baton/domain/supporter/command/SupporterTest.java similarity index 99% rename from backend/baton/src/test/java/touch/baton/domain/supporter/SupporterTest.java rename to backend/baton/src/test/java/touch/baton/domain/supporter/command/SupporterTest.java index da90ec67a..7129b7725 100644 --- a/backend/baton/src/test/java/touch/baton/domain/supporter/SupporterTest.java +++ b/backend/baton/src/test/java/touch/baton/domain/supporter/command/SupporterTest.java @@ -1,4 +1,4 @@ -package touch.baton.domain.supporter; +package touch.baton.domain.supporter.command; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; diff --git a/backend/baton/src/test/java/touch/baton/domain/supporter/repository/SupporterQueryRepositoryTest.java b/backend/baton/src/test/java/touch/baton/domain/supporter/command/repository/SupporterQueryRepositoryTest.java similarity index 75% rename from backend/baton/src/test/java/touch/baton/domain/supporter/repository/SupporterQueryRepositoryTest.java rename to backend/baton/src/test/java/touch/baton/domain/supporter/command/repository/SupporterQueryRepositoryTest.java index d7ba7ff9d..6a47eb423 100644 --- a/backend/baton/src/test/java/touch/baton/domain/supporter/repository/SupporterQueryRepositoryTest.java +++ b/backend/baton/src/test/java/touch/baton/domain/supporter/command/repository/SupporterQueryRepositoryTest.java @@ -1,15 +1,12 @@ -package touch.baton.domain.supporter.repository; +package touch.baton.domain.supporter.command.repository; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import touch.baton.config.RepositoryTestConfig; -import touch.baton.domain.member.command.Member; import touch.baton.domain.member.command.Supporter; -import touch.baton.domain.member.command.repository.MemberCommandRepository; import touch.baton.domain.member.query.repository.SupporterQueryRepository; import touch.baton.fixture.domain.MemberFixture; -import touch.baton.fixture.domain.SupporterFixture; import java.util.Optional; @@ -18,9 +15,6 @@ class SupporterQueryRepositoryTest extends RepositoryTestConfig { - @Autowired - private MemberCommandRepository memberCommandRepository; - @Autowired private SupporterQueryRepository supporterQueryRepository; @@ -28,8 +22,7 @@ class SupporterQueryRepositoryTest extends RepositoryTestConfig { @Test void joinMemberBySupporterId() { // given - final Member savedMember = memberCommandRepository.save(MemberFixture.createHyena()); - final Supporter savedSupporter = supporterQueryRepository.save(SupporterFixture.create(savedMember)); + final Supporter savedSupporter = persistSupporter(MemberFixture.createHyena()); // when final Optional maybeSupporter = supporterQueryRepository.joinMemberBySupporterId(savedSupporter.getId()); @@ -41,7 +34,7 @@ void joinMemberBySupporterId() { () -> assertThat(maybeSupporter.get().getIntroduction()).isEqualTo(savedSupporter.getIntroduction()), () -> assertThat(maybeSupporter.get().getReviewCount()).isEqualTo(savedSupporter.getReviewCount()), () -> assertThat(maybeSupporter.get().getSupporterTechnicalTags()).isEqualTo(savedSupporter.getSupporterTechnicalTags()), - () -> assertThat(maybeSupporter.get().getMember()).isEqualTo(savedMember) + () -> assertThat(maybeSupporter.get().getMember()).isEqualTo(savedSupporter.getMember()) ); } diff --git a/backend/baton/src/test/java/touch/baton/domain/supporter/command/repository/SupporterRunnerPostCommandRepositoryTest.java b/backend/baton/src/test/java/touch/baton/domain/supporter/command/repository/SupporterRunnerPostCommandRepositoryTest.java new file mode 100644 index 000000000..8a1d9a4f6 --- /dev/null +++ b/backend/baton/src/test/java/touch/baton/domain/supporter/command/repository/SupporterRunnerPostCommandRepositoryTest.java @@ -0,0 +1,79 @@ +package touch.baton.domain.supporter.command.repository; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import touch.baton.config.RepositoryTestConfig; +import touch.baton.domain.member.command.Runner; +import touch.baton.domain.member.command.Supporter; +import touch.baton.domain.member.command.SupporterRunnerPost; +import touch.baton.domain.member.command.repository.SupporterRunnerPostCommandRepository; +import touch.baton.domain.runnerpost.command.RunnerPost; +import touch.baton.fixture.domain.MemberFixture; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.SoftAssertions.assertSoftly; + +class SupporterRunnerPostCommandRepositoryTest extends RepositoryTestConfig { + + @Autowired + private SupporterRunnerPostCommandRepository supporterRunnerPostCommandRepository; + + @DisplayName("RunnerPost 외래키로 된 SupporterRunnerPost 가 존재하는지 확인한다.") + @Test + void existsByRunnerPostId() { + // given + final Runner runner = persistRunner(MemberFixture.createDitoo()); + final Supporter supporter = persistSupporter(MemberFixture.createHyena()); + final RunnerPost runnerPostOfApplicantExist = persistRunnerPost(runner); + final RunnerPost runnerPostOfApplicantNotExist = persistRunnerPost(runner); + persistApplicant(supporter, runnerPostOfApplicantExist); + + // when + final boolean actualOfExist = supporterRunnerPostCommandRepository.existsByRunnerPostId(runnerPostOfApplicantExist.getId()); + final boolean actualOfNotExist = supporterRunnerPostCommandRepository.existsByRunnerPostId(runnerPostOfApplicantNotExist.getId()); + + // then + assertSoftly(softly -> { + softly.assertThat(actualOfExist).isTrue(); + softly.assertThat(actualOfNotExist).isFalse(); + }); + } + + @DisplayName("RunnerPostId 와 SupporterId 로 존재 유무를 확인할 수 있다.") + @Test + void existsByRunnerPostIdAndSupporterId() { + // given + final Runner runner = persistRunner(MemberFixture.createEthan()); + final RunnerPost runnerPost = persistRunnerPost(runner); + final Supporter supporter = persistSupporter(MemberFixture.createHyena()); + persistApplicant(supporter, runnerPost); + + final Long notSavedRunnerPostId = -1L; + final Long notSavedSupporter = -1L; + + // when, then + assertSoftly(softly -> { + softly.assertThat(supporterRunnerPostCommandRepository.existsByRunnerPostIdAndSupporterId(runnerPost.getId(), supporter.getId())).isTrue(); + softly.assertThat(supporterRunnerPostCommandRepository.existsByRunnerPostIdAndSupporterId(notSavedRunnerPostId, supporter.getId())).isFalse(); + softly.assertThat(supporterRunnerPostCommandRepository.existsByRunnerPostIdAndSupporterId(runnerPost.getId(), notSavedSupporter)).isFalse(); + } + ); + } + + @DisplayName("서포터의 러너 게시글 리뷰 제안을 철회하는데 성공한다") + @Test + void deleteBySupporterAndRunnerPostId() { + // given + final Supporter supporter = persistSupporter(MemberFixture.createDitoo()); + final Runner runner = persistRunner(MemberFixture.createHyena()); + final RunnerPost runnerPost = persistRunnerPost(runner); + final SupporterRunnerPost supporterRunnerPost = persistApplicant(supporter, runnerPost); + + // when + supporterRunnerPostCommandRepository.deleteBySupporterIdAndRunnerPostId(supporterRunnerPost.getId(), runnerPost.getId()); + + // then + assertThat(supporterRunnerPostCommandRepository.findById(runnerPost.getId())).isNotPresent(); + } +} diff --git a/backend/baton/src/test/java/touch/baton/domain/supporter/service/SupporterCommandServiceTest.java b/backend/baton/src/test/java/touch/baton/domain/supporter/command/service/SupporterCommandServiceTest.java similarity index 96% rename from backend/baton/src/test/java/touch/baton/domain/supporter/service/SupporterCommandServiceTest.java rename to backend/baton/src/test/java/touch/baton/domain/supporter/command/service/SupporterCommandServiceTest.java index 6f97ea029..7f6b41747 100644 --- a/backend/baton/src/test/java/touch/baton/domain/supporter/service/SupporterCommandServiceTest.java +++ b/backend/baton/src/test/java/touch/baton/domain/supporter/command/service/SupporterCommandServiceTest.java @@ -1,4 +1,4 @@ -package touch.baton.domain.supporter.service; +package touch.baton.domain.supporter.command.service; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; diff --git a/backend/baton/src/test/java/touch/baton/domain/supporter/query/repository/SupporterRunnerPostQueryRepositoryTest.java b/backend/baton/src/test/java/touch/baton/domain/supporter/query/repository/SupporterRunnerPostQueryRepositoryTest.java new file mode 100644 index 000000000..3f3ec7bd6 --- /dev/null +++ b/backend/baton/src/test/java/touch/baton/domain/supporter/query/repository/SupporterRunnerPostQueryRepositoryTest.java @@ -0,0 +1,112 @@ +package touch.baton.domain.supporter.query.repository; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import touch.baton.config.RepositoryTestConfig; +import touch.baton.domain.member.command.Runner; +import touch.baton.domain.member.command.Supporter; +import touch.baton.domain.member.command.SupporterRunnerPost; +import touch.baton.domain.member.query.repository.SupporterRunnerPostQueryRepository; +import touch.baton.domain.runnerpost.command.RunnerPost; +import touch.baton.fixture.domain.MemberFixture; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +class SupporterRunnerPostQueryRepositoryTest extends RepositoryTestConfig { + + @Autowired + private SupporterRunnerPostQueryRepository supporterRunnerPostQueryRepository; + + @DisplayName("Member 가 SupporterRunnerPost 에 지원한 이력이 있을 경우 true 를 반환한다.") + @Test + void existsByRunnerPostIdAndMemberId_return_true() { + // given + final Runner runner = persistRunner(MemberFixture.createDitoo()); + final RunnerPost runnerPost = persistRunnerPost(runner); + final Supporter supporter = persistSupporter(MemberFixture.createEthan()); + final SupporterRunnerPost supporterRunnerPost = persistApplicant(supporter, runnerPost); + + supporterRunnerPostQueryRepository.save(supporterRunnerPost); + + // when + final boolean isApplicantHistoryExist = supporterRunnerPostQueryRepository.existsByRunnerPostIdAndMemberId( + runnerPost.getId(), + supporter.getMember().getId() + ); + + // then + assertThat(isApplicantHistoryExist).isTrue(); + } + + @DisplayName("Member 가 SupporterRunnerPost 에 지원한 이력이 없을 경우 false 를 반환한다.") + @Test + void existsByRunnerPostIdAndMemberId_if_supporterRunnerPost_is_not_exist_then_return_false() { + // given + final Runner runner = persistRunner(MemberFixture.createDitoo()); + final RunnerPost runnerPost = persistRunnerPost(runner); + final Supporter supporter = persistSupporter(MemberFixture.createEthan()); + + // when + final boolean isApplicantHistoryNotExist = supporterRunnerPostQueryRepository.existsByRunnerPostIdAndMemberId( + runnerPost.getId(), + supporter.getMember().getId() + ); + + // then + assertThat(isApplicantHistoryNotExist).isFalse(); + } + + @DisplayName("Member 가 SupporterRunnerPost 에 지원한 이력을 조회할 때 RunnerPost 자체가 없으면 false 를 반환한다.") + @Test + void existsByRunnerPostIdAndMemberId_if_runnerPost_is_not_exist_then_return_false() { + // given + final Supporter supporter = persistSupporter(MemberFixture.createDitoo()); + + // when + final Long notExistRunnerPostId = -1L; + final boolean isApplicantHistoryNotExist = supporterRunnerPostQueryRepository.existsByRunnerPostIdAndMemberId( + notExistRunnerPostId, + supporter.getMember().getId() + ); + + // then + assertThat(isApplicantHistoryNotExist).isFalse(); + } + + @DisplayName("RunnerPostId 로 SupporterRunnerPost 목록을 조회한다.") + @Test + void readByRunnerPostId() { + // given + final Runner runner = persistRunner(MemberFixture.createHyena()); + final RunnerPost runnerPost = persistRunnerPost(runner); + final Supporter supporterDitoo = persistSupporter(MemberFixture.createDitoo()); + final SupporterRunnerPost supporterDitooRunnerPost = persistApplicant(supporterDitoo, runnerPost); + final Supporter supporterEthan = persistSupporter(MemberFixture.createEthan()); + final SupporterRunnerPost supporterEthanRunnerPost = persistApplicant(supporterEthan, runnerPost); + + // when + final List actual = supporterRunnerPostQueryRepository.readByRunnerPostId(runnerPost.getId()); + + // then + assertThat(actual).containsExactly(supporterDitooRunnerPost, supporterEthanRunnerPost); + } + + @DisplayName("SupporterId 와 Not Started 인 ReviewStatus 로 RunnerPost 개수를 센다.") + @Test + void countRunnerPostBySupporterIdByReviewStatusNotStarted() { + // given + final Runner runner = persistRunner(MemberFixture.createHyena()); + final RunnerPost runnerPost = persistRunnerPost(runner); + final Supporter supporter = persistSupporter(MemberFixture.createDitoo()); + persistApplicant(supporter, runnerPost); + + // when + final long count = supporterRunnerPostQueryRepository.countRunnerPostBySupporterIdByReviewStatusNotStarted(supporter.getId()); + + // then + assertThat(count).isEqualTo(1); + } +} diff --git a/backend/baton/src/test/java/touch/baton/domain/supporter/service/SupporterQueryServiceTest.java b/backend/baton/src/test/java/touch/baton/domain/supporter/query/service/SupporterQueryServiceTest.java similarity index 97% rename from backend/baton/src/test/java/touch/baton/domain/supporter/service/SupporterQueryServiceTest.java rename to backend/baton/src/test/java/touch/baton/domain/supporter/query/service/SupporterQueryServiceTest.java index 6ffe4712f..1d1b0aead 100644 --- a/backend/baton/src/test/java/touch/baton/domain/supporter/service/SupporterQueryServiceTest.java +++ b/backend/baton/src/test/java/touch/baton/domain/supporter/query/service/SupporterQueryServiceTest.java @@ -1,4 +1,4 @@ -package touch.baton.domain.supporter.service; +package touch.baton.domain.supporter.query.service; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; diff --git a/backend/baton/src/test/java/touch/baton/domain/supporter/repository/SupporterRunnerPostQueryRepositoryTest.java b/backend/baton/src/test/java/touch/baton/domain/supporter/repository/SupporterRunnerPostQueryRepositoryTest.java deleted file mode 100644 index 5c9ad6548..000000000 --- a/backend/baton/src/test/java/touch/baton/domain/supporter/repository/SupporterRunnerPostQueryRepositoryTest.java +++ /dev/null @@ -1,211 +0,0 @@ -package touch.baton.domain.supporter.repository; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import touch.baton.config.RepositoryTestConfig; -import touch.baton.domain.member.command.Member; -import touch.baton.domain.member.command.Runner; -import touch.baton.domain.member.command.Supporter; -import touch.baton.domain.member.command.SupporterRunnerPost; -import touch.baton.domain.member.command.repository.MemberCommandRepository; -import touch.baton.domain.member.command.vo.Message; -import touch.baton.domain.member.query.repository.RunnerQueryRepository; -import touch.baton.domain.member.query.repository.SupporterQueryRepository; -import touch.baton.domain.member.query.repository.SupporterRunnerPostQueryRepository; -import touch.baton.domain.runnerpost.command.RunnerPost; -import touch.baton.domain.runnerpost.command.vo.Deadline; -import touch.baton.domain.runnerpost.query.repository.RunnerPostQueryRepository; -import touch.baton.fixture.domain.MemberFixture; -import touch.baton.fixture.domain.RunnerFixture; -import touch.baton.fixture.domain.RunnerPostFixture; -import touch.baton.fixture.domain.SupporterFixture; -import touch.baton.fixture.domain.SupporterRunnerPostFixture; - -import java.time.LocalDateTime; -import java.util.List; - -import static java.time.LocalDateTime.now; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.SoftAssertions.assertSoftly; -import static touch.baton.fixture.vo.DeadlineFixture.deadline; - -class SupporterRunnerPostQueryRepositoryTest extends RepositoryTestConfig { - - @Autowired - private SupporterRunnerPostQueryRepository supporterRunnerPostRepository; - - @Autowired - private MemberCommandRepository memberCommandRepository; - - @Autowired - private RunnerQueryRepository runnerQueryRepository; - - @Autowired - private SupporterQueryRepository supporterQueryRepository; - - @Autowired - private RunnerPostQueryRepository runnerPostQueryRepository; - - @DisplayName("러너 게시글 식별자값으로 서포터가 지원한 수를 count 한다.") - @Test - void countByRunnerPostIdIn() { - // given - final Member savedMemberDitoo = memberCommandRepository.save(MemberFixture.createDitoo()); - final Runner savedRunnerDitoo = runnerQueryRepository.save(RunnerFixture.createRunner(savedMemberDitoo)); - - final Member savedMemberHyena = memberCommandRepository.save(MemberFixture.createDitoo()); - final Supporter savedSupporterHyena = supporterQueryRepository.save(SupporterFixture.create(savedMemberHyena)); - - final RunnerPost savedRunnerPostOne = runnerPostQueryRepository.save(RunnerPostFixture.create(savedRunnerDitoo, new Deadline(now().plusHours(100)))); - final RunnerPost savedRunnerPostTwo = runnerPostQueryRepository.save(RunnerPostFixture.create(savedRunnerDitoo, new Deadline(now().plusHours(100)))); - final RunnerPost savedRunnerPostThree = runnerPostQueryRepository.save(RunnerPostFixture.create(savedRunnerDitoo, new Deadline(now().plusHours(100)))); - final RunnerPost savedRunnerPostFour = runnerPostQueryRepository.save(RunnerPostFixture.create(savedRunnerDitoo, new Deadline(now().plusHours(100)))); - - savedRunnerPostOne.assignSupporter(savedSupporterHyena); - savedRunnerPostTwo.assignSupporter(savedSupporterHyena); - savedRunnerPostThree.assignSupporter(savedSupporterHyena); - savedRunnerPostFour.assignSupporter(savedSupporterHyena); - - supporterRunnerPostRepository.save(createSupporterRunnerPost(savedSupporterHyena, savedRunnerPostOne)); - supporterRunnerPostRepository.save(createSupporterRunnerPost(savedSupporterHyena, savedRunnerPostTwo)); - supporterRunnerPostRepository.save(createSupporterRunnerPost(savedSupporterHyena, savedRunnerPostThree)); - supporterRunnerPostRepository.save(createSupporterRunnerPost(savedSupporterHyena, savedRunnerPostFour)); - - // when - final List runnerPostIds = List.of( - savedRunnerPostOne.getId(), - savedRunnerPostTwo.getId(), - savedRunnerPostThree.getId(), - savedRunnerPostFour.getId() - ); - final List foundRunnerPostsApplicantCounts = supporterRunnerPostRepository.countByRunnerPostIdIn(runnerPostIds); - - // then - assertThat(foundRunnerPostsApplicantCounts).containsExactly(1L, 1L, 1L, 1L); - } - - private SupporterRunnerPost createSupporterRunnerPost(final Supporter supporter, final RunnerPost runnerPost) { - return SupporterRunnerPost.builder() - .runnerPost(runnerPost) - .supporter(supporter) - .message(new Message("안녕하세요. 서포터 헤나입니다.")) - .build(); - } - - @DisplayName("Member 가 SupporterRunnerPost 에 지원한 이력이 있을 경우 true 를 반환한다.") - @Test - void existsByRunnerPostIdAndMemberId_return_true() { - // given - final Member savedMemberDitoo = memberCommandRepository.save(MemberFixture.createDitoo()); - final Runner savedRunnerDitoo = runnerQueryRepository.save(RunnerFixture.createRunner(savedMemberDitoo)); - - final Member savedMemberHyena = memberCommandRepository.save(MemberFixture.createHyena()); - final Supporter savedSupporterHyena = supporterQueryRepository.save(SupporterFixture.create(savedMemberHyena)); - - final RunnerPost savedRunnerPost = runnerPostQueryRepository.save(RunnerPostFixture.create(savedRunnerDitoo, new Deadline(now().plusHours(100)))); - - final SupporterRunnerPost runnerPostApplicant = createSupporterRunnerPost(savedSupporterHyena, savedRunnerPost); - supporterRunnerPostRepository.save(runnerPostApplicant); - - // when - final Long notExistMemberId = -1L; - final boolean isApplicantHistoryExist = supporterRunnerPostRepository.existsByRunnerPostIdAndMemberId( - savedRunnerPost.getId(), - savedMemberHyena.getId() - ); - - // then - assertThat(isApplicantHistoryExist).isTrue(); - } - - @DisplayName("Member 가 SupporterRunnerPost 에 지원한 이력이 없을 경우 false 를 반환한다.") - @Test - void existsByRunnerPostIdAndMemberId_if_supporterRunnerPost_is_not_exist_then_return_false() { - // given - final Member savedMemberDitoo = memberCommandRepository.save(MemberFixture.createDitoo()); - final Runner savedRunnerDitoo = runnerQueryRepository.save(RunnerFixture.createRunner(savedMemberDitoo)); - - final Member savedMemberHyena = memberCommandRepository.save(MemberFixture.createHyena()); - - final RunnerPost savedRunnerPost = runnerPostQueryRepository.save(RunnerPostFixture.create(savedRunnerDitoo, new Deadline(now().plusHours(100)))); - - // when - final boolean isApplicantHistoryNotExist = supporterRunnerPostRepository.existsByRunnerPostIdAndMemberId( - savedRunnerPost.getId(), - savedMemberHyena.getId() - ); - - // then - assertThat(isApplicantHistoryNotExist).isFalse(); - } - - @DisplayName("Member 가 SupporterRunnerPost 에 지원한 이력을 조회할 때 RunnerPost 자체가 없으면 false 를 반환한다.") - @Test - void existsByRunnerPostIdAndMemberId_if_runnerPost_is_not_exist_then_return_false() { - // given - final Member savedMemberHyena = memberCommandRepository.save(MemberFixture.createDitoo()); - - // when - final Long notExistRunnerPostId = -1L; - final boolean isApplicantHistoryNotExist = supporterRunnerPostRepository.existsByRunnerPostIdAndMemberId( - notExistRunnerPostId, - savedMemberHyena.getId() - ); - - // then - assertThat(isApplicantHistoryNotExist).isFalse(); - } - - @DisplayName("RunnerPost 외래키로 된 SupporterRunnerPost 가 존재하는지 확인한다.") - @Test - void existsByRunnerPostId() { - // given - final Member savedMemberDitoo = memberCommandRepository.save(MemberFixture.createDitoo()); - final Runner savedRunnerDitoo = runnerQueryRepository.save(RunnerFixture.createRunner(savedMemberDitoo)); - - final Member savedMemberHyena = memberCommandRepository.save(MemberFixture.createDitoo()); - final Supporter savedSupporterHyena = supporterQueryRepository.save(SupporterFixture.create(savedMemberHyena)); - - final RunnerPost runnerPostOfApplicantExist = runnerPostQueryRepository.save(RunnerPostFixture.create(savedRunnerDitoo, new Deadline(now().plusHours(100)))); - final RunnerPost runnerPostOfApplicantNotExist = runnerPostQueryRepository.save(RunnerPostFixture.create(savedRunnerDitoo, new Deadline(now().plusHours(100)))); - runnerPostOfApplicantExist.assignSupporter(savedSupporterHyena); - supporterRunnerPostRepository.save(createSupporterRunnerPost(savedSupporterHyena, runnerPostOfApplicantExist)); - - // when - final boolean actualOfExist = supporterRunnerPostRepository.existsByRunnerPostId(runnerPostOfApplicantExist.getId()); - final boolean actualOfNotExist = supporterRunnerPostRepository.existsByRunnerPostId(runnerPostOfApplicantNotExist.getId()); - - // then - assertSoftly(softly -> { - softly.assertThat(actualOfExist).isTrue(); - softly.assertThat(actualOfNotExist).isFalse(); - }); - } - - @DisplayName("서포터의 러너 게시글 리뷰 제안을 철회하는데 성공한다") - @Test - void deleteBySupporterAndRunnerPostId() { - // given - final Member reviewerMember = memberCommandRepository.save(MemberFixture.createDitoo()); - final Supporter reviewerSupporter = supporterQueryRepository.save(SupporterFixture.create(reviewerMember)); - - final Member revieweeMember = memberCommandRepository.save(MemberFixture.createJudy()); - final Runner revieweeRunner = runnerQueryRepository.save(RunnerFixture.createRunner(revieweeMember)); - - final RunnerPost runnerPost = runnerPostQueryRepository.save(RunnerPostFixture.create( - revieweeRunner, - reviewerSupporter, - deadline(LocalDateTime.now().plusHours(100)) - )); - - final SupporterRunnerPost deletedSupporterRunnerPost = supporterRunnerPostRepository.save( - SupporterRunnerPostFixture.create(runnerPost, reviewerSupporter)); - - // when - supporterRunnerPostRepository.deleteBySupporterIdAndRunnerPostId(reviewerSupporter.getId(), runnerPost.getId()); - - // then - assertThat(supporterRunnerPostRepository.findById(deletedSupporterRunnerPost.getId())).isNotPresent(); - } -} diff --git a/backend/baton/src/test/java/touch/baton/domain/tag/RunnerPostTagTest.java b/backend/baton/src/test/java/touch/baton/domain/tag/command/RunnerPostTagTest.java similarity index 96% rename from backend/baton/src/test/java/touch/baton/domain/tag/RunnerPostTagTest.java rename to backend/baton/src/test/java/touch/baton/domain/tag/command/RunnerPostTagTest.java index c9ca1728e..3742f29ae 100644 --- a/backend/baton/src/test/java/touch/baton/domain/tag/RunnerPostTagTest.java +++ b/backend/baton/src/test/java/touch/baton/domain/tag/command/RunnerPostTagTest.java @@ -1,4 +1,4 @@ -package touch.baton.domain.tag; +package touch.baton.domain.tag.command; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; @@ -23,9 +23,6 @@ import touch.baton.domain.runnerpost.command.vo.ReviewStatus; import touch.baton.domain.runnerpost.command.vo.Title; import touch.baton.domain.runnerpost.command.vo.WatchedCount; -import touch.baton.domain.tag.command.RunnerPostTag; -import touch.baton.domain.tag.command.RunnerPostTags; -import touch.baton.domain.tag.command.Tag; import touch.baton.domain.tag.exception.RunnerPostTagDomainException; import touch.baton.domain.technicaltag.command.SupporterTechnicalTags; import touch.baton.fixture.domain.RunnerTechnicalTagsFixture; diff --git a/backend/baton/src/test/java/touch/baton/domain/tag/RunnerPostTagsTest.java b/backend/baton/src/test/java/touch/baton/domain/tag/command/RunnerPostTagsTest.java similarity index 92% rename from backend/baton/src/test/java/touch/baton/domain/tag/RunnerPostTagsTest.java rename to backend/baton/src/test/java/touch/baton/domain/tag/command/RunnerPostTagsTest.java index 08f83ab30..598c3ee51 100644 --- a/backend/baton/src/test/java/touch/baton/domain/tag/RunnerPostTagsTest.java +++ b/backend/baton/src/test/java/touch/baton/domain/tag/command/RunnerPostTagsTest.java @@ -1,4 +1,4 @@ -package touch.baton.domain.tag; +package touch.baton.domain.tag.command; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -11,9 +11,6 @@ import touch.baton.domain.member.command.vo.OauthId; import touch.baton.domain.member.command.vo.SocialId; import touch.baton.domain.runnerpost.command.RunnerPost; -import touch.baton.domain.tag.command.RunnerPostTag; -import touch.baton.domain.tag.command.RunnerPostTags; -import touch.baton.domain.tag.command.Tag; import touch.baton.fixture.domain.RunnerTechnicalTagsFixture; import java.time.LocalDateTime; diff --git a/backend/baton/src/test/java/touch/baton/domain/tag/TagTest.java b/backend/baton/src/test/java/touch/baton/domain/tag/command/TagTest.java similarity index 97% rename from backend/baton/src/test/java/touch/baton/domain/tag/TagTest.java rename to backend/baton/src/test/java/touch/baton/domain/tag/command/TagTest.java index e57d9c1a0..f2bec9b19 100644 --- a/backend/baton/src/test/java/touch/baton/domain/tag/TagTest.java +++ b/backend/baton/src/test/java/touch/baton/domain/tag/command/TagTest.java @@ -1,4 +1,4 @@ -package touch.baton.domain.tag; +package touch.baton.domain.tag.command; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; diff --git a/backend/baton/src/test/java/touch/baton/domain/tag/vo/TagReducedNameTest.java b/backend/baton/src/test/java/touch/baton/domain/tag/command/vo/TagReducedNameTest.java similarity index 94% rename from backend/baton/src/test/java/touch/baton/domain/tag/vo/TagReducedNameTest.java rename to backend/baton/src/test/java/touch/baton/domain/tag/command/vo/TagReducedNameTest.java index 550e2d137..a26810c05 100644 --- a/backend/baton/src/test/java/touch/baton/domain/tag/vo/TagReducedNameTest.java +++ b/backend/baton/src/test/java/touch/baton/domain/tag/command/vo/TagReducedNameTest.java @@ -1,8 +1,7 @@ -package touch.baton.domain.tag.vo; +package touch.baton.domain.tag.command.vo; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import touch.baton.domain.tag.command.vo.TagReducedName; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; diff --git a/backend/baton/src/test/java/touch/baton/domain/tag/repository/RunnerPostTagQueryRepositoryTest.java b/backend/baton/src/test/java/touch/baton/domain/tag/query/repository/RunnerPostTagQueryRepositoryTest.java similarity index 94% rename from backend/baton/src/test/java/touch/baton/domain/tag/repository/RunnerPostTagQueryRepositoryTest.java rename to backend/baton/src/test/java/touch/baton/domain/tag/query/repository/RunnerPostTagQueryRepositoryTest.java index 40916fe5a..ba2e2837d 100644 --- a/backend/baton/src/test/java/touch/baton/domain/tag/repository/RunnerPostTagQueryRepositoryTest.java +++ b/backend/baton/src/test/java/touch/baton/domain/tag/query/repository/RunnerPostTagQueryRepositoryTest.java @@ -1,4 +1,4 @@ -package touch.baton.domain.tag.repository; +package touch.baton.domain.tag.query.repository; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -8,7 +8,6 @@ import touch.baton.domain.runnerpost.command.RunnerPost; import touch.baton.domain.tag.command.RunnerPostTag; import touch.baton.domain.tag.command.Tag; -import touch.baton.domain.tag.query.repository.RunnerPostTagQueryRepository; import touch.baton.fixture.domain.MemberFixture; import java.util.List; diff --git a/backend/baton/src/test/java/touch/baton/domain/tag/query/repository/TagQuerydslRepositoryTest.java b/backend/baton/src/test/java/touch/baton/domain/tag/query/repository/TagQuerydslRepositoryTest.java new file mode 100644 index 000000000..19c05e202 --- /dev/null +++ b/backend/baton/src/test/java/touch/baton/domain/tag/query/repository/TagQuerydslRepositoryTest.java @@ -0,0 +1,103 @@ +package touch.baton.domain.tag.query.repository; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import touch.baton.config.RepositoryTestConfig; +import touch.baton.domain.common.vo.TagName; +import touch.baton.domain.tag.command.Tag; +import touch.baton.domain.tag.command.vo.TagReducedName; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +class TagQuerydslRepositoryTest extends RepositoryTestConfig { + + @Autowired + private TagQuerydslRepository tagQuerydslRepository; + + @DisplayName("축약된 태그 이름으로 태그 목록을 limit 개 축약된 태그 이름 기준 오름차순으로 검색한다.") + @Test + void readTagsByTagReducedName() { + // given + for (int saveTagCount = 1; saveTagCount <= 3; saveTagCount++) { + persistTag("java" + saveTagCount); + persistTag("javascript" + saveTagCount); + persistTag("assertj" + saveTagCount); + } + for (int saveTagCount = 4; saveTagCount <= 6; saveTagCount++) { + persistTag("j ava" + saveTagCount); + persistTag("j avascript" + saveTagCount); + persistTag("a ssertj" + saveTagCount); + } + for (int saveTagCount = 7; saveTagCount <= 10; saveTagCount++) { + persistTag("ja va" + saveTagCount); + persistTag("ja vascript" + saveTagCount); + persistTag("as sertj" + saveTagCount); + } + + em.flush(); + em.close(); + + // when + final List actual = tagQuerydslRepository.findByTagReducedName(TagReducedName.from("j"), 10); + + // then + final List actualSortedTagNames = actual.stream() + .map(Tag::getTagName) + .map(TagName::getValue) + .toList(); + + assertThat(actualSortedTagNames).containsExactly( + "java1", "ja va10", "java2", "java3", "j ava4", "j ava5", "j ava6", "ja va7", "ja va8", "ja va9" + ); + } + + @DisplayName("입력된 TagReducedName 으로 시작하는 태그만 검색한다") + @Test + void success_readTagsByReducedName_when_name_isNotMatched_atAll() { + // given + persistTag("assertj"); + + em.flush(); + em.close(); + + // when + final TagReducedName tagReducedName = TagReducedName.nullableInstance("j"); + final List actual = tagQuerydslRepository.findByTagReducedName(tagReducedName, 10); + + // then + assertThat(actual.isEmpty()).isTrue(); + } + + @DisplayName("입력된 TagReducedName 으로 시작하는 이름을 갖는 태그가 없다면 빈 목록을 반환한다.") + @Test + void success_readTagsByReducedName_when_foundTags_isEmpty() { + // given + persistTag("aaaaaaaaa"); + + em.flush(); + em.close(); + + // when + final TagReducedName tagReducedName = TagReducedName.nullableInstance("b"); + final List actual = tagQuerydslRepository.findByTagReducedName(tagReducedName, 10); + + // then + assertThat(actual.isEmpty()).isTrue(); + } + + @DisplayName("TagReducedName 내부 값이 blank 인 경우 빈 목록을 반환한다.") + @Test + void success_readTagsByReducedName_when_tagReducedNameIsBlank() { + // given + final TagReducedName tagReducedName = TagReducedName.nullableInstance(""); + + // when + final List actual = tagQuerydslRepository.findByTagReducedName(tagReducedName, 10); + + // then + assertThat(actual.isEmpty()).isTrue(); + } +} diff --git a/backend/baton/src/test/java/touch/baton/domain/tag/query/service/TagQueryServiceTest.java b/backend/baton/src/test/java/touch/baton/domain/tag/query/service/TagQueryServiceTest.java new file mode 100644 index 000000000..eba2b23bd --- /dev/null +++ b/backend/baton/src/test/java/touch/baton/domain/tag/query/service/TagQueryServiceTest.java @@ -0,0 +1,77 @@ +package touch.baton.domain.tag.query.service; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import touch.baton.config.ServiceTestConfig; +import touch.baton.domain.tag.command.Tag; +import touch.baton.domain.tag.command.vo.TagReducedName; +import touch.baton.fixture.domain.TagFixture; +import touch.baton.fixture.vo.TagNameFixture; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.SoftAssertions.assertSoftly; + +class TagQueryServiceTest extends ServiceTestConfig { + + private TagQueryService tagQueryService; + + @BeforeEach + void setUp() { + tagQueryService = new TagQueryService(tagQuerydslRepository); + } + + @DisplayName("Tag의 이름으로 Tag를 오름차순으로 10개 조회한다.") + @Test + void success_readTagsByReducedName() { + // given + tagCommandRepository.save(TagFixture.create(TagNameFixture.tagName("ja va"))); + tagCommandRepository.save(TagFixture.create(TagNameFixture.tagName("jav a1"))); + tagCommandRepository.save(TagFixture.create(TagNameFixture.tagName("j ava2"))); + tagCommandRepository.save(TagFixture.create(TagNameFixture.tagName("ja va3"))); + tagCommandRepository.save(TagFixture.create(TagNameFixture.tagName("jav a4"))); + tagCommandRepository.save(TagFixture.create(TagNameFixture.tagName("java 5"))); + tagCommandRepository.save(TagFixture.create(TagNameFixture.tagName("j ava6"))); + tagCommandRepository.save(TagFixture.create(TagNameFixture.tagName("ja va7"))); + tagCommandRepository.save(TagFixture.create(TagNameFixture.tagName("jav a8"))); + tagCommandRepository.save(TagFixture.create(TagNameFixture.tagName("java 9"))); + tagCommandRepository.save(TagFixture.create(TagNameFixture.tagName("ju ja"))); + + // when + final TagReducedName tagReducedName = TagReducedName.nullableInstance("j a"); + final List actual = tagQueryService.readTagsByReducedName(tagReducedName, 10); + + // then + assertSoftly(softly -> { + softly.assertThat(actual).hasSize(10); + softly.assertThat(actual.get(0).getTagName().getValue()).isEqualTo("ja va"); + softly.assertThat(actual.get(9).getTagName().getValue()).isEqualTo("java 9"); + }); + } + + @DisplayName("TagReducedName 이 null 인 경우 빈 목록을 반환한다.") + @Test + void success_when_TagReducedName_IsNull() { + // given + tagCommandRepository.save(TagFixture.create(TagNameFixture.tagName("ja va"))); + tagCommandRepository.save(TagFixture.create(TagNameFixture.tagName("jav a1"))); + tagCommandRepository.save(TagFixture.create(TagNameFixture.tagName("j ava2"))); + tagCommandRepository.save(TagFixture.create(TagNameFixture.tagName("ja va3"))); + tagCommandRepository.save(TagFixture.create(TagNameFixture.tagName("jav a4"))); + tagCommandRepository.save(TagFixture.create(TagNameFixture.tagName("java 5"))); + tagCommandRepository.save(TagFixture.create(TagNameFixture.tagName("j ava6"))); + tagCommandRepository.save(TagFixture.create(TagNameFixture.tagName("ja va7"))); + tagCommandRepository.save(TagFixture.create(TagNameFixture.tagName("jav a8"))); + tagCommandRepository.save(TagFixture.create(TagNameFixture.tagName("java 9"))); + tagCommandRepository.save(TagFixture.create(TagNameFixture.tagName("ju ja"))); + + // when + final TagReducedName nullTagReducedName = null; + final List actual = tagQueryService.readTagsByReducedName(nullTagReducedName, 10); + + // then + assertThat(actual).isEmpty(); + } +} diff --git a/backend/baton/src/test/java/touch/baton/domain/tag/repository/TagQueryRepositoryReadTest.java b/backend/baton/src/test/java/touch/baton/domain/tag/repository/TagQueryRepositoryReadTest.java deleted file mode 100644 index 8cce780ce..000000000 --- a/backend/baton/src/test/java/touch/baton/domain/tag/repository/TagQueryRepositoryReadTest.java +++ /dev/null @@ -1,104 +0,0 @@ -package touch.baton.domain.tag.repository; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import touch.baton.config.RepositoryTestConfig; -import touch.baton.domain.tag.command.Tag; -import touch.baton.domain.tag.command.vo.TagReducedName; -import touch.baton.domain.tag.query.repository.TagQueryRepository; -import touch.baton.fixture.domain.TagFixture; -import touch.baton.fixture.vo.TagNameFixture; - -import java.util.List; -import java.util.Optional; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.SoftAssertions.assertSoftly; - -class TagQueryRepositoryReadTest extends RepositoryTestConfig { - - @Autowired - private TagQueryRepository tagQueryRepository; - - @DisplayName("이름으로 단건 검색한다.") - @Test - void findByName() { - // given - final Tag javaTag = persistTag("java"); - final Tag uppercaseJavaTag = persistTag("Java"); - - em.flush(); - em.close(); - - // when - final Optional actual = tagQueryRepository.findByTagName(TagNameFixture.tagName("java")); - - // then - assertThat(actual).contains(javaTag); - } - - @DisplayName("이름을 오름차순으로 10개 검색한다.") - @Test - void success_readTagsByReducedName() { - // given - persistTag("ja va"); - persistTag("j ava1"); - persistTag("ja va2"); - persistTag("jav a3"); - persistTag("java 4"); - persistTag("ja va5"); - persistTag("j ava6"); - persistTag("ja va7"); - persistTag("jav a8"); - persistTag("java 9"); - persistTag("assert ja"); - - em.flush(); - em.close(); - - // when - final TagReducedName reducedName = TagReducedName.from("ja"); - final List actual = tagQueryRepository.readTagsByReducedName(reducedName); - - // then - assertSoftly(softly -> { - softly.assertThat(actual).hasSize(10); - softly.assertThat(actual.get(0).getTagName().getValue()).isEqualTo("ja va"); - softly.assertThat(actual.get(9).getTagName().getValue()).isEqualTo("java 9"); - }); - - } - - @DisplayName("이름으로 시작하는 태그만 검색한다") - @Test - void fail_readTagsByReducedName() { - // given - final Tag tag = TagFixture.create(TagNameFixture.tagName("assertj")); - final TagReducedName reducedName = TagReducedName.from("j"); - tagQueryRepository.save(tag); - - // when - final List actual = tagQueryRepository.readTagsByReducedName(reducedName); - - // then - assertThat(actual.isEmpty()).isTrue(); - } - - @DisplayName("이름에 해당하는 태그가 없다면 빈 배열을 반환한다.") - @Test - void success_readTagsByReducedName_when_no_match_tag() { - // given - final TagReducedName reducedName = TagReducedName.from("hi"); - persistTag("hellohi"); - - em.flush(); - em.close(); - - // when - final List actual = tagQueryRepository.readTagsByReducedName(reducedName); - - // then - assertThat(actual.isEmpty()).isTrue(); - } -} diff --git a/backend/baton/src/test/java/touch/baton/domain/tag/service/TagQueryServiceReadTest.java b/backend/baton/src/test/java/touch/baton/domain/tag/service/TagQueryServiceReadTest.java deleted file mode 100644 index 317eb9e65..000000000 --- a/backend/baton/src/test/java/touch/baton/domain/tag/service/TagQueryServiceReadTest.java +++ /dev/null @@ -1,51 +0,0 @@ -package touch.baton.domain.tag.service; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import touch.baton.config.ServiceTestConfig; -import touch.baton.domain.tag.command.Tag; -import touch.baton.domain.tag.query.service.TagQueryService; -import touch.baton.fixture.domain.TagFixture; -import touch.baton.fixture.vo.TagNameFixture; - -import java.util.List; - -import static org.assertj.core.api.SoftAssertions.assertSoftly; - -class TagQueryServiceReadTest extends ServiceTestConfig { - - private TagQueryService tagQueryService; - - @BeforeEach - void setUp() { - tagQueryService = new TagQueryService(tagQueryRepository); - } - - @DisplayName("Tag의 이름으로 Tag를 오름차순으로 10개 조회한다.") - @Test - void success_readTagsByReducedName() { - // given - tagQueryRepository.save(TagFixture.create(TagNameFixture.tagName("ja va"))); - tagQueryRepository.save(TagFixture.create(TagNameFixture.tagName("jav a1"))); - tagQueryRepository.save(TagFixture.create(TagNameFixture.tagName("j ava2"))); - tagQueryRepository.save(TagFixture.create(TagNameFixture.tagName("ja va3"))); - tagQueryRepository.save(TagFixture.create(TagNameFixture.tagName("jav a4"))); - tagQueryRepository.save(TagFixture.create(TagNameFixture.tagName("java 5"))); - tagQueryRepository.save(TagFixture.create(TagNameFixture.tagName("j ava6"))); - tagQueryRepository.save(TagFixture.create(TagNameFixture.tagName("ja va7"))); - tagQueryRepository.save(TagFixture.create(TagNameFixture.tagName("jav a8"))); - tagQueryRepository.save(TagFixture.create(TagNameFixture.tagName("java 9"))); - tagQueryRepository.save(TagFixture.create(TagNameFixture.tagName("ju ja"))); - - // when - final List actual = tagQueryService.readTagsByReducedName("j a"); - - // then - assertSoftly(softly -> { - softly.assertThat(actual).hasSize(10); - softly.assertThat(actual.get(0).getTagName().getValue()).isEqualTo("ja va"); - softly.assertThat(actual.get(9).getTagName().getValue()).isEqualTo("java 9"); - }); - } -}