diff --git a/CHANGELOG.md b/CHANGELOG.md index 25b234fc..0ccb4318 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 1.47.0 - 2024/12/13 + +### Added + +- Added `resetAndInitialize(Collection jobs)` method to `ITestJobsService` to allow to init only specific jobs in tests + # 1.46.1 - 2024/12/04 ### Changed diff --git a/gradle.properties b/gradle.properties index e4c83bac..77bef476 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,2 @@ -version=1.46.1 +version=1.47.0 org.gradle.internal.http.socketTimeout=120000 diff --git a/integration-tests/src/test/java/com/transferwise/tasks/ext/jobs/JobsIntTest.java b/integration-tests/src/test/java/com/transferwise/tasks/ext/jobs/JobsIntTest.java index deab3141..8ec1ccfa 100644 --- a/integration-tests/src/test/java/com/transferwise/tasks/ext/jobs/JobsIntTest.java +++ b/integration-tests/src/test/java/com/transferwise/tasks/ext/jobs/JobsIntTest.java @@ -16,6 +16,7 @@ import com.transferwise.tasks.impl.jobs.test.ITestJobsService; import java.time.Duration; import java.time.ZonedDateTime; +import java.util.List; import java.util.concurrent.ThreadLocalRandom; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.BeforeEach; @@ -114,6 +115,23 @@ void jobCanBeExecutedFromTest() { assertThat(job.executionsCount).isEqualTo(1); } + @Test + void onlySelectedJobsWillExecute() { + JobC job = new JobC(); + testJobsService.resetAndInitialize(List.of(job)); + + // manually triggered job is initialized and executed + assertThat(job.executionsCount).isZero(); + + ITestJobsService.ExecuteAsyncHandle handle = testJobsService.executeAsync(job); + + await().until(() -> testJobsService.hasFinished(handle)); + assertThat(job.executionsCount).isEqualTo(1); + + // other did not initialize + assertThat(testTasksService.getTasks("TaskJob|JobA", null)).isEmpty(); + } + private T registerJobBean(T job) { applicationContext.getBeanFactory().registerSingleton(job.getClass().getSimpleName(), job); testJobsService.reset(); diff --git a/tw-tasks-jobs-test/src/main/java/com/transferwise/tasks/impl/jobs/test/ITestJobsService.java b/tw-tasks-jobs-test/src/main/java/com/transferwise/tasks/impl/jobs/test/ITestJobsService.java index 2c6b40db..1392ffb4 100644 --- a/tw-tasks-jobs-test/src/main/java/com/transferwise/tasks/impl/jobs/test/ITestJobsService.java +++ b/tw-tasks-jobs-test/src/main/java/com/transferwise/tasks/impl/jobs/test/ITestJobsService.java @@ -3,6 +3,7 @@ import com.transferwise.tasks.domain.ITaskVersionId; import com.transferwise.tasks.impl.jobs.interfaces.IJob; import com.transferwise.tasks.impl.jobs.interfaces.IJobsService; +import java.util.Collection; import lombok.Data; import lombok.experimental.Accessors; @@ -12,8 +13,20 @@ public interface ITestJobsService extends IJobsService { boolean hasFinished(ExecuteAsyncHandle handle); + /** + * Clear all existing jobs and related tw-tasks, and initialize them again (if JobsProperties.autoInitialize is true). + */ void reset(); + /** + * Clear all existing jobs and related tw-tasks and initialize with the provided jobs. + * Most likely it would be useful when `JobsProperties.autoInitialize` is false, + * when only specific jobs are needed to be initialized for the test, so that other jobs won't run. + * + * @param jobs jobs to initialize (register and create related tw-tasks) + */ + void resetAndInitialize(Collection jobs); + @Data @Accessors(chain = true) class ExecuteAsyncHandle { diff --git a/tw-tasks-jobs-test/src/main/java/com/transferwise/tasks/impl/jobs/test/TestJobsService.java b/tw-tasks-jobs-test/src/main/java/com/transferwise/tasks/impl/jobs/test/TestJobsService.java index 00ecc119..f5946101 100644 --- a/tw-tasks-jobs-test/src/main/java/com/transferwise/tasks/impl/jobs/test/TestJobsService.java +++ b/tw-tasks-jobs-test/src/main/java/com/transferwise/tasks/impl/jobs/test/TestJobsService.java @@ -9,6 +9,7 @@ import com.transferwise.tasks.impl.jobs.JobsService; import com.transferwise.tasks.impl.jobs.interfaces.IJob; import com.transferwise.tasks.test.ITestTasksService; +import java.util.Collection; import java.util.UUID; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -57,12 +58,19 @@ public boolean hasFinished(ExecuteAsyncHandle handle) { @Override public void reset() { - transactionsHelper.withTransaction().asNew().call(() -> { + transactionsHelper.withTransaction().run(() -> { testTasksService.reset(); if (jobsProperties.isAutoInitialize()) { initJobs(true); } - return null; + }); + } + + @Override + public void resetAndInitialize(Collection jobs) { + transactionsHelper.withTransaction().run(() -> { + testTasksService.reset(); + initJobs(true, jobs); }); } } diff --git a/tw-tasks-jobs/src/main/java/com/transferwise/tasks/impl/jobs/JobsService.java b/tw-tasks-jobs/src/main/java/com/transferwise/tasks/impl/jobs/JobsService.java index fcf905de..261d2d22 100644 --- a/tw-tasks-jobs/src/main/java/com/transferwise/tasks/impl/jobs/JobsService.java +++ b/tw-tasks-jobs/src/main/java/com/transferwise/tasks/impl/jobs/JobsService.java @@ -13,13 +13,12 @@ import io.micrometer.core.instrument.MeterRegistry; import java.time.ZonedDateTime; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; -import java.util.function.Function; import java.util.stream.Collectors; -import java.util.stream.Stream; import lombok.Data; import lombok.experimental.Accessors; import lombok.extern.slf4j.Slf4j; @@ -42,8 +41,8 @@ public class JobsService implements IJobsService, GracefulShutdownStrategy, Init @Autowired(required = false) private MeterRegistry meterRegistry; - private List jobContainers; - private Map cronTasksMap = new HashMap<>(); + private final List jobContainers = new ArrayList<>(); + private final Map jobContainersMap = new HashMap<>(); private final List nonBeanJobs = new ArrayList<>(); public void register(IJob job) { @@ -74,26 +73,34 @@ public boolean canShutdown() { public IJob getJobFor(IBaseTask task) { String jobName = StringUtils.substringAfter(task.getType(), "|"); jobName = StringUtils.substringBefore(jobName, "|"); - JobContainer jobContainer = cronTasksMap.get(jobName); + JobContainer jobContainer = jobContainersMap.get(jobName); if (jobContainer == null) { return null; } return jobContainer.job; } - protected void initJobs(boolean silent) { - List availableCronTasks = new ArrayList<>(applicationContext.getBeansOfType(IJob.class).values()); - - jobContainers = Stream.concat(availableCronTasks.stream(), nonBeanJobs.stream()) - .map(cronTask -> new JobContainer().setJob(cronTask).setTaskId(cronTask.getTaskId()) - .setUniqueName(StringUtils.trimToNull(cronTask.getUniqueName()))) - .collect(Collectors.toList()); - cronTasksMap = jobContainers.stream().collect(Collectors.toMap(JobContainer::getUniqueName, Function.identity())); - + protected void initJobs(boolean silent, Collection jobs) { + jobContainers.clear(); + jobContainersMap.clear(); + for (IJob job : jobs) { + var jobContainer = new JobContainer() + .setJob(job) + .setTaskId(job.getTaskId()) + .setUniqueName(StringUtils.trimToNull(job.getUniqueName())); + jobContainers.add(jobContainer); + jobContainersMap.put(jobContainer.getUniqueName(), jobContainer); + } validateState(); registerCronTasks(silent); } + protected void initJobs(boolean silent) { + List jobs = new ArrayList<>(applicationContext.getBeansOfType(IJob.class).values()); + jobs.addAll(nonBeanJobs); + initJobs(silent, jobs); + } + private void validateState() { jobContainers.forEach(c -> { if (c.getUniqueName() == null) {