diff --git a/dbrepo-metadata-db/setup-schema.sql b/dbrepo-metadata-db/setup-schema.sql index 92afa5c8ca4f93d3b57e414d550db32abd24c335..737ef8e464c454a171e53150f19bd98ed9cff20a 100644 --- a/dbrepo-metadata-db/setup-schema.sql +++ b/dbrepo-metadata-db/setup-schema.sql @@ -502,7 +502,7 @@ VALUES (1, '%Y-%c-%d %H:%i:%S.%f', 'yyyy-MM-dd HH:mm:ss.SSSSSS', '2022-01-30 13: (1, '%Y-%c-%d', 'yyyy-MM-dd', '2022-01-30', false); INSERT INTO `fda`.`mdb_ontologies` (prefix, uri, sparql_endpoint) -VALUES ('om2', 'http://www.ontology-of-units-of-measure.org/resource/om-2/', null), +VALUES ('om', 'http://www.ontology-of-units-of-measure.org/resource/om-2/', null), ('wd', 'http://www.wikidata.org/', 'https://query.wikidata.org/sparql'), ('mo', 'http://purl.org/ontology/mo/', null), ('dc', 'http://purl.org/dc/elements/1.1/', null), diff --git a/dbrepo-metadata-db/test/src/main/java/at/tuwien/test/BaseTest.java b/dbrepo-metadata-db/test/src/main/java/at/tuwien/test/BaseTest.java index 29951cebd09fc50900586e310634e30d1e0e2a17..13c1cee40c5eded82ceec8d0e3ea84ca25e421e7 100644 --- a/dbrepo-metadata-db/test/src/main/java/at/tuwien/test/BaseTest.java +++ b/dbrepo-metadata-db/test/src/main/java/at/tuwien/test/BaseTest.java @@ -1879,6 +1879,26 @@ public abstract class BaseTest { .sparqlEndpoint(ONTOLOGY_4_SPARQL_ENDPOINT) .build(); + public final static Long ONTOLOGY_5_ID = 5L; + public final static String ONTOLOGY_5_PREFIX = "db"; + public final static String ONTOLOGY_5_URI = "http://dbpedia.org"; + public final static String ONTOLOGY_5_SPARQL_ENDPOINT = "http://dbpedia.org/sparql"; + public final static UUID ONTOLOGY_5_CREATED_BY = USER_1_ID; + + public final static Ontology ONTOLOGY_5 = Ontology.builder() + .id(ONTOLOGY_5_ID) + .prefix(ONTOLOGY_5_PREFIX) + .uri(ONTOLOGY_5_URI) + .sparqlEndpoint(ONTOLOGY_5_SPARQL_ENDPOINT) + .createdBy(ONTOLOGY_5_CREATED_BY) + .build(); + + public final static OntologyCreateDto ONTOLOGY_5_CREATE_DTO = OntologyCreateDto.builder() + .prefix(ONTOLOGY_5_PREFIX) + .uri(ONTOLOGY_5_URI) + .sparqlEndpoint(ONTOLOGY_5_SPARQL_ENDPOINT) + .build(); + public final static String COLUMN_CONCEPT_TEMPERATURE_NAME = "temperature"; public final static String COLUMN_CONCEPT_TEMPERATURE_URI = "http://www.wikidata.org/entity/Q11466"; public final static String COLUMN_CONCEPT_TEMPERATURE_DESCRIPTION = "physical property of matter that quantitatively expresses the common notions of hot and cold"; diff --git a/dbrepo-semantics-service/rest-service/src/main/java/at/tuwien/endpoints/OntologyEndpoint.java b/dbrepo-semantics-service/rest-service/src/main/java/at/tuwien/endpoints/OntologyEndpoint.java index 74433460a69c41526af16f95d01cf3811ce80945..36d60d66b3073021c82f8bf66433db62325d7724 100644 --- a/dbrepo-semantics-service/rest-service/src/main/java/at/tuwien/endpoints/OntologyEndpoint.java +++ b/dbrepo-semantics-service/rest-service/src/main/java/at/tuwien/endpoints/OntologyEndpoint.java @@ -3,6 +3,7 @@ package at.tuwien.endpoints; import at.tuwien.api.error.ApiErrorDto; import at.tuwien.api.semantics.*; import at.tuwien.exception.OntologyNotFoundException; +import at.tuwien.exception.UserNotFoundException; import at.tuwien.mapper.OntologyMapper; import at.tuwien.service.OntologyService; import io.micrometer.core.annotation.Timed; @@ -93,11 +94,16 @@ public class OntologyEndpoint { content = {@Content( mediaType = "application/json", schema = @Schema(implementation = OntologyDto.class))}), + @ApiResponse(responseCode = "201", + description = "Could not find user", + content = {@Content( + mediaType = "application/json", + schema = @Schema(implementation = ApiErrorDto.class))}), }) public ResponseEntity<OntologyDto> create(@NotNull @Valid @RequestBody OntologyCreateDto data, - @NotNull Principal principal) { + @NotNull Principal principal) throws UserNotFoundException { log.debug("endpoint create ontology, data={}, principal={}", data, principal); - final OntologyDto dto = ontologyMapper.ontologyToOntologyDto(ontologyService.create(data)); + final OntologyDto dto = ontologyMapper.ontologyToOntologyDto(ontologyService.create(data, principal)); log.trace("create ontology resulted in dto {}", dto); return ResponseEntity.status(HttpStatus.CREATED) .body(dto); diff --git a/dbrepo-semantics-service/rest-service/src/main/java/at/tuwien/endpoints/QueryEndpoint.java b/dbrepo-semantics-service/rest-service/src/main/java/at/tuwien/endpoints/QueryEndpoint.java index 9d1ed742fbf29dc6434f17767c4b77fa8378bf3a..159f8c1eceaf230412dbacc1099f2c16675608b4 100644 --- a/dbrepo-semantics-service/rest-service/src/main/java/at/tuwien/endpoints/QueryEndpoint.java +++ b/dbrepo-semantics-service/rest-service/src/main/java/at/tuwien/endpoints/QueryEndpoint.java @@ -82,6 +82,10 @@ public class QueryEndpoint { log.error("Failed to find entities: uri {} does not start with expected ontology uri {}", uri, ontology.getUri()); throw new UriMalformedException("Failed to find entity: uri " + uri + " does not start with expected ontology uri " + ontology.getUri()); } + if (ontology.getSparqlEndpoint() == null) { + log.error("Failed to find SPARQL endpoint for ontology with id {}", ontology.getId()); + throw new OntologyNotFoundException("Failed to find SPARQL endpoint for ontology with id " + ontology.getId()); + } /* get */ final List<EntityDto> dtos; if (uri != null) { diff --git a/dbrepo-semantics-service/rest-service/src/test/java/at/tuwien/endpoint/OntologyEndpointUnitTest.java b/dbrepo-semantics-service/rest-service/src/test/java/at/tuwien/endpoint/OntologyEndpointUnitTest.java index a412b6c965b80dd7f89af1cc64db20d9d1accab2..00ad512534c9cc5dea5bd3a6bc7f369914c60012 100644 --- a/dbrepo-semantics-service/rest-service/src/test/java/at/tuwien/endpoint/OntologyEndpointUnitTest.java +++ b/dbrepo-semantics-service/rest-service/src/test/java/at/tuwien/endpoint/OntologyEndpointUnitTest.java @@ -8,8 +8,11 @@ import at.tuwien.api.semantics.OntologyDto; import at.tuwien.api.semantics.OntologyModifyDto; import at.tuwien.endpoints.OntologyEndpoint; import at.tuwien.entities.semantics.Ontology; +import at.tuwien.entities.user.User; import at.tuwien.exception.OntologyNotFoundException; +import at.tuwien.exception.UserNotFoundException; import at.tuwien.service.OntologyService; +import at.tuwien.service.UserService; import lombok.extern.log4j.Log4j2; import org.apache.jena.sys.JenaSystem; import org.hibernate.HibernateException; @@ -43,6 +46,9 @@ public class OntologyEndpointUnitTest extends BaseUnitTest { @MockBean private OntologyService ontologyService; + @MockBean + private UserService userService; + @BeforeAll public static void beforeAll() { JenaSystem.init(); @@ -96,7 +102,7 @@ public class OntologyEndpointUnitTest extends BaseUnitTest { /* test */ assertThrows(AccessDeniedException.class, () -> { - create_generic(ONTOLOGY_1_CREATE_DTO, null, ONTOLOGY_1); + create_generic(ONTOLOGY_1_CREATE_DTO, null, null, null, ONTOLOGY_1); }); } @@ -106,16 +112,16 @@ public class OntologyEndpointUnitTest extends BaseUnitTest { /* test */ assertThrows(AccessDeniedException.class, () -> { - create_generic(ONTOLOGY_1_CREATE_DTO, USER_4_PRINCIPAL, ONTOLOGY_1); + create_generic(ONTOLOGY_1_CREATE_DTO, USER_4_PRINCIPAL, USER_4_USERNAME, USER_4, ONTOLOGY_1); }); } @Test @WithMockUser(username = USER_3_USERNAME, authorities = {"create-ontology"}) - public void create_hasRole_succeeds() { + public void create_hasRole_succeeds() throws UserNotFoundException { /* test */ - create_generic(ONTOLOGY_1_CREATE_DTO, USER_3_PRINCIPAL, ONTOLOGY_1); + create_generic(ONTOLOGY_1_CREATE_DTO, USER_3_PRINCIPAL, USER_3_USERNAME, USER_3, ONTOLOGY_1); } @Test @@ -231,16 +237,25 @@ public class OntologyEndpointUnitTest extends BaseUnitTest { assertNotNull(body); } - public void create_generic(OntologyCreateDto createDto, Principal principal, Ontology ontology) { + public void create_generic(OntologyCreateDto createDto, Principal principal, String username, User user, Ontology ontology) + throws UserNotFoundException { /* mock */ if (ontology != null) { - when(ontologyService.create(createDto)) + when(ontologyService.create(createDto, principal)) .thenReturn(ontology); } else { doThrow(HibernateException.class) .when(ontologyService) - .create(createDto); + .create(createDto, principal); + } + if (user != null) { + when(userService.findByUsername(username)) + .thenReturn(user); + } else { + doThrow(UserNotFoundException.class) + .when(userService) + .findByUsername(username); } /* test */ diff --git a/dbrepo-semantics-service/rest-service/src/test/java/at/tuwien/endpoint/SemanticsEndpointUnitTest.java b/dbrepo-semantics-service/rest-service/src/test/java/at/tuwien/endpoint/SemanticsEndpointUnitTest.java index d140d7fb1a79905e9ff0142f1924196725c30fe9..64adc9cad1b3c64acac9f5c92a3912355f395466 100644 --- a/dbrepo-semantics-service/rest-service/src/test/java/at/tuwien/endpoint/SemanticsEndpointUnitTest.java +++ b/dbrepo-semantics-service/rest-service/src/test/java/at/tuwien/endpoint/SemanticsEndpointUnitTest.java @@ -129,13 +129,11 @@ public class SemanticsEndpointUnitTest extends BaseUnitTest { } @Test - @WithMockUser(username = USER_3_USERNAME, authorities = {"create-semantic-concept"}) + @WithMockUser(username = USER_3_USERNAME, authorities = {"create-semantic-unit"}) public void saveUnit_hasRole_succeeds() { /* test */ - assertThrows(AccessDeniedException.class, () -> { - saveUnit_generic(COLUMN_UNIT_DEGREES_CELSIUS_SAVE_DTO, COLUMN_UNIT_DEGREES_CELSIUS); - }); + saveUnit_generic(COLUMN_UNIT_DEGREES_CELSIUS_SAVE_DTO, COLUMN_UNIT_DEGREES_CELSIUS); } /* ################################################################################################### */ diff --git a/dbrepo-semantics-service/rest-service/src/test/java/at/tuwien/endpoint/TableEndpointUnitTest.java b/dbrepo-semantics-service/rest-service/src/test/java/at/tuwien/endpoint/TableEndpointUnitTest.java new file mode 100644 index 0000000000000000000000000000000000000000..cd5dc23cd807c7e066fa80796a28a1a0917e8212 --- /dev/null +++ b/dbrepo-semantics-service/rest-service/src/test/java/at/tuwien/endpoint/TableEndpointUnitTest.java @@ -0,0 +1,139 @@ + +package at.tuwien.endpoint; + +import at.tuwien.BaseUnitTest; +import at.tuwien.api.semantics.*; +import at.tuwien.endpoints.OntologyEndpoint; +import at.tuwien.endpoints.TableEndpoint; +import at.tuwien.entities.semantics.Ontology; +import at.tuwien.exception.OntologyNotFoundException; +import at.tuwien.exception.QueryMalformedException; +import at.tuwien.exception.TableColumnNotFoundException; +import at.tuwien.exception.TableNotFoundException; +import at.tuwien.service.OntologyService; +import at.tuwien.service.TableService; +import lombok.extern.log4j.Log4j2; +import org.apache.jena.sys.JenaSystem; +import org.hibernate.HibernateException; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.test.context.support.WithAnonymousUser; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import java.security.Principal; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +@Log4j2 +@SpringBootTest +@ExtendWith(SpringExtension.class) +public class TableEndpointUnitTest extends BaseUnitTest { + + @Autowired + private TableEndpoint tableEndpoint; + + @MockBean + private TableService tableService; + + @BeforeAll + public static void beforeAll() { + JenaSystem.init(); + } + + @Test + @WithAnonymousUser + public void analyseTable_anonymous_fails() { + + /* test */ + assertThrows(AccessDeniedException.class, () -> { + analyseTable_generic(DATABASE_1_ID, TABLE_1_ID); + }); + } + + @Test + @WithMockUser(username = USER_4_USERNAME) + public void findAll_noRole_fails() { + + /* test */ + assertThrows(AccessDeniedException.class, () -> { + analyseTable_generic(DATABASE_1_ID, TABLE_1_ID); + }); + } + + @Test + @WithMockUser(username = USER_1_USERNAME, authorities = {"table-semantic-analyse"}) + public void findAll_hasRole_succeeds() throws TableNotFoundException, QueryMalformedException { + + /* test */ + analyseTable_generic(DATABASE_1_ID, TABLE_1_ID); + } + + @Test + @WithAnonymousUser + public void analyseTableColumn_anonymous_fails() { + + /* test */ + assertThrows(AccessDeniedException.class, () -> { + analyseTableColumn_generic(DATABASE_1_ID, TABLE_1_ID, COLUMN_1_1_ID); + }); + } + + @Test + @WithMockUser(username = USER_4_USERNAME) + public void analyseTableColumn_noRole_fails() { + + /* test */ + assertThrows(AccessDeniedException.class, () -> { + analyseTableColumn_generic(DATABASE_1_ID, TABLE_1_ID, COLUMN_1_1_ID); + }); + } + + @Test + @WithMockUser(username = USER_1_USERNAME, authorities = {"table-semantic-analyse"}) + public void analyseTableColumn_hasRole_succeeds() throws QueryMalformedException, TableColumnNotFoundException { + + /* test */ + analyseTableColumn_generic(DATABASE_1_ID, TABLE_1_ID, COLUMN_1_1_ID); + } + + /* ################################################################################################### */ + /* ## GENERIC TEST CASES ## */ + /* ################################################################################################### */ + + public void analyseTable_generic(Long databaseId, Long tableId) throws TableNotFoundException, QueryMalformedException { + + /* mock */ + when(tableService.suggestTableSemantics(databaseId, tableId)) + .thenReturn(List.of()); + + /* test */ + final ResponseEntity<List<EntityDto>> response = tableEndpoint.analyseTable(databaseId, tableId); + assertEquals(HttpStatus.OK, response.getStatusCode()); + final List<EntityDto> body = response.getBody(); + assertNotNull(body); + } + + public void analyseTableColumn_generic(Long databaseId, Long tableId, Long columnId) throws QueryMalformedException, + TableColumnNotFoundException { + + /* mock */ + when(tableService.suggestTableColumnSemantics(databaseId, tableId, columnId)) + .thenReturn(List.of()); + + /* test */ + final ResponseEntity<List<TableColumnEntityDto>> response = tableEndpoint.analyseTableColumn(databaseId, tableId, columnId); + assertEquals(HttpStatus.OK, response.getStatusCode()); + final List<TableColumnEntityDto> body = response.getBody(); + assertNotNull(body); + } +} diff --git a/dbrepo-semantics-service/rest-service/src/test/java/at/tuwien/service/OntologyServiceIntegrationTest.java b/dbrepo-semantics-service/rest-service/src/test/java/at/tuwien/service/OntologyServiceIntegrationTest.java new file mode 100644 index 0000000000000000000000000000000000000000..1dc8023c3d8bcf3499b09df8a5fbadb06535565f --- /dev/null +++ b/dbrepo-semantics-service/rest-service/src/test/java/at/tuwien/service/OntologyServiceIntegrationTest.java @@ -0,0 +1,116 @@ +package at.tuwien.service; + +import at.tuwien.BaseUnitTest; +import at.tuwien.entities.semantics.Ontology; +import at.tuwien.exception.OntologyNotFoundException; +import at.tuwien.exception.UserNotFoundException; +import at.tuwien.repository.jpa.OntologyRepository; +import at.tuwien.repository.jpa.RealmRepository; +import at.tuwien.repository.jpa.UserRepository; +import lombok.extern.log4j.Log4j2; +import org.apache.jena.sys.JenaSystem; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +@Log4j2 +@SpringBootTest +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) +@ExtendWith(SpringExtension.class) +public class OntologyServiceIntegrationTest extends BaseUnitTest { + + @Autowired + private OntologyService ontologyService; + + @Autowired + private UserRepository userRepository; + + @Autowired + private RealmRepository realmRepository; + + @Autowired + private OntologyRepository ontologyRepository; + + @BeforeAll + public static void beforeAll() { + JenaSystem.init(); + } + + @BeforeEach + public void beforeEach() { + realmRepository.save(REALM_DBREPO); + userRepository.save(USER_1); + ontologyRepository.save(ONTOLOGY_1); + ontologyRepository.save(ONTOLOGY_2); + } + + @Test + public void findAll_succeeds() { + + /* test */ + final List<Ontology> response = ontologyService.findAll(); + assertEquals(2, response.size()); + } + + @Test + public void find_succeeds() throws OntologyNotFoundException { + + /* test */ + final Ontology response = ontologyService.find(ONTOLOGY_1_ID); + assertEquals(ONTOLOGY_1_ID, response.getId()); + assertEquals(ONTOLOGY_1_URI, response.getUri()); + } + + @Test + public void find_fails() { + + /* test */ + assertThrows(OntologyNotFoundException.class, () -> { + ontologyService.find(9999L); + }); + } + + @Test + public void create_succeeds() throws UserNotFoundException { + + /* test */ + final Ontology response = ontologyService.create(ONTOLOGY_3_CREATE_DTO, USER_1_PRINCIPAL); + assertEquals(ONTOLOGY_3_ID, response.getId()); + assertEquals(ONTOLOGY_3_URI, response.getUri()); + } + + @Test + public void create_notFound_fails() { + + /* test */ + assertThrows(UserNotFoundException.class, () -> { + ontologyService.create(ONTOLOGY_3_CREATE_DTO, USER_3_PRINCIPAL); + }); + } + + @Test + public void delete_succeeds() throws OntologyNotFoundException { + + /* test */ + ontologyService.delete(ONTOLOGY_1_ID); + } + + @Test + public void delete_fails() { + + /* test */ + assertThrows(OntologyNotFoundException.class, () -> { + ontologyService.delete(9999L); + }); + } +} diff --git a/dbrepo-semantics-service/rest-service/src/test/java/at/tuwien/service/QueryServiceUnitTest.java b/dbrepo-semantics-service/rest-service/src/test/java/at/tuwien/service/QueryServiceIntegrationTest.java similarity index 65% rename from dbrepo-semantics-service/rest-service/src/test/java/at/tuwien/service/QueryServiceUnitTest.java rename to dbrepo-semantics-service/rest-service/src/test/java/at/tuwien/service/QueryServiceIntegrationTest.java index 0a7ee7eb9144bb4f0bcdee3f8b08ea7d1c030851..42af85f682e383c07469c9ac9f6abdac422ed202 100644 --- a/dbrepo-semantics-service/rest-service/src/test/java/at/tuwien/service/QueryServiceUnitTest.java +++ b/dbrepo-semantics-service/rest-service/src/test/java/at/tuwien/service/QueryServiceIntegrationTest.java @@ -10,21 +10,23 @@ import lombok.extern.log4j.Log4j2; import org.apache.jena.sys.JenaSystem; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.junit.jupiter.SpringExtension; import java.util.List; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.*; @Log4j2 @SpringBootTest +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) @ExtendWith(SpringExtension.class) -public class QueryServiceUnitTest extends BaseUnitTest { +public class QueryServiceIntegrationTest extends BaseUnitTest { @Autowired private RealmRepository realmRepository; @@ -47,10 +49,7 @@ public class QueryServiceUnitTest extends BaseUnitTest { public void beforeEach() { realmRepository.save(REALM_DBREPO); userRepository.save(USER_1); - ontologyRepository.save(ONTOLOGY_1); - ontologyRepository.save(ONTOLOGY_2); - ontologyRepository.save(ONTOLOGY_3); - ontologyRepository.save(ONTOLOGY_4); + ontologyRepository.saveAll(List.of(ONTOLOGY_1, ONTOLOGY_2, ONTOLOGY_3, ONTOLOGY_4)); } @Test @@ -65,15 +64,27 @@ public class QueryServiceUnitTest extends BaseUnitTest { } @Test - public void findByLabel_measurements_succeeds() throws QueryMalformedException { + @Disabled + public void findByLabel_measurements_fails() throws QueryMalformedException { /* test */ final List<EntityDto> response = queryService.findByLabel(ONTOLOGY_1, "tonne"); assertEquals(1, response.size()); final EntityDto entity0 = response.get(0); assertEquals(COLUMN_UNIT_TON_NAME, entity0.getLabel()); - assertEquals(COLUMN_UNIT_TON_URI, entity0.getUri()); - assertEquals(COLUMN_UNIT_TON_DESCRIPTION, entity0.getDescription()); + assertNull(COLUMN_UNIT_TON_URI); + assertNull(COLUMN_UNIT_TON_DESCRIPTION); + } + + @Test + public void findByLabel_dbpedia_succeeds() throws QueryMalformedException { + + /* test */ + final List<EntityDto> response = queryService.findByLabel(ONTOLOGY_5, "person"); + assertTrue(response.size() >= 1); + final EntityDto entity0 = response.get(0); + assertEquals("person", entity0.getLabel()); + assertNull(entity0.getDescription()); } @Test @@ -97,14 +108,27 @@ public class QueryServiceUnitTest extends BaseUnitTest { } @Test - public void findByUri_measurements_succeeds() throws QueryMalformedException { + @Disabled + public void findByUri_measurements_fails() throws QueryMalformedException { /* test */ final List<EntityDto> response = queryService.findByUri(ONTOLOGY_1, COLUMN_UNIT_TON_URI); assertEquals(1, response.size()); final EntityDto entity0 = response.get(0); assertEquals(COLUMN_UNIT_TON_URI, entity0.getUri()); - assertEquals(COLUMN_UNIT_TON_NAME, entity0.getLabel()); - assertEquals(COLUMN_UNIT_TON_DESCRIPTION, entity0.getDescription()); + assertNull(COLUMN_UNIT_TON_NAME); + assertNull(COLUMN_UNIT_TON_DESCRIPTION); + } + + @Test + public void findByUri_dbpedia_fails() throws QueryMalformedException { + + /* test */ + final List<EntityDto> response = queryService.findByUri(ONTOLOGY_5, "http://dbpedia.org/ontology/person"); + assertEquals(1, response.size()); + final EntityDto entity0 = response.get(0); + assertEquals("http://dbpedia.org/ontology/person", entity0.getUri()); + assertEquals("person", entity0.getLabel()); + assertNull(entity0.getDescription()); } } diff --git a/dbrepo-semantics-service/rest-service/src/test/java/at/tuwien/service/SemanticServiceUnitTest.java b/dbrepo-semantics-service/rest-service/src/test/java/at/tuwien/service/SemanticServiceUnitTest.java index 0b997fd6b7d2f65d1c4f68cd03778fde4b2ec67a..ed5171a3327ff929282ee9b5d71c477220a46213 100644 --- a/dbrepo-semantics-service/rest-service/src/test/java/at/tuwien/service/SemanticServiceUnitTest.java +++ b/dbrepo-semantics-service/rest-service/src/test/java/at/tuwien/service/SemanticServiceUnitTest.java @@ -9,7 +9,6 @@ import org.apache.jena.sys.JenaSystem; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.ArgumentMatchers; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; diff --git a/dbrepo-semantics-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationTest.java b/dbrepo-semantics-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c81035a6db938872ba93eb540d3dff5c6b85f6ae --- /dev/null +++ b/dbrepo-semantics-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationTest.java @@ -0,0 +1,79 @@ +package at.tuwien.service; + +import at.tuwien.BaseUnitTest; +import at.tuwien.api.semantics.EntityDto; +import at.tuwien.api.semantics.TableColumnEntityDto; +import at.tuwien.entities.database.table.columns.TableColumnKey; +import at.tuwien.exception.QueryMalformedException; +import at.tuwien.exception.TableColumnNotFoundException; +import at.tuwien.exception.TableNotFoundException; +import at.tuwien.repository.jpa.OntologyRepository; +import at.tuwien.repository.jpa.TableColumnRepository; +import at.tuwien.repository.jpa.TableRepository; +import lombok.extern.log4j.Log4j2; +import org.apache.jena.sys.JenaSystem; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import java.util.List; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +@Log4j2 +@SpringBootTest +@ExtendWith(SpringExtension.class) +public class TableServiceIntegrationTest extends BaseUnitTest { + + @Autowired + private TableService tableService; + + @MockBean + private TableRepository tableRepository; + + @MockBean + private OntologyRepository ontologyRepository; + + @MockBean + private TableColumnRepository tableColumnRepository; + + @BeforeAll + public static void beforeAll() { + JenaSystem.init(); + } + + @Test + public void suggestTableSemantics_success() throws TableNotFoundException, QueryMalformedException { + + /* mock */ + when(tableRepository.findByDatabaseIdAndId(DATABASE_1_ID, TABLE_1_ID)) + .thenReturn(Optional.of(TABLE_1)); + when(ontologyRepository.findAll()) + .thenReturn(List.of(ONTOLOGY_1, ONTOLOGY_2, ONTOLOGY_3, ONTOLOGY_4, ONTOLOGY_5)); + + /* test */ + final List<EntityDto> response = tableService.suggestTableSemantics(DATABASE_1_ID, TABLE_1_ID); + assertNotNull(response); + } + + @Test + public void suggestTableColumnSemantics_success() throws QueryMalformedException, TableColumnNotFoundException { + + /* mock */ + when(tableColumnRepository.findById(any(TableColumnKey.class))) + .thenReturn(Optional.of(TABLE_1_COLUMNS.get(0))); + when(ontologyRepository.findAll()) + .thenReturn(List.of(ONTOLOGY_1, ONTOLOGY_2, ONTOLOGY_3, ONTOLOGY_4, ONTOLOGY_5)); + + /* test */ + final List<TableColumnEntityDto> response = tableService.suggestTableColumnSemantics(DATABASE_1_ID, TABLE_1_ID, COLUMN_1_1_ID); + assertNotNull(response); + } +} diff --git a/dbrepo-semantics-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java b/dbrepo-semantics-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java new file mode 100644 index 0000000000000000000000000000000000000000..f84d3ea1d96b118a7da4bd468b11bfa4303a6045 --- /dev/null +++ b/dbrepo-semantics-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java @@ -0,0 +1,63 @@ +package at.tuwien.service; + +import at.tuwien.BaseUnitTest; +import at.tuwien.entities.database.table.Table; +import at.tuwien.exception.TableNotFoundException; +import at.tuwien.repository.jpa.TableRepository; +import lombok.extern.log4j.Log4j2; +import org.apache.jena.sys.JenaSystem; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.when; + +@Log4j2 +@SpringBootTest +@ExtendWith(SpringExtension.class) +public class TableServiceUnitTest extends BaseUnitTest { + + @Autowired + private TableService tableService; + + @MockBean + private TableRepository tableRepository; + + @BeforeAll + public static void beforeAll() { + JenaSystem.init(); + } + + @Test + public void find_success() throws TableNotFoundException { + + /* mock */ + when(tableRepository.findByDatabaseIdAndId(DATABASE_1_ID, TABLE_1_ID)) + .thenReturn(Optional.of(TABLE_1)); + + /* test */ + final Table response = tableService.find(DATABASE_1_ID, TABLE_1_ID); + assertEquals(TABLE_1_ID, response.getId()); + } + + @Test + public void find_fails() { + + /* mock */ + when(tableRepository.findByDatabaseIdAndId(DATABASE_1_ID, TABLE_1_ID)) + .thenReturn(Optional.empty()); + + /* test */ + assertThrows(TableNotFoundException.class, () -> { + tableService.find(DATABASE_1_ID, TABLE_1_ID); + }); + } +} diff --git a/dbrepo-semantics-service/services/src/main/java/at/tuwien/exception/UserNotFoundException.java b/dbrepo-semantics-service/services/src/main/java/at/tuwien/exception/UserNotFoundException.java new file mode 100644 index 0000000000000000000000000000000000000000..f758f7ddf3b3a9d28b2bfc7584a829e41d7c125f --- /dev/null +++ b/dbrepo-semantics-service/services/src/main/java/at/tuwien/exception/UserNotFoundException.java @@ -0,0 +1,21 @@ +package at.tuwien.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.NOT_FOUND) +public class UserNotFoundException extends Exception { + + public UserNotFoundException(String msg) { + super(msg); + } + + public UserNotFoundException(String msg, Throwable thr) { + super(msg, thr); + } + + public UserNotFoundException(Throwable thr) { + super(thr); + } + +} diff --git a/dbrepo-semantics-service/services/src/main/java/at/tuwien/service/OntologyService.java b/dbrepo-semantics-service/services/src/main/java/at/tuwien/service/OntologyService.java index f903a67428090f455ca6c1e5e9434445cf69c943..4a55f52491007c5ecae69bc6c59698541284a528 100644 --- a/dbrepo-semantics-service/services/src/main/java/at/tuwien/service/OntologyService.java +++ b/dbrepo-semantics-service/services/src/main/java/at/tuwien/service/OntologyService.java @@ -4,7 +4,9 @@ import at.tuwien.api.semantics.OntologyCreateDto; import at.tuwien.api.semantics.OntologyModifyDto; import at.tuwien.entities.semantics.Ontology; import at.tuwien.exception.OntologyNotFoundException; +import at.tuwien.exception.UserNotFoundException; +import java.security.Principal; import java.util.List; public interface OntologyService { @@ -12,7 +14,7 @@ public interface OntologyService { Ontology find(Long id) throws OntologyNotFoundException; - Ontology create(OntologyCreateDto data); + Ontology create(OntologyCreateDto data, Principal principal) throws UserNotFoundException; Ontology update(Long id, OntologyModifyDto data) throws OntologyNotFoundException; diff --git a/dbrepo-semantics-service/services/src/main/java/at/tuwien/service/UserService.java b/dbrepo-semantics-service/services/src/main/java/at/tuwien/service/UserService.java new file mode 100644 index 0000000000000000000000000000000000000000..6de26b3ffc045f5b7c4ac19223581e0f73a98b86 --- /dev/null +++ b/dbrepo-semantics-service/services/src/main/java/at/tuwien/service/UserService.java @@ -0,0 +1,8 @@ +package at.tuwien.service; + +import at.tuwien.entities.user.User; +import at.tuwien.exception.UserNotFoundException; + +public interface UserService { + User findByUsername(String username) throws UserNotFoundException; +} diff --git a/dbrepo-semantics-service/services/src/main/java/at/tuwien/service/impl/OntologyServiceImpl.java b/dbrepo-semantics-service/services/src/main/java/at/tuwien/service/impl/OntologyServiceImpl.java index 591538373140e9cacf00d5926e10daef58626520..5137f9f92d234d32b3f905fa634b13a68777c7a0 100644 --- a/dbrepo-semantics-service/services/src/main/java/at/tuwien/service/impl/OntologyServiceImpl.java +++ b/dbrepo-semantics-service/services/src/main/java/at/tuwien/service/impl/OntologyServiceImpl.java @@ -3,14 +3,18 @@ package at.tuwien.service.impl; import at.tuwien.api.semantics.OntologyCreateDto; import at.tuwien.api.semantics.OntologyModifyDto; import at.tuwien.entities.semantics.Ontology; +import at.tuwien.entities.user.User; import at.tuwien.exception.OntologyNotFoundException; +import at.tuwien.exception.UserNotFoundException; import at.tuwien.mapper.OntologyMapper; import at.tuwien.repository.jpa.OntologyRepository; import at.tuwien.service.OntologyService; +import at.tuwien.service.UserService; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.security.Principal; import java.util.List; import java.util.Optional; @@ -18,11 +22,14 @@ import java.util.Optional; @Service public class OntologyServiceImpl implements OntologyService { + private final UserService userService; private final OntologyMapper ontologyMapper; private final OntologyRepository ontologyRepository; @Autowired - public OntologyServiceImpl(OntologyMapper ontologyMapper, OntologyRepository ontologyRepository) { + public OntologyServiceImpl(UserService userService, OntologyMapper ontologyMapper, + OntologyRepository ontologyRepository) { + this.userService = userService; this.ontologyMapper = ontologyMapper; this.ontologyRepository = ontologyRepository; } @@ -43,8 +50,11 @@ public class OntologyServiceImpl implements OntologyService { } @Override - public Ontology create(OntologyCreateDto data) { - final Ontology ontology = ontologyRepository.save(ontologyMapper.ontologyCreateDtoToOntology(data)); + public Ontology create(OntologyCreateDto data, Principal principal) throws UserNotFoundException { + final User user = userService.findByUsername(principal.getName()); + final Ontology entity = ontologyMapper.ontologyCreateDtoToOntology(data); + entity.setCreatedBy(user.getId()); + final Ontology ontology = ontologyRepository.save(entity); log.info("Created ontology with id {}", ontology.getId()); return ontology; } diff --git a/dbrepo-semantics-service/services/src/main/java/at/tuwien/service/impl/QueryServiceImpl.java b/dbrepo-semantics-service/services/src/main/java/at/tuwien/service/impl/QueryServiceImpl.java index 5b51cfdf8c7457b38c748d4b955516a5e51e1740..742c2090371ede84aa77b90e3dd00c862388bd4c 100644 --- a/dbrepo-semantics-service/services/src/main/java/at/tuwien/service/impl/QueryServiceImpl.java +++ b/dbrepo-semantics-service/services/src/main/java/at/tuwien/service/impl/QueryServiceImpl.java @@ -7,22 +7,15 @@ import at.tuwien.mapper.OntologyMapper; import at.tuwien.repository.jpa.OntologyRepository; import at.tuwien.service.QueryService; import lombok.extern.log4j.Log4j2; -import org.apache.jena.graph.Node; -import org.apache.jena.graph.NodeFactory; import org.apache.jena.query.*; import org.apache.jena.rdf.model.RDFNode; import org.apache.jena.riot.RiotException; -import org.apache.jena.sparql.algebra.op.OpService; -import org.apache.jena.sparql.service.ServiceExecutorRegistry; -import org.apache.jena.sparql.service.single.ChainingServiceExecutor; -import org.apache.jena.sparql.util.Context; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.Iterator; import java.util.LinkedList; import java.util.List; -import java.util.Objects; @Log4j2 @Service @@ -33,29 +26,10 @@ public class QueryServiceImpl implements QueryService { private final OntologyRepository ontologyRepository; @Autowired - public QueryServiceImpl(OntologyRepository ontologyRepository, OntologyMapper ontologyMapper, - OntologyRepository ontologyRepository1) { + public QueryServiceImpl(OntologyRepository ontologyRepository, OntologyMapper ontologyMapper) { this.ontologyMapper = ontologyMapper; - this.ontologyRepository = ontologyRepository1; - final Context context = ARQ.getContext().copy(); + this.ontologyRepository = ontologyRepository; this.dataset = DatasetFactory.create(); - /* registry */ - final ServiceExecutorRegistry registry = ServiceExecutorRegistry.get(context).copy(); - ontologyRepository.findAll() - .stream() - .filter(o -> Objects.nonNull(o.getSparqlEndpoint())) - .forEach(ontology -> { - final Node node = NodeFactory.createURI(ontology.getSparqlEndpoint()); - ChainingServiceExecutor relaySef = (opExecute, original, binding, execCxt, chain) -> { - if (opExecute.getService().equals(node)) { - opExecute = new OpService(node, opExecute.getSubOp(), opExecute.getSilent()); - } - return chain.createExecution(opExecute, original, binding, execCxt); - }; - log.debug("add sparql endpoint {}", ontology.getSparqlEndpoint()); - registry.addSingleLink(relaySef); - }); - ServiceExecutorRegistry.set(context, registry); } @Override diff --git a/dbrepo-semantics-service/services/src/main/java/at/tuwien/service/impl/UserServiceImpl.java b/dbrepo-semantics-service/services/src/main/java/at/tuwien/service/impl/UserServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..99bc7ae5d4b79169e3864397427310ef9e78ffab --- /dev/null +++ b/dbrepo-semantics-service/services/src/main/java/at/tuwien/service/impl/UserServiceImpl.java @@ -0,0 +1,34 @@ +package at.tuwien.service.impl; + +import at.tuwien.entities.user.User; +import at.tuwien.exception.UserNotFoundException; +import at.tuwien.repository.jpa.UserRepository; +import at.tuwien.service.UserService; +import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Optional; + +@Log4j2 +@Service +public class UserServiceImpl implements UserService { + + private final UserRepository userRepository; + + @Autowired + public UserServiceImpl(UserRepository userRepository) { + this.userRepository = userRepository; + } + + @Override + public User findByUsername(String username) throws UserNotFoundException { + final Optional<User> optional = userRepository.findByUsername(username); + if (optional.isEmpty()) { + log.error("Failed to find user with username {}", username); + throw new UserNotFoundException("Failed to find user with username " + username); + } + return optional.get(); + } + +} diff --git a/dbrepo-ui/components/dialogs/Semantics.vue b/dbrepo-ui/components/dialogs/Semantics.vue index caf59080020368b8c0989eaa9874ed42169d901c..12f5457002c7369bd6e2526658bf654b5b683692 100644 --- a/dbrepo-ui/components/dialogs/Semantics.vue +++ b/dbrepo-ui/components/dialogs/Semantics.vue @@ -16,13 +16,15 @@ icon="mdi-share-variant" class="pl-6"> <p> - The following ontologies automatically will query the fields <code>rdfs:label</code> and - <code>schema:description</code> and store it for this column. You can still use other URIs that are not - matching these ontologies, the URI will be displayed instead. + The following ontologies automatically will query the fields <code>rdfs:label</code> and store it for this + column. You can still use other URIs that are not matching these ontologies, the URI will be displayed + instead. </p> - <div v-for="(item,idx) in ontologies" :key="idx"> - <a :href="item.uri" target="_blank" v-text="item.uri" /> - </div> + <ul> + <li v-for="(item,idx) in ontologies" :key="idx"> + <a :href="item.uri" target="_blank" v-text="item.uri" /> + </li> + </ul> </v-alert> <v-alert v-if="entity" @@ -60,10 +62,12 @@ <v-text-field v-model="uri" :loading="loading" + :success="canAutomaticResolve" + :hint="canAutomaticResolve ? 'This URI can be automatically resolved!' : 'e.g. http://www.wikidata.org/entity/Q468777'" + :persistent-hint="canAutomaticResolve" clearable label="URI" :rules="[v => isUri(v) || $t('Must start with http:// or https://')]" - hint="e.g. http://www.wikidata.org/entity/Q468777" @click:clear="uri = null" /> </v-col> </v-row> @@ -128,7 +132,23 @@ export default { }, computed: { ontologies () { - return this.$store.state.ontologies + const ontologies = this.$store.state.ontologies + if (!ontologies) { + return [] + } + return ontologies.filter(o => o.sparql) + }, + canAutomaticResolve () { + if (!this.uri) { + return false + } + let found = false + this.ontologies.forEach((o) => { + if (this.uri.startsWith(o.uri)) { + found = true + } + }) + return found }, entity () { if (!this.column[this.mode]) { diff --git a/dbrepo-ui/layouts/default.vue b/dbrepo-ui/layouts/default.vue index 30596e71b7a544decbfacd93c71eb9d1cb10587a..44edd4a29c34e41e304c0c5f0c319222ddac6b68 100644 --- a/dbrepo-ui/layouts/default.vue +++ b/dbrepo-ui/layouts/default.vue @@ -239,7 +239,6 @@ export default { }, mounted () { this.$store.dispatch('reloadMessages') - this.$store.dispatch('reloadOntologies') if (this.locale) { this.$i18n.locale = this.locale } diff --git a/dbrepo-ui/pages/container/_container_id/database/_database_id/table/_table_id/schema.vue b/dbrepo-ui/pages/container/_container_id/database/_database_id/table/_table_id/schema.vue index d5c3d1b0778113e068d10088f25c87bce469a702..54d91815591affdff3feea672bc6a1d478725dbb 100644 --- a/dbrepo-ui/pages/container/_container_id/database/_database_id/table/_table_id/schema.vue +++ b/dbrepo-ui/pages/container/_container_id/database/_database_id/table/_table_id/schema.vue @@ -168,6 +168,7 @@ export default { } }, mounted () { + this.$store.dispatch('reloadOntologies') }, methods: { isUnique (column) {