From 513356269ca36067d24db28cfda79630130e8bf1 Mon Sep 17 00:00:00 2001 From: Teryk Bellahsene Date: Thu, 31 Aug 2017 16:44:59 +0200 Subject: [PATCH] SONAR-8640 WS api/projects/search query on key does partial match and is case insensitive --- .../sonar/db/component/ComponentQuery.java | 41 ++++++------ .../sonar/db/component/ComponentMapper.xml | 11 +++- .../sonar/db/component/ComponentDaoTest.java | 63 ++++++++++++------- .../db/component/ComponentQueryTest.java | 20 ++++-- .../sonar/server/project/ws/SearchAction.java | 8 ++- .../server/project/ws/SearchActionTest.java | 9 +-- .../org/sonar/api/server/ws/WebService.java | 3 +- .../ProjectSearchTest.java | 26 ++++++++ 8 files changed, 120 insertions(+), 61 deletions(-) diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentQuery.java b/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentQuery.java index 58858246033..2568f8ba22b 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentQuery.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentQuery.java @@ -30,30 +30,16 @@ import static org.sonar.db.DaoDatabaseUtils.buildLikeValue; public class ComponentQuery { private final String nameOrKeyQuery; + private final boolean partialMatchOnKey; private final String[] qualifiers; private final String language; private final Boolean isPrivate; private final Set componentIds; private final Long analyzedBefore; - /** - * Used by Dev Cockpit 1.9. - * Could be removed when Developer Cockpit doesn't use it anymore. - * - * @deprecated since 5.4, use {@link Builder} instead - */ - @Deprecated - public ComponentQuery(@Nullable String nameOrKeyQuery, String... qualifiers) { - this.nameOrKeyQuery = nameOrKeyQuery; - this.qualifiers = Builder.validateQualifiers(qualifiers); - this.language = null; - this.componentIds = null; - this.isPrivate = null; - this.analyzedBefore = null; - } - private ComponentQuery(Builder builder) { this.nameOrKeyQuery = builder.nameOrKeyQuery; + this.partialMatchOnKey = builder.partialMatchOnKey == null ? false : builder.partialMatchOnKey; this.qualifiers = builder.qualifiers; this.language = builder.language; this.componentIds = builder.componentIds; @@ -78,6 +64,13 @@ public class ComponentQuery { return buildLikeValue(nameOrKeyQuery, WildcardPosition.BEFORE_AND_AFTER).toUpperCase(Locale.ENGLISH); } + /** + * Used by MyBatis mapper + */ + public boolean isPartialMatchOnKey() { + return partialMatchOnKey; + } + @CheckForNull public String getLanguage() { return language; @@ -104,6 +97,7 @@ public class ComponentQuery { public static class Builder { private String nameOrKeyQuery; + private Boolean partialMatchOnKey; private String[] qualifiers; private String language; private Boolean isPrivate; @@ -115,6 +109,14 @@ public class ComponentQuery { return this; } + /** + * Beware, can be resource intensive! Should be used with precautions. + */ + public Builder setPartialMatchOnKey(@Nullable Boolean partialMatchOnKey) { + this.partialMatchOnKey = partialMatchOnKey; + return this; + } + public Builder setQualifiers(String... qualifiers) { this.qualifiers = qualifiers; return this; @@ -140,13 +142,10 @@ public class ComponentQuery { return this; } - protected static String[] validateQualifiers(@Nullable String... qualifiers) { + public ComponentQuery build() { checkArgument(qualifiers != null && qualifiers.length > 0, "At least one qualifier must be provided"); - return qualifiers; - } + checkArgument(nameOrKeyQuery != null || partialMatchOnKey == null, "A query must be provided if a partial match on key is specified."); - public ComponentQuery build() { - validateQualifiers(this.qualifiers); return new ComponentQuery(this); } } diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentMapper.xml index 905d1ef8717..d9e90aa8110 100644 --- a/server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentMapper.xml +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentMapper.xml @@ -276,9 +276,16 @@ and ( - p.kee = #{query.nameOrKeyQuery,jdbcType=VARCHAR} - or upper(p.name) like #{query.nameOrKeyUpperLikeQuery,jdbcType=VARCHAR} escape '/' + or + + + upper(p.kee) like #{query.nameOrKeyUpperLikeQuery,jdbcType=VARCHAR} escape '/' + + + p.kee = #{query.nameOrKeyQuery,jdbcType=VARCHAR} + + ) diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentDaoTest.java index aae487bf389..484612e7e28 100644 --- a/server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentDaoTest.java +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentDaoTest.java @@ -608,8 +608,8 @@ public class ComponentDaoTest { ComponentDto provisionedProject = db.components().insertPrivateProject(); ComponentDto provisionedView = db.components().insertView(organization, (dto) -> { }); - String projectUuid = db.components().insertProjectAndSnapshot(ComponentTesting.newPrivateProjectDto(organization)).getComponentUuid(); - String disabledProjectUuid = db.components().insertProjectAndSnapshot(ComponentTesting.newPrivateProjectDto(organization).setEnabled(false)).getComponentUuid(); + String projectUuid = db.components().insertProjectAndSnapshot(newPrivateProjectDto(organization)).getComponentUuid(); + String disabledProjectUuid = db.components().insertProjectAndSnapshot(newPrivateProjectDto(organization).setEnabled(false)).getComponentUuid(); String viewUuid = db.components().insertProjectAndSnapshot(ComponentTesting.newView(organization)).getComponentUuid(); assertThat(underTest.selectProjects(dbSession)) @@ -621,10 +621,10 @@ public class ComponentDaoTest { public void select_provisioned() { OrganizationDto organization = db.organizations().insert(); ComponentDto provisionedProject = db.components() - .insertComponent(ComponentTesting.newPrivateProjectDto(organization).setDbKey("provisioned.project").setName("Provisioned Project")); + .insertComponent(newPrivateProjectDto(organization).setDbKey("provisioned.project").setName("Provisioned Project")); ComponentDto provisionedView = db.components().insertView(organization); - String projectUuid = db.components().insertProjectAndSnapshot(ComponentTesting.newPrivateProjectDto(organization)).getComponentUuid(); - String disabledProjectUuid = db.components().insertProjectAndSnapshot(ComponentTesting.newPrivateProjectDto(organization).setEnabled(false)).getComponentUuid(); + String projectUuid = db.components().insertProjectAndSnapshot(newPrivateProjectDto(organization)).getComponentUuid(); + String disabledProjectUuid = db.components().insertProjectAndSnapshot(newPrivateProjectDto(organization).setEnabled(false)).getComponentUuid(); String viewUuid = db.components().insertProjectAndSnapshot(ComponentTesting.newView(organization)).getComponentUuid(); Set projectQualifiers = newHashSet(Qualifiers.PROJECT); @@ -668,7 +668,7 @@ public class ComponentDaoTest { public void count_provisioned() { OrganizationDto organization = db.organizations().insert(); db.components().insertPrivateProject(organization); - db.components().insertProjectAndSnapshot(ComponentTesting.newPrivateProjectDto(organization)); + db.components().insertProjectAndSnapshot(newPrivateProjectDto(organization)); db.components().insertProjectAndSnapshot(ComponentTesting.newView(organization)); assertThat(underTest.countProvisioned(dbSession, organization.getUuid(), null, newHashSet(Qualifiers.PROJECT))).isEqualTo(1); @@ -898,10 +898,10 @@ public class ComponentDaoTest { @Test public void selectByQuery_with_paging_query_and_qualifiers() { OrganizationDto organizationDto = db.organizations().insert(); - db.components().insertProjectAndSnapshot(ComponentTesting.newPrivateProjectDto(organizationDto).setName("aaaa-name")); + db.components().insertProjectAndSnapshot(newPrivateProjectDto(organizationDto).setName("aaaa-name")); db.components().insertProjectAndSnapshot(newView(organizationDto)); for (int i = 9; i >= 1; i--) { - db.components().insertProjectAndSnapshot(ComponentTesting.newPrivateProjectDto(organizationDto).setName("project-" + i)); + db.components().insertProjectAndSnapshot(newPrivateProjectDto(organizationDto).setName("project-" + i)); } ComponentQuery query = ComponentQuery.builder().setNameOrKeyQuery("oJect").setQualifiers(Qualifiers.PROJECT).build(); @@ -953,7 +953,7 @@ public class ComponentDaoTest { @Test public void selectByQuery_name_with_special_characters() { - db.components().insertProjectAndSnapshot(ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setName("project-\\_%/-name")); + db.components().insertProjectAndSnapshot(newPrivateProjectDto(db.getDefaultOrganization()).setName("project-\\_%/-name")); ComponentQuery query = ComponentQuery.builder().setNameOrKeyQuery("-\\_%/-").setQualifiers(Qualifiers.PROJECT).build(); List result = underTest.selectByQuery(dbSession, query, 0, 10); @@ -964,7 +964,8 @@ public class ComponentDaoTest { @Test public void selectByQuery_key_with_special_characters() { - db.components().insertProjectAndSnapshot(ComponentTesting.newPrivateProjectDto(db.organizations().insert()).setDbKey("project-_%-key")); + db.components().insertProjectAndSnapshot(newPrivateProjectDto(db.organizations().insert()).setDbKey("project-_%-key")); + db.components().insertProjectAndSnapshot(newPrivateProjectDto(db.organizations().insert()).setDbKey("project-key-that-does-not-match")); ComponentQuery query = ComponentQuery.builder().setNameOrKeyQuery("project-_%-key").setQualifiers(Qualifiers.PROJECT).build(); List result = underTest.selectByQuery(dbSession, query, 0, 10); @@ -973,10 +974,24 @@ public class ComponentDaoTest { assertThat(result.get(0).getDbKey()).isEqualTo("project-_%-key"); } + @Test + public void selectByQuery_on_key_partial_match_case_insensitive() { + db.components().insertProjectAndSnapshot(newPrivateProjectDto(db.organizations().insert()).setDbKey("project-key")); + + ComponentQuery query = ComponentQuery.builder() + .setNameOrKeyQuery("JECT-K") + .setPartialMatchOnKey(true) + .setQualifiers(Qualifiers.PROJECT).build(); + List result = underTest.selectByQuery(dbSession, query, 0, 10); + + assertThat(result).hasSize(1); + assertThat(result.get(0).getDbKey()).isEqualTo("project-key"); + } + @Test public void selectByQuery_filter_on_language() { - db.components().insertComponent(ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setDbKey("java-project-key").setLanguage("java")); - db.components().insertComponent(ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setDbKey("cpp-project-key").setLanguage("cpp")); + db.components().insertComponent(newPrivateProjectDto(db.getDefaultOrganization()).setDbKey("java-project-key").setLanguage("java")); + db.components().insertComponent(newPrivateProjectDto(db.getDefaultOrganization()).setDbKey("cpp-project-key").setLanguage("cpp")); ComponentQuery query = ComponentQuery.builder().setLanguage("java").setQualifiers(Qualifiers.PROJECT).build(); List result = underTest.selectByQuery(dbSession, query, 0, 10); @@ -1006,7 +1021,7 @@ public class ComponentDaoTest { @Test public void selectByQuery_filter_on_visibility() { - db.components().insertComponent(ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setDbKey("private-key")); + db.components().insertComponent(newPrivateProjectDto(db.getDefaultOrganization()).setDbKey("private-key")); db.components().insertComponent(ComponentTesting.newPublicProjectDto(db.getDefaultOrganization()).setDbKey("public-key")); ComponentQuery privateProjectsQuery = ComponentQuery.builder().setPrivate(true).setQualifiers(Qualifiers.PROJECT).build(); @@ -1031,9 +1046,9 @@ public class ComponentDaoTest { @Test public void selectByQuery_on_component_ids() { OrganizationDto organizationDto = db.organizations().insert(); - ComponentDto sonarqube = db.components().insertComponent(ComponentTesting.newPrivateProjectDto(organizationDto)); - ComponentDto jdk8 = db.components().insertComponent(ComponentTesting.newPrivateProjectDto(organizationDto)); - ComponentDto cLang = db.components().insertComponent(ComponentTesting.newPrivateProjectDto(organizationDto)); + ComponentDto sonarqube = db.components().insertComponent(newPrivateProjectDto(organizationDto)); + ComponentDto jdk8 = db.components().insertComponent(newPrivateProjectDto(organizationDto)); + ComponentDto cLang = db.components().insertComponent(newPrivateProjectDto(organizationDto)); ComponentQuery query = ComponentQuery.builder().setQualifiers(Qualifiers.PROJECT) .setComponentIds(newHashSet(sonarqube.getId(), jdk8.getId())).build(); @@ -1181,12 +1196,12 @@ public class ComponentDaoTest { @Test public void select_projects_by_name_query() { OrganizationDto organizationDto = db.organizations().insert(); - ComponentDto project1 = db.components().insertComponent(ComponentTesting.newPrivateProjectDto(organizationDto).setName("project1")); + ComponentDto project1 = db.components().insertComponent(newPrivateProjectDto(organizationDto).setName("project1")); ComponentDto module1 = db.components().insertComponent(newModuleDto(project1).setName("module1")); ComponentDto subModule1 = db.components().insertComponent(newModuleDto(module1).setName("subModule1")); db.components().insertComponent(newFileDto(subModule1).setName("file")); - ComponentDto project2 = db.components().insertComponent(ComponentTesting.newPrivateProjectDto(organizationDto).setName("project2")); - ComponentDto project3 = db.components().insertComponent(ComponentTesting.newPrivateProjectDto(organizationDto).setName("project3")); + ComponentDto project2 = db.components().insertComponent(newPrivateProjectDto(organizationDto).setName("project2")); + ComponentDto project3 = db.components().insertComponent(newPrivateProjectDto(organizationDto).setName("project3")); assertThat(underTest.selectProjectsByNameQuery(dbSession, null, false)).extracting(ComponentDto::uuid) .containsOnly(project1.uuid(), project2.uuid(), project3.uuid()); @@ -1207,11 +1222,11 @@ public class ComponentDaoTest { OrganizationDto organizationDto = db.organizations().insert(); String[] uuids = { - db.components().insertComponent(ComponentTesting.newPrivateProjectDto(organizationDto).setProjectUuid(uuid1).setPrivate(true)).uuid(), - db.components().insertComponent(ComponentTesting.newPrivateProjectDto(organizationDto).setProjectUuid(uuid1).setPrivate(false)).uuid(), - db.components().insertComponent(ComponentTesting.newPrivateProjectDto(organizationDto).setProjectUuid(uuid2).setPrivate(true)).uuid(), - db.components().insertComponent(ComponentTesting.newPrivateProjectDto(organizationDto).setProjectUuid(uuid2).setPrivate(false)).uuid(), - db.components().insertComponent(ComponentTesting.newPrivateProjectDto(organizationDto).setRootUuid(uuid1).setProjectUuid("foo").setPrivate(false)).uuid(), + db.components().insertComponent(newPrivateProjectDto(organizationDto).setProjectUuid(uuid1).setPrivate(true)).uuid(), + db.components().insertComponent(newPrivateProjectDto(organizationDto).setProjectUuid(uuid1).setPrivate(false)).uuid(), + db.components().insertComponent(newPrivateProjectDto(organizationDto).setProjectUuid(uuid2).setPrivate(true)).uuid(), + db.components().insertComponent(newPrivateProjectDto(organizationDto).setProjectUuid(uuid2).setPrivate(false)).uuid(), + db.components().insertComponent(newPrivateProjectDto(organizationDto).setRootUuid(uuid1).setProjectUuid("foo").setPrivate(false)).uuid(), }; underTest.setPrivateForRootComponentUuid(db.getSession(), uuid1, true); diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentQueryTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentQueryTest.java index 1b6971c6fc7..d69f98c277f 100644 --- a/server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentQueryTest.java +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentQueryTest.java @@ -57,6 +57,16 @@ public class ComponentQueryTest { assertThat(underTest.getQualifiers()).containsOnly(PROJECT); } + @Test + public void test_getNameOrKeyUpperLikeQuery() throws Exception { + ComponentQuery underTest = ComponentQuery.builder() + .setNameOrKeyQuery("NAME/key") + .setQualifiers(PROJECT) + .build(); + + assertThat(underTest.getNameOrKeyUpperLikeQuery()).isEqualTo("%NAME//KEY%"); + } + @Test public void fail_if_no_qualifier_provided() { expectedException.expect(IllegalArgumentException.class); @@ -66,12 +76,10 @@ public class ComponentQueryTest { } @Test - public void test_getNameOrKeyUpperLikeQuery() throws Exception { - ComponentQuery underTest = ComponentQuery.builder() - .setNameOrKeyQuery("NAME/key") - .setQualifiers(PROJECT) - .build(); + public void fail_if_partial_match_on_key_without_a_query() { + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("A query must be provided if a partial match on key is specified."); - assertThat(underTest.getNameOrKeyUpperLikeQuery()).isEqualTo("%NAME//KEY%"); + ComponentQuery.builder().setQualifiers(PROJECT).setPartialMatchOnKey(false).build(); } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/project/ws/SearchAction.java b/server/sonar-server/src/main/java/org/sonar/server/project/ws/SearchAction.java index 015bf3740b7..562a136c070 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/project/ws/SearchAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/project/ws/SearchAction.java @@ -92,7 +92,7 @@ public class SearchAction implements ProjectsWsAction { action.createParam(Param.TEXT_QUERY) .setDescription("Limit search to:
    " + "
  • component names that contain the supplied string
  • " + - "
  • component keys that are exactly the same as the supplied string
  • " + + "
  • component keys that contain the supplied string
  • " + "
") .setExampleValue("sonar"); @@ -153,9 +153,13 @@ public class SearchAction implements ProjectsWsAction { private static ComponentQuery buildQuery(SearchWsRequest request) { List qualifiers = request.getQualifiers(); ComponentQuery.Builder query = ComponentQuery.builder() - .setNameOrKeyQuery(request.getQuery()) .setQualifiers(qualifiers.toArray(new String[qualifiers.size()])); + setNullable(request.getQuery(), q -> { + query.setNameOrKeyQuery(q); + query.setPartialMatchOnKey(true); + return query; + }); setNullable(request.getVisibility(), v -> query.setPrivate(Visibility.isPrivate(v))); setNullable(request.getAnalyzedBefore(), d -> query.setAnalyzedBefore(parseDateOrDateTime(d).getTime())); diff --git a/server/sonar-server/src/test/java/org/sonar/server/project/ws/SearchActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/project/ws/SearchActionTest.java index 439d4d10f2f..c4fbc6a0bf6 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/project/ws/SearchActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/project/ws/SearchActionTest.java @@ -92,15 +92,16 @@ public class SearchActionTest { new SearchAction(db.getDbClient(), userSession, defaultOrganizationProvider, new ProjectsWsSupport(db.getDbClient(), mock(BillingValidationsProxy.class)))); @Test - public void search_by_key_query() throws IOException { + public void search_by_key_query_with_partial_match_case_insensitive() throws IOException { userSession.addPermission(ADMINISTER, db.getDefaultOrganization()); db.components().insertComponents( ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setDbKey("project-_%-key"), + ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setDbKey("PROJECT-_%-KEY"), ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setDbKey("project-key-without-escaped-characters")); - SearchWsResponse response = call(SearchWsRequest.builder().setQuery("project-_%-key").build()); + SearchWsResponse response = call(SearchWsRequest.builder().setQuery("JeCt-_%-k").build()); - assertThat(response.getComponentsList()).extracting(Component::getKey).containsOnly("project-_%-key"); + assertThat(response.getComponentsList()).extracting(Component::getKey).containsOnly("project-_%-key", "PROJECT-_%-KEY"); } @Test @@ -288,7 +289,7 @@ public class SearchActionTest { assertThat(qParam.description()).isEqualTo("Limit search to: " + "
    " + "
  • component names that contain the supplied string
  • " + - "
  • component keys that are exactly the same as the supplied string
  • " + + "
  • component keys that contain the supplied string
  • " + "
"); WebService.Param qualifierParam = action.param("qualifiers"); diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/server/ws/WebService.java b/sonar-plugin-api/src/main/java/org/sonar/api/server/ws/WebService.java index aaa7b86b910..f200cfe8cf2 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/server/ws/WebService.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/server/ws/WebService.java @@ -19,7 +19,6 @@ */ package org.sonar.api.server.ws; -import com.google.common.base.Joiner; import java.io.IOException; import java.net.URL; import java.nio.charset.StandardCharsets; @@ -428,7 +427,7 @@ public interface WebService extends Definable { *

*/ public NewParam createSearchQuery(String exampleValue, String... pluralFields) { - String actionDescription = format("Limit search to %s that contain the supplied string.", Joiner.on(" or ").join(pluralFields)); + String actionDescription = format("Limit search to %s that contain the supplied string.", String.join(" or ", pluralFields)); return createParam(Param.TEXT_QUERY) .setDescription(actionDescription) diff --git a/tests/src/test/java/org/sonarqube/tests/projectAdministration/ProjectSearchTest.java b/tests/src/test/java/org/sonarqube/tests/projectAdministration/ProjectSearchTest.java index 69178286b3b..c8c80fb374c 100644 --- a/tests/src/test/java/org/sonarqube/tests/projectAdministration/ProjectSearchTest.java +++ b/tests/src/test/java/org/sonarqube/tests/projectAdministration/ProjectSearchTest.java @@ -65,6 +65,28 @@ public class ProjectSearchTest { assertThat(result.getComponentsList()).extracting(SearchWsResponse.Component::getKey).containsExactlyInAnyOrder(oldProject.getKey()); } + @Test + public void search_on_key_partial_match_case_insensitive() { + Organizations.Organization organization = tester.organizations().generate(); + CreateWsResponse.Project lowerCaseProject = tester.projects().generate(organization, p -> p.setKey("project-key")); + CreateWsResponse.Project upperCaseProject = tester.projects().generate(organization, p -> p.setKey("PROJECT-KEY")); + CreateWsResponse.Project anotherProject = tester.projects().generate(organization, p -> p.setKey("another-project")); + + analyzeProject(lowerCaseProject.getKey(), organization.getKey()); + analyzeProject(upperCaseProject.getKey(), organization.getKey()); + analyzeProject(anotherProject.getKey(), organization.getKey()); + + SearchWsResponse result = tester.wsClient().projects().search(SearchWsRequest.builder() + .setOrganization(organization.getKey()) + .setQualifiers(singletonList("TRK")) + .setQuery("JeCt-K") + .build()); + + assertThat(result.getComponentsList()).extracting(SearchWsResponse.Component::getKey) + .containsExactlyInAnyOrder(lowerCaseProject.getKey(), upperCaseProject.getKey()) + .doesNotContain(anotherProject.getKey()); + } + private void analyzeProject(String projectKey, Date analysisDate, String organizationKey) { runProjectAnalysis(orchestrator, "shared/xoo-sample", "sonar.organization", organizationKey, @@ -73,4 +95,8 @@ public class ProjectSearchTest { "sonar.login", "admin", "sonar.password", "admin"); } + + private void analyzeProject(String projectKey, String organizationKey) { + analyzeProject(projectKey, new Date(), organizationKey); + } } -- 2.39.5