From bbcfd87e420f1687720076ebb2c3edf76960b25f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Dec 2024 08:48:31 +0000 Subject: [PATCH 1/7] Bump org.springframework.boot:spring-boot-starter-parent Bumps [org.springframework.boot:spring-boot-starter-parent](https://github.com/spring-projects/spring-boot) from 3.4.0 to 3.4.1. - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v3.4.0...v3.4.1) --- updated-dependencies: - dependency-name: org.springframework.boot:spring-boot-starter-parent dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9b9c451c..7f7b78ab 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ org.springframework.boot spring-boot-starter-parent - 3.4.0 + 3.4.1 From 53e8aefd8daf5195020b01fbb6fa6a8252f8f702 Mon Sep 17 00:00:00 2001 From: Alexander Kiel Date: Tue, 14 Jan 2025 15:32:30 +0100 Subject: [PATCH 2/7] Lock version of Eclipse Temurin Base Image --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 2f8cc3d5..3a20cee5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM eclipse-temurin:21.0.5_11-jre +FROM eclipse-temurin:21.0.5_11-jre-jammy@sha256:5f8358c9d5615c18e95728e8b8528bda7ff40a7a5da2ac9a35b7a01f5d9b231a RUN apt-get update && apt-get upgrade -y && \ apt-get purge wget libbinutils libctf0 libctf-nobfd0 libncurses6 -y && \ From e85f46ec1986ae77dd4468fb6be013db2e92ee69 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 14 Jan 2025 14:56:23 +0000 Subject: [PATCH 3/7] Update nginx Docker tag to v1.27.3 --- .github/integration-test/basic-auth/docker-compose.yml | 2 +- .github/integration-test/oauth/docker-compose.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/integration-test/basic-auth/docker-compose.yml b/.github/integration-test/basic-auth/docker-compose.yml index b212f4a0..e7427392 100644 --- a/.github/integration-test/basic-auth/docker-compose.yml +++ b/.github/integration-test/basic-auth/docker-compose.yml @@ -37,7 +37,7 @@ services: depends_on: - data-store proxy: - image: "nginx:1.27.2" + image: "nginx:1.27.3" volumes: - "./nginx.conf:/etc/nginx/nginx.conf" - "./proxy.htpasswd:/etc/auth/.htpasswd" diff --git a/.github/integration-test/oauth/docker-compose.yml b/.github/integration-test/oauth/docker-compose.yml index a655ecb3..a3d4ff3d 100644 --- a/.github/integration-test/oauth/docker-compose.yml +++ b/.github/integration-test/oauth/docker-compose.yml @@ -50,7 +50,7 @@ services: volumes: - "./realm-test.json:/opt/keycloak/data/import/realm-test.json" proxy: - image: "nginx:1.27.2" + image: "nginx:1.27.3" healthcheck: test: ["CMD-SHELL", "curl --fail -s http://localhost:8080"] interval: "5s" From c4aff8fdbec0f3fb00acd0dee59645a17f5d94a3 Mon Sep 17 00:00:00 2001 From: Alexander Kiel Date: Tue, 14 Jan 2025 15:13:46 +0100 Subject: [PATCH 4/7] Add Query Tracing to Logging Closes: #240 --- .../basic-auth/docker-compose.yml | 2 +- .../no-auth-cohort-enabled/docker-compose.yml | 2 +- .../no-auth/docker-compose.yml | 2 +- .../integration-test/oauth/docker-compose.yml | 2 +- .../flare/rest/IdGenerator.java | 13 +++++ .../flare/rest/QueryController.java | 31 ++++++----- .../flare/service/DataStore.java | 9 ++-- .../service/DiskCachingFhirQueryService.java | 11 ++-- .../flare/service/FhirQueryService.java | 23 ++++++-- .../service/MemCachingFhirQueryService.java | 52 ++++++++++++++----- .../flare/service/StructuredQueryService.java | 19 ++++--- .../flare/rest/QueryControllerTest.java | 18 ++++--- .../flare/service/DataStoreIT.java | 16 +++--- .../flare/service/DataStoreTest.java | 8 +-- .../DiskCachingFhirQueryServiceTest.java | 22 ++++---- .../MemCachingFhirQueryServiceTest.java | 18 ++++--- .../service/StructuredQueryServiceIT.java | 18 ++++--- .../service/StructuredQueryServiceTest.java | 35 +++++++------ 18 files changed, 189 insertions(+), 112 deletions(-) create mode 100644 src/main/java/de/medizininformatikinitiative/flare/rest/IdGenerator.java diff --git a/.github/integration-test/basic-auth/docker-compose.yml b/.github/integration-test/basic-auth/docker-compose.yml index e7427392..104f36a8 100644 --- a/.github/integration-test/basic-auth/docker-compose.yml +++ b/.github/integration-test/basic-auth/docker-compose.yml @@ -1,6 +1,6 @@ services: data-store: - image: "samply/blaze:0.30" + image: "samply/blaze:0.31" healthcheck: test: ["CMD-SHELL", "curl --fail -s http://localhost:8080/health"] interval: "5s" diff --git a/.github/integration-test/no-auth-cohort-enabled/docker-compose.yml b/.github/integration-test/no-auth-cohort-enabled/docker-compose.yml index 95236ab7..9d81c15e 100644 --- a/.github/integration-test/no-auth-cohort-enabled/docker-compose.yml +++ b/.github/integration-test/no-auth-cohort-enabled/docker-compose.yml @@ -1,6 +1,6 @@ services: data-store: - image: "samply/blaze:0.30" + image: "samply/blaze:0.31" healthcheck: test: ["CMD-SHELL", "curl --fail -s http://localhost:8080/health"] interval: "5s" diff --git a/.github/integration-test/no-auth/docker-compose.yml b/.github/integration-test/no-auth/docker-compose.yml index 273c19e3..4d94b98a 100644 --- a/.github/integration-test/no-auth/docker-compose.yml +++ b/.github/integration-test/no-auth/docker-compose.yml @@ -1,6 +1,6 @@ services: data-store: - image: "samply/blaze:0.30" + image: "samply/blaze:0.31" healthcheck: test: ["CMD-SHELL", "curl --fail -s http://localhost:8080/health"] interval: "5s" diff --git a/.github/integration-test/oauth/docker-compose.yml b/.github/integration-test/oauth/docker-compose.yml index a3d4ff3d..963ee08b 100644 --- a/.github/integration-test/oauth/docker-compose.yml +++ b/.github/integration-test/oauth/docker-compose.yml @@ -72,7 +72,7 @@ services: keycloak: condition: service_healthy data-store: - image: "samply/blaze:0.30" + image: "samply/blaze:0.31" healthcheck: test: ["CMD-SHELL", "curl --fail -s http://localhost:8080/health"] interval: "5s" diff --git a/src/main/java/de/medizininformatikinitiative/flare/rest/IdGenerator.java b/src/main/java/de/medizininformatikinitiative/flare/rest/IdGenerator.java new file mode 100644 index 00000000..faef6676 --- /dev/null +++ b/src/main/java/de/medizininformatikinitiative/flare/rest/IdGenerator.java @@ -0,0 +1,13 @@ +package de.medizininformatikinitiative.flare.rest; + +import org.springframework.stereotype.Component; + +import java.util.UUID; + +@Component +public class IdGenerator { + + public UUID generateRandom() { + return UUID.randomUUID(); + } +} diff --git a/src/main/java/de/medizininformatikinitiative/flare/rest/QueryController.java b/src/main/java/de/medizininformatikinitiative/flare/rest/QueryController.java index e2d26cb6..cca96302 100644 --- a/src/main/java/de/medizininformatikinitiative/flare/rest/QueryController.java +++ b/src/main/java/de/medizininformatikinitiative/flare/rest/QueryController.java @@ -17,9 +17,9 @@ import org.springframework.web.reactive.function.server.ServerResponse; import reactor.core.publisher.Mono; -import java.util.Objects; import java.util.Set; +import static java.util.Objects.requireNonNull; import static org.springframework.web.reactive.function.server.RequestPredicates.POST; import static org.springframework.web.reactive.function.server.RequestPredicates.accept; import static org.springframework.web.reactive.function.server.RouterFunctions.route; @@ -33,14 +33,15 @@ public class QueryController { private static final Logger logger = LoggerFactory.getLogger(QueryController.class); private final StructuredQueryService queryService; + private final IdGenerator queryIdGenerator; - public QueryController(StructuredQueryService queryService) { - this.queryService = Objects.requireNonNull(queryService); + public QueryController(StructuredQueryService queryService, IdGenerator queryIdGenerator) { + this.queryService = requireNonNull(queryService); + this.queryIdGenerator = requireNonNull(queryIdGenerator); } @Bean public RouterFunction queryRouter(@Value("${flare.cohort.enabled}") boolean cohortEnabled) { - var route = route(POST("query/execute").and(accept(MEDIA_TYPE_SQ)), this::execute) .andRoute(POST("query/translate").and(accept(MEDIA_TYPE_SQ)), this::translate); @@ -53,40 +54,42 @@ public RouterFunction queryRouter(@Value("${flare.cohort.enabled public Mono execute(ServerRequest request) { var startNanoTime = System.nanoTime(); - logger.debug("Execute feasibility query"); + var queryId = queryIdGenerator.generateRandom(); + logger.debug("Execute feasibility query {}", queryId); return request.bodyToMono(StructuredQuery.class) - .flatMap(queryService::execute).map(Set::size) + .flatMap(query -> queryService.execute(queryId, query)).map(Set::size) .flatMap(count -> { - logger.debug("Finished feasibility query returning cohort size {} in {} seconds.", count, + logger.debug("Finished feasibility query {} returning cohort size {} in {} seconds.", queryId, count, "%.1f".formatted(Util.durationSecondsSince(startNanoTime))); return ok().bodyValue(count); }) .onErrorResume(MappingException.class, e -> { - logger.warn("Mapping error: {}", e.getMessage()); + logger.warn("Mapping error in feasibility query {}: {}", queryId, e.getMessage()); return badRequest().bodyValue(new Error(e.getMessage())); }) .onErrorResume(WebClientRequestException.class, e -> { - logger.error("Service not available because of downstream web client errors: {}", e.getMessage()); + logger.error("Service not available in feasibility query {} because of downstream web client errors: {}", queryId, e.getMessage()); return status(503).bodyValue(new Error(e.getMessage())); }); } public Mono executeCohort(ServerRequest request) { var startNanoTime = System.nanoTime(); - logger.debug("Execute cohort query"); + var queryId = queryIdGenerator.generateRandom(); + logger.debug("Execute cohort query {}", queryId); return request.bodyToMono(StructuredQuery.class) - .flatMap(queryService::execute) + .flatMap(query -> queryService.execute(queryId, query)) .flatMap(population -> { - logger.debug("Finished cohort query returning cohort of {} patient IDs in {} seconds.", population.size(), + logger.debug("Finished cohort query {} returning cohort of {} patient IDs in {} seconds.", queryId, population.size(), "%.1f".formatted(Util.durationSecondsSince(startNanoTime))); return ok().bodyValue(population); }) .onErrorResume(MappingException.class, e -> { - logger.warn("Mapping error: {}", e.getMessage()); + logger.warn("Mapping error in cohort query {}: {}", queryId, e.getMessage()); return badRequest().bodyValue(new Error(e.getMessage())); }) .onErrorResume(WebClientRequestException.class, e -> { - logger.error("Service not available because of downstream web client errors: {}", e.getMessage()); + logger.error("Service not available in cohort query {} because of downstream web client errors: {}", queryId, e.getMessage()); return status(503).bodyValue(new Error(e.getMessage())); }); } diff --git a/src/main/java/de/medizininformatikinitiative/flare/service/DataStore.java b/src/main/java/de/medizininformatikinitiative/flare/service/DataStore.java index 653ec1a7..cc0f684f 100644 --- a/src/main/java/de/medizininformatikinitiative/flare/service/DataStore.java +++ b/src/main/java/de/medizininformatikinitiative/flare/service/DataStore.java @@ -21,6 +21,7 @@ import java.time.Clock; import java.time.Duration; import java.util.Objects; +import java.util.UUID; import java.util.stream.Collectors; import static de.medizininformatikinitiative.flare.model.fhir.QueryParams.stringValue; @@ -48,9 +49,9 @@ public void init() { } @Override - public Mono execute(Query query, boolean ignoreCache) { + public Mono execute(UUID id, Query query, boolean ignoreCache) { var startNanoTime = System.nanoTime(); - logger.debug("Execute query: {}", query); + logger.debug("Execute query as part of query {}: {}", id, query); return client.post() .uri("/{type}/_search", query.type()) .contentType(APPLICATION_FORM_URLENCODED) @@ -66,9 +67,9 @@ public Mono execute(Query query, boolean ignoreCache) { .flatMap(bundle -> Flux.fromStream(bundle.entry().stream().flatMap(e -> e.resource().patientId().stream()))) .collect(Collectors.toSet()) .map(patientIds -> Population.copyOf(patientIds).withCreated(clock.instant())) - .doOnNext(p -> logger.debug("Finished query `{}` returning {} patients in {} seconds.", query, p.size(), + .doOnNext(p -> logger.debug("Finished query `{}` as part of query {} returning {} patients in {} seconds.", query, id, p.size(), "%.1f".formatted(Util.durationSecondsSince(startNanoTime)))) - .doOnError(e -> logger.error("Error while executing query `{}`: {}", query, e.getMessage())); + .doOnError(e -> logger.error("Error while executing query `{}` as part of query {}: {}", query, id, e.getMessage())); } private static boolean shouldRetry(HttpStatusCode code) { diff --git a/src/main/java/de/medizininformatikinitiative/flare/service/DiskCachingFhirQueryService.java b/src/main/java/de/medizininformatikinitiative/flare/service/DiskCachingFhirQueryService.java index cffa8ea4..7d150acd 100644 --- a/src/main/java/de/medizininformatikinitiative/flare/service/DiskCachingFhirQueryService.java +++ b/src/main/java/de/medizininformatikinitiative/flare/service/DiskCachingFhirQueryService.java @@ -13,6 +13,7 @@ import java.nio.ByteBuffer; import java.time.Clock; import java.time.Duration; +import java.util.UUID; import java.util.concurrent.atomic.AtomicLong; import static java.nio.charset.StandardCharsets.UTF_8; @@ -54,16 +55,16 @@ public void init() throws RocksDBException { } @Override - public Mono execute(Query query, boolean ignoreCache) { + public Mono execute(UUID id, Query query, boolean ignoreCache) { if (ignoreCache) { - return executeQuery(query, true); + return executeQuery(id, query, true); } else { - return internalGet(query).switchIfEmpty(Mono.defer(() -> executeQuery(query, false))); + return internalGet(query).switchIfEmpty(Mono.defer(() -> executeQuery(id, query, false))); } } - private Mono executeQuery(Query query, boolean ignoreCache) { - return fhirQueryService.execute(query, ignoreCache).doOnNext(population -> put(query, population)); + private Mono executeQuery(UUID id, Query query, boolean ignoreCache) { + return fhirQueryService.execute(id, query, ignoreCache).doOnNext(population -> put(query, population)); } private Mono internalGet(Query query) { diff --git a/src/main/java/de/medizininformatikinitiative/flare/service/FhirQueryService.java b/src/main/java/de/medizininformatikinitiative/flare/service/FhirQueryService.java index 7b50866e..8bbf0bb8 100644 --- a/src/main/java/de/medizininformatikinitiative/flare/service/FhirQueryService.java +++ b/src/main/java/de/medizininformatikinitiative/flare/service/FhirQueryService.java @@ -4,11 +4,28 @@ import de.medizininformatikinitiative.flare.model.fhir.Query; import reactor.core.publisher.Mono; +import java.util.UUID; + public interface FhirQueryService { - Mono execute(Query query, boolean ignoreCache); + /** + * Executes {@code query}. + * + * @param id the ID of the query used for tracing purposes + * @param query the query to execute + * @param ignoreCache if the cache shouldn't be used + * @return the population result + */ + Mono execute(UUID id, Query query, boolean ignoreCache); - default Mono execute(Query query) { - return execute(query, false); + /** + * Executes {@code query} using a potentially cache. + * + * @param id the ID of the query used for tracing purposes + * @param query the query to execute + * @return the population result + */ + default Mono execute(UUID id, Query query) { + return execute(id, query, false); } } diff --git a/src/main/java/de/medizininformatikinitiative/flare/service/MemCachingFhirQueryService.java b/src/main/java/de/medizininformatikinitiative/flare/service/MemCachingFhirQueryService.java index 2b3983d0..fba907e1 100644 --- a/src/main/java/de/medizininformatikinitiative/flare/service/MemCachingFhirQueryService.java +++ b/src/main/java/de/medizininformatikinitiative/flare/service/MemCachingFhirQueryService.java @@ -12,6 +12,8 @@ import reactor.core.publisher.Mono; import java.time.Duration; +import java.util.Objects; +import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; @@ -21,12 +23,12 @@ public class MemCachingFhirQueryService implements FhirQueryService { private static final Logger logger = LoggerFactory.getLogger(MemCachingFhirQueryService.class); - private static final Weigher WEIGHER = (key, value) -> - key.toString().length() + value.memSize(); + private static final Weigher WEIGHER = (key, value) -> + key.query.toString().length() + value.memSize(); private final FhirQueryService fhirQueryService; private final Config config; - private AsyncLoadingCache cache; + private AsyncLoadingCache cache; public MemCachingFhirQueryService(FhirQueryService fhirQueryService, Config config) { this.fhirQueryService = requireNonNull(fhirQueryService); @@ -46,9 +48,9 @@ public void init() { } @Override - public Mono execute(Query query, boolean ignoreCache) { - logger.trace("Try loading population for query `{}` from memory.", query); - return Mono.fromFuture(cache.get(query)); + public Mono execute(UUID id, Query query, boolean ignoreCache) { + logger.trace("Try loading population for query `{}` part of query {} from memory.", query, id); + return Mono.fromFuture(cache.get(new QueryWrapper(id, query))); } public CacheStats stats() { @@ -67,21 +69,43 @@ public CacheStats stats() { public record Config(long sizeInMebibytes, Duration expire, Duration refresh) { } - private class CacheLoader implements AsyncCacheLoader { + public record CacheStats(long estimatedEntryCount, long maxMemoryMiB, long usedMemoryMiB, long hitCount, + long missCount, long evictionCount, long loadSuccessCount, long loadFailureCount, + long totalLoadTimeNanos) { + } + + private record QueryWrapper(UUID id, Query query) { + + private QueryWrapper { + requireNonNull(id); + requireNonNull(query); + } @Override - public CompletableFuture asyncLoad(Query query, Executor executor) { - return fhirQueryService.execute(query).toFuture(); + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) return false; + QueryWrapper that = (QueryWrapper) o; + return Objects.equals(query, that.query); } @Override - public CompletableFuture asyncReload(Query query, Population oldValue, Executor executor) { - return fhirQueryService.execute(query, true).toFuture(); + public int hashCode() { + return Objects.hashCode(query); } } - public record CacheStats(long estimatedEntryCount, long maxMemoryMiB, long usedMemoryMiB, long hitCount, - long missCount, long evictionCount, long loadSuccessCount, long loadFailureCount, - long totalLoadTimeNanos) { + private class CacheLoader implements AsyncCacheLoader { + + @Override + public CompletableFuture asyncLoad(QueryWrapper query, Executor executor) { + logger.trace("Cache miss for query `{}` part of query {}.", query.query, query.id); + return fhirQueryService.execute(query.id, query.query).toFuture(); + } + + @Override + public CompletableFuture asyncReload(QueryWrapper query, Population oldValue, Executor executor) { + logger.trace("Refresh query `{}`.", query.query); + return fhirQueryService.execute(query.id, query.query, true).toFuture(); + } } } diff --git a/src/main/java/de/medizininformatikinitiative/flare/service/StructuredQueryService.java b/src/main/java/de/medizininformatikinitiative/flare/service/StructuredQueryService.java index 035c6235..998b6a92 100644 --- a/src/main/java/de/medizininformatikinitiative/flare/service/StructuredQueryService.java +++ b/src/main/java/de/medizininformatikinitiative/flare/service/StructuredQueryService.java @@ -15,6 +15,8 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import java.util.UUID; + import static de.medizininformatikinitiative.flare.model.translate.Operator.Name.UNION; import static java.util.Objects.requireNonNull; @@ -36,14 +38,15 @@ public StructuredQueryService(@Qualifier("memCachingFhirQueryService") FhirQuery /** * Executes {@code query} and returns the Population of Patient IDs. * + * @param id the ID of the query used for tracing purposes * @param query the query to execute * @return the Patient IDs qualifying the criteria */ - public Mono execute(StructuredQuery query) { - var includedPatients = query.inclusionCriteria().executeAndIntersection(this::executeUnionGroup) + public Mono execute(UUID id, StructuredQuery query) { + var includedPatients = query.inclusionCriteria().executeAndIntersection(group -> executeUnionGroup(id, group)) .defaultIfEmpty(Population.of()); var excludedPatients = query.exclusionCriteria().map(c -> c.map(CriterionGroup::wrapCriteria) - .executeAndUnion(group -> group.executeAndIntersection(this::executeUnionGroup)) + .executeAndUnion(group -> group.executeAndIntersection(group1 -> executeUnionGroup(id, group1))) .defaultIfEmpty(Population.of())) .orElse(Mono.just(Population.of())); return includedPatients @@ -51,14 +54,14 @@ public Mono execute(StructuredQuery query) { } - private Mono executeUnionGroup(CriterionGroup group) { - return group.executeAndUnion(this::executeSingle); + private Mono executeUnionGroup(UUID id, CriterionGroup group) { + return group.executeAndUnion(criterion -> executeSingle(id, criterion)); } - private Flux executeSingle(Criterion criterion) { - logger.trace("Execute single criterion {}", criterion); + private Flux executeSingle(UUID id, Criterion criterion) { + logger.trace("Execute single criterion of query {}: {}", id, criterion); return translator.toQuery(criterion) - .either(Flux::error, queries -> Flux.fromIterable(queries).flatMap(fhirQueryService::execute)); + .either(Flux::error, queries -> Flux.fromIterable(queries).flatMap(query -> fhirQueryService.execute(id, query))); } /** diff --git a/src/test/java/de/medizininformatikinitiative/flare/rest/QueryControllerTest.java b/src/test/java/de/medizininformatikinitiative/flare/rest/QueryControllerTest.java index 8ba19d52..ca2bd413 100644 --- a/src/test/java/de/medizininformatikinitiative/flare/rest/QueryControllerTest.java +++ b/src/test/java/de/medizininformatikinitiative/flare/rest/QueryControllerTest.java @@ -15,21 +15,20 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.http.MediaType; -import org.springframework.test.context.event.annotation.BeforeTestExecution; -import org.springframework.test.context.event.annotation.BeforeTestMethod; -import org.springframework.test.context.transaction.BeforeTransaction; import org.springframework.test.web.reactive.server.WebTestClient; import org.testcontainers.shaded.com.fasterxml.jackson.core.JsonProcessingException; import org.testcontainers.shaded.com.fasterxml.jackson.databind.ObjectMapper; import reactor.core.publisher.Mono; import java.util.List; +import java.util.UUID; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class QueryControllerTest { + static final UUID ID = UUID.randomUUID(); static final String PATIENT_ID = "patient-id-211701"; static final String PATIENT_ID_1 = "patient-id-1-131300"; static final MediaType MEDIA_TYPE_SQ = MediaType.valueOf("application/sq+json"); @@ -41,6 +40,9 @@ class QueryControllerTest { @Mock StructuredQueryService queryService; + @Mock + IdGenerator queryIdGenerator; + @InjectMocks private QueryController controller; @@ -53,7 +55,8 @@ void setUp() { @Test void execute() { - when(queryService.execute(STRUCTURED_QUERY)).thenReturn(Mono.just(Population.of(PATIENT_ID))); + when(queryIdGenerator.generateRandom()).thenReturn(ID); + when(queryService.execute(ID, STRUCTURED_QUERY)).thenReturn(Mono.just(Population.of(PATIENT_ID))); client.post() .uri("/query/execute") @@ -87,7 +90,8 @@ void execute() { @Test void executeCohort() throws JsonProcessingException { - when(queryService.execute(STRUCTURED_QUERY)).thenReturn(Mono.just(Population.of(PATIENT_ID, PATIENT_ID_1))); + when(queryIdGenerator.generateRandom()).thenReturn(ID); + when(queryService.execute(ID, STRUCTURED_QUERY)).thenReturn(Mono.just(Population.of(PATIENT_ID, PATIENT_ID_1))); ObjectMapper objectMapper = new ObjectMapper(); @@ -123,7 +127,6 @@ void executeCohort() throws JsonProcessingException { @Test void executeCohortDisabled() { - client = WebTestClient.bindToRouterFunction(controller.queryRouter(false)).build(); client.post() @@ -157,7 +160,8 @@ void executeCohortDisabled() { @Test void execute_error() { - when(queryService.execute(STRUCTURED_QUERY)).thenReturn(Mono.error(new MappingNotFoundException(ContextualTermCode.of(TestUtil.CONTEXT, FEVER)))); + when(queryIdGenerator.generateRandom()).thenReturn(ID); + when(queryService.execute(ID, STRUCTURED_QUERY)).thenReturn(Mono.error(new MappingNotFoundException(ContextualTermCode.of(TestUtil.CONTEXT, FEVER)))); client.post() .uri("/query/execute") diff --git a/src/test/java/de/medizininformatikinitiative/flare/service/DataStoreIT.java b/src/test/java/de/medizininformatikinitiative/flare/service/DataStoreIT.java index 98f2e1aa..b7b99bd3 100644 --- a/src/test/java/de/medizininformatikinitiative/flare/service/DataStoreIT.java +++ b/src/test/java/de/medizininformatikinitiative/flare/service/DataStoreIT.java @@ -23,6 +23,7 @@ import java.time.Clock; import java.time.Instant; import java.time.ZoneOffset; +import java.util.UUID; import static org.springframework.http.MediaType.APPLICATION_JSON; @@ -31,6 +32,7 @@ class DataStoreIT { private static final Logger logger = LoggerFactory.getLogger(DataStoreIT.class); + private static final UUID ID = UUID.randomUUID(); private static final Instant FIXED_INSTANT = Instant.ofEpochSecond(104152); @Container @@ -64,7 +66,7 @@ void setUp() { @Test void execute_empty() { - var result = dataStore.execute(Query.ofType("Observation")); + var result = dataStore.execute(ID, Query.ofType("Observation")); StepVerifier.create(result).expectNext(Population.of().withCreated(FIXED_INSTANT)).verifyComplete(); } @@ -74,7 +76,7 @@ void execute_oneObservation() { createPatient("0"); createObservation("0"); - var result = dataStore.execute(Query.ofType("Observation")); + var result = dataStore.execute(ID, Query.ofType("Observation")); StepVerifier.create(result).expectNext(Population.of("0").withCreated(FIXED_INSTANT)).verifyComplete(); } @@ -85,7 +87,7 @@ void execute_twoObservationsFromOnePatient() { createObservation("0"); createObservation("0"); - var result = dataStore.execute(Query.ofType("Observation")); + var result = dataStore.execute(ID, Query.ofType("Observation")); StepVerifier.create(result).expectNext(Population.of("0").withCreated(FIXED_INSTANT)).verifyComplete(); } @@ -97,7 +99,7 @@ void execute_twoObservationsFromTwoPatients() { createObservation("0"); createObservation("1"); - var result = dataStore.execute(Query.ofType("Observation")); + var result = dataStore.execute(ID, Query.ofType("Observation")); StepVerifier.create(result).expectNext(Population.of("0", "1").withCreated(FIXED_INSTANT)).verifyComplete(); } @@ -107,7 +109,7 @@ void execute_twoObservationsFromTwoPatients() { void execute_OneObsWithoutReference_FromOnePat() { createObservation_withoutReference(); - var result = dataStore.execute(Query.ofType("Observation")); + var result = dataStore.execute(ID, Query.ofType("Observation")); StepVerifier.create(result).expectNext(Population.of().withCreated(FIXED_INSTANT)).verifyComplete(); } @@ -120,7 +122,7 @@ void execute_OneObsWithoutReferenceOneObsWithReference_FromTwoPats() { createObservation_withoutReference(); createObservation("1"); - var result = dataStore.execute(Query.ofType("Observation")); + var result = dataStore.execute(ID, Query.ofType("Observation")); StepVerifier.create(result).expectNext(Population.of("1").withCreated(FIXED_INSTANT)).verifyComplete(); } @@ -130,7 +132,7 @@ void execute_OneObsWithoutReferenceOneObsWithReference_FromTwoPats() { void pendingAcquireQueueReachedMaximum() { createPatient("0"); - var result = Flux.range(1, 1000).flatMap(i -> dataStore.execute(Query.ofType("Patient"))).collectList(); + var result = Flux.range(1, 1000).flatMap(i -> dataStore.execute(ID, Query.ofType("Patient"))).collectList(); StepVerifier.create(result).verifyErrorMessage("Pending acquire queue has reached its maximum size of 8"); } diff --git a/src/test/java/de/medizininformatikinitiative/flare/service/DataStoreTest.java b/src/test/java/de/medizininformatikinitiative/flare/service/DataStoreTest.java index ea4e43fb..2a16c2cd 100644 --- a/src/test/java/de/medizininformatikinitiative/flare/service/DataStoreTest.java +++ b/src/test/java/de/medizininformatikinitiative/flare/service/DataStoreTest.java @@ -15,9 +15,11 @@ import java.time.Clock; import java.time.Instant; import java.time.ZoneOffset; +import java.util.UUID; class DataStoreTest { + private static final UUID ID = UUID.randomUUID(); private static final Instant FIXED_INSTANT = Instant.ofEpochSecond(104152); private static MockWebServer mockStore; @@ -50,7 +52,7 @@ void execute_retry(int statusCode) { mockStore.enqueue(new MockResponse().setResponseCode(statusCode)); mockStore.enqueue(new MockResponse().setResponseCode(200)); - var result = dataStore.execute(Query.ofType("Observation")); + var result = dataStore.execute(ID, Query.ofType("Observation")); StepVerifier.create(result).expectNext(Population.of().withCreated(FIXED_INSTANT)).verifyComplete(); } @@ -64,7 +66,7 @@ void execute_retry_fails() { mockStore.enqueue(new MockResponse().setResponseCode(500)); mockStore.enqueue(new MockResponse().setResponseCode(200)); - var result = dataStore.execute(Query.ofType("Observation")); + var result = dataStore.execute(ID, Query.ofType("Observation")); StepVerifier.create(result).verifyErrorMessage("Retries exhausted: 3/3"); } @@ -74,7 +76,7 @@ void execute_retry_fails() { void execute_retry_400() { mockStore.enqueue(new MockResponse().setResponseCode(400)); - var result = dataStore.execute(Query.ofType("Observation")); + var result = dataStore.execute(ID, Query.ofType("Observation")); StepVerifier.create(result).verifyError(WebClientResponseException.BadRequest.class); } diff --git a/src/test/java/de/medizininformatikinitiative/flare/service/DiskCachingFhirQueryServiceTest.java b/src/test/java/de/medizininformatikinitiative/flare/service/DiskCachingFhirQueryServiceTest.java index bc10efc1..22faf037 100644 --- a/src/test/java/de/medizininformatikinitiative/flare/service/DiskCachingFhirQueryServiceTest.java +++ b/src/test/java/de/medizininformatikinitiative/flare/service/DiskCachingFhirQueryServiceTest.java @@ -22,6 +22,7 @@ import java.time.Duration; import java.time.Instant; import java.time.ZoneOffset; +import java.util.UUID; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -33,6 +34,7 @@ @ExtendWith(MockitoExtension.class) class DiskCachingFhirQueryServiceTest { + static final UUID ID = UUID.randomUUID(); static final Query QUERY = Query.ofType("foo"); static final String PATIENT_ID = "patient-id-113617"; static final String PATIENT_ID_1 = "patient-id-1-103010"; @@ -61,9 +63,9 @@ void tearDown() { @Test void execute_error() { - when(queryService.execute(QUERY, false)).thenReturn(Mono.error(new Exception(ERROR_MSG))); + when(queryService.execute(ID, QUERY, false)).thenReturn(Mono.error(new Exception(ERROR_MSG))); - var result = service.execute(QUERY); + var result = service.execute(ID, QUERY); StepVerifier.create(result).verifyErrorMessage(ERROR_MSG); waitForTasksToFinish(); @@ -72,9 +74,9 @@ void execute_error() { @Test void execute_miss() { - when(queryService.execute(QUERY, false)).thenReturn(Mono.just(Population.of(PATIENT_ID))); + when(queryService.execute(ID, QUERY, false)).thenReturn(Mono.just(Population.of(PATIENT_ID))); - var result = service.execute(QUERY); + var result = service.execute(ID, QUERY); StepVerifier.create(result).expectNext(Population.of(PATIENT_ID)).verifyComplete(); waitForTasksToFinish(); @@ -85,7 +87,7 @@ void execute_miss() { void execute_hit() { ensureCacheContains(QUERY, Population.of(PATIENT_ID)); - var result = service.execute(QUERY); + var result = service.execute(ID, QUERY); StepVerifier.create(result).expectNext(Population.of(PATIENT_ID)).verifyComplete(); waitForTasksToFinish(); @@ -95,9 +97,9 @@ void execute_hit() { @Test void execute_ignoringCache() { ensureCacheContains(QUERY, Population.of(PATIENT_ID_1)); - when(queryService.execute(QUERY, true)).thenReturn(Mono.just(Population.of(PATIENT_ID_2))); + when(queryService.execute(ID, QUERY, true)).thenReturn(Mono.just(Population.of(PATIENT_ID_2))); - var result = service.execute(QUERY, true); + var result = service.execute(ID, QUERY, true); StepVerifier.create(result).expectNext(Population.of(PATIENT_ID_2)).verifyComplete(); waitForTasksToFinish(); @@ -108,9 +110,9 @@ void execute_ignoringCache() { @DisplayName("expired populations will not be returned as hit") void execute_expiredHit() { ensureCacheContains(QUERY, Population.of(PATIENT_ID_1).withCreated(Instant.EPOCH.minus(2, MINUTES))); - when(queryService.execute(QUERY, false)).thenReturn(Mono.just(Population.of(PATIENT_ID_2))); + when(queryService.execute(ID, QUERY, false)).thenReturn(Mono.just(Population.of(PATIENT_ID_2))); - var result = service.execute(QUERY, false); + var result = service.execute(ID, QUERY, false); StepVerifier.create(result).expectNext(Population.of(PATIENT_ID_2)).verifyComplete(); waitForTasksToFinish(); @@ -123,7 +125,7 @@ void execute_hit_largePopulation(int n) { var population = populationOfSize(n); ensureCacheContains(QUERY, population); - var result = service.execute(QUERY); + var result = service.execute(ID, QUERY); StepVerifier.create(result).expectNext(population).verifyComplete(); waitForTasksToFinish(); diff --git a/src/test/java/de/medizininformatikinitiative/flare/service/MemCachingFhirQueryServiceTest.java b/src/test/java/de/medizininformatikinitiative/flare/service/MemCachingFhirQueryServiceTest.java index 1647c57b..67d97748 100644 --- a/src/test/java/de/medizininformatikinitiative/flare/service/MemCachingFhirQueryServiceTest.java +++ b/src/test/java/de/medizininformatikinitiative/flare/service/MemCachingFhirQueryServiceTest.java @@ -11,12 +11,14 @@ import reactor.test.StepVerifier; import java.time.Duration; +import java.util.UUID; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class MemCachingFhirQueryServiceTest { + static final UUID ID = UUID.randomUUID(); static final Query QUERY = Query.ofType("foo"); static final String PATIENT_ID = "patient-id-113003"; static final String ERROR_MSG = "error-msg-103632"; @@ -35,18 +37,18 @@ void setUp() { @Test void execute_error() { - when(queryService.execute(QUERY)).thenReturn(Mono.error(new Exception(ERROR_MSG))); + when(queryService.execute(ID, QUERY)).thenReturn(Mono.error(new Exception(ERROR_MSG))); - var result = service.execute(QUERY); + var result = service.execute(ID, QUERY); StepVerifier.create(result).verifyErrorMessage(ERROR_MSG); } @Test void execute_success() { - when(queryService.execute(QUERY)).thenReturn(Mono.just(Population.of(PATIENT_ID))); + when(queryService.execute(ID, QUERY)).thenReturn(Mono.just(Population.of(PATIENT_ID))); - var result = service.execute(QUERY); + var result = service.execute(ID, QUERY); StepVerifier.create(result).expectNext(Population.of(PATIENT_ID)).verifyComplete(); } @@ -56,12 +58,12 @@ void refresh() throws InterruptedException { service = new MemCachingFhirQueryService(queryService, new MemCachingFhirQueryService.Config(128, Duration.ofMinutes(1), Duration.ofMillis(100))); service.init(); - when(queryService.execute(QUERY)).thenReturn(Mono.just(Population.of())); - service.execute(QUERY); - when(queryService.execute(QUERY, true)).thenReturn(Mono.just(Population.of(PATIENT_ID))); + when(queryService.execute(ID, QUERY)).thenReturn(Mono.just(Population.of())); + service.execute(ID, QUERY); + when(queryService.execute(ID, QUERY, true)).thenReturn(Mono.just(Population.of(PATIENT_ID))); Thread.sleep(200); - var result = service.execute(QUERY); + var result = service.execute(ID, QUERY); StepVerifier.create(result).expectNext(Population.of(PATIENT_ID)).verifyComplete(); } diff --git a/src/test/java/de/medizininformatikinitiative/flare/service/StructuredQueryServiceIT.java b/src/test/java/de/medizininformatikinitiative/flare/service/StructuredQueryServiceIT.java index c5b0ead9..86c11fda 100644 --- a/src/test/java/de/medizininformatikinitiative/flare/service/StructuredQueryServiceIT.java +++ b/src/test/java/de/medizininformatikinitiative/flare/service/StructuredQueryServiceIT.java @@ -41,6 +41,7 @@ import java.util.Arrays; import java.util.List; import java.util.Objects; +import java.util.UUID; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -51,12 +52,13 @@ @SpringBootTest class StructuredQueryServiceIT { + private static final Logger logger = LoggerFactory.getLogger(StructuredQueryServiceIT.class); + + private static final UUID ID = UUID.randomUUID(); private static final Clock CLOCK_2000 = Clock.fixed(LocalDate.of(2000, 1, 1).atStartOfDay().toInstant(ZoneOffset.UTC), ZoneOffset.UTC); private static final TermCode I08 = TermCode.of("http://fhir.de/CodeSystem/bfarm/icd-10-gm", "I08", ""); private static final TermCode DIAGNOSIS = TermCode.of("fdpg.mii.cds", "Diagnose", "Diagnose"); - private static final Logger logger = LoggerFactory.getLogger(StructuredQueryServiceIT.class); - @Container @SuppressWarnings("resource") private static final GenericContainer blaze = new GenericContainer<>("samply/blaze:0.29") @@ -130,7 +132,7 @@ void setUp() throws URISyntaxException, IOException { void execute_Criterion() { var query = StructuredQuery.of(CriterionGroup.of(CriterionGroup.of(Criterion.of(ContextualConcept.of(DIAGNOSIS, Concept.of(I08)))))); - var result = service.execute(query); + var result = service.execute(ID, query); StepVerifier.create(result).expectNext(Population.of("id-pat-diag-I08.0")).verifyComplete(); } @@ -139,7 +141,7 @@ void execute_Criterion() { void execute_genderTestCase() throws URISyntaxException, IOException { var query = parseSq(Files.readString(resourcePathFlareApplication("testCases").resolve("returningOther").resolve("2-gender.json"))); - var result = service.execute(query); + var result = service.execute(ID, query); StepVerifier.create(result).expectNextMatches(p -> p.size() == 172).verifyComplete(); } @@ -148,7 +150,7 @@ void execute_genderTestCase() throws URISyntaxException, IOException { void execute_consentTestCase() throws URISyntaxException, IOException { var query = parseSq(Files.readString(resourcePathFlareApplication("testCases").resolve("returningOther").resolve("consent.json"))); - var result = service.execute(query); + var result = service.execute(ID, query); StepVerifier.create(result).expectNext(Population.of("id-pat-consent-test")).verifyComplete(); } @@ -164,7 +166,7 @@ void execute_specimenTestCase() throws IOException, URISyntaxException { var query = parseSq(slurpStructuredQueryService("referencedCriteria/sq-test-specimen-diag.json")); - var result = service.execute(query); + var result = service.execute(ID, query); StepVerifier.create(result).expectNext(Population.of("id-pat-diab-test-1")).verifyComplete(); @@ -173,7 +175,7 @@ void execute_specimenTestCase() throws IOException, URISyntaxException { @ParameterizedTest @MethodSource("getTestQueriesReturningOnePatient") void execute_casesReturningOne(StructuredQuery query) { - var result = service.execute(query); + var result = service.execute(ID, query); StepVerifier.create(result).expectNextMatches(p -> p.size() == 1).verifyComplete(); } @@ -221,7 +223,7 @@ void execute_BloodPressureTestCase() throws Exception { } """); - var result = service_BloodPressure.execute(query); + var result = service_BloodPressure.execute(ID, query); StepVerifier.create(result).expectNext(Population.of("id-pat-bloodpressure-test")).verifyComplete(); diff --git a/src/test/java/de/medizininformatikinitiative/flare/service/StructuredQueryServiceTest.java b/src/test/java/de/medizininformatikinitiative/flare/service/StructuredQueryServiceTest.java index 5ce6a4cc..347a7e4e 100644 --- a/src/test/java/de/medizininformatikinitiative/flare/service/StructuredQueryServiceTest.java +++ b/src/test/java/de/medizininformatikinitiative/flare/service/StructuredQueryServiceTest.java @@ -31,6 +31,7 @@ @ExtendWith(MockitoExtension.class) class StructuredQueryServiceTest { + static final UUID ID = UUID.randomUUID(); static final String BFARM = "http://fhir.de/CodeSystem/bfarm/icd-10-gm"; static final Criterion CONCEPT_CRITERION = Criterion.of(cc(1)); static final Population EMPTY_POP = Population.of(); @@ -63,7 +64,7 @@ void setUp() { @Test void execute() { - var result = service.execute(query); + var result = service.execute(ID, query); StepVerifier.create(result).verifyError(MappingNotFoundException.class); } @@ -85,7 +86,7 @@ class SingleExpansion { void execute() { var query = query(incl(PATIENT_POP)); - var result = service.execute(query); + var result = service.execute(ID, query); StepVerifier.create(result).expectNext(PATIENT_POP).verifyComplete(); @@ -111,7 +112,7 @@ class MultipleExpansion { void execute_MultiplePatients() { var query = query(inclExpand(PATIENT_1_POP, PATIENT_2_POP)); - var result = service.execute(query); + var result = service.execute(ID, query); StepVerifier.create(result).expectNext(PATIENT_1_POP.union(PATIENT_2_POP)).verifyComplete(); } @@ -121,7 +122,7 @@ void execute_MultiplePatients() { void execute_SamePatient() { var query = query(inclExpand(PATIENT_POP, PATIENT_POP)); - var result = service.execute(query); + var result = service.execute(ID, query); StepVerifier.create(result).expectNext(PATIENT_POP).verifyComplete(); @@ -149,7 +150,7 @@ class ConjunctionInclusion { void execute_MultiplePatients() { var query = query(inclAnd(PATIENT_1_POP, PATIENT_2_POP)); - var result = service.execute(query); + var result = service.execute(ID, query); StepVerifier.create(result).expectNext(EMPTY_POP).verifyComplete(); } @@ -159,7 +160,7 @@ void execute_MultiplePatients() { void execute_SamePatient() { var query = query(inclAnd(PATIENT_POP, PATIENT_POP)); - var result = service.execute(query); + var result = service.execute(ID, query); StepVerifier.create(result).expectNext(PATIENT_POP).verifyComplete(); } @@ -184,7 +185,7 @@ class DisjunctionInclusion { void execute_MultiplePatients() { var query = query(inclOr(PATIENT_1_POP, PATIENT_2_POP)); - var result = service.execute(query); + var result = service.execute(ID, query); StepVerifier.create(result).expectNext(PATIENT_1_POP.union(PATIENT_2_POP)).verifyComplete(); } @@ -194,7 +195,7 @@ void execute_MultiplePatients() { void execute_SamePatient() { var query = query(inclOr(PATIENT_POP, PATIENT_POP)); - var result = service.execute(query); + var result = service.execute(ID, query); StepVerifier.create(result).expectNext(PATIENT_POP).verifyComplete(); } @@ -219,7 +220,7 @@ class SingleInclusionAndExclusion { void execute_PatientNotExcluded() { var query = query(incl(PATIENT_POP), excl(PATIENT_1_POP)); - var result = service.execute(query); + var result = service.execute(ID, query); StepVerifier.create(result).expectNext(PATIENT_POP).verifyComplete(); } @@ -229,7 +230,7 @@ void execute_PatientNotExcluded() { void execute_PatientExcluded() { var query = query(incl(PATIENT_POP), excl(PATIENT_POP)); - var result = service.execute(query); + var result = service.execute(ID, query); StepVerifier.create(result).expectNext(EMPTY_POP).verifyComplete(); } @@ -255,7 +256,7 @@ class SingleInclusionAndDisjunctionExclusion { void execute_PatientNotExcluded() { var query = query(incl(PATIENT_POP), exclOr(PATIENT_1_POP, PATIENT_2_POP)); - var result = service.execute(query); + var result = service.execute(ID, query); StepVerifier.create(result).expectNext(PATIENT_POP).verifyComplete(); @@ -266,7 +267,7 @@ void execute_PatientNotExcluded() { void execute_PatientExcluded() { var query = query(incl(PATIENT_POP), exclOr(PATIENT_POP, PATIENT_1_POP)); - var result = service.execute(query); + var result = service.execute(ID, query); StepVerifier.create(result).expectNext(EMPTY_POP).verifyComplete(); } @@ -293,7 +294,7 @@ class SingleInclusionAndConjunctionExclusion { void execute_PatientNotExcluded() { var query = query(incl(PATIENT_POP), exclAnd(PATIENT_POP, PATIENT_1_POP)); - var result = service.execute(query); + var result = service.execute(ID, query); StepVerifier.create(result).expectNext(PATIENT_POP).verifyComplete(); } @@ -303,7 +304,7 @@ void execute_PatientNotExcluded() { void execute_PatientExcluded() { var query = query(incl(PATIENT_POP), exclAnd(PATIENT_POP, PATIENT_POP)); - var result = service.execute(query); + var result = service.execute(ID, query); StepVerifier.create(result).expectNext(EMPTY_POP).verifyComplete(); } @@ -348,15 +349,15 @@ CriterionGroup group(TermCode c1, TermCode c2) { Criterion whenQuery(Population population) { var criterionQuery = whenCriterion(TermCode.of(BFARM, UUID.randomUUID().toString(), "")); - when(fhirQueryService.execute(criterionQuery.query)).thenReturn(Mono.just(population)); + when(fhirQueryService.execute(ID, criterionQuery.query)).thenReturn(Mono.just(population)); return criterionQuery.criterion; } Criterion whenQueryExpand(Population p1, Population p2) { var criterionQuery = whenCriterionExpand(TermCode.of(BFARM, UUID.randomUUID().toString(), ""), TermCode.of(BFARM, UUID.randomUUID().toString(), "")); - when(fhirQueryService.execute(criterionQuery.query1)).thenReturn(Mono.just(p1)); - when(fhirQueryService.execute(criterionQuery.query2)).thenReturn(Mono.just(p2)); + when(fhirQueryService.execute(ID, criterionQuery.query1)).thenReturn(Mono.just(p1)); + when(fhirQueryService.execute(ID, criterionQuery.query2)).thenReturn(Mono.just(p2)); return criterionQuery.criterion; } From c8ab49bbd7725a6ff490ed54cf989fb906992e47 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 14 Jan 2025 15:56:15 +0000 Subject: [PATCH 5/7] Update dependency org.rocksdb:rocksdbjni to v9.8.4 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7f7b78ab..fa7f9508 100644 --- a/pom.xml +++ b/pom.xml @@ -61,7 +61,7 @@ org.rocksdb rocksdbjni - 9.7.3 + 9.8.4 From 1af48596a3ad030d5051ac8f5a3aa88d9828d10f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 14 Jan 2025 17:12:49 +0000 Subject: [PATCH 6/7] Update codecov/codecov-action action to v5 --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index eb60b19e..326d67d6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -42,7 +42,7 @@ jobs: run: mvn -B verify - name: Upload coverage to Codecov - uses: codecov/codecov-action@v4 + uses: codecov/codecov-action@v5 - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v3 From 18c401c1dfd1a8b071c9a54a16f0101d089da02e Mon Sep 17 00:00:00 2001 From: Alexander Kiel Date: Wed, 15 Jan 2025 09:30:57 +0100 Subject: [PATCH 7/7] Release v2.5.0 --- CHANGELOG.md | 8 ++++++++ docker-compose.yml | 2 +- pom.xml | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e84a492a..55b54ebc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## v2.5.0 + +### Enhancements + +* Add Query Tracing to Logging ([#240](https://github.com/medizininformatik-initiative/flare/issues/240)) + +The full changelog can be found [here](https://github.com/medizininformatik-initiative/flare/milestone/16?closed=1). + ## v2.4.1 ### Enhancements diff --git a/docker-compose.yml b/docker-compose.yml index 4be96f1f..0c5575b3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,6 @@ services: flare: - image: ghcr.io/medizininformatik-initiative/flare:2.4.1 + image: ghcr.io/medizininformatik-initiative/flare:2.5.0 ports: - 8080:8080 volumes: diff --git a/pom.xml b/pom.xml index fa7f9508..9721320d 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,7 @@ de.medizininformatik-initiative flare - 2.4.1 + 2.5.0 Flare Flare