1 package de.dlr.shepard.integrationtests;
2
3 import static io.restassured.RestAssured.given;
4 import static org.assertj.core.api.Assertions.assertThat;
5 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
6 import static org.junit.jupiter.api.Assertions.assertEquals;
7 import static org.junit.jupiter.api.Assertions.assertTrue;
8
9 import de.dlr.shepard.ErrorResponse;
10 import de.dlr.shepard.RandomGenerator;
11 import de.dlr.shepard.auth.permission.io.PermissionsIO;
12 import de.dlr.shepard.auth.permission.model.Roles;
13 import de.dlr.shepard.common.util.Constants;
14 import de.dlr.shepard.common.util.JsonConverter;
15 import de.dlr.shepard.common.util.PermissionType;
16 import de.dlr.shepard.data.spatialdata.io.FilterCondition;
17 import de.dlr.shepard.data.spatialdata.io.Operator;
18 import de.dlr.shepard.data.spatialdata.io.SpatialDataContainerIO;
19 import de.dlr.shepard.data.spatialdata.io.SpatialDataPointIO;
20 import de.dlr.shepard.data.spatialdata.model.geometryFilter.AxisAlignedBoundingBox;
21 import de.dlr.shepard.data.spatialdata.model.geometryFilter.BoundingSphere;
22 import de.dlr.shepard.data.spatialdata.model.geometryFilter.KNearestNeighbor;
23 import io.quarkus.test.junit.QuarkusIntegrationTest;
24 import java.util.ArrayList;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.stream.Collectors;
28 import java.util.stream.IntStream;
29 import org.junit.jupiter.api.AfterAll;
30 import org.junit.jupiter.api.BeforeAll;
31 import org.junit.jupiter.api.MethodOrderer;
32 import org.junit.jupiter.api.Order;
33 import org.junit.jupiter.api.Test;
34 import org.junit.jupiter.api.TestMethodOrder;
35
36 @QuarkusIntegrationTest
37 @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
38 public class SpatialDataIT extends BaseTestCaseIT {
39
40 private static String containerURL;
41 private static SpatialDataContainerIO container;
42 private static ArrayList<SpatialDataContainerIO> existingContainers = new ArrayList<>();
43 private static List<SpatialDataPointIO> createdDataPoints;
44
45 @BeforeAll
46 public static void setUp() {
47 containerURL = Constants.SPATIAL_DATA_CONTAINERS;
48
49 IntStream.range(0, 50).forEach(index -> {
50 var containerName = "container_" + index + RandomGenerator.generateString(20);
51 var toCreate = new SpatialDataContainerIO();
52 toCreate.setName(containerName);
53
54 var actual = given()
55 .spec(requestSpecOfDefaultUser)
56 .body(toCreate)
57 .when()
58 .post(containerURL)
59 .then()
60 .statusCode(201)
61 .extract()
62 .as(SpatialDataContainerIO.class);
63 existingContainers.add(actual);
64 });
65 }
66
67 @AfterAll
68 public static void tearDown() {
69 existingContainers.forEach(container ->
70 given().spec(requestSpecOfDefaultUser).when().delete(containerURL + "/" + container.getId())
71 );
72 }
73
74 @Test
75 @Order(1)
76 public void createSpatialDataContainer() {
77 var containerName = "SpatialContainer";
78 var toCreate = new SpatialDataContainerIO();
79 toCreate.setName(containerName);
80
81 var actual = given()
82 .spec(requestSpecOfDefaultUser)
83 .body(toCreate)
84 .when()
85 .post(containerURL)
86 .then()
87 .statusCode(201)
88 .extract()
89 .as(SpatialDataContainerIO.class);
90 container = actual;
91
92 assertThat(actual.getId()).isNotNull();
93 assertThat(actual.getCreatedAt()).isNotNull();
94 assertThat(actual.getCreatedBy()).isEqualTo(nameOfDefaultUser);
95 assertThat(actual.getName()).isEqualTo(containerName);
96 assertThat(actual.getUpdatedAt()).isNull();
97 assertThat(actual.getUpdatedBy()).isNull();
98 }
99
100 @Test
101 @Order(2)
102 public void getAllSpatialDataContainers_success() {
103 var actual = given()
104 .spec(requestSpecOfDefaultUser)
105 .when()
106 .get(containerURL)
107 .then()
108 .statusCode(200)
109 .extract()
110 .as(SpatialDataContainerIO[].class);
111
112 assertThat(actual).contains(container);
113 }
114
115 @Test
116 @Order(2)
117 public void getAllSpatialDataContainers_filterByName_success() {
118 var actual = given()
119 .spec(requestSpecOfDefaultUser)
120 .queryParam("name", container.getName())
121 .when()
122 .get(containerURL)
123 .then()
124 .statusCode(200)
125 .extract()
126 .as(SpatialDataContainerIO[].class);
127
128 assertThat(actual).contains(container);
129
130 actual = given()
131 .spec(requestSpecOfDefaultUser)
132 .queryParam("name", RandomGenerator.generateString(20))
133 .when()
134 .get(containerURL)
135 .then()
136 .statusCode(200)
137 .extract()
138 .as(SpatialDataContainerIO[].class);
139
140 assertThat(actual).doesNotContain(container);
141 }
142
143 @Test
144 @Order(2)
145 public void getAllSpatialDataContainers_requestPage_success() {
146 var allContainers = given()
147 .spec(requestSpecOfDefaultUser)
148 .when()
149 .get(containerURL)
150 .then()
151 .statusCode(200)
152 .extract()
153 .as(SpatialDataContainerIO[].class);
154 var firstPage = given()
155 .spec(requestSpecOfDefaultUser)
156 .queryParam("page", 0)
157 .queryParam("size", 3)
158 .when()
159 .get(containerURL)
160 .then()
161 .statusCode(200)
162 .extract()
163 .as(SpatialDataContainerIO[].class);
164
165 var thirdPage = given()
166 .spec(requestSpecOfDefaultUser)
167 .queryParam("page", 2)
168 .queryParam("size", 3)
169 .when()
170 .get(containerURL)
171 .then()
172 .statusCode(200)
173 .extract()
174 .as(SpatialDataContainerIO[].class);
175
176 assertTrue(firstPage.length == 3);
177 assertTrue(thirdPage.length == 3);
178
179 SpatialDataContainerIO[] expectedFirstPge = { allContainers[0], allContainers[1], allContainers[2] };
180 SpatialDataContainerIO[] expectedThirdPge = { allContainers[6], allContainers[7], allContainers[8] };
181 assertArrayEquals(expectedFirstPge, firstPage);
182 assertArrayEquals(expectedThirdPge, thirdPage);
183 }
184
185 @Test
186 @Order(2)
187 public void getAllSpatialDataContainers_orderBy_success() {
188 var allContainersDesc = given()
189 .spec(requestSpecOfDefaultUser)
190 .queryParam("orderBy", "createdAt")
191 .queryParam("orderDesc", true)
192 .when()
193 .get(containerURL)
194 .then()
195 .statusCode(200)
196 .extract()
197 .as(SpatialDataContainerIO[].class);
198
199 var allContainersAsc = given()
200 .spec(requestSpecOfDefaultUser)
201 .queryParam("orderBy", "createdAt")
202 .queryParam("orderDesc", false)
203 .when()
204 .get(containerURL)
205 .then()
206 .statusCode(200)
207 .extract()
208 .as(SpatialDataContainerIO[].class);
209
210 IntStream.range(0, allContainersAsc.length).forEach(index ->
211 assertTrue(
212 allContainersAsc[index].getCreatedAt()
213 .before(allContainersDesc[allContainersAsc.length - 1 - index].getCreatedAt()) ||
214 allContainersAsc[index].getCreatedAt()
215 .equals(allContainersDesc[allContainersAsc.length - 1 - index].getCreatedAt())
216 )
217 );
218 }
219
220 @Test
221 @Order(4)
222 public void getSpatialDataContainer_success() {
223 var actual = given()
224 .spec(requestSpecOfDefaultUser)
225 .when()
226 .get(containerURL + "/" + container.getId())
227 .then()
228 .statusCode(200)
229 .extract()
230 .as(SpatialDataContainerIO.class);
231
232 assertThat(actual).isEqualTo(container);
233 }
234
235 @Test
236 @Order(4)
237 public void getSpatialDataContainer_wrongPermissions_forbid() {
238
239 given().spec(requestSpecOfOtherUser).when().get(containerURL + "/" + container.getId()).then().statusCode(403);
240 }
241
242 @Test
243 @Order(5)
244 public void getSpatialDataContainer_doesNotExist_notFound() {
245 ErrorResponse actual = given()
246 .spec(requestSpecOfDefaultUser)
247 .when()
248 .get(containerURL + "/999999")
249 .then()
250 .statusCode(404)
251 .extract()
252 .as(ErrorResponse.class);
253 assertThat(actual.getMessage()).isEqualTo("ID ERROR - Spatial data container with id 999999 is null or deleted");
254 }
255
256 @Test
257 @Order(6)
258 public void addSpatialDataPoints_success() {
259 createdDataPoints = IntStream.range(0, 10)
260 .mapToObj(index ->
261 new SpatialDataPointIO(
262 Long.valueOf(index),
263 index * 10.0,
264 index * 10.0,
265 index * 10.0,
266 Map.of("a_meta_data", "metadata_%s".formatted(index)),
267 Map.of("a_measurement", index)
268 )
269 )
270 .collect(Collectors.toList());
271 given()
272 .spec(requestSpecOfDefaultUser)
273 .body(createdDataPoints)
274 .when()
275 .post(String.format("%s/%d/%s", containerURL, container.getId(), Constants.PAYLOAD))
276 .then()
277 .statusCode(204);
278 }
279
280 @Test
281 @Order(6)
282 public void addSpatialDataPoints_wrongPermissions_forbid() {
283 createdDataPoints = IntStream.range(0, 10)
284 .mapToObj(index ->
285 new SpatialDataPointIO(
286 Long.valueOf(index),
287 index * 10.0,
288 index * 10.0,
289 index * 10.0,
290 Map.of("a_meta_data", "metadata_%s".formatted(index)),
291 Map.of("a_measurement", index)
292 )
293 )
294 .collect(Collectors.toList());
295 given()
296 .spec(requestSpecOfOtherUser)
297 .body(createdDataPoints)
298 .when()
299 .post(String.format("%s/%d/%s", containerURL, container.getId(), Constants.PAYLOAD))
300 .then()
301 .statusCode(403);
302 }
303
304 @Test
305 @Order(7)
306 public void getSpatialData_noFilters_retrievesAllPoints_Success() {
307 var dataPoints = given()
308 .spec(requestSpecOfDefaultUser)
309 .when()
310 .get(String.format("%s/%d/%s", containerURL, container.getId(), Constants.PAYLOAD))
311 .then()
312 .extract()
313 .as(SpatialDataPointIO[].class);
314 assertArrayEquals(createdDataPoints.toArray(), dataPoints);
315 }
316
317 @Test
318 @Order(7)
319 public void getSpatialData_geometryFilterBoundingSphere_success() {
320 BoundingSphere boundingSphere = new BoundingSphere(49, 0, 0, 0);
321
322 String geometryFilter = JsonConverter.convertToString(boundingSphere);
323 var dataPoints = given()
324 .spec(requestSpecOfDefaultUser)
325 .queryParam("geometryFilter", geometryFilter)
326 .when()
327 .get(String.format("%s/%d/%s", containerURL, container.getId(), Constants.PAYLOAD))
328 .then()
329 .extract()
330 .as(SpatialDataPointIO[].class);
331
332 SpatialDataPointIO[] expectedDataPoints = {
333 createdDataPoints.get(0),
334 createdDataPoints.get(1),
335 createdDataPoints.get(2),
336 };
337 assertArrayEquals(expectedDataPoints, dataPoints);
338 }
339
340 @Test
341 @Order(7)
342 public void getSpatialData_geometryFilterAxisAlignedBoundingBox_success() {
343 AxisAlignedBoundingBox axisAlignedBoundingBox = new AxisAlignedBoundingBox(-1, -1, -1, 49, 49, 49);
344
345 String geometryFilter = JsonConverter.convertToString(axisAlignedBoundingBox);
346 var dataPoints = given()
347 .spec(requestSpecOfDefaultUser)
348 .queryParam("geometryFilter", geometryFilter)
349 .when()
350 .get(String.format("%s/%d/%s", containerURL, container.getId(), Constants.PAYLOAD))
351 .then()
352 .extract()
353 .as(SpatialDataPointIO[].class);
354 assertEquals(dataPoints.length, 5);
355 }
356
357 @Test
358 @Order(7)
359 public void getSpatialData_geometryFilterKNN_success() {
360 KNearestNeighbor kNearestNeighbor = new KNearestNeighbor(3, 1, 1, 1);
361
362 String geometryFilter = JsonConverter.convertToString(kNearestNeighbor);
363
364 var dataPoints = given()
365 .spec(requestSpecOfDefaultUser)
366 .queryParam("geometryFilter", geometryFilter)
367 .when()
368 .get(String.format("%s/%d/%s", containerURL, container.getId(), Constants.PAYLOAD))
369 .then()
370 .extract()
371 .as(SpatialDataPointIO[].class);
372 assertEquals(dataPoints.length, 3);
373 }
374
375 @Test
376 @Order(7)
377 public void getSpatialData_geometryFilterKNNWithMetadataFilter_success() {
378 KNearestNeighbor kNearestNeighbor = new KNearestNeighbor(3, 1, 1, 1);
379
380 String geometryFilter = JsonConverter.convertToString(kNearestNeighbor);
381 String metadataFilter = JsonConverter.convertToString(Map.of("a_meta_data", "metadata_1"));
382 var dataPoints = given()
383 .spec(requestSpecOfDefaultUser)
384 .queryParam("geometryFilter", geometryFilter)
385 .queryParam("metadataFilter", metadataFilter)
386 .when()
387 .get(String.format("%s/%d/%s", containerURL, container.getId(), Constants.PAYLOAD))
388 .then()
389 .extract()
390 .as(SpatialDataPointIO[].class);
391 assertEquals(dataPoints.length, 1);
392 assertEquals(dataPoints[0].getMetadata().get("a_meta_data"), "metadata_1");
393 }
394
395 @Test
396 @Order(7)
397 public void getSpatialData_geometryFilterKNNWithMeasurementsFilter_success() {
398 KNearestNeighbor kNearestNeighbor = new KNearestNeighbor(3, 1, 1, 1);
399
400 String geometryFilter = JsonConverter.convertToString(kNearestNeighbor);
401 List<FilterCondition> measurementsFilters = List.of(new FilterCondition("a_measurement", Operator.EQUALS, 1));
402 String measurementsFilter = JsonConverter.convertToString(measurementsFilters);
403 var dataPoints = given()
404 .spec(requestSpecOfDefaultUser)
405 .queryParam("geometryFilter", geometryFilter)
406 .queryParam("measurementsFilter", measurementsFilter)
407 .when()
408 .get(String.format("%s/%d/%s", containerURL, container.getId(), Constants.PAYLOAD))
409 .then()
410 .extract()
411 .as(SpatialDataPointIO[].class);
412 assertEquals(dataPoints.length, 1);
413 assertEquals(dataPoints[0].getMeasurements().get("a_measurement"), 1);
414 }
415
416 @Test
417 @Order(7)
418 public void getSpatialData_geometryFilterKNNWithTimeDuration_success() {
419 KNearestNeighbor kNearestNeighbor = new KNearestNeighbor(50, 1, 1, 1);
420
421 String geometryFilter = JsonConverter.convertToString(kNearestNeighbor);
422 var dataPoints = given()
423 .spec(requestSpecOfDefaultUser)
424 .queryParam("geometryFilter", geometryFilter)
425 .queryParam("startTime", 0)
426 .queryParam("endTime", 4)
427 .when()
428 .get(String.format("%s/%d/%s", containerURL, container.getId(), Constants.PAYLOAD))
429 .then()
430 .extract()
431 .as(SpatialDataPointIO[].class);
432 assertEquals(dataPoints.length, 5);
433 }
434
435 @Test
436 @Order(7)
437 public void getSpatialData_geometryFilterBoundingSphereWithLimit_success() {
438 BoundingSphere boundingSphere = new BoundingSphere(110, 0, 0, 0);
439
440 String geometryFilter = JsonConverter.convertToString(boundingSphere);
441 var dataPoints = given()
442 .spec(requestSpecOfDefaultUser)
443 .queryParam("geometryFilter", geometryFilter)
444 .queryParam("limit", 5)
445 .when()
446 .get(String.format("%s/%d/%s", containerURL, container.getId(), Constants.PAYLOAD))
447 .then()
448 .extract()
449 .as(SpatialDataPointIO[].class);
450 assertEquals(dataPoints.length, 5);
451 }
452
453 @Test
454 @Order(7)
455 public void getSpatialData_geometryFilterKNNWithSkip_success() {
456 BoundingSphere boundingSphere = new BoundingSphere(200, 0, 0, 0);
457
458 String geometryFilter = JsonConverter.convertToString(boundingSphere);
459 var dataPoints = given()
460 .spec(requestSpecOfDefaultUser)
461 .queryParam("geometryFilter", geometryFilter)
462 .queryParam("skip", 2)
463 .when()
464 .get(String.format("%s/%d/%s", containerURL, container.getId(), Constants.PAYLOAD))
465 .then()
466 .extract()
467 .as(SpatialDataPointIO[].class);
468 assertEquals(dataPoints.length, 5);
469 }
470
471 @Test
472 @Order(7)
473 public void getSpatialData_wrongPermissions_forbid() {
474 BoundingSphere boundingSphere = new BoundingSphere(200, 0, 0, 0);
475 String geometryFilter = JsonConverter.convertToString(boundingSphere);
476 given()
477 .spec(requestSpecOfOtherUser)
478 .queryParam("geometryFilter", geometryFilter)
479 .queryParam("skip", 2)
480 .when()
481 .get(String.format("%s/%d/%s", containerURL, container.getId(), Constants.PAYLOAD))
482 .then()
483 .statusCode(403);
484 }
485
486 @Test
487 @Order(8)
488 public void getPermissions_success() {
489 PermissionsIO expectedPermissions = new PermissionsIO();
490 expectedPermissions.setEntityId(container.getId());
491 expectedPermissions.setOwner(defaultUser.getUser().getUsername());
492 expectedPermissions.setPermissionType(PermissionType.Private);
493 expectedPermissions.setManager(new String[] {});
494 expectedPermissions.setReader(new String[] {});
495 expectedPermissions.setWriter(new String[] {});
496
497 PermissionsIO actualPermissions = given()
498 .spec(requestSpecOfDefaultUser)
499 .when()
500 .get(String.format("%s/%d/%s", containerURL, container.getId(), Constants.PERMISSIONS))
501 .then()
502 .statusCode(200)
503 .extract()
504 .as(PermissionsIO.class);
505
506 assertEquals(expectedPermissions, actualPermissions);
507 }
508
509 @Test
510 @Order(8)
511 public void getPermissions_wrongPermissions_forbid() {
512 given()
513 .spec(requestSpecOfOtherUser)
514 .when()
515 .get(String.format("%s/%d/%s", containerURL, container.getId(), Constants.PERMISSIONS))
516 .then()
517 .statusCode(403);
518 }
519
520 @Test
521 @Order(8)
522 public void getRoles_success() {
523 Roles expectedRolesOwner = new Roles();
524 expectedRolesOwner.setOwner(true);
525 expectedRolesOwner.setManager(false);
526 expectedRolesOwner.setReader(false);
527 expectedRolesOwner.setWriter(false);
528
529 Roles actualRolesOwner = given()
530 .spec(requestSpecOfDefaultUser)
531 .when()
532 .get(String.format("%s/%d/%s", containerURL, container.getId(), Constants.ROLES))
533 .then()
534 .statusCode(200)
535 .extract()
536 .as(Roles.class);
537
538 assertEquals(expectedRolesOwner, actualRolesOwner);
539 }
540
541 @Test
542 @Order(9)
543 public void updatePermissions_setPublicReadableAndWritePermissionsToOtherUser_success() {
544
545 PermissionsIO updatedPermissions = new PermissionsIO();
546 updatedPermissions.setEntityId(container.getId());
547 updatedPermissions.setOwner(defaultUser.getUser().getUsername());
548 updatedPermissions.setPermissionType(PermissionType.PublicReadable);
549 updatedPermissions.setManager(new String[] {});
550 updatedPermissions.setReader(new String[] {});
551 updatedPermissions.setWriter(new String[] { otherUser.getUser().getUsername() });
552
553 PermissionsIO actualPermissions = given()
554 .spec(requestSpecOfDefaultUser)
555 .body(updatedPermissions)
556 .when()
557 .put(String.format("%s/%d/%s", containerURL, container.getId(), Constants.PERMISSIONS))
558 .then()
559 .statusCode(200)
560 .extract()
561 .as(PermissionsIO.class);
562
563 assertEquals(updatedPermissions, actualPermissions);
564
565
566 BoundingSphere boundingSphere = new BoundingSphere(200, 0, 0, 0);
567 String geometryFilter = JsonConverter.convertToString(boundingSphere);
568 given()
569 .spec(requestSpecOfOtherUser)
570 .queryParam("geometryFilter", geometryFilter)
571 .queryParam("skip", 2)
572 .when()
573 .get(String.format("%s/%d/%s", containerURL, container.getId(), Constants.PAYLOAD))
574 .then()
575 .statusCode(200);
576
577
578 createdDataPoints = IntStream.range(0, 10)
579 .mapToObj(index ->
580 new SpatialDataPointIO(
581 Long.valueOf(index),
582 index * 10.0,
583 index * 10.0,
584 index * 10.0,
585 Map.of("a_meta_data", "metadata_%s".formatted(index)),
586 Map.of("a_measurement", index)
587 )
588 )
589 .collect(Collectors.toList());
590 given()
591 .spec(requestSpecOfOtherUser)
592 .body(createdDataPoints)
593 .when()
594 .post(String.format("%s/%d/%s", containerURL, container.getId(), Constants.PAYLOAD))
595 .then()
596 .statusCode(204);
597 }
598
599 @Test
600 @Order(10)
601 public void updatePermissions_OtherUserIsNotManager_forbid() {
602 PermissionsIO updatedPermissions = new PermissionsIO();
603 updatedPermissions.setEntityId(container.getId());
604 updatedPermissions.setOwner(defaultUser.getUser().getUsername());
605 updatedPermissions.setPermissionType(PermissionType.PublicReadable);
606 updatedPermissions.setManager(new String[] {});
607 updatedPermissions.setReader(new String[] {});
608 updatedPermissions.setWriter(new String[] { otherUser.getUser().getUsername() });
609
610 given()
611 .spec(requestSpecOfOtherUser)
612 .body(updatedPermissions)
613 .when()
614 .put(String.format("%s/%d/%s", containerURL, container.getId(), Constants.PERMISSIONS))
615 .then()
616 .statusCode(403);
617 }
618
619 @Test
620 @Order(11)
621 public void deleteContainer() {
622
623 given().spec(requestSpecOfOtherUser).when().delete(containerURL + "/" + container.getId()).then().statusCode(403);
624
625 given().spec(requestSpecOfDefaultUser).when().delete(containerURL + "/" + container.getId()).then().statusCode(200);
626
627 given().spec(requestSpecOfDefaultUser).when().get(containerURL + "/" + container.getId()).then().statusCode(404);
628 }
629 }