diff options
author | Daniel Schwarz <daniel.schwarz@sonarsource.com> | 2017-05-02 11:58:40 +0200 |
---|---|---|
committer | Daniel Schwarz <bartfastiel@users.noreply.github.com> | 2017-05-04 16:35:21 +0200 |
commit | 5a73d8007a26cbdc9859bf2ea58591ff8de14f74 (patch) | |
tree | 36773cf8304b14b4a814050e87729fea08317336 /server/sonar-server | |
parent | 5e1fdd17e3147180e3a4273705835e2fc393ae20 (diff) | |
download | sonarqube-5a73d8007a26cbdc9859bf2ea58591ff8de14f74.tar.gz sonarqube-5a73d8007a26cbdc9859bf2ea58591ff8de14f74.zip |
SONAR-8924 let api/qualityprofiles/search use project’s organization
Diffstat (limited to 'server/sonar-server')
4 files changed, 100 insertions, 113 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/SearchAction.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/SearchAction.java index cf0da1c57d9..51df70a0807 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/SearchAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/SearchAction.java @@ -23,6 +23,7 @@ import com.google.common.annotations.VisibleForTesting; import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import javax.annotation.Nullable; import org.sonar.api.resources.Languages; import org.sonar.api.rule.RuleStatus; import org.sonar.api.server.ws.Request; @@ -31,6 +32,7 @@ import org.sonar.api.server.ws.WebService; import org.sonar.api.server.ws.WebService.NewAction; import org.sonar.db.DbClient; import org.sonar.db.DbSession; +import org.sonar.db.component.ComponentDto; import org.sonar.db.organization.OrganizationDto; import org.sonar.db.qualityprofile.QualityProfileDto; import org.sonar.server.util.LanguageParamUtils; @@ -41,6 +43,7 @@ import org.sonarqube.ws.client.qualityprofile.SearchWsRequest; import static java.lang.String.format; import static java.util.function.Function.identity; import static org.sonar.api.utils.DateUtils.formatDateTime; +import static org.sonar.server.ws.WsUtils.checkFoundWithOptional; import static org.sonar.server.ws.WsUtils.checkRequest; import static org.sonar.server.ws.WsUtils.writeProtobuf; import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.ACTION_SEARCH; @@ -125,16 +128,43 @@ public class SearchAction implements QProfileWsAction { private SearchData load(SearchWsRequest request) { try (DbSession dbSession = dbClient.openSession(false)) { - OrganizationDto organization = wsSupport.getOrganizationByKey(dbSession, request.getOrganizationKey()); + + @Nullable ComponentDto project; + OrganizationDto organization; + if (request.getProjectKey() == null) { + project = null; + organization = wsSupport.getOrganizationByKey(dbSession, request.getOrganizationKey()); + } else { + project = getProject(request.getProjectKey(), dbSession); + organization = dbClient.organizationDao().selectByUuid(dbSession, project.getOrganizationUuid()) + .orElseThrow(() -> new IllegalStateException( + String.format("Organization with uuid '%s' is referenced by project '%s' but could not be found", project.getOrganizationUuid(), project.getKey()))); + if (request.getOrganizationKey() != null && !request.getOrganizationKey().equals(organization.getKey())) { + throw new IllegalArgumentException(String.format("The provided organization key '%s' does not match the organization key '%s' of the component '%s'", + request.getOrganizationKey(), + organization.getKey(), + project.getKey() + )); + } + } + return new SearchData() .setOrganization(organization) - .setProfiles(dataLoader.findProfiles(dbSession, request, organization)) + .setProfiles(dataLoader.findProfiles(dbSession, request, organization, project)) .setActiveRuleCountByProfileKey(dbClient.activeRuleDao().countActiveRulesByProfileKey(dbSession, organization)) .setActiveDeprecatedRuleCountByProfileKey(dbClient.activeRuleDao().countActiveRulesForRuleStatusByProfileKey(dbSession, organization, RuleStatus.DEPRECATED)) .setProjectCountByProfileKey(dbClient.qualityProfileDao().countProjectsByProfileKey(dbSession, organization)); } } + private ComponentDto getProject(String moduleKey, DbSession dbSession) { + ComponentDto module = checkFoundWithOptional(dbClient.componentDao().selectByKey(dbSession, moduleKey), "Component key '%s' not found", moduleKey); + if (module.isRootProject()) { + return module; + } + return dbClient.componentDao().selectOrFailByUuid(dbSession, module.projectUuid()); + } + private static void validateRequest(SearchWsRequest request) { boolean hasLanguage = request.getLanguage() != null; boolean isDefault = request.getDefaults(); diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/SearchDataLoader.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/SearchDataLoader.java index a7e5d9f4423..7cdcc7a9706 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/SearchDataLoader.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/SearchDataLoader.java @@ -37,7 +37,6 @@ import org.sonar.db.DbSession; import org.sonar.db.component.ComponentDto; import org.sonar.db.organization.OrganizationDto; import org.sonar.db.qualityprofile.QualityProfileDto; -import org.sonar.server.component.ComponentFinder; import org.sonar.server.qualityprofile.QProfileLookup; import org.sonarqube.ws.client.qualityprofile.SearchWsRequest; @@ -52,23 +51,20 @@ public class SearchDataLoader { private final Languages languages; private final QProfileLookup profileLookup; private final DbClient dbClient; - private final ComponentFinder componentFinder; - public SearchDataLoader(Languages languages, QProfileLookup profileLookup, DbClient dbClient, - ComponentFinder componentFinder) { + public SearchDataLoader(Languages languages, QProfileLookup profileLookup, DbClient dbClient) { this.languages = languages; this.profileLookup = profileLookup; this.dbClient = dbClient; - this.componentFinder = componentFinder; } @VisibleForTesting - List<QualityProfileDto> findProfiles(DbSession dbSession, SearchWsRequest request, OrganizationDto organization) { + List<QualityProfileDto> findProfiles(DbSession dbSession, SearchWsRequest request, OrganizationDto organization, @Nullable ComponentDto project) { Collection<QualityProfileDto> profiles; if (askDefaultProfiles(request)) { profiles = findDefaultProfiles(dbSession, request, organization); - } else if (hasComponentKey(request)) { - profiles = findProjectProfiles(dbSession, request, organization); + } else if (project != null) { + profiles = findProjectProfiles(dbSession, request, organization, project); } else { profiles = findAllProfiles(dbSession, request, organization); } @@ -92,8 +88,7 @@ public class SearchDataLoader { return qualityProfiles.values(); } - private Collection<QualityProfileDto> findProjectProfiles(DbSession dbSession, SearchWsRequest request, OrganizationDto organization) { - String componentKey = request.getProjectKey(); + private Collection<QualityProfileDto> findProjectProfiles(DbSession dbSession, SearchWsRequest request, OrganizationDto organization, ComponentDto project) { String profileName = request.getProfileName(); Set<String> languageKeys = getLanguageKeys(); @@ -102,12 +97,12 @@ public class SearchDataLoader { // look up profiles by profileName (if any) for each language Set<String> unresolvedLanguages = lookupByProfileName(dbSession, organization, qualityProfiles, languageKeys, profileName); // look up profile by componentKey for each language for which we don't have one yet - Set<String> stillUnresolvedLanguages = lookupByModuleKey(dbSession, organization, qualityProfiles, unresolvedLanguages, componentKey); + Set<String> stillUnresolvedLanguages = lookupByModule(dbSession, organization, qualityProfiles, unresolvedLanguages, project); // look up profile by default for each language for which we don't have one yet Set<String> noDefaultProfileLanguages = lookupDefaults(dbSession, organization, qualityProfiles, stillUnresolvedLanguages); if (!noDefaultProfileLanguages.isEmpty()) { - throw new IllegalStateException(format("No quality profile can been found on language(s) '%s' for project '%s'", noDefaultProfileLanguages, componentKey)); + throw new IllegalStateException(format("No quality profile can been found on language(s) '%s' for project '%s'", noDefaultProfileLanguages, project.getKey())); } return qualityProfiles.values(); @@ -134,26 +129,17 @@ public class SearchDataLoader { return difference(languageKeys, qualityProfiles.keySet()); } - private Set<String> lookupByModuleKey(DbSession dbSession, OrganizationDto organization, Map<String, QualityProfileDto> qualityProfiles, Set<String> languageKeys, - @Nullable String moduleKey) { - if (languageKeys.isEmpty() || moduleKey == null) { + private Set<String> lookupByModule(DbSession dbSession, OrganizationDto organization, Map<String, QualityProfileDto> qualityProfiles, Set<String> languageKeys, + ComponentDto project) { + if (languageKeys.isEmpty()) { return languageKeys; } - ComponentDto project = getProject(moduleKey, dbSession); - dbClient.qualityProfileDao().selectByProjectAndLanguages(dbSession, organization, project.getKey(), languageKeys) + dbClient.qualityProfileDao().selectByProjectAndLanguages(dbSession, organization, project, languageKeys) .forEach(qualityProfile -> qualityProfiles.put(qualityProfile.getLanguage(), qualityProfile)); return difference(languageKeys, qualityProfiles.keySet()); } - private ComponentDto getProject(String moduleKey, DbSession session) { - ComponentDto module = componentFinder.getByKey(session, moduleKey); - if (module.isRootProject()) { - return module; - } - return dbClient.componentDao().selectOrFailByUuid(session, module.projectUuid()); - } - private Set<String> lookupDefaults(DbSession dbSession, OrganizationDto organization, Map<String, QualityProfileDto> qualityProfiles, Set<String> languageKeys) { if (languageKeys.isEmpty()) { return languageKeys; @@ -182,8 +168,4 @@ public class SearchDataLoader { private static boolean askDefaultProfiles(SearchWsRequest request) { return request.getDefaults(); } - - private static boolean hasComponentKey(SearchWsRequest request) { - return request.getProjectKey() != null; - } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/SearchActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/SearchActionTest.java index a4852e837f7..6a8b7b29e21 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/SearchActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/SearchActionTest.java @@ -21,7 +21,6 @@ package org.sonar.server.qualityprofile.ws; import java.util.ArrayList; import java.util.Arrays; -import java.util.Date; import java.util.List; import org.junit.Before; import org.junit.Rule; @@ -44,13 +43,13 @@ import org.sonar.db.qualityprofile.QualityProfileDbTester; import org.sonar.db.qualityprofile.QualityProfileDto; import org.sonar.db.qualityprofile.QualityProfileTesting; import org.sonar.db.rule.RuleDefinitionDto; -import org.sonar.server.component.ComponentFinder; import org.sonar.server.exceptions.BadRequestException; import org.sonar.server.language.LanguageTesting; import org.sonar.server.organization.DefaultOrganizationProvider; import org.sonar.server.organization.TestDefaultOrganizationProvider; import org.sonar.server.qualityprofile.QProfileLookup; import org.sonar.server.tester.UserSessionRule; +import org.sonar.server.ws.TestRequest; import org.sonar.server.ws.WsActionTester; import org.sonarqube.ws.QualityProfiles; import org.sonarqube.ws.QualityProfiles.SearchWsResponse; @@ -58,10 +57,7 @@ import org.sonarqube.ws.QualityProfiles.SearchWsResponse.QualityProfile; import org.sonarqube.ws.client.qualityprofile.SearchWsRequest; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.tuple; -import static org.sonar.api.utils.DateUtils.formatDateTime; import static org.sonar.api.utils.DateUtils.parseDateTime; -import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto; import static org.sonar.db.qualityprofile.QualityProfileTesting.newQualityProfileDto; import static org.sonar.test.JsonAssert.assertJson; import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_DEFAULTS; @@ -77,7 +73,7 @@ public class SearchActionTest { public UserSessionRule userSession = UserSessionRule.standalone(); @Rule public ExpectedException thrown = ExpectedException.none(); - private QualityProfileDbTester qualityProfileDb = new QualityProfileDbTester(db); + private QualityProfileDbTester qualityProfileDb = db.qualityProfiles(); private ComponentDbTester componentDb = new ComponentDbTester(db); private DbClient dbClient = db.getDbClient(); private DbSession dbSession = db.getSession(); @@ -101,8 +97,8 @@ public class SearchActionTest { new SearchDataLoader( languages, new QProfileLookup(dbClient), - dbClient, - new ComponentFinder(dbClient)), + dbClient + ), languages, dbClient, qProfileWsSupport); @@ -240,41 +236,38 @@ public class SearchActionTest { @Test public void search_for_project_qp() { - long time = DateUtils.parseDateTime("2016-12-22T19:10:03+0100").getTime(); - OrganizationDto org = db.getDefaultOrganization(); - QualityProfileDto qualityProfileOnXoo1 = QualityProfileDto.createFor("sonar-way-xoo1-12345") - .setOrganizationUuid(org.getUuid()) - .setLanguage(xoo1.getKey()) - .setRulesUpdatedAt("2016-12-21T19:10:03+0100") - .setLastUsed(time) - .setName("Sonar way"); - QualityProfileDto qualityProfileOnXoo2 = QualityProfileDto.createFor("sonar-way-xoo2-12345") - .setOrganizationUuid(org.getUuid()) - .setLanguage(xoo2.getKey()) - .setRulesUpdatedAt("2016-12-21T19:10:03+0100") - .setLastUsed(time) - .setName("Sonar way"); - QualityProfileDto anotherQualityProfileOnXoo1 = QualityProfileDto.createFor("sonar-way-xoo1-45678") - .setOrganizationUuid(org.getUuid()) - .setLanguage(xoo1.getKey()) - .setRulesUpdatedAt("2016-12-21T19:10:03+0100") - .setLastUsed(time) - .setName("Another way"); - ComponentDto project = newPrivateProjectDto(org, "project-uuid"); - qualityProfileDb.insertQualityProfiles(qualityProfileOnXoo1, qualityProfileOnXoo2, anotherQualityProfileOnXoo1); - qualityProfileDb.insertProjectWithQualityProfileAssociations(project, qualityProfileOnXoo1, qualityProfileOnXoo2); + OrganizationDto org = db.organizations().insert(); + ComponentDto project = db.components().insertPrivateProject(org); + QualityProfileDto qualityProfileOnXoo1 = db.qualityProfiles().insert(org, q -> q.setLanguage(xoo1.getKey())); + db.qualityProfiles().associateProjectWithQualityProfile(project, qualityProfileOnXoo1); + QualityProfileDto qualityProfileOnXoo2 = db.qualityProfiles().insert(org, q -> q.setLanguage(xoo2.getKey()).setDefault(true)); + db.qualityProfiles().associateProjectWithQualityProfile(project, qualityProfileOnXoo2); + db.qualityProfiles().insert(org, q -> q.setLanguage(xoo1.getKey()).setDefault(true)); - SearchWsResponse result = ws.newRequest().setParam(PARAM_PROJECT_KEY, project.key()) + SearchWsResponse result = ws.newRequest() + .setParam(PARAM_PROJECT_KEY, project.key()) .executeProtobuf(SearchWsResponse.class); assertThat(result.getProfilesList()) - .hasSize(2) .extracting(QualityProfile::getKey) - .contains("sonar-way-xoo1-12345", "sonar-way-xoo2-12345") - .doesNotContain("sonar-way-xoo1-45678"); - assertThat(result.getProfilesList()) - .extracting(QualityProfile::getRulesUpdatedAt, QualityProfile::getLastUsed) - .contains(tuple("2016-12-21T19:10:03+0100", formatDateTime(time))); + .containsExactlyInAnyOrder(qualityProfileOnXoo1.getKey(), qualityProfileOnXoo2.getKey()); + } + + @Test + public void search_for_project_qp_with_wrong_organization() { + OrganizationDto org1 = db.organizations().insert(); + OrganizationDto org2 = db.organizations().insert(); + ComponentDto project = db.components().insertPrivateProject(org1); + + TestRequest request = ws.newRequest() + .setParam(PARAM_PROJECT_KEY, project.key()) + .setParam(PARAM_ORGANIZATION, org2.getKey()); + + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage( + "The provided organization key '" + org2.getKey() + "' does not match the organization key '" + org1.getKey() + "' of the component '" + project.getKey() + "'"); + + request.execute(); } @Test @@ -310,35 +303,21 @@ public class SearchActionTest { @Test public void search_by_profile_name() { OrganizationDto org = db.organizations().insert(); - QualityProfileDto qualityProfileOnXoo1 = QualityProfileDto.createFor("sonar-way-xoo1-12345") - .setOrganizationUuid(org.getUuid()) - .setLanguage(xoo1.getKey()) - .setRulesUpdatedAtAsDate(new Date()) - .setName("Sonar way"); - QualityProfileDto qualityProfileOnXoo2 = QualityProfileDto.createFor("sonar-way-xoo2-12345") - .setOrganizationUuid(org.getUuid()) - .setLanguage(xoo2.getKey()) - .setRulesUpdatedAtAsDate(new Date()) - .setName("Sonar way") - .setDefault(true); - QualityProfileDto anotherQualityProfileOnXoo1 = QualityProfileDto.createFor("sonar-way-xoo1-45678") - .setOrganizationUuid(org.getUuid()) - .setLanguage(xoo1.getKey()) - .setRulesUpdatedAtAsDate(new Date()) - .setName("Another way") - .setDefault(true); - qualityProfileDb.insertQualityProfiles(qualityProfileOnXoo1, qualityProfileOnXoo2, anotherQualityProfileOnXoo1); - ComponentDto project = componentDb.insertComponent(newPrivateProjectDto(org, "project-uuid")); + QualityProfileDto qualityProfileOnXoo1 = db.qualityProfiles().insert(org, q -> q.setLanguage(xoo1.getKey()).setName("Sonar way")); + QualityProfileDto qualityProfileOnXoo2 = db.qualityProfiles().insert(org, q -> q.setLanguage(xoo2.getKey()).setName("Sonar way").setDefault(true)); + QualityProfileDto anotherQualityProfileOnXoo1 = db.qualityProfiles().insert(org, q -> q.setLanguage(xoo1.getKey()).setName("Another way").setDefault(true)); + ComponentDto project = componentDb.insertPrivateProject(org); - String result = ws.newRequest() + SearchWsResponse result = ws.newRequest() .setParam(PARAM_ORGANIZATION, org.getKey()) .setParam(PARAM_PROJECT_KEY, project.key()) .setParam(PARAM_PROFILE_NAME, "Sonar way") - .execute().getInput(); + .executeProtobuf(SearchWsResponse.class); - assertThat(result) - .contains("sonar-way-xoo1-12345", "sonar-way-xoo2-12345") - .doesNotContain("sonar-way-xoo1-45678"); + assertThat(result.getProfilesList()) + .extracting(QualityProfile::getKey) + .contains(qualityProfileOnXoo1.getKey(), qualityProfileOnXoo2.getKey()) + .doesNotContain(anotherQualityProfileOnXoo1.getKey()); } @Test diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/SearchDataLoaderTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/SearchDataLoaderTest.java index 614e7284b63..582e62ca153 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/SearchDataLoaderTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/SearchDataLoaderTest.java @@ -22,6 +22,7 @@ package org.sonar.server.qualityprofile.ws; import java.util.Arrays; import java.util.List; import java.util.function.Consumer; +import javax.annotation.Nullable; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -38,7 +39,6 @@ import org.sonar.db.qualityprofile.QualityProfileDto; import org.sonar.db.qualityprofile.QualityProfileTesting; import org.sonar.server.component.ComponentFinder; import org.sonar.server.language.LanguageTesting; -import org.sonar.server.organization.TestDefaultOrganizationProvider; import org.sonar.server.qualityprofile.QProfileLookup; import org.sonarqube.ws.client.qualityprofile.SearchWsRequest; @@ -60,7 +60,6 @@ public class SearchDataLoaderTest { private Languages languages; private QProfileLookup profileLookup; private ComponentFinder componentFinder; - private QProfileWsSupport qProfileWsSupport; private OrganizationDto organization; @Before @@ -69,16 +68,14 @@ public class SearchDataLoaderTest { languages = new Languages(); DbClient dbClient = dbTester.getDbClient(); profileLookup = new QProfileLookup(dbClient); - TestDefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(dbTester); - qProfileWsSupport = new QProfileWsSupport(dbClient, null, defaultOrganizationProvider); componentFinder = mock(ComponentFinder.class); } @Test public void find_no_profiles_if_database_is_empty() throws Exception { assertThat(findProfiles( - new SearchWsRequest() - )).isEmpty(); + new SearchWsRequest(), + null)).isEmpty(); } @Test @@ -86,8 +83,8 @@ public class SearchDataLoaderTest { insertQualityProfile(organization); assertThat(findProfiles( new SearchWsRequest() - .setOrganizationKey(organization.getKey()) - )).hasSize(1); + .setOrganizationKey(organization.getKey()), + null)).hasSize(1); } @Test @@ -96,8 +93,8 @@ public class SearchDataLoaderTest { assertThat(findProfiles( new SearchWsRequest() .setOrganizationKey(organization.getKey()) - .setDefaults(true) - )).hasSize(1); + .setDefaults(true), + null)).hasSize(1); } @Test @@ -106,9 +103,8 @@ public class SearchDataLoaderTest { ComponentDto project1 = insertProject(); assertThat(findProfiles( new SearchWsRequest() - .setOrganizationKey(organization.getKey()) - .setProjectKey(project1.getKey()) - )).hasSize(1); + .setOrganizationKey(organization.getKey()), + project1)).hasSize(1); } @Test @@ -117,18 +113,18 @@ public class SearchDataLoaderTest { assertThat(findProfiles( new SearchWsRequest() .setOrganizationKey(organization.getKey()) - .setLanguage(qualityProfile.getLanguage()) - )).hasSize(1); + .setLanguage(qualityProfile.getLanguage()), + null)).hasSize(1); assertThat(findProfiles( new SearchWsRequest() .setOrganizationKey(organization.getKey()) - .setLanguage("other language") - )).hasSize(0); + .setLanguage("other language"), + null)).hasSize(0); } - private List<QualityProfileDto> findProfiles(SearchWsRequest request) { - return new SearchDataLoader(languages, profileLookup, dbTester.getDbClient(), componentFinder) - .findProfiles(dbTester.getSession(), request, organization); + private List<QualityProfileDto> findProfiles(SearchWsRequest request, @Nullable ComponentDto project) { + return new SearchDataLoader(languages, profileLookup, dbTester.getDbClient()) + .findProfiles(dbTester.getSession(), request, organization, project); } private QualityProfileDto insertQualityProfile(OrganizationDto organization, Consumer<QualityProfileDto>... specials) { |