Loading src/main/java/org/etsi/osl/tmf/metrics/api/ServiceOrderMetricsApi.java 0 → 100644 +75 −0 Viewed Changes for src/main/java/org/etsi/osl/tmf/metrics/api/ServiceOrderMetricsApi.java: 75 added lines, 0 removed lines. Original line number Diff line number Diff line package org.etsi.osl.tmf.metrics.api; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import org.etsi.osl.tmf.metrics.ActiveServiceOrders; import org.etsi.osl.tmf.metrics.ServiceOrdersGroupByDay; import org.etsi.osl.tmf.metrics.ServiceOrdersGroupByState; import org.etsi.osl.tmf.metrics.TotalServiceOrders; import org.etsi.osl.tmf.so641.model.ServiceOrderStateType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import java.time.OffsetDateTime; import java.util.Map; @Tag(name = "MetricsApi") public interface ServiceOrderMetricsApi { Logger log = LoggerFactory.getLogger(ServiceOrderMetricsApi.class); @Operation(summary = "Get total number of service orders", operationId = "getTotalServiceOrders") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Success"), @ApiResponse(responseCode = "400", description = "Bad Request"), @ApiResponse(responseCode = "500", description = "Internal Server Error") }) @RequestMapping(value = "/metrics/totalServiceOrders", method = RequestMethod.GET, produces = "application/json;charset=utf-8") ResponseEntity<TotalServiceOrders> getTotalServiceOrders( @Valid @RequestParam(value = "state", required = false) ServiceOrderStateType state ); @Operation(summary = "Get total number of active service orders", operationId = "getTotalActiveServiceOrders") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Success"), @ApiResponse(responseCode = "400", description = "Bad Request"), @ApiResponse(responseCode = "500", description = "Internal Server Error") }) @RequestMapping(value = "/metrics/activeServiceOrders", method = RequestMethod.GET, produces = "application/json;charset=utf-8") ResponseEntity<ActiveServiceOrders> getTotalActiveServiceOrders(); @Operation(summary = "Get service orders grouped by day", operationId = "getServiceOrdersGroupedByDay") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Success"), @ApiResponse(responseCode = "400", description = "Bad Request"), @ApiResponse(responseCode = "500", description = "Internal Server Error") }) @RequestMapping(value = "/metrics/serviceOrdersGroupByDay", method = RequestMethod.GET, produces = "application/json;charset=utf-8") ResponseEntity<ServiceOrdersGroupByDay> getServiceOrdersGroupedByDay( @Valid @RequestParam(value = "starttime", required = true) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) OffsetDateTime starttime, @Valid @RequestParam(value = "endtime", required = true) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) OffsetDateTime endtime ); @Operation(summary = "Get service orders grouped by state", operationId = "getServiceOrdersGroupedByState") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Success"), @ApiResponse(responseCode = "400", description = "Bad Request"), @ApiResponse(responseCode = "500", description = "Internal Server Error") }) @RequestMapping(value = "/metrics/serviceOrdersGroupByState", method = RequestMethod.GET, produces = "application/json;charset=utf-8") ResponseEntity<ServiceOrdersGroupByState> getServiceOrdersGroupedByState( @Valid @RequestParam(value = "starttime", required = true) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) OffsetDateTime starttime, @Valid @RequestParam(value = "endtime", required = true) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) OffsetDateTime endtime ); } src/main/java/org/etsi/osl/tmf/metrics/api/ServiceOrderMetricsApiController.java 0 → 100644 +123 −0 Viewed Changes for src/main/java/org/etsi/osl/tmf/metrics/api/ServiceOrderMetricsApiController.java: 123 added lines, 0 removed lines. Original line number Diff line number Diff line package org.etsi.osl.tmf.metrics.api; import org.etsi.osl.tmf.metrics.*; import org.etsi.osl.tmf.metrics.reposervices.ServiceOrderMetricsRepoService; import org.etsi.osl.tmf.so641.model.ServiceOrderStateType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import java.time.OffsetDateTime; import java.time.temporal.ChronoUnit; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @Controller public class ServiceOrderMetricsApiController implements ServiceOrderMetricsApi { private static final Logger log = LoggerFactory.getLogger(ServiceOrderMetricsApiController.class); private final ServiceOrderMetricsRepoService serviceOrderMetricsRepoService; @Autowired public ServiceOrderMetricsApiController(ServiceOrderMetricsRepoService serviceOrderMetricsRepoService) { this.serviceOrderMetricsRepoService = serviceOrderMetricsRepoService; } @Override public ResponseEntity<TotalServiceOrders> getTotalServiceOrders(ServiceOrderStateType state) { try { int totalServiceOrders = serviceOrderMetricsRepoService.countTotalServiceOrders(state); TotalServiceOrders response = new TotalServiceOrders(totalServiceOrders); return new ResponseEntity<>(response, HttpStatus.OK); } catch (Exception e) { log.error("Couldn't retrieve total service orders. ", e); return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } } @Override public ResponseEntity<ActiveServiceOrders> getTotalActiveServiceOrders() { try { int totalActiveServiceOrders = serviceOrderMetricsRepoService.countTotalActiveServiceOrders(); ActiveServiceOrders response = new ActiveServiceOrders(totalActiveServiceOrders); return new ResponseEntity<>(response, HttpStatus.OK); } catch (Exception e) { log.error("Couldn't retrieve total active service orders. ", e); return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } } @Override public ResponseEntity<ServiceOrdersGroupByDay> getServiceOrdersGroupedByDay(OffsetDateTime starttime, OffsetDateTime endtime) { try { Map<String, Integer> orderDatesGroupedByDate = serviceOrderMetricsRepoService.getServiceOrdersGroupedByDay(starttime, endtime); // Fill missing days with count 0 Map<String, Integer> fullDayMap = new LinkedHashMap<>(); OffsetDateTime cursor = starttime.truncatedTo(ChronoUnit.DAYS); OffsetDateTime endDay = endtime.truncatedTo(ChronoUnit.DAYS); while (!cursor.isAfter(endDay)) { String key = cursor.toInstant().toString(); fullDayMap.put(key, orderDatesGroupedByDate.getOrDefault(key, 0)); cursor = cursor.plusDays(1); } // Convert to model list List<ServiceOrdersGroupByDayItem> groupByDayList = fullDayMap.entrySet().stream() .map(entry -> new ServiceOrdersGroupByDayItem(entry.getKey(), entry.getValue())) .toList(); ServiceOrdersGroupByDayAggregations aggregations = new ServiceOrdersGroupByDayAggregations(groupByDayList); int total = fullDayMap.values().stream().mapToInt(Integer::intValue).sum(); ServiceOrdersGroupByDayParent wrapper = new ServiceOrdersGroupByDayParent(total, aggregations); ServiceOrdersGroupByDay response = new ServiceOrdersGroupByDay(wrapper); return new ResponseEntity<>(response, HttpStatus.OK); } catch (Exception e) { log.error("Couldn't retrieve services grouped by state. ", e); return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } } @Override public ResponseEntity<ServiceOrdersGroupByState> getServiceOrdersGroupedByState(OffsetDateTime starttime, OffsetDateTime endtime) { try { Map<String, Integer> servicesByState = serviceOrderMetricsRepoService.getServiceOrdersGroupedByState(starttime, endtime); // Initialize with all possible states and 0. Ensures that all states are represented, even if not present in the data. Map<String, Integer> fullStateMap = new LinkedHashMap<>(); for (ServiceOrderStateType state : ServiceOrderStateType.values()) { fullStateMap.put(state.name(), 0); } // Overwrite counts with actual data servicesByState.forEach((key, value) -> { fullStateMap.put(key.toUpperCase(), value); }); // Create aggregation items List<ServiceOrdersGroupByStateItem> groupByStateList = fullStateMap.entrySet().stream() .map(entry -> new ServiceOrdersGroupByStateItem(ServiceOrderStateType.valueOf(entry.getKey()), entry.getValue())) .toList(); // Build response structure using models ServiceOrdersGroupByStateAggregations aggregations = new ServiceOrdersGroupByStateAggregations(groupByStateList); int total = fullStateMap.values().stream().mapToInt(Integer::intValue).sum(); ServiceOrdersGroupByStateParent services = new ServiceOrdersGroupByStateParent(total, aggregations); ServiceOrdersGroupByState response = new ServiceOrdersGroupByState(services); return new ResponseEntity<>(response, HttpStatus.OK); } catch (Exception e) { log.error("Couldn't retrieve services grouped by state. ", e); return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } } } src/main/java/org/etsi/osl/tmf/metrics/reposervices/ServiceOrderMetricsRepoService.java 0 → 100644 +79 −0 Viewed Changes for src/main/java/org/etsi/osl/tmf/metrics/reposervices/ServiceOrderMetricsRepoService.java: 79 added lines, 0 removed lines. Original line number Diff line number Diff line package org.etsi.osl.tmf.metrics.reposervices; import com.fasterxml.jackson.databind.ObjectMapper; import org.etsi.osl.tmf.so641.model.ServiceOrderStateType; import org.etsi.osl.tmf.so641.repo.ServiceOrderRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.time.OffsetDateTime; import java.time.temporal.ChronoUnit; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @Service public class ServiceOrderMetricsRepoService { @Autowired ObjectMapper objectMapper; @Autowired ServiceOrderRepository serviceOrderRepository; public int countTotalServiceOrders(ServiceOrderStateType state) { if (state == null) { return serviceOrderRepository.countAll(); } else { return serviceOrderRepository.countByState(state); } } public int countTotalActiveServiceOrders() { OffsetDateTime currentDate = OffsetDateTime.now(); List<ServiceOrderStateType> activeStates = List.of( ServiceOrderStateType.INPROGRESS, ServiceOrderStateType.COMPLETED ); return serviceOrderRepository.countAllActive(currentDate, activeStates); } public Map<String, Integer> getServiceOrdersGroupedByDay(OffsetDateTime starttime, OffsetDateTime endtime) { if (starttime.plusDays(31).isBefore(endtime)) { starttime = endtime.minusDays(31); } List<OffsetDateTime> orderDates = serviceOrderRepository.getOrderDatesBetweenDates(starttime, endtime); // First group by day with count as Long Map<String, Long> grouped = orderDates.stream() .map(dt -> dt.truncatedTo(ChronoUnit.DAYS)) // Remove time portion .collect(Collectors.groupingBy( dt -> dt.toInstant().toString(), // Format as ISO string (Z) Collectors.counting() )); // Convert Map<String, Long> to Map<String, Integer> return grouped.entrySet().stream() .collect(Collectors.toMap( Map.Entry::getKey, e -> e.getValue().intValue() )); } public Map<String, Integer> getServiceOrdersGroupedByState(OffsetDateTime starttime, OffsetDateTime endtime) { if (starttime.plusDays(31).isBefore(endtime)) { starttime = endtime.minusDays(31); } List<Object[]> rawResults = serviceOrderRepository.groupByStateBetweenDates(starttime, endtime); return rawResults.stream() .collect(Collectors.toMap( row -> row[0].toString(), row -> ((Number) row[1]).intValue() )); } } src/main/java/org/etsi/osl/tmf/so641/repo/ServiceOrderRepository.java +24 −0 Viewed Changes for src/main/java/org/etsi/osl/tmf/so641/repo/ServiceOrderRepository.java: 24 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ */ package org.etsi.osl.tmf.so641.repo; import java.time.OffsetDateTime; import java.util.List; import java.util.Optional; import org.etsi.osl.tmf.common.model.UserPartRoleType; Loading Loading @@ -51,4 +52,27 @@ public interface ServiceOrderRepository extends JpaRepository<ServiceOrder, Long + "WHERE sor.uuid = ?1 " + "ORDER BY an.date ASC") Optional<ServiceOrder> findNotesOfServOrder(String id); // Methods for metrics @Query("SELECT COUNT(sor) FROM ServiceOrder sor") int countAll(); int countByState(ServiceOrderStateType state); @Query("SELECT COUNT(sor) FROM ServiceOrder sor " + "WHERE sor.state IN :states " + "AND sor.requestedStartDate < :currentDate AND sor.requestedCompletionDate > :currentDate") int countAllActive(OffsetDateTime currentDate, List<ServiceOrderStateType> states); @Query("SELECT sor.state, COUNT(sor) FROM ServiceOrder sor " + "WHERE sor.orderDate >= :starttime AND sor.orderDate <= :endtime " + "GROUP BY sor.state") List<Object[]> groupByStateBetweenDates(OffsetDateTime starttime, OffsetDateTime endtime); @Query("SELECT sor.orderDate FROM ServiceOrder sor " + "WHERE sor.orderDate >= :starttime AND sor.orderDate <= :endtime") List<OffsetDateTime> getOrderDatesBetweenDates(OffsetDateTime starttime, OffsetDateTime endtime); } src/test/java/org/etsi/osl/services/api/metrics/ServiceOrderMetricsApiControllerTest.java 0 → 100644 +254 −0 Viewed Changes for src/test/java/org/etsi/osl/services/api/metrics/ServiceOrderMetricsApiControllerTest.java: 254 added lines, 0 removed lines. Original line number Diff line number Diff line package org.etsi.osl.services.api.metrics; import com.jayway.jsonpath.JsonPath; import org.etsi.osl.tmf.JsonUtils; import org.etsi.osl.tmf.OpenAPISpringBoot; import org.etsi.osl.tmf.so641.model.*; import org.etsi.osl.tmf.so641.reposervices.ServiceOrderRepoService; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.MediaType; import org.springframework.security.test.context.support.WithMockUser; import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.context.WebApplicationContext; import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @RunWith(SpringRunner.class) @Transactional @SpringBootTest( webEnvironment = SpringBootTest.WebEnvironment.MOCK, classes = OpenAPISpringBoot.class ) //@AutoConfigureTestDatabase //this automatically uses h2 @AutoConfigureMockMvc @ActiveProfiles("testing") //@TestPropertySource( // locations = "classpath:application-testing.yml") public class ServiceOrderMetricsApiControllerTest { @Autowired private MockMvc mvc; @Autowired ServiceOrderRepoService serviceOrderRepoService; @Autowired private WebApplicationContext context; @Before public void setup() throws Exception { mvc = MockMvcBuilders .webAppContextSetup(context) .apply(springSecurity()) .build(); } @WithMockUser(username="osadmin", roles = {"ADMIN","USER"}) @Test public void testCountTotalServiceOrders() throws Exception { createServiceOrder(ServiceOrderStateType.INPROGRESS); String response = mvc.perform(MockMvcRequestBuilders.get("/metrics/totalServiceOrders" ) .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isOk() ) .andReturn().getResponse().getContentAsString(); int totalServiceOrders = JsonPath.read(response, "$.totalServiceOrders"); assertThat(totalServiceOrders).isEqualTo(serviceOrderRepoService.findAll().size()); } @WithMockUser(username="osadmin", roles = {"ADMIN","USER"}) @Test public void testCountTotalServiceOrdersWithState() throws Exception { createServiceOrder(ServiceOrderStateType.INPROGRESS); createServiceOrder(ServiceOrderStateType.ACKNOWLEDGED); String response = mvc.perform(MockMvcRequestBuilders.get("/metrics/totalServiceOrders" ) .param("state", "ACKNOWLEDGED") .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isOk() ) .andReturn().getResponse().getContentAsString(); int totalServiceOrders = JsonPath.read(response, "$.totalServiceOrders"); List<ServiceOrder> serviceOrdersList = serviceOrderRepoService.findAll(); int activeServiceOrders = (int) serviceOrdersList.stream().filter(serviceOrder -> serviceOrder.getState() == ServiceOrderStateType.ACKNOWLEDGED).count(); assertThat(totalServiceOrders).isEqualTo(activeServiceOrders); assertThat(activeServiceOrders).isEqualTo(1); } @WithMockUser(username="osadmin", roles = {"ADMIN","USER"}) @Test public void testGetTotalActiveServiceOrders() throws Exception { createServiceOrder(ServiceOrderStateType.INPROGRESS); createServiceOrder(ServiceOrderStateType.INPROGRESS); createServiceOrder(ServiceOrderStateType.COMPLETED); createServiceOrder(ServiceOrderStateType.COMPLETED); createServiceOrder(ServiceOrderStateType.ACKNOWLEDGED); createServiceOrder(ServiceOrderStateType.REJECTED); String response = mvc.perform(MockMvcRequestBuilders.get("/metrics/activeServiceOrders" ) .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isOk() ) .andReturn().getResponse().getContentAsString(); int totalServiceOrders = JsonPath.read(response, "$.activeServiceOrders"); assertThat(totalServiceOrders).isEqualTo(4); } @WithMockUser(username = "osadmin", roles = {"ADMIN", "USER"}) @Test public void testGetServiceOrdersGroupedByDay() throws Exception { String startTime = OffsetDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT); createServiceOrder(ServiceOrderStateType.INPROGRESS); createServiceOrder(ServiceOrderStateType.INPROGRESS); createServiceOrder(ServiceOrderStateType.INPROGRESS); createServiceOrder(ServiceOrderStateType.ACKNOWLEDGED); createServiceOrder(ServiceOrderStateType.ACKNOWLEDGED); createServiceOrder(ServiceOrderStateType.PARTIAL); String endTime = OffsetDateTime.now(ZoneOffset.UTC).plusDays(4).format(DateTimeFormatter.ISO_INSTANT); String response = mvc.perform(MockMvcRequestBuilders.get("/metrics/serviceOrdersGroupByDay") .param("starttime", startTime) .param("endtime", endTime) .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(); List<Map<String, Object>> groupByDay = JsonPath.read(response, "$.serviceOrders.aggregations.groupByDay"); OffsetDateTime start = OffsetDateTime.parse(startTime); OffsetDateTime end = OffsetDateTime.parse(endTime); DateTimeFormatter formatter = DateTimeFormatter.ISO_INSTANT; Map<String, Integer> dayCounts = groupByDay.stream() .collect(Collectors.toMap( entry -> (String) entry.get("key"), entry -> (Integer) entry.get("count") )); int totalDays = (int) ChronoUnit.DAYS.between(start.toLocalDate(), end.toLocalDate()) + 1; for (int i = 0; i < totalDays; i++) { OffsetDateTime day = start.plusDays(i).toLocalDate().atStartOfDay().atOffset(ZoneOffset.UTC); String dayKey = formatter.format(day.toInstant()); if (i == 0) { // Today: should have all 6 assertThat(dayCounts.get(dayKey)).isEqualTo(6); } else { // Other days: should be 0 assertThat(dayCounts.get(dayKey)).isEqualTo(0); } } } @WithMockUser(username = "osadmin", roles = {"ADMIN", "USER"}) @Test public void testGetServiceOrdersGroupedByState() throws Exception { String startTime = OffsetDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT); createServiceOrder(ServiceOrderStateType.INPROGRESS); createServiceOrder(ServiceOrderStateType.INPROGRESS); createServiceOrder(ServiceOrderStateType.INPROGRESS); createServiceOrder(ServiceOrderStateType.ACKNOWLEDGED); createServiceOrder(ServiceOrderStateType.ACKNOWLEDGED); createServiceOrder(ServiceOrderStateType.PARTIAL); String endTime = OffsetDateTime.now(ZoneOffset.UTC).plusDays(4).format(DateTimeFormatter.ISO_INSTANT); String response = mvc.perform(MockMvcRequestBuilders.get("/metrics/serviceOrdersGroupByState") .param("starttime", startTime) .param("endtime", endTime) .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(); List<Map<String, Object>> groupByState = JsonPath.read(response, "$.serviceOrders.aggregations.groupByState"); // Create a map from key -> count Map<String, Integer> stateCounts = groupByState.stream() .collect(Collectors.toMap( entry -> (String) entry.get("key"), entry -> (Integer) entry.get("count") )); assertThat(stateCounts.get("INPROGRESS")).isEqualTo(3); assertThat(stateCounts.get("ACKNOWLEDGED")).isEqualTo(2); assertThat(stateCounts.get("PARTIAL")).isEqualTo(1); assertThat(stateCounts.get("INITIAL")).isEqualTo(0); assertThat(stateCounts.get("REJECTED")).isEqualTo(0); assertThat(stateCounts.get("PENDING")).isEqualTo(0); assertThat(stateCounts.get("HELD")).isEqualTo(0); assertThat(stateCounts.get("CANCELLED")).isEqualTo(0); assertThat(stateCounts.get("COMPLETED")).isEqualTo(0); assertThat(stateCounts.get("FAILED")).isEqualTo(0); } private void createServiceOrder(ServiceOrderStateType stateType) throws Exception { ServiceOrderCreate serviceOrder = new ServiceOrderCreate(); serviceOrder.setCategory("Test Category"); serviceOrder.setDescription("A Test Service Order"); serviceOrder.setRequestedStartDate(OffsetDateTime.now(ZoneOffset.UTC).toString()); serviceOrder.setRequestedCompletionDate(OffsetDateTime.now(ZoneOffset.UTC).plusDays(3).toString()); String response = mvc .perform(MockMvcRequestBuilders.post("/serviceOrdering/v4/serviceOrder") .with( SecurityMockMvcRequestPostProcessors.csrf()) .contentType(MediaType.APPLICATION_JSON).content(JsonUtils.toJson(serviceOrder))) .andExpect(status().isOk()).andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()).andReturn().getResponse().getContentAsString(); ServiceOrder responseSO = JsonUtils.toJsonObj(response, ServiceOrder.class); // Update Service Order State String soId = responseSO.getId(); ServiceOrderUpdate servOrderUpd = new ServiceOrderUpdate(); servOrderUpd.setState(stateType); String response2 = mvc.perform(MockMvcRequestBuilders.patch("/serviceOrdering/v4/serviceOrder/" + soId) .with( SecurityMockMvcRequestPostProcessors.csrf()) .contentType(MediaType.APPLICATION_JSON) .content( JsonUtils.toJson( servOrderUpd ) )) .andExpect(status().isOk() ) .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)) .andReturn().getResponse().getContentAsString(); ServiceOrder responsesServiceOrder2 = JsonUtils.toJsonObj(response2, ServiceOrder.class); assertThat(responsesServiceOrder2.getState().toString()).isEqualTo(stateType.toString()); } } Loading
src/main/java/org/etsi/osl/tmf/metrics/api/ServiceOrderMetricsApi.java 0 → 100644 +75 −0 Viewed Changes for src/main/java/org/etsi/osl/tmf/metrics/api/ServiceOrderMetricsApi.java: 75 added lines, 0 removed lines. Original line number Diff line number Diff line package org.etsi.osl.tmf.metrics.api; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import org.etsi.osl.tmf.metrics.ActiveServiceOrders; import org.etsi.osl.tmf.metrics.ServiceOrdersGroupByDay; import org.etsi.osl.tmf.metrics.ServiceOrdersGroupByState; import org.etsi.osl.tmf.metrics.TotalServiceOrders; import org.etsi.osl.tmf.so641.model.ServiceOrderStateType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import java.time.OffsetDateTime; import java.util.Map; @Tag(name = "MetricsApi") public interface ServiceOrderMetricsApi { Logger log = LoggerFactory.getLogger(ServiceOrderMetricsApi.class); @Operation(summary = "Get total number of service orders", operationId = "getTotalServiceOrders") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Success"), @ApiResponse(responseCode = "400", description = "Bad Request"), @ApiResponse(responseCode = "500", description = "Internal Server Error") }) @RequestMapping(value = "/metrics/totalServiceOrders", method = RequestMethod.GET, produces = "application/json;charset=utf-8") ResponseEntity<TotalServiceOrders> getTotalServiceOrders( @Valid @RequestParam(value = "state", required = false) ServiceOrderStateType state ); @Operation(summary = "Get total number of active service orders", operationId = "getTotalActiveServiceOrders") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Success"), @ApiResponse(responseCode = "400", description = "Bad Request"), @ApiResponse(responseCode = "500", description = "Internal Server Error") }) @RequestMapping(value = "/metrics/activeServiceOrders", method = RequestMethod.GET, produces = "application/json;charset=utf-8") ResponseEntity<ActiveServiceOrders> getTotalActiveServiceOrders(); @Operation(summary = "Get service orders grouped by day", operationId = "getServiceOrdersGroupedByDay") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Success"), @ApiResponse(responseCode = "400", description = "Bad Request"), @ApiResponse(responseCode = "500", description = "Internal Server Error") }) @RequestMapping(value = "/metrics/serviceOrdersGroupByDay", method = RequestMethod.GET, produces = "application/json;charset=utf-8") ResponseEntity<ServiceOrdersGroupByDay> getServiceOrdersGroupedByDay( @Valid @RequestParam(value = "starttime", required = true) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) OffsetDateTime starttime, @Valid @RequestParam(value = "endtime", required = true) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) OffsetDateTime endtime ); @Operation(summary = "Get service orders grouped by state", operationId = "getServiceOrdersGroupedByState") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Success"), @ApiResponse(responseCode = "400", description = "Bad Request"), @ApiResponse(responseCode = "500", description = "Internal Server Error") }) @RequestMapping(value = "/metrics/serviceOrdersGroupByState", method = RequestMethod.GET, produces = "application/json;charset=utf-8") ResponseEntity<ServiceOrdersGroupByState> getServiceOrdersGroupedByState( @Valid @RequestParam(value = "starttime", required = true) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) OffsetDateTime starttime, @Valid @RequestParam(value = "endtime", required = true) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) OffsetDateTime endtime ); }
src/main/java/org/etsi/osl/tmf/metrics/api/ServiceOrderMetricsApiController.java 0 → 100644 +123 −0 Viewed Changes for src/main/java/org/etsi/osl/tmf/metrics/api/ServiceOrderMetricsApiController.java: 123 added lines, 0 removed lines. Original line number Diff line number Diff line package org.etsi.osl.tmf.metrics.api; import org.etsi.osl.tmf.metrics.*; import org.etsi.osl.tmf.metrics.reposervices.ServiceOrderMetricsRepoService; import org.etsi.osl.tmf.so641.model.ServiceOrderStateType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import java.time.OffsetDateTime; import java.time.temporal.ChronoUnit; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @Controller public class ServiceOrderMetricsApiController implements ServiceOrderMetricsApi { private static final Logger log = LoggerFactory.getLogger(ServiceOrderMetricsApiController.class); private final ServiceOrderMetricsRepoService serviceOrderMetricsRepoService; @Autowired public ServiceOrderMetricsApiController(ServiceOrderMetricsRepoService serviceOrderMetricsRepoService) { this.serviceOrderMetricsRepoService = serviceOrderMetricsRepoService; } @Override public ResponseEntity<TotalServiceOrders> getTotalServiceOrders(ServiceOrderStateType state) { try { int totalServiceOrders = serviceOrderMetricsRepoService.countTotalServiceOrders(state); TotalServiceOrders response = new TotalServiceOrders(totalServiceOrders); return new ResponseEntity<>(response, HttpStatus.OK); } catch (Exception e) { log.error("Couldn't retrieve total service orders. ", e); return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } } @Override public ResponseEntity<ActiveServiceOrders> getTotalActiveServiceOrders() { try { int totalActiveServiceOrders = serviceOrderMetricsRepoService.countTotalActiveServiceOrders(); ActiveServiceOrders response = new ActiveServiceOrders(totalActiveServiceOrders); return new ResponseEntity<>(response, HttpStatus.OK); } catch (Exception e) { log.error("Couldn't retrieve total active service orders. ", e); return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } } @Override public ResponseEntity<ServiceOrdersGroupByDay> getServiceOrdersGroupedByDay(OffsetDateTime starttime, OffsetDateTime endtime) { try { Map<String, Integer> orderDatesGroupedByDate = serviceOrderMetricsRepoService.getServiceOrdersGroupedByDay(starttime, endtime); // Fill missing days with count 0 Map<String, Integer> fullDayMap = new LinkedHashMap<>(); OffsetDateTime cursor = starttime.truncatedTo(ChronoUnit.DAYS); OffsetDateTime endDay = endtime.truncatedTo(ChronoUnit.DAYS); while (!cursor.isAfter(endDay)) { String key = cursor.toInstant().toString(); fullDayMap.put(key, orderDatesGroupedByDate.getOrDefault(key, 0)); cursor = cursor.plusDays(1); } // Convert to model list List<ServiceOrdersGroupByDayItem> groupByDayList = fullDayMap.entrySet().stream() .map(entry -> new ServiceOrdersGroupByDayItem(entry.getKey(), entry.getValue())) .toList(); ServiceOrdersGroupByDayAggregations aggregations = new ServiceOrdersGroupByDayAggregations(groupByDayList); int total = fullDayMap.values().stream().mapToInt(Integer::intValue).sum(); ServiceOrdersGroupByDayParent wrapper = new ServiceOrdersGroupByDayParent(total, aggregations); ServiceOrdersGroupByDay response = new ServiceOrdersGroupByDay(wrapper); return new ResponseEntity<>(response, HttpStatus.OK); } catch (Exception e) { log.error("Couldn't retrieve services grouped by state. ", e); return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } } @Override public ResponseEntity<ServiceOrdersGroupByState> getServiceOrdersGroupedByState(OffsetDateTime starttime, OffsetDateTime endtime) { try { Map<String, Integer> servicesByState = serviceOrderMetricsRepoService.getServiceOrdersGroupedByState(starttime, endtime); // Initialize with all possible states and 0. Ensures that all states are represented, even if not present in the data. Map<String, Integer> fullStateMap = new LinkedHashMap<>(); for (ServiceOrderStateType state : ServiceOrderStateType.values()) { fullStateMap.put(state.name(), 0); } // Overwrite counts with actual data servicesByState.forEach((key, value) -> { fullStateMap.put(key.toUpperCase(), value); }); // Create aggregation items List<ServiceOrdersGroupByStateItem> groupByStateList = fullStateMap.entrySet().stream() .map(entry -> new ServiceOrdersGroupByStateItem(ServiceOrderStateType.valueOf(entry.getKey()), entry.getValue())) .toList(); // Build response structure using models ServiceOrdersGroupByStateAggregations aggregations = new ServiceOrdersGroupByStateAggregations(groupByStateList); int total = fullStateMap.values().stream().mapToInt(Integer::intValue).sum(); ServiceOrdersGroupByStateParent services = new ServiceOrdersGroupByStateParent(total, aggregations); ServiceOrdersGroupByState response = new ServiceOrdersGroupByState(services); return new ResponseEntity<>(response, HttpStatus.OK); } catch (Exception e) { log.error("Couldn't retrieve services grouped by state. ", e); return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } } }
src/main/java/org/etsi/osl/tmf/metrics/reposervices/ServiceOrderMetricsRepoService.java 0 → 100644 +79 −0 Viewed Changes for src/main/java/org/etsi/osl/tmf/metrics/reposervices/ServiceOrderMetricsRepoService.java: 79 added lines, 0 removed lines. Original line number Diff line number Diff line package org.etsi.osl.tmf.metrics.reposervices; import com.fasterxml.jackson.databind.ObjectMapper; import org.etsi.osl.tmf.so641.model.ServiceOrderStateType; import org.etsi.osl.tmf.so641.repo.ServiceOrderRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.time.OffsetDateTime; import java.time.temporal.ChronoUnit; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @Service public class ServiceOrderMetricsRepoService { @Autowired ObjectMapper objectMapper; @Autowired ServiceOrderRepository serviceOrderRepository; public int countTotalServiceOrders(ServiceOrderStateType state) { if (state == null) { return serviceOrderRepository.countAll(); } else { return serviceOrderRepository.countByState(state); } } public int countTotalActiveServiceOrders() { OffsetDateTime currentDate = OffsetDateTime.now(); List<ServiceOrderStateType> activeStates = List.of( ServiceOrderStateType.INPROGRESS, ServiceOrderStateType.COMPLETED ); return serviceOrderRepository.countAllActive(currentDate, activeStates); } public Map<String, Integer> getServiceOrdersGroupedByDay(OffsetDateTime starttime, OffsetDateTime endtime) { if (starttime.plusDays(31).isBefore(endtime)) { starttime = endtime.minusDays(31); } List<OffsetDateTime> orderDates = serviceOrderRepository.getOrderDatesBetweenDates(starttime, endtime); // First group by day with count as Long Map<String, Long> grouped = orderDates.stream() .map(dt -> dt.truncatedTo(ChronoUnit.DAYS)) // Remove time portion .collect(Collectors.groupingBy( dt -> dt.toInstant().toString(), // Format as ISO string (Z) Collectors.counting() )); // Convert Map<String, Long> to Map<String, Integer> return grouped.entrySet().stream() .collect(Collectors.toMap( Map.Entry::getKey, e -> e.getValue().intValue() )); } public Map<String, Integer> getServiceOrdersGroupedByState(OffsetDateTime starttime, OffsetDateTime endtime) { if (starttime.plusDays(31).isBefore(endtime)) { starttime = endtime.minusDays(31); } List<Object[]> rawResults = serviceOrderRepository.groupByStateBetweenDates(starttime, endtime); return rawResults.stream() .collect(Collectors.toMap( row -> row[0].toString(), row -> ((Number) row[1]).intValue() )); } }
src/main/java/org/etsi/osl/tmf/so641/repo/ServiceOrderRepository.java +24 −0 Viewed Changes for src/main/java/org/etsi/osl/tmf/so641/repo/ServiceOrderRepository.java: 24 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ */ package org.etsi.osl.tmf.so641.repo; import java.time.OffsetDateTime; import java.util.List; import java.util.Optional; import org.etsi.osl.tmf.common.model.UserPartRoleType; Loading Loading @@ -51,4 +52,27 @@ public interface ServiceOrderRepository extends JpaRepository<ServiceOrder, Long + "WHERE sor.uuid = ?1 " + "ORDER BY an.date ASC") Optional<ServiceOrder> findNotesOfServOrder(String id); // Methods for metrics @Query("SELECT COUNT(sor) FROM ServiceOrder sor") int countAll(); int countByState(ServiceOrderStateType state); @Query("SELECT COUNT(sor) FROM ServiceOrder sor " + "WHERE sor.state IN :states " + "AND sor.requestedStartDate < :currentDate AND sor.requestedCompletionDate > :currentDate") int countAllActive(OffsetDateTime currentDate, List<ServiceOrderStateType> states); @Query("SELECT sor.state, COUNT(sor) FROM ServiceOrder sor " + "WHERE sor.orderDate >= :starttime AND sor.orderDate <= :endtime " + "GROUP BY sor.state") List<Object[]> groupByStateBetweenDates(OffsetDateTime starttime, OffsetDateTime endtime); @Query("SELECT sor.orderDate FROM ServiceOrder sor " + "WHERE sor.orderDate >= :starttime AND sor.orderDate <= :endtime") List<OffsetDateTime> getOrderDatesBetweenDates(OffsetDateTime starttime, OffsetDateTime endtime); }
src/test/java/org/etsi/osl/services/api/metrics/ServiceOrderMetricsApiControllerTest.java 0 → 100644 +254 −0 Viewed Changes for src/test/java/org/etsi/osl/services/api/metrics/ServiceOrderMetricsApiControllerTest.java: 254 added lines, 0 removed lines. Original line number Diff line number Diff line package org.etsi.osl.services.api.metrics; import com.jayway.jsonpath.JsonPath; import org.etsi.osl.tmf.JsonUtils; import org.etsi.osl.tmf.OpenAPISpringBoot; import org.etsi.osl.tmf.so641.model.*; import org.etsi.osl.tmf.so641.reposervices.ServiceOrderRepoService; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.MediaType; import org.springframework.security.test.context.support.WithMockUser; import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.context.WebApplicationContext; import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @RunWith(SpringRunner.class) @Transactional @SpringBootTest( webEnvironment = SpringBootTest.WebEnvironment.MOCK, classes = OpenAPISpringBoot.class ) //@AutoConfigureTestDatabase //this automatically uses h2 @AutoConfigureMockMvc @ActiveProfiles("testing") //@TestPropertySource( // locations = "classpath:application-testing.yml") public class ServiceOrderMetricsApiControllerTest { @Autowired private MockMvc mvc; @Autowired ServiceOrderRepoService serviceOrderRepoService; @Autowired private WebApplicationContext context; @Before public void setup() throws Exception { mvc = MockMvcBuilders .webAppContextSetup(context) .apply(springSecurity()) .build(); } @WithMockUser(username="osadmin", roles = {"ADMIN","USER"}) @Test public void testCountTotalServiceOrders() throws Exception { createServiceOrder(ServiceOrderStateType.INPROGRESS); String response = mvc.perform(MockMvcRequestBuilders.get("/metrics/totalServiceOrders" ) .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isOk() ) .andReturn().getResponse().getContentAsString(); int totalServiceOrders = JsonPath.read(response, "$.totalServiceOrders"); assertThat(totalServiceOrders).isEqualTo(serviceOrderRepoService.findAll().size()); } @WithMockUser(username="osadmin", roles = {"ADMIN","USER"}) @Test public void testCountTotalServiceOrdersWithState() throws Exception { createServiceOrder(ServiceOrderStateType.INPROGRESS); createServiceOrder(ServiceOrderStateType.ACKNOWLEDGED); String response = mvc.perform(MockMvcRequestBuilders.get("/metrics/totalServiceOrders" ) .param("state", "ACKNOWLEDGED") .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isOk() ) .andReturn().getResponse().getContentAsString(); int totalServiceOrders = JsonPath.read(response, "$.totalServiceOrders"); List<ServiceOrder> serviceOrdersList = serviceOrderRepoService.findAll(); int activeServiceOrders = (int) serviceOrdersList.stream().filter(serviceOrder -> serviceOrder.getState() == ServiceOrderStateType.ACKNOWLEDGED).count(); assertThat(totalServiceOrders).isEqualTo(activeServiceOrders); assertThat(activeServiceOrders).isEqualTo(1); } @WithMockUser(username="osadmin", roles = {"ADMIN","USER"}) @Test public void testGetTotalActiveServiceOrders() throws Exception { createServiceOrder(ServiceOrderStateType.INPROGRESS); createServiceOrder(ServiceOrderStateType.INPROGRESS); createServiceOrder(ServiceOrderStateType.COMPLETED); createServiceOrder(ServiceOrderStateType.COMPLETED); createServiceOrder(ServiceOrderStateType.ACKNOWLEDGED); createServiceOrder(ServiceOrderStateType.REJECTED); String response = mvc.perform(MockMvcRequestBuilders.get("/metrics/activeServiceOrders" ) .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isOk() ) .andReturn().getResponse().getContentAsString(); int totalServiceOrders = JsonPath.read(response, "$.activeServiceOrders"); assertThat(totalServiceOrders).isEqualTo(4); } @WithMockUser(username = "osadmin", roles = {"ADMIN", "USER"}) @Test public void testGetServiceOrdersGroupedByDay() throws Exception { String startTime = OffsetDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT); createServiceOrder(ServiceOrderStateType.INPROGRESS); createServiceOrder(ServiceOrderStateType.INPROGRESS); createServiceOrder(ServiceOrderStateType.INPROGRESS); createServiceOrder(ServiceOrderStateType.ACKNOWLEDGED); createServiceOrder(ServiceOrderStateType.ACKNOWLEDGED); createServiceOrder(ServiceOrderStateType.PARTIAL); String endTime = OffsetDateTime.now(ZoneOffset.UTC).plusDays(4).format(DateTimeFormatter.ISO_INSTANT); String response = mvc.perform(MockMvcRequestBuilders.get("/metrics/serviceOrdersGroupByDay") .param("starttime", startTime) .param("endtime", endTime) .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(); List<Map<String, Object>> groupByDay = JsonPath.read(response, "$.serviceOrders.aggregations.groupByDay"); OffsetDateTime start = OffsetDateTime.parse(startTime); OffsetDateTime end = OffsetDateTime.parse(endTime); DateTimeFormatter formatter = DateTimeFormatter.ISO_INSTANT; Map<String, Integer> dayCounts = groupByDay.stream() .collect(Collectors.toMap( entry -> (String) entry.get("key"), entry -> (Integer) entry.get("count") )); int totalDays = (int) ChronoUnit.DAYS.between(start.toLocalDate(), end.toLocalDate()) + 1; for (int i = 0; i < totalDays; i++) { OffsetDateTime day = start.plusDays(i).toLocalDate().atStartOfDay().atOffset(ZoneOffset.UTC); String dayKey = formatter.format(day.toInstant()); if (i == 0) { // Today: should have all 6 assertThat(dayCounts.get(dayKey)).isEqualTo(6); } else { // Other days: should be 0 assertThat(dayCounts.get(dayKey)).isEqualTo(0); } } } @WithMockUser(username = "osadmin", roles = {"ADMIN", "USER"}) @Test public void testGetServiceOrdersGroupedByState() throws Exception { String startTime = OffsetDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT); createServiceOrder(ServiceOrderStateType.INPROGRESS); createServiceOrder(ServiceOrderStateType.INPROGRESS); createServiceOrder(ServiceOrderStateType.INPROGRESS); createServiceOrder(ServiceOrderStateType.ACKNOWLEDGED); createServiceOrder(ServiceOrderStateType.ACKNOWLEDGED); createServiceOrder(ServiceOrderStateType.PARTIAL); String endTime = OffsetDateTime.now(ZoneOffset.UTC).plusDays(4).format(DateTimeFormatter.ISO_INSTANT); String response = mvc.perform(MockMvcRequestBuilders.get("/metrics/serviceOrdersGroupByState") .param("starttime", startTime) .param("endtime", endTime) .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(); List<Map<String, Object>> groupByState = JsonPath.read(response, "$.serviceOrders.aggregations.groupByState"); // Create a map from key -> count Map<String, Integer> stateCounts = groupByState.stream() .collect(Collectors.toMap( entry -> (String) entry.get("key"), entry -> (Integer) entry.get("count") )); assertThat(stateCounts.get("INPROGRESS")).isEqualTo(3); assertThat(stateCounts.get("ACKNOWLEDGED")).isEqualTo(2); assertThat(stateCounts.get("PARTIAL")).isEqualTo(1); assertThat(stateCounts.get("INITIAL")).isEqualTo(0); assertThat(stateCounts.get("REJECTED")).isEqualTo(0); assertThat(stateCounts.get("PENDING")).isEqualTo(0); assertThat(stateCounts.get("HELD")).isEqualTo(0); assertThat(stateCounts.get("CANCELLED")).isEqualTo(0); assertThat(stateCounts.get("COMPLETED")).isEqualTo(0); assertThat(stateCounts.get("FAILED")).isEqualTo(0); } private void createServiceOrder(ServiceOrderStateType stateType) throws Exception { ServiceOrderCreate serviceOrder = new ServiceOrderCreate(); serviceOrder.setCategory("Test Category"); serviceOrder.setDescription("A Test Service Order"); serviceOrder.setRequestedStartDate(OffsetDateTime.now(ZoneOffset.UTC).toString()); serviceOrder.setRequestedCompletionDate(OffsetDateTime.now(ZoneOffset.UTC).plusDays(3).toString()); String response = mvc .perform(MockMvcRequestBuilders.post("/serviceOrdering/v4/serviceOrder") .with( SecurityMockMvcRequestPostProcessors.csrf()) .contentType(MediaType.APPLICATION_JSON).content(JsonUtils.toJson(serviceOrder))) .andExpect(status().isOk()).andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()).andReturn().getResponse().getContentAsString(); ServiceOrder responseSO = JsonUtils.toJsonObj(response, ServiceOrder.class); // Update Service Order State String soId = responseSO.getId(); ServiceOrderUpdate servOrderUpd = new ServiceOrderUpdate(); servOrderUpd.setState(stateType); String response2 = mvc.perform(MockMvcRequestBuilders.patch("/serviceOrdering/v4/serviceOrder/" + soId) .with( SecurityMockMvcRequestPostProcessors.csrf()) .contentType(MediaType.APPLICATION_JSON) .content( JsonUtils.toJson( servOrderUpd ) )) .andExpect(status().isOk() ) .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)) .andReturn().getResponse().getContentAsString(); ServiceOrder responsesServiceOrder2 = JsonUtils.toJsonObj(response2, ServiceOrder.class); assertThat(responsesServiceOrder2.getState().toString()).isEqualTo(stateType.toString()); } }