From a16387722ae93b0130e48da9e9811e9c635a1181 Mon Sep 17 00:00:00 2001 From: Daniel Schwarz Date: Wed, 15 Mar 2017 11:40:04 +0100 Subject: [PATCH] SONAR-8857 make ws/api/qualityprofiles/search support organizations --- .../org/sonar/db/version/rows-h2.sql | 2 + .../org/sonar/db/version/schema-h2.ddl | 2 +- .../db/qualityprofile/QualityProfileDao.java | 12 +- .../qualityprofile/QualityProfileMapper.java | 7 +- .../qualityprofile/QualityProfileMapper.xml | 22 +-- .../qualityprofile/QualityProfileDaoTest.java | 38 ++-- .../QualityProfileDaoTest/delete-result.xml | 2 +- .../QualityProfileDaoTest/insert-result.xml | 6 +- .../QualityProfileDaoTest/projects.xml | 4 +- .../select_all_is_sorted_by_profile_name.xml | 6 +- .../QualityProfileDaoTest/shared.xml | 4 +- .../QualityProfileDaoTest/update-result.xml | 4 +- .../db/migration/version/v64/DbVersion64.java | 7 +- ...nQualityProfileOrganizationUuidAndKey.java | 42 +++++ .../v64/MakeQualityProfileKeyUnique.java | 51 ++++++ .../version/v64/DbVersion64Test.java | 2 +- ...opUniqueIndexOnQualityProfileKeyTest.java} | 4 +- ...lityProfileOrganizationUuidAndKeyTest.java | 40 ++++ .../v64/MakeQualityProfileKeyUniqueTest.java | 40 ++++ ...fileOrganizationUuidAndKeyUniqueTest.java} | 4 +- .../initial.sql | 0 .../initial.sql | 15 ++ .../initial.sql | 0 .../initial.sql | 14 ++ .../sonar/server/qualityprofile/QProfile.java | 14 +- .../qualityprofile/QProfileFactory.java | 12 +- .../server/qualityprofile/QProfileLoader.java | 14 +- .../server/qualityprofile/QProfileLookup.java | 38 ++-- .../qualityprofile/ws/QProfileWsSupport.java | 2 +- .../qualityprofile/ws/SearchAction.java | 11 +- .../qualityprofile/ws/SearchDataLoader.java | 107 +++++------ .../org/sonar/server/rule/ws/AppAction.java | 9 +- .../QProfileBackuperMediumTest.java | 3 +- .../QProfileFactoryMediumTest.java | 27 ++- .../QProfileServiceMediumTest.java | 5 +- .../server/qualityprofile/QProfileTest.java | 6 - .../RegisterQualityProfilesMediumTest.java | 23 ++- .../ws/InheritanceActionMediumTest.java | 11 +- .../qualityprofile/ws/QProfilesWsTest.java | 3 +- .../qualityprofile/ws/SearchActionTest.java | 73 +++++++- .../ws/SearchDataLoaderTest.java | 97 ++++++++++ .../ws/SearchDataLoaderTest2.java | 171 ++++++++++++++++++ .../sonar/server/rule/ws/AppActionTest.java | 4 +- .../qualityprofile/SearchWsRequest.java | 10 + 44 files changed, 772 insertions(+), 196 deletions(-) create mode 100644 server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v64/DropUniqueIndexOnQualityProfileOrganizationUuidAndKey.java create mode 100644 server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v64/MakeQualityProfileKeyUnique.java rename server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v64/{LetQualityProfileKeyNotBeUniqueAnymoreTest.java => DropUniqueIndexOnQualityProfileKeyTest.java} (87%) create mode 100644 server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v64/DropUniqueIndexOnQualityProfileOrganizationUuidAndKeyTest.java create mode 100644 server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v64/MakeQualityProfileKeyUniqueTest.java rename server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v64/{LetQualityProfileOrganizationUuidAndKeyBeUniqueTest.java => MakeQualityProfileOrganizationUuidAndKeyUniqueTest.java} (87%) rename server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v64/{LetQualityProfileKeyNotBeUniqueAnymoreTest => DropUniqueIndexOnQualityProfileKeyTest}/initial.sql (100%) create mode 100644 server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v64/DropUniqueIndexOnQualityProfileOrganizationUuidAndKeyTest/initial.sql rename server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v64/{LetQualityProfileOrganizationUuidAndKeyBeUniqueTest => MakeQualityProfileKeyUniqueTest}/initial.sql (100%) create mode 100644 server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v64/MakeQualityProfileOrganizationUuidAndKeyUniqueTest/initial.sql create mode 100644 server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/SearchDataLoaderTest.java create mode 100644 server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/SearchDataLoaderTest2.java diff --git a/server/sonar-db-core/src/main/resources/org/sonar/db/version/rows-h2.sql b/server/sonar-db-core/src/main/resources/org/sonar/db/version/rows-h2.sql index fb328ec1e1b..51b6f812af3 100644 --- a/server/sonar-db-core/src/main/resources/org/sonar/db/version/rows-h2.sql +++ b/server/sonar-db-core/src/main/resources/org/sonar/db/version/rows-h2.sql @@ -541,6 +541,8 @@ INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1605'); INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1606'); INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1607'); INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1608'); +INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1609'); +INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1610'); INSERT INTO USERS(ID, LOGIN, NAME, EMAIL, EXTERNAL_IDENTITY, EXTERNAL_IDENTITY_PROVIDER, USER_LOCAL, CRYPTED_PASSWORD, SALT, IS_ROOT, CREATED_AT, UPDATED_AT) VALUES (1, 'admin', 'Administrator', '', 'admin', 'sonarqube', true, 'a373a0e667abb2604c1fd571eb4ad47fe8cc0878', '48bc4b0d93179b5103fd3885ea9119498e9d161b', false, '1418215735482', '1418215735482'); ALTER TABLE USERS ALTER COLUMN ID RESTART WITH 2; diff --git a/server/sonar-db-core/src/main/resources/org/sonar/db/version/schema-h2.ddl b/server/sonar-db-core/src/main/resources/org/sonar/db/version/schema-h2.ddl index f08ac56173f..028846ad102 100644 --- a/server/sonar-db-core/src/main/resources/org/sonar/db/version/schema-h2.ddl +++ b/server/sonar-db-core/src/main/resources/org/sonar/db/version/schema-h2.ddl @@ -55,7 +55,7 @@ CREATE TABLE "RULES_PROFILES" ( "LAST_USED" BIGINT, "USER_UPDATED_AT" BIGINT ); -CREATE UNIQUE INDEX "UNIQ_QPROF_ORG_AND_KEY" ON "RULES_PROFILES" ("ORGANIZATION_UUID", "KEE"); +CREATE UNIQUE INDEX "UNIQ_QPROF_KEY" ON "RULES_PROFILES" ("KEE"); CREATE TABLE "PROJECT_QPROFILES" ( diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QualityProfileDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QualityProfileDao.java index f39c32e0607..43ad30d7a29 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QualityProfileDao.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QualityProfileDao.java @@ -63,8 +63,8 @@ public class QualityProfileDao implements Dao { return executeLargeInputs(keys, mapper(session)::selectByKeys); } - public List selectAll(DbSession session) { - return mapper(session).selectAll(); + public List selectAll(DbSession session, OrganizationDto organization) { + return mapper(session).selectAll(organization.getUuid()); } public void insert(DbSession session, QualityProfileDto profile, QualityProfileDto... otherProfiles) { @@ -102,8 +102,8 @@ public class QualityProfileDao implements Dao { mapper.delete(profileId); } - public List selectDefaultProfiles(DbSession session, Collection languageKeys) { - return executeLargeInputs(languageKeys, mapper(session)::selectDefaultProfiles); + public List selectDefaultProfiles(DbSession session, OrganizationDto organization, Collection languageKeys) { + return executeLargeInputs(languageKeys, chunk -> mapper(session).selectDefaultProfiles(organization.getUuid(), chunk)); } @CheckForNull @@ -116,8 +116,8 @@ public class QualityProfileDao implements Dao { return mapper(session).selectByProjectAndLanguage(projectKey, language); } - public List selectByProjectAndLanguages(DbSession session, String projectKey, Collection languageKeys) { - return executeLargeInputs(languageKeys, input -> mapper(session).selectByProjectAndLanguages(projectKey, input)); + public List selectByProjectAndLanguages(DbSession session, OrganizationDto organization, String projectKey, Collection languageKeys) { + return executeLargeInputs(languageKeys, input -> mapper(session).selectByProjectAndLanguages(organization.getUuid(), projectKey, input)); } public List selectByLanguage(DbSession dbSession, String language) { diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QualityProfileMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QualityProfileMapper.java index 8d25631c339..337f87bc39d 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QualityProfileMapper.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QualityProfileMapper.java @@ -32,12 +32,12 @@ public interface QualityProfileMapper { void delete(int id); - List selectAll(); + List selectAll(@Param("organizationUuid") String organizationUuid); @CheckForNull QualityProfileDto selectDefaultProfile(@Param("language") String language); - List selectDefaultProfiles(@Param("languages") List languages); + List selectDefaultProfiles(@Param("organizationUuid") String organizationUuid, @Param("languages") List languages); @CheckForNull QualityProfileDto selectByNameAndLanguage(@Param("organizationUuid") String organizationUuid, @Param("name") String name, @Param("language") String language); @@ -71,7 +71,8 @@ public interface QualityProfileMapper { QualityProfileDto selectByProjectAndLanguage(@Param("projectKey") String projectKey, @Param("language") String language); - List selectByProjectAndLanguages(@Param("projectKey") String projectKey, @Param("languages") List input); + List selectByProjectAndLanguages(@Param("organizationUuid") String organizationUuid, @Param("projectKey") String projectKey, + @Param("languages") List input); void insertProjectProfileAssociation(@Param("projectUuid") String projectUuid, @Param("profileKey") String profileKey); diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/qualityprofile/QualityProfileMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/qualityprofile/QualityProfileMapper.xml index b94b3dd74a3..3c18327b9dc 100644 --- a/server/sonar-db-dao/src/main/resources/org/sonar/db/qualityprofile/QualityProfileMapper.xml +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/qualityprofile/QualityProfileMapper.xml @@ -55,6 +55,7 @@ SELECT FROM rules_profiles p + WHERE p.organization_uuid = #{organizationUuid,jdbcType=VARCHAR} ORDER BY p.name, p.language @@ -141,13 +142,9 @@ SELECT FROM rules_profiles p - - p.is_default=${_true} - AND p.language in - - #{language} - - + WHERE p.is_default=${_true} + AND p.language in #{language, jdbcType=VARCHAR} + AND p.organization_uuid = #{organizationUuid, jdbcType=VARCHAR} diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/qualityprofile/QualityProfileDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/qualityprofile/QualityProfileDaoTest.java index 469a25429ca..a53823ef76b 100644 --- a/server/sonar-db-dao/src/test/java/org/sonar/db/qualityprofile/QualityProfileDaoTest.java +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/qualityprofile/QualityProfileDaoTest.java @@ -52,11 +52,12 @@ public class QualityProfileDaoTest { private DbSession dbSession = dbTester.getSession(); private QualityProfileDbTester qualityProfileDb = new QualityProfileDbTester(dbTester); private QualityProfileDao underTest = dbTester.getDbClient().qualityProfileDao(); - private OrganizationDto organization = OrganizationTesting.newOrganizationDto(); + private OrganizationDto organization; @Before public void before() { when(system.now()).thenReturn(UtcDateUtils.parseDateTime("2014-01-20T12:00:00+0000").getTime()); + organization = dbTester.organizations().insertForUuid("QualityProfileDaoTest-ORG"); } @Test @@ -64,7 +65,7 @@ public class QualityProfileDaoTest { dbTester.prepareDbUnit(getClass(), "shared.xml"); QualityProfileDto dto = QualityProfileDto.createFor("abcde") - .setOrganizationUuid("org-123") + .setOrganizationUuid(organization.getUuid()) .setName("ABCDE") .setLanguage("xoo"); @@ -106,7 +107,7 @@ public class QualityProfileDaoTest { public void find_all() { dbTester.prepareDbUnit(getClass(), "shared.xml"); - List dtos = underTest.selectAll(dbTester.getSession()); + List dtos = underTest.selectAll(dbTester.getSession(), organization); assertThat(dtos).hasSize(2); @@ -127,7 +128,7 @@ public class QualityProfileDaoTest { public void find_all_is_sorted_by_profile_name() { dbTester.prepareDbUnit(getClass(), "select_all_is_sorted_by_profile_name.xml"); - List dtos = underTest.selectAll(dbTester.getSession()); + List dtos = underTest.selectAll(dbTester.getSession(), organization); assertThat(dtos).hasSize(3); assertThat(dtos.get(0).getName()).isEqualTo("First"); @@ -150,33 +151,33 @@ public class QualityProfileDaoTest { public void get_default_profiles() { dbTester.prepareDbUnit(getClass(), "shared.xml"); - List java = underTest.selectDefaultProfiles(dbTester.getSession(), singletonList("java")); + List java = underTest.selectDefaultProfiles(dbTester.getSession(), organization, singletonList("java")); assertThat(java).extracting("key").containsOnly("java_sonar_way"); - assertThat(underTest.selectDefaultProfiles(dbTester.getSession(), singletonList("js"))).isEmpty(); - assertThat(underTest.selectDefaultProfiles(dbTester.getSession(), of("java", "js"))).extracting("key").containsOnly("java_sonar_way"); - assertThat(underTest.selectDefaultProfiles(dbTester.getSession(), of("js", "java"))).extracting("key").containsOnly("java_sonar_way"); + assertThat(underTest.selectDefaultProfiles(dbTester.getSession(), organization, singletonList("js"))).isEmpty(); + assertThat(underTest.selectDefaultProfiles(dbTester.getSession(), organization, of("java", "js"))).extracting("key").containsOnly("java_sonar_way"); + assertThat(underTest.selectDefaultProfiles(dbTester.getSession(), organization, of("js", "java"))).extracting("key").containsOnly("java_sonar_way"); } @Test public void get_by_name_and_language() { dbTester.prepareDbUnit(getClass(), "shared.xml"); - QualityProfileDto dto = underTest.selectByNameAndLanguage("Sonar Way", "java", dbTester.getSession()); + QualityProfileDto dto = underTest.selectByNameAndLanguage(organization, "Sonar Way", "java", dbTester.getSession()); assertThat(dto.getId()).isEqualTo(1); assertThat(dto.getName()).isEqualTo("Sonar Way"); assertThat(dto.getLanguage()).isEqualTo("java"); assertThat(dto.getParentKee()).isNull(); - assertThat(underTest.selectByNameAndLanguage("Sonar Way", "java", dbTester.getSession())).isNotNull(); - assertThat(underTest.selectByNameAndLanguage("Sonar Way", "unknown", dbTester.getSession())).isNull(); + assertThat(underTest.selectByNameAndLanguage(organization, "Sonar Way", "java", dbTester.getSession())).isNotNull(); + assertThat(underTest.selectByNameAndLanguage(organization, "Sonar Way", "unknown", dbTester.getSession())).isNull(); } @Test public void get_by_name_and_languages() { dbTester.prepareDbUnit(getClass(), "shared.xml"); - List dtos = underTest.selectByNameAndLanguages("Sonar Way", singletonList("java"), dbTester.getSession()); + List dtos = underTest.selectByNameAndLanguages(organization, "Sonar Way", singletonList("java"), dbTester.getSession()); assertThat(dtos).hasSize(1); QualityProfileDto dto = dtos.iterator().next(); assertThat(dto.getId()).isEqualTo(1); @@ -184,8 +185,8 @@ public class QualityProfileDaoTest { assertThat(dto.getLanguage()).isEqualTo("java"); assertThat(dto.getParentKee()).isNull(); - assertThat(underTest.selectByNameAndLanguages("Sonar Way", singletonList("unknown"), dbTester.getSession())).isEmpty(); - assertThat(underTest.selectByNameAndLanguages("Sonar Way", of("java", "unknown"), dbTester.getSession())).extracting("id").containsOnly(1); + assertThat(underTest.selectByNameAndLanguages(organization, "Sonar Way", singletonList("unknown"), dbTester.getSession())).isEmpty(); + assertThat(underTest.selectByNameAndLanguages(organization, "Sonar Way", of("java", "unknown"), dbTester.getSession())).extracting("id").containsOnly(1); } @Test @@ -271,12 +272,13 @@ public class QualityProfileDaoTest { public void select_by_project_key_and_languages() { dbTester.prepareDbUnit(getClass(), "projects.xml"); - List dto = underTest.selectByProjectAndLanguages(dbTester.getSession(), "org.codehaus.sonar:sonar", singletonList("java")); + OrganizationDto organization = dbTester.organizations().insert(OrganizationTesting.newOrganizationDto().setUuid("org1")); + List dto = underTest.selectByProjectAndLanguages(dbTester.getSession(), organization, "org.codehaus.sonar:sonar", singletonList("java")); assertThat(dto).extracting("id").containsOnly(1); - assertThat(underTest.selectByProjectAndLanguages(dbTester.getSession(), "org.codehaus.sonar:sonar", singletonList("unkown"))).isEmpty(); - assertThat(underTest.selectByProjectAndLanguages(dbTester.getSession(), "org.codehaus.sonar:sonar", of("java", "unkown"))).extracting("id").containsOnly(1); - assertThat(underTest.selectByProjectAndLanguages(dbTester.getSession(), "unknown", singletonList("java"))).isEmpty(); + assertThat(underTest.selectByProjectAndLanguages(dbTester.getSession(), organization, "org.codehaus.sonar:sonar", singletonList("unkown"))).isEmpty(); + assertThat(underTest.selectByProjectAndLanguages(dbTester.getSession(), organization, "org.codehaus.sonar:sonar", of("java", "unkown"))).extracting("id").containsOnly(1); + assertThat(underTest.selectByProjectAndLanguages(dbTester.getSession(), organization, "unknown", singletonList("java"))).isEmpty(); } @Test diff --git a/server/sonar-db-dao/src/test/resources/org/sonar/db/qualityprofile/QualityProfileDaoTest/delete-result.xml b/server/sonar-db-dao/src/test/resources/org/sonar/db/qualityprofile/QualityProfileDaoTest/delete-result.xml index b73e8d78720..8bb9ecfc7cf 100644 --- a/server/sonar-db-dao/src/test/resources/org/sonar/db/qualityprofile/QualityProfileDaoTest/delete-result.xml +++ b/server/sonar-db-dao/src/test/resources/org/sonar/db/qualityprofile/QualityProfileDaoTest/delete-result.xml @@ -1,6 +1,6 @@ - diff --git a/server/sonar-db-dao/src/test/resources/org/sonar/db/qualityprofile/QualityProfileDaoTest/insert-result.xml b/server/sonar-db-dao/src/test/resources/org/sonar/db/qualityprofile/QualityProfileDaoTest/insert-result.xml index fda182db3af..52dd12b3d7e 100644 --- a/server/sonar-db-dao/src/test/resources/org/sonar/db/qualityprofile/QualityProfileDaoTest/insert-result.xml +++ b/server/sonar-db-dao/src/test/resources/org/sonar/db/qualityprofile/QualityProfileDaoTest/insert-result.xml @@ -1,12 +1,12 @@ - - - diff --git a/server/sonar-db-dao/src/test/resources/org/sonar/db/qualityprofile/QualityProfileDaoTest/projects.xml b/server/sonar-db-dao/src/test/resources/org/sonar/db/qualityprofile/QualityProfileDaoTest/projects.xml index e34f6ff42f9..4cdb013dfc9 100644 --- a/server/sonar-db-dao/src/test/resources/org/sonar/db/qualityprofile/QualityProfileDaoTest/projects.xml +++ b/server/sonar-db-dao/src/test/resources/org/sonar/db/qualityprofile/QualityProfileDaoTest/projects.xml @@ -3,7 +3,7 @@ - - - diff --git a/server/sonar-db-dao/src/test/resources/org/sonar/db/qualityprofile/QualityProfileDaoTest/shared.xml b/server/sonar-db-dao/src/test/resources/org/sonar/db/qualityprofile/QualityProfileDaoTest/shared.xml index 2e457f02990..bc987b85bf6 100644 --- a/server/sonar-db-dao/src/test/resources/org/sonar/db/qualityprofile/QualityProfileDaoTest/shared.xml +++ b/server/sonar-db-dao/src/test/resources/org/sonar/db/qualityprofile/QualityProfileDaoTest/shared.xml @@ -1,9 +1,9 @@ - - diff --git a/server/sonar-db-dao/src/test/resources/org/sonar/db/qualityprofile/QualityProfileDaoTest/update-result.xml b/server/sonar-db-dao/src/test/resources/org/sonar/db/qualityprofile/QualityProfileDaoTest/update-result.xml index 61606c037c0..c4e08677fcf 100644 --- a/server/sonar-db-dao/src/test/resources/org/sonar/db/qualityprofile/QualityProfileDaoTest/update-result.xml +++ b/server/sonar-db-dao/src/test/resources/org/sonar/db/qualityprofile/QualityProfileDaoTest/update-result.xml @@ -1,8 +1,8 @@ - - diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v64/DbVersion64.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v64/DbVersion64.java index 90693d1b7e6..1b2722f7cf3 100644 --- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v64/DbVersion64.java +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v64/DbVersion64.java @@ -33,9 +33,14 @@ public class DbVersion64 implements DbVersion { .add(1602, "Add RULES_PROFILES.ORGANIZATION_UUID", AddQualityProfileOrganizationUuid.class) .add(1603, "Set RULES_PROFILES.ORGANIZATION_UUID to default", SetQualityProfileOrganizationUuidToDefault.class) .add(1604, "Make RULES_PROFILES.ORGANIZATION_UUID not nullable", MakeQualityProfileOrganizationUuidNotNullable.class) + .add(1605, "Drop unique index on RULES_PROFILES.KEE", DropUniqueIndexOnQualityProfileKey.class) .add(1606, "Make RULES_PROFILES.ORGANIZATION_UUID and KEE unique", MakeQualityProfileOrganizationUuidAndKeyUnique.class) + .add(1607, "Create ORGANIZATION_MEMBERS table", CreateOrganizationMembersTable.class) - .add(1608, "Populate ORGANIZATION_MEMBERS table", PopulateOrganizationMembersTable.class); + .add(1608, "Populate ORGANIZATION_MEMBERS table", PopulateOrganizationMembersTable.class) + + .add(1609, "Drop unique index on RULES_PROFILES.ORGANIZATION_UUID and KEE", DropUniqueIndexOnQualityProfileOrganizationUuidAndKey.class) + .add(1610, "Make RULES_PROFILES.KEE unique", MakeQualityProfileKeyUnique.class); } } diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v64/DropUniqueIndexOnQualityProfileOrganizationUuidAndKey.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v64/DropUniqueIndexOnQualityProfileOrganizationUuidAndKey.java new file mode 100644 index 00000000000..807d2530882 --- /dev/null +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v64/DropUniqueIndexOnQualityProfileOrganizationUuidAndKey.java @@ -0,0 +1,42 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.platform.db.migration.version.v64; + +import org.sonar.db.Database; +import org.sonar.server.platform.db.migration.sql.DropIndexBuilder; +import org.sonar.server.platform.db.migration.step.DdlChange; + +import java.sql.SQLException; + +public class DropUniqueIndexOnQualityProfileOrganizationUuidAndKey extends DdlChange { + + public DropUniqueIndexOnQualityProfileOrganizationUuidAndKey(Database db) { + super(db); + } + + @Override + public void execute(DdlChange.Context context) throws SQLException { + context.execute( + new DropIndexBuilder(getDialect()) + .setTable("rules_profiles") + .setName("uniq_qprof_org_and_key") + .build()); + } +} diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v64/MakeQualityProfileKeyUnique.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v64/MakeQualityProfileKeyUnique.java new file mode 100644 index 00000000000..e689395fcd0 --- /dev/null +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v64/MakeQualityProfileKeyUnique.java @@ -0,0 +1,51 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.platform.db.migration.version.v64; + +import org.sonar.db.Database; +import org.sonar.server.platform.db.migration.sql.CreateIndexBuilder; +import org.sonar.server.platform.db.migration.step.DdlChange; + +import java.sql.SQLException; + +import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.UUID_SIZE; +import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.newVarcharColumnDefBuilder; + +public class MakeQualityProfileKeyUnique extends DdlChange { + + public MakeQualityProfileKeyUnique(Database db) { + super(db); + } + + @Override + public void execute(DdlChange.Context context) throws SQLException { + context.execute( + new CreateIndexBuilder(getDialect()) + .setTable("rules_profiles") + .setName("uniq_qprof_key") + .addColumn( + newVarcharColumnDefBuilder() + .setColumnName("kee") + .setLimit(255) + .build()) + .setUnique(true) + .build()); + } +} diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v64/DbVersion64Test.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v64/DbVersion64Test.java index 9dcd8b2800d..290a9bb221b 100644 --- a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v64/DbVersion64Test.java +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v64/DbVersion64Test.java @@ -35,7 +35,7 @@ public class DbVersion64Test { @Test public void verify_migration_count() { - verifyMigrationCount(underTest, 9); + verifyMigrationCount(underTest, 11); } } diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v64/LetQualityProfileKeyNotBeUniqueAnymoreTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v64/DropUniqueIndexOnQualityProfileKeyTest.java similarity index 87% rename from server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v64/LetQualityProfileKeyNotBeUniqueAnymoreTest.java rename to server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v64/DropUniqueIndexOnQualityProfileKeyTest.java index 9005567031f..0f2c19a71a9 100644 --- a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v64/LetQualityProfileKeyNotBeUniqueAnymoreTest.java +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v64/DropUniqueIndexOnQualityProfileKeyTest.java @@ -24,10 +24,10 @@ import org.junit.Rule; import org.junit.Test; import org.sonar.db.CoreDbTester; -public class LetQualityProfileKeyNotBeUniqueAnymoreTest { +public class DropUniqueIndexOnQualityProfileKeyTest { @Rule - public CoreDbTester db = CoreDbTester.createForSchema(LetQualityProfileKeyNotBeUniqueAnymoreTest.class, "initial.sql"); + public CoreDbTester db = CoreDbTester.createForSchema(DropUniqueIndexOnQualityProfileKeyTest.class, "initial.sql"); public DropUniqueIndexOnQualityProfileKey underTest = new DropUniqueIndexOnQualityProfileKey(db.database()); diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v64/DropUniqueIndexOnQualityProfileOrganizationUuidAndKeyTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v64/DropUniqueIndexOnQualityProfileOrganizationUuidAndKeyTest.java new file mode 100644 index 00000000000..f6582a21d90 --- /dev/null +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v64/DropUniqueIndexOnQualityProfileOrganizationUuidAndKeyTest.java @@ -0,0 +1,40 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.platform.db.migration.version.v64; + +import org.junit.Rule; +import org.junit.Test; +import org.sonar.db.CoreDbTester; + +import java.sql.SQLException; + +public class DropUniqueIndexOnQualityProfileOrganizationUuidAndKeyTest { + + @Rule + public CoreDbTester db = CoreDbTester.createForSchema(DropUniqueIndexOnQualityProfileOrganizationUuidAndKeyTest.class, "initial.sql"); + + public DropUniqueIndexOnQualityProfileOrganizationUuidAndKey underTest = new DropUniqueIndexOnQualityProfileOrganizationUuidAndKey(db.database()); + + @Test + public void test() throws SQLException { + underTest.execute(); + db.assertIndexDoesNotExist("rules_profiles", "uniq_qprof_org_and_key"); + } +} diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v64/MakeQualityProfileKeyUniqueTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v64/MakeQualityProfileKeyUniqueTest.java new file mode 100644 index 00000000000..dea39dca32f --- /dev/null +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v64/MakeQualityProfileKeyUniqueTest.java @@ -0,0 +1,40 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.platform.db.migration.version.v64; + +import org.junit.Rule; +import org.junit.Test; +import org.sonar.db.CoreDbTester; + +import java.sql.SQLException; + +public class MakeQualityProfileKeyUniqueTest { + + @Rule + public CoreDbTester db = CoreDbTester.createForSchema(MakeQualityProfileKeyUniqueTest.class, "initial.sql"); + + public MakeQualityProfileKeyUnique underTest = new MakeQualityProfileKeyUnique(db.database()); + + @Test + public void test() throws SQLException { + underTest.execute(); + db.assertUniqueIndex("rules_profiles", "uniq_qprof_key", "kee"); + } +} diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v64/LetQualityProfileOrganizationUuidAndKeyBeUniqueTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v64/MakeQualityProfileOrganizationUuidAndKeyUniqueTest.java similarity index 87% rename from server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v64/LetQualityProfileOrganizationUuidAndKeyBeUniqueTest.java rename to server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v64/MakeQualityProfileOrganizationUuidAndKeyUniqueTest.java index 6ed404240eb..89c773e1a6c 100644 --- a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v64/LetQualityProfileOrganizationUuidAndKeyBeUniqueTest.java +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v64/MakeQualityProfileOrganizationUuidAndKeyUniqueTest.java @@ -24,10 +24,10 @@ import org.junit.Rule; import org.junit.Test; import org.sonar.db.CoreDbTester; -public class LetQualityProfileOrganizationUuidAndKeyBeUniqueTest { +public class MakeQualityProfileOrganizationUuidAndKeyUniqueTest { @Rule - public CoreDbTester db = CoreDbTester.createForSchema(LetQualityProfileOrganizationUuidAndKeyBeUniqueTest.class, "initial.sql"); + public CoreDbTester db = CoreDbTester.createForSchema(MakeQualityProfileOrganizationUuidAndKeyUniqueTest.class, "initial.sql"); public MakeQualityProfileOrganizationUuidAndKeyUnique underTest = new MakeQualityProfileOrganizationUuidAndKeyUnique(db.database()); diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v64/LetQualityProfileKeyNotBeUniqueAnymoreTest/initial.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v64/DropUniqueIndexOnQualityProfileKeyTest/initial.sql similarity index 100% rename from server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v64/LetQualityProfileKeyNotBeUniqueAnymoreTest/initial.sql rename to server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v64/DropUniqueIndexOnQualityProfileKeyTest/initial.sql diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v64/DropUniqueIndexOnQualityProfileOrganizationUuidAndKeyTest/initial.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v64/DropUniqueIndexOnQualityProfileOrganizationUuidAndKeyTest/initial.sql new file mode 100644 index 00000000000..1803644d492 --- /dev/null +++ b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v64/DropUniqueIndexOnQualityProfileOrganizationUuidAndKeyTest/initial.sql @@ -0,0 +1,15 @@ +CREATE TABLE "RULES_PROFILES" ( + "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), + "NAME" VARCHAR(100) NOT NULL, + "LANGUAGE" VARCHAR(20), + "ORGANIZATION_UUID" VARCHAR(40) NOT NULL, + "KEE" VARCHAR(255) NOT NULL, + "PARENT_KEE" VARCHAR(255), + "RULES_UPDATED_AT" VARCHAR(100), + "IS_DEFAULT" BOOLEAN NOT NULL DEFAULT FALSE, + "CREATED_AT" TIMESTAMP, + "UPDATED_AT" TIMESTAMP, + "LAST_USED" BIGINT, + "USER_UPDATED_AT" BIGINT +); +CREATE UNIQUE INDEX "UNIQ_QPROF_ORG_AND_KEY" ON "RULES_PROFILES" ("ORGANIZATION_UUID", "KEE"); diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v64/LetQualityProfileOrganizationUuidAndKeyBeUniqueTest/initial.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v64/MakeQualityProfileKeyUniqueTest/initial.sql similarity index 100% rename from server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v64/LetQualityProfileOrganizationUuidAndKeyBeUniqueTest/initial.sql rename to server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v64/MakeQualityProfileKeyUniqueTest/initial.sql diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v64/MakeQualityProfileOrganizationUuidAndKeyUniqueTest/initial.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v64/MakeQualityProfileOrganizationUuidAndKeyUniqueTest/initial.sql new file mode 100644 index 00000000000..29ff1d55f0b --- /dev/null +++ b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v64/MakeQualityProfileOrganizationUuidAndKeyUniqueTest/initial.sql @@ -0,0 +1,14 @@ +CREATE TABLE "RULES_PROFILES" ( + "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), + "NAME" VARCHAR(100) NOT NULL, + "LANGUAGE" VARCHAR(20), + "ORGANIZATION_UUID" VARCHAR(40) NOT NULL, + "KEE" VARCHAR(255) NOT NULL, + "PARENT_KEE" VARCHAR(255), + "RULES_UPDATED_AT" VARCHAR(100), + "IS_DEFAULT" BOOLEAN NOT NULL DEFAULT FALSE, + "CREATED_AT" TIMESTAMP, + "UPDATED_AT" TIMESTAMP, + "LAST_USED" BIGINT, + "USER_UPDATED_AT" BIGINT +); diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfile.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfile.java index 4039f8508ff..85668c94324 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfile.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfile.java @@ -23,11 +23,13 @@ import javax.annotation.CheckForNull; import javax.annotation.Nullable; import org.apache.commons.lang.builder.ReflectionToStringBuilder; import org.apache.commons.lang.builder.ToStringStyle; +import org.sonar.db.organization.OrganizationDto; import org.sonar.db.qualityprofile.QualityProfileDto; public class QProfile { private int id; + private OrganizationDto organization; private String key; private String name; private String language; @@ -54,6 +56,15 @@ public class QProfile { return this; } + public OrganizationDto organization() { + return organization; + } + + public QProfile setOrganization(OrganizationDto organization) { + this.organization = organization; + return this; + } + public String name() { return name; } @@ -133,9 +144,10 @@ public class QProfile { return this; } - public static QProfile from(QualityProfileDto dto) { + public static QProfile from(QualityProfileDto dto, OrganizationDto organization) { return new QProfile() .setId(dto.getId()) + .setOrganization(organization) .setKey(dto.getKey()) .setName(dto.getName()) .setLanguage(dto.getLanguage()) diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileFactory.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileFactory.java index 0fdda3f5d46..17a646cb919 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileFactory.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileFactory.java @@ -130,8 +130,8 @@ public class QProfileFactory { // ------------- DEFAULT PROFILE - public List getDefaults(DbSession session, Collection languageKeys) { - return db.qualityProfileDao().selectDefaultProfiles(session, languageKeys); + public List getDefaults(DbSession session, OrganizationDto organization, Collection languageKeys) { + return db.qualityProfileDao().selectDefaultProfiles(session, organization, languageKeys); } public void setDefault(String profileKey) { @@ -189,12 +189,12 @@ public class QProfileFactory { return db.qualityProfileDao().selectByProjectAndLanguage(session, projectKey, language); } - public List getByProjectAndLanguages(DbSession session, String projectKey, Set languageKeys) { - return db.qualityProfileDao().selectByProjectAndLanguages(session, projectKey, languageKeys); + public List getByProjectAndLanguages(DbSession session, OrganizationDto organization, String projectKey, Set languageKeys) { + return db.qualityProfileDao().selectByProjectAndLanguages(session, organization, projectKey, languageKeys); } - public List getByNameAndLanguages(DbSession session, String name, Collection languages) { - return db.qualityProfileDao().selectByNameAndLanguages(name, languages, session); + public List getByNameAndLanguages(DbSession session, OrganizationDto organization, String name, Collection languages) { + return db.qualityProfileDao().selectByNameAndLanguages(organization, name, languages, session); } private static void checkNotDefault(QualityProfileDto p) { diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileLoader.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileLoader.java index 9fb2f2876a7..4b08155f5d2 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileLoader.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileLoader.java @@ -26,7 +26,9 @@ import java.util.stream.Collectors; import org.sonar.api.server.ServerSide; import org.sonar.db.DbClient; import org.sonar.db.DbSession; +import org.sonar.db.organization.OrganizationDto; import org.sonar.db.qualityprofile.QualityProfileDto; +import org.sonar.server.organization.DefaultOrganizationProvider; import org.sonar.server.qualityprofile.index.ActiveRuleIndex; import org.sonar.server.search.FacetValue; @@ -35,17 +37,25 @@ public class QProfileLoader { private final DbClient dbClient; private final ActiveRuleIndex activeRuleIndex; + private final DefaultOrganizationProvider defaultOrganizationProvider; - public QProfileLoader(DbClient dbClient, ActiveRuleIndex activeRuleIndex) { + public QProfileLoader(DbClient dbClient, ActiveRuleIndex activeRuleIndex, DefaultOrganizationProvider defaultOrganizationProvider) { this.dbClient = dbClient; this.activeRuleIndex = activeRuleIndex; + this.defaultOrganizationProvider = defaultOrganizationProvider; } public Map> getAllProfileStats() { try (DbSession dbSession = dbClient.openSession(false)) { - List keys = dbClient.qualityProfileDao().selectAll(dbSession).stream().map(QualityProfileDto::getKey).collect(Collectors.toList()); + List keys = dbClient.qualityProfileDao().selectAll(dbSession, getDefaultOrganization(dbSession)).stream().map(QualityProfileDto::getKey).collect(Collectors.toList()); return activeRuleIndex.getStatsByProfileKeys(keys); } } + private OrganizationDto getDefaultOrganization(DbSession dbSession) { + String defaultOrganizationKey = defaultOrganizationProvider.get().getKey(); + return dbClient.organizationDao() + .selectByKey(dbSession, defaultOrganizationKey) + .orElseThrow(() -> new IllegalStateException("Cannot find default organization with key "+defaultOrganizationKey)); + } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileLookup.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileLookup.java index c947646237e..2ba025e55da 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileLookup.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileLookup.java @@ -19,18 +19,19 @@ */ package org.sonar.server.qualityprofile; -import com.google.common.base.Function; -import com.google.common.collect.Iterables; +import static com.google.common.collect.Lists.newArrayList; +import static org.sonar.core.util.stream.Collectors.toList; + import java.util.List; + import javax.annotation.CheckForNull; -import javax.annotation.Nonnull; + import org.sonar.api.server.ServerSide; import org.sonar.db.DbClient; import org.sonar.db.DbSession; +import org.sonar.db.organization.OrganizationDto; import org.sonar.db.qualityprofile.QualityProfileDto; -import static com.google.common.collect.Lists.newArrayList; - @ServerSide public class QProfileLookup { @@ -40,12 +41,12 @@ public class QProfileLookup { this.db = db; } - public List allProfiles(DbSession dbSession) { - return toQProfiles(db.qualityProfileDao().selectAll(dbSession)); + public List allProfiles(DbSession dbSession, OrganizationDto organization) { + return toQProfiles(db.qualityProfileDao().selectAll(dbSession, organization), organization); } - public List profiles(DbSession dbSession, String language) { - return toQProfiles(db.qualityProfileDao().selectByLanguage(dbSession, language)); + public List profiles(DbSession dbSession, String language, OrganizationDto organization) { + return toQProfiles(db.qualityProfileDao().selectByLanguage(dbSession, language), organization); } @CheckForNull @@ -53,7 +54,7 @@ public class QProfileLookup { try (DbSession dbSession = db.openSession(false)) { QualityProfileDto dto = findQualityProfile(name, language, dbSession); if (dto != null) { - return QProfile.from(dto); + return QProfile.from(dto, null); } return null; } @@ -61,7 +62,7 @@ public class QProfileLookup { public List ancestors(QualityProfileDto profile, DbSession session) { List ancestors = newArrayList(); - incrementAncestors(QProfile.from(profile), ancestors, session); + incrementAncestors(QProfile.from(profile, null), ancestors, session); return ancestors; } @@ -71,27 +72,18 @@ public class QProfileLookup { if (parentDto == null) { throw new IllegalStateException("Cannot find parent of profile : " + profile.id()); } - QProfile parent = QProfile.from(parentDto); + QProfile parent = QProfile.from(parentDto, null); ancestors.add(parent); incrementAncestors(parent, ancestors, session); } } - private static List toQProfiles(List dtos) { - return newArrayList(Iterables.transform(dtos, ToQProfile.INSTANCE)); + private static List toQProfiles(List dtos, OrganizationDto organization) { + return dtos.stream().map(dto -> QProfile.from(dto, organization)).collect(toList(dtos.size())); } @CheckForNull private QualityProfileDto findQualityProfile(String name, String language, DbSession session) { return db.qualityProfileDao().selectByNameAndLanguage(name, language, session); } - - private enum ToQProfile implements Function { - INSTANCE; - - @Override - public QProfile apply(@Nonnull QualityProfileDto input) { - return QProfile.from(input); - } - } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfileWsSupport.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfileWsSupport.java index f3b3ff3b40d..284c0163971 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfileWsSupport.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfileWsSupport.java @@ -82,7 +82,7 @@ public class QProfileWsSupport { .checkPermission(ADMINISTER_QUALITY_PROFILES, defaultOrganizationProvider.get().getUuid()); } - public NewParam createOrganizationParam(NewAction create) { + public static NewParam createOrganizationParam(NewAction create) { return create .createParam(PARAM_ORGANIZATION) .setDescription("Organization key") 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 58e95b38d34..be3ab857289 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 @@ -19,6 +19,7 @@ */ package org.sonar.server.qualityprofile.ws; +import com.google.common.annotations.VisibleForTesting; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -57,6 +58,9 @@ public class SearchAction implements QProfileWsAction { .setHandler(this) .setResponseExample(getClass().getResource("search-example.json")); + QProfileWsSupport.createOrganizationParam(action) + .setSince("6.4"); + action .createParam(PARAM_LANGUAGE) .setDescription( @@ -92,13 +96,15 @@ public class SearchAction implements QProfileWsAction { private static SearchWsRequest toSearchWsRequest(Request request) { return new SearchWsRequest() + .setOrganizationKey(request.param(PARAM_ORGANIZATION)) .setProjectKey(request.param(PARAM_PROJECT_KEY)) .setProfileName(request.param(PARAM_PROFILE_NAME)) .setDefaults(request.paramAsBoolean(PARAM_DEFAULTS)) .setLanguage(request.param(PARAM_LANGUAGE)); } - private SearchWsResponse doHandle(SearchWsRequest request) { + @VisibleForTesting + SearchWsResponse doHandle(SearchWsRequest request) { SearchData data = dataLoader.load(request); return buildResponse(data); } @@ -113,6 +119,9 @@ public class SearchAction implements QProfileWsAction { QualityProfile.Builder profileBuilder = response.addProfilesBuilder(); String profileKey = profile.key(); + if (profile.organization() != null) { + profileBuilder.setOrganization(profile.organization().getKey()); + } profileBuilder.setKey(profileKey); if (profile.name() != null) { profileBuilder.setName(profile.name()); 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 11eb3cf05ac..0880b1dbd3f 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 @@ -19,6 +19,7 @@ */ package org.sonar.server.qualityprofile.ws; +import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.Sets; import java.util.Arrays; import java.util.Collection; @@ -27,16 +28,14 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.function.Function; import java.util.stream.Collectors; import javax.annotation.Nullable; -import org.apache.commons.lang.builder.CompareToBuilder; import org.sonar.api.resources.Language; import org.sonar.api.resources.Languages; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.component.ComponentDto; -import org.sonar.db.qualityprofile.QualityProfileDto; +import org.sonar.db.organization.OrganizationDto; import org.sonar.server.component.ComponentFinder; import org.sonar.server.qualityprofile.QProfile; import org.sonar.server.qualityprofile.QProfileFactory; @@ -48,6 +47,11 @@ import static java.lang.String.format; import static org.sonar.server.ws.WsUtils.checkRequest; public class SearchDataLoader { + + private static final Comparator Q_PROFILE_COMPARATOR = Comparator + .comparing(QProfile::language) + .thenComparing(QProfile::name); + private final Languages languages; private final QProfileLookup profileLookup; private final QProfileFactory profileFactory; @@ -55,14 +59,17 @@ public class SearchDataLoader { private final ComponentFinder componentFinder; private final ActiveRuleIndex activeRuleIndex; + private final QProfileWsSupport qProfileWsSupport; + public SearchDataLoader(Languages languages, QProfileLookup profileLookup, QProfileFactory profileFactory, DbClient dbClient, - ComponentFinder componentFinder, ActiveRuleIndex activeRuleIndex) { + ComponentFinder componentFinder, ActiveRuleIndex activeRuleIndex, QProfileWsSupport qProfileWsSupport) { this.languages = languages; this.profileLookup = profileLookup; this.profileFactory = profileFactory; this.dbClient = dbClient; this.componentFinder = componentFinder; this.activeRuleIndex = activeRuleIndex; + this.qProfileWsSupport = qProfileWsSupport; } SearchData load(SearchWsRequest request) { @@ -77,27 +84,29 @@ public class SearchDataLoader { } } - private List findProfiles(DbSession dbSession, SearchWsRequest request) { + @VisibleForTesting + List findProfiles(DbSession dbSession, SearchWsRequest request) { + OrganizationDto organization = qProfileWsSupport.getOrganizationByKey(dbSession, request.getOrganizationKey()); Collection profiles; if (askDefaultProfiles(request)) { - profiles = findDefaultProfiles(dbSession, request); + profiles = findDefaultProfiles(dbSession, request, organization); } else if (hasComponentKey(request)) { - profiles = findProjectProfiles(dbSession, request); + profiles = findProjectProfiles(dbSession, request, organization); } else { - profiles = findAllProfiles(dbSession, request); + profiles = findAllProfiles(dbSession, request, organization); } - return profiles.stream().sorted(QProfileComparator.INSTANCE).collect(Collectors.toList()); + return profiles.stream().sorted(Q_PROFILE_COMPARATOR).collect(Collectors.toList()); } - private Collection findDefaultProfiles(DbSession dbSession, SearchWsRequest request) { + private Collection findDefaultProfiles(DbSession dbSession, SearchWsRequest request, OrganizationDto organization) { String profileName = request.getProfileName(); Set languageKeys = getLanguageKeys(); Map qualityProfiles = new HashMap<>(languageKeys.size()); - Set missingLanguageKeys = lookupByProfileName(dbSession, qualityProfiles, languageKeys, profileName); - Set noDefaultProfileLanguageKeys = lookupDefaults(dbSession, qualityProfiles, missingLanguageKeys); + Set missingLanguageKeys = lookupByProfileName(dbSession, organization, qualityProfiles, languageKeys, profileName); + Set noDefaultProfileLanguageKeys = lookupDefaults(dbSession, organization, qualityProfiles, missingLanguageKeys); if (!noDefaultProfileLanguageKeys.isEmpty()) { throw new IllegalStateException(format("No quality profile can been found on language(s) '%s'", noDefaultProfileLanguageKeys)); @@ -106,7 +115,7 @@ public class SearchDataLoader { return qualityProfiles.values(); } - private Collection findProjectProfiles(DbSession dbSession, SearchWsRequest request) { + private Collection findProjectProfiles(DbSession dbSession, SearchWsRequest request, OrganizationDto organization) { String componentKey = request.getProjectKey(); String profileName = request.getProfileName(); @@ -114,11 +123,11 @@ public class SearchDataLoader { Map qualityProfiles = new HashMap<>(languageKeys.size()); // look up profiles by profileName (if any) for each language - Set unresolvedLanguages = lookupByProfileName(dbSession, qualityProfiles, languageKeys, profileName); + Set unresolvedLanguages = lookupByProfileName(dbSession, organization, qualityProfiles, languageKeys, profileName); // look up profile by componentKey for each language for which we don't have one yet - Set stillUnresolvedLanguages = lookupByModuleKey(dbSession, qualityProfiles, unresolvedLanguages, componentKey); + Set stillUnresolvedLanguages = lookupByModuleKey(dbSession, organization, qualityProfiles, unresolvedLanguages, componentKey); // look up profile by default for each language for which we don't have one yet - Set noDefaultProfileLanguages = lookupDefaults(dbSession, qualityProfiles, stillUnresolvedLanguages); + Set 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)); @@ -127,31 +136,36 @@ public class SearchDataLoader { return qualityProfiles.values(); } - private List findAllProfiles(DbSession dbSession, SearchWsRequest request) { + private List findAllProfiles(DbSession dbSession, SearchWsRequest request, OrganizationDto organization) { String language = request.getLanguage(); if (language == null) { - return profileLookup.allProfiles(dbSession).stream().filter(qProfile -> languages.get(qProfile.language()) != null).collect(Collectors.toList()); + return profileLookup.allProfiles(dbSession, organization).stream().filter(qProfile -> languages.get(qProfile.language()) != null).collect(Collectors.toList()); } - return profileLookup.profiles(dbSession, language); + return profileLookup.profiles(dbSession, language, organization); } - private Set lookupByProfileName(DbSession dbSession, Map qualityProfiles, Set languageKeys, @Nullable String profileName) { + private Set lookupByProfileName(DbSession dbSession, OrganizationDto organization, Map qualityProfiles, Set languageKeys, + @Nullable String profileName) { if (languageKeys.isEmpty() || profileName == null) { return languageKeys; } - addAllFromDto(qualityProfiles, profileFactory.getByNameAndLanguages(dbSession, profileName, languageKeys)); + profileFactory.getByNameAndLanguages(dbSession, organization, profileName, languageKeys) + .forEach(qualityProfile -> qualityProfiles + .put(qualityProfile.getLanguage(), QProfile.from(qualityProfile, organization))); return difference(languageKeys, qualityProfiles.keySet()); } - private Set lookupByModuleKey(DbSession dbSession, Map qualityProfiles, Set languageKeys, @Nullable String moduleKey) { + private Set lookupByModuleKey(DbSession dbSession, OrganizationDto organization, Map qualityProfiles, Set languageKeys, + @Nullable String moduleKey) { if (languageKeys.isEmpty() || moduleKey == null) { return languageKeys; } ComponentDto project = getProject(moduleKey, dbSession); - addAllFromDto(qualityProfiles, profileFactory.getByProjectAndLanguages(dbSession, project.getKey(), languageKeys)); + profileFactory.getByProjectAndLanguages(dbSession, organization, project.getKey(), languageKeys) + .forEach(qualityProfile -> qualityProfiles.put(qualityProfile.getLanguage(), QProfile.from(qualityProfile, organization))); return difference(languageKeys, qualityProfiles.keySet()); } @@ -163,12 +177,12 @@ public class SearchDataLoader { return dbClient.componentDao().selectOrFailByUuid(session, module.projectUuid()); } - private Set lookupDefaults(DbSession dbSession, Map qualityProfiles, Set languageKeys) { + private Set lookupDefaults(DbSession dbSession, OrganizationDto organization, Map qualityProfiles, Set languageKeys) { if (languageKeys.isEmpty()) { return languageKeys; } - addAll(qualityProfiles, findDefaultProfiles(dbSession, languageKeys)); + addAll(qualityProfiles, findDefaultProfiles(dbSession, organization, languageKeys)); return difference(languageKeys, qualityProfiles.keySet()); } @@ -176,10 +190,6 @@ public class SearchDataLoader { return Sets.newHashSet(Sets.difference(languageKeys, set2)); } - private static void addAllFromDto(Map qualityProfiles, Collection list) { - list.forEach(qualityProfile -> qualityProfiles.put(qualityProfile.getLanguage(), QualityProfileDtoToQProfile.INSTANCE.apply(qualityProfile))); - } - private static void addAll(Map qualityProfiles, Collection list) { list.forEach(qualityProfile -> qualityProfiles.put(qualityProfile.language(), qualityProfile)); } @@ -188,13 +198,14 @@ public class SearchDataLoader { return Arrays.stream(languages.all()).map(Language::getKey).collect(Collectors.toSet()); } - private List findDefaultProfiles(final DbSession dbSession, Set languageKeys) { - return profileFactory.getDefaults(dbSession, languageKeys).stream() - .map(QualityProfileDtoToQProfile.INSTANCE) + private List findDefaultProfiles(final DbSession dbSession, OrganizationDto organization, Set languageKeys) { + return profileFactory.getDefaults(dbSession, organization, languageKeys).stream() + .map(result -> QProfile.from(result, organization)) .collect(Collectors.toList()); } - private static void validateRequest(SearchWsRequest request) { + @VisibleForTesting + static void validateRequest(SearchWsRequest request) { boolean hasLanguage = hasLanguage(request); boolean isDefault = askDefaultProfiles(request); boolean hasComponentKey = hasComponentKey(request); @@ -202,7 +213,8 @@ public class SearchDataLoader { checkRequest(!hasLanguage || (!hasComponentKey && !hasProfileName && !isDefault), "The language parameter cannot be provided at the same time than the component key or profile name."); - checkRequest(!isDefault || !hasComponentKey, "The default parameter cannot be provided at the same time than the component key"); + checkRequest(!isDefault || !hasComponentKey, "The default parameter cannot be provided at the same time than the component key."); + checkRequest(!hasProfileName || hasComponentKey || isDefault, "The name parameter requires either projectKey or defaults to be set."); } private static boolean askDefaultProfiles(SearchWsRequest request) { @@ -220,31 +232,4 @@ public class SearchDataLoader { private static boolean hasLanguage(SearchWsRequest request) { return request.getLanguage() != null; } - - private enum QProfileComparator implements Comparator { - INSTANCE; - @Override - public int compare(QProfile o1, QProfile o2) { - return new CompareToBuilder() - .append(o1.language(), o2.language()) - .append(o1.name(), o2.name()) - .toComparison(); - } - } - - private enum QualityProfileDtoToQProfile implements Function { - INSTANCE; - - @Override - public QProfile apply(QualityProfileDto input) { - return new QProfile() - .setKey(input.getKey()) - .setName(input.getName()) - .setLanguage(input.getLanguage()) - .setDefault(input.isDefault()) - .setRulesUpdatedAt(input.getRulesUpdatedAt()) - .setLastUsed(input.getLastUsed()) - .setUserUpdatedAt(input.getUserUpdatedAt()); - } - } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/rule/ws/AppAction.java b/server/sonar-server/src/main/java/org/sonar/server/rule/ws/AppAction.java index 1b8ae4b648b..522e0a4d139 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/rule/ws/AppAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/rule/ws/AppAction.java @@ -30,6 +30,7 @@ import org.sonar.api.server.ws.WebService; import org.sonar.api.utils.text.JsonWriter; import org.sonar.db.DbClient; import org.sonar.db.DbSession; +import org.sonar.db.organization.OrganizationDto; import org.sonar.db.qualityprofile.QualityProfileDto; import org.sonar.server.organization.DefaultOrganizationProvider; import org.sonar.db.permission.OrganizationPermission; @@ -83,7 +84,7 @@ public class AppAction implements RulesWsAction { private void addProfiles(JsonWriter json, DbSession dbSession) { json.name("qualityprofiles").beginArray(); - for (QualityProfileDto profile : dbClient.qualityProfileDao().selectAll(dbSession)) { + for (QualityProfileDto profile : dbClient.qualityProfileDao().selectAll(dbSession, getDefaultOrganization(dbSession))) { if (languageIsSupported(profile)) { json .beginObject() @@ -131,4 +132,10 @@ public class AppAction implements RulesWsAction { json.endObject(); } + private OrganizationDto getDefaultOrganization(DbSession dbSession) { + String defaultOrganizationKey = defaultOrganizationProvider.get().getKey(); + return dbClient.organizationDao() + .selectByKey(dbSession, defaultOrganizationKey) + .orElseThrow(() -> new IllegalStateException("Cannot find default organization with key "+defaultOrganizationKey)); + } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileBackuperMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileBackuperMediumTest.java index e600c351373..4c3817fb829 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileBackuperMediumTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileBackuperMediumTest.java @@ -46,6 +46,7 @@ import org.sonar.db.qualityprofile.QualityProfileDto; import org.sonar.db.rule.RuleDto; import org.sonar.db.rule.RuleParamDto; import org.sonar.server.qualityprofile.index.ActiveRuleIndexer; +import org.sonar.server.qualityprofile.ws.QProfileWsSupport; import org.sonar.server.rule.index.RuleIndex; import org.sonar.server.rule.index.RuleIndexer; import org.sonar.server.rule.index.RuleQuery; @@ -392,7 +393,7 @@ public class QProfileBackuperMediumTest { dbSession.clearCache(); assertThat(db.activeRuleDao().selectAll(dbSession)).hasSize(0); - List profiles = db.qualityProfileDao().selectAll(dbSession); + List profiles = db.qualityProfileDao().selectAll(dbSession, getDefaultOrganization(tester, db, dbSession)); assertThat(profiles).hasSize(1); assertThat(profiles.get(0).getName()).isEqualTo("P1"); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileFactoryMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileFactoryMediumTest.java index d03d81de23c..e5f8b516b81 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileFactoryMediumTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileFactoryMediumTest.java @@ -50,6 +50,7 @@ import static org.junit.Assert.fail; import static org.sonar.server.qualityprofile.QProfileTesting.XOO_P1_KEY; import static org.sonar.server.qualityprofile.QProfileTesting.XOO_P2_KEY; import static org.sonar.server.qualityprofile.QProfileTesting.XOO_P3_KEY; +import static org.sonar.server.qualityprofile.QProfileTesting.getDefaultOrganization; public class QProfileFactoryMediumTest { @@ -96,7 +97,7 @@ public class QProfileFactoryMediumTest { assertThat(writtenDto.getId()).isNotNull(); // reload the dto - QualityProfileDto readDto = db.qualityProfileDao().selectByNameAndLanguage("P1", "xoo", dbSession); + QualityProfileDto readDto = db.qualityProfileDao().selectByNameAndLanguage(organization, "P1", "xoo", dbSession); assertThat(readDto.getOrganizationUuid()).isEqualTo(uuid); assertThat(readDto.getName()).isEqualTo("P1"); assertThat(readDto.getKey()).startsWith("xoo-p1"); @@ -104,7 +105,7 @@ public class QProfileFactoryMediumTest { assertThat(readDto.getId()).isNotNull(); assertThat(readDto.getParentKee()).isNull(); - assertThat(db.qualityProfileDao().selectAll(dbSession)).hasSize(1); + assertThat(db.qualityProfileDao().selectAll(dbSession, organization)).hasSize(1); } @Test @@ -150,7 +151,7 @@ public class QProfileFactoryMediumTest { activeRuleIndexer.index(changes); dbSession.clearCache(); - assertThat(db.qualityProfileDao().selectAll(dbSession)).isEmpty(); + assertThat(db.qualityProfileDao().selectAll(dbSession, getDefaultOrganization(tester, db, dbSession))).isEmpty(); assertThat(db.activeRuleDao().selectAll(dbSession)).isEmpty(); assertThat(db.activeRuleDao().selectAllParams(dbSession)).isEmpty(); assertThat(db.activeRuleDao().selectByProfileKey(dbSession, XOO_P1_KEY)).isEmpty(); @@ -162,7 +163,10 @@ public class QProfileFactoryMediumTest { initRules(); // create parent and child profiles - db.qualityProfileDao().insert(dbSession, QProfileTesting.newXooP1("org-123"), QProfileTesting.newXooP2("org-123"), QProfileTesting.newXooP3("org-123")); + db.qualityProfileDao().insert(dbSession, + QProfileTesting.newXooP1(organization), + QProfileTesting.newXooP2(organization), + QProfileTesting.newXooP3(organization)); List changes = tester.get(RuleActivator.class).setParent(dbSession, XOO_P2_KEY, XOO_P1_KEY); changes.addAll(tester.get(RuleActivator.class).setParent(dbSession, XOO_P3_KEY, XOO_P1_KEY)); changes.addAll(tester.get(RuleActivator.class).activate(dbSession, new RuleActivation(RuleTesting.XOO_X1), XOO_P1_KEY)); @@ -170,7 +174,7 @@ public class QProfileFactoryMediumTest { dbSession.clearCache(); activeRuleIndexer.index(changes); - assertThat(db.qualityProfileDao().selectAll(dbSession)).hasSize(3); + assertThat(db.qualityProfileDao().selectAll(dbSession, organization)).hasSize(3); assertThat(db.activeRuleDao().selectAll(dbSession)).hasSize(3); changes = factory.delete(dbSession, XOO_P1_KEY, false); @@ -178,7 +182,7 @@ public class QProfileFactoryMediumTest { activeRuleIndexer.index(changes); dbSession.clearCache(); - assertThat(db.qualityProfileDao().selectAll(dbSession)).isEmpty(); + assertThat(db.qualityProfileDao().selectAll(dbSession, getDefaultOrganization(tester, db, dbSession))).isEmpty(); assertThat(db.activeRuleDao().selectAll(dbSession)).isEmpty(); assertThat(db.activeRuleDao().selectAllParams(dbSession)).isEmpty(); assertThat(db.activeRuleDao().selectByProfileKey(dbSession, XOO_P1_KEY)).isEmpty(); @@ -188,7 +192,7 @@ public class QProfileFactoryMediumTest { @Test public void do_not_delete_default_profile() { - db.qualityProfileDao().insert(dbSession, QProfileTesting.newXooP1("org-123")); + db.qualityProfileDao().insert(dbSession, QProfileTesting.newXooP1(organization)); factory.setDefault(dbSession, XOO_P1_KEY); dbSession.commit(); dbSession.clearCache(); @@ -200,13 +204,16 @@ public class QProfileFactoryMediumTest { fail(); } catch (BadRequestException e) { assertThat(e).hasMessage("The profile marked as default can not be deleted: XOO_P1"); - assertThat(db.qualityProfileDao().selectAll(dbSession)).hasSize(1); + assertThat(db.qualityProfileDao().selectAll(dbSession, organization)).hasSize(1); } } @Test public void do_not_delete_if_default_descendant() { - db.qualityProfileDao().insert(dbSession, QProfileTesting.newXooP1("org-123"), QProfileTesting.newXooP2("org-123"), QProfileTesting.newXooP3("org-123")); + db.qualityProfileDao().insert(dbSession, + QProfileTesting.newXooP1(organization), + QProfileTesting.newXooP2(organization), + QProfileTesting.newXooP3(organization)); List changes = tester.get(RuleActivator.class).setParent(dbSession, XOO_P2_KEY, XOO_P1_KEY); changes.addAll(tester.get(RuleActivator.class).setParent(dbSession, XOO_P3_KEY, XOO_P1_KEY)); @@ -222,7 +229,7 @@ public class QProfileFactoryMediumTest { fail(); } catch (BadRequestException e) { assertThat(e).hasMessage("The profile marked as default can not be deleted: XOO_P3"); - assertThat(db.qualityProfileDao().selectAll(dbSession)).hasSize(3); + assertThat(db.qualityProfileDao().selectAll(dbSession, organization)).hasSize(3); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileServiceMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileServiceMediumTest.java index 74103b60b95..1de3eba881f 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileServiceMediumTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileServiceMediumTest.java @@ -37,6 +37,7 @@ import org.sonar.api.rules.RulePriority; import org.sonar.api.utils.ValidationMessages; import org.sonar.db.DbClient; import org.sonar.db.DbSession; +import org.sonar.db.organization.OrganizationDto; import org.sonar.db.rule.RuleDto; import org.sonar.db.rule.RuleTesting; import org.sonar.server.organization.DefaultOrganizationProvider; @@ -55,6 +56,7 @@ import static org.sonar.db.rule.RuleTesting.newXooX3; import static org.sonar.db.permission.OrganizationPermission.ADMINISTER_QUALITY_PROFILES; import static org.sonar.server.qualityprofile.QProfileTesting.XOO_P1_KEY; import static org.sonar.server.qualityprofile.QProfileTesting.XOO_P2_KEY; +import static org.sonar.server.qualityprofile.QProfileTesting.getDefaultOrganization; public class QProfileServiceMediumTest { @@ -88,7 +90,8 @@ public class QProfileServiceMediumTest { dbClient.ruleDao().insert(dbSession, xooRule1); // create pre-defined profiles P1 and P2 - dbClient.qualityProfileDao().insert(dbSession, QProfileTesting.newXooP1("org-123"), QProfileTesting.newXooP2("org-123")); + OrganizationDto defaultOrganization = getDefaultOrganization(tester, dbClient, dbSession); + dbClient.qualityProfileDao().insert(dbSession, QProfileTesting.newXooP1(defaultOrganization), QProfileTesting.newXooP2(defaultOrganization)); dbSession.commit(); dbSession.clearCache(); diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileTest.java index 0f16926b743..bf65202b58f 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileTest.java @@ -35,12 +35,6 @@ public class QProfileTest { assertThat(profile.parent()).isEqualTo("Parent"); } - @Test - public void to_string() { - assertThat(new QProfile().setId(1).setName("Default").setLanguage("java").setParent("Parent").toString()) - .contains("[id=1,key=,name=Default,language=java,parent=Parent,isDefault=false,rulesUpdatedAt=,lastUsed=,userUpdatedAt=]"); - } - @Test public void is_inherited() { assertThat(new QProfile().setId(1).setName("Default").setLanguage("java").setParent("Parent").isInherited()).isTrue(); diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RegisterQualityProfilesMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RegisterQualityProfilesMediumTest.java index d5ca10ec180..1c78d45c425 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RegisterQualityProfilesMediumTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RegisterQualityProfilesMediumTest.java @@ -41,6 +41,7 @@ import org.sonar.db.qualityprofile.ActiveRuleKey; import org.sonar.db.qualityprofile.ActiveRuleParamDto; import org.sonar.db.qualityprofile.QualityProfileDao; import org.sonar.db.qualityprofile.QualityProfileDto; +import org.sonar.db.qualityprofile.QualityProfileTesting; import org.sonar.server.es.SearchOptions; import org.sonar.server.platform.Platform; import org.sonar.server.rule.index.RuleIndex; @@ -50,6 +51,7 @@ import org.sonar.server.tester.ServerTester; import static com.google.common.collect.Lists.newArrayList; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.guava.api.Assertions.assertThat; +import static org.sonar.server.qualityprofile.QProfileTesting.getDefaultOrganization; // TODO replace this MediumTest by DbTester and EsTester public class RegisterQualityProfilesMediumTest { @@ -71,16 +73,17 @@ public class RegisterQualityProfilesMediumTest { public void register_existing_profile_definitions() { tester = new ServerTester().withEsIndexes().withStartupTasks().addXoo().addComponents(XooRulesDefinition.class, XooProfileDefinition.class); tester.start(); - dbSession = dbClient().openSession(false); + DbClient dbClient = dbClient(); + dbSession = dbClient.openSession(false); // Check Profile in DB - QualityProfileDao qualityProfileDao = dbClient().qualityProfileDao(); - assertThat(qualityProfileDao.selectAll(dbSession)).hasSize(1); + QualityProfileDao qualityProfileDao = dbClient.qualityProfileDao(); + assertThat(qualityProfileDao.selectAll(dbSession, getDefaultOrganization(tester, dbClient, dbSession))).hasSize(1); QualityProfileDto profile = qualityProfileDao.selectByNameAndLanguage("Basic", "xoo", dbSession); assertThat(profile).isNotNull(); // Check ActiveRules in DB - ActiveRuleDao activeRuleDao = dbClient().activeRuleDao(); + ActiveRuleDao activeRuleDao = dbClient.activeRuleDao(); assertThat(activeRuleDao.selectByProfileKey(dbSession, profile.getKey())).hasSize(2); RuleKey ruleKey = RuleKey.of("xoo", "x1"); @@ -117,11 +120,12 @@ public class RegisterQualityProfilesMediumTest { public void register_profile_definitions() { tester = new ServerTester().withEsIndexes().withStartupTasks().addXoo().addComponents(XooRulesDefinition.class, XooProfileDefinition.class); tester.start(); - dbSession = dbClient().openSession(false); + DbClient dbClient = dbClient(); + dbSession = dbClient.openSession(false); // Check Profile in DB - QualityProfileDao qualityProfileDao = dbClient().qualityProfileDao(); - assertThat(qualityProfileDao.selectAll(dbSession)).hasSize(1); + QualityProfileDao qualityProfileDao = dbClient.qualityProfileDao(); + assertThat(qualityProfileDao.selectAll(dbSession, getDefaultOrganization(tester, dbClient, dbSession))).hasSize(1); QualityProfileDto profile = qualityProfileDao.selectByNameAndLanguage("Basic", "xoo", dbSession); assertThat(profile).isNotNull(); @@ -129,7 +133,7 @@ public class RegisterQualityProfilesMediumTest { verifyDefaultProfile("xoo", "Basic"); // Check ActiveRules in DB - ActiveRuleDao activeRuleDao = dbClient().activeRuleDao(); + ActiveRuleDao activeRuleDao = dbClient.activeRuleDao(); assertThat(activeRuleDao.selectByProfileKey(dbSession, profile.getKey())).hasSize(2); RuleKey ruleKey = RuleKey.of("xoo", "x1"); @@ -153,11 +157,12 @@ public class RegisterQualityProfilesMediumTest { // xoo language is not installed tester = new ServerTester().withEsIndexes().addComponents(XooRulesDefinition.class, XooProfileDefinition.class); tester.start(); + DbClient dbClient = dbClient(); dbSession = dbClient().openSession(false); // Check Profile in DB QualityProfileDao qualityProfileDao = dbClient().qualityProfileDao(); - assertThat(qualityProfileDao.selectAll(dbSession)).hasSize(0); + assertThat(qualityProfileDao.selectAll(dbSession, getDefaultOrganization(tester, dbClient(), dbSession))).hasSize(0); } @Test diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/InheritanceActionMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/InheritanceActionMediumTest.java index c196290dd04..dd167c80804 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/InheritanceActionMediumTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/InheritanceActionMediumTest.java @@ -30,6 +30,8 @@ import org.sonar.api.rule.RuleStatus; import org.sonar.api.rule.Severity; import org.sonar.db.DbClient; import org.sonar.db.DbSession; +import org.sonar.db.organization.OrganizationDto; +import org.sonar.db.organization.OrganizationTesting; import org.sonar.db.qualityprofile.ActiveRuleDto; import org.sonar.db.qualityprofile.QualityProfileDto; import org.sonar.db.rule.RuleDto; @@ -45,6 +47,8 @@ import org.sonar.server.tester.ServerTester; import org.sonar.server.tester.UserSessionRule; import org.sonar.server.ws.WsTester; +import static org.sonar.server.qualityprofile.QProfileTesting.getDefaultOrganization; + public class InheritanceActionMediumTest { @ClassRule @@ -61,6 +65,8 @@ public class InheritanceActionMediumTest { RuleIndexer ruleIndexer; ActiveRuleIndexer activeRuleIndexer; + private OrganizationDto organization; + @Before public void setUp() { tester.clearDbAndIndexes(); @@ -70,6 +76,7 @@ public class InheritanceActionMediumTest { activeRuleIndexer = tester.get(ActiveRuleIndexer.class); wsTester = new WsTester(tester.get(QProfilesWs.class)); + organization = getDefaultOrganization(tester, db, session); } @After @@ -111,7 +118,7 @@ public class InheritanceActionMediumTest { setParent(buWide, forProject2); overrideActiveRuleSeverity(rule2, forProject2, Severity.CRITICAL); - wsTester.newGetRequest("api/qualityprofiles", "inheritance").setParam("profileKey", buWide.getKee()) + wsTester.newGetRequest("api/qualityprofiles", "inheritance").setParam("profileKey", buWide.getKee()).setParam("organization", organization.getKey()) .execute().assertJson(getClass(), "inheritance-buWide.json"); } @@ -129,7 +136,7 @@ public class InheritanceActionMediumTest { } private QualityProfileDto createProfile(String lang, String name, String key) { - QualityProfileDto profile = QProfileTesting.newQProfileDto("org-123", new QProfileName(lang, name), key); + QualityProfileDto profile = QProfileTesting.newQProfileDto(organization, new QProfileName(lang, name), key); db.qualityProfileDao().insert(session, profile); session.commit(); return profile; diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfilesWsTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfilesWsTest.java index 2d38bc4298f..167772d91f3 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfilesWsTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfilesWsTest.java @@ -129,10 +129,11 @@ public class QProfilesWsTest { WebService.Action search = controller.action("search"); assertThat(search).isNotNull(); assertThat(search.isPost()).isFalse(); - assertThat(search.params()).hasSize(4); + assertThat(search.params()).hasSize(5); assertThat(search.param("language").possibleValues()).containsOnly(xoo1Key, xoo2Key); assertThat(search.param("language").deprecatedSince()).isEqualTo("6.4"); assertThat(search.param("profileName").deprecatedSince()).isEqualTo("6.4"); + assertThat(search.param("organization").since()).isEqualTo("6.4"); } @Test 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 3adc4ab1646..68831272b2f 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,10 @@ package org.sonar.server.qualityprofile.ws; import com.google.common.collect.ImmutableMap; import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Date; +import java.util.List; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -37,6 +40,7 @@ import org.sonar.db.component.ComponentDao; import org.sonar.db.component.ComponentDbTester; import org.sonar.db.component.ComponentDto; import org.sonar.db.organization.OrganizationDto; +import org.sonar.db.organization.OrganizationTesting; import org.sonar.db.qualityprofile.QualityProfileDao; import org.sonar.db.qualityprofile.QualityProfileDbTester; import org.sonar.db.qualityprofile.QualityProfileDto; @@ -47,11 +51,14 @@ import org.sonar.server.organization.TestDefaultOrganizationProvider; import org.sonar.server.qualityprofile.QProfileFactory; import org.sonar.server.qualityprofile.QProfileLookup; import org.sonar.server.qualityprofile.index.ActiveRuleIndex; +import org.sonar.server.tester.UserSessionRule; import org.sonar.server.ws.TestRequest; import org.sonar.server.ws.WsActionTester; import org.sonarqube.ws.MediaTypes; +import org.sonarqube.ws.QualityProfiles; import org.sonarqube.ws.QualityProfiles.SearchWsResponse; import org.sonarqube.ws.QualityProfiles.SearchWsResponse.QualityProfile; +import org.sonarqube.ws.client.qualityprofile.SearchWsRequest; import static com.google.common.base.Throwables.propagate; import static org.assertj.core.api.Assertions.assertThat; @@ -64,15 +71,19 @@ import static org.sonar.db.component.ComponentTesting.newProjectDto; 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; +import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_ORGANIZATION; import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_PROFILE_NAME; import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_PROJECT_KEY; + public class SearchActionTest { @Rule public ExpectedException expectedException = ExpectedException.none(); @Rule public DbTester db = DbTester.create(System2.INSTANCE); + @Rule + public UserSessionRule userSession = UserSessionRule.standalone(); QualityProfileDbTester qualityProfileDb = new QualityProfileDbTester(db); ComponentDbTester componentDb = new ComponentDbTester(db); DbClient dbClient = db.getDbClient(); @@ -81,11 +92,13 @@ public class SearchActionTest { private DefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(db); private ActiveRuleIndex activeRuleIndex = mock(ActiveRuleIndex.class); + private QProfileWsSupport qProfileWsSupport = new QProfileWsSupport(dbClient, userSession, defaultOrganizationProvider); private Language xoo1; private Language xoo2; private WsActionTester ws; + private SearchAction underTest; @Before public void setUp() { @@ -93,14 +106,15 @@ public class SearchActionTest { xoo2 = LanguageTesting.newLanguage("xoo2"); Languages languages = new Languages(xoo1, xoo2); - ws = new WsActionTester(new SearchAction( + underTest = new SearchAction( new SearchDataLoader( languages, new QProfileLookup(dbClient), new QProfileFactory(dbClient), dbClient, - new ComponentFinder(dbClient), activeRuleIndex), - languages)); + new ComponentFinder(dbClient), activeRuleIndex, qProfileWsSupport), + languages); + ws = new WsActionTester(underTest); } @Test @@ -112,7 +126,7 @@ public class SearchActionTest { "sonar-way-xoo1-12345", 1L, "my-sonar-way-xoo2-34567", 2L)); - OrganizationDto organizationDto = db.organizations().insert(); + OrganizationDto organizationDto = getDefaultOrganization(); String organizationUuid = organizationDto.getUuid(); qualityProfileDao.insert(dbSession, QualityProfileDto.createFor("sonar-way-xoo1-12345") @@ -154,6 +168,7 @@ public class SearchActionTest { public void search_map_dates() { long time = DateUtils.parseDateTime("2016-12-22T19:10:03+0100").getTime(); qualityProfileDb.insertQualityProfiles(newQualityProfileDto() + .setOrganizationUuid(defaultOrganizationProvider.get().getUuid()) .setLanguage(xoo1.getKey()) .setRulesUpdatedAt("2016-12-21T19:10:03+0100") .setLastUsed(time) @@ -183,7 +198,7 @@ public class SearchActionTest { @Test public void search_for_project_qp() { long time = DateUtils.parseDateTime("2016-12-22T19:10:03+0100").getTime(); - OrganizationDto org = db.organizations().insert(); + OrganizationDto org = db.getDefaultOrganization(); QualityProfileDto qualityProfileOnXoo1 = QualityProfileDto.createFor("sonar-way-xoo1-12345") .setOrganizationUuid(org.getUuid()) .setLanguage(xoo1.getKey()) @@ -260,16 +275,19 @@ public class SearchActionTest { .setOrganizationUuid(org.getUuid()) .setLanguage(xoo2.getKey()) .setRulesUpdatedAtAsDate(new Date()) - .setName("Sonar way"); + .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"); + .setName("Another way") + .setDefault(true); qualityProfileDb.insertQualityProfiles(qualityProfileOnXoo1, qualityProfileOnXoo2, anotherQualityProfileOnXoo1); ComponentDto project = componentDb.insertComponent(newProjectDto(org, "project-uuid")); String result = ws.newRequest() + .setParam(PARAM_ORGANIZATION, org.getKey()) .setParam(PARAM_PROJECT_KEY, project.key()) .setParam(PARAM_PROFILE_NAME, "Sonar way") .execute().getInput(); @@ -278,6 +296,43 @@ public class SearchActionTest { .contains("sonar-way-xoo1-12345", "sonar-way-xoo2-12345") .doesNotContain("sonar-way-xoo1-45678"); } + @Test + public void search_default_profile_by_profile_name_and_org() { + List profiles = new ArrayList<>(); + for (String orgKey : Arrays.asList("ORG1", "ORG2")) { + OrganizationDto org = db.organizations().insert(OrganizationTesting.newOrganizationDto().setKey(orgKey)); + profiles.add(createProfile("A", xoo1, org, "MATCH", false)); + profiles.add(createProfile("B", xoo2, org, "NOMATCH", false)); + profiles.add(createProfile("C", xoo1, org, "NOMATCH", true)); + profiles.add(createProfile("D", xoo2, org, "NOMATCH", true)); + } + + profiles.forEach(db.qualityProfiles()::insertQualityProfile); + + SearchWsRequest request = new SearchWsRequest() + .setDefaults(true) + .setProfileName("MATCH") + .setOrganizationKey("ORG1"); + QualityProfiles.SearchWsResponse response = underTest.doHandle(request); + + assertThat(response.getProfilesList()) + .extracting(QualityProfiles.SearchWsResponse.QualityProfile::getKey) + .containsExactlyInAnyOrder( + + // name match for xoo1 + "ORG1-A", + + // default for xoo2 + "ORG1-D"); + } + + private QualityProfileDto createProfile(String keySuffix, Language language, OrganizationDto org, String name, boolean isDefault) { + return QualityProfileDto.createFor(org.getKey() + "-" + keySuffix) + .setOrganizationUuid(org.getUuid()) + .setLanguage(language.getKey()) + .setName(name) + .setDefault(isDefault); + } private SearchWsResponse call(TestRequest request) { try { @@ -288,4 +343,8 @@ public class SearchActionTest { throw propagate(e); } } + + private OrganizationDto getDefaultOrganization() { + return qProfileWsSupport.getOrganizationByKey(db.getSession(), defaultOrganizationProvider.get().getKey()); + } } 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 new file mode 100644 index 00000000000..edec5e499a7 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/SearchDataLoaderTest.java @@ -0,0 +1,97 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.qualityprofile.ws; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.sonar.server.exceptions.BadRequestException; +import org.sonarqube.ws.client.qualityprofile.SearchWsRequest; + +public class SearchDataLoaderTest { + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Test + public void name_and_default_query_is_valid() throws Exception { + SearchWsRequest request = new SearchWsRequest() + .setProfileName("bla") + .setDefaults(true); + + SearchDataLoader.validateRequest(request); + } + + @Test + public void name_and_component_query_is_valid() throws Exception { + SearchWsRequest request = new SearchWsRequest() + .setProfileName("bla") + .setProjectKey("blubb"); + + SearchDataLoader.validateRequest(request); + } + + @Test + public void name_requires_either_component_or_defaults() throws Exception { + SearchWsRequest request = new SearchWsRequest() + .setProfileName("bla"); + + thrown.expect(BadRequestException.class); + thrown.expectMessage("The name parameter requires either projectKey or defaults to be set."); + + SearchDataLoader.validateRequest(request); + } + + @Test + public void default_and_component_cannot_be_set_at_same_time() throws Exception { + SearchWsRequest request = new SearchWsRequest() + .setDefaults(true) + .setProjectKey("blubb"); + + thrown.expect(BadRequestException.class); + thrown.expectMessage("The default parameter cannot be provided at the same time than the component key."); + + SearchDataLoader.validateRequest(request); + } + + @Test + public void language_and_component_cannot_be_set_at_same_time() throws Exception { + SearchWsRequest request = new SearchWsRequest() + .setLanguage("xoo") + .setProjectKey("bla"); + + thrown.expect(BadRequestException.class); + thrown.expectMessage("The language parameter cannot be provided at the same time than the component key or profile name."); + + SearchDataLoader.validateRequest(request); + } + + @Test + public void language_and_name_cannot_be_set_at_same_time() throws Exception { + SearchWsRequest request = new SearchWsRequest() + .setLanguage("xoo") + .setProfileName("bla"); + + thrown.expect(BadRequestException.class); + thrown.expectMessage("The language parameter cannot be provided at the same time than the component key or profile name."); + + SearchDataLoader.validateRequest(request); + } +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/SearchDataLoaderTest2.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/SearchDataLoaderTest2.java new file mode 100644 index 00000000000..e555471f9da --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/SearchDataLoaderTest2.java @@ -0,0 +1,171 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.qualityprofile.ws; + +import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; + +import java.util.Arrays; +import java.util.List; +import java.util.function.Consumer; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.sonar.api.resources.Language; +import org.sonar.api.resources.Languages; +import org.sonar.api.utils.System2; +import org.sonar.db.DbClient; +import org.sonar.db.DbSession; +import org.sonar.db.DbTester; +import org.sonar.db.component.ComponentDto; +import org.sonar.db.organization.OrganizationDto; +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.QProfile; +import org.sonar.server.qualityprofile.QProfileFactory; +import org.sonar.server.qualityprofile.QProfileLookup; +import org.sonar.server.qualityprofile.index.ActiveRuleIndex; +import org.sonarqube.ws.client.qualityprofile.SearchWsRequest; + + +public class SearchDataLoaderTest2 { + + @Rule + public DbTester dbTester = DbTester.create(System2.INSTANCE); + + private Languages languages; + private QProfileLookup profileLookup; + private QProfileFactory profileFactory; + private ComponentFinder componentFinder; + private ActiveRuleIndex activeRuleIndex; + private QProfileWsSupport qProfileWsSupport; + private OrganizationDto organization; + + @Before + public void before() { + organization = dbTester.organizations().insert(); + languages = new Languages(); + DbClient dbClient = dbTester.getDbClient(); + profileLookup = new QProfileLookup(dbClient); + TestDefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(dbTester); + qProfileWsSupport = new QProfileWsSupport(dbClient, null, defaultOrganizationProvider); + profileFactory = new QProfileFactory(dbClient); + componentFinder = mock(ComponentFinder.class); + } + + @Test + public void find_no_profiles_if_database_is_empty() throws Exception { + assertThat(run( + new SearchWsRequest() + )).isEmpty(); + } + + @Test + public void findAll_in_default_organization() throws Exception { + insertQualityProfile(dbTester.getDefaultOrganization()); + assertThat(run( + new SearchWsRequest() + )).hasSize(1); + } + + @Test + public void findAll_in_specific_organization() throws Exception { + insertQualityProfile(organization); + assertThat(run( + new SearchWsRequest() + .setOrganizationKey(organization.getKey()) + )).hasSize(1); + } + + @Test + public void findDefaults_in_specific_organization() throws Exception { + insertQualityProfile(organization, dto -> dto.setDefault(true)); + assertThat(run( + new SearchWsRequest() + .setOrganizationKey(organization.getKey()) + .setDefaults(true) + )).hasSize(1); + } + + @Test + public void findForProject_in_specific_organization() throws Exception { + insertQualityProfile(organization, dto -> dto.setDefault(true)); + ComponentDto project1 = insertProject(); + assertThat(run( + new SearchWsRequest() + .setOrganizationKey(organization.getKey()) + .setProjectKey(project1.getKey()) + )).hasSize(1); + } + + @Test + public void findAllForLanguage_in_specific_organization() throws Exception { + QualityProfileDto qualityProfile = insertQualityProfile(organization, dto -> dto.setDefault(true)); + assertThat(run( + new SearchWsRequest() + .setOrganizationKey(organization.getKey()) + .setLanguage(qualityProfile.getLanguage()) + )).hasSize(1); + assertThat(run( + new SearchWsRequest() + .setOrganizationKey(organization.getKey()) + .setLanguage("other language") + )).hasSize(0); + } + + private List run(SearchWsRequest request) { + return createLoader().findProfiles(dbTester.getSession(), request); + } + + private SearchDataLoader createLoader() { + return new SearchDataLoader(languages, profileLookup, profileFactory, dbTester.getDbClient(), componentFinder, activeRuleIndex, qProfileWsSupport); + } + + private QualityProfileDto insertQualityProfile(OrganizationDto organization, Consumer... specials) { + Language language = insertLanguage(); + QualityProfileDto qualityProfile = QualityProfileTesting.newQualityProfileDto() + .setOrganizationUuid(organization.getUuid()) + .setLanguage(language.getKey()); + Arrays.stream(specials) + .forEachOrdered(c -> c.accept(qualityProfile)); + dbTester.qualityProfiles().insertQualityProfile(qualityProfile); + return qualityProfile; + } + + private Language insertLanguage() { + Language language = LanguageTesting.newLanguage(randomAlphanumeric(20)); + languages.add(language); + return language; + } + + private ComponentDto insertProject() { + ComponentDto project = dbTester.components().insertProject(organization); + doReturn(project).when(componentFinder).getByKey(any(DbSession.class), eq(project.getKey())); + return project; + } +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/rule/ws/AppActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/rule/ws/AppActionTest.java index 670916f5ae5..f861a31338c 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/rule/ws/AppActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/rule/ws/AppActionTest.java @@ -61,8 +61,8 @@ public class AppActionTest { userSessionRule.addPermission(ADMINISTER_QUALITY_PROFILES, defaultOrganizationProvider.get().getUuid()); - QualityProfileDto profile1 = QProfileTesting.newXooP1("org-123"); - QualityProfileDto profile2 = QProfileTesting.newXooP2("org-123").setParentKee(QProfileTesting.XOO_P1_KEY); + QualityProfileDto profile1 = QProfileTesting.newXooP1(db.getDefaultOrganization()); + QualityProfileDto profile2 = QProfileTesting.newXooP2(db.getDefaultOrganization()).setParentKee(QProfileTesting.XOO_P1_KEY); db.getDbClient().qualityProfileDao().insert(db.getSession(), profile1); db.getDbClient().qualityProfileDao().insert(db.getSession(), profile2); db.commit(); diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/qualityprofile/SearchWsRequest.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/qualityprofile/SearchWsRequest.java index 220c6b1772c..16d82999f07 100644 --- a/sonar-ws/src/main/java/org/sonarqube/ws/client/qualityprofile/SearchWsRequest.java +++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/qualityprofile/SearchWsRequest.java @@ -23,11 +23,21 @@ import javax.annotation.CheckForNull; import javax.annotation.Nullable; public class SearchWsRequest { + private String organizationKey; private boolean defaults; private String language; private String profileName; private String projectKey; + public String getOrganizationKey() { + return organizationKey; + } + + public SearchWsRequest setOrganizationKey(String organizationKey) { + this.organizationKey = organizationKey; + return this; + } + public boolean getDefaults() { return defaults; } -- 2.39.5