diff --git a/apps/opik-backend/src/main/java/com/comet/opik/domain/ProjectService.java b/apps/opik-backend/src/main/java/com/comet/opik/domain/ProjectService.java index e84ae2971..d0e29c200 100644 --- a/apps/opik-backend/src/main/java/com/comet/opik/domain/ProjectService.java +++ b/apps/opik-backend/src/main/java/com/comet/opik/domain/ProjectService.java @@ -318,8 +318,8 @@ private List sortByLastTrace( @NonNull Map projectLastUpdatedTraceAtMap, @NonNull SortingField sortingField) { // for projects with no traces - use last_updated_at - allProjectIdsLastUpdated.stream().filter(project -> !projectLastUpdatedTraceAtMap.containsKey(project.id())) - .forEach(project -> projectLastUpdatedTraceAtMap.put(project.id(), project.lastUpdatedAt())); + allProjectIdsLastUpdated.forEach( + project -> projectLastUpdatedTraceAtMap.computeIfAbsent(project.id(), key -> project.lastUpdatedAt())); Comparator> comparator = sortingField.direction() == Direction.DESC ? reverseOrder(Map.Entry.comparingByValue()) diff --git a/apps/opik-backend/src/test/java/com/comet/opik/api/resources/v1/priv/ProjectsResourceTest.java b/apps/opik-backend/src/test/java/com/comet/opik/api/resources/v1/priv/ProjectsResourceTest.java index 4ade829a3..e8f3909b5 100644 --- a/apps/opik-backend/src/test/java/com/comet/opik/api/resources/v1/priv/ProjectsResourceTest.java +++ b/apps/opik-backend/src/test/java/com/comet/opik/api/resources/v1/priv/ProjectsResourceTest.java @@ -831,30 +831,7 @@ void getProjects__whenSortingProjectsByLastTrace__thenReturnProjectSorted(Direct .lastUpdatedTraceAt(trace.lastUpdatedAt()).build(); }).toList(); - var sorting = List.of(SortingField.builder() - .field(SortableFields.LAST_UPDATED_TRACE_AT) - .direction(request) - .build()); - - var actualResponse = client.target(URL_TEMPLATE.formatted(baseURI)) - .queryParam("size", projects.size()) - .queryParam("sorting", URLEncoder.encode(JsonUtils.writeValueAsString(sorting), - StandardCharsets.UTF_8)) - .request() - .header(HttpHeaders.AUTHORIZATION, apiKey) - .header(WORKSPACE_HEADER, workspaceName) - .get(); - - var actualEntity = actualResponse.readEntity(Project.ProjectPage.class); - - assertThat(actualResponse.getStatusInfo().getStatusCode()).isEqualTo(200); - assertThat(actualEntity.size()).isEqualTo(projects.size()); - assertThat(actualEntity.total()).isEqualTo(projects.size()); - assertThat(actualEntity.page()).isEqualTo(1); - - var expectedProjects = expected == Direction.DESC ? projects.reversed() : projects; - assertThat(actualEntity.content()).usingRecursiveFieldByFieldElementComparatorIgnoringFields(IGNORED_FIELDS) - .containsExactlyElementsOf(expectedProjects); + requestAndAssertLastTraceSorting(workspaceName, apiKey, projects, request, expected); } @ParameterizedTest @@ -888,36 +865,10 @@ void getProjects__whenSortingProjectsByLastTraceAndNoTraceExists__thenReturnProj UUID projectId = createProject(project, apiKey, workspaceName); return project.toBuilder().id(projectId).build(); }).toList(); - List allProjects = Stream.concat(withTraceProjects.stream(), noTraceProjects.stream()).toList(); - var sorting = List.of(SortingField.builder() - .field(SortableFields.LAST_UPDATED_TRACE_AT) - .direction(request) - .build()); - - var actualResponse = client.target(URL_TEMPLATE.formatted(baseURI)) - .queryParam("size", allProjects.size()) - .queryParam("sorting", URLEncoder.encode(JsonUtils.writeValueAsString(sorting), - StandardCharsets.UTF_8)) - .request() - .header(HttpHeaders.AUTHORIZATION, apiKey) - .header(WORKSPACE_HEADER, workspaceName) - .get(); - - var actualEntity = actualResponse.readEntity(Project.ProjectPage.class); - - assertThat(actualResponse.getStatusInfo().getStatusCode()).isEqualTo(200); - assertThat(actualEntity.size()).isEqualTo(allProjects.size()); - assertThat(actualEntity.total()).isEqualTo(allProjects.size()); - assertThat(actualEntity.page()).isEqualTo(1); - - var allExpectedProjects = Stream.concat(withTraceProjects.stream(), noTraceProjects.stream()).toList(); - if (expected == Direction.DESC) { - allExpectedProjects = allExpectedProjects.reversed(); - } - - assertThat(actualEntity.content()).usingRecursiveFieldByFieldElementComparatorIgnoringFields(IGNORED_FIELDS) - .containsExactlyElementsOf(allExpectedProjects); + requestAndAssertLastTraceSorting( + workspaceName, apiKey, Stream.concat(withTraceProjects.stream(), noTraceProjects.stream()).toList(), + request, expected); } public static Stream sortDirectionProvider() { @@ -1248,6 +1199,37 @@ private void assertProject(Project project, String apiKey, String workspaceName) assertThat(actualEntity.lastUpdatedAt()).isAfter(project.createdAt()); } + private void requestAndAssertLastTraceSorting(String workspaceName, String apiKey, List allProjects, + Direction request, Direction expected) { + var sorting = List.of(SortingField.builder() + .field(SortableFields.LAST_UPDATED_TRACE_AT) + .direction(request) + .build()); + + var actualResponse = client.target(URL_TEMPLATE.formatted(baseURI)) + .queryParam("size", allProjects.size()) + .queryParam("sorting", URLEncoder.encode(JsonUtils.writeValueAsString(sorting), + StandardCharsets.UTF_8)) + .request() + .header(HttpHeaders.AUTHORIZATION, apiKey) + .header(WORKSPACE_HEADER, workspaceName) + .get(); + + var actualEntity = actualResponse.readEntity(Project.ProjectPage.class); + + assertThat(actualResponse.getStatusInfo().getStatusCode()).isEqualTo(200); + assertThat(actualEntity.size()).isEqualTo(allProjects.size()); + assertThat(actualEntity.total()).isEqualTo(allProjects.size()); + assertThat(actualEntity.page()).isEqualTo(1); + + if (expected == Direction.DESC) { + allProjects = allProjects.reversed(); + } + + assertThat(actualEntity.content()).usingRecursiveFieldByFieldElementComparatorIgnoringFields(IGNORED_FIELDS) + .containsExactlyElementsOf(allProjects); + } + @Nested @DisplayName("Create:") @TestInstance(TestInstance.Lifecycle.PER_CLASS)