diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/geoserver/wfs/DownloadWfsDataService.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/geoserver/wfs/DownloadWfsDataService.java index f6dedf64..d3793c65 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/geoserver/wfs/DownloadWfsDataService.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/geoserver/wfs/DownloadWfsDataService.java @@ -120,6 +120,10 @@ public BigInteger estimateDownloadSize( BigInteger featureCount = BigInteger.valueOf(root.get("totalFeatures").asLong()); log.debug("Total record hits {}", featureCount); + if (featureCount.equals(BigInteger.ZERO)) { + return BigInteger.ZERO; + } + // In case the records we have is smaller than our predefined SAMPLES_SIZE, we use smaller one. long sampleSize = featureCount.longValue() < SAMPLES_SIZE ? featureCount.longValue() : SAMPLES_SIZE; 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 f7fc21ef..80fea273 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 @@ -321,11 +321,12 @@ public SseEmitter downloadWfsDataWithSse(String uuid, "timestamp", System.currentTimeMillis() ))); } - catch(IllegalArgumentException iae) { + catch(Exception e) { + log.warn("Unexpected error during size estimation for UUID {}: {}", uuid, e.getMessage()); emitter.send(SseEmitter.event() .name("estimate-failed") .data(Map.of( - "message", iae.getMessage(), + "message", "Size estimation failed: " + e.getMessage(), "timestamp", System.currentTimeMillis() ))); } diff --git a/server/src/test/java/au/org/aodn/ogcapi/server/core/service/geoserver/wfs/DownloadWfsDataServiceTest.java b/server/src/test/java/au/org/aodn/ogcapi/server/core/service/geoserver/wfs/DownloadWfsDataServiceTest.java index 53096b95..ba6b2d21 100644 --- a/server/src/test/java/au/org/aodn/ogcapi/server/core/service/geoserver/wfs/DownloadWfsDataServiceTest.java +++ b/server/src/test/java/au/org/aodn/ogcapi/server/core/service/geoserver/wfs/DownloadWfsDataServiceTest.java @@ -370,6 +370,48 @@ void shouldReturnEstimatedSizeWhenBothRequestsSucceed() { long expected = 227193L * sampleBytes.length / DownloadWfsDataService.SAMPLES_SIZE; assertEquals(BigInteger.valueOf(expected), size, "Size match"); } + @Test + void shouldReturnZeroWhenTotalFeaturesIsZero() { + String uuid = "lyr-123"; + String layer = "water_bodies"; + String start = "2024-01-01"; + String end = "2024-12-31"; + Object multiPolygon = new Object(); + List fields = List.of("name", "area"); + String format = "application/json"; + + String countJson = "{\"totalFeatures\": 0, \"features\": []}"; + ResponseEntity countResponse = new ResponseEntity<>(countJson, HttpStatus.OK); + + doReturn(countResponse) + .when(restTemplate).exchange( + argThat((String url) -> url != null && url.contains("maxFeatures=1")), + eq(HttpMethod.GET), + any(HttpEntity.class), + eq(String.class)); + + doReturn(Optional.of("http://dummy.com/wfs")) + .when(wfsServer).getFeatureServerUrl(eq(uuid), anyString()); + + WfsFields fs = WfsFields.builder() + .fields(List.of( + WfsField.builder().type("dateTime").name("time").build() + )) + .build(); + + doReturn(fs) + .when(wfsServer).getDownloadableFields(eq(uuid), any(WfsServer.WfsFeatureRequest.class)); + + BigInteger size = downloadWfsDataService.estimateDownloadSize( + uuid, layer, start, end, multiPolygon, fields, format); + + assertEquals(BigInteger.ZERO, size, "Size should be zero when totalFeatures is 0"); + // No sample download should be made + verify(restTemplate, never()).exchange( + argThat((String url) -> url != null && url.contains("maxFeatures=0")), + eq(HttpMethod.GET), any(), eq(byte[].class)); + } + /** * Expect RuntimeException when GeoServer returns JSON without the totalFeatures field * (e.g. GeoServer returned an error JSON or unexpected structure)