diff --git a/backend/src/main/java/ca/bc/gov/restapi/results/common/endpoint/FeatureServiceEndpoint.java b/backend/src/main/java/ca/bc/gov/restapi/results/common/endpoint/FeatureServiceEndpoint.java index a5ae4079..4df5c647 100644 --- a/backend/src/main/java/ca/bc/gov/restapi/results/common/endpoint/FeatureServiceEndpoint.java +++ b/backend/src/main/java/ca/bc/gov/restapi/results/common/endpoint/FeatureServiceEndpoint.java @@ -1,7 +1,7 @@ package ca.bc.gov.restapi.results.common.endpoint; import ca.bc.gov.restapi.results.common.service.OpenMapsService; -import lombok.AllArgsConstructor; +import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; @@ -12,7 +12,7 @@ */ @RestController @RequestMapping("/api/feature-service") -@AllArgsConstructor +@RequiredArgsConstructor public class FeatureServiceEndpoint { private final OpenMapsService openMapsService; diff --git a/backend/src/main/java/ca/bc/gov/restapi/results/common/pagination/PaginatedResult.java b/backend/src/main/java/ca/bc/gov/restapi/results/common/pagination/PaginatedResult.java index 83a156e4..477131f8 100644 --- a/backend/src/main/java/ca/bc/gov/restapi/results/common/pagination/PaginatedResult.java +++ b/backend/src/main/java/ca/bc/gov/restapi/results/common/pagination/PaginatedResult.java @@ -1,12 +1,20 @@ package ca.bc.gov.restapi.results.common.pagination; import java.util.List; -import lombok.Getter; -import lombok.Setter; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.With; -/** Holds an API response with pagination information and data. */ -@Getter -@Setter +/** + * Holds an API response with pagination information and data. + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@With +@Builder public class PaginatedResult { private int pageIndex; diff --git a/backend/src/main/java/ca/bc/gov/restapi/results/common/pagination/PaginationParameters.java b/backend/src/main/java/ca/bc/gov/restapi/results/common/pagination/PaginationParameters.java index c8711001..7f21445d 100644 --- a/backend/src/main/java/ca/bc/gov/restapi/results/common/pagination/PaginationParameters.java +++ b/backend/src/main/java/ca/bc/gov/restapi/results/common/pagination/PaginationParameters.java @@ -2,6 +2,8 @@ import jakarta.validation.constraints.Positive; import jakarta.validation.constraints.PositiveOrZero; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; /** * Pagination parameters to be used in the processing of HTTP GET requests. @@ -9,7 +11,12 @@ * @param page The page to be returned. Zero-based, and must be non-negative; defaults to 0 * @param perPage The maximum number of results in each page. Defaults to 20 */ -public record PaginationParameters(@PositiveOrZero Integer page, @Positive Integer perPage) { +public record PaginationParameters( + @PositiveOrZero(message = "Page number needs to be zero or a positive value") + Integer page, + @Positive(message = "Page size needs to be a positive value") + Integer perPage +) { /** * Build an instance of {@link PaginationParameters}, using the default values for {@code page} @@ -23,4 +30,8 @@ public record PaginationParameters(@PositiveOrZero Integer page, @Positive Integ perPage = 5; } } + + public Pageable toPageable(int maxPageSize) { + return PageRequest.of(page, maxPageSize); + } } diff --git a/backend/src/main/java/ca/bc/gov/restapi/results/common/provider/ForestClientApiProvider.java b/backend/src/main/java/ca/bc/gov/restapi/results/common/provider/ForestClientApiProvider.java index 4a82b6eb..4b2bfa9d 100644 --- a/backend/src/main/java/ca/bc/gov/restapi/results/common/provider/ForestClientApiProvider.java +++ b/backend/src/main/java/ca/bc/gov/restapi/results/common/provider/ForestClientApiProvider.java @@ -31,7 +31,7 @@ public class ForestClientApiProvider { */ public Optional fetchClientByNumber(String number) { - log.info("Starting {} request to /clients/findByClientNumber/{number}", PROVIDER); + log.info("Starting {} request to /clients/findByClientNumber/{}", PROVIDER,number); try { diff --git a/backend/src/test/java/ca/bc/gov/restapi/results/common/endpoint/FeatureServiceEndpointIntegrationTest.java b/backend/src/test/java/ca/bc/gov/restapi/results/common/endpoint/FeatureServiceEndpointIntegrationTest.java new file mode 100644 index 00000000..42bf387b --- /dev/null +++ b/backend/src/test/java/ca/bc/gov/restapi/results/common/endpoint/FeatureServiceEndpointIntegrationTest.java @@ -0,0 +1,149 @@ +package ca.bc.gov.restapi.results.common.endpoint; + +import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; +import static com.github.tomakehurst.wiremock.client.WireMock.okJson; +import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; +import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import ca.bc.gov.restapi.results.extensions.AbstractTestContainerIntegrationTest; +import ca.bc.gov.restapi.results.extensions.WiremockLogNotifier; +import com.github.tomakehurst.wiremock.client.WireMock; +import com.github.tomakehurst.wiremock.junit5.WireMockExtension; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.client.AutoConfigureMockRestServiceServer; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.http.MediaType; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.web.servlet.MockMvc; + +@WithMockUser(roles = "user_read") +@AutoConfigureMockMvc +@DisplayName("Integrated Test | Feature Service Endpoint") +class FeatureServiceEndpointIntegrationTest extends AbstractTestContainerIntegrationTest { + + @Autowired + private MockMvc mockMvc; + + @RegisterExtension + static WireMockExtension clientApiStub = WireMockExtension + .newInstance() + .options( + wireMockConfig() + .port(10001) + .notifier(new WiremockLogNotifier()) + .asynchronousResponseEnabled(true) + .stubRequestLoggingDisabled(false) + ) + .configureStaticDsl(true) + .build(); + + @Test + + @DisplayName("Get opening polygon and properties happy path should succeed") + void getOpeningPolygonAndProperties_happyPath_shouldSucceed() throws Exception { + String openingId = "58993"; + + clientApiStub.stubFor( + WireMock.get(urlPathEqualTo("/")) + .withQueryParam("service", equalTo("WFS")) + .withQueryParam("version", equalTo("2.0.0")) + .withQueryParam("request", equalTo("GetFeature")) + .withQueryParam("typeName", equalTo("WHSE_FOREST_VEGETATION.RSLT_OPENING_SVW")) + .withQueryParam("outputFormat", equalTo("application/json")) + .withQueryParam("SrsName", equalTo("EPSG:4326")) + .withQueryParam("PROPERTYNAME", + equalTo("OPENING_ID," + + "GEOMETRY," + + "REGION_NAME," + + "REGION_CODE," + + "DISTRICT_NAME," + + "DISTRICT_CODE," + + "CLIENT_NAME," + + "CLIENT_NUMBER," + + "OPENING_WHEN_CREATED" + )) + .withQueryParam("CQL_FILTER", equalTo("OPENING_ID=" + openingId)) + .willReturn(okJson(""" + { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "id": "WHSE_FOREST_VEGETATION.RSLT_OPENING_SVW.fid-6f119ee7_19129391292_7c7b", + "geometry_name": "GEOMETRY", + "properties": { + "OPENING_ID": 58993, + "OPENING_CATEGORY_CODE": "FTML", + "OPENING_STATUS_CODE": "FG", + "REGION_CODE": "ROM", + "REGION_NAME": "Omineca Natural Resource Region", + "DISTRICT_CODE": "DMK", + "DISTRICT_NAME": "Mackenzie Natural Resource District", + "CLIENT_NAME": "CONIFEX MACKENZIE FOREST PRODUCTS INC.", + "CLIENT_NUMBER": "00161229", + "OPENING_WHO_CREATED": "MLSIS", + "OPENING_WHEN_CREATED": "1999-08-26Z", + "OPENING_WHO_UPDATED": "IDIR\\\\\\\\SCAKERLE", + "OPENING_WHEN_UPDATED": "2023-11-14Z", + "OBJECTID": 3869732, + "bbox": [ + -125.6056, + 56.06894, + -125.59267, + 56.07429 + ] + } + } + ] + } + """)) + ); + + mockMvc + .perform( + get("/api/feature-service/polygon-and-props/{openingId}", openingId) + .header("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(content().contentType("application/json")) + .andExpect(jsonPath("$.type").value("FeatureCollection")) + .andExpect(jsonPath("$.features[0].type").value("Feature")) + .andExpect( + jsonPath("$.features[0].id") + .value("WHSE_FOREST_VEGETATION.RSLT_OPENING_SVW.fid-6f119ee7_19129391292_7c7b")) + .andExpect(jsonPath("$.features[0].geometry_name").value("GEOMETRY")) + .andExpect(jsonPath("$.features[0].properties.OPENING_ID").value(openingId)) + .andExpect(jsonPath("$.features[0].properties.OPENING_CATEGORY_CODE").value("FTML")) + .andExpect(jsonPath("$.features[0].properties.OPENING_STATUS_CODE").value("FG")) + .andExpect(jsonPath("$.features[0].properties.REGION_CODE").value("ROM")) + .andExpect( + jsonPath("$.features[0].properties.REGION_NAME") + .value("Omineca Natural Resource Region")) + .andExpect(jsonPath("$.features[0].properties.DISTRICT_CODE").value("DMK")) + .andExpect( + jsonPath("$.features[0].properties.DISTRICT_NAME") + .value("Mackenzie Natural Resource District")) + .andExpect( + jsonPath("$.features[0].properties.CLIENT_NAME") + .value("CONIFEX MACKENZIE FOREST PRODUCTS INC.")) + .andExpect(jsonPath("$.features[0].properties.CLIENT_NUMBER").value("00161229")) + .andExpect(jsonPath("$.features[0].properties.OPENING_WHO_CREATED").value("MLSIS")) + .andExpect(jsonPath("$.features[0].properties.OPENING_WHEN_CREATED").value("1999-08-26Z")) + .andExpect( + jsonPath("$.features[0].properties.OPENING_WHO_UPDATED").value("IDIR\\\\SCAKERLE")) + .andExpect(jsonPath("$.features[0].properties.OPENING_WHEN_UPDATED").value("2023-11-14Z")) + .andExpect(jsonPath("$.features[0].properties.OBJECTID").value("3869732")) + .andExpect(jsonPath("$.features[0].properties.bbox[0]").value("-125.6056")) + .andExpect(jsonPath("$.features[0].properties.bbox[1]").value("56.06894")) + .andExpect(jsonPath("$.features[0].properties.bbox[2]").value("-125.59267")) + .andExpect(jsonPath("$.features[0].properties.bbox[3]").value("56.07429")) + .andReturn(); + } +} diff --git a/backend/src/test/java/ca/bc/gov/restapi/results/common/endpoint/FeatureServiceEndpointTest.java b/backend/src/test/java/ca/bc/gov/restapi/results/common/endpoint/FeatureServiceEndpointTest.java deleted file mode 100644 index cce26e10..00000000 --- a/backend/src/test/java/ca/bc/gov/restapi/results/common/endpoint/FeatureServiceEndpointTest.java +++ /dev/null @@ -1,114 +0,0 @@ -package ca.bc.gov.restapi.results.common.endpoint; - -import static org.mockito.Mockito.when; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -import ca.bc.gov.restapi.results.common.service.OpenMapsService; -import java.util.Optional; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.security.test.context.support.WithMockUser; -import org.springframework.test.web.servlet.MockMvc; - -@WebMvcTest(FeatureServiceEndpoint.class) -@WithMockUser(roles = "user_read") -class FeatureServiceEndpointTest { - - @Autowired private MockMvc mockMvc; - - @MockBean - OpenMapsService openMapsService; - - @Test - @DisplayName("Get opening polygon and properties happy path should succeed") - void getOpeningPolygonAndProperties_happyPath_shouldSucceed() throws Exception { - String openingId = "58993"; - - String response = - """ - { - "type": "FeatureCollection", - "features": [ - { - "type": "Feature", - "id": "WHSE_FOREST_VEGETATION.RSLT_OPENING_SVW.fid-6f119ee7_19129391292_7c7b", - "geometry_name": "GEOMETRY", - "properties": { - "OPENING_ID": 58993, - "OPENING_CATEGORY_CODE": "FTML", - "OPENING_STATUS_CODE": "FG", - "REGION_CODE": "ROM", - "REGION_NAME": "Omineca Natural Resource Region", - "DISTRICT_CODE": "DMK", - "DISTRICT_NAME": "Mackenzie Natural Resource District", - "CLIENT_NAME": "CONIFEX MACKENZIE FOREST PRODUCTS INC.", - "CLIENT_NUMBER": "00161229", - "OPENING_WHO_CREATED": "MLSIS", - "OPENING_WHEN_CREATED": "1999-08-26Z", - "OPENING_WHO_UPDATED": "IDIR\\\\\\\\SCAKERLE", - "OPENING_WHEN_UPDATED": "2023-11-14Z", - "OBJECTID": 3869732, - "bbox": [ - -125.6056, - 56.06894, - -125.59267, - 56.07429 - ] - } - } - ] - } - """; - - when(openMapsService.getOpeningPolygonAndProperties(openingId)) - .thenReturn(ResponseEntity.of(Optional.of(response))); - - mockMvc - .perform( - get("/api/feature-service/polygon-and-props/{openingId}", openingId) - .header("Content-Type", MediaType.APPLICATION_JSON_VALUE) - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().isOk()) - .andExpect(content().contentType("application/json")) - .andExpect(jsonPath("$.type").value("FeatureCollection")) - .andExpect(jsonPath("$.features[0].type").value("Feature")) - .andExpect( - jsonPath("$.features[0].id") - .value("WHSE_FOREST_VEGETATION.RSLT_OPENING_SVW.fid-6f119ee7_19129391292_7c7b")) - .andExpect(jsonPath("$.features[0].geometry_name").value("GEOMETRY")) - .andExpect(jsonPath("$.features[0].properties.OPENING_ID").value(openingId)) - .andExpect(jsonPath("$.features[0].properties.OPENING_CATEGORY_CODE").value("FTML")) - .andExpect(jsonPath("$.features[0].properties.OPENING_STATUS_CODE").value("FG")) - .andExpect(jsonPath("$.features[0].properties.REGION_CODE").value("ROM")) - .andExpect( - jsonPath("$.features[0].properties.REGION_NAME") - .value("Omineca Natural Resource Region")) - .andExpect(jsonPath("$.features[0].properties.DISTRICT_CODE").value("DMK")) - .andExpect( - jsonPath("$.features[0].properties.DISTRICT_NAME") - .value("Mackenzie Natural Resource District")) - .andExpect( - jsonPath("$.features[0].properties.CLIENT_NAME") - .value("CONIFEX MACKENZIE FOREST PRODUCTS INC.")) - .andExpect(jsonPath("$.features[0].properties.CLIENT_NUMBER").value("00161229")) - .andExpect(jsonPath("$.features[0].properties.OPENING_WHO_CREATED").value("MLSIS")) - .andExpect(jsonPath("$.features[0].properties.OPENING_WHEN_CREATED").value("1999-08-26Z")) - .andExpect( - jsonPath("$.features[0].properties.OPENING_WHO_UPDATED").value("IDIR\\\\SCAKERLE")) - .andExpect(jsonPath("$.features[0].properties.OPENING_WHEN_UPDATED").value("2023-11-14Z")) - .andExpect(jsonPath("$.features[0].properties.OBJECTID").value("3869732")) - .andExpect(jsonPath("$.features[0].properties.bbox[0]").value("-125.6056")) - .andExpect(jsonPath("$.features[0].properties.bbox[1]").value("56.06894")) - .andExpect(jsonPath("$.features[0].properties.bbox[2]").value("-125.59267")) - .andExpect(jsonPath("$.features[0].properties.bbox[3]").value("56.07429")) - .andReturn(); - } -} diff --git a/backend/src/test/java/ca/bc/gov/restapi/results/common/endpoint/ForestClientEndpointIntegrationTest.java b/backend/src/test/java/ca/bc/gov/restapi/results/common/endpoint/ForestClientEndpointIntegrationTest.java new file mode 100644 index 00000000..e0dc428b --- /dev/null +++ b/backend/src/test/java/ca/bc/gov/restapi/results/common/endpoint/ForestClientEndpointIntegrationTest.java @@ -0,0 +1,108 @@ +package ca.bc.gov.restapi.results.common.endpoint; + +import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; +import static com.github.tomakehurst.wiremock.client.WireMock.okJson; +import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; +import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import ca.bc.gov.restapi.results.common.dto.ForestClientDto; +import ca.bc.gov.restapi.results.common.enums.ForestClientStatusEnum; +import ca.bc.gov.restapi.results.common.enums.ForestClientTypeEnum; +import ca.bc.gov.restapi.results.common.service.ForestClientService; +import ca.bc.gov.restapi.results.extensions.AbstractTestContainerIntegrationTest; +import ca.bc.gov.restapi.results.extensions.WiremockLogNotifier; +import com.github.tomakehurst.wiremock.client.WireMock; +import com.github.tomakehurst.wiremock.junit5.WireMockExtension; +import java.util.Optional; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.web.servlet.MockMvc; + +@WithMockUser(roles = "user_read") +@AutoConfigureMockMvc +@DisplayName("Integrated Test | Forest Client Endpoint") +class ForestClientEndpointIntegrationTest extends AbstractTestContainerIntegrationTest { + + @Autowired private MockMvc mockMvc; + + @RegisterExtension + static WireMockExtension clientApiStub = WireMockExtension + .newInstance() + .options( + wireMockConfig() + .port(10000) + .notifier(new WiremockLogNotifier()) + .asynchronousResponseEnabled(true) + .stubRequestLoggingDisabled(false) + ) + .configureStaticDsl(true) + .build(); + + @Test + @DisplayName("Get forest client happy path should succeed") + void getForestClient_happyPath_shouldSucceed() throws Exception { + String clientNumber = "149081"; + + clientApiStub.stubFor( + WireMock.get(urlPathEqualTo("/clients/findByClientNumber/00149081")) + .willReturn(okJson(""" + { + "clientNumber": 149081, + "clientName": "WESTERN FOREST PRODUCTS INC.", + "legalFirstName": null, + "legalMiddleName": null, + "clientStatusCode": "ACT", + "clientTypeCode": "C", + "acronym": "WFP" + }""") + ) + ); + + mockMvc + .perform( + get("/api/forest-clients/{clientNumber}", clientNumber) + .header("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(content().contentType("application/json")) + .andExpect(jsonPath("$.clientNumber").value(clientNumber)) + .andExpect(jsonPath("$.clientName").value("WESTERN FOREST PRODUCTS INC.")) + .andExpect(jsonPath("$.legalFirstName").isEmpty()) + .andExpect(jsonPath("$.legalMiddleName").isEmpty()) + .andExpect(jsonPath("$.clientStatusCode.code").value("ACT")) + .andExpect(jsonPath("$.clientTypeCode.code").value("C")) + .andExpect(jsonPath("$.acronym").value("WFP")) + .andReturn(); + } + + @Test + @DisplayName("Get forest client not found should succeed") + void getForestClient_notFound_shouldSucceed() throws Exception { + String clientNumber = "111"; + + clientApiStub.stubFor( + WireMock.get(urlPathEqualTo("/clients/findByClientNumber/"+clientNumber)) + .willReturn(WireMock.notFound().withBody("Client not found")) + ); + + mockMvc + .perform( + get("/api/forest-clients/{clientNumber}", clientNumber) + .header("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isNotFound()) + .andReturn(); + } +} diff --git a/backend/src/test/java/ca/bc/gov/restapi/results/common/endpoint/ForestClientEndpointTest.java b/backend/src/test/java/ca/bc/gov/restapi/results/common/endpoint/ForestClientEndpointTest.java deleted file mode 100644 index 3b677f00..00000000 --- a/backend/src/test/java/ca/bc/gov/restapi/results/common/endpoint/ForestClientEndpointTest.java +++ /dev/null @@ -1,84 +0,0 @@ -package ca.bc.gov.restapi.results.common.endpoint; - -import static org.mockito.Mockito.when; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -import ca.bc.gov.restapi.results.common.dto.ForestClientDto; -import ca.bc.gov.restapi.results.common.enums.ForestClientStatusEnum; -import ca.bc.gov.restapi.results.common.enums.ForestClientTypeEnum; -import ca.bc.gov.restapi.results.common.service.ForestClientService; -import java.util.Optional; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.http.MediaType; -import org.springframework.security.test.context.support.WithMockUser; -import org.springframework.test.web.servlet.MockMvc; - -@WebMvcTest(ForestClientEndpoint.class) -@WithMockUser(roles = "user_read") -class ForestClientEndpointTest { - - @Autowired private MockMvc mockMvc; - - @MockBean private ForestClientService forestClientService; - - @Test - @DisplayName("Get forest client happy path should succeed") - void getForestClient_happyPath_shouldSucceed() throws Exception { - String clientNumber = "149081"; - - ForestClientDto clientDto = - new ForestClientDto( - clientNumber, - "WESTERN FOREST PRODUCTS INC.", - null, - null, - ForestClientStatusEnum.ACTIVE, - ForestClientTypeEnum.CORPORATION, - "WFP"); - - when(forestClientService.getClientByNumber(clientNumber)).thenReturn(Optional.of(clientDto)); - - ForestClientStatusEnum active = - ForestClientStatusEnum.of(clientDto.clientStatusCode().getCode()); - ForestClientTypeEnum type = ForestClientTypeEnum.of(clientDto.clientTypeCode().getCode()); - - mockMvc - .perform( - get("/api/forest-clients/{clientNumber}", clientNumber) - .header("Content-Type", MediaType.APPLICATION_JSON_VALUE) - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().isOk()) - .andExpect(content().contentType("application/json")) - .andExpect(jsonPath("$.clientNumber").value(clientNumber)) - .andExpect(jsonPath("$.clientName").value(clientDto.clientName())) - .andExpect(jsonPath("$.legalFirstName").value(clientDto.legalFirstName())) - .andExpect(jsonPath("$.legalMiddleName").value(clientDto.legalMiddleName())) - .andExpect(jsonPath("$.clientStatusCode.code").value(active.getCode())) - .andExpect(jsonPath("$.clientTypeCode.code").value(type.getCode().toString())) - .andExpect(jsonPath("$.acronym").value(clientDto.acronym())) - .andReturn(); - } - - @Test - @DisplayName("Get forest client not found should succeed") - void getForestClient_notFound_shouldSucceed() throws Exception { - String clientNumber = "111"; - - when(forestClientService.getClientByNumber(clientNumber)).thenReturn(Optional.empty()); - - mockMvc - .perform( - get("/api/forest-clients/{clientNumber}", clientNumber) - .header("Content-Type", MediaType.APPLICATION_JSON_VALUE) - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().isNotFound()) - .andReturn(); - } -} diff --git a/backend/src/test/java/ca/bc/gov/restapi/results/common/enums/ForestClientStatusEnumTest.java b/backend/src/test/java/ca/bc/gov/restapi/results/common/enums/ForestClientStatusEnumTest.java new file mode 100644 index 00000000..73d2a192 --- /dev/null +++ b/backend/src/test/java/ca/bc/gov/restapi/results/common/enums/ForestClientStatusEnumTest.java @@ -0,0 +1,42 @@ +package ca.bc.gov.restapi.results.common.enums; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.stream.Stream; +import org.apache.commons.lang3.StringUtils; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +@DisplayName("Unit Test | ForestClientStatusEnum") +class ForestClientStatusEnumTest { + + + @DisplayName("Test enum conversion") + @ParameterizedTest(name = "Test enum conversion for code {0} and description {1}") + @MethodSource("enumConversion") + void testEnumConversion(String code, String description, ForestClientStatusEnum expected) { + ForestClientStatusEnum actual = ForestClientStatusEnum.of(code); + assertEquals(expected, actual); + if (expected != null) { + assertEquals(expected.getCode(), actual.getCode()); + assertEquals(description, actual.getDescription()); + } + } + + private static Stream enumConversion() { + return Stream.of( + Arguments.of("ACT", "Active", ForestClientStatusEnum.ACTIVE), + Arguments.of("DAC", "Deactivated", ForestClientStatusEnum.DEACTIVATED), + Arguments.of("DEC", "Deceased", ForestClientStatusEnum.DECEASED), + Arguments.of("REC", "Receivership", ForestClientStatusEnum.RECEIVERSHIP), + Arguments.of("SPN", "Suspended", ForestClientStatusEnum.SUSPENDED), + Arguments.of(StringUtils.EMPTY, null, null), + Arguments.of(null, null, null), + Arguments.of(" ", null, null), + Arguments.of("ABC", null, null) + ); + } + +} \ No newline at end of file diff --git a/backend/src/test/java/ca/bc/gov/restapi/results/common/enums/ForestClientTypeEnumTest.java b/backend/src/test/java/ca/bc/gov/restapi/results/common/enums/ForestClientTypeEnumTest.java new file mode 100644 index 00000000..aaea4897 --- /dev/null +++ b/backend/src/test/java/ca/bc/gov/restapi/results/common/enums/ForestClientTypeEnumTest.java @@ -0,0 +1,46 @@ +package ca.bc.gov.restapi.results.common.enums; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.stream.Stream; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +@DisplayName("Unit Test | ForestClientTypeEnum") +class ForestClientTypeEnumTest { + + + @DisplayName("Test enum conversion") + @ParameterizedTest(name = "Test enum conversion for code {0} and description {1}") + @MethodSource("enumConversion") + void testEnumConversion(Character code, String description, ForestClientTypeEnum expected) { + ForestClientTypeEnum actual = ForestClientTypeEnum.of(code); + assertEquals(expected, actual); + if (expected != null) { + assertEquals(expected.getCode(), actual.getCode()); + assertEquals(description, actual.getDescription()); + } + } + + private static Stream enumConversion() { + return Stream.of( + Arguments.of('A', "Association", ForestClientTypeEnum.ASSOCIATION), + Arguments.of('B', "First Nation Band", ForestClientTypeEnum.FIRST_NATION_BAND), + Arguments.of('C', "Corporation", ForestClientTypeEnum.CORPORATION), + Arguments.of('F', "Ministry of Forests and Range", ForestClientTypeEnum.MINISTRY_OF_FORESTS_AND_RANGE), + Arguments.of('G', "Government", ForestClientTypeEnum.GOVERNMENT), + Arguments.of('I', "Individual", ForestClientTypeEnum.INDIVIDUAL), + Arguments.of('L', "Limited Partnership", ForestClientTypeEnum.LIMITED_PARTNERSHIP), + Arguments.of('P', "General Partnership", ForestClientTypeEnum.GENERAL_PARTNERSHIP), + Arguments.of('R', "First Nation Group", ForestClientTypeEnum.FIRST_NATION_GROUP), + Arguments.of('S', "Society", ForestClientTypeEnum.SOCIETY), + Arguments.of('T', "First Nation Tribal Council", ForestClientTypeEnum.FIRST_NATION_TRIBAL_COUNCIL), + Arguments.of('U', "Unregistered Company", ForestClientTypeEnum.UNREGISTERED_COMPANY), + Arguments.of(null, null, null), + Arguments.of('J', null, null) + ); + } + +} \ No newline at end of file diff --git a/backend/src/test/java/ca/bc/gov/restapi/results/common/pagination/PaginationParametersTest.java b/backend/src/test/java/ca/bc/gov/restapi/results/common/pagination/PaginationParametersTest.java new file mode 100644 index 00000000..9adce312 --- /dev/null +++ b/backend/src/test/java/ca/bc/gov/restapi/results/common/pagination/PaginationParametersTest.java @@ -0,0 +1,94 @@ +package ca.bc.gov.restapi.results.common.pagination; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import jakarta.validation.ConstraintViolation; +import jakarta.validation.Validation; +import jakarta.validation.Validator; +import jakarta.validation.ValidatorFactory; +import java.util.Set; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import org.springframework.data.domain.PageRequest; + +@DisplayName("Unit Test | Pagination Parameters") +class PaginationParametersTest { + + private static Validator validator; + + @BeforeAll + static void setUp() { + ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); + validator = factory.getValidator(); + } + + @ParameterizedTest + @CsvSource({ + "2, 10, 2, 10, 20, 2, 20", + "1, 10, 1, 10, 15, 1, 15", + }) + @DisplayName("Should check valid values") + void shouldCheckValidValues( + Integer page, + Integer perPage, + int expectedPage, + int expectedPerPage, + int maxPageSize, + int expectedPageablePage, + int expectedPageableSize + ) { + PaginationParameters params = new PaginationParameters(page, perPage); + assertEquals(expectedPage, params.page()); + assertEquals(expectedPerPage, params.perPage()); + assertEquals(PageRequest.of(expectedPageablePage, expectedPageableSize), + params.toPageable(maxPageSize)); + Set> violations = validator.validate(params); + assertTrue(violations.isEmpty()); + } + + @ParameterizedTest + @CsvSource({ + "-1, 5", + "1, -5" + }) + @DisplayName("Should check invalid values") + void shouldCheckInvalidValues( + Integer page, + Integer perPage + ) { + PaginationParameters params = new PaginationParameters(page, perPage); + Set> violations = validator.validate(params); + assertEquals(1, violations.size()); + assertNotNull(violations.iterator().next().getMessage()); + } + + @Test + @DisplayName("Should check null values") + void shouldCheckNullValues() { + PaginationParameters params = new PaginationParameters(null, 5); + assertEquals(0, params.page()); + assertEquals(5, params.perPage()); + assertEquals(PageRequest.of(0, 5), + params.toPageable(5)); + Set> violations = validator.validate(params); + assertTrue(violations.isEmpty()); + } + + @Test + @DisplayName("Should check null values perPage") + void shouldCheckNullValuesPerPage() { + PaginationParameters params = new PaginationParameters(1, null); + assertEquals(1, params.page()); + assertEquals(5, params.perPage()); + assertEquals(PageRequest.of(1, 5), + params.toPageable(5)); + Set> violations = validator.validate(params); + assertTrue(violations.isEmpty()); + } + +} \ No newline at end of file diff --git a/backend/src/test/java/ca/bc/gov/restapi/results/common/provider/ForestClientApiProviderTest.java b/backend/src/test/java/ca/bc/gov/restapi/results/common/provider/ForestClientApiProviderIntegrationTest.java similarity index 96% rename from backend/src/test/java/ca/bc/gov/restapi/results/common/provider/ForestClientApiProviderTest.java rename to backend/src/test/java/ca/bc/gov/restapi/results/common/provider/ForestClientApiProviderIntegrationTest.java index 0ea88a5f..0ea0bee2 100644 --- a/backend/src/test/java/ca/bc/gov/restapi/results/common/provider/ForestClientApiProviderTest.java +++ b/backend/src/test/java/ca/bc/gov/restapi/results/common/provider/ForestClientApiProviderIntegrationTest.java @@ -18,7 +18,8 @@ import org.junit.jupiter.api.extension.RegisterExtension; import org.springframework.web.client.RestClient; -class ForestClientApiProviderTest { +@DisplayName("Integrated Test | Forest Client API Provider") +class ForestClientApiProviderIntegrationTest { @RegisterExtension static WireMockExtension clientApiStub = WireMockExtension diff --git a/backend/src/test/java/ca/bc/gov/restapi/results/common/service/OpenMapsServiceTest.java b/backend/src/test/java/ca/bc/gov/restapi/results/common/service/OpenMapsServiceIntegrationTest.java similarity index 100% rename from backend/src/test/java/ca/bc/gov/restapi/results/common/service/OpenMapsServiceTest.java rename to backend/src/test/java/ca/bc/gov/restapi/results/common/service/OpenMapsServiceIntegrationTest.java