aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-db-dao/src/it/java
diff options
context:
space:
mode:
authorHavoc Pennington <hp@pobox.com>2025-03-01 16:37:17 -0500
committersonartech <sonartech@sonarsource.com>2025-03-04 20:03:22 +0000
commit859a87748a1f005d8d565da6f526f7d5bc45d0ea (patch)
treebea7cf34ad1b97cf7e01adb34963f2594afd1d3b /server/sonar-db-dao/src/it/java
parentce5ddb53701c4715b28ebb6c644d8309d00800ec (diff)
downloadsonarqube-859a87748a1f005d8d565da6f526f7d5bc45d0ea.tar.gz
sonarqube-859a87748a1f005d8d565da6f526f7d5bc45d0ea.zip
SQRP-299 Add query with filter/sort to ScaIssuesReleasesDetailsDao
Diffstat (limited to 'server/sonar-db-dao/src/it/java')
-rw-r--r--server/sonar-db-dao/src/it/java/org/sonar/db/sca/ScaIssuesReleasesDetailsDaoIT.java434
1 files changed, 433 insertions, 1 deletions
diff --git a/server/sonar-db-dao/src/it/java/org/sonar/db/sca/ScaIssuesReleasesDetailsDaoIT.java b/server/sonar-db-dao/src/it/java/org/sonar/db/sca/ScaIssuesReleasesDetailsDaoIT.java
index 067424aa818..42eba53cfb8 100644
--- a/server/sonar-db-dao/src/it/java/org/sonar/db/sca/ScaIssuesReleasesDetailsDaoIT.java
+++ b/server/sonar-db-dao/src/it/java/org/sonar/db/sca/ScaIssuesReleasesDetailsDaoIT.java
@@ -19,13 +19,21 @@
*/
package org.sonar.db.sca;
+import com.google.common.collect.Lists;
import java.math.BigDecimal;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.EnumMap;
import java.util.List;
+import java.util.function.Function;
+import java.util.stream.Stream;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.sonar.api.utils.System2;
import org.sonar.db.DbTester;
import org.sonar.db.Pagination;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.db.component.ProjectData;
import static org.assertj.core.api.Assertions.assertThat;
@@ -36,6 +44,15 @@ class ScaIssuesReleasesDetailsDaoIT {
private final ScaIssuesReleasesDetailsDao scaIssuesReleasesDetailsDao = db.getDbClient().scaIssuesReleasesDetailsDao();
+ private static Comparator<ScaIssueReleaseDetailsDto> identityComparator() {
+ Function<ScaIssueReleaseDetailsDto, String> typeString = dto -> dto.scaIssueType().name();
+ return Comparator.comparing(typeString)
+ .thenComparing(ScaIssueReleaseDetailsDto::vulnerabilityId)
+ .thenComparing(ScaIssueReleaseDetailsDto::packageUrl)
+ .thenComparing(ScaIssueReleaseDetailsDto::spdxLicenseId)
+ .thenComparing(ScaIssueReleaseDetailsDto::scaIssueReleaseUuid);
+ }
+
@Test
void selectByBranchUuid_shouldReturnIssues() {
var projectData = db.components().insertPrivateProject();
@@ -72,7 +89,7 @@ class ScaIssuesReleasesDetailsDaoIT {
assertThat(foundPage).hasSize(1).isSubsetOf(expected1, expected2);
var foundAllIssues = scaIssuesReleasesDetailsDao.selectByBranchUuid(db.getSession(), componentDto.branchUuid(), Pagination.forPage(1).andSize(10));
- assertThat(foundAllIssues).hasSize(2).containsExactlyInAnyOrder(expected1, expected2);
+ assertThat(foundAllIssues).hasSize(2).containsExactlyElementsOf(Stream.of(expected1, expected2).sorted(identityComparator()).toList());
}
@Test
@@ -87,4 +104,419 @@ class ScaIssuesReleasesDetailsDaoIT {
assertThat(scaIssuesReleasesDetailsDao.countByBranchUuid(db.getSession(), "bogus-branch-uuid")).isZero();
}
+
+ @Test
+ void withNoQueryFilters_shouldReturnAllIssues() {
+ setupAndExecuteQueryTest(Function.identity(), QueryTestData::expectedIssuesSortedByIdentityAsc, "All issues should be returned");
+ }
+
+ @Test
+ void withNoQueryFilters_shouldCountAllIssues() {
+ setupAndExecuteQueryCountTest(Function.identity(), 6);
+ }
+
+ @Test
+ void withNoQueryFilters_shouldSort() {
+ QueryTestData testData = createQueryTestData();
+ var expectedLists = new EnumMap<ScaIssuesReleasesDetailsQuery.Sort, List<ScaIssueReleaseDetailsDto>>(ScaIssuesReleasesDetailsQuery.Sort.class);
+ for (var sort : ScaIssuesReleasesDetailsQuery.Sort.values()) {
+ var expectedIssues = testData.expectedIssuesSorted(sort);
+ executeQueryTest(testData, queryBuilder -> queryBuilder.setSort(sort), expectedIssues,
+ "Sort %s should return expected issues".formatted(sort));
+ expectedLists.put(sort, expectedIssues);
+ }
+
+ // The assertions below here are actually about the expectations, but above
+ // we've just established that the actual matches the expectations.
+
+ // The point of this is to assert that the test data contains a distinct ordering for each
+ // ordering in ScaIssuesReleasesDetailsQuery.Sort, because if it doesn't we could get
+ // false negatives in our tests.
+ assertThat(expectedLists.values().stream().distinct().toList())
+ .as("Expected issues should have distinct orderings for each sort")
+ .containsExactlyInAnyOrderElementsOf(expectedLists.values());
+
+ // for identity, assert that our ASC and DESC actually invert each other.
+ // for severity and cvss score, this isn't supposed to be true because the
+ // secondary sort is IDENTITY_ASC even when we sort by DESC severity; but the
+ // severity and score values ignoring the other attributes should still be
+ // reversed.
+ assertThat(Lists.reverse(expectedLists.get(ScaIssuesReleasesDetailsQuery.Sort.IDENTITY_ASC)))
+ .as("IDENTITY sort should be reversed when sorted by DESC")
+ .containsExactlyElementsOf(expectedLists.get(ScaIssuesReleasesDetailsQuery.Sort.IDENTITY_DESC));
+ assertThat(
+ Lists.reverse(expectedLists.get(ScaIssuesReleasesDetailsQuery.Sort.SEVERITY_ASC)).stream()
+ .map(ScaIssueReleaseDetailsDto::severity)
+ .toList())
+ .as("SEVERITY sort should be reversed when sorted by DESC")
+ .containsExactlyElementsOf(expectedLists.get(ScaIssuesReleasesDetailsQuery.Sort.SEVERITY_DESC).stream()
+ .map(ScaIssueReleaseDetailsDto::severity)
+ .toList());
+ assertThat(Lists.reverse(expectedLists.get(ScaIssuesReleasesDetailsQuery.Sort.CVSS_SCORE_ASC).stream()
+ .map(ScaIssueReleaseDetailsDto::cvssScore)
+ .toList()))
+ .as("CVSS_SCORE sort should be reversed when sorted by DESC")
+ .containsExactlyElementsOf(expectedLists.get(ScaIssuesReleasesDetailsQuery.Sort.CVSS_SCORE_DESC).stream()
+ .map(ScaIssueReleaseDetailsDto::cvssScore)
+ .toList());
+ }
+
+ @Test
+ void withQueryFilteredByIssueType_shouldReturnExpectedTypes() {
+ QueryTestData testData = createQueryTestData();
+ executeQueryTest(testData,
+ queryBuilder -> queryBuilder.setTypes(List.of(ScaIssueType.VULNERABILITY)),
+ testData.expectedIssuesSortedByIdentityAsc().stream()
+ .filter(expected -> expected.scaIssueType() == ScaIssueType.VULNERABILITY)
+ .toList(),
+ "Only vulnerability issues should be returned");
+ executeQueryTest(testData,
+ queryBuilder -> queryBuilder.setTypes(List.of(ScaIssueType.PROHIBITED_LICENSE)),
+ testData.expectedIssuesSortedByIdentityAsc().stream()
+ .filter(expected -> expected.scaIssueType() == ScaIssueType.PROHIBITED_LICENSE)
+ .toList(),
+ "Only vulnerability issues should be returned");
+ executeQueryTest(testData,
+ queryBuilder -> queryBuilder.setTypes(List.of(ScaIssueType.values())),
+ testData.expectedIssuesSortedByIdentityAsc(),
+ "All issues should be returned");
+ executeQueryTest(testData,
+ queryBuilder -> queryBuilder.setTypes(Collections.emptyList()),
+ Collections.emptyList(),
+ "No issues should be returned when searching for zero types");
+ }
+
+ @Test
+ void withQueryFilteredByIssueType_shouldCountSelectedIssues() {
+ QueryTestData testData = createQueryTestData();
+ executeQueryCountTest(testData,
+ queryBuilder -> queryBuilder.setTypes(List.of(ScaIssueType.VULNERABILITY)),
+ 4);
+ executeQueryCountTest(testData,
+ queryBuilder -> queryBuilder.setTypes(List.of(ScaIssueType.PROHIBITED_LICENSE)),
+ 2);
+ executeQueryCountTest(testData,
+ queryBuilder -> queryBuilder.setTypes(List.of(ScaIssueType.values())),
+ 6);
+ executeQueryCountTest(testData,
+ queryBuilder -> queryBuilder.setTypes(Collections.emptyList()),
+ 0);
+ }
+
+ @Test
+ void withQueryFilteredByVulnerabilityId_shouldReturnExpectedItems() {
+ QueryTestData testData = createQueryTestData();
+ var expectedEndsInId1 = testData.expectedIssues().stream()
+ .filter(issue -> issue.vulnerabilityId() != null && issue.vulnerabilityId().endsWith("Id1"))
+ .toList();
+ assertThat(expectedEndsInId1).hasSize(1);
+ executeQueryTest(testData,
+ queryBuilder -> queryBuilder.setVulnerabilityIdSubstring("Id1"),
+ expectedEndsInId1,
+ "Only the vulnerability ending in Id1 should be returned");
+
+ executeQueryTest(testData,
+ queryBuilder -> queryBuilder.setVulnerabilityIdSubstring("NotInThere"),
+ Collections.emptyList(),
+ "No issues should be returned when searching for the substring 'NotInThere'");
+ executeQueryTest(testData,
+ queryBuilder -> queryBuilder.setVulnerabilityIdSubstring("Escape% NULL AS!%"),
+ Collections.emptyList(),
+ "No issues should be returned when searching for a string that needs escaping");
+ executeQueryTest(testData,
+ queryBuilder -> queryBuilder.setVulnerabilityIdSubstring(ScaIssueDto.NULL_VALUE),
+ Collections.emptyList(),
+ "No vulnerabilities should be returned when searching for ScaIssueDto.NULL_VALUE");
+
+ var allVulnerabilityIssues = testData.expectedIssuesSortedByIdentityAsc().stream()
+ .filter(issue -> issue.scaIssueType() == ScaIssueType.VULNERABILITY)
+ .toList();
+ assertThat(allVulnerabilityIssues).hasSize(4);
+
+ executeQueryTest(testData,
+ queryBuilder -> queryBuilder.setVulnerabilityIdSubstring("Vulnerability"),
+ allVulnerabilityIssues,
+ "All vulnerabilities should be returned when searching for the substring 'Vulnerability'");
+
+ executeQueryTest(testData,
+ queryBuilder -> queryBuilder.setVulnerabilityIdSubstring(""),
+ allVulnerabilityIssues,
+ "All vulnerabilities should be returned when searching for empty vulnerabilityId");
+ }
+
+ @Test
+ void withQueryFilteredByPackageName_shouldReturnExpectedItems() {
+ QueryTestData testData = createQueryTestData();
+ var expectedEndsInName1 = testData.expectedIssues().subList(0, 1);
+
+ executeQueryTest(testData,
+ queryBuilder -> queryBuilder.setPackageNameSubstring("Name1"),
+ expectedEndsInName1,
+ "Only the packages containing Name1 should be returned");
+
+ executeQueryTest(testData,
+ queryBuilder -> queryBuilder.setPackageNameSubstring("NotInThere"),
+ Collections.emptyList(),
+ "No issues should be returned when searching for the substring 'NotInThere'");
+ executeQueryTest(testData,
+ queryBuilder -> queryBuilder.setPackageNameSubstring("Escape% NULL AS!%"),
+ Collections.emptyList(),
+ "No issues should be returned when searching for a string that needs escaping");
+ executeQueryTest(testData,
+ queryBuilder -> queryBuilder.setPackageNameSubstring(ScaIssueDto.NULL_VALUE),
+ Collections.emptyList(),
+ "No vulnerabilities should be returned when searching for ScaIssueDto.NULL_VALUE");
+
+ executeQueryTest(testData,
+ queryBuilder -> queryBuilder.setPackageNameSubstring("Package"),
+ testData.expectedIssuesSortedByIdentityAsc(),
+ "All issues should be returned when searching for the substring 'Package'");
+
+ executeQueryTest(testData,
+ queryBuilder -> queryBuilder.setPackageNameSubstring(""),
+ testData.expectedIssuesSortedByIdentityAsc(),
+ "All issues should be returned when searching for empty package name");
+ }
+
+ @Test
+ void withQueryFilteredBySeverity_shouldReturnExpectedItems() {
+ QueryTestData testData = createQueryTestData();
+ var expectedSeverityInfo = testData.expectedIssuesSortedByIdentityAsc().stream()
+ .filter(issue -> issue.severity() == ScaSeverity.INFO)
+ .toList();
+ var expectedSeverityCritical = testData.expectedIssuesSortedByIdentityAsc().stream()
+ .filter(issue -> issue.severity() == ScaSeverity.BLOCKER)
+ .toList();
+ assertThat(expectedSeverityInfo).hasSize(5);
+ assertThat(expectedSeverityCritical).hasSize(1);
+
+ executeQueryTest(testData,
+ queryBuilder -> queryBuilder.setSeverities(List.of(ScaSeverity.INFO)),
+ expectedSeverityInfo,
+ "Only the issues of severity INFO should be returned");
+
+ executeQueryTest(testData,
+ queryBuilder -> queryBuilder.setSeverities(List.of(ScaSeverity.BLOCKER)),
+ expectedSeverityCritical,
+ "Only the issues of severity CRITICAL should be returned");
+
+ executeQueryTest(testData,
+ queryBuilder -> queryBuilder.setSeverities(List.of(ScaSeverity.LOW, ScaSeverity.HIGH)),
+ Collections.emptyList(),
+ "Should not match any severities of LOW or HIGH");
+
+ executeQueryTest(testData,
+ queryBuilder -> queryBuilder.setSeverities(List.of(ScaSeverity.BLOCKER, ScaSeverity.INFO, ScaSeverity.LOW)),
+ testData.expectedIssuesSortedByIdentityAsc(),
+ "All issues should be returned when searching for a list that contains them all");
+
+ executeQueryTest(testData,
+ queryBuilder -> queryBuilder.setSeverities(Collections.emptyList()),
+ Collections.emptyList(),
+ "No issues should be returned when searching for zero severities");
+ }
+
+ @Test
+ void withQueryFilteredByPackageManager_shouldReturnExpectedItems() {
+ QueryTestData testData = createQueryTestData();
+ var expectedPackageManagerNpm = testData.expectedIssuesWithPackageManager(PackageManager.NPM).stream()
+ .sorted(identityComparator()).toList();
+ var expectedPackageManagerMaven = testData.expectedIssuesWithPackageManager(PackageManager.MAVEN).stream()
+ .sorted(identityComparator()).toList();
+
+ assertThat(expectedPackageManagerNpm).hasSize(2);
+ assertThat(expectedPackageManagerMaven).hasSize(4);
+
+ executeQueryTest(testData,
+ queryBuilder -> queryBuilder.setPackageManagers(List.of(PackageManager.NPM)),
+ expectedPackageManagerNpm,
+ "Only the npm issues should be returned");
+
+ executeQueryTest(testData,
+ queryBuilder -> queryBuilder.setPackageManagers(List.of(PackageManager.MAVEN)),
+ expectedPackageManagerMaven,
+ "Only the Maven issues should be returned");
+
+ executeQueryTest(testData,
+ queryBuilder -> queryBuilder.setPackageManagers(List.of(PackageManager.NPM, PackageManager.MAVEN)),
+ testData.expectedIssuesSortedByIdentityAsc(),
+ "All issues should be returned when searching for two package managers");
+
+ executeQueryTest(testData,
+ queryBuilder -> queryBuilder.setPackageManagers(Collections.emptyList()),
+ Collections.emptyList(),
+ "No issues should be returned when searching for zero package managers");
+ }
+
+ @Test
+ void withQueryMultipleFiltersNonDefaultSort_shouldReturnExpectedItems() {
+ QueryTestData testData = createQueryTestData();
+ var expectedPackageManagerMaven = testData.expectedIssuesWithPackageManager(PackageManager.MAVEN);
+ var expectedTypeVulnerability = testData.expectedIssuesSortedByIdentityAsc().stream()
+ .filter(issue -> issue.scaIssueType() == ScaIssueType.VULNERABILITY)
+ .toList();
+ var sortedByCvssDesc = testData.expectedIssuesSortedByCvssDesc();
+ var expectedResults = sortedByCvssDesc.stream()
+ .filter(expectedPackageManagerMaven::contains)
+ .filter(expectedTypeVulnerability::contains)
+ .toList();
+ assertThat(expectedResults).hasSize(3);
+
+ executeQueryTest(testData,
+ queryBuilder -> queryBuilder
+ .setSort(ScaIssuesReleasesDetailsQuery.Sort.CVSS_SCORE_DESC)
+ .setPackageManagers(List.of(PackageManager.MAVEN))
+ .setTypes(List.of(ScaIssueType.VULNERABILITY)),
+ expectedResults,
+ "Maven vulnerabilities returned in cvss score desc order");
+ }
+
+ private void setupAndExecuteQueryTest(Function<ScaIssuesReleasesDetailsQuery.Builder, ScaIssuesReleasesDetailsQuery.Builder> builderFunction,
+ Function<QueryTestData, List<ScaIssueReleaseDetailsDto>> expectedIssuesFunction, String assertAs) {
+ QueryTestData testData = createQueryTestData();
+ executeQueryTest(testData, builderFunction, expectedIssuesFunction.apply(testData), assertAs);
+ }
+
+ private void executeQueryTest(QueryTestData testData,
+ Function<ScaIssuesReleasesDetailsQuery.Builder, ScaIssuesReleasesDetailsQuery.Builder> builderFunction,
+ List<ScaIssueReleaseDetailsDto> expectedIssues,
+ String assertAs) {
+ var query = builderFunction.apply(
+ new ScaIssuesReleasesDetailsQuery.Builder()
+ .setBranchUuid(testData.branchUuid())
+ .setSort(ScaIssuesReleasesDetailsQuery.Sort.IDENTITY_ASC))
+ .build();
+ var foundPage = scaIssuesReleasesDetailsDao.selectByQuery(db.getSession(), query, Pagination.forPage(1).andSize(10));
+
+ assertThat(foundPage).as(assertAs).containsExactlyElementsOf(expectedIssues);
+ }
+
+ private void setupAndExecuteQueryCountTest(Function<ScaIssuesReleasesDetailsQuery.Builder, ScaIssuesReleasesDetailsQuery.Builder> builderFunction,
+ int expectedCount) {
+ QueryTestData testData = createQueryTestData();
+ executeQueryCountTest(testData, builderFunction, expectedCount);
+ }
+
+ private void executeQueryCountTest(QueryTestData testData,
+ Function<ScaIssuesReleasesDetailsQuery.Builder, ScaIssuesReleasesDetailsQuery.Builder> builderFunction,
+ int expectedCount) {
+ var query = builderFunction.apply(
+ new ScaIssuesReleasesDetailsQuery.Builder()
+ .setBranchUuid(testData.branchUuid())
+ .setSort(ScaIssuesReleasesDetailsQuery.Sort.IDENTITY_ASC))
+ .build();
+ var count = scaIssuesReleasesDetailsDao.countByQuery(db.getSession(), query);
+
+ assertThat(count).isEqualTo(expectedCount);
+ }
+
+ private QueryTestData createQueryTestData() {
+ var projectData = db.components().insertPrivateProject();
+ var componentDto = projectData.getMainBranchComponent();
+ // the first two are set to NPM, the others default to MAVEN
+ var issue1 = db.getScaIssuesReleasesDetailsDbTester().insertIssue(ScaIssueType.VULNERABILITY, "1", componentDto.uuid(), projectData.projectUuid(),
+ scaIssueDto -> scaIssueDto,
+ scaVulnerabilityIssueDto -> scaVulnerabilityIssueDto,
+ scaReleaseDto -> scaReleaseDto.toBuilder().setPackageManager(PackageManager.NPM).build(),
+ scaIssueReleaseDto -> scaIssueReleaseDto);
+ var issue2 = db.getScaIssuesReleasesDetailsDbTester().insertIssue(ScaIssueType.PROHIBITED_LICENSE, "2", componentDto.uuid(), projectData.projectUuid(),
+ scaIssueDto -> scaIssueDto,
+ scaVulnerabilityIssueDto -> scaVulnerabilityIssueDto,
+ scaReleaseDto -> scaReleaseDto.toBuilder().setPackageManager(PackageManager.NPM).build(),
+ scaIssueReleaseDto -> scaIssueReleaseDto);
+ var issue3 = db.getScaIssuesReleasesDetailsDbTester().insertIssue(ScaIssueType.VULNERABILITY, "3", componentDto.uuid(), projectData.projectUuid());
+ var issue4 = db.getScaIssuesReleasesDetailsDbTester().insertIssue(ScaIssueType.PROHIBITED_LICENSE, "4", componentDto.uuid(), projectData.projectUuid());
+ // low cvss but high severity
+ var issue5 = db.getScaIssuesReleasesDetailsDbTester().insertIssue(ScaIssueType.VULNERABILITY, "5", componentDto.uuid(), projectData.projectUuid(),
+ scaIssueDto -> scaIssueDto,
+ scaVulnerabilityIssueDto -> scaVulnerabilityIssueDto.toBuilder()
+ .setCvssScore(new BigDecimal("2.1"))
+ .setBaseSeverity(ScaSeverity.BLOCKER)
+ .build(),
+ scaReleaseDto -> scaReleaseDto,
+ scaIssueReleaseDto -> scaIssueReleaseDto.toBuilder().setSeverity(ScaSeverity.BLOCKER).build());
+ // high cvss but low severity
+ var issue6 = db.getScaIssuesReleasesDetailsDbTester().insertIssue(ScaIssueType.VULNERABILITY, "6", componentDto.uuid(), projectData.projectUuid(),
+ scaIssueDto -> scaIssueDto,
+ scaVulnerabilityIssueDto -> scaVulnerabilityIssueDto.toBuilder()
+ .setCvssScore(new BigDecimal("9.1"))
+ .setBaseSeverity(ScaSeverity.INFO)
+ .build(),
+ scaReleaseDto -> scaReleaseDto,
+ scaIssueReleaseDto -> scaIssueReleaseDto.toBuilder().setSeverity(ScaSeverity.INFO).build());
+
+ return new QueryTestData(projectData, componentDto,
+ List.of(issue1, issue2, issue3, issue4, issue5, issue6));
+ }
+
+ private record QueryTestData(ProjectData projectData,
+ ComponentDto componentDto,
+ List<ScaIssueReleaseDetailsDto> expectedIssues) {
+ private static Comparator<ScaIssueReleaseDetailsDto> cvssScoreComparator() {
+ return Comparator.comparing(ScaIssueReleaseDetailsDto::cvssScore,
+ // we treat null cvss as a score of 0.0
+ Comparator.nullsFirst(Comparator.naturalOrder()));
+ }
+
+ private static Comparator<ScaIssueReleaseDetailsDto> severityComparator() {
+ return Comparator.comparing(dto -> dto.severity().databaseSortKey());
+ }
+
+ public String branchUuid() {
+ return componentDto.branchUuid();
+ }
+
+ public List<ScaIssueReleaseDetailsDto> expectedIssuesSortedByIdentityAsc() {
+ return expectedIssues.stream().sorted(identityComparator()).toList();
+ }
+
+ public List<ScaIssueReleaseDetailsDto> expectedIssuesSortedByIdentityDesc() {
+ return expectedIssues.stream().sorted(identityComparator().reversed()).toList();
+ }
+
+ public List<ScaIssueReleaseDetailsDto> expectedIssuesSortedBySeverityAsc() {
+ return expectedIssues.stream().sorted(severityComparator()
+ .thenComparing(cvssScoreComparator())
+ .thenComparing(identityComparator())).toList();
+ }
+
+ public List<ScaIssueReleaseDetailsDto> expectedIssuesSortedBySeverityDesc() {
+ return expectedIssues.stream().sorted(severityComparator().reversed()
+ .thenComparing(cvssScoreComparator().reversed())
+ .thenComparing(identityComparator())).toList();
+ }
+
+ public List<ScaIssueReleaseDetailsDto> expectedIssuesSortedByCvssAsc() {
+ return expectedIssues.stream().sorted(cvssScoreComparator()
+ .thenComparing(ScaIssueReleaseDetailsDto::severity)
+ .thenComparing(identityComparator())).toList();
+ }
+
+ public List<ScaIssueReleaseDetailsDto> expectedIssuesSortedByCvssDesc() {
+ return expectedIssues.stream().sorted(cvssScoreComparator().reversed()
+ .thenComparing(Comparator.comparing(ScaIssueReleaseDetailsDto::severity).reversed())
+ .thenComparing(identityComparator())).toList();
+ }
+
+ public List<ScaIssueReleaseDetailsDto> expectedIssuesSorted(ScaIssuesReleasesDetailsQuery.Sort sort) {
+ return switch (sort) {
+ case IDENTITY_ASC -> expectedIssuesSortedByIdentityAsc();
+ case IDENTITY_DESC -> expectedIssuesSortedByIdentityDesc();
+ case SEVERITY_ASC -> expectedIssuesSortedBySeverityAsc();
+ case SEVERITY_DESC -> expectedIssuesSortedBySeverityDesc();
+ case CVSS_SCORE_ASC -> expectedIssuesSortedByCvssAsc();
+ case CVSS_SCORE_DESC -> expectedIssuesSortedByCvssDesc();
+ };
+ }
+
+ public List<ScaIssueReleaseDetailsDto> expectedIssuesWithPackageManager(PackageManager packageManager) {
+ // we just have hardcoded knowledge of how we set them up, because ScaIssueReleaseDetailsDto doesn't
+ // contain the ScaReleaseDto to look at this
+ return switch (packageManager) {
+ case NPM -> expectedIssues.subList(0, 2);
+ case MAVEN -> expectedIssues.subList(2, expectedIssues.size());
+ default -> Collections.emptyList();
+ };
+ }
+ }
}