Loading src/main/java/org/etsi/osl/tmf/metrics/api/ResourceMetricsApi.java 0 → 100644 +47 −0 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.ri639.model.ResourceStatusType; 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 = "ResourceMetricsApi") public interface ResourceMetricsApi { Logger log = LoggerFactory.getLogger(ResourceMetricsApi.class); @Operation(summary = "Get total number of resources", operationId = "getTotalResources") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Success"), @ApiResponse(responseCode = "400", description = "Bad Request"), @ApiResponse(responseCode = "500", description = "Internal Server Error") }) @RequestMapping(value = "/tmf-api/metrics/totalResources", method = RequestMethod.GET, produces = "application/json;charset=utf-8") ResponseEntity<Map<String, Integer>> getTotalResources( @Valid @RequestParam(value = "state", required = false) ResourceStatusType state ); @Operation(summary = "Get resources grouped by state", operationId = "getResourcesGroupedByState") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Success"), @ApiResponse(responseCode = "400", description = "Bad Request"), @ApiResponse(responseCode = "500", description = "Internal Server Error") }) @RequestMapping(value = "/tmf-api/metrics/resourcesGroupByState", method = RequestMethod.GET, produces = "application/json;charset=utf-8") ResponseEntity<Map<String, Object>> getResourcesGroupedByState( @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/ResourceMetricsApiController.java 0 → 100644 +85 −0 Original line number Diff line number Diff line package org.etsi.osl.tmf.metrics.api; import org.etsi.osl.tmf.metrics.reposervices.ResourceMetricsRepoService; import org.etsi.osl.tmf.ri639.model.ResourceStatusType; 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.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @Controller public class ResourceMetricsApiController implements ResourceMetricsApi{ private static final Logger log = LoggerFactory.getLogger(ResourceMetricsApiController.class); private final ResourceMetricsRepoService resourceMetricsRepoService; @Autowired public ResourceMetricsApiController(ResourceMetricsRepoService resourceMetricsRepoService) { this.resourceMetricsRepoService = resourceMetricsRepoService; } @Override public ResponseEntity<Map<String, Integer>> getTotalResources(ResourceStatusType state) { try { int totalResources = resourceMetricsRepoService.countTotalResources(state); Map<String, Integer> response = new HashMap<>(); response.put("totalResources", totalResources); return new ResponseEntity<>(response, HttpStatus.OK); } catch (Exception e) { log.error("Couldn't retrieve total resources. ", e); return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } } @Override public ResponseEntity<Map<String, Object>> getResourcesGroupedByState(OffsetDateTime starttime, OffsetDateTime endtime) { try { Map<String, Integer> resourcesByState = resourceMetricsRepoService.getResourcesGroupedByState(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 (ResourceStatusType state : ResourceStatusType.values()) { fullStateMap.put(state.name(), 0); // default to 0 } // Overwrite counts with actual data resourcesByState.forEach((key, value) -> { fullStateMap.put(key.toUpperCase(), value); // normalize case just in case }); // Build groupByState list List<Map<String, Object>> groupByStateList = fullStateMap.entrySet().stream() .map(entry -> { Map<String, Object> map = new HashMap<>(); map.put("key", entry.getKey()); map.put("count", entry.getValue()); return map; }) .toList(); // Wrap in response structure Map<String, Object> aggregations = Map.of("groupByState", groupByStateList); Map<String, Object> services = Map.of( "total", fullStateMap.values().stream().mapToInt(Integer::intValue).sum(), "aggregations", aggregations ); Map<String, Object> response = Map.of("resources", services); return new ResponseEntity<>(response, HttpStatus.OK); } catch (Exception e) { log.error("Couldn't retrieve resources grouped by state. ", e); return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } } } src/main/java/org/etsi/osl/tmf/metrics/reposervices/ResourceMetricsRepoService.java 0 → 100644 +46 −0 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.ri639.model.ResourceStatusType; import org.etsi.osl.tmf.ri639.repo.ResourceRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.time.OffsetDateTime; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @Service public class ResourceMetricsRepoService { @Autowired ObjectMapper objectMapper; @Autowired ResourceRepository resourceRepository; public int countTotalResources(ResourceStatusType state) { if (state == null) { return resourceRepository.countAll(); } else { return resourceRepository.countByResourceStatus(state); } } public Map<String, Integer> getResourcesGroupedByState(OffsetDateTime starttime, OffsetDateTime endtime) { if (starttime.plusDays(31).isBefore(endtime)) { starttime = endtime.minusDays(31); } List<Object[]> rawResults = resourceRepository.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/ri639/repo/ResourceRepository.java +16 −0 Original line number Diff line number Diff line Loading @@ -19,9 +19,11 @@ */ package org.etsi.osl.tmf.ri639.repo; import java.time.OffsetDateTime; import java.util.List; import java.util.Optional; import org.etsi.osl.tmf.ri639.model.Resource; import org.etsi.osl.tmf.ri639.model.ResourceStatusType; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; Loading Loading @@ -56,4 +58,18 @@ public interface ResourceRepository extends JpaRepository<Resource, Long> { List<Resource> findByNameAndResourceVersion(String aname, String aversion); List<Resource> findByNameAndCategoryAndResourceVersion(String aname, String acategory, String aversion); // Methods for metrics @Query("SELECT COUNT(res) FROM RIResource res") int countAll(); int countByResourceStatus(ResourceStatusType status); @Query("SELECT res.resourceStatus, COUNT(res) FROM RIResource res " + "WHERE res.startOperatingDate >= :starttime AND res.endOperatingDate <= :endtime " + "GROUP BY res.resourceStatus") List<Object[]> groupByStateBetweenDates(OffsetDateTime starttime, OffsetDateTime endtime); } src/test/java/org/etsi/osl/services/api/metrics/ResourceMetricsApiControllerTest.java 0 → 100644 +240 −0 Original line number Diff line number Diff line package org.etsi.osl.services.api.metrics; import com.jayway.jsonpath.JsonPath; import org.apache.commons.io.IOUtils; import org.etsi.osl.tmf.JsonUtils; import org.etsi.osl.tmf.OpenAPISpringBoot; import org.etsi.osl.tmf.common.model.Any; import org.etsi.osl.tmf.common.model.UserPartRoleType; import org.etsi.osl.tmf.common.model.service.Note; import org.etsi.osl.tmf.common.model.service.ResourceRef; import org.etsi.osl.tmf.prm669.model.RelatedParty; import org.etsi.osl.tmf.rcm634.model.*; import org.etsi.osl.tmf.ri639.model.*; import org.etsi.osl.tmf.ri639.reposervices.ResourceRepoService; 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.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.net.URI; import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; 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 ResourceMetricsApiControllerTest { @Autowired private MockMvc mvc; @Autowired ResourceRepoService resourceRepoService; @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 testCountTotalResources() throws Exception { createResource(ResourceStatusType.AVAILABLE); String response = mvc.perform(MockMvcRequestBuilders.get("/tmf-api/metrics/totalResources" ) .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isOk() ) .andReturn().getResponse().getContentAsString(); int totalResources = JsonPath.read(response, "$.totalResources"); assertThat(totalResources).isEqualTo(resourceRepoService.findAll().size()); } @WithMockUser(username="osadmin", roles = {"ADMIN","USER"}) @Test public void testCountTotalServicesWithState() throws Exception { createResource(ResourceStatusType.AVAILABLE); createResource(ResourceStatusType.STANDBY); String response = mvc.perform(MockMvcRequestBuilders.get("/tmf-api/metrics/totalResources" ) .param("state", "STANDBY") .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isOk() ) .andReturn().getResponse().getContentAsString(); int totalResources = JsonPath.read(response, "$.totalResources"); List<Resource> resourcesList = resourceRepoService.findAll(); int standByResources = (int) resourcesList.stream().filter(resource -> resource.getResourceStatus() == ResourceStatusType.STANDBY).count(); assertThat(totalResources).isEqualTo(standByResources); assertThat(totalResources).isEqualTo(1); } @WithMockUser(username = "osadmin", roles = {"ADMIN", "USER"}) @Test public void testGetServicesGroupedByState() throws Exception { String startTime = OffsetDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT); createResource(ResourceStatusType.AVAILABLE); createResource(ResourceStatusType.AVAILABLE); createResource(ResourceStatusType.AVAILABLE); createResource(ResourceStatusType.RESERVED); createResource(ResourceStatusType.RESERVED); createResource(ResourceStatusType.STANDBY); String endTime = OffsetDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT); String response = mvc.perform(MockMvcRequestBuilders.get("/tmf-api/metrics/resourcesGroupByState") .param("starttime", startTime) .param("endtime", endTime) .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(); List<Map<String, Object>> groupByState = JsonPath.read(response, "$.resources.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("AVAILABLE")).isEqualTo(3); assertThat(stateCounts.get("RESERVED")).isEqualTo(2); assertThat(stateCounts.get("STANDBY")).isEqualTo(1); assertThat(stateCounts.get("ALARM")).isEqualTo(0); assertThat(stateCounts.get("UNKNOWN")).isEqualTo(0); assertThat(stateCounts.get("SUSPENDED")).isEqualTo(0); } private void createResource(ResourceStatusType statusType) throws Exception{ /** * first add 2 specs */ File sspec = new File( "src/test/resources/testResourceSpec.json" ); InputStream in = new FileInputStream( sspec ); String sspectext = IOUtils.toString(in, "UTF-8"); ResourceSpecificationCreate sspeccr1 = JsonUtils.toJsonObj( sspectext, ResourceSpecificationCreate.class); sspeccr1.setName("Spec1"); ResourceSpecification responsesSpec1 = createResourceSpec( sspeccr1); //res 2 is an RFS ResourceSpecificationCreate sspeccr2 = JsonUtils.toJsonObj( sspectext, ResourceSpecificationCreate.class); sspeccr2.setName("Spec2"); sspeccr2.addResourceSpecificationRelationshipWith( responsesSpec1 ); LogicalResourceSpecification responsesSpec2 = (LogicalResourceSpecification) createResourceSpec( sspeccr2 ); /** * add them as bundle */ ResourceSpecificationCreate sspeccr3 = JsonUtils.toJsonObj( sspectext, ResourceSpecificationCreate.class); sspeccr3.setName("BundleExampleSpec"); sspeccr3.isBundle(true); sspeccr3.addResourceSpecificationRelationshipWith( responsesSpec1 ); sspeccr3.addResourceSpecificationRelationshipWith( responsesSpec2 ); ResourceSpecification responsesSpec3 = createResourceSpec( sspeccr3); ResourceCreate aResource = new ResourceCreate(); aResource.setName("aNew Resource parent"); aResource.setCategory("Experimentation"); aResource.setDescription("Experimentation Descr"); aResource.setStartOperatingDate( OffsetDateTime.now(ZoneOffset.UTC ).toString() ); aResource.setEndOperatingDate( OffsetDateTime.now(ZoneOffset.UTC ).toString() ); aResource.setResourceStatus(statusType); Note noteItem = new Note(); noteItem.text("test note"); aResource.addNoteItem(noteItem); Characteristic resCharacteristicItem = new Characteristic(); resCharacteristicItem.setName( "externalPartnerServiceId" ); resCharacteristicItem.setValue( new Any("NONE")); aResource.addResourceCharacteristicItem(resCharacteristicItem); ResourceSpecificationRef aServiceSpecificationRef = new ResourceSpecificationRef(); aServiceSpecificationRef.setId(responsesSpec3.getId() ); aServiceSpecificationRef.setName(responsesSpec3.getName()); aResource.setResourceSpecification( aServiceSpecificationRef ); resourceRepoService.addResource(aResource); } private ResourceSpecification createResourceSpec(ResourceSpecificationUpdate sspeccr1) throws Exception{ URI url = new URI("/resourceCatalogManagement/v4/resourceSpecification"); if (sspeccr1 instanceof PhysicalResourceSpecificationUpdate ) { url = new URI("/resourceCatalogManagement/v4/resourceSpecification"); } String responseSpec = mvc.perform(MockMvcRequestBuilders.post( url ) .with( SecurityMockMvcRequestPostProcessors.csrf()) .contentType(MediaType.APPLICATION_JSON) .content( JsonUtils.toJson( sspeccr1 ) )) .andExpect(status().isOk()) .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(); ResourceSpecification responsesSpec1; if (sspeccr1 instanceof PhysicalResourceSpecificationUpdate ) { responsesSpec1 = JsonUtils.toJsonObj(responseSpec, PhysicalResourceSpecification.class); }else { responsesSpec1 = JsonUtils.toJsonObj(responseSpec, LogicalResourceSpecification.class); } return responsesSpec1; } } Loading
src/main/java/org/etsi/osl/tmf/metrics/api/ResourceMetricsApi.java 0 → 100644 +47 −0 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.ri639.model.ResourceStatusType; 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 = "ResourceMetricsApi") public interface ResourceMetricsApi { Logger log = LoggerFactory.getLogger(ResourceMetricsApi.class); @Operation(summary = "Get total number of resources", operationId = "getTotalResources") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Success"), @ApiResponse(responseCode = "400", description = "Bad Request"), @ApiResponse(responseCode = "500", description = "Internal Server Error") }) @RequestMapping(value = "/tmf-api/metrics/totalResources", method = RequestMethod.GET, produces = "application/json;charset=utf-8") ResponseEntity<Map<String, Integer>> getTotalResources( @Valid @RequestParam(value = "state", required = false) ResourceStatusType state ); @Operation(summary = "Get resources grouped by state", operationId = "getResourcesGroupedByState") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Success"), @ApiResponse(responseCode = "400", description = "Bad Request"), @ApiResponse(responseCode = "500", description = "Internal Server Error") }) @RequestMapping(value = "/tmf-api/metrics/resourcesGroupByState", method = RequestMethod.GET, produces = "application/json;charset=utf-8") ResponseEntity<Map<String, Object>> getResourcesGroupedByState( @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/ResourceMetricsApiController.java 0 → 100644 +85 −0 Original line number Diff line number Diff line package org.etsi.osl.tmf.metrics.api; import org.etsi.osl.tmf.metrics.reposervices.ResourceMetricsRepoService; import org.etsi.osl.tmf.ri639.model.ResourceStatusType; 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.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @Controller public class ResourceMetricsApiController implements ResourceMetricsApi{ private static final Logger log = LoggerFactory.getLogger(ResourceMetricsApiController.class); private final ResourceMetricsRepoService resourceMetricsRepoService; @Autowired public ResourceMetricsApiController(ResourceMetricsRepoService resourceMetricsRepoService) { this.resourceMetricsRepoService = resourceMetricsRepoService; } @Override public ResponseEntity<Map<String, Integer>> getTotalResources(ResourceStatusType state) { try { int totalResources = resourceMetricsRepoService.countTotalResources(state); Map<String, Integer> response = new HashMap<>(); response.put("totalResources", totalResources); return new ResponseEntity<>(response, HttpStatus.OK); } catch (Exception e) { log.error("Couldn't retrieve total resources. ", e); return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } } @Override public ResponseEntity<Map<String, Object>> getResourcesGroupedByState(OffsetDateTime starttime, OffsetDateTime endtime) { try { Map<String, Integer> resourcesByState = resourceMetricsRepoService.getResourcesGroupedByState(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 (ResourceStatusType state : ResourceStatusType.values()) { fullStateMap.put(state.name(), 0); // default to 0 } // Overwrite counts with actual data resourcesByState.forEach((key, value) -> { fullStateMap.put(key.toUpperCase(), value); // normalize case just in case }); // Build groupByState list List<Map<String, Object>> groupByStateList = fullStateMap.entrySet().stream() .map(entry -> { Map<String, Object> map = new HashMap<>(); map.put("key", entry.getKey()); map.put("count", entry.getValue()); return map; }) .toList(); // Wrap in response structure Map<String, Object> aggregations = Map.of("groupByState", groupByStateList); Map<String, Object> services = Map.of( "total", fullStateMap.values().stream().mapToInt(Integer::intValue).sum(), "aggregations", aggregations ); Map<String, Object> response = Map.of("resources", services); return new ResponseEntity<>(response, HttpStatus.OK); } catch (Exception e) { log.error("Couldn't retrieve resources grouped by state. ", e); return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } } }
src/main/java/org/etsi/osl/tmf/metrics/reposervices/ResourceMetricsRepoService.java 0 → 100644 +46 −0 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.ri639.model.ResourceStatusType; import org.etsi.osl.tmf.ri639.repo.ResourceRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.time.OffsetDateTime; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @Service public class ResourceMetricsRepoService { @Autowired ObjectMapper objectMapper; @Autowired ResourceRepository resourceRepository; public int countTotalResources(ResourceStatusType state) { if (state == null) { return resourceRepository.countAll(); } else { return resourceRepository.countByResourceStatus(state); } } public Map<String, Integer> getResourcesGroupedByState(OffsetDateTime starttime, OffsetDateTime endtime) { if (starttime.plusDays(31).isBefore(endtime)) { starttime = endtime.minusDays(31); } List<Object[]> rawResults = resourceRepository.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/ri639/repo/ResourceRepository.java +16 −0 Original line number Diff line number Diff line Loading @@ -19,9 +19,11 @@ */ package org.etsi.osl.tmf.ri639.repo; import java.time.OffsetDateTime; import java.util.List; import java.util.Optional; import org.etsi.osl.tmf.ri639.model.Resource; import org.etsi.osl.tmf.ri639.model.ResourceStatusType; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; Loading Loading @@ -56,4 +58,18 @@ public interface ResourceRepository extends JpaRepository<Resource, Long> { List<Resource> findByNameAndResourceVersion(String aname, String aversion); List<Resource> findByNameAndCategoryAndResourceVersion(String aname, String acategory, String aversion); // Methods for metrics @Query("SELECT COUNT(res) FROM RIResource res") int countAll(); int countByResourceStatus(ResourceStatusType status); @Query("SELECT res.resourceStatus, COUNT(res) FROM RIResource res " + "WHERE res.startOperatingDate >= :starttime AND res.endOperatingDate <= :endtime " + "GROUP BY res.resourceStatus") List<Object[]> groupByStateBetweenDates(OffsetDateTime starttime, OffsetDateTime endtime); }
src/test/java/org/etsi/osl/services/api/metrics/ResourceMetricsApiControllerTest.java 0 → 100644 +240 −0 Original line number Diff line number Diff line package org.etsi.osl.services.api.metrics; import com.jayway.jsonpath.JsonPath; import org.apache.commons.io.IOUtils; import org.etsi.osl.tmf.JsonUtils; import org.etsi.osl.tmf.OpenAPISpringBoot; import org.etsi.osl.tmf.common.model.Any; import org.etsi.osl.tmf.common.model.UserPartRoleType; import org.etsi.osl.tmf.common.model.service.Note; import org.etsi.osl.tmf.common.model.service.ResourceRef; import org.etsi.osl.tmf.prm669.model.RelatedParty; import org.etsi.osl.tmf.rcm634.model.*; import org.etsi.osl.tmf.ri639.model.*; import org.etsi.osl.tmf.ri639.reposervices.ResourceRepoService; 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.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.net.URI; import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; 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 ResourceMetricsApiControllerTest { @Autowired private MockMvc mvc; @Autowired ResourceRepoService resourceRepoService; @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 testCountTotalResources() throws Exception { createResource(ResourceStatusType.AVAILABLE); String response = mvc.perform(MockMvcRequestBuilders.get("/tmf-api/metrics/totalResources" ) .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isOk() ) .andReturn().getResponse().getContentAsString(); int totalResources = JsonPath.read(response, "$.totalResources"); assertThat(totalResources).isEqualTo(resourceRepoService.findAll().size()); } @WithMockUser(username="osadmin", roles = {"ADMIN","USER"}) @Test public void testCountTotalServicesWithState() throws Exception { createResource(ResourceStatusType.AVAILABLE); createResource(ResourceStatusType.STANDBY); String response = mvc.perform(MockMvcRequestBuilders.get("/tmf-api/metrics/totalResources" ) .param("state", "STANDBY") .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isOk() ) .andReturn().getResponse().getContentAsString(); int totalResources = JsonPath.read(response, "$.totalResources"); List<Resource> resourcesList = resourceRepoService.findAll(); int standByResources = (int) resourcesList.stream().filter(resource -> resource.getResourceStatus() == ResourceStatusType.STANDBY).count(); assertThat(totalResources).isEqualTo(standByResources); assertThat(totalResources).isEqualTo(1); } @WithMockUser(username = "osadmin", roles = {"ADMIN", "USER"}) @Test public void testGetServicesGroupedByState() throws Exception { String startTime = OffsetDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT); createResource(ResourceStatusType.AVAILABLE); createResource(ResourceStatusType.AVAILABLE); createResource(ResourceStatusType.AVAILABLE); createResource(ResourceStatusType.RESERVED); createResource(ResourceStatusType.RESERVED); createResource(ResourceStatusType.STANDBY); String endTime = OffsetDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT); String response = mvc.perform(MockMvcRequestBuilders.get("/tmf-api/metrics/resourcesGroupByState") .param("starttime", startTime) .param("endtime", endTime) .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(); List<Map<String, Object>> groupByState = JsonPath.read(response, "$.resources.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("AVAILABLE")).isEqualTo(3); assertThat(stateCounts.get("RESERVED")).isEqualTo(2); assertThat(stateCounts.get("STANDBY")).isEqualTo(1); assertThat(stateCounts.get("ALARM")).isEqualTo(0); assertThat(stateCounts.get("UNKNOWN")).isEqualTo(0); assertThat(stateCounts.get("SUSPENDED")).isEqualTo(0); } private void createResource(ResourceStatusType statusType) throws Exception{ /** * first add 2 specs */ File sspec = new File( "src/test/resources/testResourceSpec.json" ); InputStream in = new FileInputStream( sspec ); String sspectext = IOUtils.toString(in, "UTF-8"); ResourceSpecificationCreate sspeccr1 = JsonUtils.toJsonObj( sspectext, ResourceSpecificationCreate.class); sspeccr1.setName("Spec1"); ResourceSpecification responsesSpec1 = createResourceSpec( sspeccr1); //res 2 is an RFS ResourceSpecificationCreate sspeccr2 = JsonUtils.toJsonObj( sspectext, ResourceSpecificationCreate.class); sspeccr2.setName("Spec2"); sspeccr2.addResourceSpecificationRelationshipWith( responsesSpec1 ); LogicalResourceSpecification responsesSpec2 = (LogicalResourceSpecification) createResourceSpec( sspeccr2 ); /** * add them as bundle */ ResourceSpecificationCreate sspeccr3 = JsonUtils.toJsonObj( sspectext, ResourceSpecificationCreate.class); sspeccr3.setName("BundleExampleSpec"); sspeccr3.isBundle(true); sspeccr3.addResourceSpecificationRelationshipWith( responsesSpec1 ); sspeccr3.addResourceSpecificationRelationshipWith( responsesSpec2 ); ResourceSpecification responsesSpec3 = createResourceSpec( sspeccr3); ResourceCreate aResource = new ResourceCreate(); aResource.setName("aNew Resource parent"); aResource.setCategory("Experimentation"); aResource.setDescription("Experimentation Descr"); aResource.setStartOperatingDate( OffsetDateTime.now(ZoneOffset.UTC ).toString() ); aResource.setEndOperatingDate( OffsetDateTime.now(ZoneOffset.UTC ).toString() ); aResource.setResourceStatus(statusType); Note noteItem = new Note(); noteItem.text("test note"); aResource.addNoteItem(noteItem); Characteristic resCharacteristicItem = new Characteristic(); resCharacteristicItem.setName( "externalPartnerServiceId" ); resCharacteristicItem.setValue( new Any("NONE")); aResource.addResourceCharacteristicItem(resCharacteristicItem); ResourceSpecificationRef aServiceSpecificationRef = new ResourceSpecificationRef(); aServiceSpecificationRef.setId(responsesSpec3.getId() ); aServiceSpecificationRef.setName(responsesSpec3.getName()); aResource.setResourceSpecification( aServiceSpecificationRef ); resourceRepoService.addResource(aResource); } private ResourceSpecification createResourceSpec(ResourceSpecificationUpdate sspeccr1) throws Exception{ URI url = new URI("/resourceCatalogManagement/v4/resourceSpecification"); if (sspeccr1 instanceof PhysicalResourceSpecificationUpdate ) { url = new URI("/resourceCatalogManagement/v4/resourceSpecification"); } String responseSpec = mvc.perform(MockMvcRequestBuilders.post( url ) .with( SecurityMockMvcRequestPostProcessors.csrf()) .contentType(MediaType.APPLICATION_JSON) .content( JsonUtils.toJson( sspeccr1 ) )) .andExpect(status().isOk()) .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(); ResourceSpecification responsesSpec1; if (sspeccr1 instanceof PhysicalResourceSpecificationUpdate ) { responsesSpec1 = JsonUtils.toJsonObj(responseSpec, PhysicalResourceSpecification.class); }else { responsesSpec1 = JsonUtils.toJsonObj(responseSpec, LogicalResourceSpecification.class); } return responsesSpec1; } }