|
12 | 12 | import static org.hamcrest.Matchers.greaterThanOrEqualTo; |
13 | 13 | import static org.hamcrest.Matchers.not; |
14 | 14 | import static org.hamcrest.Matchers.startsWith; |
| 15 | +import static org.junit.jupiter.api.Assertions.assertAll; |
15 | 16 | import static org.junit.jupiter.api.Assertions.assertEquals; |
16 | 17 | import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; |
17 | 18 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; |
|
22 | 23 | import static org.tailormap.api.controller.TestUrls.layerBegroeidTerreindeelPostgis; |
23 | 24 | import static org.tailormap.api.controller.TestUrls.layerProxiedWithAuthInPublicApp; |
24 | 25 |
|
| 26 | +import java.io.ByteArrayInputStream; |
25 | 27 | import java.io.IOException; |
| 28 | +import java.io.InputStream; |
26 | 29 | import java.nio.charset.StandardCharsets; |
| 30 | +import org.apache.poi.ss.usermodel.CellType; |
| 31 | +import org.apache.poi.ss.usermodel.Sheet; |
| 32 | +import org.apache.poi.ss.usermodel.Workbook; |
| 33 | +import org.apache.poi.ss.usermodel.WorkbookFactory; |
27 | 34 | import org.awaitility.Awaitility; |
28 | 35 | import org.junit.jupiter.api.BeforeEach; |
29 | 36 | import org.junit.jupiter.api.MethodOrderer; |
@@ -256,6 +263,90 @@ void should_export_wfs_to_csv_with_authentication() throws Exception { |
256 | 263 | }); |
257 | 264 | } |
258 | 265 |
|
| 266 | + @Test |
| 267 | + void should_export_large_filter_to_excel() throws Exception { |
| 268 | + final String extractUrl = apiBasePath + layerBegroeidTerreindeelPostgis + extractPath + sseClientId; |
| 269 | + mockMvc.perform(post(extractUrl) |
| 270 | + .accept(MediaType.APPLICATION_JSON) |
| 271 | + .with(setServletPath(extractUrl)) |
| 272 | + .with(csrf()) |
| 273 | + .param("attributes", "") |
| 274 | + .param("outputFormat", "xlsx") |
| 275 | + .param("filter", StaticTestData.get("large_cql_filter")) |
| 276 | + .acceptCharset(StandardCharsets.UTF_8) |
| 277 | + .characterEncoding(StandardCharsets.UTF_8) |
| 278 | + .contentType(MediaType.APPLICATION_FORM_URLENCODED)) |
| 279 | + .andExpect(status().isAccepted()); |
| 280 | + |
| 281 | + // The SseEventBus may dispatch events slightly after the POST returns. |
| 282 | + // Awaitility polls the buffered SSE response until the expected content appears. |
| 283 | + Awaitility.await() |
| 284 | + .atMost(10, SECONDS) |
| 285 | + .untilAsserted(() -> assertThat( |
| 286 | + sseResult.getResponse().getContentAsString(), containsString("Extract task received"))); |
| 287 | + |
| 288 | + Awaitility.await().pollInterval(5, SECONDS).atMost(30, SECONDS).untilAsserted(() -> { |
| 289 | + final String stream = sseResult.getResponse().getContentAsString(); |
| 290 | + assertThat(count_completed_messages(stream), greaterThanOrEqualTo(1)); |
| 291 | + }); |
| 292 | + |
| 293 | + final String lastCompletedEventJson = |
| 294 | + getLastCompletedEventJson(sseResult.getResponse().getContentAsString()); |
| 295 | + assertThat(lastCompletedEventJson.length(), greaterThanOrEqualTo(100)); |
| 296 | + |
| 297 | + final String extractedDownloadId = getDownloadId(lastCompletedEventJson); |
| 298 | + assertThat(extractedDownloadId, containsString(".xlsx")); |
| 299 | + |
| 300 | + final String downloadUrl = apiBasePath + layerBegroeidTerreindeelPostgis + downloadPath + extractedDownloadId; |
| 301 | + MvcResult download = mockMvc.perform(get(downloadUrl).with(setServletPath(downloadUrl))) |
| 302 | + .andExpect(status().isOk()) |
| 303 | + .andExpect(result -> { |
| 304 | + String contentType = result.getResponse().getContentType(); |
| 305 | + assertThat( |
| 306 | + contentType, |
| 307 | + containsString("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")); |
| 308 | + |
| 309 | + String contentDisposition = result.getResponse().getHeader("Content-Disposition"); |
| 310 | + assertThat(contentDisposition, containsString("attachment; filename=")); |
| 311 | + assertThat(contentDisposition, containsString(extractedDownloadId)); |
| 312 | + }) |
| 313 | + .andReturn(); |
| 314 | + |
| 315 | + // open the Excel file and check that we have the expected content |
| 316 | + try (InputStream inp = new ByteArrayInputStream(download.getResponse().getContentAsByteArray()); |
| 317 | + Workbook wb = WorkbookFactory.create(inp)) { |
| 318 | + Sheet sheet = wb.getSheetAt(0); |
| 319 | + |
| 320 | + assertEquals( |
| 321 | + 18 + /*header row*/ 1, |
| 322 | + sheet.getPhysicalNumberOfRows(), |
| 323 | + () -> "Expected " + 18 + /*header row*/ 1 |
| 324 | + + " rows in the Excel sheet, including header and 18 data rows"); |
| 325 | + |
| 326 | + assertAll( |
| 327 | + "Check header and first data row", |
| 328 | + () -> assertEquals( |
| 329 | + "begroeidterreindeel", |
| 330 | + sheet.getSheetName(), |
| 331 | + "Expected sheet name to be begroeidterreindeel"), |
| 332 | + () -> assertEquals( |
| 333 | + 14, sheet.getRow(0).getPhysicalNumberOfCells(), "Expected 14 columns in the header row")); |
| 334 | + |
| 335 | + assertAll( |
| 336 | + "Check first data row", |
| 337 | + () -> assertEquals( |
| 338 | + CellType.NUMERIC, |
| 339 | + sheet.getRow(1).getCell(0).getCellType(), |
| 340 | + "Expected first cell in header to be numeric (with date format)"), |
| 341 | + () -> assertEquals( |
| 342 | + CellType.STRING, |
| 343 | + sheet.getRow(1).getCell(1).getCellType(), |
| 344 | + "Expected second cell in header to be a string"), |
| 345 | + () -> assertEquals("geenWaarde", sheet.getRow(1).getCell(1).getStringCellValue()), |
| 346 | + () -> assertEquals("G0344", sheet.getRow(1).getCell(2).getStringCellValue())); |
| 347 | + } |
| 348 | + } |
| 349 | + |
259 | 350 | /** |
260 | 351 | * Parse the last non-empty line from the SSE stream that looks something like: |
261 | 352 | * {@code data:{"details":{"message":"Extract task |
|
0 commit comments