From 15b6e576583bd207936d395c5ab51c84e9970840 Mon Sep 17 00:00:00 2001 From: rng Date: Thu, 6 Nov 2025 09:37:10 +1100 Subject: [PATCH 1/3] Bug fix on picking dateTime field --- .../server/core/service/wms/WmsServer.java | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) 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 23186e30..141382f0 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 @@ -91,15 +91,16 @@ else if(wfsUrlComponents.getQueryParams().get("CQL_FILTER") != null) { if (!target.isEmpty()) { + List range = null; if (target.size() > 2) { // Try to find possible fields where it contains start end min max - target = target.stream() + range = target.stream() .filter(v -> Stream.of("start", "end", "min", "max").anyMatch(k -> v.getName().contains(k))) .toList(); } - if (target.size() == 2) { - // Due to no standard name, we try our best to guess if 2 dateTime field + if (range != null && range.size() == 2) { + // Due to no standard name, we try our best to guess if 2 dateTime field, range mean we found start/end date String[] d = request.getDatetime().split("/"); String guess1 = target.get(0).getName(); String guess2 = target.get(1).getName(); @@ -111,15 +112,21 @@ else if(wfsUrlComponents.getQueryParams().get("CQL_FILTER") != null) { } } else { // Only 1 field so use it. - log.debug("Map datetime field to name to [{}]", target.get(0).getName()); - return String.format("CQL_FILTER=%s%s DURING %s", cql, target.get(0).getName(), request.getDatetime()); + List individual = target.stream() + .filter(v -> Stream.of("juld").anyMatch(k -> v.getName().equalsIgnoreCase(k))) + .toList(); + + if(individual.size() == 1) { + log.debug("Map datetime field to name to [{}]", target.get(0).getName()); + return String.format("CQL_FILTER=%s%s DURING %s", cql, target.get(0).getName(), request.getDatetime()); + } } } log.error("No date time field found from query for uuid {}, result will not be bounded by date time", uuid); } catch (DownloadableFieldsNotFoundException dfnf) { // Without field, we cannot create a valid CQL filte targeting a dateTime, so just return empty - return ""; } + return "".equalsIgnoreCase(cql) ? "" : String.format("CQL_FILTER=%s", cql); } return ""; } From 37633413f09d6e541ed3ee354441c5bcb231e965 Mon Sep 17 00:00:00 2001 From: rng Date: Thu, 6 Nov 2025 09:42:06 +1100 Subject: [PATCH 2/3] Update comment. --- .../aodn/ogcapi/server/core/service/wms/WmsServer.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) 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 141382f0..a8f7dcf5 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 @@ -65,13 +65,21 @@ public WmsServer() { xmlMapper.registerModule(new JavaTimeModule()); // Add JavaTimeModule xmlMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); } - + /** + * This function is used to append the CQL filter to the geonetwork query, it will guess the correct dataTime field by + * some logic, so that if user select filter by range, it works. In case of issue please debug the logic as we are + * dealing with different non-standard name + * @param uuid - The uuid of metadata + * @param request - The request object to the map + * @return - The CQL combined the wfs cql and the dateTime query. + */ protected String createCQLFilter(String uuid, FeatureRequest request) { if (request.getDatetime() != null) { // Special handle for date time field, the field name will be diff across dataset. So we need // to look it up String cql = ""; try { + // If the metadata record have wfs url query, we will use it and analysis it and extract the CQL part if exist Optional wfsUrl = wfsServer.getFeatureServerUrlByTitleOrQueryParam(uuid, request.getLayerName()); if(wfsUrl.isPresent()) { UriComponents wfsUrlComponents = UriComponentsBuilder.fromUriString(wfsUrl.get()).build(); From 182631cde82ba9009fe09bc2468a71dde66a6353 Mon Sep 17 00:00:00 2001 From: rng Date: Thu, 6 Nov 2025 11:17:31 +1100 Subject: [PATCH 3/3] Add test cases --- .../core/service/wfs/WfsDefaultParam.java | 3 + .../server/core/service/wfs/WfsServer.java | 9 +- .../core/service/wms/WmsDefaultParam.java | 3 + .../server/core/service/wms/WmsServer.java | 95 +++--- .../wfs/DownloadableFieldsServiceTest.java | 9 +- .../core/service/wms/WmsServerTest.java | 313 +++++++++++++++++- .../server/service/wfs/WfsServerTest.java | 5 +- 7 files changed, 385 insertions(+), 52 deletions(-) diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wfs/WfsDefaultParam.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wfs/WfsDefaultParam.java index 6d29d05a..2c67af44 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wfs/WfsDefaultParam.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wfs/WfsDefaultParam.java @@ -12,6 +12,9 @@ @Component @ConfigurationProperties(prefix = "wfs-default-param") public class WfsDefaultParam { + + public static final String WFS_LINK_MARKER = "Data Access > wfs"; + private Map fields; private Map download; } 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 e6429820..69001000 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 @@ -29,6 +29,7 @@ import java.util.List; import java.util.Optional; import static au.org.aodn.ogcapi.server.core.configuration.CacheConfig.DOWNLOADABLE_FIELDS; +import static au.org.aodn.ogcapi.server.core.service.wfs.WfsDefaultParam.WFS_LINK_MARKER; @Slf4j public class WfsServer { @@ -111,7 +112,7 @@ protected Optional> getAllFeatureServerUrls(String collectionId) { .filter(link -> link.getAiGroup() != null) .filter(link -> // This is the pattern for wfs link - link.getAiGroup().contains("Data Access > wfs") || + link.getAiGroup().contains(WFS_LINK_MARKER) || // The data itself can be unclean, ows is another option where it works with wfs link.getHref().contains("/ows") ) @@ -136,7 +137,7 @@ public Optional getFeatureServerUrlByTitle(String collectionId, String l return model.getLinks() .stream() .filter(link -> link.getAiGroup() != null) - .filter(link -> link.getAiGroup().contains("Data Access > wfs") && link.getTitle().equalsIgnoreCase(layerName)) + .filter(link -> link.getAiGroup().contains(WFS_LINK_MARKER) && link.getTitle().equalsIgnoreCase(layerName)) .map(LinkModel::getHref) .findFirst(); } else { @@ -157,7 +158,7 @@ public Optional getFeatureServerUrlByTitleOrQueryParam(String collection return model.getLinks() .stream() .filter(link -> link.getAiGroup() != null) - .filter(link -> link.getAiGroup().contains("Data Access > wfs")) + .filter(link -> link.getAiGroup().contains(WFS_LINK_MARKER)) .filter(link -> { Optional name = extractTypenameFromUrl(link.getHref()); return link.getTitle().equalsIgnoreCase(layerName) || @@ -247,7 +248,7 @@ public List filterLayersByWfsLinks(String collectionId, List wfsLinks = model.getLinks() .stream() .filter(link -> link.getAiGroup() != null) - .filter(link -> link.getAiGroup().contains("Data Access > wfs")) + .filter(link -> link.getAiGroup().contains(WFS_LINK_MARKER)) .toList(); if (wfsLinks.isEmpty()) { diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wms/WmsDefaultParam.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wms/WmsDefaultParam.java index 88e7e3e0..d23d3d1d 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wms/WmsDefaultParam.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wms/WmsDefaultParam.java @@ -12,6 +12,9 @@ @Component @ConfigurationProperties(prefix = "wms-default-param") public class WmsDefaultParam { + + public static final String WMS_LINK_MARKER = "Data Access > wms"; + private Map wfs; private Map ncwfs; 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 a8f7dcf5..c68a5e7e 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 @@ -35,6 +35,7 @@ import java.util.stream.Stream; import static au.org.aodn.ogcapi.server.core.configuration.CacheConfig.CACHE_WMS_MAP_TILE; +import static au.org.aodn.ogcapi.server.core.service.wms.WmsDefaultParam.WMS_LINK_MARKER; @Slf4j public class WmsServer { @@ -74,24 +75,25 @@ public WmsServer() { * @return - The CQL combined the wfs cql and the dateTime query. */ protected String createCQLFilter(String uuid, FeatureRequest request) { + String cql = ""; + + // If the metadata record have wfs url query, we will use it and analysis it and extract the CQL part if exist + Optional wfsUrl = wfsServer.getFeatureServerUrlByTitleOrQueryParam(uuid, request.getLayerName()); + if(wfsUrl.isPresent()) { + UriComponents wfsUrlComponents = UriComponentsBuilder.fromUriString(wfsUrl.get()).build(); + // Extract the CQL if existing in the WFS, we need to apply it to the WMS as well + if(wfsUrlComponents.getQueryParams().get("cql_filter") != null) { + cql = wfsUrlComponents.getQueryParams().get("cql_filter").get(0); + } + else if(wfsUrlComponents.getQueryParams().get("CQL_FILTER") != null) { + cql = wfsUrlComponents.getQueryParams().get("CQL_FILTER").get(0); + } + } + if (request.getDatetime() != null) { // Special handle for date time field, the field name will be diff across dataset. So we need // to look it up - String cql = ""; try { - // If the metadata record have wfs url query, we will use it and analysis it and extract the CQL part if exist - Optional wfsUrl = wfsServer.getFeatureServerUrlByTitleOrQueryParam(uuid, request.getLayerName()); - if(wfsUrl.isPresent()) { - UriComponents wfsUrlComponents = UriComponentsBuilder.fromUriString(wfsUrl.get()).build(); - // Extract the CQL if existing in the WFS, we need to apply it to the WMS as well - if(wfsUrlComponents.getQueryParams().get("cql_filter") != null) { - cql = wfsUrlComponents.getQueryParams().get("cql_filter").get(0) + " AND "; - } - else if(wfsUrlComponents.getQueryParams().get("CQL_FILTER") != null) { - cql = wfsUrlComponents.getQueryParams().get("CQL_FILTER").get(0) + " AND "; - } - } - List m = this.getDownloadableFields(uuid, request); List target = m.stream() .filter(value -> "dateTime".equalsIgnoreCase(value.getType())) @@ -99,44 +101,55 @@ else if(wfsUrlComponents.getQueryParams().get("CQL_FILTER") != null) { if (!target.isEmpty()) { - List range = null; + List range; if (target.size() > 2) { // Try to find possible fields where it contains start end min max range = target.stream() .filter(v -> Stream.of("start", "end", "min", "max").anyMatch(k -> v.getName().contains(k))) .toList(); - } - if (range != null && range.size() == 2) { - // Due to no standard name, we try our best to guess if 2 dateTime field, range mean we found start/end date - String[] d = request.getDatetime().split("/"); - String guess1 = target.get(0).getName(); - String guess2 = target.get(1).getName(); - if ((guess1.contains("start") || guess1.contains("min")) && (guess2.contains("end") || guess2.contains("max"))) { - return String.format("CQL_FILTER=%s%s >= %s AND %s <= %s", cql, guess1, d[0], guess2, d[1]); - } - if ((guess2.contains("start") || guess2.contains("min")) && (guess1.contains("end") || guess1.contains("max"))) { - return String.format("CQL_FILTER=%s%s >= %s AND %s <= %s", cql, guess2, d[0], guess2, d[1]); - } - } else { - // Only 1 field so use it. - List individual = target.stream() - .filter(v -> Stream.of("juld").anyMatch(k -> v.getName().equalsIgnoreCase(k))) - .toList(); + if (range.size() == 2) { + // Due to no standard name, we try our best to guess if 2 dateTime field, range mean we found start/end date + String[] d = request.getDatetime().split("/"); + String guess1 = target.get(0).getName(); + String guess2 = target.get(1).getName(); - if(individual.size() == 1) { - log.debug("Map datetime field to name to [{}]", target.get(0).getName()); - return String.format("CQL_FILTER=%s%s DURING %s", cql, target.get(0).getName(), request.getDatetime()); + if ((guess1.contains("start") || guess1.contains("min")) && (guess2.contains("end") || guess2.contains("max"))) { + String timeCql = String.format("CQL_FILTER=%s >= %s AND %s <= %s", guess1, d[0], guess2, d[1]); + return "".equalsIgnoreCase(cql) ? timeCql : timeCql + " AND " + cql; + } + if ((guess2.contains("start") || guess2.contains("min")) && (guess1.contains("end") || guess1.contains("max"))) { + String timeCql = String.format("CQL_FILTER=%s >= %s AND %s <= %s", guess2, d[0], guess2, d[1]); + return "".equalsIgnoreCase(cql) ? timeCql : timeCql + " AND " + cql; + } + return "".equalsIgnoreCase(cql) ? "" : cql; + } else { + // There are more than 1 dateTime field, it is not range type, so we try to guess the individual one + // based on some common name. Add more if needed + List individual = target.stream() + .filter(v -> Stream.of("juld", "time").anyMatch(k -> v.getName().equalsIgnoreCase(k))) + .toList(); + + if(individual.size() == 1) { + log.debug("Map datetime field to name to [{}]", individual.get(0).getName()); + String timeCql = String.format("CQL_FILTER=%s DURING %s", individual.get(0).getName(), request.getDatetime()); + return "".equalsIgnoreCase(cql) ? timeCql : timeCql + " AND " + cql; + } } } + else if(target.size() == 1) { + log.debug("Map datetime field to name to the only dateTime field [{}]", target.get(0).getName()); + String timeCql = String.format("CQL_FILTER=%s DURING %s", target.get(0).getName(), request.getDatetime()); + return "".equalsIgnoreCase(cql) ? timeCql : timeCql + " AND " + cql; + } } - log.error("No date time field found from query for uuid {}, result will not be bounded by date time", uuid); - } catch (DownloadableFieldsNotFoundException dfnf) { - // Without field, we cannot create a valid CQL filte targeting a dateTime, so just return empty + log.error("No date time field found for uuid {}, result will not be bounded by date time even specified", uuid); + } + catch (DownloadableFieldsNotFoundException dfnf) { + // Without field, we cannot create a valid CQL filte targeting a dateTime, so just return existing CQL if exist } - return "".equalsIgnoreCase(cql) ? "" : String.format("CQL_FILTER=%s", cql); } - return ""; + return "".equalsIgnoreCase(cql) ? "" : String.format("CQL_FILTER=%s", cql); } /** * Create the full WMS url to fetch the tiles image @@ -370,7 +383,7 @@ protected Optional getMapServerUrl(String collectionId, FeatureRequest r List wmsLinks = model.getLinks() .stream() .filter(link -> link.getAiGroup() != null) - .filter(link -> link.getAiGroup().contains("Data Access > wms")) + .filter(link -> link.getAiGroup().contains(WMS_LINK_MARKER)) .toList(); if (wmsLinks.isEmpty()) { diff --git a/server/src/test/java/au/org/aodn/ogcapi/server/core/service/wfs/DownloadableFieldsServiceTest.java b/server/src/test/java/au/org/aodn/ogcapi/server/core/service/wfs/DownloadableFieldsServiceTest.java index c7444b6a..a973be78 100644 --- a/server/src/test/java/au/org/aodn/ogcapi/server/core/service/wfs/DownloadableFieldsServiceTest.java +++ b/server/src/test/java/au/org/aodn/ogcapi/server/core/service/wfs/DownloadableFieldsServiceTest.java @@ -30,6 +30,7 @@ import java.util.ArrayList; import java.util.List; +import static au.org.aodn.ogcapi.server.core.service.wfs.WfsDefaultParam.WFS_LINK_MARKER; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; @@ -124,7 +125,7 @@ public void testGetDownloadableFieldsSuccess() { LinkModel.builder() .href("http://geoserver-123.aodn.org.au/geoserver/ows") .title(request.getLayerName()) - .aiGroup("Data Access > wfs") + .aiGroup(WFS_LINK_MARKER) .build()) ) .build() @@ -194,7 +195,7 @@ public void testGetDownloadableFieldsEmptyResponse() { LinkModel.builder() .href("http://geoserver-123.aodn.org.au/geoserver/ows") .title(request.getLayerName()) - .aiGroup("Data Access > wfs") + .aiGroup(WFS_LINK_MARKER) .build()) ) .build() @@ -232,7 +233,7 @@ public void testGetDownloadableFieldsWfsError() { LinkModel.builder() .href("http://geoserver-123.aodn.org.au/geoserver/ows") .title(request.getLayerName()) - .aiGroup("Data Access > wfs") + .aiGroup(WFS_LINK_MARKER) .build()) ) .build() @@ -267,7 +268,7 @@ public void testGetDownloadableFieldsNetworkError() { LinkModel.builder() .href("http://geoserver-123.aodn.org.au/geoserver/ows") .title(request.getLayerName()) - .aiGroup("Data Access > wfs") + .aiGroup(WFS_LINK_MARKER) .build()) ) .build() diff --git a/server/src/test/java/au/org/aodn/ogcapi/server/core/service/wms/WmsServerTest.java b/server/src/test/java/au/org/aodn/ogcapi/server/core/service/wms/WmsServerTest.java index 7aa6ddd0..cf4ec53d 100644 --- a/server/src/test/java/au/org/aodn/ogcapi/server/core/service/wms/WmsServerTest.java +++ b/server/src/test/java/au/org/aodn/ogcapi/server/core/service/wms/WmsServerTest.java @@ -13,6 +13,7 @@ import au.org.aodn.ogcapi.server.core.service.wfs.WfsDefaultParam; import com.fasterxml.jackson.core.JsonProcessingException; import org.junit.jupiter.api.*; +import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration; import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; @@ -27,7 +28,10 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Optional; +import static au.org.aodn.ogcapi.server.core.service.wfs.WfsDefaultParam.WFS_LINK_MARKER; +import static au.org.aodn.ogcapi.server.core.service.wms.WmsDefaultParam.WMS_LINK_MARKER; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.mockito.ArgumentMatchers.*; @@ -56,6 +60,11 @@ public class WmsServerTest { @Autowired protected WmsServer wmsServer; + @BeforeEach + public void before() { + Mockito.reset(restTemplate); + } + @Test public void verifyWfsDescribeLayerUrlGenCorrect() { FeatureRequest featureRequest = FeatureRequest @@ -232,7 +241,7 @@ public void verifyHandleServiceExceptionReportCorrect() { LinkModel.builder() .href("http://geoserver-123.aodn.org.au/geoserver/wms") .title(request.getLayerName()) - .aiGroup("Data Access > wms") + .aiGroup(WMS_LINK_MARKER) .build()) ) .build() @@ -273,4 +282,306 @@ public void verifyParseCorrect() throws JsonProcessingException { assertEquals("https://geoserver-123.aodn.org.au/geoserver/wfs?", value.getLayerDescription().getWfs()); assertEquals("imos:srs_ghrsst_l4_gamssa_url", value.getLayerDescription().getQuery().getTypeName()); } + /** + * Test with only one dateTime field in the describe layer + * @throws JsonProcessingException - Not expected + */ + @Test + public void verifyCreateCQLSingleDateTime() throws JsonProcessingException { + String uuid = "uuid1"; + String layer = "imos:srs_ghrsst_l4_gamssa_url"; + FeatureRequest request = FeatureRequest.builder() + .datetime("2023-01-01/2023-12-31") + .layerName(layer) + .build(); + + ElasticSearchBase.SearchResult stac = new ElasticSearchBase.SearchResult<>(); + stac.setCollections(new ArrayList<>()); + stac.getCollections().add( + StacCollectionModel + .builder() + .links(List.of( + LinkModel.builder() + .href("http://geoserver-123.aodn.org.au/geoserver/wfs") + .title(request.getLayerName()) + .aiGroup(WFS_LINK_MARKER) + .build()) + ) + .build() + ); + // This sample contains 1 dateTime field + String value = + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; + + when(search.searchCollections(eq(uuid))) + .thenReturn(stac); + + when(restTemplate.getForEntity( + anyString(), + eq(String.class)) + ).thenReturn(ResponseEntity.ok(value)); + + String result = wmsServer.createCQLFilter(uuid, request); + + assertEquals("CQL_FILTER=time DURING 2023-01-01/2023-12-31", result); + } + /** + * Test with only one dateTime field in the describe layer with predefined cql + * @throws JsonProcessingException - Not expected + */ + @Test + public void verifyCreateCQLSingleDateTimeWithCQL() throws JsonProcessingException { + String uuid = "uuid1"; + String layer = "imos:srs_ghrsst_l4_gamssa_url"; + FeatureRequest request = FeatureRequest.builder() + .datetime("2023-01-01/2023-12-31") + .layerName(layer) + .build(); + + ElasticSearchBase.SearchResult stac = new ElasticSearchBase.SearchResult<>(); + stac.setCollections(new ArrayList<>()); + stac.getCollections().add( + StacCollectionModel + .builder() + .links(List.of( + LinkModel.builder() + .href("http://geoserver-123.aodn.org.au/geoserver/wfs?cql_filter=set_code=1234") + .title(request.getLayerName()) + .aiGroup(WFS_LINK_MARKER) + .build()) + ) + .build() + ); + // This sample contains 1 dateTime field + String value = + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; + + when(search.searchCollections(eq(uuid))) + .thenReturn(stac); + + when(restTemplate.getForEntity( + anyString(), + eq(String.class)) + ).thenReturn(ResponseEntity.ok(value)); + + String result = wmsServer.createCQLFilter(uuid, request); + + assertEquals("CQL_FILTER=time DURING 2023-01-01/2023-12-31 AND set_code=1234", result); + } + /** + * Test with only two or more dateTime field in the describe layer with predefined cql + * @throws JsonProcessingException - Not expected + */ + @Test + public void verifyCreateCQLMultiDateTimeWithCQL() throws JsonProcessingException { + String uuid = "uuid1"; + String layer = "aatams_sattag_qc_ctd_profile_map"; + FeatureRequest request = FeatureRequest.builder() + .datetime("2023-01-01/2023-12-31") + .layerName(layer) + .build(); + + ElasticSearchBase.SearchResult stac = new ElasticSearchBase.SearchResult<>(); + stac.setCollections(new ArrayList<>()); + stac.getCollections().add( + StacCollectionModel + .builder() + .links(List.of( + LinkModel.builder() + .href("http://geoserver-123.aodn.org.au/geoserver/wfs?cql_filter=set_code=1234") + .title(request.getLayerName()) + .aiGroup(WFS_LINK_MARKER) + .build()) + ) + .build() + ); + // This sample contains 1 dateTime field + String value = + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; + + when(search.searchCollections(eq(uuid))) + .thenReturn(stac); + + when(restTemplate.getForEntity( + anyString(), + eq(String.class)) + ).thenReturn(ResponseEntity.ok(value)); + + String result = wmsServer.createCQLFilter(uuid, request); + + assertEquals("CQL_FILTER=juld DURING 2023-01-01/2023-12-31 AND set_code=1234", result); + } + /** + * Test where dateTime is a range start_xxx end_xxx + * @throws JsonProcessingException - Not expected + */ + @Test + public void verifyCreateCQLRangeDateTimeWithCQL() throws JsonProcessingException { + String uuid = "uuid1"; + String layer = "aatams_sattag_qc_ctd_profile_map"; + FeatureRequest request = FeatureRequest.builder() + .datetime("2023-01-01/2023-12-31") + .layerName(layer) + .build(); + + ElasticSearchBase.SearchResult stac = new ElasticSearchBase.SearchResult<>(); + stac.setCollections(new ArrayList<>()); + stac.getCollections().add( + StacCollectionModel + .builder() + .links(List.of( + LinkModel.builder() + .href("http://geoserver-123.aodn.org.au/geoserver/wfs?cql_filter=set_code=1234") + .title(request.getLayerName()) + .aiGroup(WFS_LINK_MARKER) + .build()) + ) + .build() + ); + // This sample contains 1 dateTime field + String value = + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; + + when(search.searchCollections(eq(uuid))) + .thenReturn(stac); + + when(restTemplate.getForEntity( + anyString(), + eq(String.class)) + ).thenReturn(ResponseEntity.ok(value)); + + String result = wmsServer.createCQLFilter(uuid, request); + + assertEquals("CQL_FILTER=start_juld >= 2023-01-01 AND end_juld <= 2023-12-31 AND set_code=1234", result); + } } diff --git a/server/src/test/java/au/org/aodn/ogcapi/server/service/wfs/WfsServerTest.java b/server/src/test/java/au/org/aodn/ogcapi/server/service/wfs/WfsServerTest.java index 58cac516..92f113d0 100644 --- a/server/src/test/java/au/org/aodn/ogcapi/server/service/wfs/WfsServerTest.java +++ b/server/src/test/java/au/org/aodn/ogcapi/server/service/wfs/WfsServerTest.java @@ -18,6 +18,7 @@ import java.util.Collections; import java.util.List; +import static au.org.aodn.ogcapi.server.core.service.wfs.WfsDefaultParam.WFS_LINK_MARKER; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; @@ -82,7 +83,7 @@ void noWfsLinks_returnsEmptyLayers() { void primaryTitleMatch_filtersMatchingLayers() { LinkModel wfsLink = LinkModel.builder() .title("test_layer") - .aiGroup("Data Access > wfs") + .aiGroup(WFS_LINK_MARKER) .href("http://example.com?wfs").build(); StacCollectionModel model = StacCollectionModel.builder().links(List.of(wfsLink)).build(); @@ -110,7 +111,7 @@ void primaryTitleMatch_filtersMatchingLayers() { void primaryTitleMatch_filtersPreferAodnMapLayers() { LinkModel wfsLink = LinkModel.builder() .title("test_layer") - .aiGroup("Data Access > wfs") + .aiGroup(WFS_LINK_MARKER) .href("http://example.com?wfs").build(); StacCollectionModel model = StacCollectionModel.builder().links(List.of(wfsLink)).build();