Skip to content

Commit

Permalink
Allow to init only specific jobs in tests (#218)
Browse files Browse the repository at this point in the history
  • Loading branch information
dmytro-bekuzarov authored Dec 13, 2024
1 parent 6aa94a7 commit 37a1559
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 17 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<IJob> jobs)` method to `ITestJobsService` to allow to init only specific jobs in tests

# 1.46.1 - 2024/12/04

### Changed
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
version=1.46.1
version=1.47.0
org.gradle.internal.http.socketTimeout=120000
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 extends IJob> T registerJobBean(T job) {
applicationContext.getBeanFactory().registerSingleton(job.getClass().getSimpleName(), job);
testJobsService.reset();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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<IJob> jobs);

@Data
@Accessors(chain = true)
class ExecuteAsyncHandle {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<IJob> jobs) {
transactionsHelper.withTransaction().run(() -> {
testTasksService.reset();
initJobs(true, jobs);
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -42,8 +41,8 @@ public class JobsService implements IJobsService, GracefulShutdownStrategy, Init
@Autowired(required = false)
private MeterRegistry meterRegistry;

private List<JobContainer> jobContainers;
private Map<String, JobContainer> cronTasksMap = new HashMap<>();
private final List<JobContainer> jobContainers = new ArrayList<>();
private final Map<String, JobContainer> jobContainersMap = new HashMap<>();
private final List<IJob> nonBeanJobs = new ArrayList<>();

public void register(IJob job) {
Expand Down Expand Up @@ -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<IJob> 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<IJob> 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<IJob> jobs = new ArrayList<>(applicationContext.getBeansOfType(IJob.class).values());
jobs.addAll(nonBeanJobs);
initJobs(silent, jobs);
}

private void validateState() {
jobContainers.forEach(c -> {
if (c.getUniqueName() == null) {
Expand Down

0 comments on commit 37a1559

Please sign in to comment.