diff --git a/src/main/java/de/numcodex/feasibility_gui_backend/query/QueryHandlerService.java b/src/main/java/de/numcodex/feasibility_gui_backend/query/QueryHandlerService.java index da6954d6..eb5c6093 100644 --- a/src/main/java/de/numcodex/feasibility_gui_backend/query/QueryHandlerService.java +++ b/src/main/java/de/numcodex/feasibility_gui_backend/query/QueryHandlerService.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import de.numcodex.feasibility_gui_backend.common.api.TermCode; import de.numcodex.feasibility_gui_backend.query.api.Query; import de.numcodex.feasibility_gui_backend.query.api.QueryTemplate; import de.numcodex.feasibility_gui_backend.query.api.SavedQuery; @@ -14,6 +15,7 @@ import de.numcodex.feasibility_gui_backend.query.result.ResultService; import de.numcodex.feasibility_gui_backend.query.templates.QueryTemplateException; import de.numcodex.feasibility_gui_backend.query.templates.QueryTemplateHandler; +import de.numcodex.feasibility_gui_backend.terminology.validation.TermCodeValidation; import lombok.NonNull; import lombok.RequiredArgsConstructor; import org.springframework.dao.DataIntegrityViolationException; @@ -58,6 +60,9 @@ public enum ResultDetail { @NonNull private final SavedQueryRepository savedQueryRepository; + @NonNull + private final TermCodeValidation termCodeValidation; + @NonNull private ObjectMapper jsonUtil; @@ -235,28 +240,44 @@ public String getAuthorId(Long queryId) throws QueryNotFoundException { return queryRepository.getAuthor(queryId).orElseThrow(QueryNotFoundException::new); } - public List convertQueriesToQueryListEntries(List queryList) { - var ret = new ArrayList(); + public QueryListEntry convertQueryToQueryListEntry(de.numcodex.feasibility_gui_backend.query.persistence.Query query, + boolean skipValidation) { + List invalidTermCodes; + if (skipValidation) { + invalidTermCodes = List.of(); + } else { + try { + var sq = jsonUtil.readValue(query.getQueryContent().getQueryContent(), StructuredQuery.class); + invalidTermCodes = termCodeValidation.getInvalidTermCodes(sq); + } catch (JsonProcessingException e) { + invalidTermCodes = List.of(); + } + } - queryList.forEach(q -> { - if (q.getSavedQuery() != null) { - ret.add( - QueryListEntry.builder() - .id(q.getId()) - .label(q.getSavedQuery().getLabel()) - .comment(q.getSavedQuery().getComment()) - .totalNumberOfPatients(q.getSavedQuery().getResultSize()) - .createdAt(q.getCreatedAt()) - .build()); - } else { - ret.add( - QueryListEntry.builder() - .id(q.getId()) - .createdAt(q.getCreatedAt()) - .build()); - } - }); + if (query.getSavedQuery() != null) { + return + QueryListEntry.builder() + .id(query.getId()) + .label(query.getSavedQuery().getLabel()) + .comment(query.getSavedQuery().getComment()) + .totalNumberOfPatients(query.getSavedQuery().getResultSize()) + .createdAt(query.getCreatedAt()) + .invalidTerms(invalidTermCodes) + .build(); + } else { + return + QueryListEntry.builder() + .id(query.getId()) + .createdAt(query.getCreatedAt()) + .invalidTerms(invalidTermCodes) + .build(); + } + } + public List convertQueriesToQueryListEntries(List queryList, + boolean skipValidation) { + var ret = new ArrayList(); + queryList.forEach(q -> ret.add(convertQueryToQueryListEntry(q, skipValidation))); return ret; } diff --git a/src/main/java/de/numcodex/feasibility_gui_backend/query/api/QueryListEntry.java b/src/main/java/de/numcodex/feasibility_gui_backend/query/api/QueryListEntry.java index b06f1c62..9a65b565 100644 --- a/src/main/java/de/numcodex/feasibility_gui_backend/query/api/QueryListEntry.java +++ b/src/main/java/de/numcodex/feasibility_gui_backend/query/api/QueryListEntry.java @@ -3,9 +3,11 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.annotation.JsonProperty; +import de.numcodex.feasibility_gui_backend.common.api.TermCode; import lombok.Builder; import java.sql.Timestamp; +import java.util.List; @JsonInclude(Include.NON_NULL) @Builder @@ -14,7 +16,8 @@ public record QueryListEntry( @JsonProperty String label, @JsonProperty String comment, @JsonProperty Timestamp createdAt, - @JsonProperty Long totalNumberOfPatients + @JsonProperty Long totalNumberOfPatients, + @JsonProperty List invalidTerms ) { } diff --git a/src/main/java/de/numcodex/feasibility_gui_backend/query/v3/QueryHandlerRestController.java b/src/main/java/de/numcodex/feasibility_gui_backend/query/v3/QueryHandlerRestController.java index d06d96fe..cfa6dfaa 100644 --- a/src/main/java/de/numcodex/feasibility_gui_backend/query/v3/QueryHandlerRestController.java +++ b/src/main/java/de/numcodex/feasibility_gui_backend/query/v3/QueryHandlerRestController.java @@ -185,11 +185,12 @@ private URI buildResultLocationUri(HttpServletRequest httpServletRequest, @GetMapping("") public List getQueryList( @RequestParam(name = "filter", required = false) String filter, + @RequestParam(value = "skipValidation", required = false, defaultValue = "false") boolean skipValidation, Principal principal) { var userId = principal.getName(); var savedOnly = (filter != null && filter.equalsIgnoreCase("saved")); var queryList = queryHandlerService.getQueryListForAuthor(userId, savedOnly); - return queryHandlerService.convertQueriesToQueryListEntries(queryList); + return queryHandlerService.convertQueriesToQueryListEntries(queryList, skipValidation); } @PostMapping("/{id}/saved") @@ -296,7 +297,7 @@ public List getQueryListForUser( @RequestParam(name = "filter", required = false) String filter) { var savedOnly = (filter != null && filter.equalsIgnoreCase("saved")); var queryList = queryHandlerService.getQueryListForAuthor(userId, savedOnly); - return queryHandlerService.convertQueriesToQueryListEntries(queryList); + return queryHandlerService.convertQueriesToQueryListEntries(queryList, true); } @GetMapping("/{id}") diff --git a/src/main/java/de/numcodex/feasibility_gui_backend/query/v3/QueryTemplateHandlerRestController.java b/src/main/java/de/numcodex/feasibility_gui_backend/query/v3/QueryTemplateHandlerRestController.java index 9b1d6025..3cce880c 100644 --- a/src/main/java/de/numcodex/feasibility_gui_backend/query/v3/QueryTemplateHandlerRestController.java +++ b/src/main/java/de/numcodex/feasibility_gui_backend/query/v3/QueryTemplateHandlerRestController.java @@ -97,22 +97,31 @@ public ResponseEntity getQueryTemplate(@PathVariable(value = "queryId") } @GetMapping(path = "") - public ResponseEntity getQueryTemplates(Principal principal) { + public ResponseEntity getQueryTemplates( + @RequestParam(value = "skipValidation", required = false, defaultValue = "false") boolean skipValidation, + Principal principal) { var queries = queryHandlerService.getQueryTemplatesForAuthor(principal.getName()); var ret = new ArrayList(); queries.forEach(q -> { try { QueryTemplate convertedQuery = queryHandlerService.convertTemplatePersistenceToApi(q); + List invalidTermCodes; + if (skipValidation) { + invalidTermCodes = List.of(); + } else { + invalidTermCodes = termCodeValidation.getInvalidTermCodes( + convertedQuery.content()); + } var convertedQueryWithoutContent = QueryTemplate.builder() - .id(convertedQuery.id()) - .label(convertedQuery.label()) - .comment(convertedQuery.comment()) - .lastModified(convertedQuery.lastModified()) - .createdBy(convertedQuery.createdBy()) - .invalidTerms(convertedQuery.invalidTerms()) - .isValid(convertedQuery.isValid()) - .build(); + .id(convertedQuery.id()) + .label(convertedQuery.label()) + .comment(convertedQuery.comment()) + .lastModified(convertedQuery.lastModified()) + .createdBy(convertedQuery.createdBy()) + .invalidTerms(invalidTermCodes) + .isValid(convertedQuery.isValid()) + .build(); ret.add(convertedQueryWithoutContent); } catch (JsonProcessingException e) { log.error("Error converting query"); @@ -143,32 +152,4 @@ public ResponseEntity deleteQueryTemplate(@PathVariable(value = "queryTe return new ResponseEntity<>(HttpStatus.NOT_FOUND); } } - - @GetMapping(path = "/validate") - public ResponseEntity validateTemplates(Principal principal) { - - var queries = queryHandlerService.getQueryTemplatesForAuthor(principal.getName()); - var ret = new ArrayList(); - queries.forEach(q -> { - try { - QueryTemplate convertedQuery = queryHandlerService.convertTemplatePersistenceToApi(q); - List invalidTermCodes = termCodeValidation.getInvalidTermCodes( - convertedQuery.content()); - var convertedQueryWithoutContent = QueryTemplate.builder() - .id(convertedQuery.id()) - .label(convertedQuery.label()) - .comment(convertedQuery.comment()) - .lastModified(convertedQuery.lastModified()) - .createdBy(convertedQuery.createdBy()) - .invalidTerms(invalidTermCodes) - .isValid(convertedQuery.isValid()) - .build(); - ret.add(convertedQueryWithoutContent); - } catch (JsonProcessingException e) { - log.error("Error converting query"); - } - }); - return new ResponseEntity<>(ret, HttpStatus.OK); - } - } diff --git a/src/main/resources/static/v3/api-docs/swagger.yaml b/src/main/resources/static/v3/api-docs/swagger.yaml index a7fc50ba..98e88284 100644 --- a/src/main/resources/static/v3/api-docs/swagger.yaml +++ b/src/main/resources/static/v3/api-docs/swagger.yaml @@ -87,6 +87,13 @@ paths: type: string enum: - saved + - name: skipValidation + in: query + description: If true, do not validate the query and do not include a list of invalid terms + required: false + schema: + type: boolean + default: false responses: 200: description: successful operation @@ -505,6 +512,14 @@ paths: summary: Read list of query templates description: Returns the list of all query templates of the current user operationId: getQueryTemplateList + parameters: + - name: skipValidation + in: query + description: If true, do not validate the query and do not include a list of invalid terms + required: false + schema: + type: boolean + default: false responses: 200: description: OK @@ -612,27 +627,6 @@ paths: security: - feasibility_auth: - user - /query/template/validate: - get: - tags: - - templates - summary: Check all own query templates for invalid or outdated termcodes - description: Returns a list of query templates with the additional info if a query is valid - operationId: validateQueryTemplateList - responses: - 200: - description: OK - content: - application/json: - schema: - items: - $ref: '#/components/schemas/QueryTemplate' - 401: - description: Unauthorized - please login first - content: { } - security: - - feasibility_auth: - - read:query /terminology/categories: get: tags: @@ -817,6 +811,7 @@ components: required: - id - label + - invalidTerms properties: id: type: integer @@ -830,6 +825,10 @@ components: format: 'date-time' totalNumberOfPatients: type: integer + invalidTerms: + type: array + items: + $ref: "#/components/schemas/TermCode" Query: type: object required: @@ -912,6 +911,7 @@ components: type: object required: - label + - invalidTerms properties: id: type: integer @@ -930,6 +930,13 @@ components: createdBy: type: string description: Keycloak id of the user who created the query + invalidTerms: + type: array + items: + $ref: "#/components/schemas/TermCode" + isValid: + type: boolean + description: is the query valid? QueryTemplate: type: object required: diff --git a/src/test/java/de/numcodex/feasibility_gui_backend/query/QueryHandlerServiceIT.java b/src/test/java/de/numcodex/feasibility_gui_backend/query/QueryHandlerServiceIT.java index bc405c7b..0ea53a1c 100644 --- a/src/test/java/de/numcodex/feasibility_gui_backend/query/QueryHandlerServiceIT.java +++ b/src/test/java/de/numcodex/feasibility_gui_backend/query/QueryHandlerServiceIT.java @@ -24,16 +24,17 @@ import java.net.URI; import java.util.List; +import de.numcodex.feasibility_gui_backend.terminology.validation.TermCodeValidation; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.EnumSource; -import org.mockito.Spy; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.context.annotation.Import; import org.springframework.dao.DataIntegrityViolationException; import org.testcontainers.junit.jupiter.Testcontainers; @@ -100,6 +101,9 @@ public class QueryHandlerServiceIT { @Autowired private QueryHashCalculator queryHashCalculator; + @MockBean + private TermCodeValidation termCodeValidation; + @Autowired @Qualifier("translation") private ObjectMapper jsonUtil; diff --git a/src/test/java/de/numcodex/feasibility_gui_backend/query/QueryHandlerServiceTest.java b/src/test/java/de/numcodex/feasibility_gui_backend/query/QueryHandlerServiceTest.java index 463ae0b0..9ea1ddf0 100644 --- a/src/test/java/de/numcodex/feasibility_gui_backend/query/QueryHandlerServiceTest.java +++ b/src/test/java/de/numcodex/feasibility_gui_backend/query/QueryHandlerServiceTest.java @@ -1,7 +1,5 @@ package de.numcodex.feasibility_gui_backend.query; -import com.fasterxml.jackson.databind.ObjectMapper; -import de.numcodex.feasibility_gui_backend.query.api.StructuredQuery; import de.numcodex.feasibility_gui_backend.query.dispatch.QueryDispatchException; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; @@ -13,19 +11,20 @@ import de.numcodex.feasibility_gui_backend.query.persistence.*; import de.numcodex.feasibility_gui_backend.query.result.ResultService; import de.numcodex.feasibility_gui_backend.query.templates.QueryTemplateHandler; +import de.numcodex.feasibility_gui_backend.terminology.validation.TermCodeValidation; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.Spy; import org.mockito.junit.jupiter.MockitoExtension; import reactor.test.StepVerifier; -import java.util.List; - import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; import java.net.URI; @@ -70,11 +69,14 @@ class QueryHandlerServiceTest { @Mock private SavedQueryRepository savedQueryRepository; + @Mock + private TermCodeValidation termCodeValidation; + private QueryHandlerService queryHandlerService; private QueryHandlerService createQueryHandlerService() { return new QueryHandlerService(queryDispatcher, queryTemplateHandler, queryRepository, queryContentRepository, - resultService, queryTemplateRepository, savedQueryRepository, jsonUtil); + resultService, queryTemplateRepository, savedQueryRepository, termCodeValidation, jsonUtil); } @BeforeEach @@ -105,28 +107,46 @@ public void testRunQuery_failsWithMonoErrorOnQueryDispatchException() throws Que .verify(); } - @Test - void convertQueriesToQueryListEntries_withoutSavedQuery() throws JsonProcessingException { - var queryList = List.of(createQuery(false)); + @ParameterizedTest + @CsvSource({"true,true", "true,false", "false,true", "false,false"}) + void convertQueriesToQueryListEntries(String withSavedQuery, String skipValidation) throws JsonProcessingException { + var queryList = List.of(createQuery(Boolean.parseBoolean(withSavedQuery))); + if (!Boolean.parseBoolean(skipValidation)) { + doReturn(List.of(TermCode.builder() + .code("LL2191-6") + .system("http://loinc.org") + .display("Geschlecht") + .build() + )).when(termCodeValidation).getInvalidTermCodes(any(StructuredQuery.class)); + } - List queryListEntries = queryHandlerService.convertQueriesToQueryListEntries(queryList); + List queryListEntries = queryHandlerService.convertQueriesToQueryListEntries(queryList, Boolean.parseBoolean(skipValidation)); assertThat(queryListEntries.size()).isEqualTo(1); assertThat(queryListEntries.get(0).id()).isEqualTo(QUERY_ID); assertThat(queryListEntries.get(0).createdAt()).isEqualTo(LAST_MODIFIED); + if (Boolean.parseBoolean(withSavedQuery)) { + assertThat(queryListEntries.get(0).label()).isEqualTo(LABEL); + assertThat(queryListEntries.get(0).totalNumberOfPatients()).isEqualTo(RESULT_SIZE); + } + if (Boolean.parseBoolean(skipValidation)) { + assertThat(queryListEntries.get(0).invalidTerms().size()).isEqualTo(0); + } else { + assertThat(queryListEntries.get(0).invalidTerms().size()).isEqualTo(1); + } } @Test - void convertQueriesToQueryListEntries_withSavedQuery() throws JsonProcessingException { - var queryList = List.of(createQuery(true)); + void convertQueriesToQueryListEntries_JsonProcessingExceptionCausesEmptyList() throws JsonProcessingException { + var queryList = List.of(createQuery(false)); + doThrow(JsonProcessingException.class).when(jsonUtil).readValue(any(String.class), any(Class.class)); - List queryListEntries = queryHandlerService.convertQueriesToQueryListEntries(queryList); + List queryListEntries = queryHandlerService.convertQueriesToQueryListEntries(queryList, false); assertThat(queryListEntries.size()).isEqualTo(1); assertThat(queryListEntries.get(0).id()).isEqualTo(QUERY_ID); assertThat(queryListEntries.get(0).createdAt()).isEqualTo(LAST_MODIFIED); - assertThat(queryListEntries.get(0).label()).isEqualTo(LABEL); - assertThat(queryListEntries.get(0).totalNumberOfPatients()).isEqualTo(RESULT_SIZE); + assertThat(queryListEntries.get(0).invalidTerms().size()).isEqualTo(0); } private Query createQuery(boolean withSavedQuery) throws JsonProcessingException { diff --git a/src/test/java/de/numcodex/feasibility_gui_backend/query/v3/QueryHandlerRestControllerIT.java b/src/test/java/de/numcodex/feasibility_gui_backend/query/v3/QueryHandlerRestControllerIT.java index 5091262d..79dceaa0 100644 --- a/src/test/java/de/numcodex/feasibility_gui_backend/query/v3/QueryHandlerRestControllerIT.java +++ b/src/test/java/de/numcodex/feasibility_gui_backend/query/v3/QueryHandlerRestControllerIT.java @@ -49,7 +49,6 @@ import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.startsWith; -import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; import static org.springframework.http.MediaType.APPLICATION_JSON; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; @@ -274,14 +273,42 @@ public void testRunQueryEndpoint_SucceedsOnExceedingHardlimitAsPowerUserWith201( @Test @WithMockUser(roles = {"FEASIBILITY_TEST_USER"}, username = "test") - public void testGetQueryList_Succeeds() throws Exception { + public void testGetQueryList_SucceedsWithValidation() throws Exception { long queryId = 1; doReturn(List.of(createValidQuery(queryId))).when(queryHandlerService).getQueryListForAuthor(any(String.class), any(Boolean.class)); - doReturn(List.of(createValidQueryListEntry(queryId))).when(queryHandlerService).convertQueriesToQueryListEntries(anyList()); + doReturn(List.of(createValidQueryListEntry(queryId, false))).when(queryHandlerService).convertQueriesToQueryListEntries(anyList(), any(Boolean.class)); - mockMvc.perform(get(URI.create(PATH_API + PATH_QUERY)).with(csrf())) + mockMvc.perform(get(URI.create(PATH_API + PATH_QUERY)).with(csrf()).param("skipValidation", "false")) .andExpect(status().isOk()) - .andExpect(jsonPath("$[0].id").value(queryId)); + .andExpect(jsonPath("$[0].id").value(queryId)) + .andExpect(jsonPath("$[0].invalidTerms").isNotEmpty()); + } + + @Test + @WithMockUser(roles = {"FEASIBILITY_TEST_USER"}, username = "test") + public void testGetQueryList_SucceedsWithoutValidation() throws Exception { + long queryId = 1; + doReturn(List.of(createValidQuery(queryId))).when(queryHandlerService).getQueryListForAuthor(any(String.class), any(Boolean.class)); + doReturn(List.of(createValidQueryListEntry(queryId, true))).when(queryHandlerService).convertQueriesToQueryListEntries(anyList(), any(Boolean.class)); + + mockMvc.perform(get(URI.create(PATH_API + PATH_QUERY)).with(csrf()).param("skipValidation", "true")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].id").value(queryId)) + .andExpect(jsonPath("$[0].invalidTerms").isArray()) + .andExpect(jsonPath("$[0].invalidTerms").isEmpty()); + } + + @Test + @WithMockUser(roles = {"FEASIBILITY_TEST_USER"}, username = "test") + public void testGetQueryList_SucceedsWithoutDefiningSkipValidation() throws Exception { + long queryId = 1; + doReturn(List.of(createValidQuery(queryId))).when(queryHandlerService).getQueryListForAuthor(any(String.class), any(Boolean.class)); + doReturn(List.of(createValidQueryListEntry(queryId, false))).when(queryHandlerService).convertQueriesToQueryListEntries(anyList(), any(Boolean.class)); + + mockMvc.perform(get(URI.create(PATH_API + PATH_QUERY)).with(csrf())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].id").value(queryId)) + .andExpect(jsonPath("$[0].invalidTerms").isNotEmpty()); } @Test @@ -290,7 +317,7 @@ public void testGetQueryListForUser_SucceedsOnValidUser() throws Exception { long queryId = 1; String userId = "user1"; doReturn(List.of(createValidQuery(queryId))).when(queryHandlerService).getQueryListForAuthor(any(String.class), any(Boolean.class)); - doReturn(List.of(createValidQueryListEntry(queryId))).when(queryHandlerService).convertQueriesToQueryListEntries(anyList()); + doReturn(List.of(createValidQueryListEntry(queryId, false))).when(queryHandlerService).convertQueriesToQueryListEntries(anyList(), any(Boolean.class)); mockMvc.perform(get(URI.create(PATH_API + PATH_QUERY + "/by-user/" + userId)).with(csrf())) .andExpect(status().isOk()) @@ -302,7 +329,7 @@ public void testGetQueryListForUser_SucceedsOnValidUser() throws Exception { public void testGetQueryListForUser_ReturnsEmptyOnUnknownUser() throws Exception { String userId = "user1"; doReturn(List.of()).when(queryHandlerService).getQueryListForAuthor(any(String.class), any(Boolean.class)); - doReturn(List.of()).when(queryHandlerService).convertQueriesToQueryListEntries(anyList()); + doReturn(List.of()).when(queryHandlerService).convertQueriesToQueryListEntries(anyList(), any(Boolean.class)); mockMvc.perform(get(URI.create(PATH_API + PATH_QUERY + "/by-user/" + userId)).with(csrf())) .andExpect(status().isOk()) @@ -656,14 +683,24 @@ private static de.numcodex.feasibility_gui_backend.query.persistence.QueryConten } @NotNull - private static QueryListEntry createValidQueryListEntry(long id) { + private static QueryListEntry createValidQueryListEntry(long id, boolean skipValidation) { return QueryListEntry.builder() .id(id) .label("abc") .createdAt(new Timestamp(new java.util.Date().getTime())) + .invalidTerms(skipValidation ? List.of() : List.of(createTermCode())) .build(); } + @NotNull + private static TermCode createTermCode() { + return TermCode.builder() + .code("LL2191-6") + .system("http://loinc.org") + .display("Geschlecht") + .build(); + } + @NotNull private static Query createValidApiQuery(long id) { return Query.builder() diff --git a/src/test/java/de/numcodex/feasibility_gui_backend/query/v3/QueryTemplateHandlerRestControllerIT.java b/src/test/java/de/numcodex/feasibility_gui_backend/query/v3/QueryTemplateHandlerRestControllerIT.java index bcfb5408..a12e0160 100644 --- a/src/test/java/de/numcodex/feasibility_gui_backend/query/v3/QueryTemplateHandlerRestControllerIT.java +++ b/src/test/java/de/numcodex/feasibility_gui_backend/query/v3/QueryTemplateHandlerRestControllerIT.java @@ -28,7 +28,6 @@ import org.springframework.test.web.servlet.MockMvc; import java.net.URI; -import java.security.Principal; import java.sql.Timestamp; import java.util.ArrayList; import java.util.List; @@ -162,7 +161,7 @@ public void testGetQueryTemplateList_succeeds() throws Exception { doReturn(createValidPersistenceQueryTemplateListToGet(listSize)).when(queryHandlerService).getQueryTemplatesForAuthor(any(String.class)); doReturn(createValidApiQueryTemplateToGet(ThreadLocalRandom.current().nextInt())).when(queryHandlerService).convertTemplatePersistenceToApi(any(de.numcodex.feasibility_gui_backend.query.persistence.QueryTemplate.class)); - mockMvc.perform(get(URI.create(PATH_API + PATH_QUERY + PATH_TEMPLATE)).with(csrf())) + mockMvc.perform(get(URI.create(PATH_API + PATH_QUERY + PATH_TEMPLATE+ "?skipValidation=true")).with(csrf())) .andExpect(status().isOk()) .andExpect(jsonPath("$.length()").value(listSize)) .andExpect(jsonPath("$.[0].id").exists()); @@ -179,6 +178,47 @@ public void testGetQueryTemplateList_emptyListOnJsonErrors() throws Exception { .andExpect(jsonPath("$.length()").value(0)); } + @Test + @WithMockUser(roles = "FEASIBILITY_TEST_USER") + public void testGetQueryTemplateListWithValidation_succeedsWithoutValidationErrors() throws Exception { + int listSize = 5; + doReturn(createValidPersistenceQueryTemplateListToGet(listSize)).when(queryHandlerService).getQueryTemplatesForAuthor(any(String.class)); + doReturn(createValidApiQueryTemplateToGet(ThreadLocalRandom.current().nextInt())).when(queryHandlerService).convertTemplatePersistenceToApi(any(de.numcodex.feasibility_gui_backend.query.persistence.QueryTemplate.class)); + doReturn(List.of()).when(termCodeValidation).getInvalidTermCodes(any(StructuredQuery.class)); + + mockMvc.perform(get(URI.create(PATH_API + PATH_QUERY + PATH_TEMPLATE)).with(csrf())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.length()").value(listSize)) + .andExpect(jsonPath("$.[*].id").exists()) + .andExpect(jsonPath("$.[*].isValid", Matchers.not(Matchers.contains(false)))); + } + + @Test + @WithMockUser(roles = "FEASIBILITY_TEST_USER") + public void testGetQueryTemplateListWithValidation_succeedsWithValidationErrors() throws Exception { + int listSize = 5; + doReturn(createValidPersistenceQueryTemplateListToGet(listSize)).when(queryHandlerService).getQueryTemplatesForAuthor(any(String.class)); + doReturn(createValidApiQueryTemplateToGet(ThreadLocalRandom.current().nextInt())).when(queryHandlerService).convertTemplatePersistenceToApi(any(de.numcodex.feasibility_gui_backend.query.persistence.QueryTemplate.class)); + doReturn(List.of(createTermCode())).when(termCodeValidation).getInvalidTermCodes(any(StructuredQuery.class)); + + mockMvc.perform(get(URI.create(PATH_API + PATH_QUERY + PATH_TEMPLATE)).with(csrf())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.length()").value(listSize)); + } + + @Test + @WithMockUser(roles = "FEASIBILITY_TEST_USER") + public void testGetQueryTemplateListWithValidation_emptyListOnJsonErrors() throws Exception { + int listSize = 5; + doReturn(createValidPersistenceQueryTemplateListToGet(listSize)).when(queryHandlerService).getQueryTemplatesForAuthor(any(String.class)); + doThrow(JsonProcessingException.class).when(queryHandlerService).convertTemplatePersistenceToApi(any(de.numcodex.feasibility_gui_backend.query.persistence.QueryTemplate.class)); + doReturn(List.of(createTermCode())).when(termCodeValidation).getInvalidTermCodes(any(StructuredQuery.class)); + + mockMvc.perform(get(URI.create(PATH_API + PATH_QUERY + PATH_TEMPLATE)).with(csrf())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.length()").value(0)); + } + @Test @WithMockUser(roles = "FEASIBILITY_TEST_USER") public void testUpdateQueryTemplate_succeeds() throws Exception { @@ -228,47 +268,6 @@ public void testDeleteQueryTemplate_failsWith404OnNotFound() throws Exception { .andExpect(status().isNotFound()); } - @Test - @WithMockUser(roles = "FEASIBILITY_TEST_USER") - public void testValidateTemplates_succeedsWithoutValidationErrors() throws Exception { - int listSize = 5; - doReturn(createValidPersistenceQueryTemplateListToGet(listSize)).when(queryHandlerService).getQueryTemplatesForAuthor(any(String.class)); - doReturn(createValidApiQueryTemplateToGet(ThreadLocalRandom.current().nextInt())).when(queryHandlerService).convertTemplatePersistenceToApi(any(de.numcodex.feasibility_gui_backend.query.persistence.QueryTemplate.class)); - doReturn(List.of()).when(termCodeValidation).getInvalidTermCodes(any(StructuredQuery.class)); - - mockMvc.perform(get(URI.create(PATH_API + PATH_QUERY + PATH_TEMPLATE + "/validate")).with(csrf())) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.length()").value(listSize)) - .andExpect(jsonPath("$.[*].id").exists()) - .andExpect(jsonPath("$.[*].isValid", Matchers.not(Matchers.contains(false)))); - } - - @Test - @WithMockUser(roles = "FEASIBILITY_TEST_USER") - public void testValidateTemplates_succeedsWithValidationErrors() throws Exception { - int listSize = 5; - doReturn(createValidPersistenceQueryTemplateListToGet(listSize)).when(queryHandlerService).getQueryTemplatesForAuthor(any(String.class)); - doReturn(createValidApiQueryTemplateToGet(ThreadLocalRandom.current().nextInt())).when(queryHandlerService).convertTemplatePersistenceToApi(any(de.numcodex.feasibility_gui_backend.query.persistence.QueryTemplate.class)); - doReturn(List.of(createTermCode())).when(termCodeValidation).getInvalidTermCodes(any(StructuredQuery.class)); - - mockMvc.perform(get(URI.create(PATH_API + PATH_QUERY + PATH_TEMPLATE + "/validate")).with(csrf())) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.length()").value(listSize)); - } - - @Test - @WithMockUser(roles = "FEASIBILITY_TEST_USER") - public void testValidateTemplates_emptyListOnJsonErrors() throws Exception { - int listSize = 5; - doReturn(createValidPersistenceQueryTemplateListToGet(listSize)).when(queryHandlerService).getQueryTemplatesForAuthor(any(String.class)); - doThrow(JsonProcessingException.class).when(queryHandlerService).convertTemplatePersistenceToApi(any(de.numcodex.feasibility_gui_backend.query.persistence.QueryTemplate.class)); - doReturn(List.of(createTermCode())).when(termCodeValidation).getInvalidTermCodes(any(StructuredQuery.class)); - - mockMvc.perform(get(URI.create(PATH_API + PATH_QUERY + PATH_TEMPLATE + "/validate")).with(csrf())) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.length()").value(0)); - } - @NotNull private static QueryTemplate createValidQueryTemplateToStore(long id) { return QueryTemplate.builder() diff --git a/src/test/java/de/numcodex/feasibility_gui_backend/terminology/v3/TerminologyRestControllerIT.java b/src/test/java/de/numcodex/feasibility_gui_backend/terminology/v3/TerminologyRestControllerIT.java index 961a0cf1..519a0894 100644 --- a/src/test/java/de/numcodex/feasibility_gui_backend/terminology/v3/TerminologyRestControllerIT.java +++ b/src/test/java/de/numcodex/feasibility_gui_backend/terminology/v3/TerminologyRestControllerIT.java @@ -16,7 +16,6 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; import org.junit.jupiter.params.provider.ValueSource; import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired;