diff --git a/src/main/java/com/mallang/statistics/batch/PostViewStatisticJobLegacy.java b/src/main/java/com/mallang/statistics/batch/PostViewStatisticJobLegacy.java deleted file mode 100644 index a68e20df..00000000 --- a/src/main/java/com/mallang/statistics/batch/PostViewStatisticJobLegacy.java +++ /dev/null @@ -1,84 +0,0 @@ -package com.mallang.statistics.batch; - -import static java.util.stream.Collectors.groupingBy; - -import com.mallang.post.domain.PostId; -import com.mallang.statistics.statistic.PostViewStatistic; -import com.mallang.statistics.statistic.PostViewStatisticRepository; -import com.mallang.statistics.statistic.source.PostViewHistory; -import com.mallang.statistics.statistic.source.PostViewHistoryRepository; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.stream.Collectors; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Component; -import org.springframework.transaction.support.TransactionTemplate; - -@RequiredArgsConstructor -@Component -public class PostViewStatisticJobLegacy { - - private final PostViewHistoryRepository postViewHistoryRepository; - private final PostViewStatisticRepository postViewStatisticRepository; - private final TransactionTemplate transactionTemplate; - - public void postViewsAggregationJob(LocalDateTime startInclude, LocalDateTime endExclude) { - Map> unprocessedHistories = getUnAggregatedViewsStep(startInclude, endExclude); - Map>> historiesGroupedByDateByPostId = - groupingViewByDateStep(unprocessedHistories); - aggregateViewsStep(historiesGroupedByDateByPostId); - } - - private Map> getUnAggregatedViewsStep( - LocalDateTime startInclude, - LocalDateTime endExclude - ) { - return postViewHistoryRepository.findWithCreatedDateBetweenIncludeStartAndExcludeEnd(startInclude, endExclude) - .stream() - .collect(groupingBy(PostViewHistory::getPostId)); - } - - private Map>> groupingViewByDateStep( - Map> unAggregatedViews - ) { - return unAggregatedViews - .entrySet() - .stream() - .collect(Collectors.toMap( - Entry::getKey, - entry -> entry.getValue() - .stream() - .collect(groupingBy(it -> it.getCreatedDate().toLocalDate())) - )); - } - - private void aggregateViewsStep(Map>> historiesGroupByDateByPostId) { - for (Entry>> entry : historiesGroupByDateByPostId.entrySet()) { - PostId postId = entry.getKey(); - Map> viewHistoriesGroupByDate = entry.getValue(); - aggregateViewsByPostIdStep(postId, viewHistoriesGroupByDate); - } - } - - private void aggregateViewsByPostIdStep(PostId postId, - Map> viewHistoriesGroupByDate) { - for (Entry> entry : viewHistoriesGroupByDate.entrySet()) { - aggregateEachPostViewsByDateStep(postId, entry.getKey(), entry.getValue()); - } - } - - private void aggregateEachPostViewsByDateStep(PostId postId, - LocalDate date, - List postViewHistories) { - transactionTemplate.executeWithoutResult(status -> { - PostViewStatistic postViewStatistic = postViewStatisticRepository - .findByPostIdAndStatisticDate(postId, date) - .orElseGet(() -> postViewStatisticRepository.save(new PostViewStatistic(date, postId))); - postViewStatistic.addCount(postViewHistories.size()); - postViewHistoryRepository.deleteAll(postViewHistories); - }); - } -} diff --git a/src/main/java/com/mallang/statistics/batch/PostViewStatisticJobSchedulerLegacy.java b/src/main/java/com/mallang/statistics/batch/PostViewStatisticJobSchedulerLegacy.java deleted file mode 100644 index cc485459..00000000 --- a/src/main/java/com/mallang/statistics/batch/PostViewStatisticJobSchedulerLegacy.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.mallang.statistics.batch; - -import com.mallang.statistics.batch.exeution.JobExecution; -import com.mallang.statistics.batch.exeution.JobHistoryRecorder; -import java.time.LocalDateTime; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Component; - -@Slf4j -@RequiredArgsConstructor -@Component -public class PostViewStatisticJobSchedulerLegacy { - - public static final String EACH_HOUR_CRON = "0 0 * * * *"; - private final JobHistoryRecorder jobHistoryRecorder; - private final PostViewStatisticJobLegacy postViewStatisticJobLegacy; - - @Scheduled(cron = EACH_HOUR_CRON) - public void runTask() { - LocalDateTime now = LocalDateTime.now(); - log.info("포스트 조회수 통계 작업 실행 [실행시간: {}]", now); - JobExecution history = new JobExecution("postViewStatisticJob", now); - LocalDateTime startInclude = now.minusHours(2); - LocalDateTime endExclude = now.minusHours(1); - jobHistoryRecorder.record(history, - () -> postViewStatisticJobLegacy.postViewsAggregationJob(startInclude, endExclude)); - } -} diff --git a/src/main/java/com/mallang/statistics/batch/exeution/JobExecution.java b/src/main/java/com/mallang/statistics/batch/exeution/JobExecution.java deleted file mode 100644 index 901c1df6..00000000 --- a/src/main/java/com/mallang/statistics/batch/exeution/JobExecution.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.mallang.statistics.batch.exeution; - -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import java.time.LocalDateTime; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NoArgsConstructor; - -@Getter -@NoArgsConstructor(access = AccessLevel.PROTECTED) -@Entity -public class JobExecution { - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - private String name; - private LocalDateTime executionTime; - - private Status status; - - private String whyFail; - - public JobExecution(String name, LocalDateTime executionTime) { - this.name = name; - this.executionTime = executionTime; - this.status = Status.PROCESSING; - } - - public void setStatus(Status status) { - this.status = status; - } - - public void fail(String whyFail) { - status = Status.FAIL; - this.whyFail = whyFail; - } -} diff --git a/src/main/java/com/mallang/statistics/batch/exeution/JobExecutionRepository.java b/src/main/java/com/mallang/statistics/batch/exeution/JobExecutionRepository.java deleted file mode 100644 index cf300370..00000000 --- a/src/main/java/com/mallang/statistics/batch/exeution/JobExecutionRepository.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.mallang.statistics.batch.exeution; - -import org.springframework.data.jpa.repository.JpaRepository; - -public interface JobExecutionRepository extends JpaRepository { -} diff --git a/src/main/java/com/mallang/statistics/batch/exeution/JobHistoryRecorder.java b/src/main/java/com/mallang/statistics/batch/exeution/JobHistoryRecorder.java deleted file mode 100644 index d31b2a18..00000000 --- a/src/main/java/com/mallang/statistics/batch/exeution/JobHistoryRecorder.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.mallang.statistics.batch.exeution; - -import static com.mallang.statistics.batch.exeution.Status.SUCCESS; - -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Component; - -@RequiredArgsConstructor -@Component -public class JobHistoryRecorder { - - private final JobExecutionRepository jobExecutionRepository; - - public void record(JobExecution history, Runnable runnable) { - jobExecutionRepository.saveAndFlush(history); - try { - runnable.run(); - history.setStatus(SUCCESS); - } catch (Exception e) { - history.fail(e.getMessage()); - } finally { - jobExecutionRepository.saveAndFlush(history); - } - } -} diff --git a/src/main/java/com/mallang/statistics/batch/exeution/Status.java b/src/main/java/com/mallang/statistics/batch/exeution/Status.java deleted file mode 100644 index c44d3656..00000000 --- a/src/main/java/com/mallang/statistics/batch/exeution/Status.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.mallang.statistics.batch.exeution; - -public enum Status { - PROCESSING, - SUCCESS, - FAIL -} diff --git a/src/main/java/com/mallang/statistics/batch/job/PostViewHistoryDto.java b/src/main/java/com/mallang/statistics/batch/job/PostViewHistoryDto.java new file mode 100644 index 00000000..5d1ae96d --- /dev/null +++ b/src/main/java/com/mallang/statistics/batch/job/PostViewHistoryDto.java @@ -0,0 +1,11 @@ +package com.mallang.statistics.batch.job; + +import java.time.LocalDate; + +public record PostViewHistoryDto( + Long postId, + Long blogId, + LocalDate date, + int viewCount +) { +} diff --git a/src/main/java/com/mallang/statistics/batch/job/PostViewStatisticJobConfig.java b/src/main/java/com/mallang/statistics/batch/job/PostViewStatisticJobConfig.java new file mode 100644 index 00000000..7cdcd1e9 --- /dev/null +++ b/src/main/java/com/mallang/statistics/batch/job/PostViewStatisticJobConfig.java @@ -0,0 +1,123 @@ +package com.mallang.statistics.batch.job; + +import com.mallang.post.domain.PostId; +import com.mallang.statistics.statistic.PostViewStatistic; +import com.mallang.statistics.statistic.PostViewStatisticRepository; +import com.mallang.statistics.statistic.source.PostViewHistoryRepository; +import jakarta.persistence.EntityManagerFactory; +import java.time.LocalDateTime; +import javax.sql.DataSource; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.batch.core.Job; +import org.springframework.batch.core.Step; +import org.springframework.batch.core.configuration.annotation.JobScope; +import org.springframework.batch.core.configuration.annotation.StepScope; +import org.springframework.batch.core.job.builder.JobBuilder; +import org.springframework.batch.core.repository.JobRepository; +import org.springframework.batch.core.step.builder.StepBuilder; +import org.springframework.batch.item.ItemProcessor; +import org.springframework.batch.item.ItemWriter; +import org.springframework.batch.item.database.JdbcCursorItemReader; +import org.springframework.batch.item.database.builder.JdbcCursorItemReaderBuilder; +import org.springframework.batch.item.database.builder.JpaItemWriterBuilder; +import org.springframework.batch.repeat.RepeatStatus; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.jdbc.core.ArgumentPreparedStatementSetter; +import org.springframework.jdbc.core.DataClassRowMapper; +import org.springframework.transaction.PlatformTransactionManager; + +@Slf4j +@RequiredArgsConstructor +@Configuration +public class PostViewStatisticJobConfig { + + private static final int CHUNK_SIZE = 500; + + private final EntityManagerFactory entityManagerFactory; + private final DataSource dataSource; + private final JobRepository jobRepository; + private final PlatformTransactionManager txManager; + private final PostViewStatisticRepository postViewStatisticRepository; + private final PostViewHistoryRepository postViewHistoryRepository; + private final StartAndEndTimeValidator startAndEndTimeValidator; + + @Bean + public Job postViewStatisticJob() { + return new JobBuilder("postViewStatisticJob", jobRepository) + .start(postViewStatisticStep()) + .next(postViewHistoryDeleteStep(null, null)) + .validator(startAndEndTimeValidator) + .build(); + } + + @Bean + public Step postViewStatisticStep() { + return new StepBuilder("postViewStatisticStep", jobRepository) + .chunk(CHUNK_SIZE, txManager) + .reader(postViewHistoryDtoReader(null, null)) + .processor(postViewHistoryToStatisticProcessor()) + .writer(postViewStatisticWriter()) + .build(); + } + + @Bean + @JobScope + public Step postViewHistoryDeleteStep( + @Value("#{jobParameters[startInclude]}") LocalDateTime startInclude, + @Value("#{jobParameters[endExclude]}") LocalDateTime endExclude + ) { + return new StepBuilder("postViewHistoryDeleteStep", jobRepository) + .tasklet((contribution, chunkContext) -> { + postViewHistoryRepository.deleteWithCreatedDateBetweenIncludeStartAndExcludeEnd( + startInclude, endExclude + ); + return RepeatStatus.FINISHED; + }, txManager) + .build(); + } + + @Bean + @StepScope + public JdbcCursorItemReader postViewHistoryDtoReader( + @Value("#{jobParameters[startInclude]}") LocalDateTime startInclude, + @Value("#{jobParameters[endExclude]}") LocalDateTime endExclude + ) { + return new JdbcCursorItemReaderBuilder() + .fetchSize(CHUNK_SIZE) + .dataSource(dataSource) + .rowMapper(new DataClassRowMapper<>(PostViewHistoryDto.class)) + .sql(""" + SELECT pvh.post_id, pvh.blog_id, pvh.date, COUNT(*) as view_count + FROM post_view_history pvh + WHERE pvh.created_date >= ? AND pvh.created_date < ? + GROUP BY pvh.post_id, pvh.blog_id, pvh.date + """) + .name("postViewHistoryDtoReader") + .preparedStatementSetter(new ArgumentPreparedStatementSetter(new Object[]{startInclude, endExclude})) + .build(); + } + + @Bean + public ItemProcessor postViewHistoryToStatisticProcessor() { + return historyDto -> { + PostId postId = new PostId(historyDto.postId(), historyDto.blogId()); + PostViewStatistic postViewStatistic = postViewStatisticRepository + .findByPostIdAndStatisticDate(postId, historyDto.date()) + .orElseGet(() -> postViewStatisticRepository.save( + new PostViewStatistic(historyDto.date(), postId) + )); + postViewStatistic.addCount(historyDto.viewCount()); + return postViewStatistic; + }; + } + + @Bean + public ItemWriter postViewStatisticWriter() { + return new JpaItemWriterBuilder() + .entityManagerFactory(entityManagerFactory) + .build(); + } +} diff --git a/src/main/java/com/mallang/statistics/batch/job/PostViewStatisticJobScheduler.java b/src/main/java/com/mallang/statistics/batch/job/PostViewStatisticJobScheduler.java new file mode 100644 index 00000000..05ebf78f --- /dev/null +++ b/src/main/java/com/mallang/statistics/batch/job/PostViewStatisticJobScheduler.java @@ -0,0 +1,37 @@ +package com.mallang.statistics.batch.job; + +import static com.mallang.common.utils.LocalDateTimeUtils.onlyHours; + +import java.time.LocalDateTime; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.batch.core.Job; +import org.springframework.batch.core.JobParameters; +import org.springframework.batch.core.JobParametersBuilder; +import org.springframework.batch.core.launch.JobLauncher; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +@Slf4j +@RequiredArgsConstructor +@Component +public class PostViewStatisticJobScheduler { + + public static final String EACH_HOUR_CRON = "0 0 * * * *"; + + private final JobLauncher jobLauncher; + private final Job postViewStatisticJob; + + @Scheduled(cron = EACH_HOUR_CRON) + public void runTask() throws Exception { + LocalDateTime now = LocalDateTime.now(); + log.info("포스트 조회수 통계 작업 실행 [실행시간: {}]", now); + LocalDateTime startInclude = onlyHours(now.minusHours(2)); + LocalDateTime endExclude = onlyHours(now); + JobParameters jobParameters = new JobParametersBuilder() + .addLocalDateTime("startInclude", startInclude) + .addLocalDateTime("endExclude", endExclude) + .toJobParameters(); + jobLauncher.run(postViewStatisticJob, jobParameters); + } +} diff --git a/src/main/java/com/mallang/statistics/statistic/source/PostViewHistory.java b/src/main/java/com/mallang/statistics/statistic/source/PostViewHistory.java index ff7fffbc..0cefcd5c 100644 --- a/src/main/java/com/mallang/statistics/statistic/source/PostViewHistory.java +++ b/src/main/java/com/mallang/statistics/statistic/source/PostViewHistory.java @@ -3,6 +3,7 @@ import com.mallang.post.domain.PostId; import jakarta.persistence.Column; import jakarta.persistence.Entity; +import java.time.LocalDate; import java.time.LocalDateTime; import java.util.UUID; import lombok.AccessLevel; @@ -20,9 +21,12 @@ public class PostViewHistory extends CommonHistory { @Column(nullable = false) private PostId postId; + private LocalDate date; + public PostViewHistory(UUID uuid, PostId postId, LocalDateTime createdDate) { super(createdDate); this.uuid = uuid; this.postId = postId; + this.date = createdDate.toLocalDate(); } } diff --git a/src/main/java/com/mallang/statistics/statistic/source/PostViewHistoryRepository.java b/src/main/java/com/mallang/statistics/statistic/source/PostViewHistoryRepository.java index 43c17b79..1beef4a5 100644 --- a/src/main/java/com/mallang/statistics/statistic/source/PostViewHistoryRepository.java +++ b/src/main/java/com/mallang/statistics/statistic/source/PostViewHistoryRepository.java @@ -23,4 +23,11 @@ List findWithCreatedDateBetweenIncludeStartAndExcludeEnd( @Modifying @Query("DELETE FROM PostViewHistory h WHERE h.postId = :postId") void deleteAllByPostId(PostId postId); + + @Modifying + @Query("DELETE FROM PostViewHistory h WHERE h.createdDate >= :startInclude AND h.createdDate < :endExclude") + void deleteWithCreatedDateBetweenIncludeStartAndExcludeEnd( + @Param("startInclude") LocalDateTime startInclude, + @Param("endExclude") LocalDateTime endExclude + ); } diff --git a/src/test/java/com/mallang/statistics/batch/PostViewStatisticJobLegacyTest.java b/src/test/java/com/mallang/statistics/batch/job/PostViewStatisticJobConfigTest.java similarity index 74% rename from src/test/java/com/mallang/statistics/batch/PostViewStatisticJobLegacyTest.java rename to src/test/java/com/mallang/statistics/batch/job/PostViewStatisticJobConfigTest.java index 06385f75..1d7a2aae 100644 --- a/src/test/java/com/mallang/statistics/batch/PostViewStatisticJobLegacyTest.java +++ b/src/test/java/com/mallang/statistics/batch/job/PostViewStatisticJobConfigTest.java @@ -1,9 +1,8 @@ -package com.mallang.statistics.batch; +package com.mallang.statistics.batch.job; import static java.util.UUID.randomUUID; import static org.assertj.core.api.Assertions.assertThat; -import com.mallang.common.DataClearExtension; import com.mallang.post.domain.PostId; import com.mallang.statistics.statistic.PostViewStatistic; import com.mallang.statistics.statistic.PostViewStatisticRepository; @@ -13,20 +12,28 @@ import java.time.LocalDateTime; import java.util.List; import java.util.Optional; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.batch.core.Job; +import org.springframework.batch.core.JobParameters; +import org.springframework.batch.core.JobParametersBuilder; +import org.springframework.batch.test.JobLauncherTestUtils; +import org.springframework.batch.test.context.SpringBatchTest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -@DisplayName("포스트 조회수 통계 작업 (PostViewStatisticJobLegacy) 은(는)") +@DisplayName("포스트 조회수 통계 배치 작업 (PostViewStatisticJobConfig) 은(는)") @SuppressWarnings("NonAsciiCharacters") @DisplayNameGeneration(ReplaceUnderscores.class) -@ExtendWith(DataClearExtension.class) +@SpringBatchTest @SpringBootTest -class PostViewStatisticJobLegacyTest { +class PostViewStatisticJobConfigTest { + + @Autowired + private JobLauncherTestUtils jobLauncherTestUtils; @Autowired private PostViewHistoryRepository postViewHistoryRepository; @@ -35,13 +42,20 @@ class PostViewStatisticJobLegacyTest { private PostViewStatisticRepository postViewStatisticRepository; @Autowired - private PostViewStatisticJobLegacy postViewStatisticJobLegacy; + private Job postViewStatisticJob; private final PostId postId1 = new PostId(1L, 1L); private final PostId postId2 = new PostId(2L, 1L); + @BeforeEach + void setUp() { + postViewHistoryRepository.deleteAll(); + postViewStatisticRepository.deleteAll(); + jobLauncherTestUtils.setJob(postViewStatisticJob); + } + @Test - void 특정_시간대에_포함되지_않으면_집계하지_않는다() { + void 특정_시간대에_포함되지_않으면_집계하지_않는다() throws Exception { // given LocalDateTime 시간_2000년_10월_4일_10시_0분 = LocalDateTime.of(2000, 10, 4, 10, 0); LocalDateTime 시간_2000년_10월_4일_10시_59분 = LocalDateTime.of(2000, 10, 4, 10, 59); @@ -62,8 +76,14 @@ class PostViewStatisticJobLegacyTest { 시간_2000년_10월_4일_11시_0분 )); + JobParameters jobParameters = new JobParametersBuilder() + .addLocalDateTime("startInclude", 시간_2000년_10월_4일_10시_0분) + .addLocalDateTime("endExclude", 시간_2000년_10월_4일_11시_0분) + .addLocalDateTime("forTestJob", LocalDateTime.now()) + .toJobParameters(); + // when - postViewStatisticJobLegacy.postViewsAggregationJob(시간_2000년_10월_4일_10시_0분, 시간_2000년_10월_4일_11시_0분); + jobLauncherTestUtils.launchJob(jobParameters); // then assertThat(postViewHistoryRepository.findAll().get(0).getId()) @@ -74,7 +94,7 @@ class PostViewStatisticJobLegacyTest { } @Test - void 시작시간은_포함되며_끝시간은_포함되지_않는다() { + void 시작시간은_포함되며_끝시간은_포함되지_않는다() throws Exception { // given LocalDateTime 시간_2000년_10월_4일_10시_0분 = LocalDateTime.of(2000, 10, 4, 10, 0); LocalDateTime 시간_2000년_10월_4일_11시_0분 = LocalDateTime.of(2000, 10, 4, 11, 0); @@ -92,8 +112,14 @@ class PostViewStatisticJobLegacyTest { 시간_2000년_10월_4일_11시_0분 )); + JobParameters jobParameters = new JobParametersBuilder() + .addLocalDateTime("startInclude", 시간_2000년_10월_4일_10시_0분) + .addLocalDateTime("endExclude", 시간_2000년_10월_4일_11시_0분) + .addLocalDateTime("forTestJob", LocalDateTime.now()) + .toJobParameters(); + // when - postViewStatisticJobLegacy.postViewsAggregationJob(시간_2000년_10월_4일_10시_0분, 시간_2000년_10월_4일_11시_0분); + jobLauncherTestUtils.launchJob(jobParameters); // then assertThat(postViewHistoryRepository.findById(시간_2000년_10월_4일_11시_0분_이력.getId())).isPresent(); @@ -104,8 +130,14 @@ class PostViewStatisticJobLegacyTest { .extracting(PostViewStatistic::getCount) .isEqualTo(1); + jobParameters = new JobParametersBuilder() + .addLocalDateTime("startInclude", 시간_2000년_10월_4일_11시_0분) + .addLocalDateTime("endExclude", 시간_2000년_10월_4일_12시_0분) + .addLocalDateTime("forTestJob", LocalDateTime.now()) + .toJobParameters(); + // when - postViewStatisticJobLegacy.postViewsAggregationJob(시간_2000년_10월_4일_11시_0분, 시간_2000년_10월_4일_12시_0분); + jobLauncherTestUtils.launchJob(jobParameters); // then assertThat(postViewHistoryRepository.findById(시간_2000년_10월_4일_11시_0분_이력.getId())).isEmpty(); @@ -117,7 +149,7 @@ class PostViewStatisticJobLegacyTest { } @Test - void 특정_시간대의_집계되지_않은_모든_조회_이력을_가져와_블로그별로_그리고_일자별로_개수를_집계한다() { + void 특정_시간대의_집계되지_않은_모든_조회_이력을_가져와_블로그별로_그리고_일자별로_개수를_집계한다() throws Exception { // given LocalDateTime 시간_2000년_10월_4일_10시_0분 = LocalDateTime.of(2000, 10, 4, 10, 0); LocalDateTime 시간_2000년_10월_4일_10시_59분 = LocalDateTime.of(2000, 10, 4, 10, 59); @@ -137,8 +169,14 @@ class PostViewStatisticJobLegacyTest { postViewHistoryRepository.save(new PostViewHistory(randomUUID(), postId1, 시간_2001년_10월_19일_20시_2분)); postViewHistoryRepository.save(new PostViewHistory(randomUUID(), postId2, 시간_2000년_10월_4일_10시_0분)); + JobParameters jobParameters = new JobParametersBuilder() + .addLocalDateTime("startInclude", 시간_2000년_10월_4일_10시_0분) + .addLocalDateTime("endExclude", 시간_2001년_10월_19일_20시_2분_0초_1나노초) + .addLocalDateTime("forTestJob", LocalDateTime.now()) + .toJobParameters(); + // when - postViewStatisticJobLegacy.postViewsAggregationJob(시간_2000년_10월_4일_10시_0분, 시간_2001년_10월_19일_20시_2분_0초_1나노초); + jobLauncherTestUtils.launchJob(jobParameters); // then assertThat(postViewHistoryRepository.findAll()).isEmpty(); @@ -146,31 +184,32 @@ class PostViewStatisticJobLegacyTest { assertThat(all).hasSize(4); LocalDate 시간_2000년_10월_4일 = LocalDate.of(2000, 10, 4); - PostViewStatistic 포스트_2_통계_2000년_10월_4일 = all.get(0); - assertThat(포스트_2_통계_2000년_10월_4일.getPostId().getPostId()).isEqualTo(2); - assertThat(포스트_2_통계_2000년_10월_4일.getStatisticDate()).isEqualTo(시간_2000년_10월_4일); - assertThat(포스트_2_통계_2000년_10월_4일.getCount()).isEqualTo(1); - PostViewStatistic 포스트_1_통계_2000년_10월_4일 = all.get(1); + PostViewStatistic 포스트_1_통계_2000년_10월_4일 = all.get(0); assertThat(포스트_1_통계_2000년_10월_4일.getPostId().getPostId()).isEqualTo(1); assertThat(포스트_1_통계_2000년_10월_4일.getStatisticDate()).isEqualTo(시간_2000년_10월_4일); assertThat(포스트_1_통계_2000년_10월_4일.getCount()).isEqualTo(3); LocalDate 시간_2000년_10월_5일 = LocalDate.of(2000, 10, 5); - PostViewStatistic 포스트_1_통계_2000년_10월_5일 = all.get(2); + PostViewStatistic 포스트_1_통계_2000년_10월_5일 = all.get(1); assertThat(포스트_1_통계_2000년_10월_5일.getPostId().getPostId()).isEqualTo(1); assertThat(포스트_1_통계_2000년_10월_5일.getStatisticDate()).isEqualTo(시간_2000년_10월_5일); assertThat(포스트_1_통계_2000년_10월_5일.getCount()).isEqualTo(3); LocalDate 시간_2001년_10월_19일 = LocalDate.of(2001, 10, 19); - PostViewStatistic 포스트_1_통계_2001년_10월_19일 = all.get(3); + PostViewStatistic 포스트_1_통계_2001년_10월_19일 = all.get(2); assertThat(포스트_1_통계_2001년_10월_19일.getPostId().getPostId()).isEqualTo(1); assertThat(포스트_1_통계_2001년_10월_19일.getStatisticDate()).isEqualTo(시간_2001년_10월_19일); assertThat(포스트_1_통계_2001년_10월_19일.getCount()).isEqualTo(1); + + PostViewStatistic 포스트_2_통계_2000년_10월_4일 = all.get(3); + assertThat(포스트_2_통계_2000년_10월_4일.getPostId().getPostId()).isEqualTo(2); + assertThat(포스트_2_통계_2000년_10월_4일.getStatisticDate()).isEqualTo(시간_2000년_10월_4일); + assertThat(포스트_2_통계_2000년_10월_4일.getCount()).isEqualTo(1); } @Test - void 이미_존재하는_통계에_대해서는_개수가_증가한다() { + void 이미_존재하는_통계에_대해서는_개수가_증가한다() throws Exception { // given LocalDateTime 시간_2000년_10월_4일_10시_0분 = LocalDateTime.of(2000, 10, 4, 10, 0); LocalDateTime 시간_2000년_10월_4일_10시_59분 = LocalDateTime.of(2000, 10, 4, 10, 59); @@ -178,7 +217,13 @@ class PostViewStatisticJobLegacyTest { LocalDateTime 시간_2000년_10월_4일_12시 = LocalDateTime.of(2000, 10, 4, 12, 0); postViewHistoryRepository.save(new PostViewHistory(randomUUID(), postId1, 시간_2000년_10월_4일_10시_0분)); postViewHistoryRepository.save(new PostViewHistory(randomUUID(), postId1, 시간_2000년_10월_4일_10시_59분)); - postViewStatisticJobLegacy.postViewsAggregationJob(시간_2000년_10월_4일_10시_0분, 시간_2000년_10월_4일_12시); + JobParameters jobParameters = new JobParametersBuilder() + .addLocalDateTime("startInclude", 시간_2000년_10월_4일_10시_0분) + .addLocalDateTime("endExclude", 시간_2000년_10월_4일_12시) + .addLocalDateTime("forTestJob", LocalDateTime.now()) + .toJobParameters(); + + jobLauncherTestUtils.launchJob(jobParameters); LocalDate 시간_2000년_10월_4일 = LocalDate.of(2000, 10, 4); Optional statistic = postViewStatisticRepository .findByPostIdAndStatisticDate(postId1, 시간_2000년_10월_4일); @@ -188,9 +233,15 @@ class PostViewStatisticJobLegacyTest { assertThat(postViewStatistic.getStatisticDate()).isEqualTo(시간_2000년_10월_4일); assertThat(postViewStatistic.getCount()).isEqualTo(2); + jobParameters = new JobParametersBuilder() + .addLocalDateTime("startInclude", 시간_2000년_10월_4일_10시_0분) + .addLocalDateTime("endExclude", 시간_2000년_10월_4일_12시) + .addLocalDateTime("forTestJob", LocalDateTime.now()) + .toJobParameters(); + // when postViewHistoryRepository.save(new PostViewHistory(randomUUID(), postId1, 시간_2000년_10월_4일_11시_0분)); - postViewStatisticJobLegacy.postViewsAggregationJob(시간_2000년_10월_4일_10시_0분, 시간_2000년_10월_4일_12시); + jobLauncherTestUtils.launchJob(jobParameters); // then assertThat(postViewHistoryRepository.findAll()).isEmpty();