diff --git a/pom.xml b/pom.xml index f32a9d68ce920206a55a4d398aab44a4da944e6e..2149fc82bc6f8188e410a8357079fec15be995f1 100644 --- a/pom.xml +++ b/pom.xml @@ -232,6 +232,12 @@ 1.2.0-SNAPSHOT compile + + org.apache.camel + camel-test-spring-junit5 + 3.20.2 + test + diff --git a/src/test/java/org/etsi/osl/metrico/DummyRouteBuilder.java b/src/test/java/org/etsi/osl/metrico/DummyRouteBuilder.java deleted file mode 100644 index fb5d771406416bdd28242eb1964ac6057e9763b3..0000000000000000000000000000000000000000 --- a/src/test/java/org/etsi/osl/metrico/DummyRouteBuilder.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.etsi.osl.metrico; - -import org.apache.camel.builder.RouteBuilder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Profile; -import org.springframework.stereotype.Component; - -@Profile("testing") -@Component -public class DummyRouteBuilder extends RouteBuilder { - private static final Logger logger = LoggerFactory.getLogger(DummyRouteBuilder.class); - - @Value("${PM_MEASUREMENT_COLLECTION_JOB_UPDATE}") - private String PM_MEASUREMENT_COLLECTION_JOB_UPDATE = ""; - @Value("${PM_MEASUREMENT_COLLECTION_GET_JOB_BY_ID}") - private String PM_MEASUREMENT_COLLECTION_GET_JOB_BY_ID = ""; - @Value("${PM_MEASUREMENT_COLLECTION_JOBS_GET}") - private String PM_MEASUREMENT_COLLECTION_JOBS_GET = ""; - @Value("${CATALOG_GET_SERVICE_BY_ID}") - private String CATALOG_GET_SERVICE_BY_ID = ""; - @Value("${CATALOG_UPD_SERVICE}") - private String CATALOG_UPD_SERVICE = ""; - @Value("${CATALOG_GET_RESOURCE_BY_ID}") - private String CATALOG_GET_RESOURCE_BY_ID = ""; - @Value("${CATALOG_UPD_RESOURCE}") - private String CATALOG_UPD_RESOURCE = ""; - @Value("${CATALOG_UPDADD_RESOURCESPEC}") - private String CATALOG_UPDADD_RESOURCESPEC = ""; - - private final String measurementCollectionJobJson = "{\n" + - " \"outputFormat\": \"JSON\",\n" + - " \"@type\": \"MeasurementCollectionJob\",\n" + - " \"consumingApplicationId\": \"app123\",\n" + - " \"producingApplicationId\": \"app456\",\n" + - " \"dataAccessEndpoint\": [],\n" + - " \"jobPriority\": 1,\n" + - " \"lastModifiedTime\": \"2023-01-01T00:00:00Z\",\n" + - " \"scheduleDefinition\": []\n" + - "}"; - - @Override - public void configure() throws Exception { - logger.info("Configuring dummy routes..."); - - from("direct:PM.MEASUREMENTCOLLECTIONJOB.GET_BY_ID") - .process(exchange -> { - logger.info("Processing GET_BY_ID route"); - exchange.getIn().setBody(measurementCollectionJobJson); - }); - } -} \ No newline at end of file diff --git a/src/test/java/org/etsi/osl/metrico/JsonUtilTest.java b/src/test/java/org/etsi/osl/metrico/JsonUtilTest.java index b84de0314815c58d36d097b5e05b9869793ed14d..944e252f9ecca501ab1737cf75da04f035c223e9 100644 --- a/src/test/java/org/etsi/osl/metrico/JsonUtilTest.java +++ b/src/test/java/org/etsi/osl/metrico/JsonUtilTest.java @@ -44,4 +44,14 @@ class JsonUtilTest { assertNull(jsonString); } + @Test + void toJsonString_unserializableObject_returnsNull() { + class SelfRef { + public SelfRef ref; + } + SelfRef obj = new SelfRef(); + obj.ref = obj; // creates a circular reference + String jsonString = JsonUtil.toJsonString(obj); + assertNull(jsonString); + } } \ No newline at end of file diff --git a/src/test/java/org/etsi/osl/metrico/MetricoCommonMethodsTest.java b/src/test/java/org/etsi/osl/metrico/MetricoCommonMethodsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..d66045b1b595fa40a882665d120a4840bd228025 --- /dev/null +++ b/src/test/java/org/etsi/osl/metrico/MetricoCommonMethodsTest.java @@ -0,0 +1,323 @@ +package org.etsi.osl.metrico; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.annotation.PostConstruct; +import org.apache.camel.CamelContext; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.builder.RouteBuilder; +import org.etsi.osl.tmf.common.model.ELifecycle; +import org.etsi.osl.tmf.common.model.EValueType; +import org.etsi.osl.tmf.pm628.model.*; +import org.etsi.osl.tmf.rcm634.model.LogicalResourceSpecification; +import org.etsi.osl.tmf.rcm634.model.ResourceSpecificationCharacteristic; +import org.etsi.osl.tmf.ri639.model.LogicalResource; +import org.etsi.osl.tmf.ri639.model.ResourceUpdate; +import org.etsi.osl.tmf.sim638.model.Service; +import org.etsi.osl.tmf.sim638.model.ServiceUpdate; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.TestConfiguration; + +import java.io.IOException; +import java.net.URI; +import java.time.OffsetDateTime; +import java.util.*; + +import static org.junit.jupiter.api.Assertions.*; + +@SpringBootTest(properties = { + "PM_MEASUREMENT_COLLECTION_JOB_UPDATE = direct:PM.MEASUREMENTCOLLECTIONJOB.UPDATE", + "PM_MEASUREMENT_COLLECTION_GET_JOB_BY_ID = direct:PM.MEASUREMENTCOLLECTIONJOB.GET_BY_ID", + "PM_MEASUREMENT_COLLECTION_JOBS_GET = direct:PM.MEASUREMENTCOLLECTIONJOBS.GET", + "PM_MEASUREMENT_COLLECTION_JOB_GET_INPROGRESS_OR_PENDING = direct:PM.MEASUREMENTCOLLECTIONJOB.GET_INPROGRESS_OR_PENDING", + "CATALOG_GET_SERVICE_BY_ID = direct:CATALOG.GET.SERVICE", + "CATALOG_UPD_SERVICE = direct:CATALOG.UPD.SERVICE", + "CATALOG_GET_RESOURCE_BY_ID = direct:CATALOG.GET.RESOURCE", + "CATALOG_UPD_RESOURCE = direct:CATALOG.UPD.RESOURCE", + "CATALOG_UPDADD_RESOURCESPEC = direct:CATALOG.UPDADD.RESOURCESPEC" +}) +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class MetricoCommonMethodsTest { + + static String OSL_METRICO_RSPEC_NAME = "Metrico_Resource_Specification"; + static String OSL_METRICO_RSPEC_CATEGORY = "metrico.osl.etsi.org/v1"; + static String OSL_METRICO_RSPEC_VERSION = "1.0.0"; + static String OSL_METRICO_RSPEC_DESCRIPTION = "This Specification is used to describe a generic METRICO job resource"; + static String OSL_METRICO_RSPEC_TYPE = "LogicalResourceSpecification"; + + @TestConfiguration + static class CamelTestRoutesConfig { + private final CamelContext camelContext; + + public CamelTestRoutesConfig(CamelContext camelContext) { + this.camelContext = camelContext; + } + + @PostConstruct + public void registerRoutes() throws Exception { + camelContext.addRoutes( + new RouteBuilder() { + @Override + public void configure() { + from("direct:PM.MEASUREMENTCOLLECTIONJOB.UPDATE").bean(MetricoCommonMethodsTest.class, "mockUpdateMeasurementCollectionJob(${header.mcjid}, ${body})"); + from("direct:PM.MEASUREMENTCOLLECTIONJOB.GET_BY_ID").bean(MetricoCommonMethodsTest.class, "mockFindMeasurementCollectionJobByUuidEagerAsString"); + from("direct:PM.MEASUREMENTCOLLECTIONJOBS.GET").bean(MetricoCommonMethodsTest.class, "mockFindAllMeasurementCollectionJobs"); + from("direct:PM.MEASUREMENTCOLLECTIONJOB.GET_INPROGRESS_OR_PENDING").bean(MetricoCommonMethodsTest.class, "mockFindPendingOrInProgressMeasurementCollectionJobsAsJson"); + from("direct:CATALOG.GET.SERVICE").bean(MetricoCommonMethodsTest.class, "mockGetServiceEagerAsString"); + from("direct:CATALOG.UPD.SERVICE").bean(MetricoCommonMethodsTest.class, "mockUpdateService(${header.serviceid}, ${body}, ${header.triggerServiceActionQueue})"); + from("direct:CATALOG.GET.RESOURCE").bean(MetricoCommonMethodsTest.class, "mockGetResourceEagerAsString"); + from("direct:CATALOG.UPD.RESOURCE").bean(MetricoCommonMethodsTest.class, "mockUpdateResource(${header.resourceId}, ${body}, ${header.triggerServiceActionQueue})"); + from("direct:CATALOG.UPDADD.RESOURCESPEC").bean(MetricoCommonMethodsTest.class, "mockAddOrUpdateResourceSpecificationByNameCategoryVersion()"); + } + } + ); + } + } + + @Autowired + private ProducerTemplate template; + @Autowired + private MetricoCommonMethods methods; + + @Test + void testRetrieveMeasurementCollectionJob() throws Exception { + String jobId = "default-job-uuid"; + MeasurementCollectionJob result = methods.retrieveMeasurementCollectionJob(jobId); + assertNotNull(result); + assertEquals(jobId, result.getUuid()); + } + + @Test + void testRetrieveMeasurementCollectionJobNull() throws Exception { + String jobId = "not-in-db-job-uuid"; + MeasurementCollectionJob result = methods.retrieveMeasurementCollectionJob(jobId); + assertNull(result); + } + + @Test + void testRetrieveMeasurementCollectionJobNFromMcjRef() throws Exception { + MeasurementCollectionJobRef mcjRef = new MeasurementCollectionJobRef(); + mcjRef.setId("default-job-uuid"); + MeasurementCollectionJob result = methods.retrieveMeasurementCollectionJob(mcjRef); + assertNotNull(result); + assertEquals(mcjRef.getId(), result.getUuid()); + } + + @Test + void testRetrieveMeasurementCollectionJobNFromMcjRefNull() throws Exception { + MeasurementCollectionJobRef mcjRef = new MeasurementCollectionJobRef(); + mcjRef.setId("not-in-db-job-uuid"); + MeasurementCollectionJob result = methods.retrieveMeasurementCollectionJob(mcjRef); + assertNull(result); + } + + @Test + void testListMeasurementCollectionJob(){ + List jobs = methods.listMeasurementCollectionJob(); + assertNotNull(jobs); + assertFalse(jobs.isEmpty()); + assertEquals(2, jobs.size()); // We mocked two jobs in the method + } + + @Test + void testListPendingOrInProgressMeasurementCollectionJobs() { + List jobs = methods.listPendingOrInProgressMeasurementCollectionJobs(); + assertNull(jobs); + } + + @Test + void testUpdateMeasurementCollectionJobById() { + String jobId = "default-job-uuid"; + MeasurementCollectionJobMVO mcjMVO = new MeasurementCollectionJobMVO(); + mcjMVO.setUuid(jobId); + + mcjMVO.setGranularity(Granularity.G_1H); + + + MeasurementCollectionJob result = methods.updateMeasurementCollectionJobById(jobId, mcjMVO); + MeasurementCollectionJob updatedJob; + + assertNotNull(result); + assertEquals(result.getUuid(), jobId); + assertEquals(Granularity.G_1H, result.getGranularity()); + } + +// Bellow here are the mocked methods for the test class + public static String mockUpdateMeasurementCollectionJob(String uuid, String mcjMVOString) { + MeasurementCollectionJob mcj = defaultMeasurementCollectionJob(); + + MeasurementCollectionJobMVO mcjMVO = null; + try { + mcjMVO = JsonUtil.toJsonObj(mcjMVOString, MeasurementCollectionJobMVO.class); + } catch (IOException e) { + throw new RuntimeException(e); + } + + mcj.setGranularity(mcjMVO.getGranularity()); + + return JsonUtil.toJsonString(mcj); + } + + public static String mockFindMeasurementCollectionJobByUuidEagerAsString(String uuid) { + if(uuid.equals("default-job-uuid")) { + return JsonUtil.toJsonString(defaultMeasurementCollectionJob()); + } + else return null; + } + + public static String mockFindAllMeasurementCollectionJobs() { + MeasurementCollectionJob job1 = defaultMeasurementCollectionJob(); + MeasurementCollectionJob job2 = defaultMeasurementCollectionJob(); + job2.setUuid("another-job-uuid"); + List jobs = List.of(job1, job2); + + try { + ObjectMapper objectMapper = new ObjectMapper(); + String jsonArray; + + List jobJsonStrings = new ArrayList<>(); + for (MeasurementCollectionJob job : jobs) { + jobJsonStrings.add(objectMapper.writeValueAsString(job)); + } + StringJoiner joiner = new StringJoiner(",", "[", "]"); + for (String jobStr : jobJsonStrings) { + joiner.add(jobStr); + } + jsonArray = joiner.toString(); + return jsonArray; + } catch (JsonProcessingException e) { + throw new RuntimeException("Failed to serialize jobs to JSON", e); + } + } + + public static String mockFindPendingOrInProgressMeasurementCollectionJobsAsJson() { + return null; + } + + public static String mockGetServiceEagerAsString(String serviceId) { + try { + Service service = new Service(); + service.setUuid("mock-service-id"); + service.setName("Mock Service"); + // Set other fields as needed for your tests + + ObjectMapper mapper = new ObjectMapper(); + return mapper.writeValueAsString(service); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static String mockUpdateService(String serviceId, ServiceUpdate body, Boolean triggerServiceActionQueue) { + try { + Service service = new Service(); + service.setUuid("mock-service-id"); + service.setName("Updated Mock Service"); + // Optionally, set more fields based on the ServiceUpdate body if needed + + ObjectMapper mapper = new ObjectMapper(); + return mapper.writeValueAsString(service); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static String mockGetResourceEagerAsString(String resourceId) { + try { + LogicalResource resource = new LogicalResource(); + resource.setUuid("mock-service-id"); + resource.setName("Mock Resource"); + // Set other fields as needed for your tests + + ObjectMapper mapper = new ObjectMapper(); + return mapper.writeValueAsString(resource); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static String mockUpdateResource(String resourceId, ResourceUpdate body, Boolean triggerServiceActionQueue) { + try { + LogicalResource resource = new LogicalResource(); + resource.setUuid("mock-service-id"); + resource.setName("Updated Mock Resource"); + // Optionally, set more fields based on the ResourceUpdate body if needed + + ObjectMapper mapper = new ObjectMapper(); + return mapper.writeValueAsString(resource); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static String mockAddOrUpdateResourceSpecificationByNameCategoryVersion() { + return JsonUtil.toJsonString(defaultResourceSpecification()); + } + + + public static LogicalResourceSpecification defaultResourceSpecification() { + LogicalResourceSpecification rsc = new LogicalResourceSpecification(); + rsc.setName(OSL_METRICO_RSPEC_NAME); + rsc.setCategory(OSL_METRICO_RSPEC_CATEGORY); + rsc.setVersion(OSL_METRICO_RSPEC_VERSION); + rsc.setDescription(OSL_METRICO_RSPEC_DESCRIPTION); + rsc.setType(OSL_METRICO_RSPEC_TYPE); + rsc.setLifecycleStatus(ELifecycle.ACTIVE.getValue()); + + ResourceSpecificationCharacteristic characteristic = new ResourceSpecificationCharacteristic(); + characteristic.setValueType(EValueType.TEXT.getValue()); + + characteristic.setName("_MT_CHARACTERISTIC_NAME"); + rsc.addResourceSpecCharacteristicItem(characteristic); + + characteristic.setName("_MT_SERVICEUUID"); + rsc.addResourceSpecCharacteristicItem(characteristic); + + characteristic.setName("_MT_END_TIME"); + rsc.addResourceSpecCharacteristicItem(characteristic); + + characteristic.setName("_MT_START_TIME"); + rsc.addResourceSpecCharacteristicItem(characteristic); + + characteristic.setName("_MT_QUERY"); + rsc.addResourceSpecCharacteristicItem(characteristic); + + characteristic.setName("_MT_URL"); + rsc.addResourceSpecCharacteristicItem(characteristic); + + characteristic.setName("_MT_RECURRING_INTERVAL"); + rsc.addResourceSpecCharacteristicItem(characteristic); + + characteristic.setName("_MT_TYPE"); + rsc.addResourceSpecCharacteristicItem(characteristic); + + return rsc; + } + + static MeasurementCollectionJob defaultMeasurementCollectionJob() { + MeasurementCollectionJob job = new MeasurementCollectionJob(); + job.setCreationTime(OffsetDateTime.now()); + job.setUuid("default-job-uuid"); + job.setGranularity(Granularity.G_1MN); + job.setExecutionState(ExecutionStateType.PENDING); + + DataAccessEndpoint dae = new DataAccessEndpoint(); + dae.setUri(URI.create("http://example.com/data")); + dae.apiType("PROMETHEUS"); + List daeList = new ArrayList<>(); + daeList.add(dae); + job.setDataAccessEndpoint(daeList); + + ScheduleDefinition sd = new ScheduleDefinition(); + sd.setScheduleDefinitionStartTime(OffsetDateTime.now()); + sd.setScheduleDefinitionEndTime(OffsetDateTime.now().plusHours(1)); + List sdList = new ArrayList<>(); + sdList.add(sd); + + return job; + } + +} \ No newline at end of file diff --git a/src/test/java/org/etsi/osl/metrico/prometheus/PrometheusQueriesTest.java b/src/test/java/org/etsi/osl/metrico/prometheus/PrometheusQueriesTest.java index 066e18c797f44a1a7911d2339d62dd22e29b70f3..864af405a2c8da050349bc9b1ece545d2ff8ccb1 100644 --- a/src/test/java/org/etsi/osl/metrico/prometheus/PrometheusQueriesTest.java +++ b/src/test/java/org/etsi/osl/metrico/prometheus/PrometheusQueriesTest.java @@ -7,10 +7,14 @@ import org.etsi.osl.tmf.pm628.model.ExecutionStateType; import org.etsi.osl.tmf.pm628.model.MeasurementCollectionJob; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.lang.reflect.Field; +import java.time.OffsetDateTime; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; @@ -121,4 +125,28 @@ class PrometheusQueriesTest { verify(metricoCommonMethods).updateService(eq("service-uuid"), any(), eq(true)); } + @Test + void testStartPeriodicQuery_SchedulesStopJobWhenEndDateTimePresent() { + Job job = new Job(); + job.setExecutionInterval(100); + job.setEndDateTime(OffsetDateTime.now().plusSeconds(61)); + MeasurementCollectionJob mcj = new MeasurementCollectionJob(); + + ScheduledExecutorService scheduler = mock(ScheduledExecutorService.class); + + try (MockedStatic jobServiceStatic = mockStatic(JobService.class)) { + jobServiceStatic.when(JobService::getScheduler).thenReturn(scheduler); + + when(jobService.startJob(any(Runnable.class), any(Job.class))).thenAnswer(invocation -> { + Job j = invocation.getArgument(1); + j.setState(ExecutionStateType.INPROGRESS); + return j; + }); + + prometheusQueries.startPeriodicQuery("http://localhost:9090", "query=up", job, mcj); + + verify(scheduler).schedule(any(Runnable.class), eq(60L), eq(TimeUnit.SECONDS)); + } + } + } \ No newline at end of file diff --git a/src/test/java/org/etsi/osl/metrico/services/MetricoServiceRouteBuilderTest.java b/src/test/java/org/etsi/osl/metrico/services/MetricoServiceRouteBuilderTest.java new file mode 100644 index 0000000000000000000000000000000000000000..00da713fb19cb058a7918b43d52d2423600d348a --- /dev/null +++ b/src/test/java/org/etsi/osl/metrico/services/MetricoServiceRouteBuilderTest.java @@ -0,0 +1,46 @@ +package org.etsi.osl.metrico.services; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.camel.CamelContext; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.test.spring.junit5.CamelSpringBootTest; +import org.etsi.osl.metrico.MetricoCommonMethods; +import org.etsi.osl.tmf.pm628.model.MeasurementCollectionJob; +import org.etsi.osl.tmf.pm628.model.MeasurementCollectionJobCreateEvent; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.TestPropertySource; + +import static org.mockito.Mockito.*; + +@CamelSpringBootTest +@SpringBootTest +@TestPropertySource(properties = { + "EVENT_MEASUREMENT_COLLECTION_JOB_CREATE=direct:eventMeasurementCollectionJobCreate" +}) +class MetricoServiceRouteBuilderTest { + + @Autowired + private ProducerTemplate producerTemplate; + + @MockBean + private MetricoService metricoService; + + @MockBean + private MetricoCommonMethods metricoCommonMethods; + + @Test + void testRouteCallsMetricoService() throws Exception { + ObjectMapper objectMapper = new ObjectMapper(); + MeasurementCollectionJobCreateEvent event = new MeasurementCollectionJobCreateEvent(); + String eventJson = objectMapper.writeValueAsString(event); + + producerTemplate.sendBody("direct:eventMeasurementCollectionJobCreate", eventJson); + + ArgumentCaptor captor = ArgumentCaptor.forClass(MeasurementCollectionJobCreateEvent.class); + verify(metricoService, timeout(1000)).startPeriodicQueryToPrometheusEvent(captor.capture()); + } +} \ No newline at end of file diff --git a/src/test/java/org/etsi/osl/metrico/services/MetricoServiceTest.java b/src/test/java/org/etsi/osl/metrico/services/MetricoServiceTest.java index 70f9ba903e73d9a807143ebc4bccd05d4328ec09..b74229859f2c7d3a748b6fc78b01bd895c8bef91 100644 --- a/src/test/java/org/etsi/osl/metrico/services/MetricoServiceTest.java +++ b/src/test/java/org/etsi/osl/metrico/services/MetricoServiceTest.java @@ -170,4 +170,114 @@ class MetricoServiceTest { verify(metricoCommonMethods).retrieveMeasurementCollectionJob("123e4567-e89b-12d3-a456-426614174002"); } + + + @Test + void testRestartPendingOrInProgressJobs_skipsJobWithNoDataAccessEndpoint() { + MeasurementCollectionJob mcj = validMCJ(); + mcj.setDataAccessEndpoint(null); + + ArrayList mcjList = new ArrayList<>(); + mcjList.add(mcj); + + when(metricoCommonMethods.listPendingOrInProgressMeasurementCollectionJobs()) + .thenReturn(mcjList); + when(metricoCommonMethods.retrieveMeasurementCollectionJob(mcj.getUuid())) + .thenReturn(mcj); + + metricoService.restartPendingOrInProgressJobs(); + + verify(metricoCommonMethods).updateMeasurementCollectionJobById(eq(mcj.getUuid()), any(MeasurementCollectionJobMVO.class)); + verify(jobService).stopAllJobs(); + } + + @Test + void testRestartPendingOrInProgressJobs_skipsJobWithMultipleDataAccessEndpoints() { + MeasurementCollectionJob mcj = validMCJ(); + DataAccessEndpoint dae2 = new DataAccessEndpoint(); + dae2.setUuid(UUID.randomUUID().toString()); + dae2.setApiType("Prometheus"); + dae2.setUri(URI.create("http://localhost:9091/api/v1/query?query=down")); + List endpoints = new ArrayList<>(mcj.getDataAccessEndpoint()); + endpoints.add(dae2); + mcj.setDataAccessEndpoint(endpoints); + + ArrayList mcjList = new ArrayList<>(); + mcjList.add(mcj); + + when(metricoCommonMethods.listPendingOrInProgressMeasurementCollectionJobs()) + .thenReturn(mcjList); + when(metricoCommonMethods.retrieveMeasurementCollectionJob(mcj.getUuid())) + .thenReturn(mcj); + + metricoService.restartPendingOrInProgressJobs(); + + verify(metricoCommonMethods).updateMeasurementCollectionJobById(eq(mcj.getUuid()), any(MeasurementCollectionJobMVO.class)); + verify(jobService).stopAllJobs(); + } + + @Test + void testRestartPendingOrInProgressJobs_skipsJobWithMultipleScheduleDefinitions() { + MeasurementCollectionJob mcj = validMCJ(); + ScheduleDefinition schedule2 = new ScheduleDefinition(); + schedule2.setScheduleDefinitionStartTime(OffsetDateTime.now().plusSeconds(2)); + schedule2.setScheduleDefinitionEndTime(OffsetDateTime.now().plusHours(2)); + List schedules = new ArrayList<>(mcj.getScheduleDefinition()); + schedules.add(schedule2); + mcj.setScheduleDefinition(schedules); + + ArrayList mcjList = new ArrayList<>(); + mcjList.add(mcj); + + when(metricoCommonMethods.listPendingOrInProgressMeasurementCollectionJobs()) + .thenReturn(mcjList); + when(metricoCommonMethods.retrieveMeasurementCollectionJob(mcj.getUuid())) + .thenReturn(mcj); + + metricoService.restartPendingOrInProgressJobs(); + + verify(metricoCommonMethods).updateMeasurementCollectionJobById(eq(mcj.getUuid()), any(MeasurementCollectionJobMVO.class)); + verify(jobService).stopAllJobs(); + } + + @Test + void testRestartPendingOrInProgressJobs_skipsJobWithEndedScheduleDefinition() { + MeasurementCollectionJob mcj = validMCJ(); + OffsetDateTime start = OffsetDateTime.now().minusHours(2); + OffsetDateTime end = OffsetDateTime.now().minusHours(1); + mcj.getScheduleDefinition().get(0).setScheduleDefinitionStartTime(start); + mcj.getScheduleDefinition().get(0).setScheduleDefinitionEndTime(end); + + ArrayList mcjList = new ArrayList<>(); + mcjList.add(mcj); + + when(metricoCommonMethods.listPendingOrInProgressMeasurementCollectionJobs()) + .thenReturn(mcjList); + when(metricoCommonMethods.retrieveMeasurementCollectionJob(mcj.getUuid())) + .thenReturn(mcj); + + metricoService.restartPendingOrInProgressJobs(); + + verify(metricoCommonMethods).updateMeasurementCollectionJobById(eq(mcj.getUuid()), any(MeasurementCollectionJobMVO.class)); + verify(jobService).stopAllJobs(); + } + + @Test + void testRestartPendingOrInProgressJobs_jobWithNoScheduleDefinition_addsAndSkipsIfEnded() { + MeasurementCollectionJob mcj = validMCJ(); + mcj.setScheduleDefinition(new ArrayList<>()); // No schedule definitions + mcj.setCreationTime(OffsetDateTime.now().minusHours(2)); + ArrayList mcjList = new ArrayList<>(); + mcjList.add(mcj); + + when(metricoCommonMethods.listPendingOrInProgressMeasurementCollectionJobs()) + .thenReturn(mcjList); + when(metricoCommonMethods.retrieveMeasurementCollectionJob(mcj.getUuid())) + .thenReturn(mcj); + + metricoService.restartPendingOrInProgressJobs(); + + verify(metricoCommonMethods).updateMeasurementCollectionJobById(eq(mcj.getUuid()), any(MeasurementCollectionJobMVO.class)); + verify(jobService).stopAllJobs(); + } } \ No newline at end of file