From c8c5beaa5804e781ebb41f51bf0db599d6e861f6 Mon Sep 17 00:00:00 2001 From: rng Date: Mon, 16 Feb 2026 16:58:37 +1100 Subject: [PATCH] Refactor to make test read application.yaml instead of hardcode --- .../core/configuration/WfsWmsConfig.java | 5 +- .../service/wfs/DownloadWfsDataService.java | 36 +------ .../server/core/service/wfs/WfsServer.java | 27 +++++ .../server/core/service/wms/WmsServer.java | 17 ++- .../aodn/ogcapi/server/processes/RestApi.java | 14 +-- .../ogcapi/server/processes/RestServices.java | 1 - .../wfs/DownloadWfsDataServiceTest.java | 102 +++++++++--------- 7 files changed, 95 insertions(+), 107 deletions(-) diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/configuration/WfsWmsConfig.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/configuration/WfsWmsConfig.java index 9074611f..4d437027 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/configuration/WfsWmsConfig.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/configuration/WfsWmsConfig.java @@ -9,6 +9,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Lazy; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.web.client.RestTemplate; @@ -36,7 +37,7 @@ public WfsServer createWfsServer(Search search, } @Bean - public WmsServer createWmsServer(@Qualifier("pretendUserEntity") HttpEntity entity) { - return new WmsServer(entity); + public WmsServer createWmsServer(Search search, @Lazy WfsServer wfsServer, @Qualifier("pretendUserEntity") HttpEntity entity) { + return new WmsServer(search, wfsServer, entity); } } diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wfs/DownloadWfsDataService.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wfs/DownloadWfsDataService.java index eac4b474..27212868 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wfs/DownloadWfsDataService.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wfs/DownloadWfsDataService.java @@ -13,7 +13,6 @@ import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; -import org.springframework.web.util.UriComponentsBuilder; import java.io.ByteArrayOutputStream; import java.io.InputStream; @@ -26,20 +25,17 @@ public class DownloadWfsDataService { private final WmsServer wmsServer; private final WfsServer wfsServer; private final RestTemplate restTemplate; - private final WfsDefaultParam wfsDefaultParam; private final HttpEntity pretendUserEntity; public DownloadWfsDataService( WmsServer wmsServer, WfsServer wfsServer, RestTemplate restTemplate, - WfsDefaultParam wfsDefaultParam, @Qualifier("pretendUserEntity") HttpEntity pretendUserEntity ) { this.wmsServer = wmsServer; this.wfsServer = wfsServer; this.restTemplate = restTemplate; - this.wfsDefaultParam = wfsDefaultParam; this.pretendUserEntity = pretendUserEntity; } @@ -95,33 +91,6 @@ private String buildCqlFilter(String startDate, String endDate, Object multiPoly return cqlFilter.toString(); } - - /** - * Build WFS GetFeature URL - */ - private String buildWfsRequestUrl(String wfsUrl, String layerName, String cqlFilter) { - UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(wfsUrl) - .scheme("https"); // Force HTTPS to fix redirect - - Map param = new HashMap<>(wfsDefaultParam.getDownload()); - param.put("typeName", layerName); - param.put("outputFormat", "text/csv"); - - // Add general query parameters - param.forEach((key, value) -> { - if (value != null) { - builder.queryParam(key, value); - } - }); - - // Add CQL filter if present - if (cqlFilter != null && !cqlFilter.isEmpty()) { - builder.queryParam("cql_filter", cqlFilter); - } - - return builder.build().toUriString(); - } - /** * Does collection lookup, WFS validation, field retrieval, and URL building */ @@ -130,7 +99,7 @@ public String prepareWfsRequestUrl( String startDate, String endDate, Object multiPolygon, - List fields,// TODO: currently not used + List fields, String layerName) { DescribeLayerResponse describeLayerResponse = wmsServer.describeLayer(uuid, FeatureRequest.builder().layerName(layerName).build()); @@ -167,12 +136,11 @@ public String prepareWfsRequestUrl( String cqlFilter = buildCqlFilter(validStartDate, validEndDate, multiPolygon, wfsFieldModel); // Build final WFS request URL - String wfsRequestUrl = buildWfsRequestUrl(wfsServerUrl, wfsTypeName, cqlFilter); + String wfsRequestUrl = wfsServer.createWfsRequestUrl(wfsServerUrl, wfsTypeName, fields, cqlFilter, null); log.info("Prepared WFS request URL: {}", wfsRequestUrl); return wfsRequestUrl; } - /** * Execute WFS request with SSE support */ diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wfs/WfsServer.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wfs/WfsServer.java index 005b1918..a67ff7a2 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wfs/WfsServer.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wfs/WfsServer.java @@ -68,7 +68,34 @@ public WfsServer(Search search, this.pretendUserEntity = entity; this.wfsDefaultParam = wfsDefaultParam; } + /** + * Build WFS GetFeature URL + */ + protected String createWfsRequestUrl(String wfsUrl, String layerName, List fields, String cqlFilter, String outputFormat) { + UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(wfsUrl) + .scheme("https"); // Force HTTPS to fix redirect + + Map param = new HashMap<>(wfsDefaultParam.getDownload()); + param.put("typeName", layerName); + param.put("outputFormat", outputFormat == null ? "text/csv" : outputFormat); + + if(fields != null) { + param.put("propertyName", String.join(",", fields)); + } + // Add general query parameters + param.forEach((key, value) -> { + if (value != null) { + builder.queryParam(key, value); + } + }); + + // Add CQL filter if present + if (cqlFilter != null && !cqlFilter.isEmpty()) { + builder.queryParam("cql_filter", cqlFilter); + } + return builder.build().toUriString(); + } /** * Get all WFS links from a collection. * diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wms/WmsServer.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wms/WmsServer.java index ecb324af..ce1f25e2 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wms/WmsServer.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wms/WmsServer.java @@ -49,13 +49,6 @@ public class WmsServer { @Autowired protected RestTemplateUtils restTemplateUtils; - @Lazy - @Autowired - protected WfsServer wfsServer; - - @Autowired - protected Search search; - @Autowired protected WmsDefaultParam wmsDefaultParam; @@ -67,13 +60,17 @@ public class WmsServer { protected WmsServer self; protected final HttpEntity pretendUserEntity; + protected WfsServer wfsServer; + protected Search search; - public WmsServer(HttpEntity entity) { + public WmsServer(Search search, WfsServer wfsServer, HttpEntity entity) { xmlMapper = new XmlMapper(); xmlMapper.registerModule(new JavaTimeModule()); // Add JavaTimeModule xmlMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - pretendUserEntity = entity; + this.pretendUserEntity = entity; + this.wfsServer = wfsServer; + this.search = search; } /** @@ -447,7 +444,7 @@ protected List createMapFeatureQueryUrl(String url, String uuid, Feature protected Optional getMapServerUrl(String collectionId, FeatureRequest request) { // Get the record contains the map feature, given one uuid , 1 result expected ElasticSearchBase.SearchResult result = search.searchCollections(collectionId); - if (!result.getCollections().isEmpty()) { + if (result != null && result.getCollections() != null && !result.getCollections().isEmpty()) { StacCollectionModel model = result.getCollections().get(0); String layerName = request != null ? request.getLayerName() : null; diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/processes/RestApi.java b/server/src/main/java/au/org/aodn/ogcapi/server/processes/RestApi.java index b4456cf6..ff9fe909 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/processes/RestApi.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/processes/RestApi.java @@ -5,7 +5,6 @@ import au.org.aodn.ogcapi.processes.model.InlineResponse200; import au.org.aodn.ogcapi.processes.model.ProcessList; import au.org.aodn.ogcapi.processes.model.Results; -import au.org.aodn.ogcapi.server.core.exception.wfs.WfsErrorHandler; import au.org.aodn.ogcapi.server.core.model.InlineValue; import au.org.aodn.ogcapi.server.core.model.enumeration.DatasetDownloadEnums; import au.org.aodn.ogcapi.server.core.model.enumeration.InlineResponseKeyEnum; @@ -122,12 +121,15 @@ public SseEmitter downloadWfsSse( final SseEmitter emitter = new SseEmitter(0L); try { - var uuid = (String) body.getInputs().get(DatasetDownloadEnums.Parameter.UUID.getValue()); - var startDate = (String) body.getInputs().get(DatasetDownloadEnums.Parameter.START_DATE.getValue()); - var endDate = (String) body.getInputs().get(DatasetDownloadEnums.Parameter.END_DATE.getValue()); + String uuid = body.getInputs().get(DatasetDownloadEnums.Parameter.UUID.getValue()).toString(); + String startDate = body.getInputs().get(DatasetDownloadEnums.Parameter.START_DATE.getValue()).toString(); + String endDate = body.getInputs().get(DatasetDownloadEnums.Parameter.END_DATE.getValue()).toString(); + String layerName = body.getInputs().get(DatasetDownloadEnums.Parameter.LAYER_NAME.getValue()).toString(); var multiPolygon = body.getInputs().get(DatasetDownloadEnums.Parameter.MULTI_POLYGON.getValue()); - var fields = (List) body.getInputs().get(DatasetDownloadEnums.Parameter.FIELDS.getValue()); - var layerName = (String) body.getInputs().get(DatasetDownloadEnums.Parameter.LAYER_NAME.getValue()); + + List fields = body.getInputs().get(DatasetDownloadEnums.Parameter.FIELDS.getValue()) instanceof List list + ? list.stream().map(String::valueOf).toList() + : null; return restServices.downloadWfsDataWithSse( uuid, startDate, endDate, multiPolygon, fields, layerName, emitter diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/processes/RestServices.java b/server/src/main/java/au/org/aodn/ogcapi/server/processes/RestServices.java index 46c50771..fa338eb9 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/processes/RestServices.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/processes/RestServices.java @@ -3,7 +3,6 @@ import au.org.aodn.ogcapi.server.core.exception.wfs.WfsErrorHandler; import au.org.aodn.ogcapi.server.core.model.enumeration.DatasetDownloadEnums; import au.org.aodn.ogcapi.server.core.service.wfs.DownloadWfsDataService; -import au.org.aodn.ogcapi.server.core.util.DatetimeUtils; import au.org.aodn.ogcapi.server.core.util.EmailUtils; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; diff --git a/server/src/test/java/au/org/aodn/ogcapi/server/core/service/wfs/DownloadWfsDataServiceTest.java b/server/src/test/java/au/org/aodn/ogcapi/server/core/service/wfs/DownloadWfsDataServiceTest.java index 2e7a796c..c55f671c 100644 --- a/server/src/test/java/au/org/aodn/ogcapi/server/core/service/wfs/DownloadWfsDataServiceTest.java +++ b/server/src/test/java/au/org/aodn/ogcapi/server/core/service/wfs/DownloadWfsDataServiceTest.java @@ -3,20 +3,24 @@ import au.org.aodn.ogcapi.server.core.model.ogc.FeatureRequest; import au.org.aodn.ogcapi.server.core.model.ogc.wfs.WFSFieldModel; import au.org.aodn.ogcapi.server.core.model.ogc.wms.DescribeLayerResponse; +import au.org.aodn.ogcapi.server.core.service.Search; import au.org.aodn.ogcapi.server.core.service.wms.WmsServer; +import au.org.aodn.ogcapi.server.core.util.RestTemplateUtils; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.HttpEntity; +import org.springframework.test.context.TestPropertySource; import org.springframework.web.client.RestTemplate; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; - import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; @@ -24,30 +28,38 @@ /** * Unit tests for DownloadWfsDataService */ +@SpringBootTest(classes = {WfsDefaultParam.class}) +@TestPropertySource(locations = "classpath:application.yaml") +@EnableConfigurationProperties(WfsDefaultParam.class) @ExtendWith(MockitoExtension.class) public class DownloadWfsDataServiceTest { @Mock - private WmsServer wmsServer; - - @Mock - private WfsServer wfsServer; + private RestTemplateUtils restTemplateUtils; @Mock private RestTemplate restTemplate; - @Mock - private WfsDefaultParam wfsDefaultParam; - @Mock private HttpEntity pretendUserEntity; - private DownloadWfsDataService downloadWfsDataService; + @Autowired + WfsDefaultParam wfsDefaultParam; + + DownloadWfsDataService downloadWfsDataService; + WmsServer wmsServer; + WfsServer wfsServer; @BeforeEach public void setUp() { + + Search search = Mockito.mock(Search.class); + + wfsServer = Mockito.spy(new WfsServer(search, restTemplate, restTemplateUtils, pretendUserEntity, wfsDefaultParam)); + wmsServer = Mockito.spy(new WmsServer(search, wfsServer, pretendUserEntity)); + downloadWfsDataService = new DownloadWfsDataService( - wmsServer, wfsServer, restTemplate, wfsDefaultParam, pretendUserEntity + wmsServer, wfsServer, restTemplate, pretendUserEntity ); } @@ -93,14 +105,10 @@ public void testPrepareWfsRequestUrl_WithNullDates() { when(layerDescription.getQuery()).thenReturn(query); when(query.getTypeName()).thenReturn(layerName); - when(wmsServer.describeLayer(eq(uuid), any(FeatureRequest.class))).thenReturn(describeLayerResponse); - when(wfsServer.getDownloadableFields(eq(uuid), any(FeatureRequest.class), anyString())).thenReturn(wfsFieldModel); - - Map defaultParams = new HashMap<>(); - defaultParams.put("service", "WFS"); - defaultParams.put("version", "2.0.0"); - defaultParams.put("request", "GetFeature"); - when(wfsDefaultParam.getDownload()).thenReturn(defaultParams); + doReturn(describeLayerResponse) + .when(wmsServer).describeLayer(eq(uuid), any(FeatureRequest.class)); + doReturn(wfsFieldModel) + .when(wfsServer).getDownloadableFields(eq(uuid), any(FeatureRequest.class), anyString()); // Test with null dates (non-specified dates from frontend) String result = downloadWfsDataService.prepareWfsRequestUrl( @@ -129,14 +137,10 @@ public void testPrepareWfsRequestUrl_WithEmptyDates() { when(layerDescription.getQuery()).thenReturn(query); when(query.getTypeName()).thenReturn(layerName); - when(wmsServer.describeLayer(eq(uuid), any(FeatureRequest.class))).thenReturn(describeLayerResponse); - when(wfsServer.getDownloadableFields(eq(uuid), any(FeatureRequest.class), anyString())).thenReturn(wfsFieldModel); - - Map defaultParams = new HashMap<>(); - defaultParams.put("service", "WFS"); - defaultParams.put("version", "2.0.0"); - defaultParams.put("request", "GetFeature"); - when(wfsDefaultParam.getDownload()).thenReturn(defaultParams); + doReturn(describeLayerResponse) + .when(wmsServer).describeLayer(eq(uuid), any(FeatureRequest.class)); + doReturn(wfsFieldModel) + .when(wfsServer).getDownloadableFields(eq(uuid), any(FeatureRequest.class), anyString()); // Test with empty string dates String result = downloadWfsDataService.prepareWfsRequestUrl( @@ -167,14 +171,10 @@ public void testPrepareWfsRequestUrl_WithValidDates() { when(layerDescription.getQuery()).thenReturn(query); when(query.getTypeName()).thenReturn(layerName); - when(wmsServer.describeLayer(eq(uuid), any(FeatureRequest.class))).thenReturn(describeLayerResponse); - when(wfsServer.getDownloadableFields(eq(uuid), any(FeatureRequest.class), anyString())).thenReturn(wfsFieldModel); - - Map defaultParams = new HashMap<>(); - defaultParams.put("service", "WFS"); - defaultParams.put("version", "2.0.0"); - defaultParams.put("request", "GetFeature"); - when(wfsDefaultParam.getDownload()).thenReturn(defaultParams); + doReturn(describeLayerResponse) + .when(wmsServer).describeLayer(eq(uuid), any(FeatureRequest.class)); + doReturn(wfsFieldModel) + .when(wfsServer).getDownloadableFields(eq(uuid), any(FeatureRequest.class), anyString()); // Test with valid dates String result = downloadWfsDataService.prepareWfsRequestUrl( @@ -207,14 +207,10 @@ public void testPrepareWfsRequestUrl_WithOnlyStartDate() { when(layerDescription.getQuery()).thenReturn(query); when(query.getTypeName()).thenReturn(layerName); - when(wmsServer.describeLayer(eq(uuid), any(FeatureRequest.class))).thenReturn(describeLayerResponse); - when(wfsServer.getDownloadableFields(eq(uuid), any(FeatureRequest.class), anyString())).thenReturn(wfsFieldModel); - - Map defaultParams = new HashMap<>(); - defaultParams.put("service", "WFS"); - defaultParams.put("version", "2.0.0"); - defaultParams.put("request", "GetFeature"); - when(wfsDefaultParam.getDownload()).thenReturn(defaultParams); + doReturn(describeLayerResponse) + .when(wmsServer).describeLayer(eq(uuid), any(FeatureRequest.class)); + doReturn(wfsFieldModel) + .when(wfsServer).getDownloadableFields(eq(uuid), any(FeatureRequest.class), anyString()); // Test with only start date (end date is null) String result = downloadWfsDataService.prepareWfsRequestUrl( @@ -245,14 +241,10 @@ public void testPrepareWfsRequestUrl_WithMMYYYYFormat() { when(layerDescription.getQuery()).thenReturn(query); when(query.getTypeName()).thenReturn(layerName); - when(wmsServer.describeLayer(eq(uuid), any(FeatureRequest.class))).thenReturn(describeLayerResponse); - when(wfsServer.getDownloadableFields(eq(uuid), any(FeatureRequest.class), anyString())).thenReturn(wfsFieldModel); - - Map defaultParams = new HashMap<>(); - defaultParams.put("service", "WFS"); - defaultParams.put("version", "2.0.0"); - defaultParams.put("request", "GetFeature"); - when(wfsDefaultParam.getDownload()).thenReturn(defaultParams); + doReturn(describeLayerResponse) + .when(wmsServer).describeLayer(eq(uuid), any(FeatureRequest.class)); + doReturn(wfsFieldModel) + .when(wfsServer).getDownloadableFields(eq(uuid), any(FeatureRequest.class), anyString()); // Test with MM-YYYY format dates String result = downloadWfsDataService.prepareWfsRequestUrl( @@ -276,8 +268,10 @@ public void testPrepareWfsRequestUrl_NoWfsServerUrl() { String uuid = "test-uuid"; String layerName = "test:layer"; - when(wmsServer.describeLayer(eq(uuid), any(FeatureRequest.class))).thenReturn(null); - when(wfsServer.getFeatureServerUrlByTitle(eq(uuid), eq(layerName))).thenReturn(java.util.Optional.empty()); + doReturn(null) + .when(wmsServer).describeLayer(eq(uuid), any(FeatureRequest.class)); + doReturn(java.util.Optional.empty()) + .when(wfsServer).getFeatureServerUrlByTitle(eq(uuid), eq(layerName)); // Test with no WFS server URL available Exception exception = assertThrows(IllegalArgumentException.class, () -> downloadWfsDataService.prepareWfsRequestUrl(