Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision

Target

Select target project
  • fair-data-austria-db-repository/fda-services
1 result
Select Git revision
Show changes
Showing
with 892 additions and 492 deletions
<?xml version="1.0" encoding="utf-8"?><testsuites><testsuite name="pytest" errors="0" failures="0" skipped="0" tests="48" time="25.604" timestamp="2025-01-29T15:46:14.797988+01:00" hostname="medusa"><testcase classname="test.test_app.JwtTest" name="test_delete_database_no_auth_fails" time="11.131" /><testcase classname="test.test_app.JwtTest" name="test_delete_database_no_role_fails" time="0.317" /><testcase classname="test.test_app.JwtTest" name="test_delete_database_not_found_fails" time="0.370" /><testcase classname="test.test_app.JwtTest" name="test_delete_database_succeeds" time="0.524" /><testcase classname="test.test_app.JwtTest" name="test_get_fields_fails" time="0.154" /><testcase classname="test.test_app.JwtTest" name="test_get_fields_succeeds" time="0.218" /><testcase classname="test.test_app.JwtTest" name="test_get_fuzzy_search_no_query_fails" time="0.173" /><testcase classname="test.test_app.JwtTest" name="test_get_fuzzy_search_succeeds" time="0.283" /><testcase classname="test.test_app.JwtTest" name="test_get_index_fails" time="0.240" /><testcase classname="test.test_app.JwtTest" name="test_get_index_succeeds" time="0.190" /><testcase classname="test.test_app.JwtTest" name="test_health_succeeds" time="0.160" /><testcase classname="test.test_app.JwtTest" name="test_post_general_search_column_succeeds" time="0.386" /><testcase classname="test.test_app.JwtTest" name="test_post_general_search_concept_succeeds" time="0.341" /><testcase classname="test.test_app.JwtTest" name="test_post_general_search_identifier_succeeds" time="0.312" /><testcase classname="test.test_app.JwtTest" name="test_post_general_search_media_type_fails" time="0.140" /><testcase classname="test.test_app.JwtTest" name="test_post_general_search_no_body_fails" time="0.134" /><testcase classname="test.test_app.JwtTest" name="test_post_general_search_succeeds" time="0.284" /><testcase classname="test.test_app.JwtTest" name="test_post_general_search_table_succeeds" time="0.336" /><testcase classname="test.test_app.JwtTest" name="test_post_general_search_unit_succeeds" time="0.246" /><testcase classname="test.test_app.JwtTest" name="test_post_general_search_view_succeeds" time="0.281" /><testcase classname="test.test_app.JwtTest" name="test_update_database_empty_body_fails" time="0.177" /><testcase classname="test.test_app.JwtTest" name="test_update_database_malformed_body_fails" time="0.180" /><testcase classname="test.test_app.JwtTest" name="test_update_database_media_type_fails" time="0.231" /><testcase classname="test.test_app.JwtTest" name="test_update_database_no_auth_fails" time="0.119" /><testcase classname="test.test_app.JwtTest" name="test_update_database_no_body_fails" time="0.150" /><testcase classname="test.test_app.JwtTest" name="test_update_database_succeeds" time="0.243" /><testcase classname="test.test_jwt.JwtTest" name="test_get_user_roles_succeeds" time="0.146" /><testcase classname="test.test_jwt.JwtTest" name="test_verify_password_empty_password_fails" time="0.144" /><testcase classname="test.test_jwt.JwtTest" name="test_verify_password_empty_username_fails" time="0.127" /><testcase classname="test.test_jwt.JwtTest" name="test_verify_password_no_password_fails" time="0.142" /><testcase classname="test.test_jwt.JwtTest" name="test_verify_password_no_username_fails" time="0.146" /><testcase classname="test.test_jwt.JwtTest" name="test_verify_password_succeeds" time="0.152" /><testcase classname="test.test_jwt.JwtTest" name="test_verify_token_empty_token_fails" time="0.144" /><testcase classname="test.test_jwt.JwtTest" name="test_verify_token_malformed_token_fails" time="0.143" /><testcase classname="test.test_jwt.JwtTest" name="test_verify_token_no_token_fails" time="0.130" /><testcase classname="test.test_jwt.JwtTest" name="test_verify_token_succeeds" time="0.212" /><testcase classname="test.test_opensearch_client.OpenSearchClientTest" name="test_delete_database_fails" time="0.120" /><testcase classname="test.test_opensearch_client.OpenSearchClientTest" name="test_delete_database_succeeds" time="0.172" /><testcase classname="test.test_opensearch_client.OpenSearchClientTest" name="test_fuzzy_search_succeeds" time="0.190" /><testcase classname="test.test_opensearch_client.OpenSearchClientTest" name="test_get_fields_for_index_database_succeeds" time="0.201" /><testcase classname="test.test_opensearch_client.OpenSearchClientTest" name="test_get_fields_for_index_user_succeeds" time="0.202" /><testcase classname="test.test_opensearch_client.OpenSearchClientTest" name="test_unit_independent_search_fails" time="0.208" /><testcase classname="test.test_opensearch_client.OpenSearchClientTest" name="test_update_database_create_succeeds" time="0.205" /><testcase classname="test.test_opensearch_client.OpenSearchClientTest" name="test_update_database_malformed_fails" time="0.237" /><testcase classname="test.test_opensearch_client.OpenSearchClientTest" name="test_update_database_succeeds" time="0.214" /><testcase classname="test.test_keycloak_client.JwtTest" name="test_obtain_user_token_malformed_fails" time="0.112" /><testcase classname="test.test_keycloak_client.JwtTest" name="test_obtain_user_token_succeeds" time="0.149" /><testcase classname="test.test_keycloak_client.JwtTest" name="test_verify_jwt_succeeds" time="0.684" /></testsuite></testsuites>
\ No newline at end of file
...@@ -8,10 +8,15 @@ ...@@ -8,10 +8,15 @@
<version>3.3.5</version> <version>3.3.5</version>
</parent> </parent>
<organization>
<name>TU Wien</name>
<url>https://www.tuwien.ac.at</url>
</organization>
<groupId>at.tuwien</groupId> <groupId>at.tuwien</groupId>
<artifactId>dbrepo-data-service</artifactId> <artifactId>dbrepo-data-service</artifactId>
<name>dbrepo-data-service</name> <name>dbrepo-data-service</name>
<version>1.6.5</version> <version>1.7.0</version>
<description>Service that manages the data</description> <description>Service that manages the data</description>
...@@ -23,7 +28,7 @@ ...@@ -23,7 +28,7 @@
<module>report</module> <module>report</module>
</modules> </modules>
<url>https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.6/</url> <url>https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.7/</url>
<developers> <developers>
<developer> <developer>
<name>Martin Weise</name> <name>Martin Weise</name>
...@@ -54,14 +59,37 @@ ...@@ -54,14 +59,37 @@
<minio.version>8.5.7</minio.version> <minio.version>8.5.7</minio.version>
<guava.version>33.3.0-jre</guava.version> <guava.version>33.3.0-jre</guava.version>
<spark.version>4.0.0-preview2</spark.version> <spark.version>4.0.0-preview2</spark.version>
<keycloak.version>26.0.4</keycloak.version>
<scala.version>2.13</scala.version> <scala.version>2.13</scala.version>
<antlr-runtime.version>3.5.2</antlr-runtime.version> <antlr-runtime.version>3.5.2</antlr-runtime.version>
<micrometer.version>1.10.0</micrometer.version> <micrometer.version>1.10.0</micrometer.version>
<!-- see https://github.com/apache/spark/blob/cde8e4a82e20a363861f451ebd5138efb3194ab8/pom.xml --> <!-- see https://github.com/apache/spark/blob/cde8e4a82e20a363861f451ebd5138efb3194ab8/pom.xml -->
<hadoop.version>3.4.0</hadoop.version> <hadoop.version>3.4.0</hadoop.version>
<jakarta-servlet.version>5.0.0</jakarta-servlet.version> <jakarta-servlet.version>5.0.0</jakarta-servlet.version>
<sonar.coverage.jacoco.xmlReportPaths>./report/target/site/jacoco-aggregate/jacoco.xml <sonar.coverage.jacoco.xmlReportPaths>
./report/target/site/jacoco-aggregate/jacoco.xml
</sonar.coverage.jacoco.xmlReportPaths> </sonar.coverage.jacoco.xmlReportPaths>
<CodeCacheSize>128m</CodeCacheSize>
<extraJavaTestArgs>
-XX:+IgnoreUnrecognizedVMOptions
--add-modules=jdk.incubator.vector
--add-opens=java.base/java.lang=ALL-UNNAMED
--add-opens=java.base/java.lang.invoke=ALL-UNNAMED
--add-opens=java.base/java.lang.reflect=ALL-UNNAMED
--add-opens=java.base/java.io=ALL-UNNAMED
--add-opens=java.base/java.net=ALL-UNNAMED
--add-opens=java.base/java.nio=ALL-UNNAMED
--add-opens=java.base/java.util=ALL-UNNAMED
--add-opens=java.base/java.util.concurrent=ALL-UNNAMED
--add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED
--add-opens=java.base/jdk.internal.ref=ALL-UNNAMED
--add-opens=java.base/sun.nio.ch=ALL-UNNAMED
--add-opens=java.base/sun.nio.cs=ALL-UNNAMED
--add-opens=java.base/sun.security.action=ALL-UNNAMED
--add-opens=java.base/sun.util.calendar=ALL-UNNAMED
-Djdk.reflect.useDirectMethodHandle=false
-Dio.netty.tryReflectionSetAccessible=true
</extraJavaTestArgs>
</properties> </properties>
<dependencies> <dependencies>
...@@ -208,6 +236,22 @@ ...@@ -208,6 +236,22 @@
<artifactId>commons-validator</artifactId> <artifactId>commons-validator</artifactId>
<version>${commons-validator.version}</version> <version>${commons-validator.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.jooq</groupId>
<artifactId>jooq</artifactId>
<version>${jooq.version}</version>
</dependency>
<!-- Authentication -->
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-common</artifactId>
<version>${keycloak.version}</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-admin-client</artifactId>
<version>${keycloak.version}</version>
</dependency>
<dependency> <dependency>
<groupId>com.fasterxml.jackson.datatype</groupId> <groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-hibernate6</artifactId> <artifactId>jackson-datatype-hibernate6</artifactId>
...@@ -323,7 +367,26 @@ ...@@ -323,7 +367,26 @@
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
<!-- Surefire runs all Java tests -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<!-- Note config is repeated in scalatest config -->
<configuration>
<argLine>@{argLine} -ea -Xmx4g -Xss4m -XX:MaxMetaspaceSize=2g -XX:ReservedCodeCacheSize=${CodeCacheSize}
${extraJavaTestArgs}
</argLine>
</configuration>
</plugin>
</plugins> </plugins>
</build> </build>
<licenses>
<license>
<name>Apache-2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.html</url>
<distribution>repo</distribution>
</license>
</licenses>
</project> </project>
...@@ -6,12 +6,12 @@ ...@@ -6,12 +6,12 @@
<parent> <parent>
<groupId>at.tuwien</groupId> <groupId>at.tuwien</groupId>
<artifactId>dbrepo-data-service</artifactId> <artifactId>dbrepo-data-service</artifactId>
<version>1.6.5</version> <version>1.7.0</version>
</parent> </parent>
<artifactId>dbrepo-data-service-querystore</artifactId> <artifactId>dbrepo-data-service-querystore</artifactId>
<name>dbrepo-data-service-querystore</name> <name>dbrepo-data-service-querystore</name>
<version>1.6.5</version> <version>1.7.0</version>
<dependencies/> <dependencies/>
......
...@@ -6,12 +6,12 @@ ...@@ -6,12 +6,12 @@
<parent> <parent>
<groupId>at.tuwien</groupId> <groupId>at.tuwien</groupId>
<artifactId>dbrepo-data-service</artifactId> <artifactId>dbrepo-data-service</artifactId>
<version>1.6.5</version> <version>1.7.0</version>
</parent> </parent>
<artifactId>report</artifactId> <artifactId>report</artifactId>
<name>dbrepo-data-service-report</name> <name>dbrepo-data-service-report</name>
<version>1.6.5</version> <version>1.7.0</version>
<description> <description>
This module is only intended for the pipeline coverage report. See the detailed report in the This module is only intended for the pipeline coverage report. See the detailed report in the
respective modules respective modules
......
...@@ -6,18 +6,18 @@ ...@@ -6,18 +6,18 @@
<parent> <parent>
<groupId>at.tuwien</groupId> <groupId>at.tuwien</groupId>
<artifactId>dbrepo-data-service</artifactId> <artifactId>dbrepo-data-service</artifactId>
<version>1.6.5</version> <version>1.7.0</version>
</parent> </parent>
<artifactId>rest-service</artifactId> <artifactId>rest-service</artifactId>
<name>dbrepo-data-service-rest-service</name> <name>dbrepo-data-service-rest-service</name>
<version>1.6.5</version> <version>1.7.0</version>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>at.tuwien</groupId> <groupId>at.tuwien</groupId>
<artifactId>services</artifactId> <artifactId>services</artifactId>
<version>1.6.5</version> <version>1.7.0</version>
</dependency> </dependency>
</dependencies> </dependencies>
......
...@@ -6,7 +6,7 @@ import at.tuwien.api.error.ApiErrorDto; ...@@ -6,7 +6,7 @@ import at.tuwien.api.error.ApiErrorDto;
import at.tuwien.api.user.UserDto; import at.tuwien.api.user.UserDto;
import at.tuwien.exception.*; import at.tuwien.exception.*;
import at.tuwien.service.AccessService; import at.tuwien.service.AccessService;
import at.tuwien.service.CredentialService; import at.tuwien.service.CacheService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
...@@ -31,13 +31,13 @@ import java.util.UUID; ...@@ -31,13 +31,13 @@ import java.util.UUID;
@RequestMapping(path = "/api/database/{databaseId}/access") @RequestMapping(path = "/api/database/{databaseId}/access")
public class AccessEndpoint extends RestEndpoint { public class AccessEndpoint extends RestEndpoint {
private final CacheService cacheService;
private final AccessService accessService; private final AccessService accessService;
private final CredentialService credentialService;
@Autowired @Autowired
public AccessEndpoint(AccessService accessService, CredentialService credentialService) { public AccessEndpoint(CacheService cacheService, AccessService accessService) {
this.cacheService = cacheService;
this.accessService = accessService; this.accessService = accessService;
this.credentialService = credentialService;
} }
@PostMapping("/{userId}") @PostMapping("/{userId}")
...@@ -74,14 +74,14 @@ public class AccessEndpoint extends RestEndpoint { ...@@ -74,14 +74,14 @@ public class AccessEndpoint extends RestEndpoint {
mediaType = "application/json", mediaType = "application/json",
schema = @Schema(implementation = ApiErrorDto.class))}), schema = @Schema(implementation = ApiErrorDto.class))}),
}) })
public ResponseEntity<Void> create(@NotNull @PathVariable("databaseId") Long databaseId, public ResponseEntity<Void> create(@NotNull @PathVariable("databaseId") UUID databaseId,
@PathVariable("userId") UUID userId, @PathVariable("userId") UUID userId,
@Valid @RequestBody CreateAccessDto data) @Valid @RequestBody CreateAccessDto data)
throws NotAllowedException, DatabaseUnavailableException, DatabaseNotFoundException, throws NotAllowedException, DatabaseUnavailableException, DatabaseNotFoundException,
RemoteUnavailableException, UserNotFoundException, DatabaseMalformedException, MetadataServiceException { RemoteUnavailableException, UserNotFoundException, DatabaseMalformedException, MetadataServiceException {
log.debug("endpoint give access to database, databaseId={}, userId={}", databaseId, userId); log.debug("endpoint give access to database, databaseId={}, userId={}", databaseId, userId);
final DatabaseDto database = credentialService.getDatabase(databaseId); final DatabaseDto database = cacheService.getDatabase(databaseId);
final UserDto user = credentialService.getUser(userId); final UserDto user = cacheService.getUser(userId);
if (database.getAccesses().stream().anyMatch(a -> a.getUser().getId().equals(userId))) { if (database.getAccesses().stream().anyMatch(a -> a.getUser().getId().equals(userId))) {
log.error("Failed to create access to user with id {}: already has access", userId); log.error("Failed to create access to user with id {}: already has access", userId);
throw new NotAllowedException("Failed to create access to user with id " + userId + ": already has access"); throw new NotAllowedException("Failed to create access to user with id " + userId + ": already has access");
...@@ -130,15 +130,15 @@ public class AccessEndpoint extends RestEndpoint { ...@@ -130,15 +130,15 @@ public class AccessEndpoint extends RestEndpoint {
mediaType = "application/json", mediaType = "application/json",
schema = @Schema(implementation = ApiErrorDto.class))}), schema = @Schema(implementation = ApiErrorDto.class))}),
}) })
public ResponseEntity<Void> update(@NotNull @PathVariable("databaseId") Long databaseId, public ResponseEntity<Void> update(@NotNull @PathVariable("databaseId") UUID databaseId,
@PathVariable("userId") UUID userId, @PathVariable("userId") UUID userId,
@Valid @RequestBody CreateAccessDto access) throws NotAllowedException, @Valid @RequestBody CreateAccessDto access) throws NotAllowedException,
DatabaseUnavailableException, DatabaseNotFoundException, RemoteUnavailableException, UserNotFoundException, DatabaseUnavailableException, DatabaseNotFoundException, RemoteUnavailableException, UserNotFoundException,
DatabaseMalformedException, MetadataServiceException { DatabaseMalformedException, MetadataServiceException {
log.debug("endpoint modify access to database, databaseId={}, userId={}, access.type={}", databaseId, userId, log.debug("endpoint modify access to database, databaseId={}, userId={}, access.type={}", databaseId, userId,
access.getType()); access.getType());
final DatabaseDto database = credentialService.getDatabase(databaseId); final DatabaseDto database = cacheService.getDatabase(databaseId);
final UserDto user = credentialService.getUser(userId); final UserDto user = cacheService.getUser(userId);
if (database.getAccesses().stream().noneMatch(a -> a.getHuserid().equals(userId))) { if (database.getAccesses().stream().noneMatch(a -> a.getHuserid().equals(userId))) {
log.error("Failed to update access to user with id {}: no access", userId); log.error("Failed to update access to user with id {}: no access", userId);
throw new NotAllowedException("Failed to update access to user with id " + userId + ": no access"); throw new NotAllowedException("Failed to update access to user with id " + userId + ": no access");
...@@ -153,22 +153,6 @@ public class AccessEndpoint extends RestEndpoint { ...@@ -153,22 +153,6 @@ public class AccessEndpoint extends RestEndpoint {
} }
} }
@PutMapping
@PreAuthorize("hasAuthority('system')")
@Operation(summary = "Invalidate access cache for database",
security = {@SecurityRequirement(name = "basicAuth")},
hidden = true)
@ApiResponses(value = {
@ApiResponse(responseCode = "202",
description = "Invalidated access cache succeeded")
})
public ResponseEntity<Void> invalidateAccess(@NotNull @PathVariable("databaseId") Long databaseId) {
log.debug("endpoint empty access cache for database, databaseId={}", databaseId);
credentialService.invalidateAccess(databaseId);
return ResponseEntity.accepted()
.build();
}
@DeleteMapping("/{userId}") @DeleteMapping("/{userId}")
@PreAuthorize("hasAuthority('system')") @PreAuthorize("hasAuthority('system')")
@Operation(summary = "Revoke access", @Operation(summary = "Revoke access",
...@@ -203,13 +187,13 @@ public class AccessEndpoint extends RestEndpoint { ...@@ -203,13 +187,13 @@ public class AccessEndpoint extends RestEndpoint {
mediaType = "application/json", mediaType = "application/json",
schema = @Schema(implementation = ApiErrorDto.class))}), schema = @Schema(implementation = ApiErrorDto.class))}),
}) })
public ResponseEntity<Void> revoke(@NotNull @PathVariable("databaseId") Long databaseId, public ResponseEntity<Void> revoke(@NotNull @PathVariable("databaseId") UUID databaseId,
@PathVariable("userId") UUID userId) throws NotAllowedException, @PathVariable("userId") UUID userId) throws NotAllowedException,
DatabaseUnavailableException, DatabaseNotFoundException, RemoteUnavailableException, UserNotFoundException, DatabaseUnavailableException, DatabaseNotFoundException, RemoteUnavailableException, UserNotFoundException,
DatabaseMalformedException, MetadataServiceException { DatabaseMalformedException, MetadataServiceException {
log.debug("endpoint revoke access to database, databaseId={}, userId={}", databaseId, userId); log.debug("endpoint revoke access to database, databaseId={}, userId={}", databaseId, userId);
final DatabaseDto database = credentialService.getDatabase(databaseId); final DatabaseDto database = cacheService.getDatabase(databaseId);
final UserDto user = credentialService.getUser(userId); final UserDto user = cacheService.getUser(userId);
if (database.getAccesses().stream().noneMatch(a -> a.getUser().getId().equals(userId))) { if (database.getAccesses().stream().noneMatch(a -> a.getUser().getId().equals(userId))) {
log.error("Failed to delete access to user with id {}: no access", userId); log.error("Failed to delete access to user with id {}: no access", userId);
throw new NotAllowedException("Failed to delete access to user with id " + userId + ": no access"); throw new NotAllowedException("Failed to delete access to user with id " + userId + ": no access");
......
...@@ -10,7 +10,7 @@ import at.tuwien.api.user.internal.UpdateUserPasswordDto; ...@@ -10,7 +10,7 @@ import at.tuwien.api.user.internal.UpdateUserPasswordDto;
import at.tuwien.exception.*; import at.tuwien.exception.*;
import at.tuwien.service.AccessService; import at.tuwien.service.AccessService;
import at.tuwien.service.ContainerService; import at.tuwien.service.ContainerService;
import at.tuwien.service.CredentialService; import at.tuwien.service.CacheService;
import at.tuwien.service.DatabaseService; import at.tuwien.service.DatabaseService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Content;
...@@ -28,6 +28,7 @@ import org.springframework.security.access.prepost.PreAuthorize; ...@@ -28,6 +28,7 @@ import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.UUID;
@Log4j2 @Log4j2
@RestController @RestController
...@@ -35,18 +36,18 @@ import java.sql.SQLException; ...@@ -35,18 +36,18 @@ import java.sql.SQLException;
@RequestMapping(path = "/api/database") @RequestMapping(path = "/api/database")
public class DatabaseEndpoint extends RestEndpoint { public class DatabaseEndpoint extends RestEndpoint {
private final CacheService cacheService;
private final AccessService accessService; private final AccessService accessService;
private final DatabaseService databaseService; private final DatabaseService databaseService;
private final ContainerService containerService; private final ContainerService containerService;
private final CredentialService credentialService;
@Autowired @Autowired
public DatabaseEndpoint(AccessService accessService, DatabaseService databaseService, public DatabaseEndpoint(CacheService cacheService, AccessService accessService, DatabaseService databaseService,
ContainerService containerService, CredentialService credentialService) { ContainerService containerService) {
this.cacheService = cacheService;
this.accessService = accessService; this.accessService = accessService;
this.databaseService = databaseService; this.databaseService = databaseService;
this.containerService = containerService; this.containerService = containerService;
this.credentialService = credentialService;
} }
@PostMapping @PostMapping
...@@ -86,7 +87,7 @@ public class DatabaseEndpoint extends RestEndpoint { ...@@ -86,7 +87,7 @@ public class DatabaseEndpoint extends RestEndpoint {
DatabaseMalformedException, QueryStoreCreateException, MetadataServiceException { DatabaseMalformedException, QueryStoreCreateException, MetadataServiceException {
log.debug("endpoint create database, data.containerId={}, data.internalName={}, data.username={}", log.debug("endpoint create database, data.containerId={}, data.internalName={}, data.username={}",
data.getContainerId(), data.getInternalName(), data.getUsername()); data.getContainerId(), data.getInternalName(), data.getUsername());
final ContainerDto container = credentialService.getContainer(data.getContainerId()); final ContainerDto container = cacheService.getContainer(data.getContainerId());
try { try {
final DatabaseDto database = containerService.createDatabase(container, data); final DatabaseDto database = containerService.createDatabase(container, data);
containerService.createQueryStore(container, data.getInternalName()); containerService.createQueryStore(container, data.getInternalName());
...@@ -128,13 +129,13 @@ public class DatabaseEndpoint extends RestEndpoint { ...@@ -128,13 +129,13 @@ public class DatabaseEndpoint extends RestEndpoint {
mediaType = "application/json", mediaType = "application/json",
schema = @Schema(implementation = ApiErrorDto.class))}), schema = @Schema(implementation = ApiErrorDto.class))}),
}) })
public ResponseEntity<Void> update(@NotNull @PathVariable("databaseId") Long databaseId, public ResponseEntity<Void> update(@NotNull @PathVariable("databaseId") UUID databaseId,
@Valid @RequestBody UpdateUserPasswordDto data) @Valid @RequestBody UpdateUserPasswordDto data)
throws DatabaseUnavailableException, DatabaseNotFoundException, RemoteUnavailableException, throws DatabaseUnavailableException, DatabaseNotFoundException, RemoteUnavailableException,
DatabaseMalformedException, MetadataServiceException { DatabaseMalformedException, MetadataServiceException {
log.debug("endpoint update user password in database, databaseId={}, data.username={}", databaseId, log.debug("endpoint update user password in database, databaseId={}, data.username={}", databaseId,
data.getUsername()); data.getUsername());
final DatabaseDto database = credentialService.getDatabase(databaseId); final DatabaseDto database = cacheService.getDatabase(databaseId);
try { try {
databaseService.update(database, data); databaseService.update(database, data);
return ResponseEntity.status(HttpStatus.ACCEPTED) return ResponseEntity.status(HttpStatus.ACCEPTED)
......
package at.tuwien.endpoints; package at.tuwien.endpoints;
import at.tuwien.ExportResourceDto; import at.tuwien.ExportResourceDto;
import at.tuwien.api.database.CreateViewDto;
import at.tuwien.api.database.DatabaseDto; import at.tuwien.api.database.DatabaseDto;
import at.tuwien.api.database.ViewColumnDto; import at.tuwien.api.database.ViewColumnDto;
import at.tuwien.api.database.ViewDto; import at.tuwien.api.database.ViewDto;
import at.tuwien.api.database.query.ExecuteStatementDto;
import at.tuwien.api.database.query.QueryDto; import at.tuwien.api.database.query.QueryDto;
import at.tuwien.api.database.query.QueryPersistDto; import at.tuwien.api.database.query.QueryPersistDto;
import at.tuwien.api.database.query.SubsetDto;
import at.tuwien.api.error.ApiErrorDto; import at.tuwien.api.error.ApiErrorDto;
import at.tuwien.exception.*; import at.tuwien.exception.*;
import at.tuwien.gateway.MetadataServiceGateway;
import at.tuwien.mapper.MariaDbMapper; import at.tuwien.mapper.MariaDbMapper;
import at.tuwien.mapper.MetadataMapper; import at.tuwien.mapper.MetadataMapper;
import at.tuwien.service.*; import at.tuwien.service.CacheService;
import at.tuwien.service.DatabaseService;
import at.tuwien.service.StorageService;
import at.tuwien.service.SubsetService;
import at.tuwien.validation.EndpointValidator; import at.tuwien.validation.EndpointValidator;
import io.micrometer.observation.annotation.Observed; import io.micrometer.observation.annotation.Observed;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
...@@ -50,27 +53,27 @@ import java.util.UUID; ...@@ -50,27 +53,27 @@ import java.util.UUID;
@RequestMapping(path = "/api/database/{databaseId}/subset") @RequestMapping(path = "/api/database/{databaseId}/subset")
public class SubsetEndpoint extends RestEndpoint { public class SubsetEndpoint extends RestEndpoint {
private final CacheService cacheService;
private final MariaDbMapper mariaDbMapper; private final MariaDbMapper mariaDbMapper;
private final SubsetService subsetService; private final SubsetService subsetService;
private final MetadataMapper metadataMapper; private final MetadataMapper metadataMapper;
private final MetricsService metricsService;
private final StorageService storageService; private final StorageService storageService;
private final DatabaseService databaseService; private final DatabaseService databaseService;
private final CredentialService credentialService;
private final EndpointValidator endpointValidator; private final EndpointValidator endpointValidator;
private final MetadataServiceGateway metadataServiceGateway;
@Autowired @Autowired
public SubsetEndpoint(MariaDbMapper mariaDbMapper, SubsetService subsetService, MetadataMapper metadataMapper, public SubsetEndpoint(CacheService cacheService, MariaDbMapper mariaDbMapper, SubsetService subsetService,
MetricsService metricsService, StorageService storageService, DatabaseService databaseService, MetadataMapper metadataMapper, StorageService storageService, DatabaseService databaseService,
CredentialService credentialService, EndpointValidator endpointValidator) { EndpointValidator endpointValidator, MetadataServiceGateway metadataServiceGateway) {
this.cacheService = cacheService;
this.mariaDbMapper = mariaDbMapper; this.mariaDbMapper = mariaDbMapper;
this.subsetService = subsetService; this.subsetService = subsetService;
this.metadataMapper = metadataMapper; this.metadataMapper = metadataMapper;
this.metricsService = metricsService;
this.storageService = storageService; this.storageService = storageService;
this.databaseService = databaseService; this.databaseService = databaseService;
this.credentialService = credentialService;
this.endpointValidator = endpointValidator; this.endpointValidator = endpointValidator;
this.metadataServiceGateway = metadataServiceGateway;
} }
@GetMapping @GetMapping
...@@ -100,13 +103,13 @@ public class SubsetEndpoint extends RestEndpoint { ...@@ -100,13 +103,13 @@ public class SubsetEndpoint extends RestEndpoint {
mediaType = "application/json", mediaType = "application/json",
schema = @Schema(implementation = ApiErrorDto.class))}), schema = @Schema(implementation = ApiErrorDto.class))}),
}) })
public ResponseEntity<List<QueryDto>> list(@NotNull @PathVariable("databaseId") Long databaseId, public ResponseEntity<List<QueryDto>> list(@NotNull @PathVariable("databaseId") UUID databaseId,
@RequestParam(name = "persisted", required = false) Boolean filterPersisted, @RequestParam(name = "persisted", required = false) Boolean filterPersisted,
Principal principal) Principal principal)
throws DatabaseUnavailableException, DatabaseNotFoundException, RemoteUnavailableException, throws DatabaseUnavailableException, DatabaseNotFoundException, RemoteUnavailableException,
QueryNotFoundException, NotAllowedException, MetadataServiceException { QueryNotFoundException, NotAllowedException, MetadataServiceException {
log.debug("endpoint find subsets in database, databaseId={}, filterPersisted={}", databaseId, filterPersisted); log.debug("endpoint find subsets in database, databaseId={}, filterPersisted={}", databaseId, filterPersisted);
final DatabaseDto database = credentialService.getDatabase(databaseId); final DatabaseDto database = cacheService.getDatabase(databaseId);
endpointValidator.validateOnlyPrivateSchemaAccess(database, principal); endpointValidator.validateOnlyPrivateSchemaAccess(database, principal);
final List<QueryDto> queries; final List<QueryDto> queries;
try { try {
...@@ -157,8 +160,8 @@ public class SubsetEndpoint extends RestEndpoint { ...@@ -157,8 +160,8 @@ public class SubsetEndpoint extends RestEndpoint {
mediaType = "application/json", mediaType = "application/json",
schema = @Schema(implementation = ApiErrorDto.class))}), schema = @Schema(implementation = ApiErrorDto.class))}),
}) })
public ResponseEntity<?> findById(@NotNull @PathVariable("databaseId") Long databaseId, public ResponseEntity<?> findById(@NotNull @PathVariable("databaseId") UUID databaseId,
@NotNull @PathVariable("subsetId") Long subsetId, @NotNull @PathVariable("subsetId") UUID subsetId,
@NotNull @RequestHeader("Accept") String accept, @NotNull @RequestHeader("Accept") String accept,
@RequestParam(required = false) Instant timestamp, @RequestParam(required = false) Instant timestamp,
Principal principal) Principal principal)
...@@ -167,7 +170,7 @@ public class SubsetEndpoint extends RestEndpoint { ...@@ -167,7 +170,7 @@ public class SubsetEndpoint extends RestEndpoint {
MetadataServiceException, TableNotFoundException, QueryMalformedException, NotAllowedException { MetadataServiceException, TableNotFoundException, QueryMalformedException, NotAllowedException {
log.debug("endpoint find subset in database, databaseId={}, subsetId={}, accept={}, timestamp={}", databaseId, log.debug("endpoint find subset in database, databaseId={}, subsetId={}, accept={}, timestamp={}", databaseId,
subsetId, accept, timestamp); subsetId, accept, timestamp);
final DatabaseDto database = credentialService.getDatabase(databaseId); final DatabaseDto database = cacheService.getDatabase(databaseId);
endpointValidator.validateOnlyPrivateSchemaAccess(database, principal); endpointValidator.validateOnlyPrivateSchemaAccess(database, principal);
final QueryDto subset; final QueryDto subset;
try { try {
...@@ -181,7 +184,7 @@ public class SubsetEndpoint extends RestEndpoint { ...@@ -181,7 +184,7 @@ public class SubsetEndpoint extends RestEndpoint {
timestamp = Instant.now(); timestamp = Instant.now();
log.debug("timestamp not set: default to {}", timestamp); log.debug("timestamp not set: default to {}", timestamp);
} }
if (accept == null || accept.isEmpty() || accept.isBlank()) { if (accept == null || accept.isBlank()) {
accept = MediaType.APPLICATION_JSON_VALUE; accept = MediaType.APPLICATION_JSON_VALUE;
log.debug("accept header not set: default to {}", accept); log.debug("accept header not set: default to {}", accept);
} }
...@@ -192,8 +195,7 @@ public class SubsetEndpoint extends RestEndpoint { ...@@ -192,8 +195,7 @@ public class SubsetEndpoint extends RestEndpoint {
case "text/csv": case "text/csv":
log.trace("accept header matches csv"); log.trace("accept header matches csv");
final String query = mariaDbMapper.rawSelectQuery(subset.getQuery(), timestamp, null, null); final String query = mariaDbMapper.rawSelectQuery(subset.getQuery(), timestamp, null, null);
final Dataset<Row> dataset = subsetService.getData(database, query, timestamp, null, null, null, null); final Dataset<Row> dataset = subsetService.getData(database, query);
metricsService.countSubsetGetData(databaseId, subsetId);
final ExportResourceDto resource = storageService.transformDataset(dataset); final ExportResourceDto resource = storageService.transformDataset(dataset);
final HttpHeaders headers = new HttpHeaders(); final HttpHeaders headers = new HttpHeaders();
headers.add("Content-Disposition", "attachment; filename=\"" + resource.getFilename() + "\""); headers.add("Content-Disposition", "attachment; filename=\"" + resource.getFilename() + "\"");
...@@ -247,8 +249,8 @@ public class SubsetEndpoint extends RestEndpoint { ...@@ -247,8 +249,8 @@ public class SubsetEndpoint extends RestEndpoint {
mediaType = "application/json", mediaType = "application/json",
schema = @Schema(implementation = ApiErrorDto.class))}), schema = @Schema(implementation = ApiErrorDto.class))}),
}) })
public ResponseEntity<List<Map<String, Object>>> create(@NotNull @PathVariable("databaseId") Long databaseId, public ResponseEntity<List<Map<String, Object>>> create(@NotNull @PathVariable("databaseId") UUID databaseId,
@Valid @RequestBody ExecuteStatementDto data, @Valid @RequestBody SubsetDto data,
Principal principal, Principal principal,
@NotNull HttpServletRequest request, @NotNull HttpServletRequest request,
@RequestParam(required = false) Instant timestamp, @RequestParam(required = false) Instant timestamp,
...@@ -258,13 +260,12 @@ public class SubsetEndpoint extends RestEndpoint { ...@@ -258,13 +260,12 @@ public class SubsetEndpoint extends RestEndpoint {
QueryNotFoundException, StorageUnavailableException, QueryMalformedException, StorageNotFoundException, QueryNotFoundException, StorageUnavailableException, QueryMalformedException, StorageNotFoundException,
QueryStoreInsertException, TableMalformedException, PaginationException, QueryNotSupportedException, QueryStoreInsertException, TableMalformedException, PaginationException, QueryNotSupportedException,
NotAllowedException, UserNotFoundException, MetadataServiceException, TableNotFoundException, NotAllowedException, UserNotFoundException, MetadataServiceException, TableNotFoundException,
ViewMalformedException, ViewNotFoundException { ViewMalformedException, ViewNotFoundException, ImageNotFoundException {
log.debug("endpoint create subset in database, databaseId={}, data.statement={}, page={}, size={}, " + log.debug("endpoint create subset in database, databaseId={}, page={}, size={}, timestamp={}", databaseId,
"timestamp={}", databaseId, data.getStatement(), page, size, page, size, timestamp);
timestamp);
/* check */ /* check */
endpointValidator.validateDataParams(page, size); endpointValidator.validateDataParams(page, size);
endpointValidator.validateForbiddenStatements(data.getStatement()); endpointValidator.validateSubsetParams(data);
/* parameters */ /* parameters */
final UUID userId; final UUID userId;
if (principal != null) { if (principal != null) {
...@@ -285,10 +286,10 @@ public class SubsetEndpoint extends RestEndpoint { ...@@ -285,10 +286,10 @@ public class SubsetEndpoint extends RestEndpoint {
log.debug("timestamp not set: default to {}", timestamp); log.debug("timestamp not set: default to {}", timestamp);
} }
/* create */ /* create */
final DatabaseDto database = credentialService.getDatabase(databaseId); final DatabaseDto database = cacheService.getDatabase(databaseId);
endpointValidator.validateOnlyPrivateSchemaAccess(database, principal); endpointValidator.validateOnlyPrivateSchemaAccess(database, principal);
try { try {
final Long subsetId = subsetService.create(database, data.getStatement(), timestamp, userId); final UUID subsetId = subsetService.create(database, data, timestamp, userId);
return getData(databaseId, subsetId, principal, request, timestamp, page, size); return getData(databaseId, subsetId, principal, request, timestamp, page, size);
} catch (SQLException e) { } catch (SQLException e) {
log.error("Failed to establish connection to database: {}", e.getMessage()); log.error("Failed to establish connection to database: {}", e.getMessage());
...@@ -304,9 +305,9 @@ public class SubsetEndpoint extends RestEndpoint { ...@@ -304,9 +305,9 @@ public class SubsetEndpoint extends RestEndpoint {
@ApiResponses(value = { @ApiResponses(value = {
@ApiResponse(responseCode = "200", @ApiResponse(responseCode = "200",
description = "Retrieved subset data", description = "Retrieved subset data",
headers = {@Header(name = "X-Count", description = "Number of rows", schema = @Schema(implementation = Long.class)), headers = {@Header(name = "X-Count", description = "Number of rows", schema = @Schema(implementation = UUID.class)),
@Header(name = "X-Headers", description = "The list of headers separated by comma", schema = @Schema(implementation = String.class)), @Header(name = "X-Headers", description = "The list of headers separated by comma", schema = @Schema(implementation = String.class)),
@Header(name = "X-Id", description = "The subset id", schema = @Schema(implementation = Long.class), required = true), @Header(name = "X-Id", description = "The subset id", schema = @Schema(implementation = UUID.class), required = true),
@Header(name = "Access-Control-Expose-Headers", description = "Reverse proxy exposing of custom headers", schema = @Schema(implementation = String.class), required = true)}, @Header(name = "Access-Control-Expose-Headers", description = "Reverse proxy exposing of custom headers", schema = @Schema(implementation = String.class), required = true)},
content = {@Content( content = {@Content(
mediaType = "application/json", mediaType = "application/json",
...@@ -332,26 +333,26 @@ public class SubsetEndpoint extends RestEndpoint { ...@@ -332,26 +333,26 @@ public class SubsetEndpoint extends RestEndpoint {
mediaType = "application/json", mediaType = "application/json",
schema = @Schema(implementation = ApiErrorDto.class))}), schema = @Schema(implementation = ApiErrorDto.class))}),
}) })
public ResponseEntity<List<Map<String, Object>>> getData(@NotNull @PathVariable("databaseId") Long databaseId, public ResponseEntity<List<Map<String, Object>>> getData(@NotNull @PathVariable("databaseId") UUID databaseId,
@NotNull @PathVariable("subsetId") Long subsetId, @NotNull @PathVariable("subsetId") UUID subsetId,
Principal principal, Principal principal,
@NotNull HttpServletRequest request, @NotNull HttpServletRequest request,
@RequestParam(required = false) Instant timestamp, @RequestParam(required = false) Instant timestamp,
@RequestParam(required = false) Long page, @RequestParam(required = false) Long page,
@RequestParam(required = false) Long size) @RequestParam(required = false) Long size)
throws PaginationException, DatabaseNotFoundException, RemoteUnavailableException, NotAllowedException, throws PaginationException, DatabaseNotFoundException, RemoteUnavailableException, NotAllowedException,
QueryNotFoundException, DatabaseUnavailableException, TableMalformedException, QueryMalformedException, QueryNotFoundException, DatabaseUnavailableException, QueryMalformedException, UserNotFoundException,
UserNotFoundException, MetadataServiceException, TableNotFoundException, ViewNotFoundException, ViewMalformedException { MetadataServiceException, TableNotFoundException, ViewNotFoundException, ViewMalformedException {
log.debug("endpoint get subset data, databaseId={}, subsetId={}, principal.name={} page={}, size={}", log.debug("endpoint get subset data, databaseId={}, subsetId={}, principal.name={} page={}, size={}",
databaseId, subsetId, principal != null ? principal.getName() : null, page, size); databaseId, subsetId, principal != null ? principal.getName() : null, page, size);
endpointValidator.validateDataParams(page, size); endpointValidator.validateDataParams(page, size);
final DatabaseDto database = credentialService.getDatabase(databaseId); final DatabaseDto database = cacheService.getDatabase(databaseId);
if (!database.getIsPublic()) { if (!database.getIsPublic()) {
if (principal == null) { if (principal == null) {
log.error("Failed to re-execute query: no authentication found"); log.error("Failed to re-execute query: no authentication found");
throw new NotAllowedException("Failed to re-execute query: no authentication found"); throw new NotAllowedException("Failed to re-execute query: no authentication found");
} }
credentialService.getAccess(databaseId, getId(principal)); cacheService.getAccess(databaseId, getId(principal));
} }
log.trace("visibility for database: is_public={}, is_schema_public={}", database.getIsPublic(), database.getIsSchemaPublic()); log.trace("visibility for database: is_public={}, is_schema_public={}", database.getIsPublic(), database.getIsSchemaPublic());
/* parameters */ /* parameters */
...@@ -379,16 +380,11 @@ public class SubsetEndpoint extends RestEndpoint { ...@@ -379,16 +380,11 @@ public class SubsetEndpoint extends RestEndpoint {
.headers(headers) .headers(headers)
.build(); .build();
} }
subset.setIdentifiers(metadataServiceGateway.getIdentifiers(database.getId(), subset.getId()));
final String query = mariaDbMapper.rawSelectQuery(subset.getQuery(), timestamp, page, size); final String query = mariaDbMapper.rawSelectQuery(subset.getQuery(), timestamp, page, size);
final Dataset<Row> dataset = subsetService.getData(database, query, timestamp, page, size, null, null); final Dataset<Row> dataset = subsetService.getData(database, query);
metricsService.countSubsetGetData(databaseId, subsetId);
final String viewName = metadataMapper.queryDtoToViewName(subset); final String viewName = metadataMapper.queryDtoToViewName(subset);
databaseService.createView(database, CreateViewDto.builder() databaseService.createView(database, viewName, subset.getQuery());
.name(viewName)
.isPublic(false)
.isSchemaPublic(false)
.query(query)
.build());
final ViewDto view = databaseService.inspectView(database, viewName); final ViewDto view = databaseService.inspectView(database, viewName);
headers.set("Access-Control-Expose-Headers", "X-Id X-Headers"); headers.set("Access-Control-Expose-Headers", "X-Id X-Headers");
headers.set("X-Headers", String.join(",", view.getColumns().stream().map(ViewColumnDto::getInternalName).toList())); headers.set("X-Headers", String.join(",", view.getColumns().stream().map(ViewColumnDto::getInternalName).toList()));
...@@ -439,16 +435,16 @@ public class SubsetEndpoint extends RestEndpoint { ...@@ -439,16 +435,16 @@ public class SubsetEndpoint extends RestEndpoint {
mediaType = "application/json", mediaType = "application/json",
schema = @Schema(implementation = ApiErrorDto.class))}), schema = @Schema(implementation = ApiErrorDto.class))}),
}) })
public ResponseEntity<QueryDto> persist(@NotNull @PathVariable("databaseId") Long databaseId, public ResponseEntity<QueryDto> persist(@NotNull @PathVariable("databaseId") UUID databaseId,
@NotNull @PathVariable("queryId") Long queryId, @NotNull @PathVariable("queryId") UUID queryId,
@NotNull @Valid @RequestBody QueryPersistDto data, @NotNull @Valid @RequestBody QueryPersistDto data,
@NotNull Principal principal) throws NotAllowedException, @NotNull Principal principal) throws NotAllowedException,
RemoteUnavailableException, DatabaseNotFoundException, QueryStorePersistException, RemoteUnavailableException, DatabaseNotFoundException, QueryStorePersistException,
DatabaseUnavailableException, QueryNotFoundException, UserNotFoundException, MetadataServiceException { DatabaseUnavailableException, QueryNotFoundException, UserNotFoundException, MetadataServiceException {
log.debug("endpoint persist query, databaseId={}, queryId={}, data.persist={}, principal.name={}", databaseId, log.debug("endpoint persist query, databaseId={}, queryId={}, data.persist={}, principal.name={}", databaseId,
queryId, data.getPersist(), principal.getName()); queryId, data.getPersist(), principal.getName());
final DatabaseDto database = credentialService.getDatabase(databaseId); final DatabaseDto database = cacheService.getDatabase(databaseId);
credentialService.getAccess(databaseId, getId(principal)); cacheService.getAccess(databaseId, getId(principal));
try { try {
subsetService.persist(database, queryId, data.getPersist()); subsetService.persist(database, queryId, data.getPersist());
final QueryDto dto = subsetService.findById(database, queryId); final QueryDto dto = subsetService.findById(database, queryId);
......
...@@ -41,6 +41,7 @@ import java.sql.SQLException; ...@@ -41,6 +41,7 @@ import java.sql.SQLException;
import java.time.Instant; import java.time.Instant;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID;
@Log4j2 @Log4j2
@RestController @RestController
...@@ -48,28 +49,25 @@ import java.util.Map; ...@@ -48,28 +49,25 @@ import java.util.Map;
@RequestMapping(path = "/api/database/{databaseId}/table") @RequestMapping(path = "/api/database/{databaseId}/table")
public class TableEndpoint extends RestEndpoint { public class TableEndpoint extends RestEndpoint {
private final CacheService cacheService;
private final TableService tableService; private final TableService tableService;
private final MariaDbMapper mariaDbMapper; private final MariaDbMapper mariaDbMapper;
private final SubsetService subsetService; private final SubsetService subsetService;
private final MetricsService metricsService;
private final StorageService storageService; private final StorageService storageService;
private final DatabaseService databaseService; private final DatabaseService databaseService;
private final CredentialService credentialService;
private final EndpointValidator endpointValidator; private final EndpointValidator endpointValidator;
private final MetadataServiceGateway metadataServiceGateway; private final MetadataServiceGateway metadataServiceGateway;
@Autowired @Autowired
public TableEndpoint(TableService tableService, MariaDbMapper mariaDbMapper, SubsetService subsetService, public TableEndpoint(CacheService cacheService, TableService tableService, MariaDbMapper mariaDbMapper,
MetricsService metricsService, StorageService storageService, DatabaseService databaseService, SubsetService subsetService, StorageService storageService, DatabaseService databaseService,
CredentialService credentialService, EndpointValidator endpointValidator, EndpointValidator endpointValidator, MetadataServiceGateway metadataServiceGateway) {
MetadataServiceGateway metadataServiceGateway) { this.cacheService = cacheService;
this.tableService = tableService; this.tableService = tableService;
this.mariaDbMapper = mariaDbMapper; this.mariaDbMapper = mariaDbMapper;
this.subsetService = subsetService; this.subsetService = subsetService;
this.metricsService = metricsService;
this.storageService = storageService; this.storageService = storageService;
this.databaseService = databaseService; this.databaseService = databaseService;
this.credentialService = credentialService;
this.endpointValidator = endpointValidator; this.endpointValidator = endpointValidator;
this.metadataServiceGateway = metadataServiceGateway; this.metadataServiceGateway = metadataServiceGateway;
} }
...@@ -106,7 +104,7 @@ public class TableEndpoint extends RestEndpoint { ...@@ -106,7 +104,7 @@ public class TableEndpoint extends RestEndpoint {
mediaType = "application/json", mediaType = "application/json",
schema = @Schema(implementation = ApiErrorDto.class))}), schema = @Schema(implementation = ApiErrorDto.class))}),
}) })
public ResponseEntity<TableDto> create(@NotNull @PathVariable("databaseId") Long databaseId, public ResponseEntity<TableDto> create(@NotNull @PathVariable("databaseId") UUID databaseId,
@Valid @RequestBody TableCreateDto data) throws DatabaseNotFoundException, @Valid @RequestBody TableCreateDto data) throws DatabaseNotFoundException,
RemoteUnavailableException, TableMalformedException, DatabaseUnavailableException, TableExistsException, RemoteUnavailableException, TableMalformedException, DatabaseUnavailableException, TableExistsException,
TableNotFoundException, QueryMalformedException, MetadataServiceException, ContainerNotFoundException { TableNotFoundException, QueryMalformedException, MetadataServiceException, ContainerNotFoundException {
...@@ -117,7 +115,7 @@ public class TableEndpoint extends RestEndpoint { ...@@ -117,7 +115,7 @@ public class TableEndpoint extends RestEndpoint {
throw new TableMalformedException("Table must have a primary key"); throw new TableMalformedException("Table must have a primary key");
} }
/* create */ /* create */
final DatabaseDto database = credentialService.getDatabase(databaseId); final DatabaseDto database = cacheService.getDatabase(databaseId);
try { try {
final TableDto table = databaseService.createTable(database, data); final TableDto table = databaseService.createTable(database, data);
return ResponseEntity.status(HttpStatus.CREATED) return ResponseEntity.status(HttpStatus.CREATED)
...@@ -155,15 +153,17 @@ public class TableEndpoint extends RestEndpoint { ...@@ -155,15 +153,17 @@ public class TableEndpoint extends RestEndpoint {
mediaType = "application/json", mediaType = "application/json",
schema = @Schema(implementation = ApiErrorDto.class))}), schema = @Schema(implementation = ApiErrorDto.class))}),
}) })
public ResponseEntity<TableDto> update(@NotNull @PathVariable("databaseId") Long databaseId, public ResponseEntity<TableDto> update(@NotNull @PathVariable("databaseId") UUID databaseId,
@NotNull @PathVariable("tableId") Long tableId, @NotNull @PathVariable("tableId") UUID tableId,
@Valid @RequestBody TableUpdateDto data) throws RemoteUnavailableException, @Valid @RequestBody TableUpdateDto data) throws RemoteUnavailableException,
TableMalformedException, DatabaseUnavailableException, TableNotFoundException, MetadataServiceException { TableMalformedException, DatabaseUnavailableException, TableNotFoundException, MetadataServiceException,
DatabaseNotFoundException {
log.debug("endpoint update table, databaseId={}, data.description={}", databaseId, data.getDescription()); log.debug("endpoint update table, databaseId={}, data.description={}", databaseId, data.getDescription());
/* create */ /* create */
final TableDto table = credentialService.getTable(databaseId, tableId); final TableDto table = cacheService.getTable(databaseId, tableId);
final DatabaseDto database = cacheService.getDatabase(databaseId);
try { try {
tableService.updateTable(table, data); tableService.updateTable(database, table, data);
return ResponseEntity.status(HttpStatus.ACCEPTED) return ResponseEntity.status(HttpStatus.ACCEPTED)
.build(); .build();
} catch (SQLException e) { } catch (SQLException e) {
...@@ -199,14 +199,15 @@ public class TableEndpoint extends RestEndpoint { ...@@ -199,14 +199,15 @@ public class TableEndpoint extends RestEndpoint {
mediaType = "application/json", mediaType = "application/json",
schema = @Schema(implementation = ApiErrorDto.class))}), schema = @Schema(implementation = ApiErrorDto.class))}),
}) })
public ResponseEntity<Void> delete(@NotNull @PathVariable("databaseId") Long databaseId, public ResponseEntity<Void> delete(@NotNull @PathVariable("databaseId") UUID databaseId,
@NotNull @PathVariable("tableId") Long tableId) @NotNull @PathVariable("tableId") UUID tableId)
throws DatabaseUnavailableException, RemoteUnavailableException, TableNotFoundException, throws DatabaseUnavailableException, RemoteUnavailableException, TableNotFoundException,
QueryMalformedException, MetadataServiceException { QueryMalformedException, MetadataServiceException, DatabaseNotFoundException {
log.debug("endpoint delete table, databaseId={}, tableId={}", databaseId, tableId); log.debug("endpoint delete table, databaseId={}, tableId={}", databaseId, tableId);
final TableDto table = credentialService.getTable(databaseId, tableId); final TableDto table = cacheService.getTable(databaseId, tableId);
final DatabaseDto database = cacheService.getDatabase(databaseId);
try { try {
tableService.delete(table); tableService.delete(database, table);
return ResponseEntity.status(HttpStatus.ACCEPTED) return ResponseEntity.status(HttpStatus.ACCEPTED)
.build(); .build();
} catch (SQLException e) { } catch (SQLException e) {
...@@ -249,8 +250,8 @@ public class TableEndpoint extends RestEndpoint { ...@@ -249,8 +250,8 @@ public class TableEndpoint extends RestEndpoint {
mediaType = "application/json", mediaType = "application/json",
schema = @Schema(implementation = ApiErrorDto.class))}), schema = @Schema(implementation = ApiErrorDto.class))}),
}) })
public ResponseEntity<List<Map<String, Object>>> getData(@NotNull @PathVariable("databaseId") Long databaseId, public ResponseEntity<List<Map<String, Object>>> getData(@NotNull @PathVariable("databaseId") UUID databaseId,
@NotNull @PathVariable("tableId") Long tableId, @NotNull @PathVariable("tableId") UUID tableId,
@RequestParam(required = false) Instant timestamp, @RequestParam(required = false) Instant timestamp,
@RequestParam(required = false) Long page, @RequestParam(required = false) Long page,
@RequestParam(required = false) Long size, @RequestParam(required = false) Long size,
...@@ -274,30 +275,29 @@ public class TableEndpoint extends RestEndpoint { ...@@ -274,30 +275,29 @@ public class TableEndpoint extends RestEndpoint {
timestamp = Instant.now(); timestamp = Instant.now();
log.debug("timestamp not set: default to {}", timestamp); log.debug("timestamp not set: default to {}", timestamp);
} }
final TableDto table = credentialService.getTable(databaseId, tableId); final TableDto table = cacheService.getTable(databaseId, tableId);
if (!table.getIsPublic()) { if (!table.getIsPublic()) {
if (principal == null) { if (principal == null) {
log.error("Failed find table data: authentication required"); log.error("Failed find table data: authentication required");
throw new NotAllowedException("Failed to find table data: authentication required"); throw new NotAllowedException("Failed to find table data: authentication required");
} }
credentialService.getAccess(databaseId, getId(principal)); cacheService.getAccess(databaseId, getId(principal));
} }
final DatabaseDto database = cacheService.getDatabase(databaseId);
try { try {
final HttpHeaders headers = new HttpHeaders(); final HttpHeaders headers = new HttpHeaders();
if (request.getMethod().equals("HEAD")) { if (request.getMethod().equals("HEAD")) {
headers.set("Access-Control-Expose-Headers", "X-Count"); headers.set("Access-Control-Expose-Headers", "X-Count");
headers.set("X-Count", "" + tableService.getCount(table, timestamp)); headers.set("X-Count", "" + tableService.getCount(database, table, timestamp));
return ResponseEntity.ok() return ResponseEntity.ok()
.headers(headers) .headers(headers)
.build(); .build();
} }
headers.set("Access-Control-Expose-Headers", "X-Headers"); headers.set("Access-Control-Expose-Headers", "X-Headers");
headers.set("X-Headers", String.join(",", table.getColumns().stream().map(ColumnDto::getInternalName).toList())); headers.set("X-Headers", String.join(",", table.getColumns().stream().map(ColumnDto::getInternalName).toList()));
final String query = mariaDbMapper.defaultRawSelectQuery(table.getDatabase().getInternalName(), final String query = mariaDbMapper.defaultRawSelectQuery(database.getInternalName(),
table.getInternalName(), timestamp, page, size); table.getInternalName(), timestamp, page, size);
final Dataset<Row> dataset = subsetService.getData(credentialService.getDatabase(table.getTdbid()), final Dataset<Row> dataset = subsetService.getData(database, query);
query, timestamp, page, size, null, null);
metricsService.countTableGetData(databaseId, tableId);
return ResponseEntity.ok() return ResponseEntity.ok()
.headers(headers) .headers(headers)
.body(transform(dataset)); .body(transform(dataset));
...@@ -337,20 +337,21 @@ public class TableEndpoint extends RestEndpoint { ...@@ -337,20 +337,21 @@ public class TableEndpoint extends RestEndpoint {
mediaType = "application/json", mediaType = "application/json",
schema = @Schema(implementation = ApiErrorDto.class))}), schema = @Schema(implementation = ApiErrorDto.class))}),
}) })
public ResponseEntity<Void> insertRawTuple(@NotNull @PathVariable("databaseId") Long databaseId, public ResponseEntity<Void> insertRawTuple(@NotNull @PathVariable("databaseId") UUID databaseId,
@NotNull @PathVariable("tableId") Long tableId, @NotNull @PathVariable("tableId") UUID tableId,
@Valid @RequestBody TupleDto data, @Valid @RequestBody TupleDto data,
@NotNull Principal principal, @NotNull Principal principal,
@RequestHeader("Authorization") String authorization) @RequestHeader("Authorization") String authorization)
throws DatabaseUnavailableException, RemoteUnavailableException, TableNotFoundException, throws DatabaseUnavailableException, RemoteUnavailableException, TableNotFoundException,
TableMalformedException, QueryMalformedException, NotAllowedException, StorageUnavailableException, TableMalformedException, QueryMalformedException, NotAllowedException, StorageUnavailableException,
StorageNotFoundException, MetadataServiceException { StorageNotFoundException, MetadataServiceException, DatabaseNotFoundException {
log.debug("endpoint insert raw table data, databaseId={}, tableId={}", databaseId, tableId); log.debug("endpoint insert raw table data, databaseId={}, tableId={}", databaseId, tableId);
final TableDto table = credentialService.getTable(databaseId, tableId); final TableDto table = cacheService.getTable(databaseId, tableId);
final DatabaseAccessDto access = credentialService.getAccess(databaseId, getId(principal)); final DatabaseAccessDto access = cacheService.getAccess(databaseId, getId(principal));
endpointValidator.validateOnlyWriteOwnOrWriteAllAccess(access.getType(), table.getOwner().getId(), getId(principal)); endpointValidator.validateOnlyWriteOwnOrWriteAllAccess(access.getType(), table.getOwner().getId(), getId(principal));
final DatabaseDto database = cacheService.getDatabase(databaseId);
try { try {
tableService.createTuple(table, data); tableService.createTuple(database, table, data);
metadataServiceGateway.updateTableStatistics(databaseId, tableId, authorization); metadataServiceGateway.updateTableStatistics(databaseId, tableId, authorization);
return ResponseEntity.status(HttpStatus.CREATED) return ResponseEntity.status(HttpStatus.CREATED)
.build(); .build();
...@@ -390,20 +391,22 @@ public class TableEndpoint extends RestEndpoint { ...@@ -390,20 +391,22 @@ public class TableEndpoint extends RestEndpoint {
mediaType = "application/json", mediaType = "application/json",
schema = @Schema(implementation = ApiErrorDto.class))}), schema = @Schema(implementation = ApiErrorDto.class))}),
}) })
public ResponseEntity<Void> updateRawTuple(@NotNull @PathVariable("databaseId") Long databaseId, public ResponseEntity<Void> updateRawTuple(@NotNull @PathVariable("databaseId") UUID databaseId,
@NotNull @PathVariable("tableId") Long tableId, @NotNull @PathVariable("tableId") UUID tableId,
@Valid @RequestBody TupleUpdateDto data, @Valid @RequestBody TupleUpdateDto data,
@NotNull Principal principal, @NotNull Principal principal,
@RequestHeader("Authorization") String authorization) @RequestHeader("Authorization") String authorization)
throws DatabaseUnavailableException, RemoteUnavailableException, TableNotFoundException, throws DatabaseUnavailableException, RemoteUnavailableException, TableNotFoundException,
TableMalformedException, QueryMalformedException, NotAllowedException, MetadataServiceException { TableMalformedException, QueryMalformedException, NotAllowedException, MetadataServiceException,
DatabaseNotFoundException {
log.debug("endpoint update raw table data, databaseId={}, tableId={}, data.keys={}", databaseId, tableId, log.debug("endpoint update raw table data, databaseId={}, tableId={}, data.keys={}", databaseId, tableId,
data.getKeys()); data.getKeys());
final TableDto table = credentialService.getTable(databaseId, tableId); final TableDto table = cacheService.getTable(databaseId, tableId);
final DatabaseAccessDto access = credentialService.getAccess(databaseId, getId(principal)); final DatabaseAccessDto access = cacheService.getAccess(databaseId, getId(principal));
endpointValidator.validateOnlyWriteOwnOrWriteAllAccess(access.getType(), table.getOwner().getId(), getId(principal)); endpointValidator.validateOnlyWriteOwnOrWriteAllAccess(access.getType(), table.getOwner().getId(), getId(principal));
final DatabaseDto database = cacheService.getDatabase(databaseId);
try { try {
tableService.updateTuple(table, data); tableService.updateTuple(database, table, data);
metadataServiceGateway.updateTableStatistics(databaseId, tableId, authorization); metadataServiceGateway.updateTableStatistics(databaseId, tableId, authorization);
return ResponseEntity.status(HttpStatus.ACCEPTED) return ResponseEntity.status(HttpStatus.ACCEPTED)
.build(); .build();
...@@ -443,20 +446,22 @@ public class TableEndpoint extends RestEndpoint { ...@@ -443,20 +446,22 @@ public class TableEndpoint extends RestEndpoint {
mediaType = "application/json", mediaType = "application/json",
schema = @Schema(implementation = ApiErrorDto.class))}), schema = @Schema(implementation = ApiErrorDto.class))}),
}) })
public ResponseEntity<Void> deleteRawTuple(@NotNull @PathVariable("databaseId") Long databaseId, public ResponseEntity<Void> deleteRawTuple(@NotNull @PathVariable("databaseId") UUID databaseId,
@NotNull @PathVariable("tableId") Long tableId, @NotNull @PathVariable("tableId") UUID tableId,
@Valid @RequestBody TupleDeleteDto data, @Valid @RequestBody TupleDeleteDto data,
@NotNull Principal principal, @NotNull Principal principal,
@RequestHeader("Authorization") String authorization) @RequestHeader("Authorization") String authorization)
throws DatabaseUnavailableException, RemoteUnavailableException, TableNotFoundException, throws DatabaseUnavailableException, RemoteUnavailableException, TableNotFoundException,
TableMalformedException, QueryMalformedException, NotAllowedException, MetadataServiceException { TableMalformedException, QueryMalformedException, NotAllowedException, MetadataServiceException,
DatabaseNotFoundException {
log.debug("endpoint delete raw table data, databaseId={}, tableId={}, data.keys={}", databaseId, tableId, log.debug("endpoint delete raw table data, databaseId={}, tableId={}, data.keys={}", databaseId, tableId,
data.getKeys()); data.getKeys());
final TableDto table = credentialService.getTable(databaseId, tableId); final TableDto table = cacheService.getTable(databaseId, tableId);
final DatabaseAccessDto access = credentialService.getAccess(databaseId, getId(principal)); final DatabaseAccessDto access = cacheService.getAccess(databaseId, getId(principal));
endpointValidator.validateOnlyWriteOwnOrWriteAllAccess(access.getType(), table.getOwner().getId(), getId(principal)); endpointValidator.validateOnlyWriteOwnOrWriteAllAccess(access.getType(), table.getOwner().getId(), getId(principal));
final DatabaseDto database = cacheService.getDatabase(databaseId);
try { try {
tableService.deleteTuple(table, data); tableService.deleteTuple(database, table, data);
metadataServiceGateway.updateTableStatistics(databaseId, tableId, authorization); metadataServiceGateway.updateTableStatistics(databaseId, tableId, authorization);
return ResponseEntity.status(HttpStatus.ACCEPTED) return ResponseEntity.status(HttpStatus.ACCEPTED)
.build(); .build();
...@@ -498,12 +503,12 @@ public class TableEndpoint extends RestEndpoint { ...@@ -498,12 +503,12 @@ public class TableEndpoint extends RestEndpoint {
mediaType = "application/json", mediaType = "application/json",
schema = @Schema(implementation = ApiErrorDto.class))}), schema = @Schema(implementation = ApiErrorDto.class))}),
}) })
public ResponseEntity<List<TableHistoryDto>> getHistory(@NotNull @PathVariable("databaseId") Long databaseId, public ResponseEntity<List<TableHistoryDto>> getHistory(@NotNull @PathVariable("databaseId") UUID databaseId,
@NotNull @PathVariable("tableId") Long tableId, @NotNull @PathVariable("tableId") UUID tableId,
@RequestParam(value = "size", required = false) Long size, @RequestParam(value = "size", required = false) Long size,
Principal principal) throws DatabaseUnavailableException, Principal principal) throws DatabaseUnavailableException,
RemoteUnavailableException, TableNotFoundException, NotAllowedException, MetadataServiceException, RemoteUnavailableException, TableNotFoundException, NotAllowedException, MetadataServiceException,
PaginationException { PaginationException, DatabaseNotFoundException {
log.debug("endpoint find table history, databaseId={}, tableId={}", databaseId, tableId); log.debug("endpoint find table history, databaseId={}, tableId={}", databaseId, tableId);
if (size != null && size <= 0) { if (size != null && size <= 0) {
log.error("Invalid size: must be > 0"); log.error("Invalid size: must be > 0");
...@@ -512,16 +517,17 @@ public class TableEndpoint extends RestEndpoint { ...@@ -512,16 +517,17 @@ public class TableEndpoint extends RestEndpoint {
log.debug("size not set: default to 100L"); log.debug("size not set: default to 100L");
size = 100L; size = 100L;
} }
final TableDto table = credentialService.getTable(databaseId, tableId); final TableDto table = cacheService.getTable(databaseId, tableId);
if (!table.getIsPublic()) { if (!table.getIsPublic()) {
if (principal == null) { if (principal == null) {
log.error("Failed to find table history: no authentication found"); log.error("Failed to find table history: no authentication found");
throw new NotAllowedException("Failed to find table history: no authentication found"); throw new NotAllowedException("Failed to find table history: no authentication found");
} }
credentialService.getAccess(databaseId, getId(principal)); cacheService.getAccess(databaseId, getId(principal));
} }
final DatabaseDto database = cacheService.getDatabase(databaseId);
try { try {
final List<TableHistoryDto> dto = tableService.history(table, size); final List<TableHistoryDto> dto = tableService.history(database, table, size);
return ResponseEntity.status(HttpStatus.OK) return ResponseEntity.status(HttpStatus.OK)
.body(dto); .body(dto);
} catch (SQLException e) { } catch (SQLException e) {
...@@ -567,11 +573,11 @@ public class TableEndpoint extends RestEndpoint { ...@@ -567,11 +573,11 @@ public class TableEndpoint extends RestEndpoint {
mediaType = "application/json", mediaType = "application/json",
schema = @Schema(implementation = ApiErrorDto.class))}), schema = @Schema(implementation = ApiErrorDto.class))}),
}) })
public ResponseEntity<List<TableDto>> getSchema(@NotNull @PathVariable("databaseId") Long databaseId) public ResponseEntity<List<TableDto>> getSchema(@NotNull @PathVariable("databaseId") UUID databaseId)
throws DatabaseUnavailableException, DatabaseNotFoundException, RemoteUnavailableException, throws DatabaseUnavailableException, DatabaseNotFoundException, RemoteUnavailableException,
DatabaseMalformedException, TableNotFoundException, MetadataServiceException { DatabaseMalformedException, TableNotFoundException, MetadataServiceException {
log.debug("endpoint inspect table schemas, databaseId={}", databaseId); log.debug("endpoint inspect table schemas, databaseId={}", databaseId);
final DatabaseDto database = credentialService.getDatabase(databaseId); final DatabaseDto database = cacheService.getDatabase(databaseId);
try { try {
return ResponseEntity.ok(databaseService.exploreTables(database)); return ResponseEntity.ok(databaseService.exploreTables(database));
} catch (SQLException e) { } catch (SQLException e) {
...@@ -612,8 +618,8 @@ public class TableEndpoint extends RestEndpoint { ...@@ -612,8 +618,8 @@ public class TableEndpoint extends RestEndpoint {
mediaType = "application/json", mediaType = "application/json",
schema = @Schema(implementation = ApiErrorDto.class))}), schema = @Schema(implementation = ApiErrorDto.class))}),
}) })
public ResponseEntity<InputStreamResource> exportDataset(@NotNull @PathVariable("databaseId") Long databaseId, public ResponseEntity<InputStreamResource> exportDataset(@NotNull @PathVariable("databaseId") UUID databaseId,
@NotNull @PathVariable("tableId") Long tableId, @NotNull @PathVariable("tableId") UUID tableId,
@RequestParam(required = false) Instant timestamp, @RequestParam(required = false) Instant timestamp,
Principal principal) Principal principal)
throws RemoteUnavailableException, TableNotFoundException, NotAllowedException, StorageUnavailableException, throws RemoteUnavailableException, TableNotFoundException, NotAllowedException, StorageUnavailableException,
...@@ -624,19 +630,19 @@ public class TableEndpoint extends RestEndpoint { ...@@ -624,19 +630,19 @@ public class TableEndpoint extends RestEndpoint {
timestamp = Instant.now(); timestamp = Instant.now();
log.debug("timestamp not set: default to {}", timestamp); log.debug("timestamp not set: default to {}", timestamp);
} }
final TableDto table = credentialService.getTable(databaseId, tableId); final TableDto table = cacheService.getTable(databaseId, tableId);
if (!table.getIsPublic()) { if (!table.getIsPublic()) {
if (principal == null) { if (principal == null) {
log.error("Failed to export private table: principal is null"); log.error("Failed to export private table: principal is null");
throw new NotAllowedException("Failed to export private table: principal is null"); throw new NotAllowedException("Failed to export private table: principal is null");
} }
credentialService.getAccess(databaseId, getId(principal)); cacheService.getAccess(databaseId, getId(principal));
} }
final String query = mariaDbMapper.defaultRawSelectQuery(table.getDatabase().getInternalName(), final DatabaseDto database = cacheService.getDatabase(databaseId);
final String query = mariaDbMapper.defaultRawSelectQuery(database.getInternalName(),
table.getInternalName(), timestamp, null, null); table.getInternalName(), timestamp, null, null);
final Dataset<Row> dataset = subsetService.getData(credentialService.getDatabase(table.getTdbid()), final Dataset<Row> dataset = subsetService.getData(cacheService.getDatabase(table.getDatabaseId()),
query, timestamp, null, null, null, null); query);
metricsService.countTableGetData(databaseId, tableId);
final ExportResourceDto resource = storageService.transformDataset(dataset); final ExportResourceDto resource = storageService.transformDataset(dataset);
final HttpHeaders headers = new HttpHeaders(); final HttpHeaders headers = new HttpHeaders();
headers.add("Content-Disposition", "attachment; filename=\"" + resource.getFilename() + "\""); headers.add("Content-Disposition", "attachment; filename=\"" + resource.getFilename() + "\"");
...@@ -676,24 +682,25 @@ public class TableEndpoint extends RestEndpoint { ...@@ -676,24 +682,25 @@ public class TableEndpoint extends RestEndpoint {
mediaType = "application/json", mediaType = "application/json",
schema = @Schema(implementation = ApiErrorDto.class))}), schema = @Schema(implementation = ApiErrorDto.class))}),
}) })
public ResponseEntity<Void> importDataset(@NotNull @PathVariable("databaseId") Long databaseId, public ResponseEntity<Void> importDataset(@NotNull @PathVariable("databaseId") UUID databaseId,
@NotNull @PathVariable("tableId") Long tableId, @NotNull @PathVariable("tableId") UUID tableId,
@Valid @RequestBody ImportDto data, @Valid @RequestBody ImportDto data,
@NotNull Principal principal, @NotNull Principal principal,
@RequestHeader("Authorization") String authorization) @RequestHeader("Authorization") String authorization)
throws RemoteUnavailableException, TableNotFoundException, NotAllowedException, MetadataServiceException, throws RemoteUnavailableException, TableNotFoundException, NotAllowedException, MetadataServiceException,
StorageNotFoundException, MalformedException, StorageUnavailableException, QueryMalformedException, StorageNotFoundException, MalformedException, StorageUnavailableException, QueryMalformedException,
DatabaseUnavailableException { DatabaseUnavailableException, DatabaseNotFoundException {
log.debug("endpoint insert table data, databaseId={}, tableId={}, data.location={}", databaseId, tableId, data.getLocation()); log.debug("endpoint insert table data, databaseId={}, tableId={}, data.location={}", databaseId, tableId, data.getLocation());
final TableDto table = credentialService.getTable(databaseId, tableId); final TableDto table = cacheService.getTable(databaseId, tableId);
final DatabaseAccessDto access = credentialService.getAccess(databaseId, getId(principal)); final DatabaseAccessDto access = cacheService.getAccess(databaseId, getId(principal));
endpointValidator.validateOnlyWriteOwnOrWriteAllAccess(access.getType(), table.getOwner().getId(), getId(principal)); endpointValidator.validateOnlyWriteOwnOrWriteAllAccess(access.getType(), table.getOwner().getId(), getId(principal));
if (data.getLineTermination() == null) { if (data.getLineTermination() == null) {
data.setLineTermination("\\r\\n"); data.setLineTermination("\\r\\n");
log.debug("line termination not present, default to {}", data.getLineTermination()); log.debug("line termination not present, default to {}", data.getLineTermination());
} }
final DatabaseDto database = cacheService.getDatabase(databaseId);
try { try {
tableService.importDataset(table, data); tableService.importDataset(database, table, data);
} catch (SQLException | TableMalformedException e) { } catch (SQLException | TableMalformedException e) {
log.error("Failed to establish connection to database: {}", e.getMessage()); log.error("Failed to establish connection to database: {}", e.getMessage());
throw new DatabaseUnavailableException("Failed to establish connection to database", e); throw new DatabaseUnavailableException("Failed to establish connection to database", e);
...@@ -730,14 +737,14 @@ public class TableEndpoint extends RestEndpoint { ...@@ -730,14 +737,14 @@ public class TableEndpoint extends RestEndpoint {
mediaType = "application/json", mediaType = "application/json",
schema = @Schema(implementation = ApiErrorDto.class))}), schema = @Schema(implementation = ApiErrorDto.class))}),
}) })
public ResponseEntity<TableStatisticDto> statistic(@NotNull @PathVariable("databaseId") Long databaseId, public ResponseEntity<TableStatisticDto> statistic(@NotNull @PathVariable("databaseId") UUID databaseId,
@NotNull @PathVariable("tableId") Long tableId) @NotNull @PathVariable("tableId") UUID tableId)
throws DatabaseUnavailableException, RemoteUnavailableException, TableNotFoundException, throws DatabaseUnavailableException, RemoteUnavailableException, TableNotFoundException,
MetadataServiceException, TableMalformedException { MetadataServiceException, TableMalformedException, DatabaseNotFoundException {
log.debug("endpoint generate table statistic, databaseId={}, tableId={}", databaseId, tableId); log.debug("endpoint generate table statistic, databaseId={}, tableId={}", databaseId, tableId);
final DatabaseDto database = cacheService.getDatabase(databaseId);
try { try {
return ResponseEntity.ok(tableService.getStatistics( return ResponseEntity.ok(tableService.getStatistics(database, cacheService.getTable(databaseId, tableId)));
credentialService.getTable(databaseId, tableId)));
} catch (SQLException e) { } catch (SQLException e) {
log.error("Failed to establish connection to database: {}", e.getMessage()); log.error("Failed to establish connection to database: {}", e.getMessage());
throw new DatabaseUnavailableException("Failed to establish connection to database", e); throw new DatabaseUnavailableException("Failed to establish connection to database", e);
......
package at.tuwien.endpoints;
import at.tuwien.api.database.ViewDto;
import at.tuwien.api.error.ApiErrorDto;
import at.tuwien.api.file.UploadResponseDto;
import at.tuwien.exception.*;
import at.tuwien.service.StorageService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import jakarta.validation.constraints.NotNull;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
@Log4j2
@RestController
@CrossOrigin(origins = "*")
@RequestMapping(path = "/api/upload")
public class UploadEndpoint extends RestEndpoint {
private final StorageService storageService;
@Autowired
public UploadEndpoint(StorageService storageService) {
this.storageService = storageService;
}
@PostMapping
@PreAuthorize("hasAuthority('upload-file')")
@Operation(summary = "Uploads a multipart file",
description = "Uploads a multipart file to the Storage Service. Requires role `upload-file`.",
security = {@SecurityRequirement(name = "basicAuth"), @SecurityRequirement(name = "bearerAuth")})
@ApiResponses(value = {
@ApiResponse(responseCode = "201",
description = "Uploaded the file",
content = {@Content(
mediaType = "application/json",
schema = @Schema(implementation = ViewDto.class))}),
@ApiResponse(responseCode = "503",
description = "Failed to establish connection with the storage service",
content = {@Content(
mediaType = "application/json",
schema = @Schema(implementation = ApiErrorDto.class))}),
})
public ResponseEntity<UploadResponseDto> create(@NotNull @RequestParam("file") MultipartFile file) throws DatabaseUnavailableException,
DatabaseNotFoundException, RemoteUnavailableException, ViewMalformedException, MetadataServiceException {
log.debug("endpoint upload file, file.originalFilename={}", file.getOriginalFilename());
try {
final String key = storageService.putObject(file.getBytes());
return ResponseEntity.status(HttpStatus.CREATED)
.body(UploadResponseDto.builder()
.s3Key(key)
.build());
} catch (IOException e) {
log.error("Failed to establish connection to database: {}", e.getMessage());
throw new DatabaseUnavailableException("Failed to establish connection to database: " + e.getMessage(), e);
}
}
}
...@@ -37,6 +37,7 @@ import java.sql.SQLException; ...@@ -37,6 +37,7 @@ import java.sql.SQLException;
import java.time.Instant; import java.time.Instant;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID;
@Log4j2 @Log4j2
@RestController @RestController
...@@ -45,28 +46,23 @@ import java.util.Map; ...@@ -45,28 +46,23 @@ import java.util.Map;
public class ViewEndpoint extends RestEndpoint { public class ViewEndpoint extends RestEndpoint {
private final ViewService viewService; private final ViewService viewService;
private final TableService tableService; private final CacheService cacheService;
private final MariaDbMapper mariaDbMapper; private final MariaDbMapper mariaDbMapper;
private final SubsetService subsetService; private final SubsetService subsetService;
private final MetricsService metricsService;
private final StorageService storageService; private final StorageService storageService;
private final DatabaseService databaseService; private final DatabaseService databaseService;
private final CredentialService credentialService;
private final EndpointValidator endpointValidator; private final EndpointValidator endpointValidator;
@Autowired @Autowired
public ViewEndpoint(ViewService viewService, TableService tableService, MariaDbMapper mariaDbMapper, public ViewEndpoint(ViewService viewService, CacheService cacheService, MariaDbMapper mariaDbMapper,
SubsetService subsetService, MetricsService metricsService, StorageService storageService, SubsetService subsetService, StorageService storageService, DatabaseService databaseService,
DatabaseService databaseService, CredentialService credentialService,
EndpointValidator endpointValidator) { EndpointValidator endpointValidator) {
this.viewService = viewService; this.viewService = viewService;
this.tableService = tableService; this.cacheService = cacheService;
this.mariaDbMapper = mariaDbMapper; this.mariaDbMapper = mariaDbMapper;
this.subsetService = subsetService; this.subsetService = subsetService;
this.metricsService = metricsService;
this.storageService = storageService; this.storageService = storageService;
this.databaseService = databaseService; this.databaseService = databaseService;
this.credentialService = credentialService;
this.endpointValidator = endpointValidator; this.endpointValidator = endpointValidator;
} }
...@@ -107,11 +103,11 @@ public class ViewEndpoint extends RestEndpoint { ...@@ -107,11 +103,11 @@ public class ViewEndpoint extends RestEndpoint {
mediaType = "application/json", mediaType = "application/json",
schema = @Schema(implementation = ApiErrorDto.class))}), schema = @Schema(implementation = ApiErrorDto.class))}),
}) })
public ResponseEntity<List<ViewDto>> getSchema(@NotNull @PathVariable("databaseId") Long databaseId) public ResponseEntity<List<ViewDto>> getSchema(@NotNull @PathVariable("databaseId") UUID databaseId)
throws DatabaseUnavailableException, DatabaseNotFoundException, RemoteUnavailableException, throws DatabaseUnavailableException, DatabaseNotFoundException, RemoteUnavailableException,
DatabaseMalformedException, MetadataServiceException, ViewNotFoundException { DatabaseMalformedException, MetadataServiceException, ViewNotFoundException {
log.debug("endpoint inspect view schemas, databaseId={}", databaseId); log.debug("endpoint inspect view schemas, databaseId={}", databaseId);
final DatabaseDto database = credentialService.getDatabase(databaseId); final DatabaseDto database = cacheService.getDatabase(databaseId);
try { try {
return ResponseEntity.ok(databaseService.exploreViews(database)); return ResponseEntity.ok(databaseService.exploreViews(database));
} catch (SQLException e) { } catch (SQLException e) {
...@@ -152,14 +148,19 @@ public class ViewEndpoint extends RestEndpoint { ...@@ -152,14 +148,19 @@ public class ViewEndpoint extends RestEndpoint {
mediaType = "application/json", mediaType = "application/json",
schema = @Schema(implementation = ApiErrorDto.class))}), schema = @Schema(implementation = ApiErrorDto.class))}),
}) })
public ResponseEntity<ViewDto> create(@NotNull @PathVariable("databaseId") Long databaseId, public ResponseEntity<ViewDto> create(@NotNull @PathVariable("databaseId") UUID databaseId,
@Valid @RequestBody CreateViewDto data) throws DatabaseUnavailableException, @Valid @RequestBody CreateViewDto data) throws DatabaseUnavailableException,
DatabaseNotFoundException, RemoteUnavailableException, ViewMalformedException, MetadataServiceException { DatabaseNotFoundException, RemoteUnavailableException, ViewMalformedException, MetadataServiceException,
TableNotFoundException, ImageNotFoundException, QueryMalformedException {
log.debug("endpoint create view, databaseId={}, data.name={}", databaseId, data.getName()); log.debug("endpoint create view, databaseId={}, data.name={}", databaseId, data.getName());
final DatabaseDto database = credentialService.getDatabase(databaseId); /* check */
endpointValidator.validateSubsetParams(data.getQuery());
/* create */
final DatabaseDto database = cacheService.getDatabase(databaseId);
try { try {
return ResponseEntity.status(HttpStatus.CREATED) return ResponseEntity.status(HttpStatus.CREATED)
.body(databaseService.createView(database, data)); .body(databaseService.createView(database, mariaDbMapper.nameToInternalName(data.getName()),
mariaDbMapper.subsetDtoToRawQuery(database, data.getQuery())));
} catch (SQLException e) { } catch (SQLException e) {
log.error("Failed to establish connection to database: {}", e.getMessage()); log.error("Failed to establish connection to database: {}", e.getMessage());
throw new DatabaseUnavailableException("Failed to establish connection to database: " + e.getMessage(), e); throw new DatabaseUnavailableException("Failed to establish connection to database: " + e.getMessage(), e);
...@@ -195,14 +196,15 @@ public class ViewEndpoint extends RestEndpoint { ...@@ -195,14 +196,15 @@ public class ViewEndpoint extends RestEndpoint {
mediaType = "application/json", mediaType = "application/json",
schema = @Schema(implementation = ApiErrorDto.class))}), schema = @Schema(implementation = ApiErrorDto.class))}),
}) })
public ResponseEntity<Void> delete(@NotNull @PathVariable("databaseId") Long databaseId, public ResponseEntity<Void> delete(@NotNull @PathVariable("databaseId") UUID databaseId,
@NotNull @PathVariable("viewId") Long viewId) @NotNull @PathVariable("viewId") UUID viewId)
throws DatabaseUnavailableException, RemoteUnavailableException, ViewNotFoundException, throws DatabaseUnavailableException, RemoteUnavailableException, ViewNotFoundException,
ViewMalformedException, MetadataServiceException { ViewMalformedException, MetadataServiceException, DatabaseNotFoundException {
log.debug("endpoint delete view, databaseId={}, viewId={}", databaseId, viewId); log.debug("endpoint delete view, databaseId={}, viewId={}", databaseId, viewId);
final ViewDto view = credentialService.getView(databaseId, viewId); final ViewDto view = cacheService.getView(databaseId, viewId);
final DatabaseDto database = cacheService.getDatabase(databaseId);
try { try {
viewService.delete(view); viewService.delete(database, view);
return ResponseEntity.status(HttpStatus.ACCEPTED) return ResponseEntity.status(HttpStatus.ACCEPTED)
.build(); .build();
} catch (SQLException e) { } catch (SQLException e) {
...@@ -250,8 +252,8 @@ public class ViewEndpoint extends RestEndpoint { ...@@ -250,8 +252,8 @@ public class ViewEndpoint extends RestEndpoint {
mediaType = "application/json", mediaType = "application/json",
schema = @Schema(implementation = ApiErrorDto.class))}), schema = @Schema(implementation = ApiErrorDto.class))}),
}) })
public ResponseEntity<List<Map<String, Object>>> getData(@NotNull @PathVariable("databaseId") Long databaseId, public ResponseEntity<List<Map<String, Object>>> getData(@NotNull @PathVariable("databaseId") UUID databaseId,
@NotNull @PathVariable("viewId") Long viewId, @NotNull @PathVariable("viewId") UUID viewId,
@RequestParam(required = false) Long page, @RequestParam(required = false) Long page,
@RequestParam(required = false) Long size, @RequestParam(required = false) Long size,
@RequestParam(required = false) Instant timestamp, @RequestParam(required = false) Instant timestamp,
...@@ -275,30 +277,30 @@ public class ViewEndpoint extends RestEndpoint { ...@@ -275,30 +277,30 @@ public class ViewEndpoint extends RestEndpoint {
timestamp = Instant.now(); timestamp = Instant.now();
log.debug("timestamp not set: default to {}", timestamp); log.debug("timestamp not set: default to {}", timestamp);
} }
final ViewDto view = credentialService.getView(databaseId, viewId); final ViewDto view = cacheService.getView(databaseId, viewId);
if (!view.getIsPublic()) { if (!view.getIsPublic()) {
if (principal == null) { if (principal == null) {
log.error("Failed to get data from view: unauthorized"); log.error("Failed to get data from view: unauthorized");
throw new NotAllowedException("Failed to get data from view: unauthorized"); throw new NotAllowedException("Failed to get data from view: unauthorized");
} }
credentialService.getAccess(databaseId, getId(principal)); cacheService.getAccess(databaseId, getId(principal));
} }
final DatabaseDto database = cacheService.getDatabase(databaseId);
try { try {
final HttpHeaders headers = new HttpHeaders(); final HttpHeaders headers = new HttpHeaders();
if (request.getMethod().equals("HEAD")) { if (request.getMethod().equals("HEAD")) {
headers.set("Access-Control-Expose-Headers", "X-Count"); headers.set("Access-Control-Expose-Headers", "X-Count");
headers.set("X-Count", "" + viewService.count(view, timestamp)); headers.set("X-Count", "" + viewService.count(database, view, timestamp));
return ResponseEntity.ok() return ResponseEntity.ok()
.headers(headers) .headers(headers)
.build(); .build();
} }
headers.set("Access-Control-Expose-Headers", "X-Headers"); headers.set("Access-Control-Expose-Headers", "X-Headers");
headers.set("X-Headers", String.join(",", view.getColumns().stream().map(ViewColumnDto::getInternalName).toList())); headers.set("X-Headers", String.join(",", view.getColumns().stream().map(ViewColumnDto::getInternalName).toList()));
final String query = mariaDbMapper.defaultRawSelectQuery(view.getDatabase().getInternalName(), final String query = mariaDbMapper.defaultRawSelectQuery(database.getInternalName(),
view.getInternalName(), timestamp, page, size); view.getInternalName(), timestamp, page, size);
final Dataset<Row> dataset = subsetService.getData(credentialService.getDatabase(databaseId), final Dataset<Row> dataset = subsetService.getData(cacheService.getDatabase(databaseId),
query, timestamp, page, size, null, null); query);
metricsService.countViewGetData(databaseId, viewId);
return ResponseEntity.ok() return ResponseEntity.ok()
.headers(headers) .headers(headers)
.body(transform(dataset)); .body(transform(dataset));
...@@ -340,8 +342,8 @@ public class ViewEndpoint extends RestEndpoint { ...@@ -340,8 +342,8 @@ public class ViewEndpoint extends RestEndpoint {
mediaType = "application/json", mediaType = "application/json",
schema = @Schema(implementation = ApiErrorDto.class))}), schema = @Schema(implementation = ApiErrorDto.class))}),
}) })
public ResponseEntity<InputStreamResource> exportDataset(@NotNull @PathVariable("databaseId") Long databaseId, public ResponseEntity<InputStreamResource> exportDataset(@NotNull @PathVariable("databaseId") UUID databaseId,
@NotNull @PathVariable("viewId") Long viewId, @NotNull @PathVariable("viewId") UUID viewId,
@RequestParam(required = false) Instant timestamp, @RequestParam(required = false) Instant timestamp,
Principal principal) Principal principal)
throws RemoteUnavailableException, ViewNotFoundException, NotAllowedException, MetadataServiceException, throws RemoteUnavailableException, ViewNotFoundException, NotAllowedException, MetadataServiceException,
...@@ -353,19 +355,19 @@ public class ViewEndpoint extends RestEndpoint { ...@@ -353,19 +355,19 @@ public class ViewEndpoint extends RestEndpoint {
log.debug("timestamp not set: default to {}", timestamp); log.debug("timestamp not set: default to {}", timestamp);
} }
/* parameters */ /* parameters */
final ViewDto view = credentialService.getView(databaseId, viewId); final ViewDto view = cacheService.getView(databaseId, viewId);
if (!view.getIsPublic()) { if (!view.getIsPublic()) {
if (principal == null) { if (principal == null) {
log.error("Failed to export private view: principal is null"); log.error("Failed to export private view: principal is null");
throw new NotAllowedException("Failed to export private view: principal is null"); throw new NotAllowedException("Failed to export private view: principal is null");
} }
credentialService.getAccess(databaseId, getId(principal)); cacheService.getAccess(databaseId, getId(principal));
} }
final String query = mariaDbMapper.defaultRawSelectQuery(view.getDatabase().getInternalName(), final DatabaseDto database = cacheService.getDatabase(databaseId);
final String query = mariaDbMapper.defaultRawSelectQuery(database.getInternalName(),
view.getInternalName(), timestamp, null, null); view.getInternalName(), timestamp, null, null);
final Dataset<Row> dataset = subsetService.getData(credentialService.getDatabase(databaseId), final Dataset<Row> dataset = subsetService.getData(cacheService.getDatabase(databaseId),
query, timestamp, null, null, null, null); query);
metricsService.countViewGetData(databaseId, viewId);
final ExportResourceDto resource = storageService.transformDataset(dataset); final ExportResourceDto resource = storageService.transformDataset(dataset);
final HttpHeaders headers = new HttpHeaders(); final HttpHeaders headers = new HttpHeaders();
headers.add("Content-Disposition", "attachment; filename=\"" + resource.getFilename() + "\""); headers.add("Content-Disposition", "attachment; filename=\"" + resource.getFilename() + "\"");
......
...@@ -458,6 +458,13 @@ public class ApiExceptionHandler extends ResponseEntityExceptionHandler { ...@@ -458,6 +458,13 @@ public class ApiExceptionHandler extends ResponseEntityExceptionHandler {
return generic_handle(e.getClass(), e.getLocalizedMessage()); return generic_handle(e.getClass(), e.getLocalizedMessage());
} }
@Hidden
@ResponseStatus(code = HttpStatus.CONFLICT)
@ExceptionHandler(ViewExistsException.class)
public ResponseEntity<ApiErrorDto> handle(ViewExistsException e) {
return generic_handle(e.getClass(), e.getLocalizedMessage());
}
@Hidden @Hidden
@ResponseStatus(code = HttpStatus.BAD_REQUEST) @ResponseStatus(code = HttpStatus.BAD_REQUEST)
@ExceptionHandler(ViewMalformedException.class) @ExceptionHandler(ViewMalformedException.class)
......
...@@ -3,10 +3,13 @@ package at.tuwien.validation; ...@@ -3,10 +3,13 @@ package at.tuwien.validation;
import at.tuwien.api.database.AccessTypeDto; import at.tuwien.api.database.AccessTypeDto;
import at.tuwien.api.database.DatabaseAccessDto; import at.tuwien.api.database.DatabaseAccessDto;
import at.tuwien.api.database.DatabaseDto; import at.tuwien.api.database.DatabaseDto;
import at.tuwien.api.database.query.FilterDto;
import at.tuwien.api.database.query.FilterTypeDto;
import at.tuwien.api.database.query.SubsetDto;
import at.tuwien.config.QueryConfig; import at.tuwien.config.QueryConfig;
import at.tuwien.endpoints.RestEndpoint; import at.tuwien.endpoints.RestEndpoint;
import at.tuwien.exception.*; import at.tuwien.exception.*;
import at.tuwien.service.CredentialService; import at.tuwien.service.CacheService;
import lombok.extern.log4j.Log4j2; import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
...@@ -24,10 +27,10 @@ import java.util.regex.Pattern; ...@@ -24,10 +27,10 @@ import java.util.regex.Pattern;
public class EndpointValidator extends RestEndpoint { public class EndpointValidator extends RestEndpoint {
private final QueryConfig queryConfig; private final QueryConfig queryConfig;
private final CredentialService credentialService; private final CacheService credentialService;
@Autowired @Autowired
public EndpointValidator(QueryConfig queryConfig, CredentialService credentialService) { public EndpointValidator(QueryConfig queryConfig, CacheService credentialService) {
this.queryConfig = queryConfig; this.queryConfig = queryConfig;
this.credentialService = credentialService; this.credentialService = credentialService;
} }
...@@ -63,6 +66,22 @@ public class EndpointValidator extends RestEndpoint { ...@@ -63,6 +66,22 @@ public class EndpointValidator extends RestEndpoint {
validateOnlyAccess(database, principal, writeAccessOnly); validateOnlyAccess(database, principal, writeAccessOnly);
} }
public void validateSubsetParams(SubsetDto subset) throws QueryMalformedException {
if (subset.getFilter() != null) {
final List<FilterDto> filters = subset.getFilter();
FilterTypeDto previous = null;
for (int i = 0; i < filters.size(); i++) {
final FilterDto filter = filters.get(i);
if ((i == 0 && !filter.getType().equals(FilterTypeDto.WHERE)) ||
(i > 0 && !previous.equals(FilterTypeDto.WHERE) && (filter.getType().equals(FilterTypeDto.AND) || filter.getType().equals(FilterTypeDto.OR)))) {
log.error("Failed to validate subset: invalid specification, must be where-[(and|or)-where]");
throw new QueryMalformedException("Failed to validate subset: invalid specification, must be where-[(and|or)-where]");
}
previous = filter.getType();
}
}
}
public void validateOnlyPrivateSchemaHasRole(DatabaseDto database, Principal principal, String role) public void validateOnlyPrivateSchemaHasRole(DatabaseDto database, Principal principal, String role)
throws NotAllowedException { throws NotAllowedException {
if (database.getIsSchemaPublic()) { if (database.getIsSchemaPublic()) {
......
CREATE PROCEDURE hash_table(IN name VARCHAR(255), OUT hash VARCHAR(255), OUT count BIGINT) BEGIN DECLARE _sql TEXT; SELECT CONCAT('SELECT SHA2(GROUP_CONCAT(CONCAT_WS(\'\',', GROUP_CONCAT(CONCAT('`', column_name, '`') ORDER BY column_name), ') SEPARATOR \',\'), 256) AS hash, COUNT(*) AS count FROM `', name, '` INTO @hash, @count;') FROM `information_schema`.`columns` WHERE `table_schema` = DATABASE() AND `table_name` = name INTO _sql; PREPARE stmt FROM _sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET hash = @hash; SET count = @count; END;
CREATE PROCEDURE store_query(IN query TEXT, IN executed DATETIME, OUT queryId BIGINT) BEGIN DECLARE _queryhash varchar(255) DEFAULT SHA2(query, 256); DECLARE _username varchar(255) DEFAULT REGEXP_REPLACE(current_user(), '@.*', ''); DECLARE _query TEXT DEFAULT CONCAT('CREATE OR REPLACE TABLE _tmp AS (', query, ')'); PREPARE stmt FROM _query; EXECUTE stmt; DEALLOCATE PREPARE stmt; CALL hash_table('_tmp', @hash, @count); DROP TABLE IF EXISTS `_tmp`; IF @hash IS NULL THEN INSERT INTO `qs_queries` (`created_by`, `query`, `query_normalized`, `is_persisted`, `query_hash`, `result_hash`, `result_number`, `executed`) SELECT _username, query, query, false, _queryhash, @hash, @count, executed WHERE NOT EXISTS (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` IS NULL); SET queryId = (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` IS NULL); ELSE INSERT INTO `qs_queries` (`created_by`, `query`, `query_normalized`, `is_persisted`, `query_hash`, `result_hash`, `result_number`, `executed`) SELECT _username, query, query, false, _queryhash, @hash, @count, executed WHERE NOT EXISTS (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` = @hash); SET queryId = (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` = @hash); END IF; END;
CREATE DEFINER = 'root' PROCEDURE _store_query(IN _username VARCHAR(255), IN query TEXT, IN executed DATETIME, OUT queryId BIGINT) BEGIN DECLARE _queryhash varchar(255) DEFAULT SHA2(query, 256); DECLARE _query TEXT DEFAULT CONCAT('CREATE OR REPLACE TABLE _tmp AS (', query, ')'); PREPARE stmt FROM _query; EXECUTE stmt; DEALLOCATE PREPARE stmt; CALL hash_table('_tmp', @hash, @count); DROP TABLE IF EXISTS `_tmp`; IF @hash IS NULL THEN INSERT INTO `qs_queries` (`created_by`, `query`, `query_normalized`, `is_persisted`, `query_hash`, `result_hash`, `result_number`, `executed`) SELECT _username, query, query, false, _queryhash, @hash, @count, executed WHERE NOT EXISTS (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` IS NULL); SET queryId = (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` IS NULL); ELSE INSERT INTO `qs_queries` (`created_by`, `query`, `query_normalized`, `is_persisted`, `query_hash`, `result_hash`, `result_number`, `executed`) SELECT _username, query, query, false, _queryhash, @hash, @count, executed WHERE NOT EXISTS (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` = @hash); SET queryId = (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` = @hash); END IF; END;
\ No newline at end of file
...@@ -30,10 +30,10 @@ public class MariaDbConfig { ...@@ -30,10 +30,10 @@ public class MariaDbConfig {
log.debug("created database {}", database); log.debug("created database {}", database);
} }
public static void createInitDatabase(ContainerDto container, DatabaseDto database) throws SQLException { public static void createInitDatabase(DatabaseDto database) throws SQLException {
final String jdbc = "jdbc:mariadb://" + container.getHost() + ":" + container.getPort(); final String jdbc = "jdbc:mariadb://" + database.getContainer().getHost() + ":" + database.getContainer().getPort();
log.trace("connect to database {}", jdbc); log.trace("connect to database {}", jdbc);
try (Connection connection = DriverManager.getConnection(jdbc, container.getUsername(), container.getPassword())) { try (Connection connection = DriverManager.getConnection(jdbc, database.getContainer().getUsername(), database.getContainer().getPassword())) {
ResourceDatabasePopulator populator = new ResourceDatabasePopulator(new ClassPathResource("init/" + database.getInternalName() + ".sql"), new ClassPathResource("init/users.sql"), new ClassPathResource("init/querystore.sql")); ResourceDatabasePopulator populator = new ResourceDatabasePopulator(new ClassPathResource("init/" + database.getInternalName() + ".sql"), new ClassPathResource("init/users.sql"), new ClassPathResource("init/querystore.sql"));
populator.setSeparator(";\n"); populator.setSeparator(";\n");
populator.populate(connection); populator.populate(connection);
...@@ -141,11 +141,11 @@ public class MariaDbConfig { ...@@ -141,11 +141,11 @@ public class MariaDbConfig {
} }
} }
public static void insertQueryStore(DatabaseDto database, QueryDto query, UUID userId) throws SQLException { public static UUID insertQueryStore(DatabaseDto database, QueryDto query, UUID userId) throws SQLException {
final String jdbc = "jdbc:mariadb://" + database.getContainer().getHost() + ":" + database.getContainer().getPort() + "/" + database.getInternalName(); final String jdbc = "jdbc:mariadb://" + database.getContainer().getHost() + ":" + database.getContainer().getPort() + "/" + database.getInternalName();
log.trace("connect to database: {}", jdbc); log.trace("connect to database: {}", jdbc);
try (Connection connection = DriverManager.getConnection(jdbc, database.getContainer().getUsername(), database.getContainer().getPassword())) { try (Connection connection = DriverManager.getConnection(jdbc, database.getContainer().getUsername(), database.getContainer().getPassword())) {
final PreparedStatement prepareStatement = connection.prepareStatement( PreparedStatement prepareStatement = connection.prepareStatement(
"INSERT INTO qs_queries (created_by, query, query_normalized, is_persisted, query_hash, result_hash, result_number, created, executed) VALUES (?,?,?,?,?,?,?,?,?)"); "INSERT INTO qs_queries (created_by, query, query_normalized, is_persisted, query_hash, result_hash, result_number, created, executed) VALUES (?,?,?,?,?,?,?,?,?)");
prepareStatement.setString(1, String.valueOf(userId)); prepareStatement.setString(1, String.valueOf(userId));
prepareStatement.setString(2, query.getQuery()); prepareStatement.setString(2, query.getQuery());
...@@ -158,6 +158,13 @@ public class MariaDbConfig { ...@@ -158,6 +158,13 @@ public class MariaDbConfig {
prepareStatement.setTimestamp(9, Timestamp.from(query.getExecution())); prepareStatement.setTimestamp(9, Timestamp.from(query.getExecution()));
log.trace("prepared statement: {}", prepareStatement); log.trace("prepared statement: {}", prepareStatement);
prepareStatement.executeUpdate(); prepareStatement.executeUpdate();
/* select */
prepareStatement = connection.prepareStatement("SELECT id FROM qs_queries WHERE query_hash = ? LIMIT 1");
prepareStatement.setString(1, query.getQueryHash());
final ResultSet result = prepareStatement.executeQuery();
UUID queryId;
result.next();
return UUID.fromString(result.getString(1));
} }
} }
......
...@@ -6,7 +6,7 @@ import at.tuwien.api.user.UserDto; ...@@ -6,7 +6,7 @@ import at.tuwien.api.user.UserDto;
import at.tuwien.endpoints.AccessEndpoint; import at.tuwien.endpoints.AccessEndpoint;
import at.tuwien.exception.*; import at.tuwien.exception.*;
import at.tuwien.service.AccessService; import at.tuwien.service.AccessService;
import at.tuwien.service.CredentialService; import at.tuwien.service.CacheService;
import at.tuwien.test.AbstractUnitTest; import at.tuwien.test.AbstractUnitTest;
import lombok.extern.log4j.Log4j2; import lombok.extern.log4j.Log4j2;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
...@@ -34,7 +34,7 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { ...@@ -34,7 +34,7 @@ public class AccessEndpointUnitTest extends AbstractUnitTest {
private AccessEndpoint accessEndpoint; private AccessEndpoint accessEndpoint;
@MockBean @MockBean
private CredentialService credentialService; private CacheService credentialService;
@MockBean @MockBean
private AccessService accessService; private AccessService accessService;
......
...@@ -7,7 +7,7 @@ import at.tuwien.endpoints.DatabaseEndpoint; ...@@ -7,7 +7,7 @@ import at.tuwien.endpoints.DatabaseEndpoint;
import at.tuwien.exception.*; import at.tuwien.exception.*;
import at.tuwien.service.AccessService; import at.tuwien.service.AccessService;
import at.tuwien.service.ContainerService; import at.tuwien.service.ContainerService;
import at.tuwien.service.CredentialService; import at.tuwien.service.CacheService;
import at.tuwien.service.DatabaseService; import at.tuwien.service.DatabaseService;
import at.tuwien.test.AbstractUnitTest; import at.tuwien.test.AbstractUnitTest;
import lombok.extern.log4j.Log4j2; import lombok.extern.log4j.Log4j2;
...@@ -48,7 +48,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { ...@@ -48,7 +48,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest {
private DatabaseService databaseService; private DatabaseService databaseService;
@MockBean @MockBean
private CredentialService credentialService; private CacheService credentialService;
@BeforeEach @BeforeEach
public void beforeEach() { public void beforeEach() {
......
package at.tuwien.endpoint; package at.tuwien.endpoint;
import at.tuwien.api.database.CreateViewDto;
import at.tuwien.api.database.DatabaseDto; import at.tuwien.api.database.DatabaseDto;
import at.tuwien.api.database.query.ExecuteStatementDto;
import at.tuwien.api.database.query.QueryDto; import at.tuwien.api.database.query.QueryDto;
import at.tuwien.api.database.query.QueryPersistDto; import at.tuwien.api.database.query.QueryPersistDto;
import at.tuwien.api.database.query.SubsetDto;
import at.tuwien.endpoints.SubsetEndpoint; import at.tuwien.endpoints.SubsetEndpoint;
import at.tuwien.exception.*; import at.tuwien.exception.*;
import at.tuwien.service.CredentialService; import at.tuwien.gateway.MetadataServiceGateway;
import at.tuwien.service.CacheService;
import at.tuwien.service.DatabaseService; import at.tuwien.service.DatabaseService;
import at.tuwien.service.StorageService; import at.tuwien.service.StorageService;
import at.tuwien.service.SubsetService; import at.tuwien.service.SubsetService;
...@@ -34,8 +34,10 @@ import java.sql.SQLException; ...@@ -34,8 +34,10 @@ import java.sql.SQLException;
import java.time.Instant; import java.time.Instant;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
@Log4j2 @Log4j2
...@@ -62,7 +64,10 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { ...@@ -62,7 +64,10 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
private DatabaseService databaseService; private DatabaseService databaseService;
@MockBean @MockBean
private CredentialService credentialService; private CacheService credentialService;
@MockBean
private MetadataServiceGateway metadataServiceGateway;
@BeforeEach @BeforeEach
public void beforeEach() { public void beforeEach() {
...@@ -147,7 +152,9 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { ...@@ -147,7 +152,9 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
@Test @Test
@WithMockUser(username = USER_1_USERNAME) @WithMockUser(username = USER_1_USERNAME)
public void findById_privateDataPrivateSchema_succeeds() throws DatabaseNotFoundException, SQLException, public void findById_privateDataPrivateSchema_succeeds() throws DatabaseNotFoundException, SQLException,
RemoteUnavailableException, UserNotFoundException, QueryNotFoundException, MetadataServiceException, DatabaseUnavailableException, TableNotFoundException, StorageUnavailableException, NotAllowedException, ViewMalformedException, QueryMalformedException, FormatNotAvailableException { RemoteUnavailableException, UserNotFoundException, QueryNotFoundException, MetadataServiceException,
DatabaseUnavailableException, TableNotFoundException, StorageUnavailableException, NotAllowedException,
QueryMalformedException, FormatNotAvailableException {
/* mock */ /* mock */
when(credentialService.getDatabase(DATABASE_1_ID)) when(credentialService.getDatabase(DATABASE_1_ID))
...@@ -159,13 +166,29 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { ...@@ -159,13 +166,29 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
generic_findById(DATABASE_1_ID, QUERY_1_ID, "application/json", null, USER_1_PRINCIPAL); generic_findById(DATABASE_1_ID, QUERY_1_ID, "application/json", null, USER_1_PRINCIPAL);
} }
@Test
@WithMockUser(username = USER_1_USERNAME)
public void findById_privateDataPrivateSchemaAcceptEmpty_succeeds() throws DatabaseNotFoundException, SQLException,
RemoteUnavailableException, UserNotFoundException, QueryNotFoundException, MetadataServiceException,
DatabaseUnavailableException, TableNotFoundException, StorageUnavailableException, NotAllowedException,
QueryMalformedException, FormatNotAvailableException {
/* mock */
when(credentialService.getDatabase(DATABASE_1_ID))
.thenReturn(DATABASE_1_PRIVILEGED_DTO);
when(subsetService.findById(DATABASE_1_PRIVILEGED_DTO, QUERY_1_ID))
.thenReturn(QUERY_1_DTO);
/* test */
generic_findById(DATABASE_1_ID, QUERY_1_ID, null, null, USER_1_PRINCIPAL);
}
@Test @Test
@WithMockUser(username = USER_3_USERNAME) @WithMockUser(username = USER_3_USERNAME)
public void findById_publicDataPrivateSchema_succeeds() throws DatabaseNotFoundException, SQLException, public void findById_publicDataPrivateSchema_succeeds() throws DatabaseNotFoundException, SQLException,
RemoteUnavailableException, UserNotFoundException, DatabaseUnavailableException, NotAllowedException, RemoteUnavailableException, UserNotFoundException, DatabaseUnavailableException, NotAllowedException,
StorageUnavailableException, QueryMalformedException, QueryNotFoundException, StorageUnavailableException, QueryMalformedException, QueryNotFoundException,
FormatNotAvailableException, TableNotFoundException, MetadataServiceException, FormatNotAvailableException, TableNotFoundException, MetadataServiceException {
ViewMalformedException {
/* mock */ /* mock */
when(credentialService.getDatabase(DATABASE_3_ID)) when(credentialService.getDatabase(DATABASE_3_ID))
...@@ -199,7 +222,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { ...@@ -199,7 +222,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
public void findById_privateDataPrivateSchemaAcceptCsv_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, public void findById_privateDataPrivateSchemaAcceptCsv_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException,
UserNotFoundException, DatabaseUnavailableException, StorageUnavailableException, QueryMalformedException, UserNotFoundException, DatabaseUnavailableException, StorageUnavailableException, QueryMalformedException,
QueryNotFoundException, FormatNotAvailableException, SQLException, MetadataServiceException, QueryNotFoundException, FormatNotAvailableException, SQLException, MetadataServiceException,
TableNotFoundException, ViewMalformedException, NotAllowedException { TableNotFoundException, NotAllowedException {
final Dataset<Row> mock = sparkSession.emptyDataFrame(); final Dataset<Row> mock = sparkSession.emptyDataFrame();
/* mock */ /* mock */
...@@ -207,7 +230,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { ...@@ -207,7 +230,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
.thenReturn(DATABASE_1_PRIVILEGED_DTO); .thenReturn(DATABASE_1_PRIVILEGED_DTO);
when(subsetService.findById(DATABASE_1_PRIVILEGED_DTO, QUERY_1_ID)) when(subsetService.findById(DATABASE_1_PRIVILEGED_DTO, QUERY_1_ID))
.thenReturn(QUERY_5_DTO); .thenReturn(QUERY_5_DTO);
when(subsetService.getData(any(DatabaseDto.class), anyString(), any(Instant.class), eq(null), eq(null), eq(null), eq(null))) when(subsetService.getData(any(DatabaseDto.class), anyString()))
.thenReturn(mock); .thenReturn(mock);
when(storageService.transformDataset(any(Dataset.class))) when(storageService.transformDataset(any(Dataset.class)))
.thenReturn(EXPORT_RESOURCE_DTO); .thenReturn(EXPORT_RESOURCE_DTO);
...@@ -243,7 +266,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { ...@@ -243,7 +266,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
.thenReturn(DATABASE_3_PRIVILEGED_DTO); .thenReturn(DATABASE_3_PRIVILEGED_DTO);
when(subsetService.findById(DATABASE_4_PRIVILEGED_DTO, QUERY_5_ID)) when(subsetService.findById(DATABASE_4_PRIVILEGED_DTO, QUERY_5_ID))
.thenReturn(QUERY_5_DTO); .thenReturn(QUERY_5_DTO);
when(subsetService.getData(any(DatabaseDto.class), anyString(), any(Instant.class), eq(0L), eq(10L), eq(null), eq(null))) when(subsetService.getData(any(DatabaseDto.class), anyString()))
.thenReturn(mock); .thenReturn(mock);
when(storageService.transformDataset(any(Dataset.class))) when(storageService.transformDataset(any(Dataset.class)))
.thenReturn(EXPORT_RESOURCE_DTO); .thenReturn(EXPORT_RESOURCE_DTO);
...@@ -294,43 +317,28 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { ...@@ -294,43 +317,28 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
TableMalformedException, NotAllowedException, QueryNotSupportedException, PaginationException, TableMalformedException, NotAllowedException, QueryNotSupportedException, PaginationException,
StorageNotFoundException, DatabaseUnavailableException, StorageUnavailableException, SQLException, StorageNotFoundException, DatabaseUnavailableException, StorageUnavailableException, SQLException,
QueryMalformedException, QueryNotFoundException, DatabaseNotFoundException, RemoteUnavailableException, QueryMalformedException, QueryNotFoundException, DatabaseNotFoundException, RemoteUnavailableException,
MetadataServiceException, TableNotFoundException, ViewMalformedException, ViewNotFoundException { MetadataServiceException, TableNotFoundException, ViewMalformedException, ViewNotFoundException,
ImageNotFoundException {
final Dataset<Row> mock = sparkSession.emptyDataFrame(); final Dataset<Row> mock = sparkSession.emptyDataFrame();
final ExecuteStatementDto request = ExecuteStatementDto.builder()
.statement(QUERY_5_STATEMENT)
.build();
/* mock */ /* mock */
when(credentialService.getDatabase(DATABASE_3_ID)) when(credentialService.getDatabase(DATABASE_3_ID))
.thenReturn(DATABASE_3_PRIVILEGED_DTO); .thenReturn(DATABASE_3_PRIVILEGED_DTO);
when(subsetService.getData(any(DatabaseDto.class), anyString(), any(Instant.class), eq(0L), eq(10L), eq(null), eq(null))) when(subsetService.getData(any(DatabaseDto.class), anyString()))
.thenReturn(mock); .thenReturn(mock);
when(subsetService.findById(eq(DATABASE_3_PRIVILEGED_DTO), anyLong())) when(subsetService.findById(any(DatabaseDto.class), any(UUID.class)))
.thenReturn(QUERY_5_DTO); .thenReturn(QUERY_5_DTO);
when(subsetService.create(any(DatabaseDto.class), any(SubsetDto.class), any(Instant.class), any(UUID.class)))
.thenReturn(QUERY_5_ID);
when(databaseService.inspectView(any(DatabaseDto.class), anyString())) when(databaseService.inspectView(any(DatabaseDto.class), anyString()))
.thenReturn(QUERY_5_VIEW_DTO); .thenReturn(QUERY_5_VIEW_DTO);
when(metadataServiceGateway.getIdentifiers(DATABASE_3_ID, QUERY_5_ID))
.thenReturn(List.of());
when(httpServletRequest.getMethod()) when(httpServletRequest.getMethod())
.thenReturn("POST"); .thenReturn("POST");
/* test */ /* test */
subsetEndpoint.create(DATABASE_3_ID, request, USER_1_PRINCIPAL, httpServletRequest, null, 0L, 10L); subsetEndpoint.create(DATABASE_3_ID, QUERY_5_SUBSET_DTO, USER_1_PRINCIPAL, httpServletRequest, null, 0L, 10L);
}
@Test
@WithMockUser(username = USER_1_USERNAME, authorities = {"execute-query"})
public void create_forbiddenKeyword_fails() {
final ExecuteStatementDto request = ExecuteStatementDto.builder()
.statement("SELECT COUNT(id) FROM tbl")
.build();
/* mock */
when(httpServletRequest.getMethod())
.thenReturn("POST");
/* test */
assertThrows(QueryNotSupportedException.class, () -> {
subsetEndpoint.create(DATABASE_3_ID, request, USER_1_PRINCIPAL, httpServletRequest, null, 0L, 10L);
});
} }
@Test @Test
...@@ -340,39 +348,35 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { ...@@ -340,39 +348,35 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
PaginationException, StorageNotFoundException, DatabaseUnavailableException, StorageUnavailableException, PaginationException, StorageNotFoundException, DatabaseUnavailableException, StorageUnavailableException,
QueryMalformedException, QueryNotFoundException, DatabaseNotFoundException, RemoteUnavailableException, QueryMalformedException, QueryNotFoundException, DatabaseNotFoundException, RemoteUnavailableException,
SQLException, MetadataServiceException, TableNotFoundException, ViewMalformedException, SQLException, MetadataServiceException, TableNotFoundException, ViewMalformedException,
ViewNotFoundException { ViewNotFoundException, ImageNotFoundException {
final Dataset<Row> mock = sparkSession.emptyDataFrame(); final Dataset<Row> mock = sparkSession.emptyDataFrame();
final ExecuteStatementDto request = ExecuteStatementDto.builder()
.statement(QUERY_5_STATEMENT)
.build();
/* mock */ /* mock */
when(credentialService.getDatabase(DATABASE_3_ID)) when(credentialService.getDatabase(DATABASE_3_ID))
.thenReturn(DATABASE_3_PRIVILEGED_DTO); .thenReturn(DATABASE_3_PRIVILEGED_DTO);
when(subsetService.create(any(DatabaseDto.class), eq(QUERY_5_STATEMENT), any(Instant.class), eq(USER_1_ID))) when(subsetService.create(any(DatabaseDto.class), any(SubsetDto.class), any(Instant.class), eq(USER_1_ID)))
.thenReturn(QUERY_5_ID); .thenReturn(QUERY_5_ID);
when(subsetService.findById(any(DatabaseDto.class), eq(QUERY_5_ID))) when(subsetService.findById(any(DatabaseDto.class), eq(QUERY_5_ID)))
.thenReturn(QUERY_5_DTO); .thenReturn(QUERY_5_DTO);
when(subsetService.getData(any(DatabaseDto.class), anyString(), any(Instant.class), eq(0L), eq(10L), eq(null), eq(null))) when(subsetService.getData(any(DatabaseDto.class), anyString()))
.thenReturn(mock); .thenReturn(mock);
when(databaseService.createView(any(DatabaseDto.class), any(CreateViewDto.class))) when(databaseService.createView(any(DatabaseDto.class), anyString(), anyString()))
.thenReturn(QUERY_5_VIEW_DTO); .thenReturn(QUERY_5_VIEW_DTO);
when(databaseService.inspectView(any(DatabaseDto.class), anyString())) when(databaseService.inspectView(any(DatabaseDto.class), anyString()))
.thenReturn(QUERY_5_VIEW_DTO); .thenReturn(QUERY_5_VIEW_DTO);
when(metadataServiceGateway.getIdentifiers(DATABASE_3_ID, QUERY_5_ID))
.thenReturn(List.of());
when(httpServletRequest.getMethod()) when(httpServletRequest.getMethod())
.thenReturn("POST"); .thenReturn("POST");
/* test */ /* test */
subsetEndpoint.create(DATABASE_3_ID, request, USER_1_PRINCIPAL, httpServletRequest, null, null, null); subsetEndpoint.create(DATABASE_3_ID, QUERY_5_SUBSET_DTO, USER_1_PRINCIPAL, httpServletRequest, null, null, null);
} }
@Test @Test
@WithMockUser(username = USER_1_USERNAME, authorities = {"execute-query"}) @WithMockUser(username = USER_1_USERNAME, authorities = {"execute-query"})
public void create_databaseNotFound_fails() throws RemoteUnavailableException, public void create_databaseNotFound_fails() throws RemoteUnavailableException,
DatabaseNotFoundException, MetadataServiceException { DatabaseNotFoundException, MetadataServiceException {
final ExecuteStatementDto request = ExecuteStatementDto.builder()
.statement(QUERY_5_STATEMENT)
.build();
/* mock */ /* mock */
doThrow(DatabaseNotFoundException.class) doThrow(DatabaseNotFoundException.class)
...@@ -383,36 +387,36 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { ...@@ -383,36 +387,36 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
/* test */ /* test */
assertThrows(DatabaseNotFoundException.class, () -> { assertThrows(DatabaseNotFoundException.class, () -> {
subsetEndpoint.create(DATABASE_3_ID, request, USER_1_PRINCIPAL, httpServletRequest, null, null, null); subsetEndpoint.create(DATABASE_3_ID, QUERY_5_SUBSET_DTO, USER_1_PRINCIPAL, httpServletRequest, null, null, null);
}); });
} }
@Test @Test
@WithAnonymousUser @WithAnonymousUser
public void create_publicDataPublicSchemaAnonymous_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, public void create_publicDataPublicSchemaAnonymous_succeeds() throws DatabaseNotFoundException,
MetadataServiceException, UserNotFoundException, QueryStoreInsertException, TableMalformedException, RemoteUnavailableException, MetadataServiceException, UserNotFoundException, QueryStoreInsertException,
NotAllowedException, SQLException, QueryNotFoundException, DatabaseUnavailableException, TableMalformedException, NotAllowedException, SQLException, QueryNotFoundException, PaginationException,
StorageUnavailableException, QueryMalformedException, QueryNotSupportedException, PaginationException, DatabaseUnavailableException, StorageUnavailableException, QueryMalformedException,
StorageNotFoundException, TableNotFoundException, ViewMalformedException, ViewNotFoundException { QueryNotSupportedException, StorageNotFoundException, TableNotFoundException, ViewMalformedException,
ViewNotFoundException, ImageNotFoundException {
final Dataset<Row> mock = sparkSession.emptyDataFrame(); final Dataset<Row> mock = sparkSession.emptyDataFrame();
final ExecuteStatementDto request = ExecuteStatementDto.builder()
.statement(QUERY_5_STATEMENT)
.build();
/* mock */ /* mock */
when(credentialService.getDatabase(DATABASE_4_ID)) when(credentialService.getDatabase(DATABASE_4_ID))
.thenReturn(DATABASE_4_PRIVILEGED_DTO); .thenReturn(DATABASE_4_PRIVILEGED_DTO);
when(subsetService.findById(eq(DATABASE_4_PRIVILEGED_DTO), anyLong())) when(subsetService.findById(eq(DATABASE_4_PRIVILEGED_DTO), any(UUID.class)))
.thenReturn(QUERY_5_DTO); .thenReturn(QUERY_9_DTO);
when(subsetService.getData(any(DatabaseDto.class), anyString(), any(Instant.class), eq(0L), eq(10L), eq(null), eq(null))) when(subsetService.create(eq(DATABASE_4_PRIVILEGED_DTO), any(SubsetDto.class), any(Instant.class), eq(null)))
.thenReturn(QUERY_9_ID);
when(subsetService.getData(any(DatabaseDto.class), anyString()))
.thenReturn(mock); .thenReturn(mock);
when(databaseService.inspectView(any(DatabaseDto.class), anyString())) when(databaseService.inspectView(any(DatabaseDto.class), anyString()))
.thenReturn(QUERY_5_VIEW_DTO); .thenReturn(QUERY_9_VIEW_DTO);
when(httpServletRequest.getMethod()) when(httpServletRequest.getMethod())
.thenReturn("POST"); .thenReturn("POST");
/* test */ /* test */
subsetEndpoint.create(DATABASE_4_ID, request, null, httpServletRequest, null, null, null); subsetEndpoint.create(DATABASE_4_ID, QUERY_9_SUBSET_DTO, null, httpServletRequest, null, null, null);
} }
@Test @Test
...@@ -421,26 +425,28 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { ...@@ -421,26 +425,28 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
MetadataServiceException, UserNotFoundException, QueryStoreInsertException, TableMalformedException, MetadataServiceException, UserNotFoundException, QueryStoreInsertException, TableMalformedException,
NotAllowedException, SQLException, QueryNotFoundException, DatabaseUnavailableException, NotAllowedException, SQLException, QueryNotFoundException, DatabaseUnavailableException,
StorageUnavailableException, QueryMalformedException, QueryNotSupportedException, PaginationException, StorageUnavailableException, QueryMalformedException, QueryNotSupportedException, PaginationException,
StorageNotFoundException, TableNotFoundException, ViewMalformedException, ViewNotFoundException { StorageNotFoundException, TableNotFoundException, ViewMalformedException, ViewNotFoundException,
ImageNotFoundException {
final Dataset<Row> mock = sparkSession.emptyDataFrame(); final Dataset<Row> mock = sparkSession.emptyDataFrame();
final ExecuteStatementDto request = ExecuteStatementDto.builder()
.statement(QUERY_1_STATEMENT)
.build();
/* mock */ /* mock */
when(credentialService.getDatabase(DATABASE_1_ID)) when(credentialService.getDatabase(DATABASE_1_ID))
.thenReturn(DATABASE_1_PRIVILEGED_DTO); .thenReturn(DATABASE_1_PRIVILEGED_DTO);
when(subsetService.findById(eq(DATABASE_1_PRIVILEGED_DTO), anyLong())) when(subsetService.findById(any(DatabaseDto.class), any(UUID.class)))
.thenReturn(QUERY_1_DTO); .thenReturn(QUERY_1_DTO);
when(subsetService.getData(any(DatabaseDto.class), anyString(), any(Instant.class), eq(0L), eq(10L), eq(null), eq(null))) when(subsetService.create(any(DatabaseDto.class), any(SubsetDto.class), any(Instant.class), any(UUID.class)))
.thenReturn(QUERY_1_ID);
when(subsetService.getData(any(DatabaseDto.class), anyString()))
.thenReturn(mock); .thenReturn(mock);
when(databaseService.inspectView(any(DatabaseDto.class), anyString())) when(databaseService.inspectView(any(DatabaseDto.class), anyString()))
.thenReturn(QUERY_1_VIEW_DTO); .thenReturn(QUERY_1_VIEW_DTO);
when(metadataServiceGateway.getIdentifiers(DATABASE_1_ID, QUERY_1_ID))
.thenReturn(List.of(IDENTIFIER_1_BRIEF_DTO, IDENTIFIER_2_BRIEF_DTO));
when(httpServletRequest.getMethod()) when(httpServletRequest.getMethod())
.thenReturn("POST"); .thenReturn("POST");
/* test */ /* test */
subsetEndpoint.create(DATABASE_1_ID, request, USER_1_PRINCIPAL, httpServletRequest, null, null, null); subsetEndpoint.create(DATABASE_1_ID, QUERY_1_SUBSET_DTO, USER_1_PRINCIPAL, httpServletRequest, null, null, null);
} }
@Test @Test
...@@ -449,29 +455,28 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { ...@@ -449,29 +455,28 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
MetadataServiceException, UserNotFoundException, QueryNotFoundException, QueryMalformedException, MetadataServiceException, UserNotFoundException, QueryNotFoundException, QueryMalformedException,
TableNotFoundException, RemoteUnavailableException { TableNotFoundException, RemoteUnavailableException {
final Dataset<Row> mock = sparkSession.emptyDataFrame(); final Dataset<Row> mock = sparkSession.emptyDataFrame();
final ExecuteStatementDto request = ExecuteStatementDto.builder()
.statement(QUERY_5_STATEMENT)
.build();
/* mock */ /* mock */
when(credentialService.getDatabase(DATABASE_2_ID)) when(credentialService.getDatabase(DATABASE_2_ID))
.thenReturn(DATABASE_2_PRIVILEGED_DTO); .thenReturn(DATABASE_2_PRIVILEGED_DTO);
when(subsetService.findById(eq(DATABASE_2_PRIVILEGED_DTO), anyLong())) when(subsetService.findById(eq(DATABASE_2_PRIVILEGED_DTO), any(UUID.class)))
.thenReturn(QUERY_2_DTO); .thenReturn(QUERY_8_DTO);
when(subsetService.getData(any(DatabaseDto.class), anyString(), any(Instant.class), eq(0L), eq(10L), eq(null), eq(null))) when(subsetService.getData(any(DatabaseDto.class), anyString()))
.thenReturn(mock); .thenReturn(mock);
when(metadataServiceGateway.getIdentifiers(DATABASE_2_ID, QUERY_8_ID))
.thenReturn(List.of());
when(httpServletRequest.getMethod()) when(httpServletRequest.getMethod())
.thenReturn("POST"); .thenReturn("POST");
/* test */ /* test */
assertThrows(NotAllowedException.class, () -> { assertThrows(NotAllowedException.class, () -> {
subsetEndpoint.create(DATABASE_2_ID, request, null, httpServletRequest, null, null, null); subsetEndpoint.create(DATABASE_2_ID, QUERY_8_SUBSET_DTO, null, httpServletRequest, null, null, null);
}); });
} }
@Test @Test
public void getData_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, UserNotFoundException, public void getData_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, UserNotFoundException,
NotAllowedException, SQLException, QueryNotFoundException, TableMalformedException, QueryMalformedException, NotAllowedException, SQLException, QueryNotFoundException, QueryMalformedException,
DatabaseUnavailableException, PaginationException, MetadataServiceException, TableNotFoundException, DatabaseUnavailableException, PaginationException, MetadataServiceException, TableNotFoundException,
ViewNotFoundException, ViewMalformedException { ViewNotFoundException, ViewMalformedException {
final Dataset<Row> mock = sparkSession.emptyDataFrame(); final Dataset<Row> mock = sparkSession.emptyDataFrame();
...@@ -483,10 +488,12 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { ...@@ -483,10 +488,12 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
.thenReturn(QUERY_5_DTO); .thenReturn(QUERY_5_DTO);
when(subsetService.reExecuteCount(DATABASE_3_PRIVILEGED_DTO, QUERY_5_DTO)) when(subsetService.reExecuteCount(DATABASE_3_PRIVILEGED_DTO, QUERY_5_DTO))
.thenReturn(QUERY_5_RESULT_NUMBER); .thenReturn(QUERY_5_RESULT_NUMBER);
when(subsetService.getData(any(DatabaseDto.class), anyString(), any(Instant.class), eq(0L), eq(10L), eq(null), eq(null))) when(subsetService.getData(any(DatabaseDto.class), anyString()))
.thenReturn(mock); .thenReturn(mock);
when(databaseService.inspectView(any(DatabaseDto.class), anyString())) when(databaseService.inspectView(any(DatabaseDto.class), anyString()))
.thenReturn(QUERY_5_VIEW_DTO); .thenReturn(QUERY_5_VIEW_DTO);
when(metadataServiceGateway.getIdentifiers(DATABASE_3_ID, QUERY_5_ID))
.thenReturn(List.of());
when(httpServletRequest.getMethod()) when(httpServletRequest.getMethod())
.thenReturn("GET"); .thenReturn("GET");
...@@ -523,9 +530,9 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { ...@@ -523,9 +530,9 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
@Test @Test
@WithMockUser(username = USER_1_USERNAME) @WithMockUser(username = USER_1_USERNAME)
public void getData_private_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, public void getData_private_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException,
UserNotFoundException, DatabaseUnavailableException, NotAllowedException, TableMalformedException, UserNotFoundException, DatabaseUnavailableException, NotAllowedException, QueryMalformedException,
QueryMalformedException, QueryNotFoundException, PaginationException, SQLException, QueryNotFoundException, PaginationException, SQLException, MetadataServiceException,
MetadataServiceException, TableNotFoundException, ViewNotFoundException, ViewMalformedException { TableNotFoundException, ViewNotFoundException, ViewMalformedException {
final Dataset<Row> mock = sparkSession.emptyDataFrame(); final Dataset<Row> mock = sparkSession.emptyDataFrame();
/* mock */ /* mock */
...@@ -535,10 +542,12 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { ...@@ -535,10 +542,12 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
.thenReturn(QUERY_1_DTO); .thenReturn(QUERY_1_DTO);
when(subsetService.reExecuteCount(DATABASE_1_PRIVILEGED_DTO, QUERY_1_DTO)) when(subsetService.reExecuteCount(DATABASE_1_PRIVILEGED_DTO, QUERY_1_DTO))
.thenReturn(QUERY_1_RESULT_NUMBER); .thenReturn(QUERY_1_RESULT_NUMBER);
when(subsetService.getData(any(DatabaseDto.class), anyString(), any(Instant.class), eq(0L), eq(10L), eq(null), eq(null))) when(subsetService.getData(any(DatabaseDto.class), anyString()))
.thenReturn(mock); .thenReturn(mock);
when(databaseService.inspectView(any(DatabaseDto.class), anyString())) when(databaseService.inspectView(any(DatabaseDto.class), anyString()))
.thenReturn(QUERY_1_VIEW_DTO); .thenReturn(QUERY_1_VIEW_DTO);
when(metadataServiceGateway.getIdentifiers(DATABASE_1_ID, QUERY_1_ID))
.thenReturn(List.of(IDENTIFIER_1_BRIEF_DTO, IDENTIFIER_2_BRIEF_DTO));
when(httpServletRequest.getMethod()) when(httpServletRequest.getMethod())
.thenReturn("GET"); .thenReturn("GET");
...@@ -584,9 +593,9 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { ...@@ -584,9 +593,9 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
@Test @Test
@WithMockUser(username = USER_1_USERNAME) @WithMockUser(username = USER_1_USERNAME)
public void getData_privateHead_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, public void getData_privateHead_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException,
UserNotFoundException, DatabaseUnavailableException, NotAllowedException, TableMalformedException, UserNotFoundException, DatabaseUnavailableException, NotAllowedException, QueryMalformedException,
QueryMalformedException, QueryNotFoundException, PaginationException, SQLException, QueryNotFoundException, PaginationException, SQLException, MetadataServiceException,
MetadataServiceException, TableNotFoundException, ViewNotFoundException, ViewMalformedException { TableNotFoundException, ViewNotFoundException, ViewMalformedException {
/* mock */ /* mock */
when(credentialService.getDatabase(DATABASE_1_ID)) when(credentialService.getDatabase(DATABASE_1_ID))
...@@ -705,7 +714,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { ...@@ -705,7 +714,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
}); });
} }
protected List<QueryDto> generic_list(Long databaseId, DatabaseDto database, Principal principal) protected List<QueryDto> generic_list(UUID databaseId, DatabaseDto database, Principal principal)
throws NotAllowedException, DatabaseUnavailableException, QueryNotFoundException, DatabaseNotFoundException, throws NotAllowedException, DatabaseUnavailableException, QueryNotFoundException, DatabaseNotFoundException,
RemoteUnavailableException, MetadataServiceException { RemoteUnavailableException, MetadataServiceException {
...@@ -725,11 +734,11 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { ...@@ -725,11 +734,11 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest {
return response.getBody(); return response.getBody();
} }
protected void generic_findById(Long databaseId, Long subsetId, String accept, Instant timestamp, protected void generic_findById(UUID databaseId, UUID subsetId, String accept, Instant timestamp,
Principal principal) throws UserNotFoundException, DatabaseUnavailableException, Principal principal) throws UserNotFoundException, DatabaseUnavailableException,
StorageUnavailableException, NotAllowedException, QueryMalformedException, QueryNotFoundException, StorageUnavailableException, NotAllowedException, QueryMalformedException, QueryNotFoundException,
DatabaseNotFoundException, RemoteUnavailableException, FormatNotAvailableException, DatabaseNotFoundException, RemoteUnavailableException, FormatNotAvailableException,
MetadataServiceException, TableNotFoundException, ViewMalformedException { MetadataServiceException, TableNotFoundException {
/* test */ /* test */
final ResponseEntity<?> response = subsetEndpoint.findById(databaseId, subsetId, accept, timestamp, principal); final ResponseEntity<?> response = subsetEndpoint.findById(databaseId, subsetId, accept, timestamp, principal);
......
...@@ -4,10 +4,11 @@ import at.tuwien.api.database.DatabaseAccessDto; ...@@ -4,10 +4,11 @@ import at.tuwien.api.database.DatabaseAccessDto;
import at.tuwien.api.database.DatabaseDto; import at.tuwien.api.database.DatabaseDto;
import at.tuwien.api.database.query.ImportDto; import at.tuwien.api.database.query.ImportDto;
import at.tuwien.api.database.table.*; import at.tuwien.api.database.table.*;
import at.tuwien.api.database.table.internal.TableCreateDto;
import at.tuwien.endpoints.TableEndpoint; import at.tuwien.endpoints.TableEndpoint;
import at.tuwien.exception.*; import at.tuwien.exception.*;
import at.tuwien.gateway.MetadataServiceGateway; import at.tuwien.gateway.MetadataServiceGateway;
import at.tuwien.service.CredentialService; import at.tuwien.service.CacheService;
import at.tuwien.service.DatabaseService; import at.tuwien.service.DatabaseService;
import at.tuwien.service.SubsetService; import at.tuwien.service.SubsetService;
import at.tuwien.service.TableService; import at.tuwien.service.TableService;
...@@ -68,7 +69,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -68,7 +69,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
private DatabaseService databaseService; private DatabaseService databaseService;
@MockBean @MockBean
private CredentialService credentialService; private CacheService credentialService;
@MockBean @MockBean
private MetadataServiceGateway metadataServiceGateway; private MetadataServiceGateway metadataServiceGateway;
...@@ -103,10 +104,10 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -103,10 +104,10 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
/* mock */ /* mock */
when(credentialService.getDatabase(DATABASE_1_ID)) when(credentialService.getDatabase(DATABASE_1_ID))
.thenReturn(DATABASE_1_PRIVILEGED_DTO); .thenReturn(DATABASE_1_PRIVILEGED_DTO);
when(databaseService.createTable(DATABASE_1_PRIVILEGED_DTO, TABLE_4_CREATE_INTERNAL_DTO)) when(databaseService.createTable(any(DatabaseDto.class), any(TableCreateDto.class)))
.thenReturn(TABLE_4_PRIVILEGED_DTO); .thenReturn(TABLE_4_DTO);
when(databaseService.inspectTable(DATABASE_1_PRIVILEGED_DTO, TABLE_4_INTERNALNAME)) when(databaseService.inspectTable(any(DatabaseDto.class), anyString()))
.thenReturn(TABLE_4_PRIVILEGED_DTO); .thenReturn(TABLE_4_DTO);
/* test */ /* test */
final ResponseEntity<TableDto> response = tableEndpoint.create(DATABASE_1_ID, TABLE_4_CREATE_INTERNAL_DTO); final ResponseEntity<TableDto> response = tableEndpoint.create(DATABASE_1_ID, TABLE_4_CREATE_INTERNAL_DTO);
...@@ -170,12 +171,14 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -170,12 +171,14 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
@Test @Test
@WithAnonymousUser @WithAnonymousUser
public void statistic_succeeds() throws DatabaseUnavailableException, TableNotFoundException, SQLException, public void statistic_succeeds() throws DatabaseUnavailableException, TableNotFoundException, SQLException,
TableMalformedException, RemoteUnavailableException, MetadataServiceException { TableMalformedException, RemoteUnavailableException, MetadataServiceException, DatabaseNotFoundException {
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID)) when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID))
.thenReturn(TABLE_8_PRIVILEGED_DTO); .thenReturn(TABLE_8_DTO);
when(tableService.getStatistics(any(TableDto.class))) when(credentialService.getDatabase(DATABASE_3_ID))
.thenReturn(DATABASE_3_PRIVILEGED_DTO);
when(tableService.getStatistics(any(DatabaseDto.class), any(TableDto.class)))
.thenReturn(TABLE_8_STATISTIC_DTO); .thenReturn(TABLE_8_STATISTIC_DTO);
/* test */ /* test */
...@@ -186,14 +189,16 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -186,14 +189,16 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
@Test @Test
@WithAnonymousUser @WithAnonymousUser
public void statistic_unavailable_fails() throws TableNotFoundException, TableMalformedException, public void statistic_unavailable_fails() throws TableNotFoundException, TableMalformedException,
RemoteUnavailableException, MetadataServiceException, SQLException { RemoteUnavailableException, MetadataServiceException, SQLException, DatabaseNotFoundException {
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID)) when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID))
.thenReturn(TABLE_8_PRIVILEGED_DTO); .thenReturn(TABLE_8_DTO);
when(credentialService.getDatabase(DATABASE_3_ID))
.thenReturn(DATABASE_3_PRIVILEGED_DTO);
doThrow(SQLException.class) doThrow(SQLException.class)
.when(tableService) .when(tableService)
.getStatistics(any(TableDto.class)); .getStatistics(any(DatabaseDto.class), any(TableDto.class));
/* test */ /* test */
assertThrows(DatabaseUnavailableException.class, () -> { assertThrows(DatabaseUnavailableException.class, () -> {
...@@ -220,14 +225,17 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -220,14 +225,17 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
@Test @Test
@WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"}) @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
public void delete_succeeds() throws RemoteUnavailableException, DatabaseUnavailableException, public void delete_succeeds() throws RemoteUnavailableException, DatabaseUnavailableException,
TableNotFoundException, QueryMalformedException, SQLException, MetadataServiceException { TableNotFoundException, QueryMalformedException, SQLException, MetadataServiceException,
DatabaseNotFoundException {
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_1_ID, TABLE_1_ID)) when(credentialService.getTable(DATABASE_1_ID, TABLE_1_ID))
.thenReturn(TABLE_1_PRIVILEGED_DTO); .thenReturn(TABLE_1_DTO);
when(credentialService.getDatabase(DATABASE_1_ID))
.thenReturn(DATABASE_1_PRIVILEGED_DTO);
doNothing() doNothing()
.when(tableService) .when(tableService)
.delete(TABLE_1_PRIVILEGED_DTO); .delete(DATABASE_1_DTO, TABLE_1_DTO);
/* test */ /* test */
final ResponseEntity<Void> response = tableEndpoint.delete(DATABASE_1_ID, TABLE_1_ID); final ResponseEntity<Void> response = tableEndpoint.delete(DATABASE_1_ID, TABLE_1_ID);
...@@ -263,14 +271,16 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -263,14 +271,16 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
@Test @Test
@WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"}) @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
public void delete_unavailable_fails() throws RemoteUnavailableException, TableNotFoundException, SQLException, public void delete_unavailable_fails() throws RemoteUnavailableException, TableNotFoundException, SQLException,
MetadataServiceException, QueryMalformedException { MetadataServiceException, QueryMalformedException, DatabaseNotFoundException {
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_1_ID, TABLE_1_ID)) when(credentialService.getTable(DATABASE_1_ID, TABLE_1_ID))
.thenReturn(TABLE_1_PRIVILEGED_DTO); .thenReturn(TABLE_1_DTO);
when(credentialService.getDatabase(DATABASE_1_ID))
.thenReturn(DATABASE_1_PRIVILEGED_DTO);
doThrow(SQLException.class) doThrow(SQLException.class)
.when(tableService) .when(tableService)
.delete(TABLE_1_PRIVILEGED_DTO); .delete(any(DatabaseDto.class), any(TableDto.class));
/* test */ /* test */
assertThrows(DatabaseUnavailableException.class, () -> { assertThrows(DatabaseUnavailableException.class, () -> {
...@@ -286,17 +296,17 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -286,17 +296,17 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
final Dataset<Row> mock = sparkSession.emptyDataFrame(); final Dataset<Row> mock = sparkSession.emptyDataFrame();
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID)) when(credentialService.getTable(DATABASE_1_ID, TABLE_4_ID))
.thenReturn(TABLE_8_PRIVILEGED_DTO); .thenReturn(TABLE_4_DTO);
when(credentialService.getDatabase(DATABASE_3_ID)) when(credentialService.getDatabase(DATABASE_1_ID))
.thenReturn(DATABASE_3_PRIVILEGED_DTO); .thenReturn(DATABASE_1_PRIVILEGED_DTO);
when(subsetService.getData(any(DatabaseDto.class), anyString(), any(Instant.class), eq(0L), eq(10L), eq(null), eq(null))) when(subsetService.getData(any(DatabaseDto.class), anyString()))
.thenReturn(mock); .thenReturn(mock);
when(httpServletRequest.getMethod()) when(httpServletRequest.getMethod())
.thenReturn("GET"); .thenReturn("GET");
/* test */ /* test */
final ResponseEntity<List<Map<String, Object>>> response = tableEndpoint.getData(DATABASE_3_ID, TABLE_8_ID, null, null, null, httpServletRequest, null); final ResponseEntity<List<Map<String, Object>>> response = tableEndpoint.getData(DATABASE_1_ID, TABLE_4_ID, null, null, null, httpServletRequest, null);
assertEquals(HttpStatus.OK, response.getStatusCode()); assertEquals(HttpStatus.OK, response.getStatusCode());
} }
...@@ -309,17 +319,19 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -309,17 +319,19 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
final Dataset<Row> mock = sparkSession.emptyDataFrame(); final Dataset<Row> mock = sparkSession.emptyDataFrame();
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID)) when(credentialService.getTable(DATABASE_2_ID, TABLE_5_ID))
.thenReturn(TABLE_8_PRIVILEGED_DTO); .thenReturn(TABLE_5_DTO);
when(tableService.getCount(eq(TABLE_8_PRIVILEGED_DTO), any(Instant.class))) when(credentialService.getDatabase(DATABASE_2_ID))
.thenReturn(DATABASE_2_PRIVILEGED_DTO);
when(tableService.getCount(any(DatabaseDto.class), any(TableDto.class), any(Instant.class)))
.thenReturn(3L); .thenReturn(3L);
when(subsetService.getData(eq(DATABASE_3_PRIVILEGED_DTO), anyString(), any(Instant.class), eq(0L), eq(10L), eq(null), eq(null))) when(subsetService.getData(eq(DATABASE_2_DTO), anyString()))
.thenReturn(mock); .thenReturn(mock);
when(httpServletRequest.getMethod()) when(httpServletRequest.getMethod())
.thenReturn("HEAD"); .thenReturn("HEAD");
/* test */ /* test */
final ResponseEntity<List<Map<String, Object>>> response = tableEndpoint.getData(DATABASE_3_ID, TABLE_8_ID, null, null, null, httpServletRequest, null); final ResponseEntity<List<Map<String, Object>>> response = tableEndpoint.getData(DATABASE_2_ID, TABLE_5_ID, null, null, null, httpServletRequest, null);
assertEquals(HttpStatus.OK, response.getStatusCode()); assertEquals(HttpStatus.OK, response.getStatusCode());
assertNotNull(response.getHeaders().get("Access-Control-Expose-Headers")); assertNotNull(response.getHeaders().get("Access-Control-Expose-Headers"));
assertEquals("X-Count", response.getHeaders().get("Access-Control-Expose-Headers").get(0)); assertEquals("X-Count", response.getHeaders().get("Access-Control-Expose-Headers").get(0));
...@@ -335,7 +347,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -335,7 +347,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_1_ID, TABLE_1_ID)) when(credentialService.getTable(DATABASE_1_ID, TABLE_1_ID))
.thenReturn(TABLE_1_PRIVILEGED_DTO); .thenReturn(TABLE_1_DTO);
/* test */ /* test */
assertThrows(NotAllowedException.class, () -> { assertThrows(NotAllowedException.class, () -> {
...@@ -350,7 +362,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -350,7 +362,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_1_ID, TABLE_1_ID)) when(credentialService.getTable(DATABASE_1_ID, TABLE_1_ID))
.thenReturn(TABLE_1_PRIVILEGED_DTO); .thenReturn(TABLE_1_DTO);
doThrow(NotAllowedException.class) doThrow(NotAllowedException.class)
.when(credentialService) .when(credentialService)
.getAccess(DATABASE_1_ID, USER_2_ID); .getAccess(DATABASE_1_ID, USER_2_ID);
...@@ -361,25 +373,42 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -361,25 +373,42 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
}); });
} }
@Test
@WithAnonymousUser
public void getData_notAllowed_fails() throws TableNotFoundException, RemoteUnavailableException,
MetadataServiceException{
/* mock */
when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID))
.thenReturn(TABLE_8_DTO);
when(httpServletRequest.getMethod())
.thenReturn("GET");
/* test */
assertThrows(NotAllowedException.class, () -> {
tableEndpoint.getData(DATABASE_3_ID, TABLE_8_ID, null, null, null, httpServletRequest, null);
});
}
@Test @Test
@WithAnonymousUser @WithAnonymousUser
public void getData_unavailable_fails() throws TableNotFoundException, RemoteUnavailableException, public void getData_unavailable_fails() throws TableNotFoundException, RemoteUnavailableException,
MetadataServiceException, QueryMalformedException, DatabaseNotFoundException { MetadataServiceException, QueryMalformedException, DatabaseNotFoundException {
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID)) when(credentialService.getTable(DATABASE_2_ID, TABLE_5_ID))
.thenReturn(TABLE_8_PRIVILEGED_DTO); .thenReturn(TABLE_5_DTO);
when(credentialService.getDatabase(DATABASE_3_ID)) when(credentialService.getDatabase(DATABASE_2_ID))
.thenReturn(DATABASE_3_PRIVILEGED_DTO); .thenReturn(DATABASE_2_DTO);
doThrow(QueryMalformedException.class) doThrow(QueryMalformedException.class)
.when(subsetService) .when(subsetService)
.getData(any(DatabaseDto.class), anyString(), any(Instant.class), eq(0L), eq(10L), eq(null), eq(null)); .getData(any(DatabaseDto.class), anyString());
when(httpServletRequest.getMethod()) when(httpServletRequest.getMethod())
.thenReturn("GET"); .thenReturn("GET");
/* test */ /* test */
assertThrows(DatabaseUnavailableException.class, () -> { assertThrows(DatabaseUnavailableException.class, () -> {
tableEndpoint.getData(DATABASE_3_ID, TABLE_8_ID, null, null, null, httpServletRequest, null); tableEndpoint.getData(DATABASE_2_ID, TABLE_5_ID, null, null, null, httpServletRequest, null);
}); });
} }
...@@ -390,7 +419,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -390,7 +419,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_1_ID, TABLE_1_ID)) when(credentialService.getTable(DATABASE_1_ID, TABLE_1_ID))
.thenReturn(TABLE_1_PRIVILEGED_DTO); .thenReturn(TABLE_1_DTO);
doThrow(RemoteUnavailableException.class) doThrow(RemoteUnavailableException.class)
.when(credentialService) .when(credentialService)
.getAccess(DATABASE_1_ID, USER_2_ID); .getAccess(DATABASE_1_ID, USER_2_ID);
...@@ -411,12 +440,12 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -411,12 +440,12 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_1_ID, TABLE_1_ID)) when(credentialService.getTable(DATABASE_1_ID, TABLE_1_ID))
.thenReturn(TABLE_1_PRIVILEGED_DTO); .thenReturn(TABLE_1_DTO);
when(credentialService.getDatabase(DATABASE_1_ID)) when(credentialService.getDatabase(DATABASE_1_ID))
.thenReturn(DATABASE_1_PRIVILEGED_DTO); .thenReturn(DATABASE_1_PRIVILEGED_DTO);
when(credentialService.getAccess(DATABASE_1_ID, USER_2_ID)) when(credentialService.getAccess(DATABASE_1_ID, USER_2_ID))
.thenReturn(access); .thenReturn(access);
when(subsetService.getData(any(DatabaseDto.class), anyString(), any(Instant.class), eq(0L), eq(10L), eq(null), eq(null))) when(subsetService.getData(any(DatabaseDto.class), anyString()))
.thenReturn(mock); .thenReturn(mock);
when(httpServletRequest.getMethod()) when(httpServletRequest.getMethod())
.thenReturn("GET"); .thenReturn("GET");
...@@ -446,7 +475,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -446,7 +475,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
@WithMockUser(username = USER_1_USERNAME, authorities = {"insert-table-data"}) @WithMockUser(username = USER_1_USERNAME, authorities = {"insert-table-data"})
public void insertRawTuple_succeeds() throws DatabaseUnavailableException, TableNotFoundException, public void insertRawTuple_succeeds() throws DatabaseUnavailableException, TableNotFoundException,
TableMalformedException, NotAllowedException, QueryMalformedException, RemoteUnavailableException, TableMalformedException, NotAllowedException, QueryMalformedException, RemoteUnavailableException,
SQLException, StorageUnavailableException, StorageNotFoundException, MetadataServiceException { SQLException, StorageUnavailableException, StorageNotFoundException, MetadataServiceException, DatabaseNotFoundException {
final TupleDto request = TupleDto.builder() final TupleDto request = TupleDto.builder()
.data(new HashMap<>() {{ .data(new HashMap<>() {{
put(COLUMN_8_1_INTERNAL_NAME, 7L); put(COLUMN_8_1_INTERNAL_NAME, 7L);
...@@ -456,12 +485,14 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -456,12 +485,14 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID)) when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID))
.thenReturn(TABLE_8_PRIVILEGED_DTO); .thenReturn(TABLE_8_DTO);
when(credentialService.getDatabase(DATABASE_3_ID))
.thenReturn(DATABASE_3_PRIVILEGED_DTO);
when(credentialService.getAccess(DATABASE_3_ID, USER_1_ID)) when(credentialService.getAccess(DATABASE_3_ID, USER_1_ID))
.thenReturn(DATABASE_3_USER_1_WRITE_OWN_ACCESS_DTO); .thenReturn(DATABASE_3_USER_1_WRITE_OWN_ACCESS_DTO);
doNothing() doNothing()
.when(tableService) .when(tableService)
.createTuple(TABLE_8_PRIVILEGED_DTO, request); .createTuple(DATABASE_3_PRIVILEGED_DTO, TABLE_8_DTO, request);
doNothing() doNothing()
.when(metadataServiceGateway) .when(metadataServiceGateway)
.updateTableStatistics(DATABASE_3_ID, TABLE_8_ID, TOKEN_ACCESS_TOKEN); .updateTableStatistics(DATABASE_3_ID, TABLE_8_ID, TOKEN_ACCESS_TOKEN);
...@@ -473,7 +504,8 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -473,7 +504,8 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
@Test @Test
@WithMockUser(username = USER_3_USERNAME) @WithMockUser(username = USER_3_USERNAME)
public void insertRawTuple_noRole_fails() { public void insertRawTuple_noRole_fails() throws DatabaseNotFoundException, RemoteUnavailableException,
MetadataServiceException {
final TupleDto request = TupleDto.builder() final TupleDto request = TupleDto.builder()
.data(new HashMap<>() {{ .data(new HashMap<>() {{
put(COLUMN_8_1_INTERNAL_NAME, 7L); put(COLUMN_8_1_INTERNAL_NAME, 7L);
...@@ -481,6 +513,10 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -481,6 +513,10 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
}}) }})
.build(); .build();
/* mock */
when(credentialService.getDatabase(DATABASE_3_ID))
.thenReturn(DATABASE_3_PRIVILEGED_DTO);
/* test */ /* test */
assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> { assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> {
tableEndpoint.insertRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL, TOKEN_ACCESS_TOKEN); tableEndpoint.insertRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL, TOKEN_ACCESS_TOKEN);
...@@ -490,7 +526,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -490,7 +526,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
@Test @Test
@WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"}) @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"})
public void insertRawTuple_tableNotFound_fails() throws TableNotFoundException, RemoteUnavailableException, public void insertRawTuple_tableNotFound_fails() throws TableNotFoundException, RemoteUnavailableException,
MetadataServiceException { MetadataServiceException, DatabaseNotFoundException {
final TupleDto request = TupleDto.builder() final TupleDto request = TupleDto.builder()
.data(new HashMap<>() {{ .data(new HashMap<>() {{
put(COLUMN_8_1_INTERNAL_NAME, 7L); put(COLUMN_8_1_INTERNAL_NAME, 7L);
...@@ -499,6 +535,8 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -499,6 +535,8 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
.build(); .build();
/* mock */ /* mock */
when(credentialService.getDatabase(DATABASE_3_ID))
.thenReturn(DATABASE_3_PRIVILEGED_DTO);
doThrow(TableNotFoundException.class) doThrow(TableNotFoundException.class)
.when(credentialService) .when(credentialService)
.getTable(DATABASE_3_ID, TABLE_8_ID); .getTable(DATABASE_3_ID, TABLE_8_ID);
...@@ -512,7 +550,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -512,7 +550,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
@Test @Test
@WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"}) @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"})
public void insertRawTuple_readAccess_fails() throws TableNotFoundException, RemoteUnavailableException, public void insertRawTuple_readAccess_fails() throws TableNotFoundException, RemoteUnavailableException,
NotAllowedException, MetadataServiceException { NotAllowedException, MetadataServiceException, DatabaseNotFoundException {
final TupleDto request = TupleDto.builder() final TupleDto request = TupleDto.builder()
.data(new HashMap<>() {{ .data(new HashMap<>() {{
put(COLUMN_8_1_INTERNAL_NAME, 7L); put(COLUMN_8_1_INTERNAL_NAME, 7L);
...@@ -522,7 +560,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -522,7 +560,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID)) when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID))
.thenReturn(TABLE_8_PRIVILEGED_DTO); .thenReturn(TABLE_8_DTO);
when(credentialService.getDatabase(DATABASE_3_ID))
.thenReturn(DATABASE_3_PRIVILEGED_DTO);
when(credentialService.getAccess(DATABASE_3_ID, USER_3_ID)) when(credentialService.getAccess(DATABASE_3_ID, USER_3_ID))
.thenReturn(DATABASE_3_USER_3_READ_ACCESS_DTO); .thenReturn(DATABASE_3_USER_3_READ_ACCESS_DTO);
...@@ -536,7 +576,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -536,7 +576,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
@WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"}) @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"})
public void insertRawTuple_unavailable_fails() throws TableNotFoundException, RemoteUnavailableException, public void insertRawTuple_unavailable_fails() throws TableNotFoundException, RemoteUnavailableException,
NotAllowedException, MetadataServiceException, TableMalformedException, StorageUnavailableException, NotAllowedException, MetadataServiceException, TableMalformedException, StorageUnavailableException,
SQLException, QueryMalformedException, StorageNotFoundException { SQLException, QueryMalformedException, StorageNotFoundException, DatabaseNotFoundException {
final TupleDto request = TupleDto.builder() final TupleDto request = TupleDto.builder()
.data(new HashMap<>() {{ .data(new HashMap<>() {{
put(COLUMN_8_1_INTERNAL_NAME, 7L); put(COLUMN_8_1_INTERNAL_NAME, 7L);
...@@ -546,12 +586,14 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -546,12 +586,14 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID)) when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID))
.thenReturn(TABLE_8_PRIVILEGED_DTO); .thenReturn(TABLE_8_DTO);
when(credentialService.getDatabase(DATABASE_3_ID))
.thenReturn(DATABASE_3_PRIVILEGED_DTO);
when(credentialService.getAccess(DATABASE_3_ID, USER_1_ID)) when(credentialService.getAccess(DATABASE_3_ID, USER_1_ID))
.thenReturn(DATABASE_3_USER_1_WRITE_OWN_ACCESS_DTO); .thenReturn(DATABASE_3_USER_1_WRITE_OWN_ACCESS_DTO);
doThrow(SQLException.class) doThrow(SQLException.class)
.when(tableService) .when(tableService)
.createTuple(TABLE_8_PRIVILEGED_DTO, request); .createTuple(DATABASE_3_PRIVILEGED_DTO, TABLE_8_DTO, request);
/* test */ /* test */
assertThrows(DatabaseUnavailableException.class, () -> { assertThrows(DatabaseUnavailableException.class, () -> {
...@@ -563,7 +605,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -563,7 +605,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
@WithMockUser(username = USER_1_USERNAME, authorities = {"insert-table-data"}) @WithMockUser(username = USER_1_USERNAME, authorities = {"insert-table-data"})
public void insertRawTuple_writeOwnAccess_succeeds() throws TableNotFoundException, RemoteUnavailableException, public void insertRawTuple_writeOwnAccess_succeeds() throws TableNotFoundException, RemoteUnavailableException,
NotAllowedException, DatabaseUnavailableException, TableMalformedException, QueryMalformedException, NotAllowedException, DatabaseUnavailableException, TableMalformedException, QueryMalformedException,
StorageUnavailableException, StorageNotFoundException, MetadataServiceException { StorageUnavailableException, StorageNotFoundException, MetadataServiceException, DatabaseNotFoundException {
final TupleDto request = TupleDto.builder() final TupleDto request = TupleDto.builder()
.data(new HashMap<>() {{ .data(new HashMap<>() {{
put(COLUMN_8_1_INTERNAL_NAME, 7L); put(COLUMN_8_1_INTERNAL_NAME, 7L);
...@@ -573,7 +615,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -573,7 +615,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID)) when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID))
.thenReturn(TABLE_8_PRIVILEGED_DTO); .thenReturn(TABLE_8_DTO);
when(credentialService.getDatabase(DATABASE_3_ID))
.thenReturn(DATABASE_3_PRIVILEGED_DTO);
when(credentialService.getAccess(DATABASE_3_ID, USER_1_ID)) when(credentialService.getAccess(DATABASE_3_ID, USER_1_ID))
.thenReturn(DATABASE_3_USER_1_WRITE_OWN_ACCESS_DTO); .thenReturn(DATABASE_3_USER_1_WRITE_OWN_ACCESS_DTO);
...@@ -584,7 +628,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -584,7 +628,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
@Test @Test
@WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"}) @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"})
public void insertRawTuple_writeOwnAccessForeign_fails() throws TableNotFoundException, RemoteUnavailableException, public void insertRawTuple_writeOwnAccessForeign_fails() throws TableNotFoundException, RemoteUnavailableException,
NotAllowedException, MetadataServiceException { NotAllowedException, MetadataServiceException, DatabaseNotFoundException {
final TupleDto request = TupleDto.builder() final TupleDto request = TupleDto.builder()
.data(new HashMap<>() {{ .data(new HashMap<>() {{
put(COLUMN_8_1_INTERNAL_NAME, 7L); put(COLUMN_8_1_INTERNAL_NAME, 7L);
...@@ -594,7 +638,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -594,7 +638,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID)) when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID))
.thenReturn(TABLE_8_PRIVILEGED_DTO); .thenReturn(TABLE_8_DTO);
when(credentialService.getDatabase(DATABASE_3_ID))
.thenReturn(DATABASE_3_PRIVILEGED_DTO);
when(credentialService.getAccess(DATABASE_3_ID, USER_3_ID)) when(credentialService.getAccess(DATABASE_3_ID, USER_3_ID))
.thenReturn(DATABASE_3_USER_3_WRITE_OWN_ACCESS_DTO); .thenReturn(DATABASE_3_USER_3_WRITE_OWN_ACCESS_DTO);
...@@ -606,9 +652,10 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -606,9 +652,10 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
@Test @Test
@WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"}) @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"})
public void insertRawTuple_writeAllAccessForeign_succeeds() throws TableNotFoundException, RemoteUnavailableException, public void insertRawTuple_writeAllAccessForeign_succeeds() throws TableNotFoundException,
NotAllowedException, DatabaseUnavailableException, TableMalformedException, QueryMalformedException, RemoteUnavailableException, NotAllowedException, DatabaseUnavailableException, TableMalformedException,
StorageUnavailableException, StorageNotFoundException, MetadataServiceException { QueryMalformedException, StorageUnavailableException, StorageNotFoundException, MetadataServiceException,
DatabaseNotFoundException {
final TupleDto request = TupleDto.builder() final TupleDto request = TupleDto.builder()
.data(new HashMap<>() {{ .data(new HashMap<>() {{
put(COLUMN_8_1_INTERNAL_NAME, 7L); put(COLUMN_8_1_INTERNAL_NAME, 7L);
...@@ -618,7 +665,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -618,7 +665,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID)) when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID))
.thenReturn(TABLE_8_PRIVILEGED_DTO); .thenReturn(TABLE_8_DTO);
when(credentialService.getDatabase(DATABASE_3_ID))
.thenReturn(DATABASE_3_PRIVILEGED_DTO);
when(credentialService.getAccess(DATABASE_3_ID, USER_3_ID)) when(credentialService.getAccess(DATABASE_3_ID, USER_3_ID))
.thenReturn(DATABASE_3_USER_3_WRITE_ALL_ACCESS_DTO); .thenReturn(DATABASE_3_USER_3_WRITE_ALL_ACCESS_DTO);
...@@ -630,7 +679,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -630,7 +679,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
@WithMockUser(username = USER_1_USERNAME, authorities = {"insert-table-data"}) @WithMockUser(username = USER_1_USERNAME, authorities = {"insert-table-data"})
public void updateTuple_succeeds() throws DatabaseUnavailableException, TableNotFoundException, public void updateTuple_succeeds() throws DatabaseUnavailableException, TableNotFoundException,
TableMalformedException, NotAllowedException, QueryMalformedException, RemoteUnavailableException, TableMalformedException, NotAllowedException, QueryMalformedException, RemoteUnavailableException,
SQLException, MetadataServiceException { SQLException, MetadataServiceException, DatabaseNotFoundException {
final TupleUpdateDto request = TupleUpdateDto.builder() final TupleUpdateDto request = TupleUpdateDto.builder()
.keys(new HashMap<>() {{ .keys(new HashMap<>() {{
put(COLUMN_8_1_INTERNAL_NAME, 6L); put(COLUMN_8_1_INTERNAL_NAME, 6L);
...@@ -643,12 +692,14 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -643,12 +692,14 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID)) when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID))
.thenReturn(TABLE_8_PRIVILEGED_DTO); .thenReturn(TABLE_8_DTO);
when(credentialService.getDatabase(DATABASE_3_ID))
.thenReturn(DATABASE_3_PRIVILEGED_DTO);
when(credentialService.getAccess(DATABASE_3_ID, USER_1_ID)) when(credentialService.getAccess(DATABASE_3_ID, USER_1_ID))
.thenReturn(DATABASE_3_USER_1_WRITE_OWN_ACCESS_DTO); .thenReturn(DATABASE_3_USER_1_WRITE_OWN_ACCESS_DTO);
doNothing() doNothing()
.when(tableService) .when(tableService)
.updateTuple(TABLE_8_PRIVILEGED_DTO, request); .updateTuple(DATABASE_3_PRIVILEGED_DTO, TABLE_8_DTO, request);
doNothing() doNothing()
.when(metadataServiceGateway) .when(metadataServiceGateway)
.updateTableStatistics(DATABASE_3_ID, TABLE_8_ID, TOKEN_ACCESS_TOKEN); .updateTableStatistics(DATABASE_3_ID, TABLE_8_ID, TOKEN_ACCESS_TOKEN);
...@@ -660,7 +711,8 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -660,7 +711,8 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
@Test @Test
@WithMockUser(username = USER_3_USERNAME) @WithMockUser(username = USER_3_USERNAME)
public void updateTuple_noRole_fails() { public void updateTuple_noRole_fails() throws DatabaseNotFoundException, RemoteUnavailableException,
MetadataServiceException {
final TupleUpdateDto request = TupleUpdateDto.builder() final TupleUpdateDto request = TupleUpdateDto.builder()
.keys(new HashMap<>() {{ .keys(new HashMap<>() {{
put(COLUMN_8_1_INTERNAL_NAME, 6L); put(COLUMN_8_1_INTERNAL_NAME, 6L);
...@@ -671,6 +723,10 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -671,6 +723,10 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
}}) }})
.build(); .build();
/* mock */
when(credentialService.getDatabase(DATABASE_3_ID))
.thenReturn(DATABASE_3_PRIVILEGED_DTO);
/* test */ /* test */
assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> { assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> {
tableEndpoint.updateRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL, TOKEN_ACCESS_TOKEN); tableEndpoint.updateRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL, TOKEN_ACCESS_TOKEN);
...@@ -680,7 +736,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -680,7 +736,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
@Test @Test
@WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"}) @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"})
public void updateTuple_tableNotFound_fails() throws TableNotFoundException, RemoteUnavailableException, public void updateTuple_tableNotFound_fails() throws TableNotFoundException, RemoteUnavailableException,
MetadataServiceException { MetadataServiceException, DatabaseNotFoundException {
final TupleUpdateDto request = TupleUpdateDto.builder() final TupleUpdateDto request = TupleUpdateDto.builder()
.keys(new HashMap<>() {{ .keys(new HashMap<>() {{
put(COLUMN_8_1_INTERNAL_NAME, 6L); put(COLUMN_8_1_INTERNAL_NAME, 6L);
...@@ -692,6 +748,8 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -692,6 +748,8 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
.build(); .build();
/* mock */ /* mock */
when(credentialService.getDatabase(DATABASE_3_ID))
.thenReturn(DATABASE_3_PRIVILEGED_DTO);
doThrow(TableNotFoundException.class) doThrow(TableNotFoundException.class)
.when(credentialService) .when(credentialService)
.getTable(DATABASE_3_ID, TABLE_8_ID); .getTable(DATABASE_3_ID, TABLE_8_ID);
...@@ -705,7 +763,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -705,7 +763,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
@Test @Test
@WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"}) @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"})
public void updateTuple_readAccess_fails() throws TableNotFoundException, RemoteUnavailableException, public void updateTuple_readAccess_fails() throws TableNotFoundException, RemoteUnavailableException,
NotAllowedException, MetadataServiceException { NotAllowedException, MetadataServiceException, DatabaseNotFoundException {
final TupleUpdateDto request = TupleUpdateDto.builder() final TupleUpdateDto request = TupleUpdateDto.builder()
.keys(new HashMap<>() {{ .keys(new HashMap<>() {{
put(COLUMN_8_1_INTERNAL_NAME, 6L); put(COLUMN_8_1_INTERNAL_NAME, 6L);
...@@ -718,7 +776,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -718,7 +776,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID)) when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID))
.thenReturn(TABLE_8_PRIVILEGED_DTO); .thenReturn(TABLE_8_DTO);
when(credentialService.getDatabase(DATABASE_3_ID))
.thenReturn(DATABASE_3_PRIVILEGED_DTO);
when(credentialService.getAccess(DATABASE_3_ID, USER_3_ID)) when(credentialService.getAccess(DATABASE_3_ID, USER_3_ID))
.thenReturn(DATABASE_3_USER_3_READ_ACCESS_DTO); .thenReturn(DATABASE_3_USER_3_READ_ACCESS_DTO);
...@@ -731,7 +791,8 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -731,7 +791,8 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
@Test @Test
@WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"}) @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"})
public void updateTuple_unavailable_fails() throws TableNotFoundException, RemoteUnavailableException, SQLException, public void updateTuple_unavailable_fails() throws TableNotFoundException, RemoteUnavailableException, SQLException,
NotAllowedException, MetadataServiceException, TableMalformedException, QueryMalformedException { NotAllowedException, MetadataServiceException, TableMalformedException, QueryMalformedException,
DatabaseNotFoundException {
final TupleUpdateDto request = TupleUpdateDto.builder() final TupleUpdateDto request = TupleUpdateDto.builder()
.keys(new HashMap<>() {{ .keys(new HashMap<>() {{
put(COLUMN_8_1_INTERNAL_NAME, 6L); put(COLUMN_8_1_INTERNAL_NAME, 6L);
...@@ -744,12 +805,14 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -744,12 +805,14 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID)) when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID))
.thenReturn(TABLE_8_PRIVILEGED_DTO); .thenReturn(TABLE_8_DTO);
when(credentialService.getDatabase(DATABASE_3_ID))
.thenReturn(DATABASE_3_PRIVILEGED_DTO);
when(credentialService.getAccess(DATABASE_3_ID, USER_3_ID)) when(credentialService.getAccess(DATABASE_3_ID, USER_3_ID))
.thenReturn(DATABASE_3_USER_3_WRITE_ALL_ACCESS_DTO); .thenReturn(DATABASE_3_USER_3_WRITE_ALL_ACCESS_DTO);
doThrow(SQLException.class) doThrow(SQLException.class)
.when(tableService) .when(tableService)
.updateTuple(TABLE_8_PRIVILEGED_DTO, request); .updateTuple(DATABASE_3_PRIVILEGED_DTO, TABLE_8_DTO, request);
/* test */ /* test */
assertThrows(DatabaseUnavailableException.class, () -> { assertThrows(DatabaseUnavailableException.class, () -> {
...@@ -761,7 +824,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -761,7 +824,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
@WithMockUser(username = USER_1_USERNAME, authorities = {"insert-table-data"}) @WithMockUser(username = USER_1_USERNAME, authorities = {"insert-table-data"})
public void updateTuple_writeOwnAccess_succeeds() throws DatabaseUnavailableException, TableNotFoundException, public void updateTuple_writeOwnAccess_succeeds() throws DatabaseUnavailableException, TableNotFoundException,
TableMalformedException, NotAllowedException, QueryMalformedException, RemoteUnavailableException, TableMalformedException, NotAllowedException, QueryMalformedException, RemoteUnavailableException,
SQLException, MetadataServiceException { SQLException, MetadataServiceException, DatabaseNotFoundException {
final TupleUpdateDto request = TupleUpdateDto.builder() final TupleUpdateDto request = TupleUpdateDto.builder()
.keys(new HashMap<>() {{ .keys(new HashMap<>() {{
put(COLUMN_8_1_INTERNAL_NAME, 6L); put(COLUMN_8_1_INTERNAL_NAME, 6L);
...@@ -774,12 +837,14 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -774,12 +837,14 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID)) when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID))
.thenReturn(TABLE_8_PRIVILEGED_DTO); .thenReturn(TABLE_8_DTO);
when(credentialService.getDatabase(DATABASE_3_ID))
.thenReturn(DATABASE_3_PRIVILEGED_DTO);
when(credentialService.getAccess(DATABASE_3_ID, USER_1_ID)) when(credentialService.getAccess(DATABASE_3_ID, USER_1_ID))
.thenReturn(DATABASE_3_USER_1_WRITE_OWN_ACCESS_DTO); .thenReturn(DATABASE_3_USER_1_WRITE_OWN_ACCESS_DTO);
doNothing() doNothing()
.when(tableService) .when(tableService)
.updateTuple(TABLE_8_PRIVILEGED_DTO, request); .updateTuple(DATABASE_3_PRIVILEGED_DTO, TABLE_8_DTO, request);
doNothing() doNothing()
.when(metadataServiceGateway) .when(metadataServiceGateway)
.updateTableStatistics(DATABASE_3_ID, TABLE_8_ID, TOKEN_ACCESS_TOKEN); .updateTableStatistics(DATABASE_3_ID, TABLE_8_ID, TOKEN_ACCESS_TOKEN);
...@@ -789,10 +854,84 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -789,10 +854,84 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
assertEquals(HttpStatus.ACCEPTED, response.getStatusCode()); assertEquals(HttpStatus.ACCEPTED, response.getStatusCode());
} }
@Test
@WithMockUser(username = USER_1_USERNAME, authorities = {"system"})
public void update_succeeds() throws DatabaseUnavailableException, TableNotFoundException,
TableMalformedException, RemoteUnavailableException, SQLException, MetadataServiceException,
DatabaseNotFoundException {
/* mock */
when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID))
.thenReturn(TABLE_8_DTO);
when(credentialService.getDatabase(DATABASE_3_ID))
.thenReturn(DATABASE_3_PRIVILEGED_DTO);
doNothing()
.when(tableService)
.updateTable(DATABASE_3_PRIVILEGED_DTO, TABLE_8_DTO, TABLE_8_UPDATE_DTO);
/* test */
final ResponseEntity<TableDto> response = tableEndpoint.update(DATABASE_3_ID, TABLE_8_ID, TABLE_8_UPDATE_DTO);
assertEquals(HttpStatus.ACCEPTED, response.getStatusCode());
}
@Test
@WithMockUser(username = USER_1_USERNAME, authorities = {"system"})
public void update_tableNotFound_fails() throws TableNotFoundException, RemoteUnavailableException,
MetadataServiceException, DatabaseNotFoundException {
/* mock */
when(credentialService.getDatabase(DATABASE_3_ID))
.thenReturn(DATABASE_3_PRIVILEGED_DTO);
doThrow(TableNotFoundException.class)
.when(credentialService)
.getTable(DATABASE_3_ID, TABLE_8_ID);
/* test */
assertThrows(TableNotFoundException.class, () -> {
tableEndpoint.update(DATABASE_3_ID, TABLE_8_ID, TABLE_8_UPDATE_DTO);
});
}
@Test
@WithMockUser(username = USER_1_USERNAME, authorities = {"system"})
public void update_unavailable_fails() throws TableNotFoundException, RemoteUnavailableException,
MetadataServiceException, DatabaseNotFoundException {
/* mock */
when(credentialService.getDatabase(DATABASE_3_ID))
.thenReturn(DATABASE_3_PRIVILEGED_DTO);
doThrow(RemoteUnavailableException.class)
.when(credentialService)
.getTable(DATABASE_3_ID, TABLE_8_ID);
/* test */
assertThrows(RemoteUnavailableException.class, () -> {
tableEndpoint.update(DATABASE_3_ID, TABLE_8_ID, TABLE_8_UPDATE_DTO);
});
}
@Test
@WithMockUser(username = USER_1_USERNAME, authorities = {"system"})
public void update_exception_fails() throws TableNotFoundException, RemoteUnavailableException,
MetadataServiceException, DatabaseNotFoundException {
/* mock */
when(credentialService.getDatabase(DATABASE_3_ID))
.thenReturn(DATABASE_3_PRIVILEGED_DTO);
doThrow(MetadataServiceException.class)
.when(credentialService)
.getTable(DATABASE_3_ID, TABLE_8_ID);
/* test */
assertThrows(MetadataServiceException.class, () -> {
tableEndpoint.update(DATABASE_3_ID, TABLE_8_ID, TABLE_8_UPDATE_DTO);
});
}
@Test @Test
@WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"}) @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"})
public void updateTuple_writeOwnAccessForeign_fails() throws TableNotFoundException, RemoteUnavailableException, public void updateTuple_writeOwnAccessForeign_fails() throws TableNotFoundException, RemoteUnavailableException,
NotAllowedException, MetadataServiceException { NotAllowedException, MetadataServiceException, DatabaseNotFoundException {
final TupleUpdateDto request = TupleUpdateDto.builder() final TupleUpdateDto request = TupleUpdateDto.builder()
.keys(new HashMap<>() {{ .keys(new HashMap<>() {{
put(COLUMN_8_1_INTERNAL_NAME, 6L); put(COLUMN_8_1_INTERNAL_NAME, 6L);
...@@ -805,7 +944,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -805,7 +944,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID)) when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID))
.thenReturn(TABLE_8_PRIVILEGED_DTO); .thenReturn(TABLE_8_DTO);
when(credentialService.getDatabase(DATABASE_3_ID))
.thenReturn(DATABASE_3_PRIVILEGED_DTO);
when(credentialService.getAccess(DATABASE_3_ID, USER_3_ID)) when(credentialService.getAccess(DATABASE_3_ID, USER_3_ID))
.thenReturn(DATABASE_3_USER_3_WRITE_OWN_ACCESS_DTO); .thenReturn(DATABASE_3_USER_3_WRITE_OWN_ACCESS_DTO);
...@@ -819,7 +960,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -819,7 +960,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
@WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"}) @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"})
public void updateTuple_writeAllAccessForeign_succeeds() throws TableNotFoundException, RemoteUnavailableException, public void updateTuple_writeAllAccessForeign_succeeds() throws TableNotFoundException, RemoteUnavailableException,
NotAllowedException, DatabaseUnavailableException, TableMalformedException, QueryMalformedException, NotAllowedException, DatabaseUnavailableException, TableMalformedException, QueryMalformedException,
SQLException, MetadataServiceException { SQLException, MetadataServiceException, DatabaseNotFoundException {
final TupleUpdateDto request = TupleUpdateDto.builder() final TupleUpdateDto request = TupleUpdateDto.builder()
.keys(new HashMap<>() {{ .keys(new HashMap<>() {{
put(COLUMN_8_1_INTERNAL_NAME, 6L); put(COLUMN_8_1_INTERNAL_NAME, 6L);
...@@ -832,12 +973,14 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -832,12 +973,14 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID)) when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID))
.thenReturn(TABLE_8_PRIVILEGED_DTO); .thenReturn(TABLE_8_DTO);
when(credentialService.getDatabase(DATABASE_3_ID))
.thenReturn(DATABASE_3_PRIVILEGED_DTO);
when(credentialService.getAccess(DATABASE_3_ID, USER_3_ID)) when(credentialService.getAccess(DATABASE_3_ID, USER_3_ID))
.thenReturn(DATABASE_3_USER_3_WRITE_ALL_ACCESS_DTO); .thenReturn(DATABASE_3_USER_3_WRITE_ALL_ACCESS_DTO);
doNothing() doNothing()
.when(tableService) .when(tableService)
.updateTuple(TABLE_8_PRIVILEGED_DTO, request); .updateTuple(DATABASE_3_PRIVILEGED_DTO, TABLE_8_DTO, request);
doNothing() doNothing()
.when(metadataServiceGateway) .when(metadataServiceGateway)
.updateTableStatistics(DATABASE_3_ID, TABLE_8_ID, TOKEN_ACCESS_TOKEN); .updateTableStatistics(DATABASE_3_ID, TABLE_8_ID, TOKEN_ACCESS_TOKEN);
...@@ -851,7 +994,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -851,7 +994,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
@WithMockUser(username = USER_1_USERNAME, authorities = {"delete-table-data"}) @WithMockUser(username = USER_1_USERNAME, authorities = {"delete-table-data"})
public void deleteTuple_succeeds() throws DatabaseUnavailableException, TableNotFoundException, public void deleteTuple_succeeds() throws DatabaseUnavailableException, TableNotFoundException,
TableMalformedException, NotAllowedException, QueryMalformedException, RemoteUnavailableException, TableMalformedException, NotAllowedException, QueryMalformedException, RemoteUnavailableException,
SQLException, MetadataServiceException { SQLException, MetadataServiceException, DatabaseNotFoundException {
final TupleDeleteDto request = TupleDeleteDto.builder() final TupleDeleteDto request = TupleDeleteDto.builder()
.keys(new HashMap<>() {{ .keys(new HashMap<>() {{
put(COLUMN_8_1_INTERNAL_NAME, 6L); put(COLUMN_8_1_INTERNAL_NAME, 6L);
...@@ -860,12 +1003,14 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -860,12 +1003,14 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID)) when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID))
.thenReturn(TABLE_8_PRIVILEGED_DTO); .thenReturn(TABLE_8_DTO);
when(credentialService.getDatabase(DATABASE_3_ID))
.thenReturn(DATABASE_3_PRIVILEGED_DTO);
when(credentialService.getAccess(DATABASE_3_ID, USER_1_ID)) when(credentialService.getAccess(DATABASE_3_ID, USER_1_ID))
.thenReturn(DATABASE_3_USER_1_WRITE_OWN_ACCESS_DTO); .thenReturn(DATABASE_3_USER_1_WRITE_OWN_ACCESS_DTO);
doNothing() doNothing()
.when(tableService) .when(tableService)
.deleteTuple(TABLE_8_PRIVILEGED_DTO, request); .deleteTuple(DATABASE_3_PRIVILEGED_DTO, TABLE_8_DTO, request);
doNothing() doNothing()
.when(metadataServiceGateway) .when(metadataServiceGateway)
.updateTableStatistics(DATABASE_3_ID, TABLE_8_ID, TOKEN_ACCESS_TOKEN); .updateTableStatistics(DATABASE_3_ID, TABLE_8_ID, TOKEN_ACCESS_TOKEN);
...@@ -877,13 +1022,18 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -877,13 +1022,18 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
@Test @Test
@WithMockUser(username = USER_3_USERNAME) @WithMockUser(username = USER_3_USERNAME)
public void deleteTuple_noRole_fails() { public void deleteTuple_noRole_fails() throws DatabaseNotFoundException, RemoteUnavailableException,
MetadataServiceException {
final TupleDeleteDto request = TupleDeleteDto.builder() final TupleDeleteDto request = TupleDeleteDto.builder()
.keys(new HashMap<>() {{ .keys(new HashMap<>() {{
put(COLUMN_8_1_INTERNAL_NAME, 6L); put(COLUMN_8_1_INTERNAL_NAME, 6L);
}}) }})
.build(); .build();
/* mock */
when(credentialService.getDatabase(DATABASE_3_ID))
.thenReturn(DATABASE_3_PRIVILEGED_DTO);
/* test */ /* test */
assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> { assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> {
tableEndpoint.deleteRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL, TOKEN_ACCESS_TOKEN); tableEndpoint.deleteRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL, TOKEN_ACCESS_TOKEN);
...@@ -893,7 +1043,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -893,7 +1043,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
@Test @Test
@WithMockUser(username = USER_3_USERNAME, authorities = {"delete-table-data"}) @WithMockUser(username = USER_3_USERNAME, authorities = {"delete-table-data"})
public void deleteTuple_tableNotFound_fails() throws TableNotFoundException, RemoteUnavailableException, public void deleteTuple_tableNotFound_fails() throws TableNotFoundException, RemoteUnavailableException,
MetadataServiceException { MetadataServiceException, DatabaseNotFoundException {
final TupleDeleteDto request = TupleDeleteDto.builder() final TupleDeleteDto request = TupleDeleteDto.builder()
.keys(new HashMap<>() {{ .keys(new HashMap<>() {{
put(COLUMN_8_1_INTERNAL_NAME, 6L); put(COLUMN_8_1_INTERNAL_NAME, 6L);
...@@ -901,6 +1051,8 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -901,6 +1051,8 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
.build(); .build();
/* mock */ /* mock */
when(credentialService.getDatabase(DATABASE_3_ID))
.thenReturn(DATABASE_3_PRIVILEGED_DTO);
doThrow(TableNotFoundException.class) doThrow(TableNotFoundException.class)
.when(credentialService) .when(credentialService)
.getTable(DATABASE_3_ID, TABLE_8_ID); .getTable(DATABASE_3_ID, TABLE_8_ID);
...@@ -914,7 +1066,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -914,7 +1066,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
@Test @Test
@WithMockUser(username = USER_1_USERNAME, authorities = {"delete-table-data"}) @WithMockUser(username = USER_1_USERNAME, authorities = {"delete-table-data"})
public void deleteTuple_readAccess_fails() throws TableNotFoundException, RemoteUnavailableException, public void deleteTuple_readAccess_fails() throws TableNotFoundException, RemoteUnavailableException,
NotAllowedException, MetadataServiceException { NotAllowedException, MetadataServiceException, DatabaseNotFoundException {
final TupleDeleteDto request = TupleDeleteDto.builder() final TupleDeleteDto request = TupleDeleteDto.builder()
.keys(new HashMap<>() {{ .keys(new HashMap<>() {{
put(COLUMN_8_1_INTERNAL_NAME, 6L); put(COLUMN_8_1_INTERNAL_NAME, 6L);
...@@ -923,7 +1075,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -923,7 +1075,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID)) when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID))
.thenReturn(TABLE_8_PRIVILEGED_DTO); .thenReturn(TABLE_8_DTO);
when(credentialService.getDatabase(DATABASE_3_ID))
.thenReturn(DATABASE_3_PRIVILEGED_DTO);
when(credentialService.getAccess(DATABASE_3_ID, USER_3_ID)) when(credentialService.getAccess(DATABASE_3_ID, USER_3_ID))
.thenReturn(DATABASE_3_USER_3_READ_ACCESS_DTO); .thenReturn(DATABASE_3_USER_3_READ_ACCESS_DTO);
...@@ -936,7 +1090,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -936,7 +1090,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
@Test @Test
@WithMockUser(username = USER_1_USERNAME, authorities = {"delete-table-data"}) @WithMockUser(username = USER_1_USERNAME, authorities = {"delete-table-data"})
public void deleteTuple_unavailable_fails() throws TableNotFoundException, RemoteUnavailableException, SQLException, public void deleteTuple_unavailable_fails() throws TableNotFoundException, RemoteUnavailableException, SQLException,
NotAllowedException, MetadataServiceException, TableMalformedException, QueryMalformedException { NotAllowedException, MetadataServiceException, TableMalformedException, QueryMalformedException, DatabaseNotFoundException {
final TupleDeleteDto request = TupleDeleteDto.builder() final TupleDeleteDto request = TupleDeleteDto.builder()
.keys(new HashMap<>() {{ .keys(new HashMap<>() {{
put(COLUMN_8_1_INTERNAL_NAME, 6L); put(COLUMN_8_1_INTERNAL_NAME, 6L);
...@@ -945,12 +1099,14 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -945,12 +1099,14 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID)) when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID))
.thenReturn(TABLE_8_PRIVILEGED_DTO); .thenReturn(TABLE_8_DTO);
when(credentialService.getDatabase(DATABASE_3_ID))
.thenReturn(DATABASE_3_PRIVILEGED_DTO);
when(credentialService.getAccess(DATABASE_3_ID, USER_1_ID)) when(credentialService.getAccess(DATABASE_3_ID, USER_1_ID))
.thenReturn(DATABASE_3_USER_3_WRITE_OWN_ACCESS_DTO); .thenReturn(DATABASE_3_USER_3_WRITE_OWN_ACCESS_DTO);
doThrow(SQLException.class) doThrow(SQLException.class)
.when(tableService) .when(tableService)
.deleteTuple(TABLE_8_PRIVILEGED_DTO, request); .deleteTuple(DATABASE_3_PRIVILEGED_DTO, TABLE_8_DTO, request);
/* test */ /* test */
assertThrows(DatabaseUnavailableException.class, () -> { assertThrows(DatabaseUnavailableException.class, () -> {
...@@ -962,7 +1118,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -962,7 +1118,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
@WithMockUser(username = USER_1_USERNAME, authorities = {"delete-table-data"}) @WithMockUser(username = USER_1_USERNAME, authorities = {"delete-table-data"})
public void deleteTuple_writeOwnAccess_succeeds() throws TableNotFoundException, RemoteUnavailableException, public void deleteTuple_writeOwnAccess_succeeds() throws TableNotFoundException, RemoteUnavailableException,
NotAllowedException, TableMalformedException, SQLException, QueryMalformedException, NotAllowedException, TableMalformedException, SQLException, QueryMalformedException,
DatabaseUnavailableException, MetadataServiceException { DatabaseUnavailableException, MetadataServiceException, DatabaseNotFoundException {
final TupleDeleteDto request = TupleDeleteDto.builder() final TupleDeleteDto request = TupleDeleteDto.builder()
.keys(new HashMap<>() {{ .keys(new HashMap<>() {{
put(COLUMN_8_1_INTERNAL_NAME, 6L); put(COLUMN_8_1_INTERNAL_NAME, 6L);
...@@ -971,12 +1127,14 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -971,12 +1127,14 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID)) when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID))
.thenReturn(TABLE_8_PRIVILEGED_DTO); .thenReturn(TABLE_8_DTO);
when(credentialService.getDatabase(DATABASE_3_ID))
.thenReturn(DATABASE_3_PRIVILEGED_DTO);
when(credentialService.getAccess(DATABASE_3_ID, USER_1_ID)) when(credentialService.getAccess(DATABASE_3_ID, USER_1_ID))
.thenReturn(DATABASE_3_USER_3_WRITE_OWN_ACCESS_DTO); .thenReturn(DATABASE_3_USER_3_WRITE_OWN_ACCESS_DTO);
doNothing() doNothing()
.when(tableService) .when(tableService)
.deleteTuple(TABLE_8_PRIVILEGED_DTO, request); .deleteTuple(DATABASE_3_PRIVILEGED_DTO, TABLE_8_DTO, request);
doNothing() doNothing()
.when(metadataServiceGateway) .when(metadataServiceGateway)
.updateTableStatistics(DATABASE_3_ID, TABLE_8_ID, TOKEN_ACCESS_TOKEN); .updateTableStatistics(DATABASE_3_ID, TABLE_8_ID, TOKEN_ACCESS_TOKEN);
...@@ -989,7 +1147,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -989,7 +1147,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
@Test @Test
@WithMockUser(username = USER_3_USERNAME, authorities = {"delete-table-data"}) @WithMockUser(username = USER_3_USERNAME, authorities = {"delete-table-data"})
public void deleteTuple_writeOwnAccessForeign_fails() throws TableNotFoundException, RemoteUnavailableException, public void deleteTuple_writeOwnAccessForeign_fails() throws TableNotFoundException, RemoteUnavailableException,
NotAllowedException, MetadataServiceException { NotAllowedException, MetadataServiceException, DatabaseNotFoundException {
final TupleDeleteDto request = TupleDeleteDto.builder() final TupleDeleteDto request = TupleDeleteDto.builder()
.keys(new HashMap<>() {{ .keys(new HashMap<>() {{
put(COLUMN_8_1_INTERNAL_NAME, 6L); put(COLUMN_8_1_INTERNAL_NAME, 6L);
...@@ -998,7 +1156,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -998,7 +1156,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID)) when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID))
.thenReturn(TABLE_8_PRIVILEGED_DTO); .thenReturn(TABLE_8_DTO);
when(credentialService.getDatabase(DATABASE_3_ID))
.thenReturn(DATABASE_3_PRIVILEGED_DTO);
when(credentialService.getAccess(DATABASE_3_ID, USER_3_ID)) when(credentialService.getAccess(DATABASE_3_ID, USER_3_ID))
.thenReturn(DATABASE_3_USER_3_WRITE_OWN_ACCESS_DTO); .thenReturn(DATABASE_3_USER_3_WRITE_OWN_ACCESS_DTO);
...@@ -1012,7 +1172,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -1012,7 +1172,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
@WithMockUser(username = USER_3_USERNAME, authorities = {"delete-table-data"}) @WithMockUser(username = USER_3_USERNAME, authorities = {"delete-table-data"})
public void deleteTuple_writeAllAccessForeign_succeeds() throws TableNotFoundException, RemoteUnavailableException, public void deleteTuple_writeAllAccessForeign_succeeds() throws TableNotFoundException, RemoteUnavailableException,
NotAllowedException, DatabaseUnavailableException, TableMalformedException, QueryMalformedException, NotAllowedException, DatabaseUnavailableException, TableMalformedException, QueryMalformedException,
SQLException, MetadataServiceException { SQLException, MetadataServiceException, DatabaseNotFoundException {
final TupleDeleteDto request = TupleDeleteDto.builder() final TupleDeleteDto request = TupleDeleteDto.builder()
.keys(new HashMap<>() {{ .keys(new HashMap<>() {{
put(COLUMN_8_1_INTERNAL_NAME, 6L); put(COLUMN_8_1_INTERNAL_NAME, 6L);
...@@ -1021,12 +1181,14 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -1021,12 +1181,14 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID)) when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID))
.thenReturn(TABLE_8_PRIVILEGED_DTO); .thenReturn(TABLE_8_DTO);
when(credentialService.getDatabase(DATABASE_3_ID))
.thenReturn(DATABASE_3_PRIVILEGED_DTO);
when(credentialService.getAccess(DATABASE_3_ID, USER_3_ID)) when(credentialService.getAccess(DATABASE_3_ID, USER_3_ID))
.thenReturn(DATABASE_3_USER_3_WRITE_ALL_ACCESS_DTO); .thenReturn(DATABASE_3_USER_3_WRITE_ALL_ACCESS_DTO);
doNothing() doNothing()
.when(tableService) .when(tableService)
.deleteTuple(TABLE_8_PRIVILEGED_DTO, request); .deleteTuple(DATABASE_3_PRIVILEGED_DTO, TABLE_8_DTO, request);
doNothing() doNothing()
.when(metadataServiceGateway) .when(metadataServiceGateway)
.updateTableStatistics(DATABASE_3_ID, TABLE_8_ID, TOKEN_ACCESS_TOKEN); .updateTableStatistics(DATABASE_3_ID, TABLE_8_ID, TOKEN_ACCESS_TOKEN);
...@@ -1039,27 +1201,31 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -1039,27 +1201,31 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
@Test @Test
@WithAnonymousUser @WithAnonymousUser
public void getHistory_succeeds() throws DatabaseUnavailableException, TableNotFoundException, public void getHistory_succeeds() throws DatabaseUnavailableException, TableNotFoundException,
RemoteUnavailableException, SQLException, NotAllowedException, MetadataServiceException, PaginationException { RemoteUnavailableException, SQLException, NotAllowedException, MetadataServiceException, PaginationException, DatabaseNotFoundException {
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID)) when(credentialService.getTable(DATABASE_2_ID, TABLE_5_ID))
.thenReturn(TABLE_8_PRIVILEGED_DTO); .thenReturn(TABLE_5_DTO);
when(tableService.history(TABLE_8_PRIVILEGED_DTO, null)) when(credentialService.getDatabase(DATABASE_2_ID))
.thenReturn(DATABASE_2_PRIVILEGED_DTO);
when(tableService.history(DATABASE_2_PRIVILEGED_DTO, TABLE_5_DTO, null))
.thenReturn(List.of()); .thenReturn(List.of());
/* test */ /* test */
final ResponseEntity<List<TableHistoryDto>> response = tableEndpoint.getHistory(DATABASE_3_ID, TABLE_8_ID, null, null); final ResponseEntity<List<TableHistoryDto>> response = tableEndpoint.getHistory(DATABASE_2_ID, TABLE_5_ID, null, null);
assertEquals(HttpStatus.OK, response.getStatusCode()); assertEquals(HttpStatus.OK, response.getStatusCode());
} }
@Test @Test
@WithAnonymousUser @WithAnonymousUser
public void getHistory_privateNoRole_fails() throws TableNotFoundException, RemoteUnavailableException, public void getHistory_privateNoRole_fails() throws TableNotFoundException, RemoteUnavailableException,
MetadataServiceException { MetadataServiceException, DatabaseNotFoundException {
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_1_ID, TABLE_1_ID)) when(credentialService.getTable(DATABASE_1_ID, TABLE_1_ID))
.thenReturn(TABLE_1_PRIVILEGED_DTO); .thenReturn(TABLE_1_DTO);
when(credentialService.getDatabase(DATABASE_1_ID))
.thenReturn(DATABASE_1_PRIVILEGED_DTO);
/* test */ /* test */
assertThrows(NotAllowedException.class, () -> { assertThrows(NotAllowedException.class, () -> {
...@@ -1081,11 +1247,13 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -1081,11 +1247,13 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
@Test @Test
@WithMockUser(username = USER_4_USERNAME) @WithMockUser(username = USER_4_USERNAME)
public void getHistory_privateNoAccess_fails() throws NotAllowedException, RemoteUnavailableException, public void getHistory_privateNoAccess_fails() throws NotAllowedException, RemoteUnavailableException,
TableNotFoundException, MetadataServiceException { TableNotFoundException, MetadataServiceException, DatabaseNotFoundException {
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_1_ID, TABLE_1_ID)) when(credentialService.getTable(DATABASE_1_ID, TABLE_1_ID))
.thenReturn(TABLE_1_PRIVILEGED_DTO); .thenReturn(TABLE_1_DTO);
when(credentialService.getDatabase(DATABASE_1_ID))
.thenReturn(DATABASE_1_PRIVILEGED_DTO);
doThrow(NotAllowedException.class) doThrow(NotAllowedException.class)
.when(credentialService) .when(credentialService)
.getAccess(DATABASE_1_ID, USER_4_ID); .getAccess(DATABASE_1_ID, USER_4_ID);
...@@ -1099,14 +1267,15 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -1099,14 +1267,15 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
@Test @Test
@WithMockUser(username = USER_2_USERNAME) @WithMockUser(username = USER_2_USERNAME)
public void getHistory_private_succeeds() throws NotAllowedException, RemoteUnavailableException, SQLException, public void getHistory_private_succeeds() throws NotAllowedException, RemoteUnavailableException, SQLException,
TableNotFoundException, MetadataServiceException, DatabaseUnavailableException, PaginationException { TableNotFoundException, MetadataServiceException, DatabaseUnavailableException, PaginationException,
DatabaseNotFoundException {
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_1_ID, TABLE_1_ID)) when(credentialService.getTable(DATABASE_1_ID, TABLE_1_ID))
.thenReturn(TABLE_1_PRIVILEGED_DTO); .thenReturn(TABLE_1_DTO);
when(credentialService.getAccess(DATABASE_1_ID, USER_2_ID)) when(credentialService.getAccess(DATABASE_1_ID, USER_2_ID))
.thenReturn(DATABASE_1_USER_2_READ_ACCESS_DTO); .thenReturn(DATABASE_1_USER_2_READ_ACCESS_DTO);
when(tableService.history(TABLE_1_PRIVILEGED_DTO, 10L)) when(tableService.history(DATABASE_1_PRIVILEGED_DTO, TABLE_1_DTO, 10L))
.thenReturn(List.of()); .thenReturn(List.of());
/* test */ /* test */
...@@ -1117,27 +1286,31 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -1117,27 +1286,31 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
@Test @Test
@WithAnonymousUser @WithAnonymousUser
public void getHistory_unavailable_succeeds() throws RemoteUnavailableException, SQLException, public void getHistory_unavailable_succeeds() throws RemoteUnavailableException, SQLException,
TableNotFoundException, MetadataServiceException { TableNotFoundException, MetadataServiceException, DatabaseNotFoundException {
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID)) when(credentialService.getTable(DATABASE_2_ID, TABLE_5_ID))
.thenReturn(TABLE_8_PRIVILEGED_DTO); .thenReturn(TABLE_5_DTO);
when(credentialService.getDatabase(DATABASE_2_ID))
.thenReturn(DATABASE_2_PRIVILEGED_DTO);
doThrow(SQLException.class) doThrow(SQLException.class)
.when(tableService) .when(tableService)
.history(TABLE_8_PRIVILEGED_DTO, 100L); .history(any(DatabaseDto.class), any(TableDto.class), anyLong());
/* test */ /* test */
assertThrows(DatabaseUnavailableException.class, () -> { assertThrows(DatabaseUnavailableException.class, () -> {
tableEndpoint.getHistory(DATABASE_3_ID, TABLE_8_ID, null, null); tableEndpoint.getHistory(DATABASE_2_ID, TABLE_5_ID, null, null);
}); });
} }
@Test @Test
@WithAnonymousUser @WithAnonymousUser
public void getHistory_tableNotFound_fails() throws TableNotFoundException, RemoteUnavailableException, public void getHistory_tableNotFound_fails() throws TableNotFoundException, RemoteUnavailableException,
MetadataServiceException { MetadataServiceException, DatabaseNotFoundException {
/* mock */ /* mock */
when(credentialService.getDatabase(DATABASE_3_ID))
.thenReturn(DATABASE_3_PRIVILEGED_DTO);
doThrow(TableNotFoundException.class) doThrow(TableNotFoundException.class)
.when(credentialService) .when(credentialService)
.getTable(DATABASE_3_ID, TABLE_8_ID); .getTable(DATABASE_3_ID, TABLE_8_ID);
...@@ -1155,15 +1328,15 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -1155,15 +1328,15 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
final Dataset<Row> mock = sparkSession.emptyDataFrame(); final Dataset<Row> mock = sparkSession.emptyDataFrame();
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID)) when(credentialService.getTable(DATABASE_1_ID, TABLE_4_ID))
.thenReturn(TABLE_8_PRIVILEGED_DTO); .thenReturn(TABLE_4_DTO);
when(credentialService.getDatabase(DATABASE_3_ID)) when(credentialService.getDatabase(DATABASE_1_ID))
.thenReturn(DATABASE_3_PRIVILEGED_DTO); .thenReturn(DATABASE_1_PRIVILEGED_DTO);
when(subsetService.getData(any(DatabaseDto.class), anyString(), any(Instant.class), eq(null), eq(null), eq(null), eq(null))) when(subsetService.getData(any(DatabaseDto.class), anyString()))
.thenReturn(mock); .thenReturn(mock);
/* test */ /* test */
final ResponseEntity<InputStreamResource> response = tableEndpoint.exportDataset(DATABASE_3_ID, TABLE_8_ID, null, null); final ResponseEntity<InputStreamResource> response = tableEndpoint.exportDataset(DATABASE_1_ID, TABLE_4_ID, null, null);
assertEquals(HttpStatus.OK, response.getStatusCode()); assertEquals(HttpStatus.OK, response.getStatusCode());
} }
...@@ -1177,12 +1350,14 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -1177,12 +1350,14 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_1_ID, TABLE_1_ID)) when(credentialService.getTable(DATABASE_1_ID, TABLE_1_ID))
.thenReturn(TABLE_1_PRIVILEGED_DTO); .thenReturn(TABLE_1_DTO);
when(credentialService.getDatabase(DATABASE_1_ID))
.thenReturn(DATABASE_1_PRIVILEGED_DTO);
when(credentialService.getAccess(DATABASE_1_ID, USER_2_ID)) when(credentialService.getAccess(DATABASE_1_ID, USER_2_ID))
.thenReturn(access); .thenReturn(access);
when(credentialService.getDatabase(DATABASE_1_ID)) when(credentialService.getDatabase(DATABASE_1_ID))
.thenReturn(DATABASE_1_PRIVILEGED_DTO); .thenReturn(DATABASE_1_DTO);
when(subsetService.getData(any(DatabaseDto.class), anyString(), any(Instant.class), eq(null), eq(null), eq(null), eq(null))) when(subsetService.getData(any(DatabaseDto.class), anyString()))
.thenReturn(mock); .thenReturn(mock);
/* test */ /* test */
...@@ -1193,11 +1368,13 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -1193,11 +1368,13 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
@Test @Test
@WithMockUser(username = USER_4_USERNAME) @WithMockUser(username = USER_4_USERNAME)
public void exportData_privateNoAccess_fails() throws TableNotFoundException, NotAllowedException, public void exportData_privateNoAccess_fails() throws TableNotFoundException, NotAllowedException,
RemoteUnavailableException, MetadataServiceException { RemoteUnavailableException, MetadataServiceException, DatabaseNotFoundException {
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_1_ID, TABLE_1_ID)) when(credentialService.getTable(DATABASE_1_ID, TABLE_1_ID))
.thenReturn(TABLE_1_PRIVILEGED_DTO); .thenReturn(TABLE_1_DTO);
when(credentialService.getDatabase(DATABASE_1_ID))
.thenReturn(DATABASE_1_PRIVILEGED_DTO);
doThrow(NotAllowedException.class) doThrow(NotAllowedException.class)
.when(credentialService) .when(credentialService)
.getAccess(DATABASE_1_ID, USER_4_ID); .getAccess(DATABASE_1_ID, USER_4_ID);
...@@ -1216,9 +1393,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -1216,9 +1393,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
/* mock */ /* mock */
when(credentialService.getDatabase(DATABASE_3_ID)) when(credentialService.getDatabase(DATABASE_3_ID))
.thenReturn(DATABASE_3_PRIVILEGED_DTO); .thenReturn(DATABASE_3_DTO);
when(databaseService.exploreTables(DATABASE_3_PRIVILEGED_DTO)) when(databaseService.exploreTables(DATABASE_3_DTO))
.thenReturn(List.of(TABLE_8_PRIVILEGED_DTO)); .thenReturn(List.of(TABLE_8_DTO));
/* test */ /* test */
final ResponseEntity<List<TableDto>> response = tableEndpoint.getSchema(DATABASE_3_ID); final ResponseEntity<List<TableDto>> response = tableEndpoint.getSchema(DATABASE_3_ID);
...@@ -1252,10 +1429,10 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -1252,10 +1429,10 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
/* mock */ /* mock */
when(credentialService.getDatabase(DATABASE_3_ID)) when(credentialService.getDatabase(DATABASE_3_ID))
.thenReturn(DATABASE_3_PRIVILEGED_DTO); .thenReturn(DATABASE_3_DTO);
doThrow(SQLException.class) doThrow(SQLException.class)
.when(databaseService) .when(databaseService)
.exploreTables(DATABASE_3_PRIVILEGED_DTO); .exploreTables(DATABASE_3_DTO);
/* test */ /* test */
assertThrows(DatabaseUnavailableException.class, () -> { assertThrows(DatabaseUnavailableException.class, () -> {
...@@ -1266,7 +1443,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -1266,7 +1443,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
@Test @Test
@WithMockUser(username = USER_1_USERNAME, authorities = {"insert-table-data"}) @WithMockUser(username = USER_1_USERNAME, authorities = {"insert-table-data"})
public void importDataset_succeeds() throws TableNotFoundException, NotAllowedException, RemoteUnavailableException, public void importDataset_succeeds() throws TableNotFoundException, NotAllowedException, RemoteUnavailableException,
MetadataServiceException, StorageNotFoundException, MalformedException, StorageUnavailableException, DatabaseUnavailableException, QueryMalformedException, SQLException, TableMalformedException { MetadataServiceException, StorageNotFoundException, MalformedException, StorageUnavailableException,
DatabaseUnavailableException, QueryMalformedException, SQLException, TableMalformedException,
DatabaseNotFoundException {
final ImportDto request = ImportDto.builder() final ImportDto request = ImportDto.builder()
.header(true) .header(true)
.lineTermination(null) .lineTermination(null)
...@@ -1275,12 +1454,14 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -1275,12 +1454,14 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID)) when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID))
.thenReturn(TABLE_8_PRIVILEGED_DTO); .thenReturn(TABLE_8_DTO);
when(credentialService.getDatabase(DATABASE_3_ID))
.thenReturn(DATABASE_3_PRIVILEGED_DTO);
when(credentialService.getAccess(DATABASE_3_ID, USER_1_ID)) when(credentialService.getAccess(DATABASE_3_ID, USER_1_ID))
.thenReturn(DATABASE_3_USER_1_WRITE_OWN_ACCESS_DTO); .thenReturn(DATABASE_3_USER_1_WRITE_OWN_ACCESS_DTO);
doNothing() doNothing()
.when(tableService) .when(tableService)
.importDataset(TABLE_8_PRIVILEGED_DTO, request); .importDataset(DATABASE_3_PRIVILEGED_DTO, TABLE_8_DTO, request);
doNothing() doNothing()
.when(metadataServiceGateway) .when(metadataServiceGateway)
.updateTableStatistics(DATABASE_3_ID, TABLE_8_ID, TOKEN_ACCESS_TOKEN); .updateTableStatistics(DATABASE_3_ID, TABLE_8_ID, TOKEN_ACCESS_TOKEN);
...@@ -1330,7 +1511,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -1330,7 +1511,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
@WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"}) @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"})
public void importDataset_unavailable_fails() throws RemoteUnavailableException, TableNotFoundException, public void importDataset_unavailable_fails() throws RemoteUnavailableException, TableNotFoundException,
MetadataServiceException, NotAllowedException, StorageNotFoundException, MalformedException, MetadataServiceException, NotAllowedException, StorageNotFoundException, MalformedException,
StorageUnavailableException, SQLException, QueryMalformedException, TableMalformedException { StorageUnavailableException, SQLException, QueryMalformedException, TableMalformedException, DatabaseNotFoundException {
final ImportDto request = ImportDto.builder() final ImportDto request = ImportDto.builder()
.header(true) .header(true)
.lineTermination("\\n") .lineTermination("\\n")
...@@ -1339,12 +1520,14 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -1339,12 +1520,14 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID)) when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID))
.thenReturn(TABLE_8_PRIVILEGED_DTO); .thenReturn(TABLE_8_DTO);
when(credentialService.getDatabase(DATABASE_3_ID))
.thenReturn(DATABASE_3_PRIVILEGED_DTO);
when(credentialService.getAccess(DATABASE_3_ID, USER_3_ID)) when(credentialService.getAccess(DATABASE_3_ID, USER_3_ID))
.thenReturn(DATABASE_3_USER_3_WRITE_ALL_ACCESS_DTO); .thenReturn(DATABASE_3_USER_3_WRITE_ALL_ACCESS_DTO);
doThrow(SQLException.class) doThrow(SQLException.class)
.when(tableService) .when(tableService)
.importDataset(any(TableDto.class), eq(request)); .importDataset(any(DatabaseDto.class), any(TableDto.class), eq(request));
/* test */ /* test */
assertThrows(DatabaseUnavailableException.class, () -> { assertThrows(DatabaseUnavailableException.class, () -> {
...@@ -1356,7 +1539,8 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -1356,7 +1539,8 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
@WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"}) @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"})
public void importDataset_writeOwnAccess_fails() throws RemoteUnavailableException, TableNotFoundException, public void importDataset_writeOwnAccess_fails() throws RemoteUnavailableException, TableNotFoundException,
MetadataServiceException, NotAllowedException, StorageNotFoundException, MalformedException, MetadataServiceException, NotAllowedException, StorageNotFoundException, MalformedException,
StorageUnavailableException, SQLException, QueryMalformedException, TableMalformedException { StorageUnavailableException, SQLException, QueryMalformedException, TableMalformedException,
DatabaseNotFoundException {
final ImportDto request = ImportDto.builder() final ImportDto request = ImportDto.builder()
.header(true) .header(true)
.lineTermination("\\n") .lineTermination("\\n")
...@@ -1365,12 +1549,14 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -1365,12 +1549,14 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID)) when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID))
.thenReturn(TABLE_8_PRIVILEGED_DTO); .thenReturn(TABLE_8_DTO);
when(credentialService.getDatabase(DATABASE_3_ID))
.thenReturn(DATABASE_3_PRIVILEGED_DTO);
when(credentialService.getAccess(DATABASE_3_ID, USER_3_ID)) when(credentialService.getAccess(DATABASE_3_ID, USER_3_ID))
.thenReturn(DATABASE_3_USER_3_WRITE_OWN_ACCESS_DTO); .thenReturn(DATABASE_3_USER_3_WRITE_OWN_ACCESS_DTO);
doThrow(SQLException.class) doThrow(SQLException.class)
.when(tableService) .when(tableService)
.importDataset(any(TableDto.class), eq(request)); .importDataset(any(DatabaseDto.class), any(TableDto.class), eq(request));
/* test */ /* test */
assertThrows(NotAllowedException.class, () -> { assertThrows(NotAllowedException.class, () -> {
...@@ -1381,7 +1567,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -1381,7 +1567,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
@Test @Test
@WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"}) @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"})
public void importDataset_readAccess_fails() throws TableNotFoundException, RemoteUnavailableException, public void importDataset_readAccess_fails() throws TableNotFoundException, RemoteUnavailableException,
NotAllowedException, MetadataServiceException { NotAllowedException, MetadataServiceException, DatabaseNotFoundException {
final ImportDto request = ImportDto.builder() final ImportDto request = ImportDto.builder()
.header(true) .header(true)
.lineTermination("\\n") .lineTermination("\\n")
...@@ -1390,7 +1576,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -1390,7 +1576,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID)) when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID))
.thenReturn(TABLE_8_PRIVILEGED_DTO); .thenReturn(TABLE_8_DTO);
when(credentialService.getDatabase(DATABASE_3_ID))
.thenReturn(DATABASE_3_PRIVILEGED_DTO);
when(credentialService.getAccess(DATABASE_3_ID, USER_3_ID)) when(credentialService.getAccess(DATABASE_3_ID, USER_3_ID))
.thenReturn(DATABASE_3_USER_3_READ_ACCESS_DTO); .thenReturn(DATABASE_3_USER_3_READ_ACCESS_DTO);
...@@ -1404,7 +1592,8 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -1404,7 +1592,8 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
@WithMockUser(username = USER_1_USERNAME, authorities = {"insert-table-data"}) @WithMockUser(username = USER_1_USERNAME, authorities = {"insert-table-data"})
public void importDataset_writeOwnAccess_succeeds() throws TableNotFoundException, RemoteUnavailableException, public void importDataset_writeOwnAccess_succeeds() throws TableNotFoundException, RemoteUnavailableException,
NotAllowedException, MetadataServiceException, StorageNotFoundException, MalformedException, NotAllowedException, MetadataServiceException, StorageNotFoundException, MalformedException,
StorageUnavailableException, DatabaseUnavailableException, QueryMalformedException { StorageUnavailableException, DatabaseUnavailableException, QueryMalformedException,
DatabaseNotFoundException {
final ImportDto request = ImportDto.builder() final ImportDto request = ImportDto.builder()
.header(true) .header(true)
.lineTermination("\\n") .lineTermination("\\n")
...@@ -1413,7 +1602,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -1413,7 +1602,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID)) when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID))
.thenReturn(TABLE_8_PRIVILEGED_DTO); .thenReturn(TABLE_8_DTO);
when(credentialService.getDatabase(DATABASE_3_ID))
.thenReturn(DATABASE_3_PRIVILEGED_DTO);
when(credentialService.getAccess(DATABASE_3_ID, USER_1_ID)) when(credentialService.getAccess(DATABASE_3_ID, USER_1_ID))
.thenReturn(DATABASE_3_USER_1_WRITE_OWN_ACCESS_DTO); .thenReturn(DATABASE_3_USER_1_WRITE_OWN_ACCESS_DTO);
...@@ -1424,7 +1615,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -1424,7 +1615,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
@Test @Test
@WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"}) @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"})
public void importDataset_writeOwnAccessForeign_fails() throws TableNotFoundException, RemoteUnavailableException, public void importDataset_writeOwnAccessForeign_fails() throws TableNotFoundException, RemoteUnavailableException,
NotAllowedException, MetadataServiceException { NotAllowedException, MetadataServiceException, DatabaseNotFoundException {
final ImportDto request = ImportDto.builder() final ImportDto request = ImportDto.builder()
.header(true) .header(true)
.lineTermination("\\n") .lineTermination("\\n")
...@@ -1433,7 +1624,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -1433,7 +1624,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID)) when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID))
.thenReturn(TABLE_8_PRIVILEGED_DTO); .thenReturn(TABLE_8_DTO);
when(credentialService.getDatabase(DATABASE_3_ID))
.thenReturn(DATABASE_3_PRIVILEGED_DTO);
when(credentialService.getAccess(DATABASE_3_ID, USER_3_ID)) when(credentialService.getAccess(DATABASE_3_ID, USER_3_ID))
.thenReturn(DATABASE_3_USER_3_WRITE_OWN_ACCESS_DTO); .thenReturn(DATABASE_3_USER_3_WRITE_OWN_ACCESS_DTO);
...@@ -1447,7 +1640,8 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -1447,7 +1640,8 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
@WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"}) @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"})
public void importDataset_writeAllAccessForeign_succeeds() throws TableNotFoundException, public void importDataset_writeAllAccessForeign_succeeds() throws TableNotFoundException,
RemoteUnavailableException, NotAllowedException, MetadataServiceException, StorageNotFoundException, RemoteUnavailableException, NotAllowedException, MetadataServiceException, StorageNotFoundException,
MalformedException, StorageUnavailableException, DatabaseUnavailableException, QueryMalformedException { MalformedException, StorageUnavailableException, DatabaseUnavailableException, QueryMalformedException,
DatabaseNotFoundException {
final ImportDto request = ImportDto.builder() final ImportDto request = ImportDto.builder()
.header(true) .header(true)
.lineTermination("\\n") .lineTermination("\\n")
...@@ -1456,7 +1650,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -1456,7 +1650,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID)) when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID))
.thenReturn(TABLE_8_PRIVILEGED_DTO); .thenReturn(TABLE_8_DTO);
when(credentialService.getDatabase(DATABASE_3_ID))
.thenReturn(DATABASE_3_PRIVILEGED_DTO);
when(credentialService.getAccess(DATABASE_3_ID, USER_1_ID)) when(credentialService.getAccess(DATABASE_3_ID, USER_1_ID))
.thenReturn(DATABASE_3_USER_3_WRITE_ALL_ACCESS_DTO); .thenReturn(DATABASE_3_USER_3_WRITE_ALL_ACCESS_DTO);
...@@ -1468,7 +1664,8 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -1468,7 +1664,8 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
@WithMockUser(username = USER_2_USERNAME, authorities = {"insert-table-data"}) @WithMockUser(username = USER_2_USERNAME, authorities = {"insert-table-data"})
public void importDataset_privateForeign_succeeds() throws TableNotFoundException, RemoteUnavailableException, public void importDataset_privateForeign_succeeds() throws TableNotFoundException, RemoteUnavailableException,
NotAllowedException, MetadataServiceException, StorageNotFoundException, MalformedException, NotAllowedException, MetadataServiceException, StorageNotFoundException, MalformedException,
StorageUnavailableException, DatabaseUnavailableException, QueryMalformedException { StorageUnavailableException, DatabaseUnavailableException, QueryMalformedException,
DatabaseNotFoundException {
final ImportDto request = ImportDto.builder() final ImportDto request = ImportDto.builder()
.header(true) .header(true)
.lineTermination("\\n") .lineTermination("\\n")
...@@ -1477,7 +1674,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -1477,7 +1674,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_1_ID, TABLE_1_ID)) when(credentialService.getTable(DATABASE_1_ID, TABLE_1_ID))
.thenReturn(TABLE_1_PRIVILEGED_DTO); .thenReturn(TABLE_1_DTO);
when(credentialService.getDatabase(DATABASE_1_ID))
.thenReturn(DATABASE_1_PRIVILEGED_DTO);
when(credentialService.getAccess(DATABASE_1_ID, USER_2_ID)) when(credentialService.getAccess(DATABASE_1_ID, USER_2_ID))
.thenReturn(DATABASE_1_USER_2_WRITE_ALL_ACCESS_DTO); .thenReturn(DATABASE_1_USER_2_WRITE_ALL_ACCESS_DTO);
...@@ -1489,7 +1688,8 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -1489,7 +1688,8 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
@WithMockUser(username = USER_2_USERNAME, authorities = {"insert-table-data"}) @WithMockUser(username = USER_2_USERNAME, authorities = {"insert-table-data"})
public void importDataset_private_succeeds() throws TableNotFoundException, RemoteUnavailableException, public void importDataset_private_succeeds() throws TableNotFoundException, RemoteUnavailableException,
NotAllowedException, MetadataServiceException, StorageNotFoundException, MalformedException, NotAllowedException, MetadataServiceException, StorageNotFoundException, MalformedException,
StorageUnavailableException, DatabaseUnavailableException, QueryMalformedException { StorageUnavailableException, DatabaseUnavailableException, QueryMalformedException,
DatabaseNotFoundException {
final ImportDto request = ImportDto.builder() final ImportDto request = ImportDto.builder()
.header(true) .header(true)
.lineTermination("\\n") .lineTermination("\\n")
...@@ -1498,7 +1698,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -1498,7 +1698,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_1_ID, TABLE_2_ID)) when(credentialService.getTable(DATABASE_1_ID, TABLE_2_ID))
.thenReturn(TABLE_2_PRIVILEGED_DTO); .thenReturn(TABLE_2_DTO);
when(credentialService.getDatabase(DATABASE_1_ID))
.thenReturn(DATABASE_1_PRIVILEGED_DTO);
when(credentialService.getAccess(DATABASE_1_ID, USER_2_ID)) when(credentialService.getAccess(DATABASE_1_ID, USER_2_ID))
.thenReturn(DATABASE_1_USER_2_WRITE_OWN_ACCESS_DTO); .thenReturn(DATABASE_1_USER_2_WRITE_OWN_ACCESS_DTO);
...@@ -1509,7 +1711,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -1509,7 +1711,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
@Test @Test
@WithMockUser(username = USER_2_USERNAME, authorities = {"insert-table-data"}) @WithMockUser(username = USER_2_USERNAME, authorities = {"insert-table-data"})
public void importDataset_privateForeign_fails() throws TableNotFoundException, RemoteUnavailableException, public void importDataset_privateForeign_fails() throws TableNotFoundException, RemoteUnavailableException,
NotAllowedException, MetadataServiceException { NotAllowedException, MetadataServiceException, DatabaseNotFoundException {
final ImportDto request = ImportDto.builder() final ImportDto request = ImportDto.builder()
.header(true) .header(true)
.lineTermination("\\n") .lineTermination("\\n")
...@@ -1518,7 +1720,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -1518,7 +1720,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_1_ID, TABLE_1_ID)) when(credentialService.getTable(DATABASE_1_ID, TABLE_1_ID))
.thenReturn(TABLE_1_PRIVILEGED_DTO); .thenReturn(TABLE_1_DTO);
when(credentialService.getDatabase(DATABASE_1_ID))
.thenReturn(DATABASE_1_PRIVILEGED_DTO);
when(credentialService.getAccess(DATABASE_1_ID, USER_2_ID)) when(credentialService.getAccess(DATABASE_1_ID, USER_2_ID))
.thenReturn(DATABASE_1_USER_2_WRITE_OWN_ACCESS_DTO); .thenReturn(DATABASE_1_USER_2_WRITE_OWN_ACCESS_DTO);
...@@ -1531,7 +1735,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -1531,7 +1735,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
@Test @Test
@WithMockUser(username = USER_2_USERNAME, authorities = {"insert-table-data"}) @WithMockUser(username = USER_2_USERNAME, authorities = {"insert-table-data"})
public void importDataset_privateReadAccess_fails() throws TableNotFoundException, RemoteUnavailableException, public void importDataset_privateReadAccess_fails() throws TableNotFoundException, RemoteUnavailableException,
NotAllowedException, MetadataServiceException { NotAllowedException, MetadataServiceException, DatabaseNotFoundException {
final ImportDto request = ImportDto.builder() final ImportDto request = ImportDto.builder()
.header(true) .header(true)
.lineTermination("\\n") .lineTermination("\\n")
...@@ -1540,7 +1744,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest { ...@@ -1540,7 +1744,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest {
/* mock */ /* mock */
when(credentialService.getTable(DATABASE_1_ID, TABLE_2_ID)) when(credentialService.getTable(DATABASE_1_ID, TABLE_2_ID))
.thenReturn(TABLE_2_PRIVILEGED_DTO); .thenReturn(TABLE_2_DTO);
when(credentialService.getDatabase(DATABASE_1_ID))
.thenReturn(DATABASE_1_PRIVILEGED_DTO);
when(credentialService.getAccess(DATABASE_1_ID, USER_2_ID)) when(credentialService.getAccess(DATABASE_1_ID, USER_2_ID))
.thenReturn(DATABASE_1_USER_2_READ_ACCESS_DTO); .thenReturn(DATABASE_1_USER_2_READ_ACCESS_DTO);
......
...@@ -4,7 +4,7 @@ import at.tuwien.api.database.DatabaseDto; ...@@ -4,7 +4,7 @@ import at.tuwien.api.database.DatabaseDto;
import at.tuwien.api.database.ViewDto; import at.tuwien.api.database.ViewDto;
import at.tuwien.endpoints.ViewEndpoint; import at.tuwien.endpoints.ViewEndpoint;
import at.tuwien.exception.*; import at.tuwien.exception.*;
import at.tuwien.service.CredentialService; import at.tuwien.service.CacheService;
import at.tuwien.service.DatabaseService; import at.tuwien.service.DatabaseService;
import at.tuwien.service.SubsetService; import at.tuwien.service.SubsetService;
import at.tuwien.service.ViewService; import at.tuwien.service.ViewService;
...@@ -32,6 +32,7 @@ import java.util.List; ...@@ -32,6 +32,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
@Log4j2 @Log4j2
...@@ -46,7 +47,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { ...@@ -46,7 +47,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
private DatabaseService databaseService; private DatabaseService databaseService;
@MockBean @MockBean
private CredentialService credentialService; private CacheService credentialService;
@MockBean @MockBean
private HttpServletRequest httpServletRequest; private HttpServletRequest httpServletRequest;
...@@ -68,13 +69,14 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { ...@@ -68,13 +69,14 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
@Test @Test
@WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"}) @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
public void create_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, ViewMalformedException, public void create_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, ViewMalformedException,
SQLException, DatabaseUnavailableException, MetadataServiceException { SQLException, DatabaseUnavailableException, MetadataServiceException, TableNotFoundException,
ImageNotFoundException, QueryMalformedException {
/* mock */ /* mock */
when(credentialService.getDatabase(DATABASE_1_ID)) when(credentialService.getDatabase(DATABASE_1_ID))
.thenReturn(DATABASE_1_PRIVILEGED_DTO); .thenReturn(DATABASE_1_DTO);
when(databaseService.createView(DATABASE_1_PRIVILEGED_DTO, VIEW_1_CREATE_DTO)) when(databaseService.createView(any(DatabaseDto.class), anyString(), anyString()))
.thenReturn(VIEW_1_PRIVILEGED_DTO); .thenReturn(VIEW_1_DTO);
/* test */ /* test */
final ResponseEntity<ViewDto> response = viewEndpoint.create(DATABASE_1_ID, VIEW_1_CREATE_DTO); final ResponseEntity<ViewDto> response = viewEndpoint.create(DATABASE_1_ID, VIEW_1_CREATE_DTO);
...@@ -88,10 +90,10 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { ...@@ -88,10 +90,10 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
/* mock */ /* mock */
when(credentialService.getDatabase(DATABASE_1_ID)) when(credentialService.getDatabase(DATABASE_1_ID))
.thenReturn(DATABASE_1_PRIVILEGED_DTO); .thenReturn(DATABASE_1_DTO);
doThrow(SQLException.class) doThrow(SQLException.class)
.when(databaseService) .when(databaseService)
.createView(DATABASE_1_PRIVILEGED_DTO, VIEW_1_CREATE_DTO); .createView(any(DatabaseDto.class), anyString(), anyString());
/* test */ /* test */
assertThrows(DatabaseUnavailableException.class, () -> { assertThrows(DatabaseUnavailableException.class, () -> {
...@@ -106,9 +108,9 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { ...@@ -106,9 +108,9 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
/* mock */ /* mock */
when(credentialService.getDatabase(DATABASE_1_ID)) when(credentialService.getDatabase(DATABASE_1_ID))
.thenReturn(DATABASE_1_PRIVILEGED_DTO); .thenReturn(DATABASE_1_DTO);
when(databaseService.createView(DATABASE_1_PRIVILEGED_DTO, VIEW_1_CREATE_DTO)) when(databaseService.createView(DATABASE_1_DTO, VIEW_1_NAME, VIEW_1_QUERY))
.thenReturn(VIEW_1_PRIVILEGED_DTO); .thenReturn(VIEW_1_DTO);
/* test */ /* test */
assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> { assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> {
...@@ -139,8 +141,8 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { ...@@ -139,8 +141,8 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
/* mock */ /* mock */
when(credentialService.getDatabase(DATABASE_1_ID)) when(credentialService.getDatabase(DATABASE_1_ID))
.thenReturn(DATABASE_1_PRIVILEGED_DTO); .thenReturn(DATABASE_1_DTO);
when(databaseService.exploreViews(DATABASE_1_PRIVILEGED_DTO)) when(databaseService.exploreViews(DATABASE_1_DTO))
.thenReturn(List.of(VIEW_1_DTO, VIEW_2_DTO, VIEW_3_DTO)); .thenReturn(List.of(VIEW_1_DTO, VIEW_2_DTO, VIEW_3_DTO));
/* test */ /* test */
...@@ -181,10 +183,10 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { ...@@ -181,10 +183,10 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
/* mock */ /* mock */
when(credentialService.getDatabase(DATABASE_1_ID)) when(credentialService.getDatabase(DATABASE_1_ID))
.thenReturn(DATABASE_1_PRIVILEGED_DTO); .thenReturn(DATABASE_1_DTO);
doThrow(SQLException.class) doThrow(SQLException.class)
.when(databaseService) .when(databaseService)
.exploreViews(DATABASE_1_PRIVILEGED_DTO); .exploreViews(DATABASE_1_DTO);
/* test */ /* test */
assertThrows(DatabaseUnavailableException.class, () -> { assertThrows(DatabaseUnavailableException.class, () -> {
...@@ -205,14 +207,16 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { ...@@ -205,14 +207,16 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
@Test @Test
@WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"}) @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
public void delete_succeeds() throws RemoteUnavailableException, ViewMalformedException, ViewNotFoundException, public void delete_succeeds() throws RemoteUnavailableException, ViewMalformedException, ViewNotFoundException,
SQLException, DatabaseUnavailableException, MetadataServiceException { SQLException, DatabaseUnavailableException, MetadataServiceException, DatabaseNotFoundException {
/* mock */ /* mock */
when(credentialService.getView(DATABASE_1_ID, VIEW_1_ID)) when(credentialService.getView(DATABASE_1_ID, VIEW_1_ID))
.thenReturn(VIEW_1_PRIVILEGED_DTO); .thenReturn(VIEW_1_DTO);
when(credentialService.getDatabase(DATABASE_1_ID))
.thenReturn(DATABASE_1_PRIVILEGED_DTO);
doNothing() doNothing()
.when(viewService) .when(viewService)
.delete(VIEW_1_PRIVILEGED_DTO); .delete(DATABASE_1_PRIVILEGED_DTO, VIEW_1_DTO);
/* test */ /* test */
final ResponseEntity<Void> response = viewEndpoint.delete(DATABASE_1_ID, VIEW_1_ID); final ResponseEntity<Void> response = viewEndpoint.delete(DATABASE_1_ID, VIEW_1_ID);
...@@ -222,14 +226,16 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { ...@@ -222,14 +226,16 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
@Test @Test
@WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"}) @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"})
public void delete_unavailable_fails() throws RemoteUnavailableException, ViewMalformedException, SQLException, public void delete_unavailable_fails() throws RemoteUnavailableException, ViewMalformedException, SQLException,
MetadataServiceException, ViewNotFoundException { MetadataServiceException, ViewNotFoundException, DatabaseNotFoundException {
/* mock */ /* mock */
when(credentialService.getView(DATABASE_1_ID, VIEW_1_ID)) when(credentialService.getView(DATABASE_1_ID, VIEW_1_ID))
.thenReturn(VIEW_1_PRIVILEGED_DTO); .thenReturn(VIEW_1_DTO);
when(credentialService.getDatabase(DATABASE_1_ID))
.thenReturn(DATABASE_1_PRIVILEGED_DTO);
doThrow(SQLException.class) doThrow(SQLException.class)
.when(viewService) .when(viewService)
.delete(VIEW_1_PRIVILEGED_DTO); .delete(DATABASE_1_PRIVILEGED_DTO, VIEW_1_DTO);
/* test */ /* test */
assertThrows(DatabaseUnavailableException.class, () -> { assertThrows(DatabaseUnavailableException.class, () -> {
...@@ -247,7 +253,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { ...@@ -247,7 +253,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
.thenReturn(DATABASE_1_PRIVILEGED_DTO); .thenReturn(DATABASE_1_PRIVILEGED_DTO);
doNothing() doNothing()
.when(viewService) .when(viewService)
.delete(VIEW_1_PRIVILEGED_DTO); .delete(DATABASE_1_PRIVILEGED_DTO,VIEW_1_DTO);
/* test */ /* test */
assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> { assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> {
...@@ -274,18 +280,18 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { ...@@ -274,18 +280,18 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
@Test @Test
@WithMockUser(username = USER_1_USERNAME, authorities = {"view-database-view-data"}) @WithMockUser(username = USER_1_USERNAME, authorities = {"view-database-view-data"})
public void getData_privateDataPrivateSchema_succeeds() throws RemoteUnavailableException, ViewNotFoundException, public void getData_privateDataPrivateSchema_succeeds() throws RemoteUnavailableException, ViewNotFoundException,
SQLException, DatabaseUnavailableException, QueryMalformedException, PaginationException, DatabaseUnavailableException, QueryMalformedException, PaginationException, NotAllowedException,
NotAllowedException, MetadataServiceException, TableNotFoundException, DatabaseNotFoundException { MetadataServiceException, TableNotFoundException, DatabaseNotFoundException {
final Dataset<Row> mock = sparkSession.emptyDataFrame(); final Dataset<Row> mock = sparkSession.emptyDataFrame();
/* mock */ /* mock */
when(credentialService.getView(DATABASE_1_ID, VIEW_1_ID)) when(credentialService.getView(DATABASE_1_ID, VIEW_1_ID))
.thenReturn(VIEW_1_PRIVILEGED_DTO); .thenReturn(VIEW_1_DTO);
when(credentialService.getDatabase(DATABASE_1_ID)) when(credentialService.getDatabase(DATABASE_1_ID))
.thenReturn(DATABASE_1_PRIVILEGED_DTO); .thenReturn(DATABASE_1_DTO);
when(credentialService.getAccess(DATABASE_1_ID, USER_1_ID)) when(credentialService.getAccess(DATABASE_1_ID, USER_1_ID))
.thenReturn(DATABASE_1_USER_1_READ_ACCESS_DTO); .thenReturn(DATABASE_1_USER_1_READ_ACCESS_DTO);
when(subsetService.getData(any(DatabaseDto.class), anyString(), any(Instant.class), eq(0L), eq(10L), eq(null), eq(null))) when(subsetService.getData(any(DatabaseDto.class), anyString()))
.thenReturn(mock); .thenReturn(mock);
when(httpServletRequest.getMethod()) when(httpServletRequest.getMethod())
.thenReturn("GET"); .thenReturn("GET");
...@@ -296,6 +302,31 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { ...@@ -296,6 +302,31 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
assertNotNull(response.getBody()); assertNotNull(response.getBody());
} }
@Test
@WithAnonymousUser
public void getData_privateDataPrivateSchemaAnonymous_fails() throws RemoteUnavailableException,
ViewNotFoundException, QueryMalformedException, NotAllowedException, MetadataServiceException,
TableNotFoundException, DatabaseNotFoundException {
final Dataset<Row> mock = sparkSession.emptyDataFrame();
/* mock */
when(credentialService.getView(DATABASE_1_ID, VIEW_1_ID))
.thenReturn(VIEW_1_DTO);
when(credentialService.getDatabase(DATABASE_1_ID))
.thenReturn(DATABASE_1_PRIVILEGED_DTO);
when(credentialService.getAccess(DATABASE_1_ID, USER_1_ID))
.thenReturn(DATABASE_1_USER_1_READ_ACCESS_DTO);
when(subsetService.getData(any(DatabaseDto.class), anyString()))
.thenReturn(mock);
when(httpServletRequest.getMethod())
.thenReturn("GET");
/* test */
assertThrows(NotAllowedException.class, () -> {
viewEndpoint.getData(DATABASE_1_ID, VIEW_1_ID, null, null, null, httpServletRequest, null);
});
}
@Test @Test
@WithMockUser(username = USER_1_USERNAME, authorities = {"view-database-view-data"}) @WithMockUser(username = USER_1_USERNAME, authorities = {"view-database-view-data"})
public void getData_privateHead_succeeds() throws RemoteUnavailableException, ViewNotFoundException, public void getData_privateHead_succeeds() throws RemoteUnavailableException, ViewNotFoundException,
...@@ -304,12 +335,14 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { ...@@ -304,12 +335,14 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
/* mock */ /* mock */
when(credentialService.getView(DATABASE_1_ID, VIEW_3_ID)) when(credentialService.getView(DATABASE_1_ID, VIEW_3_ID))
.thenReturn(VIEW_3_PRIVILEGED_DTO); .thenReturn(VIEW_3_DTO);
when(credentialService.getDatabase(DATABASE_1_ID))
.thenReturn(DATABASE_1_PRIVILEGED_DTO);
when(credentialService.getAccess(DATABASE_1_ID, USER_1_ID)) when(credentialService.getAccess(DATABASE_1_ID, USER_1_ID))
.thenReturn(DATABASE_1_USER_1_READ_ACCESS_DTO); .thenReturn(DATABASE_1_USER_1_READ_ACCESS_DTO);
when(httpServletRequest.getMethod()) when(httpServletRequest.getMethod())
.thenReturn("HEAD"); .thenReturn("HEAD");
when(viewService.count(eq(VIEW_3_PRIVILEGED_DTO), any(Instant.class))) when(viewService.count(any(DatabaseDto.class), eq(VIEW_3_DTO), any(Instant.class)))
.thenReturn(VIEW_3_DATA_COUNT); .thenReturn(VIEW_3_DATA_COUNT);
/* test */ /* test */
...@@ -331,7 +364,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { ...@@ -331,7 +364,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
/* mock */ /* mock */
when(credentialService.getView(DATABASE_1_ID, VIEW_1_ID)) when(credentialService.getView(DATABASE_1_ID, VIEW_1_ID))
.thenReturn(VIEW_1_PRIVILEGED_DTO); .thenReturn(VIEW_1_DTO);
when(httpServletRequest.getMethod()) when(httpServletRequest.getMethod())
.thenReturn("GET"); .thenReturn("GET");
doThrow(NotAllowedException.class) doThrow(NotAllowedException.class)
...@@ -367,7 +400,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { ...@@ -367,7 +400,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
/* mock */ /* mock */
when(credentialService.getView(DATABASE_1_ID, VIEW_1_ID)) when(credentialService.getView(DATABASE_1_ID, VIEW_1_ID))
.thenReturn(VIEW_1_PRIVILEGED_DTO); .thenReturn(VIEW_1_DTO);
doThrow(NotAllowedException.class) doThrow(NotAllowedException.class)
.when(credentialService) .when(credentialService)
.getAccess(DATABASE_1_ID, USER_4_ID); .getAccess(DATABASE_1_ID, USER_4_ID);
...@@ -385,7 +418,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { ...@@ -385,7 +418,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
/* mock */ /* mock */
when(credentialService.getView(DATABASE_1_ID, VIEW_1_ID)) when(credentialService.getView(DATABASE_1_ID, VIEW_1_ID))
.thenReturn(VIEW_1_PRIVILEGED_DTO); .thenReturn(VIEW_1_DTO);
doThrow(NotAllowedException.class) doThrow(NotAllowedException.class)
.when(credentialService) .when(credentialService)
.getAccess(DATABASE_1_ID, USER_4_ID); .getAccess(DATABASE_1_ID, USER_4_ID);
...@@ -419,7 +452,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { ...@@ -419,7 +452,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest {
/* mock */ /* mock */
when(credentialService.getView(DATABASE_1_ID, VIEW_1_ID)) when(credentialService.getView(DATABASE_1_ID, VIEW_1_ID))
.thenReturn(VIEW_1_PRIVILEGED_DTO); .thenReturn(VIEW_1_DTO);
doThrow(NotAllowedException.class) doThrow(NotAllowedException.class)
.when(credentialService) .when(credentialService)
.getAccess(DATABASE_1_ID, USER_4_ID); .getAccess(DATABASE_1_ID, USER_4_ID);
......