From d5a72e1ee5ccdcc1c486f287378bd28c5aee1d92 Mon Sep 17 00:00:00 2001 From: Geir Sagberg Date: Tue, 9 Jul 2024 10:42:23 +0200 Subject: [PATCH] Do not serialize/deserialize task data (fixes #116) --- .../bekk/dbscheduler/ui/model/TaskModel.java | 133 +----------------- .../bekk/dbscheduler/ui/service/LogLogic.java | 38 ++--- .../dbscheduler/ui/service/TaskLogic.java | 37 +++-- .../bekk/dbscheduler/ui/util/QueryUtils.java | 7 +- .../ui/util/mapper/TaskMapper.java | 8 +- .../bekk/exampleapp/model/TaskData.java | 30 ++-- .../bekk/exampleapp/service/TaskService.java | 4 +- .../bekk/exampleapp/tasks/SpawnerTask.java | 2 +- .../bekk/exampleapp/model/TaskData.java | 30 ++-- .../model/TaskScheduleAndNoData.java | 43 ++++++ .../bekk/exampleapp/service/TaskService.java | 4 +- .../tasks/DynamicRecurringTaskExample.java | 39 +++++ .../bekk/exampleapp/tasks/SpawnerTask.java | 2 +- .../DynamicRecurringSchedulingTest.java | 68 +++++++++ 14 files changed, 234 insertions(+), 211 deletions(-) create mode 100644 example-app/src/main/java/com/github/bekk/exampleapp/model/TaskScheduleAndNoData.java create mode 100644 example-app/src/main/java/com/github/bekk/exampleapp/tasks/DynamicRecurringTaskExample.java create mode 100644 example-app/src/test/java/com/github/bekk/exampleapp/DynamicRecurringSchedulingTest.java diff --git a/db-scheduler-ui/src/main/java/no/bekk/dbscheduler/ui/model/TaskModel.java b/db-scheduler-ui/src/main/java/no/bekk/dbscheduler/ui/model/TaskModel.java index b285201c..4c669cb9 100644 --- a/db-scheduler-ui/src/main/java/no/bekk/dbscheduler/ui/model/TaskModel.java +++ b/db-scheduler-ui/src/main/java/no/bekk/dbscheduler/ui/model/TaskModel.java @@ -13,13 +13,17 @@ */ package no.bekk.dbscheduler.ui.model; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; import java.time.Instant; import java.util.List; -import java.util.stream.Collectors; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; +@Getter +@Setter +@AllArgsConstructor public class TaskModel { + private String taskName; private List taskInstance; private List taskData; @@ -31,127 +35,4 @@ public class TaskModel { private List consecutiveFailures; private Instant lastHeartbeat; private int version; - - private static final ObjectMapper objectMapper = new ObjectMapper(); - - public TaskModel( - String taskName, - List taskInstance, - List inputTaskData, - List executionTime, - List picked, - List pickedBy, - List lastSuccess, - Instant lastFailure, - List consecutiveFailures, - Instant lastHeartbeat, - int version) { - this.taskName = taskName; - this.taskInstance = taskInstance; - this.taskData = serializeTaskData(inputTaskData); - this.executionTime = executionTime; - this.picked = picked; - this.pickedBy = pickedBy; - this.lastSuccess = lastSuccess; - this.lastFailure = lastFailure; - this.consecutiveFailures = consecutiveFailures; - this.lastHeartbeat = lastHeartbeat; - this.version = version; - } - - public TaskModel() {} - - private List serializeTaskData(List inputTaskDataList) { - return inputTaskDataList.stream() - .map( - data -> { - try { - String serializedData = objectMapper.writeValueAsString(data); - return objectMapper.readValue(serializedData, Object.class); - } catch (JsonProcessingException e) { - throw new RuntimeException(e); - } - }) - .collect(Collectors.toList()); - } - - public String getTaskName() { - return taskName; - } - - public List getTaskInstance() { - return taskInstance; - } - - public void setTaskInstance(List taskInstance) { - this.taskInstance = taskInstance; - } - - public List getTaskData() { - return taskData; - } - - public void setTaskData(List inputTaskData) { - this.taskData = serializeTaskData(inputTaskData); - } - - public void setExecutionTime(List executionTime) { - this.executionTime = executionTime; - } - - public List getExecutionTime() { - return executionTime; - } - - public List isPicked() { - return picked; - } - - public void setPicked(List picked) { - this.picked = picked; - } - - public List getPickedBy() { - return pickedBy; - } - - public void setPickedBy(List pickedBy) { - this.pickedBy = pickedBy; - } - - public List getLastSuccess() { - return lastSuccess; - } - - public void setLastSuccess(List lastSuccess) { - this.lastSuccess = lastSuccess; - } - - public Instant getLastFailure() { - return lastFailure; - } - - public void setLastFailure(Instant lastFailure) { - this.lastFailure = lastFailure; - } - - public List getConsecutiveFailures() { - return consecutiveFailures; - } - - public Instant getLastHeartbeat() { - return lastHeartbeat; - } - - public void setLastHeartbeat(Instant lastHeartbeat) { - this.lastHeartbeat = lastHeartbeat; - } - - public int getVersion() { - return version; - } - - public void setConsecutiveFailures(List consecutiveFailures) { - this.consecutiveFailures = consecutiveFailures; - } } diff --git a/db-scheduler-ui/src/main/java/no/bekk/dbscheduler/ui/service/LogLogic.java b/db-scheduler-ui/src/main/java/no/bekk/dbscheduler/ui/service/LogLogic.java index 554193db..1d05eaa1 100644 --- a/db-scheduler-ui/src/main/java/no/bekk/dbscheduler/ui/service/LogLogic.java +++ b/db-scheduler-ui/src/main/java/no/bekk/dbscheduler/ui/service/LogLogic.java @@ -35,13 +35,11 @@ import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; -import org.springframework.stereotype.Service; -@Service public class LogLogic { - private final NamedParameterJdbcTemplate namedParameterJdbcTemplate; private static final int DEFAULT_LIMIT = 500; + private final NamedParameterJdbcTemplate namedParameterJdbcTemplate; private final Caching caching; private final LogModelRowMapper logModelRowMapper; @@ -124,7 +122,23 @@ public List getLogsDirectlyFromDB(TaskDetailsRequestParams requestPara queryBuilder.getQuery(), queryBuilder.getParameters(), logModelRowMapper); } + private enum Operators { + GREATER_THAN_OR_EQUALS(">="), + LESS_THAN_OR_EQUALS("<="); + + private final String operator; + + Operators(String operator) { + this.operator = operator; + } + + public String getOperator() { + return operator; + } + } + private static class TimeCondition implements AndCondition { + private final String varName; private final String operator; private final Instant value; @@ -147,6 +161,7 @@ public void setParameters(MapSqlParameterSource p) { } private static class SearchCondition implements AndCondition { + private final String searchTerm; private final Map params; @@ -176,6 +191,7 @@ public void setParameters(MapSqlParameterSource p) { } public static class FilterCondition implements AndCondition { + private final TaskRequestParams.TaskFilter filterCondition; public FilterCondition(TaskRequestParams.TaskFilter filterCondition) { @@ -197,6 +213,7 @@ public void setParameters(MapSqlParameterSource p) { @RequiredArgsConstructor public static class LogModelRowMapper implements RowMapper { + private final boolean showData; private final Serializer serializer; @@ -224,19 +241,4 @@ public LogModel mapRow(ResultSet rs, int rowNum) throws SQLException { rs.getString("exception_stacktrace")); } } - - private enum Operators { - GREATER_THAN_OR_EQUALS(">="), - LESS_THAN_OR_EQUALS("<="); - - private final String operator; - - Operators(String operator) { - this.operator = operator; - } - - public String getOperator() { - return operator; - } - } } diff --git a/db-scheduler-ui/src/main/java/no/bekk/dbscheduler/ui/service/TaskLogic.java b/db-scheduler-ui/src/main/java/no/bekk/dbscheduler/ui/service/TaskLogic.java index 4c0cf12b..2023aa2c 100644 --- a/db-scheduler-ui/src/main/java/no/bekk/dbscheduler/ui/service/TaskLogic.java +++ b/db-scheduler-ui/src/main/java/no/bekk/dbscheduler/ui/service/TaskLogic.java @@ -19,25 +19,29 @@ import com.github.kagkarlsson.scheduler.Scheduler; import com.github.kagkarlsson.scheduler.task.TaskInstanceId; import java.time.Instant; -import java.util.*; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; import java.util.stream.Collectors; -import no.bekk.dbscheduler.ui.model.*; +import no.bekk.dbscheduler.ui.model.GetTasksResponse; +import no.bekk.dbscheduler.ui.model.PollResponse; +import no.bekk.dbscheduler.ui.model.TaskDetailsRequestParams; +import no.bekk.dbscheduler.ui.model.TaskModel; +import no.bekk.dbscheduler.ui.model.TaskRequestParams; import no.bekk.dbscheduler.ui.util.Caching; import no.bekk.dbscheduler.ui.util.QueryUtils; import no.bekk.dbscheduler.ui.util.mapper.TaskMapper; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; -import org.springframework.stereotype.Service; import org.springframework.web.server.ResponseStatusException; -@Service public class TaskLogic { private final Scheduler scheduler; private final Caching caching; private final boolean showData; - @Autowired public TaskLogic(Scheduler scheduler, Caching caching, boolean showData) { this.scheduler = scheduler; this.scheduler.start(); @@ -76,7 +80,6 @@ public void runTaskGroupNow(String taskName, boolean onlyFailed) { System.out.println("Failed to run task: " + e.getMessage()); } } - ; }); } @@ -222,11 +225,17 @@ private void handleNewTask( Set newRunningTaskNames, String taskName, String status) { - if (newTaskNames.contains(taskName) && params.getTaskName() == null) return; + if (newTaskNames.contains(taskName) && params.getTaskName() == null) { + return; + } newTaskNames.add(taskName); - if (status.charAt(0) == '1') newFailureTaskNames.add(taskName); - if (status.charAt(1) == '1') newRunningTaskNames.add(taskName); + if (status.charAt(0) == '1') { + newFailureTaskNames.add(taskName); + } + if (status.charAt(1) == '1') { + newRunningTaskNames.add(taskName); + } } private void handleStatusChange( @@ -243,14 +252,18 @@ private void handleStatusChange( && (!newFailureTaskNames.contains(taskName) || params.getTaskName() != null)) { newFailureTaskNames.add(taskName); } - if (cachedStatus.charAt(0) == '1' && status.charAt(0) == '0') stoppedFailing++; + if (cachedStatus.charAt(0) == '1' && status.charAt(0) == '0') { + stoppedFailing++; + } if (cachedStatus.charAt(1) == '0' && status.charAt(1) == '1' && (!newRunningTaskNames.contains(taskName) || params.getTaskName() != null)) { newRunningTaskNames.add(taskName); } - if (cachedStatus.charAt(1) == '1' && status.charAt(1) == '0') finishedRunning++; + if (cachedStatus.charAt(1) == '1' && status.charAt(1) == '0') { + finishedRunning++; + } } private String getStatus(ScheduledExecution task) { diff --git a/db-scheduler-ui/src/main/java/no/bekk/dbscheduler/ui/util/QueryUtils.java b/db-scheduler-ui/src/main/java/no/bekk/dbscheduler/ui/util/QueryUtils.java index 4b819cd6..82bc84e5 100644 --- a/db-scheduler-ui/src/main/java/no/bekk/dbscheduler/ui/util/QueryUtils.java +++ b/db-scheduler-ui/src/main/java/no/bekk/dbscheduler/ui/util/QueryUtils.java @@ -44,12 +44,13 @@ public static List filterTasks( case FAILED: return task.getConsecutiveFailures().stream().anyMatch(failures -> failures != 0); case RUNNING: - return task.isPicked().stream().anyMatch(Boolean::booleanValue); + return task.getPicked().stream().anyMatch(Boolean::booleanValue); case SCHEDULED: - return IntStream.range(0, task.isPicked().size()) + return IntStream.range(0, task.getPicked().size()) .anyMatch( i -> - !task.isPicked().get(i) && task.getConsecutiveFailures().get(i) == 0); + !task.getPicked().get(i) + && task.getConsecutiveFailures().get(i) == 0); default: return true; } diff --git a/db-scheduler-ui/src/main/java/no/bekk/dbscheduler/ui/util/mapper/TaskMapper.java b/db-scheduler-ui/src/main/java/no/bekk/dbscheduler/ui/util/mapper/TaskMapper.java index 3cb414de..8e89be62 100644 --- a/db-scheduler-ui/src/main/java/no/bekk/dbscheduler/ui/util/mapper/TaskMapper.java +++ b/db-scheduler-ui/src/main/java/no/bekk/dbscheduler/ui/util/mapper/TaskMapper.java @@ -21,6 +21,7 @@ import no.bekk.dbscheduler.ui.model.TaskModel; public class TaskMapper { + public static List mapScheduledExecutionsToTaskModel( List> scheduledExecutions) { return scheduledExecutions.stream() @@ -63,7 +64,7 @@ public static List groupTasks(List tasks) { .collect(Collectors.toList())); taskModel.setPicked( taskModels.stream() - .map(TaskModel::isPicked) + .map(TaskModel::getPicked) .flatMap(List::stream) .collect(Collectors.toList())); taskModel.setPickedBy( @@ -92,11 +93,6 @@ public static List groupTasks(List tasks) { .collect(Collectors.toList()); } - public static List mapAllExecutionsToTaskModel( - List> scheduledExecutions) { - return groupTasks(mapScheduledExecutionsToTaskModel(scheduledExecutions)); - } - public static List mapAllExecutionsToTaskModelUngrouped( List> scheduledExecutions) { return mapScheduledExecutionsToTaskModel(scheduledExecutions); diff --git a/example-app-webflux/src/main/java/com/github/bekk/exampleapp/model/TaskData.java b/example-app-webflux/src/main/java/com/github/bekk/exampleapp/model/TaskData.java index d13942ec..d54dcc69 100644 --- a/example-app-webflux/src/main/java/com/github/bekk/exampleapp/model/TaskData.java +++ b/example-app-webflux/src/main/java/com/github/bekk/exampleapp/model/TaskData.java @@ -14,29 +14,17 @@ package com.github.bekk.exampleapp.model; import java.io.Serializable; +import java.time.Instant; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; +@Setter +@Getter +@AllArgsConstructor public class TaskData implements Serializable { + private long id; private String data; - - public TaskData(long id, String data) { - this.id = id; - this.data = data; - } - - public long getId() { - return id; - } - - public void setId(long id) { - this.id = id; - } - - public String getData() { - return data; - } - - public void setData(String data) { - this.data = data; - } + private Instant time; } diff --git a/example-app-webflux/src/main/java/com/github/bekk/exampleapp/service/TaskService.java b/example-app-webflux/src/main/java/com/github/bekk/exampleapp/service/TaskService.java index d9d2470a..4ac84e5a 100644 --- a/example-app-webflux/src/main/java/com/github/bekk/exampleapp/service/TaskService.java +++ b/example-app-webflux/src/main/java/com/github/bekk/exampleapp/service/TaskService.java @@ -26,6 +26,7 @@ @Service public class TaskService { + private final Scheduler scheduler; public TaskService(Scheduler scheduler) { @@ -33,7 +34,8 @@ public TaskService(Scheduler scheduler) { } public void runManuallyTriggeredTasks() { - scheduler.schedule(ONE_TIME_TASK.instance("1", new TaskData(1, "test data")), Instant.now()); + scheduler.schedule( + ONE_TIME_TASK.instance("1", new TaskData(1, "test data", Instant.now())), Instant.now()); scheduler.schedule( CHAINED_STEP_1_TASK.instance("3", new TestObject("Ole Nordman", 1, "ole.nordman@mail.com")), diff --git a/example-app-webflux/src/main/java/com/github/bekk/exampleapp/tasks/SpawnerTask.java b/example-app-webflux/src/main/java/com/github/bekk/exampleapp/tasks/SpawnerTask.java index 8f02d4ca..2773bf4c 100644 --- a/example-app-webflux/src/main/java/com/github/bekk/exampleapp/tasks/SpawnerTask.java +++ b/example-app-webflux/src/main/java/com/github/bekk/exampleapp/tasks/SpawnerTask.java @@ -49,7 +49,7 @@ public Task runSpawner() { client.schedule( ONE_TIME_SPAWNER_TASK.instance( "spawned " + randomUUID + " loopnr: " + i, - new TaskData(123, "{data: MASSIVEDATA}")), + new TaskData(123, "{data: MASSIVEDATA}", Instant.now())), Instant.now().plusSeconds(60)); } }); diff --git a/example-app/src/main/java/com/github/bekk/exampleapp/model/TaskData.java b/example-app/src/main/java/com/github/bekk/exampleapp/model/TaskData.java index d13942ec..d54dcc69 100644 --- a/example-app/src/main/java/com/github/bekk/exampleapp/model/TaskData.java +++ b/example-app/src/main/java/com/github/bekk/exampleapp/model/TaskData.java @@ -14,29 +14,17 @@ package com.github.bekk.exampleapp.model; import java.io.Serializable; +import java.time.Instant; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; +@Setter +@Getter +@AllArgsConstructor public class TaskData implements Serializable { + private long id; private String data; - - public TaskData(long id, String data) { - this.id = id; - this.data = data; - } - - public long getId() { - return id; - } - - public void setId(long id) { - this.id = id; - } - - public String getData() { - return data; - } - - public void setData(String data) { - this.data = data; - } + private Instant time; } diff --git a/example-app/src/main/java/com/github/bekk/exampleapp/model/TaskScheduleAndNoData.java b/example-app/src/main/java/com/github/bekk/exampleapp/model/TaskScheduleAndNoData.java new file mode 100644 index 00000000..5f014cfb --- /dev/null +++ b/example-app/src/main/java/com/github/bekk/exampleapp/model/TaskScheduleAndNoData.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) Bekk + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.github.bekk.exampleapp.model; + +import com.github.kagkarlsson.scheduler.task.helper.ScheduleAndData; +import com.github.kagkarlsson.scheduler.task.schedule.CronSchedule; +import java.io.Serializable; + +public class TaskScheduleAndNoData implements ScheduleAndData, Serializable { + + private static final long serialVersionUID = 1L; // recommended when using Java serialization + + private final CronSchedule schedule; + + private TaskScheduleAndNoData() { + this(null); + } + + public TaskScheduleAndNoData(CronSchedule schedule) { + this.schedule = schedule; + } + + @Override + public CronSchedule getSchedule() { + return this.schedule; + } + + @Override + public Object getData() { + return null; + } +} diff --git a/example-app/src/main/java/com/github/bekk/exampleapp/service/TaskService.java b/example-app/src/main/java/com/github/bekk/exampleapp/service/TaskService.java index d9d2470a..4ac84e5a 100644 --- a/example-app/src/main/java/com/github/bekk/exampleapp/service/TaskService.java +++ b/example-app/src/main/java/com/github/bekk/exampleapp/service/TaskService.java @@ -26,6 +26,7 @@ @Service public class TaskService { + private final Scheduler scheduler; public TaskService(Scheduler scheduler) { @@ -33,7 +34,8 @@ public TaskService(Scheduler scheduler) { } public void runManuallyTriggeredTasks() { - scheduler.schedule(ONE_TIME_TASK.instance("1", new TaskData(1, "test data")), Instant.now()); + scheduler.schedule( + ONE_TIME_TASK.instance("1", new TaskData(1, "test data", Instant.now())), Instant.now()); scheduler.schedule( CHAINED_STEP_1_TASK.instance("3", new TestObject("Ole Nordman", 1, "ole.nordman@mail.com")), diff --git a/example-app/src/main/java/com/github/bekk/exampleapp/tasks/DynamicRecurringTaskExample.java b/example-app/src/main/java/com/github/bekk/exampleapp/tasks/DynamicRecurringTaskExample.java new file mode 100644 index 00000000..f42c50e1 --- /dev/null +++ b/example-app/src/main/java/com/github/bekk/exampleapp/tasks/DynamicRecurringTaskExample.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) Bekk + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.github.bekk.exampleapp.tasks; + +import com.github.bekk.exampleapp.model.TaskScheduleAndNoData; +import com.github.kagkarlsson.scheduler.task.TaskWithDataDescriptor; +import com.github.kagkarlsson.scheduler.task.helper.RecurringTaskWithPersistentSchedule; +import com.github.kagkarlsson.scheduler.task.helper.Tasks; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import utils.Utils; + +@Configuration +public class DynamicRecurringTaskExample { + + public static final TaskWithDataDescriptor DYNAMIC_RECURRING_TASK = + new TaskWithDataDescriptor<>("dynamic-recurring-task", TaskScheduleAndNoData.class); + + @Bean + public RecurringTaskWithPersistentSchedule runDynamicRecurringTask() { + return Tasks.recurringWithPersistentSchedule(DYNAMIC_RECURRING_TASK) + .execute( + (inst, ctx) -> { + Utils.sleep(500); + System.out.println("Executed dynamic recurring task: " + inst.getTaskName()); + }); + } +} diff --git a/example-app/src/main/java/com/github/bekk/exampleapp/tasks/SpawnerTask.java b/example-app/src/main/java/com/github/bekk/exampleapp/tasks/SpawnerTask.java index 8f02d4ca..2773bf4c 100644 --- a/example-app/src/main/java/com/github/bekk/exampleapp/tasks/SpawnerTask.java +++ b/example-app/src/main/java/com/github/bekk/exampleapp/tasks/SpawnerTask.java @@ -49,7 +49,7 @@ public Task runSpawner() { client.schedule( ONE_TIME_SPAWNER_TASK.instance( "spawned " + randomUUID + " loopnr: " + i, - new TaskData(123, "{data: MASSIVEDATA}")), + new TaskData(123, "{data: MASSIVEDATA}", Instant.now())), Instant.now().plusSeconds(60)); } }); diff --git a/example-app/src/test/java/com/github/bekk/exampleapp/DynamicRecurringSchedulingTest.java b/example-app/src/test/java/com/github/bekk/exampleapp/DynamicRecurringSchedulingTest.java new file mode 100644 index 00000000..cef90e4c --- /dev/null +++ b/example-app/src/test/java/com/github/bekk/exampleapp/DynamicRecurringSchedulingTest.java @@ -0,0 +1,68 @@ +package com.github.bekk.exampleapp; + +import static com.github.bekk.exampleapp.tasks.DynamicRecurringTaskExample.DYNAMIC_RECURRING_TASK; +import static org.assertj.core.api.Assertions.assertThat; + +import com.github.bekk.exampleapp.model.TaskScheduleAndNoData; +import com.github.kagkarlsson.scheduler.SchedulerClient; +import com.github.kagkarlsson.scheduler.task.schedule.CronSchedule; +import com.github.kagkarlsson.scheduler.task.schedule.Schedules; +import java.time.Instant; +import no.bekk.dbscheduler.ui.controller.TaskController; +import no.bekk.dbscheduler.ui.model.GetTasksResponse; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +@SpringBootTest( + classes = {ExampleApp.class}, + webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +public class DynamicRecurringSchedulingTest { + + @Autowired TaskController controller; + @LocalServerPort private Integer serverPort; + private String baseUrl; + @Autowired private TestRestTemplate restTemplate; + + @Autowired private SchedulerClient schedulerClient; + + @Test + public void testGetTasksReturnsDynamicRecurringTask() { + // Given + CronSchedule cron = Schedules.cron("0 0/1 * * * *"); // every minute + TaskScheduleAndNoData data = new TaskScheduleAndNoData(cron); + + schedulerClient.schedule( + DYNAMIC_RECURRING_TASK.instance("single_instance", data), + cron.getInitialExecutionTime(Instant.now())); + + // When + ResponseEntity result = + this.restTemplate.getForEntity( + baseUrl + + "/db-scheduler-api/tasks/all?filter=ALL&pageNumber=0&size=10&sorting=DEFAULT&asc=true&searchTerm=" + + DYNAMIC_RECURRING_TASK.getTaskName(), + GetTasksResponse.class); + + // Then + Assertions.assertEquals(result.getStatusCode(), HttpStatus.OK); + result.getBody().getItems().forEach(t -> System.out.println(t.getTaskName())); + assertThat(result.getBody().getItems()) + .anyMatch( + taskModel -> taskModel.getTaskName().equals(DYNAMIC_RECURRING_TASK.getTaskName())); + } + + @BeforeEach + public void setUp() { + baseUrl = "http://localhost:" + serverPort; + } +}