From c911f9b9c55f91be8270f148a7bb1dc6c11fbce8 Mon Sep 17 00:00:00 2001 From: wlsh44 Date: Thu, 25 Sep 2025 09:38:14 +0900 Subject: [PATCH 1/3] =?UTF-8?q?fix:=20=EC=9C=A0=EC=A0=80=EA=B0=80=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1=ED=95=9C=20=ED=88=AC=ED=91=9C=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EB=93=9D=ED=91=9C=EC=9C=A8=20=EC=98=A4=EB=A5=98=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../persistence/PostQueryDslRepository.java | 2 +- .../application/PostQueryServiceTest.java | 149 ++++++++++++++---- 2 files changed, 117 insertions(+), 34 deletions(-) diff --git a/src/main/java/com/chooz/post/persistence/PostQueryDslRepository.java b/src/main/java/com/chooz/post/persistence/PostQueryDslRepository.java index 9f6d6fe..e2ad17b 100644 --- a/src/main/java/com/chooz/post/persistence/PostQueryDslRepository.java +++ b/src/main/java/com/chooz/post/persistence/PostQueryDslRepository.java @@ -122,7 +122,7 @@ public Slice findPostsWithVoteCountByUserId(Long userId, Long .select(new QPostWithVoteCount( post, JPAExpressions - .select(vote.userId.countDistinct()) + .select(vote.userId.count()) .from(vote) .where( vote.postId.eq(post.id), diff --git a/src/test/java/com/chooz/post/application/PostQueryServiceTest.java b/src/test/java/com/chooz/post/application/PostQueryServiceTest.java index d071888..4714a04 100644 --- a/src/test/java/com/chooz/post/application/PostQueryServiceTest.java +++ b/src/test/java/com/chooz/post/application/PostQueryServiceTest.java @@ -126,6 +126,89 @@ void findUserPosts2() throws Exception { ); } + @Test + @DisplayName("유저가 작성한 게시글 조회 - 중복 투표") + void findUserPosts_multiple() { + //given + User user = userRepository.save(UserFixture.createDefaultUser()); + Post post1 = postRepository.save(PostFixture.createPostBuilder() + .userId(user.getId()) + .pollOption(PostFixture.multiplePollOption()) + .build()); + Post post2 = postRepository.save(PostFixture.createPostBuilder() + .userId(user.getId()) + .pollOption(PostFixture.multiplePollOption()) + .build()); + //유저1 게시글1 선택지 1, 2 복수 투표 + voteRepository.save(VoteFixture.createDefaultVote(user.getId(), post1.getId(), post1.getPollChoices().get(0).getId())); + voteRepository.save(VoteFixture.createDefaultVote(user.getId(), post1.getId(), post1.getPollChoices().get(1).getId())); + + //유저1 게시글2 선택지 1 단일 투표 + voteRepository.save(VoteFixture.createDefaultVote(user.getId(), post2.getId(), post2.getPollChoices().get(0).getId())); + + //when + var response = postService.findUserPosts(user.getId(), null, 10); + + //then + List data = response.data(); + assertAll( + () -> assertThat(response.data()).hasSize(2), + () -> assertThat(response.hasNext()).isFalse(), + + () -> assertThat(data.getFirst().id()).isEqualTo(post2.getId()), + () -> assertThat(data.getFirst().title()).isEqualTo(post2.getTitle()), + + () -> assertThat(data.getFirst().postVoteInfo().mostVotedPollChoice().title()).isEqualTo(post2.getPollChoices().get(0).getTitle()), + () -> assertThat(data.getFirst().postVoteInfo().totalVoterCount()).isEqualTo(1), + () -> assertThat(data.getFirst().postVoteInfo().mostVotedPollChoice().voteCount()).isEqualTo(1), + () -> assertThat(data.getFirst().postVoteInfo().mostVotedPollChoice().voteRatio()).isEqualTo("100"), + + () -> assertThat(data.get(1).id()).isEqualTo(post1.getId()), + () -> assertThat(data.get(1).title()).isEqualTo(post1.getTitle()), + + () -> assertThat(data.get(1).postVoteInfo().mostVotedPollChoice().title()).isEqualTo(post1.getPollChoices().get(0).getTitle()), + () -> assertThat(data.get(1).postVoteInfo().totalVoterCount()).isEqualTo(2), + () -> assertThat(data.get(1).postVoteInfo().mostVotedPollChoice().voteCount()).isEqualTo(1), + () -> assertThat(data.get(1).postVoteInfo().mostVotedPollChoice().voteRatio()).isEqualTo("50") + ); + } + + @Test + @DisplayName("유저가 작성한 게시글 조회 - 중복 투표2") + void findUserPosts_multiple2() { + //given + User user = userRepository.save(UserFixture.createDefaultUser()); + User user2 = userRepository.save(UserFixture.createDefaultUser()); + Post post = postRepository.save(PostFixture.createPostBuilder() + .userId(user.getId()) + .pollOption(PostFixture.multiplePollOption()) + .build()); + //유저1 선택지 1, 2 복수 투표 + voteRepository.save(VoteFixture.createDefaultVote(user.getId(), post.getId(), post.getPollChoices().get(0).getId())); + voteRepository.save(VoteFixture.createDefaultVote(user.getId(), post.getId(), post.getPollChoices().get(1).getId())); + + //유저2 선택지 1 단일 투표 + voteRepository.save(VoteFixture.createDefaultVote(user.getId(), post.getId(), post.getPollChoices().get(0).getId())); + + //when + var response = postService.findUserPosts(user.getId(), null, 10); + + //then + List data = response.data(); + assertAll( + () -> assertThat(response.data()).hasSize(1), + () -> assertThat(response.hasNext()).isFalse(), + + () -> assertThat(data.getFirst().id()).isEqualTo(post.getId()), + () -> assertThat(data.getFirst().title()).isEqualTo(post.getTitle()), + + () -> assertThat(data.getFirst().postVoteInfo().mostVotedPollChoice().title()).isEqualTo(post.getPollChoices().get(0).getTitle()), + () -> assertThat(data.getFirst().postVoteInfo().totalVoterCount()).isEqualTo(3), + () -> assertThat(data.getFirst().postVoteInfo().mostVotedPollChoice().voteCount()).isEqualTo(2), + () -> assertThat(data.getFirst().postVoteInfo().mostVotedPollChoice().voteRatio()).isEqualTo("67") + ); + } + @Test @DisplayName("유저가 투표한 게시글 조회 - 커서 null인 경우") void findVotedPosts() throws Exception { @@ -151,38 +234,7 @@ void findVotedPosts() throws Exception { } @Test - @DisplayName("피드 조회 - 내 게시글 1개, 공개 게시글 15개, 투표 10개, 댓글 20개") - void findFeed() throws Exception { - //given - int size = 20; - User user1 = userRepository.save(createUserBuilder().build()); - User user2 = userRepository.save(createUserBuilder().build()); - - List publicPosts = createPostsWithScope(user2, Scope.PUBLIC, 15); - createPostsWithScope(user2, Scope.PRIVATE, 3); - Post myPost = postRepository.save(createPostBuilder().userId(user1.getId()).build()); - - createVotes(user1, publicPosts.getFirst(), 10); - createComments(user1, publicPosts.getFirst(), 20); - - List publicPostVotes = voteRepository.findByPostIdAndDeletedFalse(publicPosts.getFirst().getId()); - List publicPostComments = commentRepository.findByPostIdAndDeletedFalse(publicPosts.getFirst().getId()); - - //when - CursorBasePaginatedResponse response = postService.findFeed(user1.getId(), null, size); - - //then - assertAll( - () -> assertThat(response.data().size()).isEqualTo(16), - () -> assertThat(response.data().getLast().voterCount()).isEqualTo(1), - () -> assertThat(response.data().getLast().commentCount()).isEqualTo(publicPostComments.size()), - () -> assertThat(response.data().getLast().isAuthor()).isFalse(), - () -> assertThat(response.data().getFirst().isAuthor()).isTrue() - ); - } - - @Test - @DisplayName("투표 현황 조회 - 중복 투표") + @DisplayName("유저가 투표한 게시글 조회 - 중복 투표") void findVotedPosts_multiple() { //given User user = userRepository.save(UserFixture.createDefaultUser()); @@ -214,7 +266,7 @@ void findVotedPosts_multiple() { } @Test - @DisplayName("투표 현황 조회 - 중복 투표2") + @DisplayName("유저가 투표한 게시글 조회 - 중복 투표2") void findVotedPosts_multiple2() { //given User user = userRepository.save(UserFixture.createDefaultUser()); @@ -249,6 +301,37 @@ void findVotedPosts_multiple2() { ); } + @Test + @DisplayName("피드 조회 - 내 게시글 1개, 공개 게시글 15개, 투표 10개, 댓글 20개") + void findFeed() throws Exception { + //given + int size = 20; + User user1 = userRepository.save(createUserBuilder().build()); + User user2 = userRepository.save(createUserBuilder().build()); + + List publicPosts = createPostsWithScope(user2, Scope.PUBLIC, 15); + createPostsWithScope(user2, Scope.PRIVATE, 3); + Post myPost = postRepository.save(createPostBuilder().userId(user1.getId()).build()); + + createVotes(user1, publicPosts.getFirst(), 10); + createComments(user1, publicPosts.getFirst(), 20); + + List publicPostVotes = voteRepository.findByPostIdAndDeletedFalse(publicPosts.getFirst().getId()); + List publicPostComments = commentRepository.findByPostIdAndDeletedFalse(publicPosts.getFirst().getId()); + + //when + CursorBasePaginatedResponse response = postService.findFeed(user1.getId(), null, size); + + //then + assertAll( + () -> assertThat(response.data().size()).isEqualTo(16), + () -> assertThat(response.data().getLast().voterCount()).isEqualTo(1), + () -> assertThat(response.data().getLast().commentCount()).isEqualTo(publicPostComments.size()), + () -> assertThat(response.data().getLast().isAuthor()).isFalse(), + () -> assertThat(response.data().getFirst().isAuthor()).isTrue() + ); + } + private List createPosts(User user, int size) { List posts = new ArrayList<>(); for (int i = 0; i < size; i ++) { From 324ecb9f332dcd3e7c3fd1c1174d8693305b8542 Mon Sep 17 00:00:00 2001 From: wlsh44 Date: Thu, 25 Sep 2025 09:55:41 +0900 Subject: [PATCH 2/3] =?UTF-8?q?fix:=20=EC=8B=9C=EA=B0=84=20=EB=A7=88?= =?UTF-8?q?=EA=B0=90=2059=EB=B6=84=20=EC=A0=9C=ED=95=9C=EC=9C=BC=EB=A1=9C?= =?UTF-8?q?=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/chooz/post/domain/CloseOption.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/chooz/post/domain/CloseOption.java b/src/main/java/com/chooz/post/domain/CloseOption.java index d1f3dcc..2e15628 100644 --- a/src/main/java/com/chooz/post/domain/CloseOption.java +++ b/src/main/java/com/chooz/post/domain/CloseOption.java @@ -59,7 +59,7 @@ private static void validateVoterCloseType(Integer maxVoterCount) { } private static void validateDateCloseType(LocalDateTime closedAt) { - if (Objects.isNull(closedAt) || closedAt.isBefore(LocalDateTime.now().plusHours(1))) { + if (Objects.isNull(closedAt) || closedAt.isBefore(LocalDateTime.now().plusMinutes(59))) { throw new BadRequestException(ErrorCode.INVALID_DATE_CLOSE_OPTION); } } From d8efab7615d7d07da01e6f9ce080eb42791a31cf Mon Sep 17 00:00:00 2001 From: wlsh44 Date: Thu, 25 Sep 2025 10:09:08 +0900 Subject: [PATCH 3/3] =?UTF-8?q?fix:=20=EB=A7=88=EA=B0=90=20=EC=8A=A4?= =?UTF-8?q?=EC=BC=80=EC=A4=84=EB=A7=81=20=EA=B0=84=EA=B2=A9=201=EC=B4=88?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD=20=EB=B0=8F=20=EC=84=9C=EB=B2=84?= =?UTF-8?q?=20=EC=8B=9C=EA=B0=84=20=EB=A1=9C=EA=B7=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/chooz/post/application/DateCloseScheduler.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/chooz/post/application/DateCloseScheduler.java b/src/main/java/com/chooz/post/application/DateCloseScheduler.java index b5221aa..5d85ed0 100644 --- a/src/main/java/com/chooz/post/application/DateCloseScheduler.java +++ b/src/main/java/com/chooz/post/application/DateCloseScheduler.java @@ -8,6 +8,7 @@ import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; +import java.time.LocalDateTime; import java.util.List; @Slf4j @@ -18,9 +19,9 @@ public class DateCloseScheduler { private final PostRepository postRepository; @Transactional - @Scheduled(fixedDelay = 1000 * 60) + @Scheduled(fixedDelay = 1000) public void closePostsByDate() { - log.info("마감 스케줄링 시작"); + log.info("마감 스케줄링 시작 | 서버 시간: {}", LocalDateTime.now()); List postsNeedToClose = postRepository.findPostsNeedToClose(); postsNeedToClose.forEach(Post::close); log.info("총 {}개 게시글 마감", postsNeedToClose.size());