Browse Source

SONAR-9304 Compress rules_profiles for built-in profiles

tags/6.5-M1
Teryk Bellahsene 7 years ago
parent
commit
93ece4c32c
100 changed files with 3127 additions and 1587 deletions
  1. 3
    0
      it/it-tests/src/test/java/it/Category4Suite.java
  2. 1
    3
      it/it-tests/src/test/java/it/Category5Suite.java
  3. 8
    2
      it/it-tests/src/test/java/it/Category6Suite.java
  4. 2
    2
      it/it-tests/src/test/java/it/issue/OrganizationIssueAssignTest.java
  5. 3
    3
      it/it-tests/src/test/java/it/organization/OrganizationMembershipTest.java
  6. 6
    4
      it/it-tests/src/test/java/it/organization/OrganizationTest.java
  7. 21
    27
      it/it-tests/src/test/java/it/organization/RootUserOnOrganizationTest.java
  8. 55
    0
      it/it-tests/src/test/java/it/organization/RootUserTest.java
  9. 2
    2
      it/it-tests/src/test/java/it/qualityProfile/OrganizationQualityProfilesPageTest.java
  10. 2
    3
      it/it-tests/src/test/java/it/rule/RulesPerOrganizationTest.java
  11. 6
    4
      it/it-tests/src/test/java/util/ItUtils.java
  12. 2
    2
      server/sonar-db-dao/src/main/java/org/sonar/db/organization/OrganizationDao.java
  13. 1
    2
      server/sonar-db-dao/src/main/java/org/sonar/db/organization/OrganizationMapper.java
  14. 46
    84
      server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/ActiveRuleDao.java
  15. 13
    9
      server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/ActiveRuleDto.java
  16. 18
    16
      server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/ActiveRuleKey.java
  17. 10
    14
      server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/ActiveRuleMapper.java
  18. 44
    0
      server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/OrgActiveRuleDto.java
  19. 79
    0
      server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/OrgQProfileDto.java
  20. 5
    5
      server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileChangeDao.java
  21. 10
    12
      server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileChangeDto.java
  22. 2
    2
      server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileChangeMapper.java
  23. 1
    1
      server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileChangeQuery.java
  24. 25
    8
      server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileDto.java
  25. 66
    46
      server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QualityProfileDao.java
  26. 9
    7
      server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QualityProfileMapper.java
  27. 131
    0
      server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/RulesProfileDto.java
  28. 5
    0
      server/sonar-db-dao/src/main/java/org/sonar/db/rule/RuleDao.java
  29. 3
    11
      server/sonar-db-dao/src/main/resources/org/sonar/db/organization/OrganizationMapper.xml
  30. 134
    102
      server/sonar-db-dao/src/main/resources/org/sonar/db/qualityprofile/ActiveRuleMapper.xml
  31. 46
    39
      server/sonar-db-dao/src/main/resources/org/sonar/db/qualityprofile/QProfileChangeMapper.xml
  32. 31
    13
      server/sonar-db-dao/src/main/resources/org/sonar/db/qualityprofile/QualityProfileMapper.xml
  33. 1
    0
      server/sonar-db-dao/src/test/java/org/sonar/db/DbTester.java
  34. 0
    14
      server/sonar-db-dao/src/test/java/org/sonar/db/organization/OrganizationDaoTest.java
  35. 149
    264
      server/sonar-db-dao/src/test/java/org/sonar/db/qualityprofile/ActiveRuleDaoTest.java
  36. 14
    31
      server/sonar-db-dao/src/test/java/org/sonar/db/qualityprofile/ActiveRuleKeyTest.java
  37. 128
    123
      server/sonar-db-dao/src/test/java/org/sonar/db/qualityprofile/QProfileChangeDaoTest.java
  38. 178
    134
      server/sonar-db-dao/src/test/java/org/sonar/db/qualityprofile/QualityProfileDaoTest.java
  39. 5
    3
      server/sonar-db-dao/src/test/java/org/sonar/db/qualityprofile/QualityProfileTesting.java
  40. 2
    2
      server/sonar-db-dao/src/test/java/org/sonar/db/rule/RuleTesting.java
  41. 4
    1
      server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v65/DbVersion65.java
  42. 110
    0
      server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v65/DeleteOrphansFromRulesProfiles.java
  43. 78
    0
      server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v65/SetRulesProfilesIsBuiltInToTrueForDefaultOrganization.java
  44. 124
    0
      server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v65/UpdateOrgQProfilesToPointToBuiltInProfiles.java
  45. 1
    1
      server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v65/DbVersion65Test.java
  46. 277
    0
      server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v65/DeleteOrphansFromRulesProfilesTest.java
  47. 158
    0
      server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v65/SetRulesProfilesIsBuiltInToTrueForDefaultOrganizationTest.java
  48. 201
    0
      server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v65/UpdateOrgQProfilesToPointToBuiltInProfilesTest.java
  49. 57
    0
      server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v65/DeleteOrphansFromRulesProfilesTest/initial.sql
  50. 34
    0
      server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v65/SetRulesProfilesIsBuiltInToTrueForDefaultOrganizationTest/initial.sql
  51. 33
    0
      server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v65/UpdateOrgQProfilesToPointToBuiltInProfilesTest/initial.sql
  52. 2
    3
      server/sonar-server/src/main/java/org/sonar/server/es/BaseDoc.java
  53. 1
    1
      server/sonar-server/src/main/java/org/sonar/server/es/BulkIndexer.java
  54. 1
    1
      server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIteratorFactory.java
  55. 33
    22
      server/sonar-server/src/main/java/org/sonar/server/organization/OrganizationCreationImpl.java
  56. 2
    7
      server/sonar-server/src/main/java/org/sonar/server/organization/ws/DeleteAction.java
  57. 2
    2
      server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java
  58. 2
    0
      server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevelStartup.java
  59. 23
    10
      server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ActiveRuleChange.java
  60. 1
    1
      server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfile.java
  61. 5
    2
      server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileInsert.java
  62. 73
    37
      server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileInsertImpl.java
  63. 2
    3
      server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileRepository.java
  64. 10
    8
      server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileRepositoryImpl.java
  65. 9
    8
      server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileBackuperImpl.java
  66. 7
    6
      server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileComparison.java
  67. 17
    18
      server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileExporters.java
  68. 43
    26
      server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileFactory.java
  69. 1
    1
      server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileLookup.java
  70. 5
    6
      server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileResetImpl.java
  71. 21
    33
      server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RegisterQualityProfiles.java
  72. 81
    107
      server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivator.java
  73. 1
    1
      server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivatorContext.java
  74. 11
    18
      server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivatorContextFactory.java
  75. 32
    37
      server/sonar-server/src/main/java/org/sonar/server/qualityprofile/index/ActiveRuleDoc.java
  76. 75
    54
      server/sonar-server/src/main/java/org/sonar/server/qualityprofile/index/ActiveRuleIndexer.java
  77. 4
    18
      server/sonar-server/src/main/java/org/sonar/server/qualityprofile/index/ActiveRuleIterator.java
  78. 48
    0
      server/sonar-server/src/main/java/org/sonar/server/qualityprofile/index/ActiveRuleIteratorFactory.java
  79. 69
    0
      server/sonar-server/src/main/java/org/sonar/server/qualityprofile/index/ActiveRuleIteratorForMultipleChunks.java
  80. 132
    0
      server/sonar-server/src/main/java/org/sonar/server/qualityprofile/index/ActiveRuleIteratorForSingleChunk.java
  81. 0
    93
      server/sonar-server/src/main/java/org/sonar/server/qualityprofile/index/ActiveRuleResultSetIterator.java
  82. 2
    2
      server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ActivateRuleAction.java
  83. 1
    1
      server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ActivateRulesAction.java
  84. 2
    2
      server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ChangeParentAction.java
  85. 1
    1
      server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ChangelogAction.java
  86. 2
    2
      server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ChangelogLoader.java
  87. 1
    1
      server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/CreateAction.java
  88. 1
    3
      server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/DeactivateRuleAction.java
  89. 1
    1
      server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/DeactivateRulesAction.java
  90. 3
    4
      server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/DeleteAction.java
  91. 1
    1
      server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ExportAction.java
  92. 3
    3
      server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/InheritanceAction.java
  93. 2
    2
      server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/SearchAction.java
  94. 11
    11
      server/sonar-server/src/main/java/org/sonar/server/rule/RegisterRules.java
  95. 7
    6
      server/sonar-server/src/main/java/org/sonar/server/rule/RuleUpdater.java
  96. 7
    11
      server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleIndex.java
  97. 20
    12
      server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleIndexDefinition.java
  98. 3
    3
      server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleIteratorForSingleChunk.java
  99. 2
    2
      server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleMetadataIterator.java
  100. 0
    0
      server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleQuery.java

+ 3
- 0
it/it-tests/src/test/java/it/Category4Suite.java View File

@@ -29,6 +29,7 @@ import it.duplication.CrossProjectDuplicationsOnRemoveFileTest;
import it.duplication.CrossProjectDuplicationsTest;
import it.duplication.DuplicationsTest;
import it.duplication.NewDuplicationsTest;
import it.organization.RootUserTest;
import it.projectEvent.EventTest;
import it.projectEvent.ProjectActivityPageTest;
import it.qualityProfile.QualityProfilesPageTest;
@@ -57,6 +58,8 @@ import static util.ItUtils.xooPlugin;

@RunWith(Suite.class)
@Suite.SuiteClasses({
// organization
RootUserTest.class,
// server system
ServerSystemTest.class,
PingTest.class,

+ 1
- 3
it/it-tests/src/test/java/it/Category5Suite.java View File

@@ -19,7 +19,6 @@
*/
package it;

import it.organization.RootTest;
import it.serverSystem.ClusterTest;
import it.serverSystem.RestartTest;
import it.serverSystem.ServerSystemRestartingOrchestrator;
@@ -46,8 +45,7 @@ import org.junit.runners.Suite;
// update center
UpdateCenterTest.class,
RealmAuthenticationTest.class,
SsoAuthenticationTest.class,
RootTest.class
SsoAuthenticationTest.class
})
public class Category5Suite {


+ 8
- 2
it/it-tests/src/test/java/it/Category6Suite.java View File

@@ -20,6 +20,7 @@
package it;

import com.sonar.orchestrator.Orchestrator;
import com.sonar.orchestrator.http.HttpMethod;
import it.issue.IssueTagsTest;
import it.issue.OrganizationIssueAssignTest;
import it.organization.BillingTest;
@@ -27,6 +28,7 @@ import it.organization.OrganizationMembershipTest;
import it.organization.OrganizationTest;
import it.projectSearch.LeakProjectsPageTest;
import it.projectSearch.SearchProjectsTest;
import it.organization.RootUserOnOrganizationTest;
import it.qualityProfile.OrganizationQualityProfilesPageTest;
import it.qualityProfile.QualityProfilesBuiltInTest;
import it.uiExtension.OrganizationUiExtensionsTest;
@@ -36,7 +38,6 @@ import org.junit.ClassRule;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;

import static java.util.Collections.emptyMap;
import static util.ItUtils.pluginArtifact;
import static util.ItUtils.xooPlugin;

@@ -50,6 +51,7 @@ import static util.ItUtils.xooPlugin;
OrganizationMembershipTest.class,
OrganizationQualityProfilesPageTest.class,
OrganizationTest.class,
RootUserOnOrganizationTest.class,
OrganizationUiExtensionsTest.class,
QualityProfilesBuiltInTest.class,
BillingTest.class,
@@ -73,6 +75,10 @@ public class Category6Suite {
}

public static void enableOrganizationsSupport() {
ORCHESTRATOR.getServer().post("api/organizations/enable_support", emptyMap());
ORCHESTRATOR.getServer()
.newHttpCall("api/organizations/enable_support")
.setMethod(HttpMethod.POST)
.setAdminCredentials()
.execute();
}
}

+ 2
- 2
it/it-tests/src/test/java/it/issue/OrganizationIssueAssignTest.java View File

@@ -50,7 +50,7 @@ import static it.Category6Suite.enableOrganizationsSupport;
import static java.lang.String.format;
import static java.util.Collections.singletonList;
import static org.assertj.core.api.Assertions.assertThat;
import static util.ItUtils.deleteOrganizationsIfExists;
import static util.ItUtils.deleteOrganizations;
import static util.ItUtils.newAdminWsClient;
import static util.ItUtils.newOrganizationKey;
import static util.ItUtils.restoreProfile;
@@ -97,7 +97,7 @@ public class OrganizationIssueAssignTest {
@After
public void tearDown() throws Exception {
userRule.deactivateUsers(ASSIGNEE_LOGIN, OTHER_LOGIN);
deleteOrganizationsIfExists(orchestrator, ORGANIZATION_KEY, OTHER_ORGANIZATION_KEY);
deleteOrganizations(orchestrator);
}

@Test

+ 3
- 3
it/it-tests/src/test/java/it/organization/OrganizationMembershipTest.java View File

@@ -44,7 +44,7 @@ import util.user.UserRule;
import static it.Category6Suite.enableOrganizationsSupport;
import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
import static org.assertj.core.api.Assertions.assertThat;
import static util.ItUtils.deleteOrganizationsIfExists;
import static util.ItUtils.deleteOrganizations;
import static util.ItUtils.newAdminWsClient;
import static util.ItUtils.newOrganizationKey;
import static util.ItUtils.newUserWsClient;
@@ -73,12 +73,12 @@ public class OrganizationMembershipTest {
adminClient = newAdminWsClient(orchestrator);
enableOrganizationsSupport();
setServerProperty(orchestrator, "sonar.organizations.anyoneCanCreate", "true");
deleteOrganizationsIfExists(orchestrator, KEY);
deleteOrganizations(orchestrator);
}

@After
public void tearDown() throws Exception {
deleteOrganizationsIfExists(orchestrator, KEY);
deleteOrganizations(orchestrator);
}

@Test

+ 6
- 4
it/it-tests/src/test/java/it/organization/OrganizationTest.java View File

@@ -58,7 +58,7 @@ import static java.util.Collections.singletonList;
import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.fail;
import static util.ItUtils.deleteOrganizationsIfExists;
import static util.ItUtils.deleteOrganizations;
import static util.ItUtils.newAdminWsClient;
import static util.ItUtils.newUserWsClient;
import static util.ItUtils.newWsClient;
@@ -95,13 +95,13 @@ public class OrganizationTest {
@Before
public void setUp() throws Exception {
resetSettings(orchestrator, null, SETTING_ANYONE_CAN_CREATE_ORGANIZATIONS);
deleteOrganizationsIfExists(orchestrator, KEY, "an-org");
deleteOrganizations(orchestrator);
userRule.deactivateUsers(USER_LOGIN);
}

@After
public void tearDown() throws Exception {
deleteOrganizationsIfExists(orchestrator, KEY, "an-org");
deleteOrganizations(orchestrator);
}

@Test
@@ -275,6 +275,7 @@ public class OrganizationTest {

@Test
public void an_organization_member_can_analyze_project() {

assertThatOrganizationDoesNotExit(KEY);

Organizations.Organization createdOrganization = adminOrganizationService.create(new CreateWsRequest.Builder()
@@ -459,13 +460,14 @@ public class OrganizationTest {
for (QualityProfiles.SearchWsResponse.QualityProfile profile : response.getProfilesList()) {
assertThat(profile.getIsInherited()).isFalse();
assertThat(profile.getProjectCount()).isEqualTo(0);
assertThat(profile.getIsBuiltIn()).isTrue();
if (profile.getName().toLowerCase(Locale.ENGLISH).contains("empty")) {
assertThat(profile.getActiveRuleCount()).isEqualTo(0);
} else {
assertThat(profile.getActiveRuleCount()).isGreaterThan(0);
// that allows to check the Elasticsearch index of active rules
Rules.SearchResponse activeRulesResponse = adminClient.rules().search(new org.sonarqube.ws.client.rule.SearchWsRequest().setActivation(true).setQProfile(profile.getKey()));
assertThat(activeRulesResponse.getTotal()).isEqualTo(profile.getActiveRuleCount());
assertThat(activeRulesResponse.getTotal()).as("profile " + profile.getName()).isEqualTo(profile.getActiveRuleCount());
assertThat(activeRulesResponse.getRulesCount()).isEqualTo((int)profile.getActiveRuleCount());
}
}

it/it-tests/src/test/java/it/organization/RootTest.java → it/it-tests/src/test/java/it/organization/RootUserOnOrganizationTest.java View File

@@ -20,55 +20,56 @@
package it.organization;

import com.sonar.orchestrator.Orchestrator;
import it.Category6Suite;
import java.sql.SQLException;
import java.util.Collections;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.sonarqube.ws.WsRoot;
import org.sonarqube.ws.client.HttpException;
import org.sonarqube.ws.client.WsClient;
import org.sonarqube.ws.client.user.SearchRequest;
import org.sonarqube.ws.client.user.UsersService;
import util.user.UserRule;

import static it.Category6Suite.enableOrganizationsSupport;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
import static util.ItUtils.newAdminWsClient;
import static util.ItUtils.newUserWsClient;
import static util.ItUtils.newWsClient;

public class RootTest {
public class RootUserOnOrganizationTest {

private static Orchestrator orchestrator;
@ClassRule
public static Orchestrator orchestrator = Category6Suite.ORCHESTRATOR;

private static UserRule userRule;

@Before
public void start() {
orchestrator = Orchestrator.builderEnv().build();
orchestrator.start();
userRule = UserRule.from(orchestrator);
}

@After
public void stop() {
if (orchestrator != null) {
orchestrator.stop();
userRule = null;
}
public void tearDown() throws Exception {
UsersService service = newAdminWsClient(orchestrator).users();
service.search(SearchRequest.builder().build()).getUsersList()
.stream()
.filter(u -> !u.getLogin().equals("admin"))
.forEach(u -> {
userRule.deactivateUsers(u.getLogin());
});
}

@Test
public void nobody_is_root_by_default() {
// anonymous
verifyHttpError(() -> newWsClient(orchestrator).rootService().search(), 403);

// admin
verifyHttpError(() -> newAdminWsClient(orchestrator).rootService().search(), 403);
@BeforeClass
public static void enableOrganizations() throws Exception {
enableOrganizationsSupport();
}

@Test
public void system_administrator_is_flagged_as_root_when_he_enables_organization_support() {
enableOrganizationSupport();
assertThat(newAdminWsClient(orchestrator).rootService().search().getRootsList())
.extracting(WsRoot.Root::getLogin)
.containsOnly(UserRule.ADMIN_LOGIN);
@@ -76,7 +77,6 @@ public class RootTest {

@Test
public void a_root_can_flag_other_user_as_root() {
enableOrganizationSupport();
userRule.createUser("bar", "foo");
userRule.setRoot("bar");

@@ -87,13 +87,11 @@ public class RootTest {

@Test
public void last_root_can_not_be_unset_root() throws SQLException {
enableOrganizationSupport();
verifyHttpError(() -> newAdminWsClient(orchestrator).rootService().unsetRoot(UserRule.ADMIN_LOGIN), 400);
}

@Test
public void root_can_be_set_and_unset_via_web_services() {
enableOrganizationSupport();
userRule.createUser("root1", "bar");
userRule.createUser("root2", "bar");
WsClient root1WsClient = newUserWsClient(orchestrator, "root1", "bar");
@@ -114,11 +112,7 @@ public class RootTest {
// root2 can unset root itself as it's not the last root
root2WsClient.rootService().unsetRoot("root2");
}

private static void enableOrganizationSupport() {
orchestrator.getServer().post("api/organizations/enable_support", Collections.emptyMap());
}

private static void verifyHttpError(Runnable runnable, int expectedErrorCode) {
try {
runnable.run();

+ 55
- 0
it/it-tests/src/test/java/it/organization/RootUserTest.java View File

@@ -0,0 +1,55 @@
/*
* 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 it.organization;

import com.sonar.orchestrator.Orchestrator;
import it.Category4Suite;
import org.junit.ClassRule;
import org.junit.Test;
import org.sonarqube.ws.client.HttpException;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
import static util.ItUtils.newAdminWsClient;
import static util.ItUtils.newWsClient;

public class RootUserTest {

@ClassRule
public static Orchestrator orchestrator = Category4Suite.ORCHESTRATOR;

@Test
public void nobody_is_root_by_default() {
// anonymous
verifyHttpError(() -> newWsClient(orchestrator).rootService().search(), 403);

// admin
verifyHttpError(() -> newAdminWsClient(orchestrator).rootService().search(), 403);
}

private static void verifyHttpError(Runnable runnable, int expectedErrorCode) {
try {
runnable.run();
fail("Ws Call should have failed with http code " + expectedErrorCode);
} catch (HttpException e) {
assertThat(e.code()).isEqualTo(expectedErrorCode);
}
}
}

+ 2
- 2
it/it-tests/src/test/java/it/qualityProfile/OrganizationQualityProfilesPageTest.java View File

@@ -37,7 +37,7 @@ import pageobjects.Navigation;

import static com.codeborne.selenide.Selenide.$;
import static it.Category6Suite.enableOrganizationsSupport;
import static util.ItUtils.deleteOrganizationsIfExists;
import static util.ItUtils.deleteOrganizations;
import static util.ItUtils.newAdminWsClient;
import static util.ItUtils.projectDir;
import static util.selenium.Selenese.runSelenese;
@@ -59,7 +59,7 @@ public class OrganizationQualityProfilesPageTest {

@AfterClass
public static void tearDown() throws Exception {
deleteOrganizationsIfExists(orchestrator, ORGANIZATION);
deleteOrganizations(orchestrator);
}

@Before

+ 2
- 3
it/it-tests/src/test/java/it/rule/RulesPerOrganizationTest.java View File

@@ -33,7 +33,7 @@ import util.ItUtils;

import static it.Category6Suite.enableOrganizationsSupport;
import static org.assertj.core.api.Assertions.assertThat;
import static util.ItUtils.deleteOrganizationsIfExists;
import static util.ItUtils.deleteOrganizations;
import static util.ItUtils.newAdminWsClient;
import static util.ItUtils.newWsClient;

@@ -56,8 +56,7 @@ public class RulesPerOrganizationTest {

@AfterClass
public static void tearDown() throws Exception {
deleteOrganizationsIfExists(orchestrator, ORGANIZATION_FOO);
deleteOrganizationsIfExists(orchestrator, ORGANIZATION_BAR);
deleteOrganizations(orchestrator);
}

private static void createOrganization(String organization) {

+ 6
- 4
it/it-tests/src/test/java/util/ItUtils.java View File

@@ -372,10 +372,12 @@ public class ItUtils {
return "key-" + randomAlphabetic(100);
}

public static void deleteOrganizationsIfExists(Orchestrator orchestrator, String... organizationKeys) {
OrganizationService adminOrganizationService = newAdminWsClient(orchestrator).organizations();
adminOrganizationService.search(SearchWsRequest.builder().setOrganizations(organizationKeys).build()).getOrganizationsList()
.forEach(organization -> adminOrganizationService.delete(organization.getKey()));
public static void deleteOrganizations(Orchestrator orchestrator) {
OrganizationService service = newAdminWsClient(orchestrator).organizations();
service.search(SearchWsRequest.builder().build()).getOrganizationsList()
.stream()
.filter(o -> !o.getGuarded())
.forEach(organization -> service.delete(organization.getKey()));
}

public static class ComponentNavigation {

+ 2
- 2
server/sonar-db-dao/src/main/java/org/sonar/db/organization/OrganizationDao.java View File

@@ -75,8 +75,8 @@ public class OrganizationDao implements Dao {
return getMapper(dbSession).selectByPermission(userId, permission);
}

public List<OrganizationDto> selectWithoutQualityProfile(DbSession dbSession, String profileLanguage, String profileName) {
return getMapper(dbSession).selectWithoutQualityProfile(profileLanguage, profileName);
public List<String> selectAllUuids(DbSession dbSession) {
return getMapper(dbSession).selectAllUuids();
}

/**

+ 1
- 2
server/sonar-db-dao/src/main/java/org/sonar/db/organization/OrganizationMapper.java View File

@@ -42,8 +42,7 @@ public interface OrganizationMapper {

List<OrganizationDto> selectByPermission(@Param("userId") Integer userId, @Param("permission") String permission);

List<OrganizationDto> selectWithoutQualityProfile(@Param("profileLanguage") String profileLanguage,
@Param("profileName") String profileName);
List<String> selectAllUuids();

DefaultTemplates selectDefaultTemplatesByUuid(@Param("uuid") String uuid);


+ 46
- 84
server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/ActiveRuleDao.java View File

@@ -19,19 +19,18 @@
*/
package org.sonar.db.qualityprofile;

import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import javax.annotation.CheckForNull;
import java.util.Optional;
import org.sonar.api.rule.RuleStatus;
import org.sonar.db.Dao;
import org.sonar.db.DatabaseUtils;
import org.sonar.db.DbSession;
import org.sonar.db.KeyLongValue;
import org.sonar.db.RowNotFoundException;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.rule.RuleParamDto;

import static org.sonar.db.DatabaseUtils.executeLargeInputs;

@@ -40,26 +39,16 @@ public class ActiveRuleDao implements Dao {
private static final String QUALITY_PROFILE_IS_NOT_PERSISTED = "Quality profile is not persisted (missing id)";
private static final String RULE_IS_NOT_PERSISTED = "Rule is not persisted";
private static final String RULE_PARAM_IS_NOT_PERSISTED = "Rule param is not persisted";
private static final String ACTIVE_RULE_KEY_CANNOT_BE_NULL = "ActiveRuleKey cannot be null";
private static final String ACTIVE_RULE_IS_NOT_PERSISTED = "ActiveRule is not persisted";
private static final String ACTIVE_RULE_IS_ALREADY_PERSISTED = "ActiveRule is already persisted";
private static final String ACTIVE_RULE_PARAM_IS_NOT_PERSISTED = "ActiveRuleParam is not persisted";
private static final String ACTIVE_RULE_PARAM_IS_ALREADY_PERSISTED = "ActiveRuleParam is already persisted";
private static final String PARAMETER_NAME_CANNOT_BE_NULL = "ParameterName cannot be null";

public Optional<ActiveRuleDto> selectByKey(DbSession session, ActiveRuleKey key) {
return Optional.fromNullable(mapper(session).selectByKey(key.qProfile(), key.ruleKey().repository(), key.ruleKey().rule()));
public Optional<ActiveRuleDto> selectByKey(DbSession dbSession, ActiveRuleKey key) {
return Optional.ofNullable(mapper(dbSession).selectByKey(key.getRuleProfileUuid(), key.getRuleKey().repository(), key.getRuleKey().rule()));
}

public ActiveRuleDto selectOrFailByKey(DbSession session, ActiveRuleKey key) {
Optional<ActiveRuleDto> activeRule = selectByKey(session, key);
if (activeRule.isPresent()) {
return activeRule.get();
}
throw new RowNotFoundException(String.format("Active rule with key '%s' does not exist", key));
}

public List<ActiveRuleDto> selectByRuleId(DbSession dbSession, OrganizationDto organization, int ruleId) {
public List<OrgActiveRuleDto> selectByRuleId(DbSession dbSession, OrganizationDto organization, int ruleId) {
return mapper(dbSession).selectByRuleId(organization.getUuid(), ruleId);
}

@@ -67,49 +56,54 @@ public class ActiveRuleDao implements Dao {
return mapper(dbSession).selectByRuleIdOfAllOrganizations(ruleId);
}

public List<ActiveRuleDto> selectByRuleIds(DbSession dbSession, String organizationUuid, List<Integer> ids) {
return executeLargeInputs(ids, chunk -> mapper(dbSession).selectByRuleIds(organizationUuid, chunk));
public List<OrgActiveRuleDto> selectByRuleIds(DbSession dbSession, OrganizationDto organization, List<Integer> ids) {
return executeLargeInputs(ids, chunk -> mapper(dbSession).selectByRuleIds(organization.getUuid(), chunk));
}

/**
* Active rule on removed rule are NOT returned
*/
public List<ActiveRuleDto> selectByProfileKey(DbSession session, String profileKey) {
return mapper(session).selectByProfileKey(profileKey);
public List<OrgActiveRuleDto> selectByProfileUuid(DbSession dbSession, String uuid) {
return mapper(dbSession).selectByProfileUuid(uuid);
}

public List<OrgActiveRuleDto> selectByProfile(DbSession dbSession, QProfileDto profile) {
return selectByProfileUuid(dbSession, profile.getKee());
}

public ActiveRuleDto insert(DbSession session, ActiveRuleDto item) {
public ActiveRuleDto insert(DbSession dbSession, ActiveRuleDto item) {
Preconditions.checkArgument(item.getProfileId() != null, QUALITY_PROFILE_IS_NOT_PERSISTED);
Preconditions.checkArgument(item.getRuleId() != null, RULE_IS_NOT_PERSISTED);
Preconditions.checkArgument(item.getId() == null, ACTIVE_RULE_IS_ALREADY_PERSISTED);
mapper(session).insert(item);
mapper(dbSession).insert(item);
return item;
}

public ActiveRuleDto update(DbSession session, ActiveRuleDto item) {
public ActiveRuleDto update(DbSession dbSession, ActiveRuleDto item) {
Preconditions.checkArgument(item.getProfileId() != null, QUALITY_PROFILE_IS_NOT_PERSISTED);
Preconditions.checkArgument(item.getRuleId() != null, ActiveRuleDao.RULE_IS_NOT_PERSISTED);
Preconditions.checkArgument(item.getId() != null, ACTIVE_RULE_IS_NOT_PERSISTED);
mapper(session).update(item);
mapper(dbSession).update(item);
return item;
}

public void delete(DbSession session, ActiveRuleKey key) {
Optional<ActiveRuleDto> activeRule = selectByKey(session, key);
public Optional<ActiveRuleDto> delete(DbSession dbSession, ActiveRuleKey key) {
Optional<ActiveRuleDto> activeRule = selectByKey(dbSession, key);
if (activeRule.isPresent()) {
mapper(session).deleteParameters(activeRule.get().getId());
mapper(session).delete(activeRule.get().getId());
mapper(dbSession).deleteParameters(activeRule.get().getId());
mapper(dbSession).delete(activeRule.get().getId());
}
return activeRule;
}

public void deleteByProfileKeys(DbSession dbSession, Collection<String> profileKeys) {
public void deleteByRuleProfileUuids(DbSession dbSession, Collection<String> rulesProfileUuids) {
ActiveRuleMapper mapper = mapper(dbSession);
DatabaseUtils.executeLargeUpdates(profileKeys, mapper::deleteByProfileKeys);
DatabaseUtils.executeLargeUpdates(rulesProfileUuids, mapper::deleteByRuleProfileUuids);
}

public void deleteParametersByProfileKeys(DbSession dbSession, Collection<String> profileKeys) {
public void deleteParametersByRuleProfileUuids(DbSession dbSession, Collection<String> rulesProfileUuids) {
ActiveRuleMapper mapper = mapper(dbSession);
DatabaseUtils.executeLargeUpdates(profileKeys, mapper::deleteParametersByProfileKeys);
DatabaseUtils.executeLargeUpdates(rulesProfileUuids, mapper::deleteParametersByRuleProfileUuids);
}

/**
@@ -123,68 +117,36 @@ public class ActiveRuleDao implements Dao {
return executeLargeInputs(activeRuleIds, mapper(dbSession)::selectParamsByActiveRuleIds);
}

@CheckForNull
public ActiveRuleParamDto selectParamByKeyAndName(ActiveRuleKey key, String name, DbSession session) {
Preconditions.checkNotNull(key, ACTIVE_RULE_KEY_CANNOT_BE_NULL);
Preconditions.checkNotNull(name, PARAMETER_NAME_CANNOT_BE_NULL);
Optional<ActiveRuleDto> activeRule = selectByKey(session, key);
if (activeRule.isPresent()) {
return mapper(session).selectParamByActiveRuleAndKey(activeRule.get().getId(), name);
}
return null;
}

/**
* @deprecated currently used only by tests
*/
@Deprecated
public List<ActiveRuleParamDto> selectAllParams(DbSession dbSession) {
return mapper(dbSession).selectAllParams();
}

public ActiveRuleParamDto insertParam(DbSession session, ActiveRuleDto activeRule, ActiveRuleParamDto activeRuleParam) {
public ActiveRuleParamDto insertParam(DbSession dbSession, ActiveRuleDto activeRule, ActiveRuleParamDto activeRuleParam) {
Preconditions.checkArgument(activeRule.getId() != null, ACTIVE_RULE_IS_NOT_PERSISTED);
Preconditions.checkArgument(activeRuleParam.getId() == null, ACTIVE_RULE_PARAM_IS_ALREADY_PERSISTED);
Preconditions.checkNotNull(activeRuleParam.getRulesParameterId(), RULE_PARAM_IS_NOT_PERSISTED);

activeRuleParam.setActiveRuleId(activeRule.getId());
mapper(session).insertParameter(activeRuleParam);
mapper(dbSession).insertParameter(activeRuleParam);
return activeRuleParam;
}

public void updateParam(DbSession session, ActiveRuleDto activeRule, ActiveRuleParamDto activeRuleParam) {
Preconditions.checkNotNull(activeRule.getId(), ACTIVE_RULE_IS_NOT_PERSISTED);
public void updateParam(DbSession dbSession, ActiveRuleParamDto activeRuleParam) {
Preconditions.checkNotNull(activeRuleParam.getId(), ACTIVE_RULE_PARAM_IS_NOT_PERSISTED);
mapper(session).updateParameter(activeRuleParam);
mapper(dbSession).updateParameter(activeRuleParam);
}

public void deleteParam(DbSession session, ActiveRuleDto activeRule, ActiveRuleParamDto activeRuleParam) {
Preconditions.checkNotNull(activeRule.getId(), ACTIVE_RULE_IS_NOT_PERSISTED);
public void deleteParam(DbSession dbSession, ActiveRuleParamDto activeRuleParam) {
Preconditions.checkNotNull(activeRuleParam.getId(), ACTIVE_RULE_PARAM_IS_NOT_PERSISTED);
deleteParamById(session, activeRuleParam.getId());
deleteParamById(dbSession, activeRuleParam.getId());
}

public void deleteParamById(DbSession session, int id) {
mapper(session).deleteParameter(id);
}

public void deleteParamByKeyAndName(DbSession session, ActiveRuleKey key, String param) {
// TODO SQL rewrite to delete by key
Optional<ActiveRuleDto> activeRule = selectByKey(session, key);
if (activeRule.isPresent()) {
ActiveRuleParamDto activeRuleParam = mapper(session).selectParamByActiveRuleAndKey(activeRule.get().getId(), param);
if (activeRuleParam != null) {
mapper(session).deleteParameter(activeRuleParam.getId());
}
}
public void deleteParamById(DbSession dbSession, int id) {
mapper(dbSession).deleteParameter(id);
}

public void deleteParamsByRuleParamOfAllOrganizations(DbSession dbSession, int ruleId, String paramKey) {
List<ActiveRuleDto> activeRules = selectByRuleIdOfAllOrganizations(dbSession, ruleId);
public void deleteParamsByRuleParamOfAllOrganizations(DbSession dbSession, RuleParamDto param) {
List<ActiveRuleDto> activeRules = selectByRuleIdOfAllOrganizations(dbSession, param.getRuleId());
for (ActiveRuleDto activeRule : activeRules) {
for (ActiveRuleParamDto activeParam : selectParamsByActiveRuleId(dbSession, activeRule.getId())) {
if (activeParam.getKey().equals(paramKey)) {
deleteParam(dbSession, activeRule, activeParam);
if (activeParam.getKey().equals(param.getName())) {
deleteParam(dbSession, activeParam);
}
}
}
@@ -193,26 +155,26 @@ public class ActiveRuleDao implements Dao {
/**
* Active rule on removed rule are NOT taken into account
*/
public Map<String, Long> countActiveRulesByProfileKey(DbSession dbSession, OrganizationDto organization) {
public Map<String, Long> countActiveRulesByProfileUuid(DbSession dbSession, OrganizationDto organization) {
return KeyLongValue.toMap(
mapper(dbSession).countActiveRulesByProfileKey(organization.getUuid()));
mapper(dbSession).countActiveRulesByProfileUuid(organization.getUuid()));
}

public Map<String, Long> countActiveRulesForRuleStatusByProfileKey(DbSession dbSession, OrganizationDto organization, RuleStatus ruleStatus) {
public Map<String, Long> countActiveRulesForRuleStatusByProfileUuid(DbSession dbSession, OrganizationDto organization, RuleStatus ruleStatus) {
return KeyLongValue.toMap(
mapper(dbSession).countActiveRulesForRuleStatusByProfileKey(organization.getUuid(), ruleStatus));
mapper(dbSession).countActiveRulesForRuleStatusByProfileUuid(organization.getUuid(), ruleStatus));
}

/**
* Active rule on removed rule are NOT taken into account
*/
public Map<String, Long> countActiveRulesForInheritanceByProfileKey(DbSession dbSession, OrganizationDto organization, String inheritance) {
public Map<String, Long> countActiveRulesForInheritanceByProfileUuid(DbSession dbSession, OrganizationDto organization, String inheritance) {
return KeyLongValue.toMap(
mapper(dbSession).countActiveRulesForInheritanceByProfileKey(organization.getUuid(), inheritance));
mapper(dbSession).countActiveRulesForInheritanceByProfileUuid(organization.getUuid(), inheritance));
}

private static ActiveRuleMapper mapper(DbSession session) {
return session.getMapper(ActiveRuleMapper.class);
private static ActiveRuleMapper mapper(DbSession dbSession) {
return dbSession.getMapper(ActiveRuleMapper.class);
}

}

+ 13
- 9
server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/ActiveRuleDto.java View File

@@ -48,17 +48,21 @@ public class ActiveRuleDto {
// These fields do not exists in db, it's only retrieve by joins
private String repository;
private String ruleField;
private String profileKey;
private String ruleProfileUuid;

public ActiveRuleDto setKey(ActiveRuleKey key) {
this.repository = key.ruleKey().repository();
this.ruleField = key.ruleKey().rule();
this.profileKey = key.qProfile();
this.repository = key.getRuleKey().repository();
this.ruleField = key.getRuleKey().rule();
this.ruleProfileUuid = key.getRuleProfileUuid();
return this;
}

public ActiveRuleKey getKey() {
return ActiveRuleKey.of(profileKey, RuleKey.of(repository, ruleField));
return new ActiveRuleKey(ruleProfileUuid, RuleKey.of(repository, ruleField));
}

public RuleKey getRuleKey() {
return RuleKey.of(repository, ruleField);
}

public Integer getId() {
@@ -142,13 +146,13 @@ public class ActiveRuleDto {
return this;
}

public static ActiveRuleDto createFor(QProfileDto profileDto, RuleDefinitionDto ruleDto) {
requireNonNull(profileDto.getId(), "Profile is not persisted");
public static ActiveRuleDto createFor(QProfileDto profile, RuleDefinitionDto ruleDto) {
requireNonNull(profile.getId(), "Profile is not persisted");
requireNonNull(ruleDto.getId(), "Rule is not persisted");
ActiveRuleDto dto = new ActiveRuleDto();
dto.setProfileId(profileDto.getId());
dto.setProfileId(profile.getId());
dto.setRuleId(ruleDto.getId());
dto.setKey(ActiveRuleKey.of(profileDto.getKee(), ruleDto.getKey()));
dto.setKey(ActiveRuleKey.of(profile, ruleDto.getKey()));
return dto;
}


+ 18
- 16
server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/ActiveRuleKey.java View File

@@ -29,21 +29,23 @@ import org.sonar.api.rule.RuleKey;
*/
public class ActiveRuleKey implements Serializable, Comparable<ActiveRuleKey> {

private final String qualityProfileKey;
private final String ruleProfileUuid;
private final RuleKey ruleKey;

protected ActiveRuleKey(String qualityProfileKey, RuleKey ruleKey) {
this.qualityProfileKey = qualityProfileKey;
protected ActiveRuleKey(String ruleProfileUuid, RuleKey ruleKey) {
this.ruleProfileUuid = ruleProfileUuid;
this.ruleKey = ruleKey;
}

/**
* Create a key. Parameters are NOT null.
*/
public static ActiveRuleKey of(String qualityProfileKey, RuleKey ruleKey) {
Preconditions.checkNotNull(qualityProfileKey, "QProfile is missing");
Preconditions.checkNotNull(ruleKey, "RuleKey is missing");
return new ActiveRuleKey(qualityProfileKey, ruleKey);
public static ActiveRuleKey of(QProfileDto profile, RuleKey ruleKey) {
return new ActiveRuleKey(profile.getRulesProfileUuid(), ruleKey);
}

public static ActiveRuleKey of(RulesProfileDto rulesProfile, RuleKey ruleKey) {
return new ActiveRuleKey(rulesProfile.getKee(), ruleKey);
}

/**
@@ -53,23 +55,23 @@ public class ActiveRuleKey implements Serializable, Comparable<ActiveRuleKey> {
public static ActiveRuleKey parse(String s) {
Preconditions.checkArgument(s.split(":").length >= 3, "Bad format of activeRule key: " + s);
int semiColonPos = s.indexOf(':');
String key = s.substring(0, semiColonPos);
String ruleProfileUuid = s.substring(0, semiColonPos);
String ruleKey = s.substring(semiColonPos + 1);
return ActiveRuleKey.of(key, RuleKey.parse(ruleKey));
return new ActiveRuleKey(ruleProfileUuid, RuleKey.parse(ruleKey));
}

/**
* Never null
*/
public RuleKey ruleKey() {
public RuleKey getRuleKey() {
return ruleKey;
}

/**
* Never null
*/
public String qProfile() {
return qualityProfileKey;
public String getRuleProfileUuid() {
return ruleProfileUuid;
}

@Override
@@ -81,7 +83,7 @@ public class ActiveRuleKey implements Serializable, Comparable<ActiveRuleKey> {
return false;
}
ActiveRuleKey activeRuleKey = (ActiveRuleKey) o;
if (!qualityProfileKey.equals(activeRuleKey.qualityProfileKey)) {
if (!ruleProfileUuid.equals(activeRuleKey.ruleProfileUuid)) {
return false;
}
return ruleKey.equals(activeRuleKey.ruleKey);
@@ -89,7 +91,7 @@ public class ActiveRuleKey implements Serializable, Comparable<ActiveRuleKey> {

@Override
public int hashCode() {
int result = qualityProfileKey.hashCode();
int result = ruleProfileUuid.hashCode();
result = 31 * result + ruleKey.hashCode();
return result;
}
@@ -99,12 +101,12 @@ public class ActiveRuleKey implements Serializable, Comparable<ActiveRuleKey> {
*/
@Override
public String toString() {
return String.format("%s:%s", qualityProfileKey, ruleKey.toString());
return String.format("%s:%s", ruleProfileUuid, ruleKey.toString());
}

@Override
public int compareTo(ActiveRuleKey o) {
int compareQualityProfileKey = this.qualityProfileKey.compareTo(o.qualityProfileKey);
int compareQualityProfileKey = this.ruleProfileUuid.compareTo(o.ruleProfileUuid);
if (compareQualityProfileKey == 0) {
return this.ruleKey.compareTo(o.ruleKey);
}

+ 10
- 14
server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/ActiveRuleMapper.java View File

@@ -34,19 +34,20 @@ public interface ActiveRuleMapper {

void delete(int activeRuleId);

void deleteByProfileKeys(@Param("profileKeys") Collection<String> profileKeys);
void deleteByRuleProfileUuids(@Param("rulesProfileUuids") Collection<String> rulesProfileUuids);

ActiveRuleDto selectByKey(@Param("profileKey") String profileKey, @Param("repository") String repository, @Param("rule") String rule);
@CheckForNull
ActiveRuleDto selectByKey(@Param("ruleProfileUuid") String ruleProfileUuid, @Param("repository") String repository, @Param("rule") String rule);

List<ActiveRuleDto> selectByKeys(@Param("keys") List<ActiveRuleKey> keys);

List<ActiveRuleDto> selectByRuleId(@Param("organizationUuid") String organizationUuid, @Param("ruleId") int ruleId);
List<OrgActiveRuleDto> selectByRuleId(@Param("organizationUuid") String organizationUuid, @Param("ruleId") int ruleId);

List<ActiveRuleDto> selectByRuleIdOfAllOrganizations(int ruleId);

List<ActiveRuleDto> selectByRuleIds(@Param("organizationUuid") String organizationUuid, @Param("ruleIds") List<Integer> partitionOfRuleIds);
List<OrgActiveRuleDto> selectByRuleIds(@Param("organizationUuid") String organizationUuid, @Param("ruleIds") List<Integer> partitionOfRuleIds);

List<ActiveRuleDto> selectByProfileKey(String key);
List<OrgActiveRuleDto> selectByProfileUuid(String uuid);

void insertParameter(ActiveRuleParamDto dto);

@@ -54,22 +55,17 @@ public interface ActiveRuleMapper {

void deleteParameters(int activeRuleId);

void deleteParametersByProfileKeys(@Param("profileKeys") Collection<String> profileKeys);
void deleteParametersByRuleProfileUuids(@Param("rulesProfileUuids") Collection<String> rulesProfileUuids);

void deleteParameter(int activeRuleParamId);

@CheckForNull
ActiveRuleParamDto selectParamByActiveRuleAndKey(@Param("activeRuleId") int activeRuleId, @Param("key") String key);

List<ActiveRuleParamDto> selectParamsByActiveRuleId(int activeRuleId);

List<ActiveRuleParamDto> selectParamsByActiveRuleIds(@Param("ids") List<Integer> ids);

List<ActiveRuleParamDto> selectAllParams();

List<KeyLongValue> countActiveRulesByProfileKey(@Param("organizationUuid") String organizationUuid);
List<KeyLongValue> countActiveRulesByProfileUuid(@Param("organizationUuid") String organizationUuid);

List<KeyLongValue> countActiveRulesForRuleStatusByProfileKey(@Param("organizationUuid") String organizationUuid, @Param("ruleStatus") RuleStatus ruleStatus);
List<KeyLongValue> countActiveRulesForRuleStatusByProfileUuid(@Param("organizationUuid") String organizationUuid, @Param("ruleStatus") RuleStatus ruleStatus);

List<KeyLongValue> countActiveRulesForInheritanceByProfileKey(@Param("organizationUuid") String organizationUuid, @Param("inheritance") String inheritance);
List<KeyLongValue> countActiveRulesForInheritanceByProfileUuid(@Param("organizationUuid") String organizationUuid, @Param("inheritance") String inheritance);
}

+ 44
- 0
server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/OrgActiveRuleDto.java View File

@@ -0,0 +1,44 @@
/*
* 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.db.qualityprofile;

public class OrgActiveRuleDto extends ActiveRuleDto {

private String organizationUuid;
private String profileUuid;

public String getOrganizationUuid() {
return organizationUuid;
}

public OrgActiveRuleDto setOrganizationUuid(String s) {
this.organizationUuid = s;
return this;
}

public String getProfileUuid() {
return profileUuid;
}

public OrgActiveRuleDto setProfileUuid(String s) {
this.profileUuid = s;
return this;
}
}

+ 79
- 0
server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/OrgQProfileDto.java View File

@@ -0,0 +1,79 @@
/*
* 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.db.qualityprofile;

import javax.annotation.CheckForNull;
import javax.annotation.Nullable;

/**
* Represents the table "org_qprofiles"
*/
public class OrgQProfileDto {

private String uuid;
private String organizationUuid;
private String rulesProfileUuid;
private String parentUuid;

public String getOrganizationUuid() {
return organizationUuid;
}

public OrgQProfileDto setOrganizationUuid(String organizationUuid) {
this.organizationUuid = organizationUuid;
return this;
}

public String getUuid() {
return uuid;
}

public OrgQProfileDto setUuid(String s) {
this.uuid = s;
return this;
}

public String getRulesProfileUuid() {
return rulesProfileUuid;
}

public OrgQProfileDto setRulesProfileUuid(String s) {
this.rulesProfileUuid = s;
return this;
}

@CheckForNull
public String getParentUuid() {
return parentUuid;
}

public OrgQProfileDto setParentUuid(@Nullable String s) {
this.parentUuid = s;
return this;
}

public static OrgQProfileDto from(QProfileDto qProfileDto) {
return new OrgQProfileDto()
.setUuid(qProfileDto.getKee())
.setOrganizationUuid(qProfileDto.getOrganizationUuid())
.setRulesProfileUuid(qProfileDto.getRulesProfileUuid())
.setParentUuid(qProfileDto.getParentKee());
}
}

+ 5
- 5
server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileChangeDao.java View File

@@ -41,7 +41,7 @@ public class QProfileChangeDao implements Dao {

public void insert(DbSession dbSession, QProfileChangeDto dto) {
checkState(dto.getCreatedAt() == 0L, "Date of QProfileChangeDto must be set by DAO only. Got %s.", dto.getCreatedAt());
dto.setKey(uuidFactory.create());
dto.setUuid(uuidFactory.create());
dto.setCreatedAt(system2.now());
mapper(dbSession).insert(dto);
}
@@ -50,13 +50,13 @@ public class QProfileChangeDao implements Dao {
return mapper(dbSession).selectByQuery(query);
}

public int countForProfileUuid(DbSession dbSession, String profileUuid) {
return mapper(dbSession).countForProfileUuid(profileUuid);
public int countForQProfileUuid(DbSession dbSession, String profileUuid) {
return mapper(dbSession).countForQProfileUuid(profileUuid);
}

public void deleteByProfileKeys(DbSession dbSession, Collection<String> profileUuids) {
public void deleteByRulesProfileUuids(DbSession dbSession, Collection<String> ruleProfileUuids) {
QProfileChangeMapper mapper = mapper(dbSession);
DatabaseUtils.executeLargeUpdates(profileUuids, mapper::deleteByProfileUuids);
DatabaseUtils.executeLargeUpdates(ruleProfileUuids, mapper::deleteByRuleProfileUuids);
}

private static QProfileChangeMapper mapper(DbSession dbSession) {

+ 10
- 12
server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileChangeDto.java View File

@@ -29,30 +29,28 @@ import org.sonar.api.utils.KeyValueFormat;

public class QProfileChangeDto {

private String key;
private String profileKey;
// can't be named "type" because it's a reserved word in Oracle
// (used by Mybatis to map DB column with DTO field)
private String uuid;
private String rulesProfileUuid;
private String changeType;
private String login;
private String data;
private long createdAt;

public String getKey() {
return key;
public String getUuid() {
return uuid;
}

public QProfileChangeDto setKey(String s) {
this.key = s;
public QProfileChangeDto setUuid(String s) {
this.uuid = s;
return this;
}

public String getProfileKey() {
return profileKey;
public String getRulesProfileUuid() {
return rulesProfileUuid;
}

public QProfileChangeDto setProfileKey(String s) {
this.profileKey = s;
public QProfileChangeDto setRulesProfileUuid(String s) {
this.rulesProfileUuid = s;
return this;
}


+ 2
- 2
server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileChangeMapper.java View File

@@ -29,7 +29,7 @@ public interface QProfileChangeMapper {

List<QProfileChangeDto> selectByQuery(@Param("query") QProfileChangeQuery query);

int countForProfileUuid(@Param("profileUuid") String profileUuid);
int countForQProfileUuid(@Param("qProfileUuid") String qProfileUuid);

void deleteByProfileUuids(@Param("profileUuids") Collection<String> profileUuids);
void deleteByRuleProfileUuids(@Param("ruleProfileUuids") Collection<String> uuids);
}

+ 1
- 1
server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileChangeQuery.java View File

@@ -26,7 +26,7 @@ import org.apache.commons.lang.builder.ToStringStyle;

import static java.util.Objects.requireNonNull;

public class QProfileChangeQuery {
public final class QProfileChangeQuery {

private final String profileUuid;
private Long fromIncluded;

+ 25
- 8
server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileDto.java View File

@@ -45,20 +45,17 @@ public class QProfileDto {
private Long lastUsed;
private Long userUpdatedAt;
private boolean isBuiltIn;
private String rulesProfileUuid;

public String getOrganizationUuid() {
return organizationUuid;
}

public QProfileDto setOrganizationUuid(String organizationUuid) {
this.organizationUuid = organizationUuid;
public QProfileDto setOrganizationUuid(String s) {
this.organizationUuid = s;
return this;
}

public QProfileDto setKey(String s) {
return setKee(s);
}

public String getKee() {
return kee;
}
@@ -68,6 +65,15 @@ public class QProfileDto {
return this;
}

public String getRulesProfileUuid() {
return rulesProfileUuid;
}

public QProfileDto setRulesProfileUuid(String s) {
this.rulesProfileUuid = s;
return this;
}

public Integer getId() {
return id;
}
@@ -148,7 +154,18 @@ public class QProfileDto {
return this;
}

public static QProfileDto createFor(String key) {
return new QProfileDto().setKee(key);
public static QProfileDto from(OrgQProfileDto org, RulesProfileDto rules) {
return new QProfileDto()
.setIsBuiltIn(rules.isBuiltIn())
.setKee(org.getUuid())
.setParentKee(org.getParentUuid())
.setOrganizationUuid(org.getOrganizationUuid())
.setId(rules.getId())
.setRulesProfileUuid(rules.getKee())
.setLanguage(rules.getLanguage())
.setName(rules.getName())
.setRulesUpdatedAt(rules.getRulesUpdatedAt())
.setLastUsed(rules.getLastUsed())
.setUserUpdatedAt(rules.getUserUpdatedAt());
}
}

+ 66
- 46
server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QualityProfileDao.java View File

@@ -19,7 +19,6 @@
*/
package org.sonar.db.qualityprofile;

import com.google.common.base.Preconditions;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
@@ -37,6 +36,7 @@ import org.sonar.db.RowNotFoundException;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.organization.OrganizationDto;

import static com.google.common.base.Preconditions.checkArgument;
import static org.sonar.db.DatabaseUtils.executeLargeInputs;
import static org.sonar.db.DatabaseUtils.executeLargeUpdates;

@@ -49,28 +49,42 @@ public class QualityProfileDao implements Dao {
}

@CheckForNull
public QProfileDto selectByUuid(DbSession session, String uuid) {
return mapper(session).selectByUuid(uuid);
public QProfileDto selectByUuid(DbSession dbSession, String uuid) {
return mapper(dbSession).selectByUuid(uuid);
}

public QProfileDto selectOrFailByUuid(DbSession session, String uuid) {
QProfileDto dto = selectByUuid(session, uuid);
public QProfileDto selectOrFailByUuid(DbSession dbSession, String uuid) {
QProfileDto dto = selectByUuid(dbSession, uuid);
if (dto == null) {
throw new RowNotFoundException("Quality profile not found: " + uuid);
}
return dto;
}

public List<QProfileDto> selectByUuids(DbSession session, List<String> uuids) {
return executeLargeInputs(uuids, mapper(session)::selectByUuids);
public List<QProfileDto> selectByUuids(DbSession dbSession, List<String> uuids) {
return executeLargeInputs(uuids, mapper(dbSession)::selectByUuids);
}

public List<QProfileDto> selectAll(DbSession session, OrganizationDto organization) {
return mapper(session).selectAll(organization.getUuid());
public List<QProfileDto> selectOrderedByOrganizationUuid(DbSession dbSession, OrganizationDto organization) {
return mapper(dbSession).selectOrderedByOrganizationUuid(organization.getUuid());
}

public void insert(DbSession session, QProfileDto profile, QProfileDto... otherProfiles) {
QualityProfileMapper mapper = mapper(session);
public List<RulesProfileDto> selectBuiltInRulesProfiles(DbSession dbSession) {
return mapper(dbSession).selectBuiltInRuleProfiles();
}

public void insert(DbSession dbSession, RulesProfileDto dto) {
QualityProfileMapper mapper = mapper(dbSession);
mapper.insertRuleProfile(dto, new Date(system.now()));
}

public void insert(DbSession dbSession, OrgQProfileDto dto) {
QualityProfileMapper mapper = mapper(dbSession);
mapper.insertOrgQProfile(dto, system.now());
}

public void insert(DbSession dbSession, QProfileDto profile, QProfileDto... otherProfiles) {
QualityProfileMapper mapper = mapper(dbSession);
doInsert(mapper, profile);
for (QProfileDto other : otherProfiles) {
doInsert(mapper, other);
@@ -78,14 +92,16 @@ public class QualityProfileDao implements Dao {
}

private void doInsert(QualityProfileMapper mapper, QProfileDto profile) {
Preconditions.checkArgument(profile.getId() == null, "Quality profile is already persisted (got id %d)", profile.getId());
checkArgument(profile.getId() == null, "Quality profile is already persisted (got id %d)", profile.getId());
long now = system.now();
mapper.insertRulesProfile(profile, new Date(now));
mapper.insertOrgQProfile(profile, now);
RulesProfileDto rulesProfile = RulesProfileDto.from(profile);
mapper.insertRuleProfile(rulesProfile, new Date(now));
mapper.insertOrgQProfile(OrgQProfileDto.from(profile), now);
profile.setId(rulesProfile.getId());
}

public void update(DbSession session, QProfileDto profile, QProfileDto... otherProfiles) {
QualityProfileMapper mapper = mapper(session);
public void update(DbSession dbSession, QProfileDto profile, QProfileDto... otherProfiles) {
QualityProfileMapper mapper = mapper(dbSession);
long now = system.now();
doUpdate(mapper, profile, now);
for (QProfileDto otherProfile : otherProfiles) {
@@ -94,55 +110,55 @@ public class QualityProfileDao implements Dao {
}

private void doUpdate(QualityProfileMapper mapper, QProfileDto profile, long now) {
mapper.updateRulesProfile(profile, new Date(now));
mapper.updateRuleProfile(profile, new Date(now));
mapper.updateOrgQProfile(profile, now);
}

public List<QProfileDto> selectDefaultProfiles(DbSession session, OrganizationDto organization, Collection<String> languages) {
return mapper(session).selectDefaultProfiles(organization.getUuid(), languages);
public List<QProfileDto> selectDefaultProfiles(DbSession dbSession, OrganizationDto organization, Collection<String> languages) {
return mapper(dbSession).selectDefaultProfiles(organization.getUuid(), languages);
}

@CheckForNull
public QProfileDto selectDefaultProfile(DbSession session, OrganizationDto organization, String language) {
return mapper(session).selectDefaultProfile(organization.getUuid(), language);
public QProfileDto selectDefaultProfile(DbSession dbSession, OrganizationDto organization, String language) {
return mapper(dbSession).selectDefaultProfile(organization.getUuid(), language);
}

@CheckForNull
public QProfileDto selectAssociatedToProjectAndLanguage(DbSession session, ComponentDto project, String language) {
return mapper(session).selectAssociatedToProjectUuidAndLanguage(project.getOrganizationUuid(), project.projectUuid(), language);
public QProfileDto selectAssociatedToProjectAndLanguage(DbSession dbSession, ComponentDto project, String language) {
return mapper(dbSession).selectAssociatedToProjectUuidAndLanguage(project.getOrganizationUuid(), project.projectUuid(), language);
}

public List<QProfileDto> selectAssociatedToProjectUuidAndLanguages(DbSession session, ComponentDto project, Collection<String> languages) {
return mapper(session).selectAssociatedToProjectUuidAndLanguages(project.getOrganizationUuid(), project.uuid(), languages);
public List<QProfileDto> selectAssociatedToProjectUuidAndLanguages(DbSession dbSession, ComponentDto project, Collection<String> languages) {
return mapper(dbSession).selectAssociatedToProjectUuidAndLanguages(project.getOrganizationUuid(), project.uuid(), languages);
}

public List<QProfileDto> selectByLanguage(DbSession dbSession, OrganizationDto organization, String language) {
return mapper(dbSession).selectByLanguage(organization.getUuid(), language);
}

public List<QProfileDto> selectChildren(DbSession session, String uuid) {
return mapper(session).selectChildren(uuid);
public List<QProfileDto> selectChildren(DbSession dbSession, QProfileDto profile) {
return mapper(dbSession).selectChildren(profile.getKee());
}

/**
* All descendants, in the top-down order.
*/
public List<QProfileDto> selectDescendants(DbSession session, String uuid) {
public List<QProfileDto> selectDescendants(DbSession dbSession, QProfileDto profile) {
List<QProfileDto> descendants = new ArrayList<>();
for (QProfileDto child : selectChildren(session, uuid)) {
for (QProfileDto child : selectChildren(dbSession, profile)) {
descendants.add(child);
descendants.addAll(selectDescendants(session, child.getKee()));
descendants.addAll(selectDescendants(dbSession, child));
}
return descendants;
}

@CheckForNull
public QProfileDto selectByNameAndLanguage(DbSession session, OrganizationDto organization, String name, String language) {
return mapper(session).selectByNameAndLanguage(organization.getUuid(), name, language);
public QProfileDto selectByNameAndLanguage(DbSession dbSession, OrganizationDto organization, String name, String language) {
return mapper(dbSession).selectByNameAndLanguage(organization.getUuid(), name, language);
}

public List<QProfileDto> selectByNameAndLanguages(DbSession session, OrganizationDto organization, String name, Collection<String> languages) {
return mapper(session).selectByNameAndLanguages(organization.getUuid(), name, languages);
public List<QProfileDto> selectByNameAndLanguages(DbSession dbSession, OrganizationDto organization, String name, Collection<String> languages) {
return mapper(dbSession).selectByNameAndLanguages(organization.getUuid(), name, languages);
}

public Map<String, Long> countProjectsByProfileUuid(DbSession dbSession, OrganizationDto organization) {
@@ -166,38 +182,42 @@ public class QualityProfileDao implements Dao {
DatabaseUtils.executeLargeUpdates(profileUuids, mapper::deleteProjectAssociationByProfileUuids);
}

public List<ProjectQprofileAssociationDto> selectSelectedProjects(DbSession session, OrganizationDto organization, QProfileDto profile, @Nullable String query) {
public List<ProjectQprofileAssociationDto> selectSelectedProjects(DbSession dbSession, OrganizationDto organization, QProfileDto profile, @Nullable String query) {
String nameQuery = sqlQueryString(query);
return mapper(session).selectSelectedProjects(organization.getUuid(), profile.getKee(), nameQuery);
return mapper(dbSession).selectSelectedProjects(organization.getUuid(), profile.getKee(), nameQuery);
}

public List<ProjectQprofileAssociationDto> selectDeselectedProjects(DbSession session, OrganizationDto organization, QProfileDto profile, @Nullable String query) {
public List<ProjectQprofileAssociationDto> selectDeselectedProjects(DbSession dbSession, OrganizationDto organization, QProfileDto profile, @Nullable String query) {
String nameQuery = sqlQueryString(query);
return mapper(session).selectDeselectedProjects(organization.getUuid(), profile.getKee(), nameQuery);
return mapper(dbSession).selectDeselectedProjects(organization.getUuid(), profile.getKee(), nameQuery);
}

public List<ProjectQprofileAssociationDto> selectProjectAssociations(DbSession session, OrganizationDto organization, QProfileDto profile, @Nullable String query) {
public List<ProjectQprofileAssociationDto> selectProjectAssociations(DbSession dbSession, OrganizationDto organization, QProfileDto profile, @Nullable String query) {
String nameQuery = sqlQueryString(query);
return mapper(session).selectProjectAssociations(organization.getUuid(), profile.getKee(), nameQuery);
return mapper(dbSession).selectProjectAssociations(organization.getUuid(), profile.getKee(), nameQuery);
}

public Collection<String> selectUuidsOfCustomRulesProfiles(DbSession dbSession, String language, String name) {
return mapper(dbSession).selectUuidsOfCustomQProfiles(language, name);
return mapper(dbSession).selectUuidsOfCustomRuleProfiles(language, name);
}

public void renameRulesProfilesAndCommit(DbSession dbSession, Collection<String> rulesProfileUuids, String newName) {
QualityProfileMapper mapper = mapper(dbSession);
Date now = new Date(system.now());
executeLargeUpdates(rulesProfileUuids, partition -> {
mapper.renameRulesProfiles(newName, now, partition);
mapper.renameRuleProfiles(newName, now, partition);
dbSession.commit();
});
}

public void deleteByUuids(DbSession dbSession, Collection<String> profileUuids) {
public void deleteOrgQProfilesByUuids(DbSession dbSession, Collection<String> profileUuids) {
QualityProfileMapper mapper = mapper(dbSession);
DatabaseUtils.executeLargeUpdates(profileUuids, mapper::deleteOrgQProfilesByUuids);
DatabaseUtils.executeLargeUpdates(profileUuids, mapper::deleteRulesProfilesByUuids);
}

public void deleteRulesProfilesByUuids(DbSession dbSession, Collection<String> rulesProfileUuids) {
QualityProfileMapper mapper = mapper(dbSession);
DatabaseUtils.executeLargeUpdates(rulesProfileUuids, mapper::deleteRuleProfilesByUuids);
}

private static String sqlQueryString(@Nullable String query) {
@@ -207,7 +227,7 @@ public class QualityProfileDao implements Dao {
return "%" + query.toUpperCase(Locale.ENGLISH) + "%";
}

private static QualityProfileMapper mapper(DbSession session) {
return session.getMapper(QualityProfileMapper.class);
private static QualityProfileMapper mapper(DbSession dbSession) {
return dbSession.getMapper(QualityProfileMapper.class);
}
}

+ 9
- 7
server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QualityProfileMapper.java View File

@@ -28,19 +28,21 @@ import org.sonar.db.KeyLongValue;

public interface QualityProfileMapper {

void insertOrgQProfile(@Param("dto") QProfileDto dto, @Param("now") long now);
void insertOrgQProfile(@Param("dto") OrgQProfileDto dto, @Param("now") long now);

void insertRulesProfile(@Param("dto") QProfileDto dto, @Param("now") Date now);
void insertRuleProfile(@Param("dto") RulesProfileDto dto, @Param("now") Date now);

void updateRulesProfile(@Param("dto") QProfileDto dto, @Param("now") Date now);
void updateRuleProfile(@Param("dto") QProfileDto dto, @Param("now") Date now);

void updateOrgQProfile(@Param("dto") QProfileDto dto, @Param("now") long now);

void deleteRulesProfilesByUuids(@Param("uuids") Collection<String> uuids);
void deleteRuleProfilesByUuids(@Param("uuids") Collection<String> uuids);

void deleteOrgQProfilesByUuids(@Param("uuids") Collection<String> uuids);

List<QProfileDto> selectAll(@Param("organizationUuid") String organizationUuid);
List<RulesProfileDto> selectBuiltInRuleProfiles();

List<QProfileDto> selectOrderedByOrganizationUuid(@Param("organizationUuid") String organizationUuid);

@CheckForNull
QProfileDto selectDefaultProfile(@Param("organizationUuid") String organizationUuid, @Param("language") String language);
@@ -116,7 +118,7 @@ public interface QualityProfileMapper {
@Param("profileUuid") String profileUuid,
@Param("nameQuery") String nameQuery);

List<String> selectUuidsOfCustomQProfiles(@Param("language") String language, @Param("name") String name);
List<String> selectUuidsOfCustomRuleProfiles(@Param("language") String language, @Param("name") String name);

void renameRulesProfiles(@Param("newName") String newName, @Param("updatedAt") Date updatedAt, @Param("uuids") Collection<String> uuids);
void renameRuleProfiles(@Param("newName") String newName, @Param("updatedAt") Date updatedAt, @Param("uuids") Collection<String> uuids);
}

+ 131
- 0
server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/RulesProfileDto.java View File

@@ -0,0 +1,131 @@
/*
* 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.db.qualityprofile;

import java.util.Date;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.sonar.core.util.UtcDateUtils;

/**
* Represents the table "rules_profiles"
*/
public class RulesProfileDto {

private Integer id;
private String kee;
private String name;
private String language;
private String rulesUpdatedAt;
private Long lastUsed;
private Long userUpdatedAt;
private boolean isBuiltIn;

public String getKee() {
return kee;
}

public RulesProfileDto setKee(String s) {
this.kee = s;
return this;
}

public Integer getId() {
return id;
}

public RulesProfileDto setId(Integer id) {
this.id = id;
return this;
}

public String getName() {
return name;
}

public RulesProfileDto setName(String name) {
this.name = name;
return this;
}

public String getLanguage() {
return language;
}

public RulesProfileDto setLanguage(String language) {
this.language = language;
return this;
}

public String getRulesUpdatedAt() {
return rulesUpdatedAt;
}

public RulesProfileDto setRulesUpdatedAt(String s) {
this.rulesUpdatedAt = s;
return this;
}

public RulesProfileDto setRulesUpdatedAtAsDate(Date d) {
this.rulesUpdatedAt = UtcDateUtils.formatDateTime(d);
return this;
}

@CheckForNull
public Long getLastUsed() {
return lastUsed;
}

public RulesProfileDto setLastUsed(@Nullable Long lastUsed) {
this.lastUsed = lastUsed;
return this;
}

@CheckForNull
public Long getUserUpdatedAt() {
return userUpdatedAt;
}

public RulesProfileDto setUserUpdatedAt(@Nullable Long userUpdatedAt) {
this.userUpdatedAt = userUpdatedAt;
return this;
}

public boolean isBuiltIn() {
return isBuiltIn;
}

public RulesProfileDto setIsBuiltIn(boolean b) {
this.isBuiltIn = b;
return this;
}

public static RulesProfileDto from(QProfileDto qProfileDto) {
return new RulesProfileDto()
.setKee(qProfileDto.getRulesProfileUuid())
.setLanguage(qProfileDto.getLanguage())
.setName(qProfileDto.getName())
.setIsBuiltIn(qProfileDto.isBuiltIn())
.setId(qProfileDto.getId())
.setLastUsed(qProfileDto.getLastUsed())
.setRulesUpdatedAt(qProfileDto.getRulesUpdatedAt())
.setUserUpdatedAt(qProfileDto.getUserUpdatedAt());
}
}

+ 5
- 0
server/sonar-db-dao/src/main/java/org/sonar/db/rule/RuleDao.java View File

@@ -88,6 +88,11 @@ public class RuleDao implements Dao {
return executeLargeInputs(ids, mapper(session)::selectDefinitionByIds);
}

public List<RuleDto> selectByKeys(DbSession session, OrganizationDto organization, Collection<RuleKey> keys) {
return ensureOrganizationIsSet(organization.getUuid(),
executeLargeInputs(keys, chunk -> mapper(session).selectByKeys(organization.getUuid(), chunk)));
}

public List<RuleDto> selectByKeys(DbSession session, String organizationUuid, Collection<RuleKey> keys) {
return ensureOrganizationIsSet(organizationUuid,
executeLargeInputs(keys, chunk -> mapper(session).selectByKeys(organizationUuid, chunk)));

+ 3
- 11
server/sonar-db-dao/src/main/resources/org/sonar/db/organization/OrganizationMapper.xml View File

@@ -129,18 +129,10 @@
and gu.user_id = #{userId,jdbcType=INTEGER}
</select>

<select id="selectWithoutQualityProfile" parameterType="map" resultType="Organization">
select
<include refid="selectColumns"/>
from organizations org
where not exists (
select 1 from rules_profiles p
inner join org_qprofiles oqp on oqp.rules_profile_uuid = p.kee
where oqp.organization_uuid = org.uuid
and p.language = #{profileLanguage, jdbcType=VARCHAR}
and p.name = #{profileName, jdbcType=VARCHAR}
)
<select id="selectAllUuids" resultType="String">
select uuid from organizations
</select>

<select id="selectDefaultGroupIdByUuid" resultType="Integer">
select org.default_group_id
from organizations org

+ 134
- 102
server/sonar-db-dao/src/main/resources/org/sonar/db/qualityprofile/ActiveRuleMapper.xml View File

@@ -3,7 +3,7 @@

<mapper namespace="org.sonar.db.qualityprofile.ActiveRuleMapper">

<sql id="activeRuleKeyColumns">
<sql id="activeRuleColumns">
a.id,
a.profile_id as "profileId",
a.rule_id as "ruleId",
@@ -11,106 +11,145 @@
a.inheritance as "inheritance",
r.plugin_rule_key as "rulefield",
r.plugin_name as "repository",
qp.kee as "profileKey",
rp.kee as "ruleProfileUuid",
a.created_at as "createdAt",
a.updated_at as "updatedAt"
</sql>

<sql id="orgActiveRuleColumns">
a.id,
a.profile_id as "profileId",
a.rule_id as "ruleId",
a.failure_level as "severity",
a.inheritance as "inheritance",
r.plugin_rule_key as "rulefield",
r.plugin_name as "repository",
rp.kee as "ruleProfileUuid",
a.created_at as "createdAt",
a.updated_at as "updatedAt",
oqp.organization_uuid as "organizationUuid",
oqp.uuid as "profileUuid"
</sql>

<sql id="activeRuleKeyJoin">
inner join rules_profiles qp on qp.id=a.profile_id
inner join org_qprofiles oqp on oqp.rules_profile_uuid = qp.kee
inner join rules_profiles rp on rp.id = a.profile_id
inner join rules r on r.id = a.rule_id
</sql>

<insert id="insert" parameterType="ActiveRule" keyColumn="id" useGeneratedKeys="true" keyProperty="id">
INSERT INTO active_rules (profile_id, rule_id, failure_level, inheritance, created_at, updated_at)
VALUES (#{profileId}, #{ruleId}, #{severity}, #{inheritance}, #{createdAt}, #{updatedAt})
insert into active_rules (
profile_id,
rule_id,
failure_level,
inheritance,
created_at,
updated_at
) values (
#{profileId, jdbcType=BIGINT},
#{ruleId, jdbcType=BIGINT},
#{severity, jdbcType=INTEGER},
#{inheritance, jdbcType=VARCHAR},
#{createdAt, jdbcType=BIGINT},
#{updatedAt, jdbcType=BIGINT}
)
</insert>

<update id="update" parameterType="ActiveRule">
UPDATE active_rules SET
failure_level=#{severity},
inheritance=#{inheritance},
updated_at=#{updatedAt}
WHERE id=#{id}
update active_rules
set
failure_level = #{severity, jdbcType=INTEGER},
inheritance = #{inheritance, jdbcType=VARCHAR},
updated_at = #{updatedAt, jdbcType=BIGINT}
where
id = #{id, jdbcType=BIGINT}
</update>

<update id="delete" parameterType="int">
DELETE FROM active_rules WHERE id=#{id}
</update>
<delete id="delete" parameterType="int">
delete from active_rules
where
id=#{id, jdbcType=BIGINT}
</delete>

<update id="deleteByProfileKeys" parameterType="String">
<delete id="deleteByRuleProfileUuids" parameterType="String">
delete from active_rules
where exists (
select 1
from rules_profiles p
where p.id = profile_id and p.kee in
<foreach collection="profileKeys" open="(" close=")" item="profileKey" separator=",">#{profileKey, jdbcType=VARCHAR}</foreach>
from rules_profiles rp
where rp.id = profile_id
and rp.kee in
<foreach collection="rulesProfileUuids" open="(" close=")" item="rulesProfileUuid" separator=",">#{rulesProfileUuid, jdbcType=VARCHAR}</foreach>
)
</update>
</delete>

<select id="selectByKey" parameterType="map" resultType="ActiveRule">
SELECT
<include refid="activeRuleKeyColumns"/>
FROM active_rules a
select
<include refid="activeRuleColumns"/>
from active_rules a
<include refid="activeRuleKeyJoin"/>
WHERE
qp.kee = #{profileKey}
AND r.plugin_rule_key = #{rule}
AND r.plugin_name = #{repository}
where
rp.kee = #{ruleProfileUuid, jdbcType=VARCHAR}
and r.plugin_rule_key = #{rule, jdbcType=VARCHAR}
and r.plugin_name = #{repository, jdbcType=VARCHAR}
</select>

<select id="selectByKeys" parameterType="map" resultType="ActiveRule">
SELECT
<include refid="activeRuleKeyColumns"/>
FROM active_rules a
select
<include refid="activeRuleColumns"/>
from active_rules a
<include refid="activeRuleKeyJoin"/>
WHERE
where
<foreach collection="keys" item="key" open="(" separator=" or " close=")">
(qp.kee = #{key.qualityProfileKey}
AND r.plugin_rule_key = #{key.ruleKey.rule}
AND r.plugin_name = #{key.ruleKey.repository}
(rp.kee = #{key.ruleProfileUuid, jdbcType=VARCHAR}
AND r.plugin_rule_key = #{key.ruleKey.rule, jdbcType=VARCHAR}
AND r.plugin_name = #{key.ruleKey.repository, jdbcType=VARCHAR}
)
</foreach>
</select>

<select id="selectByProfileKey" parameterType="string" resultType="ActiveRule">
SELECT
<include refid="activeRuleKeyColumns"/>
FROM active_rules a
INNER JOIN rules_profiles qp ON qp.id=a.profile_id
INNER JOIN rules r ON r.id = a.rule_id AND r.status != 'REMOVED'
where qp.kee=#{id}
<select id="selectByProfileUuid" parameterType="string" resultType="org.sonar.db.qualityprofile.OrgActiveRuleDto">
select
<include refid="orgActiveRuleColumns"/>
from active_rules a
inner join rules_profiles rp on rp.id = a.profile_id
inner join org_qprofiles oqp on oqp.rules_profile_uuid = rp.kee
inner join rules r on r.id = a.rule_id and r.status != 'REMOVED'
where oqp.uuid = #{id, jdbcType=VARCHAR}
</select>

<select id="selectByRuleId" parameterType="map" resultType="ActiveRule">
SELECT
<include refid="activeRuleKeyColumns"/>
FROM active_rules a
<include refid="activeRuleKeyJoin"/>
WHERE a.rule_id=#{ruleId, jdbcType=BIGINT}
AND oqp.organization_uuid=#{organizationUuid, jdbcType=VARCHAR}
<select id="selectByRuleId" parameterType="map" resultType="org.sonar.db.qualityprofile.OrgActiveRuleDto">
select
<include refid="orgActiveRuleColumns"/>
from active_rules a
inner join rules_profiles rp on rp.id = a.profile_id
inner join org_qprofiles oqp on oqp.rules_profile_uuid = rp.kee
inner join rules r on r.id = a.rule_id
where
a.rule_id = #{ruleId, jdbcType=BIGINT}
and oqp.organization_uuid = #{organizationUuid, jdbcType=VARCHAR}
</select>

<select id="selectByRuleIdOfAllOrganizations" parameterType="Integer" resultType="ActiveRule">
SELECT
<include refid="activeRuleKeyColumns"/>
FROM active_rules a
select
<include refid="activeRuleColumns"/>
from active_rules a
<include refid="activeRuleKeyJoin"/>
WHERE a.rule_id=#{ruleId}
where
a.rule_id = #{ruleId, jdbcType=BIGINT}
</select>

<select id="selectByRuleIds" parameterType="List" resultType="ActiveRule">
SELECT
<include refid="activeRuleKeyColumns"/>
FROM active_rules a
<include refid="activeRuleKeyJoin"/>
WHERE
<select id="selectByRuleIds" parameterType="List" resultType="org.sonar.db.qualityprofile.OrgActiveRuleDto">
select
<include refid="orgActiveRuleColumns"/>
from active_rules a
inner join rules_profiles rp on rp.id = a.profile_id
inner join org_qprofiles oqp on oqp.rules_profile_uuid = rp.kee
inner join rules r on r.id = a.rule_id
where
a.rule_id in
<foreach collection="ruleIds" item="ruleId" separator="," open="(" close=")">
#{ruleId}
#{ruleId, jdbcType=BIGINT}
</foreach>
AND oqp.organization_uuid=#{organizationUuid, jdbcType=VARCHAR}
and oqp.organization_uuid = #{organizationUuid, jdbcType=VARCHAR}
</select>

<!-- Parameters -->
@@ -124,43 +163,52 @@
</sql>

<insert id="insertParameter" parameterType="ActiveRuleParam" keyColumn="id" useGeneratedKeys="true" keyProperty="id">
INSERT INTO active_rule_parameters (active_rule_id, rules_parameter_id, rules_parameter_key, value)
VALUES (#{activeRuleId}, #{rulesParameterId}, #{key}, #{value})
insert into active_rule_parameters (
active_rule_id,
rules_parameter_id,
rules_parameter_key,
value
) values (
#{activeRuleId, jdbcType=BIGINT},
#{rulesParameterId, jdbcType=BIGINT},
#{key, jdbcType=VARCHAR},
#{value, jdbcType=VARCHAR}
)
</insert>

<update id="updateParameter" parameterType="ActiveRuleParam">
UPDATE active_rule_parameters SET
value=#{value}
WHERE id=#{id}
value=#{value, jdbcType=VARCHAR}
WHERE id=#{id, jdbcType=BIGINT}
</update>

<update id="deleteParameters" parameterType="int">
DELETE FROM active_rule_parameters WHERE active_rule_id=#{id}
</update>
<delete id="deleteParameters" parameterType="int">
DELETE FROM active_rule_parameters WHERE active_rule_id=#{id, jdbcType=BIGINT}
</delete>

<update id="deleteParametersByProfileKeys" parameterType="String">
<delete id="deleteParametersByRuleProfileUuids" parameterType="String">
delete from active_rule_parameters
where exists (
select 1 from active_rules ar
inner join rules_profiles p on p.id = ar.profile_id
inner join rules_profiles rp on rp.id = ar.profile_id
where ar.id = active_rule_id
and p.kee in
<foreach collection="profileKeys" open="(" close=")" item="profileKey" separator=",">
#{profileKey, jdbcType=VARCHAR}
and rp.kee in
<foreach collection="rulesProfileUuids" open="(" close=")" item="rulesProfileUuid" separator=",">
#{rulesProfileUuid, jdbcType=VARCHAR}
</foreach>
)
</update>
</delete>

<update id="deleteParameter" parameterType="int">
DELETE FROM active_rule_parameters WHERE id=#{id}
</update>
<delete id="deleteParameter" parameterType="int">
DELETE FROM active_rule_parameters WHERE id=#{id, jdbcType=BIGINT}
</delete>

<select id="selectParamsByActiveRuleId" parameterType="Integer" resultType="ActiveRuleParam">
select
<include refid="activeRuleParamColumns"/>
from active_rule_parameters p
<where>
p.active_rule_id=#{id}
p.active_rule_id=#{id, jdbcType=BIGINT}
</where>
</select>

@@ -170,51 +218,35 @@
from active_rule_parameters p
<where>
<foreach collection="ids" item="id" open="(" separator=" or " close=")">
p.active_rule_id=#{id}
p.active_rule_id=#{id, jdbcType=BIGINT}
</foreach>
</where>
</select>

<select id="selectParamByActiveRuleAndKey" parameterType="map" resultType="ActiveRuleParam">
SELECT
<include refid="activeRuleParamColumns"/>
FROM active_rule_parameters p
<where>
AND p.active_rule_id=#{activeRuleId}
AND p.rules_parameter_key=#{key}
</where>
</select>

<select id="selectAllParams" resultType="ActiveRuleParam">
select
<include refid="activeRuleParamColumns"/>
from active_rule_parameters p
</select>

<select id="countActiveRulesByProfileKey" resultType="KeyLongValue" parameterType="map">
select rp.kee as "key", count(ar.id) as "value"
<select id="countActiveRulesByProfileUuid" resultType="KeyLongValue" parameterType="map">
select oqp.uuid as "key", count(ar.id) as "value"
from active_rules ar
inner join rules_profiles rp on rp.id = ar.profile_id
inner join org_qprofiles oqp on oqp.rules_profile_uuid = rp.kee
inner join rules r on r.id = ar.rule_id
where oqp.organization_uuid = #{organizationUuid, jdbcType=VARCHAR}
and r.status != 'REMOVED'
group by rp.kee
group by oqp.uuid
</select>

<select id="countActiveRulesForRuleStatusByProfileKey" resultType="KeyLongValue" parameterType="map">
select rp.kee as "key", count(ar.id) as "value"
<select id="countActiveRulesForRuleStatusByProfileUuid" resultType="KeyLongValue" parameterType="map">
select oqp.uuid as "key", count(ar.id) as "value"
from active_rules ar
inner join rules_profiles rp on rp.id = ar.profile_id
inner join org_qprofiles oqp on oqp.rules_profile_uuid = rp.kee
inner join rules r on r.id = ar.rule_id
where oqp.organization_uuid = #{organizationUuid, jdbcType=VARCHAR}
and r.status = #{ruleStatus, jdbcType=VARCHAR}
group by rp.kee
group by oqp.uuid
</select>

<select id="countActiveRulesForInheritanceByProfileKey" resultType="KeyLongValue" parameterType="map">
select rp.kee as "key", count(ar.id) as "value"
<select id="countActiveRulesForInheritanceByProfileUuid" resultType="KeyLongValue" parameterType="map">
select oqp.uuid as "key", count(ar.id) as "value"
from active_rules ar
inner join rules_profiles rp on rp.id = ar.profile_id
inner join org_qprofiles oqp on oqp.rules_profile_uuid = rp.kee
@@ -222,7 +254,7 @@
where oqp.organization_uuid = #{organizationUuid, jdbcType=VARCHAR}
and ar.inheritance = #{inheritance, jdbcType=VARCHAR}
and r.status != 'REMOVED'
group by rp.kee
group by oqp.uuid
</select>
</mapper>


+ 46
- 39
server/sonar-db-dao/src/main/resources/org/sonar/db/qualityprofile/QProfileChangeMapper.xml View File

@@ -3,28 +3,41 @@

<mapper namespace="org.sonar.db.qualityprofile.QProfileChangeMapper">

<sql id="selectColumns">
qpc.kee as "uuid",
qpc.qprofile_key as rulesProfileUuid,
qpc.created_at as createdAt,
qpc.user_login as login,
qpc.change_type as changeType,
qpc.change_data as data
</sql>

<insert id="insert" useGeneratedKeys="false" parameterType="org.sonar.db.qualityprofile.QProfileChangeDto">
insert into qprofile_changes
(
kee,
qprofile_key,
created_at,
user_login,
change_type,
change_data
kee,
qprofile_key,
created_at,
user_login,
change_type,
change_data
) values (
#{key,jdbcType=VARCHAR},
#{profileKey,jdbcType=VARCHAR},
#{createdAt,jdbcType=BIGINT},
#{login,jdbcType=VARCHAR},
#{changeType,jdbcType=VARCHAR},
#{data,jdbcType=VARCHAR}
#{uuid, jdbcType=VARCHAR},
#{rulesProfileUuid, jdbcType=VARCHAR},
#{createdAt, jdbcType=BIGINT},
#{login, jdbcType=VARCHAR},
#{changeType, jdbcType=VARCHAR},
#{data, jdbcType=VARCHAR}
)
</insert>

<select id="countForProfileUuid" resultType="int">
select count(kee) from qprofile_changes
where qprofile_key = #{profileUuid, jdbcType=VARCHAR}
<select id="countForQProfileUuid" resultType="int">
select count(qpc.kee)
from qprofile_changes qpc
inner join rules_profiles rp on rp.kee = qpc.qprofile_key
inner join org_qprofiles oqp on oqp.rules_profile_uuid = rp.kee
where
oqp.uuid = #{qProfileUuid, jdbcType=VARCHAR}
</select>

<select id="selectByQuery" resultType="org.sonar.db.qualityprofile.QProfileChangeDto">
@@ -40,8 +53,8 @@
</select>

<select id="selectByQuery" databaseId="oracle" resultType="org.sonar.db.qualityprofile.QProfileChangeDto">
select "key", profileKey, createdAt, login, changeType, data from (
select rownum rnum, "key", profileKey, createdAt, login, changeType, data from (
select "uuid", rulesProfileUuid, createdAt, login, changeType, data from (
select rownum rnum, "uuid", rulesProfileUuid, createdAt, login, changeType, data from (
<include refid="sqlSelectByQuery" />
)
where rownum &lt;= #{query.total}
@@ -49,33 +62,27 @@
where rnum > #{query.offset}
</select>

<sql id="sqlColumns">
kee as "key",
qprofile_key as profileKey,
created_at as createdAt,
user_login as login,
change_type as changeType,
change_data as data
</sql>

<sql id="sqlSelectByQuery">
select <include refid="sqlColumns" />
from qprofile_changes
where qprofile_key = #{query.profileUuid, jdbcType=VARCHAR}
<if test="query.fromIncluded != null">
and created_at &gt;= #{query.fromIncluded}
</if>
<if test="query.toExcluded != null">
and created_at &lt; #{query.toExcluded}
</if>
order by created_at desc
select <include refid="selectColumns" />
from qprofile_changes qpc
inner join rules_profiles rp on rp.kee = qpc.qprofile_key
inner join org_qprofiles oqp on oqp.rules_profile_uuid = rp.kee
where
oqp.uuid = #{query.profileUuid, jdbcType=VARCHAR}
<if test="query.fromIncluded != null">
and qpc.created_at &gt;= #{query.fromIncluded}
</if>
<if test="query.toExcluded != null">
and qpc.created_at &lt; #{query.toExcluded}
</if>
order by qpc.created_at desc
</sql>

<delete id="deleteByProfileUuids" parameterType="String">
<delete id="deleteByRuleProfileUuids" parameterType="String">
delete from qprofile_changes
where qprofile_key in
<foreach collection="profileUuids" open="(" close=")" item="profileUuid" separator=",">
#{profileUuid, jdbcType=VARCHAR}
<foreach collection="ruleProfileUuids" open="(" close=")" item="ruleProfileUuid" separator=",">
#{ruleProfileUuid, jdbcType=VARCHAR}
</foreach>
</delete>
</mapper>

+ 31
- 13
server/sonar-db-dao/src/main/resources/org/sonar/db/qualityprofile/QualityProfileMapper.xml View File

@@ -8,6 +8,7 @@
oqp.organization_uuid as organizationUuid,
oqp.parent_uuid as parentKee,
rp.id as id,
rp.kee as rulesProfileUuid,
rp.name as name,
rp.language as language,
rp.rules_updated_at as rulesUpdatedAt,
@@ -16,7 +17,18 @@
rp.is_built_in as isBuiltIn
</sql>

<insert id="insertRulesProfile" parameterType="map" keyColumn="id" useGeneratedKeys="true" keyProperty="dto.id">
<sql id="ruleProfileColumns">
rp.id as id,
rp.kee as kee,
rp.name as name,
rp.language as language,
rp.rules_updated_at as rulesUpdatedAt,
rp.last_used as lastUsed,
rp.user_updated_at as userUpdatedAt,
rp.is_built_in as isBuiltIn
</sql>

<insert id="insertRuleProfile" parameterType="map" keyColumn="id" useGeneratedKeys="true" keyProperty="dto.id">
insert into rules_profiles (
kee,
name,
@@ -49,16 +61,16 @@
created_at,
updated_at
) values (
#{dto.kee, jdbcType=VARCHAR},
#{dto.uuid, jdbcType=VARCHAR},
#{dto.organizationUuid, jdbcType=VARCHAR},
#{dto.kee, jdbcType=VARCHAR},
#{dto.parentKee, jdbcType=VARCHAR},
#{dto.rulesProfileUuid, jdbcType=VARCHAR},
#{dto.parentUuid, jdbcType=VARCHAR},
#{now, jdbcType=BIGINT},
#{now, jdbcType=BIGINT}
)
</insert>

<update id="updateRulesProfile" parameterType="map">
<update id="updateRuleProfile" parameterType="map">
update rules_profiles
set
name = #{dto.name, jdbcType=VARCHAR},
@@ -69,7 +81,7 @@
user_updated_at = #{dto.userUpdatedAt, jdbcType=BIGINT},
is_built_in = #{dto.isBuiltIn, jdbcType=BOOLEAN}
where
kee = #{dto.kee, jdbcType=VARCHAR}
kee = #{dto.rulesProfileUuid, jdbcType=VARCHAR}
</update>

<update id="updateOrgQProfile" parameterType="map">
@@ -81,7 +93,7 @@
uuid = #{dto.kee, jdbcType=VARCHAR}
</update>

<delete id="deleteRulesProfilesByUuids" parameterType="String">
<delete id="deleteRuleProfilesByUuids" parameterType="String">
delete from rules_profiles
where kee in
<foreach collection="uuids" open="(" close=")" item="uuid" separator=",">#{uuid, jdbcType=VARCHAR}</foreach>
@@ -93,7 +105,13 @@
<foreach collection="uuids" open="(" close=")" item="uuid" separator=",">#{uuid, jdbcType=VARCHAR}</foreach>
</delete>

<select id="selectAll" parameterType="map" resultType="org.sonar.db.qualityprofile.QProfileDto">
<select id="selectBuiltInRuleProfiles" resultType="org.sonar.db.qualityprofile.RulesProfileDto">
select <include refid="ruleProfileColumns"/>
from rules_profiles rp
where rp.is_built_in = ${_true}
</select>

<select id="selectOrderedByOrganizationUuid" parameterType="map" resultType="org.sonar.db.qualityprofile.QProfileDto">
select
<include refid="qProfileColumns"/>
from org_qprofiles oqp
@@ -124,7 +142,7 @@
inner join default_qprofiles dp on dp.qprofile_uuid = oqp.uuid
where
dp.language in <foreach collection="languages" open="(" close=")" item="language" separator=",">#{language, jdbcType=VARCHAR}</foreach>
and dp.organization_uuid = #{organizationUuid, jdbcType=VARCHAR}
and dp.organization_uuid = oqp.organization_uuid
and rp.language = dp.language
and oqp.organization_uuid = #{organizationUuid, jdbcType=VARCHAR}
</select>
@@ -166,7 +184,7 @@
from org_qprofiles oqp
inner join rules_profiles rp on oqp.rules_profile_uuid = rp.kee
where
oqp.uuid in <foreach collection="uuids" open="(" close=")" item="uuid" separator=",">#{uuid}</foreach>
oqp.uuid in <foreach collection="uuids" open="(" close=")" item="uuid" separator=",">#{uuid, jdbcType=VARCHAR}</foreach>
</select>

<select id="selectByLanguage" parameterType="String" resultType="org.sonar.db.qualityprofile.QProfileDto">
@@ -300,8 +318,8 @@
ORDER BY pj.name ASC
</select>

<select id="selectUuidsOfCustomQProfiles" parameterType="map" resultType="string">
select oqp.uuid
<select id="selectUuidsOfCustomRuleProfiles" parameterType="map" resultType="string">
select oqp.rules_profile_uuid
from org_qprofiles oqp
inner join organizations o on o.uuid = oqp.organization_uuid
inner join rules_profiles rp on rp.kee = oqp.rules_profile_uuid
@@ -311,7 +329,7 @@
and rp.is_built_in = ${_false}
</select>

<update id="renameRulesProfiles" parameterType="map">
<update id="renameRuleProfiles" parameterType="map">
update rules_profiles
set
name = #{newName, jdbcType=VARCHAR},

+ 1
- 0
server/sonar-db-dao/src/test/java/org/sonar/db/DbTester.java View File

@@ -229,6 +229,7 @@ public class DbTester extends AbstractDbTester<TestDb> {
@Override
protected void after() {
if (session != null) {
session.rollback();
session.close();
}
db.stop();

+ 0
- 14
server/sonar-db-dao/src/test/java/org/sonar/db/organization/OrganizationDaoTest.java View File

@@ -41,7 +41,6 @@ import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.sonar.db.dialect.Dialect;
import org.sonar.db.dialect.Oracle;
import org.sonar.db.qualityprofile.QProfileDto;
import org.sonar.db.user.GroupDto;
import org.sonar.db.user.GroupTesting;
import org.sonar.db.user.UserDto;
@@ -873,19 +872,6 @@ public class OrganizationDaoTest {
.containsOnlyOnce(organization.getUuid());
}

@Test
public void selectWithoutQualityProfile_returns_() {
OrganizationDto orgWithoutAnyProfiles = dbTester.organizations().insert();
OrganizationDto orgWithProfiles = dbTester.organizations().insert();
QProfileDto profile = dbTester.qualityProfiles().insert(orgWithProfiles);

assertThat(underTest.selectWithoutQualityProfile(dbSession, "js", "foo"))
.extracting(OrganizationDto::getUuid).containsExactlyInAnyOrder(orgWithoutAnyProfiles.getUuid(), orgWithProfiles.getUuid());

assertThat(underTest.selectWithoutQualityProfile(dbSession, profile.getLanguage(), profile.getName()))
.extracting(OrganizationDto::getUuid).containsExactlyInAnyOrder(orgWithoutAnyProfiles.getUuid());
}

private void expectDtoCanNotBeNull() {
expectedException.expect(NullPointerException.class);
expectedException.expectMessage("OrganizationDto can't be null");

+ 149
- 264
server/sonar-db-dao/src/test/java/org/sonar/db/qualityprofile/ActiveRuleDaoTest.java View File

@@ -22,18 +22,18 @@ package org.sonar.db.qualityprofile;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.junit.After;
import java.util.Objects;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.rule.RuleStatus;
import org.sonar.api.rule.Severity;
import org.sonar.api.server.rule.RuleParamType;
import org.sonar.api.utils.System2;
import org.sonar.db.DbClient;
import org.sonar.api.utils.internal.TestSystem2;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.sonar.db.RowNotFoundException;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.organization.OrganizationTesting;
import org.sonar.db.rule.RuleDefinitionDto;
@@ -44,10 +44,8 @@ import static com.google.common.collect.Lists.newArrayList;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;
import static org.assertj.core.data.MapEntry.entry;
import static org.assertj.guava.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.sonar.api.rule.Severity.BLOCKER;
import static org.sonar.api.rule.Severity.MAJOR;
import static org.sonar.db.qualityprofile.ActiveRuleDto.INHERITED;
@@ -61,97 +59,59 @@ public class ActiveRuleDaoTest {

private static final long NOW = 10_000_000L;

private OrganizationDto organization = OrganizationTesting.newOrganizationDto();

private QProfileDto profile1 = QProfileDto.createFor("qp1").setOrganizationUuid(organization.getUuid()).setName("QProfile1");
private QProfileDto profile2 = QProfileDto.createFor("qp2").setOrganizationUuid(organization.getUuid()).setName("QProfile2");

private RuleDefinitionDto rule1 = RuleTesting.newRule(RuleTesting.XOO_X1);
private RuleDefinitionDto rule2 = RuleTesting.newRule(RuleTesting.XOO_X2);
private RuleDefinitionDto rule3 = RuleTesting.newRule(RuleTesting.XOO_X3);
private RuleDefinitionDto removedRule = RuleTesting.newRule().setStatus(RuleStatus.REMOVED);

private OrganizationDto organization;
private QProfileDto profile1;
private QProfileDto profile2;
private RuleDefinitionDto rule1;
private RuleDefinitionDto rule2;
private RuleDefinitionDto rule3;
private RuleDefinitionDto removedRule;
private RuleParamDto rule1Param1;
private RuleParamDto rule1Param2;
private RuleParamDto rule2Param1;

private System2 system = mock(System2.class);
private System2 system = new TestSystem2().setNow(NOW);

@Rule
public DbTester dbTester = DbTester.create(system);
public DbTester db = DbTester.create(system);

private DbClient dbClient = dbTester.getDbClient();
private DbSession dbSession = dbTester.getSession();
private DbSession dbSession = db.getSession();

private ActiveRuleDao underTest = dbTester.getDbClient().activeRuleDao();
private ActiveRuleDao underTest = db.getDbClient().activeRuleDao();

@Before
public void setUp() {
when(system.now()).thenReturn(NOW);

dbClient.qualityProfileDao().insert(dbSession, profile1);
dbClient.qualityProfileDao().insert(dbSession, profile2);
dbTester.rules().insert(rule1);
dbTester.rules().insert(rule2);
dbTester.rules().insert(rule3);
dbTester.rules().insert(removedRule);
organization = db.organizations().insert();
profile1 = db.qualityProfiles().insert(organization);
profile2 = db.qualityProfiles().insert(organization);
rule1 = db.rules().insert();
rule2 = db.rules().insert();
rule3 = db.rules().insert();
removedRule = db.rules().insert(r -> r.setStatus(RuleStatus.REMOVED));

rule1Param1 = new RuleParamDto()
.setName("param1")
.setDefaultValue("value1")
.setType(RuleParamType.STRING.toString());
dbClient.ruleDao().insertRuleParam(dbSession, rule1, rule1Param1);

rule1Param2 = new RuleParamDto()
.setRuleId(rule1.getId())
.setName("param2")
.setDefaultValue("2")
.setType(RuleParamType.INTEGER.toString());
dbClient.ruleDao().insertRuleParam(dbSession, rule1, rule1Param2);

rule2Param1 = new RuleParamDto()
.setRuleId(rule2.getId())
.setName("param1")
.setDefaultValue("1")
.setType(RuleParamType.INTEGER.toString());
dbClient.ruleDao().insertRuleParam(dbSession, rule2, rule2Param1);

dbSession.commit();
}

@After
public void tearDown() {
// minor optimization, no need to commit pending operations
dbSession.rollback();
rule1Param1 = db.rules().insertRuleParam(rule1);
rule1Param2 = db.rules().insertRuleParam(rule1);
rule2Param1 = db.rules().insertRuleParam(rule2);
}

@Test
public void select_by_key() {
public void selectByKey() {
ActiveRuleDto activeRule = createFor(profile1, rule1).setSeverity(BLOCKER);
underTest.insert(dbSession, activeRule);

assertThat(underTest.selectByKey(dbSession, activeRule.getKey())).isPresent();
assertThat(underTest.selectByKey(dbSession, ActiveRuleKey.of(profile2.getKee(), rule2.getKey()))).isAbsent();
}

@Test
public void select_or_fail_by_key() {
ActiveRuleDto activeRule = createFor(profile1, rule1).setSeverity(BLOCKER);
underTest.insert(dbSession, activeRule);

assertThat(underTest.selectOrFailByKey(dbSession, activeRule.getKey())).isNotNull();

thrown.expect(RowNotFoundException.class);
thrown.expectMessage("Active rule with key 'qp2:xoo:x2' does not exist");
underTest.selectOrFailByKey(dbSession, ActiveRuleKey.of(profile2.getKee(), rule2.getKey()));
assertThat(underTest.selectByKey(dbSession, ActiveRuleKey.of(profile2, rule2.getKey()))).isEmpty();
}

@Test
public void select_by_rule() {
ActiveRuleDto activeRule1 = createFor(profile1, rule1).setSeverity(BLOCKER);
ActiveRuleDto activeRule2 = createFor(profile2, rule1).setSeverity(BLOCKER);
underTest.insert(dbTester.getSession(), activeRule1);
underTest.insert(dbTester.getSession(), activeRule2);
underTest.insert(dbSession, activeRule1);
underTest.insert(dbSession, activeRule2);
dbSession.commit();

assertThat(underTest.selectByRuleId(dbSession, organization, rule1.getId())).extracting("key").containsOnly(activeRule1.getKey(), activeRule2.getKey());
@@ -168,31 +128,34 @@ public class ActiveRuleDaoTest {
underTest.insert(dbSession, activeRule3);
dbSession.commit();

assertThat(underTest.selectByRuleIds(dbSession, organization.getUuid(), Collections.singletonList(rule1.getId())))
assertThat(underTest.selectByRuleIds(dbSession, organization, Collections.singletonList(rule1.getId())))
.extracting("key").containsOnly(activeRule1.getKey(), activeRule3.getKey());
assertThat(underTest.selectByRuleIds(dbSession, organization.getUuid(), newArrayList(rule1.getId(), rule2.getId())))
assertThat(underTest.selectByRuleIds(dbSession, organization, newArrayList(rule1.getId(), rule2.getId())))
.extracting("key").containsOnly(activeRule1.getKey(), activeRule2.getKey(), activeRule3.getKey());
}

@Test
public void select_by_profile() {
public void selectByProfile() {
ActiveRuleDto activeRule1 = createFor(profile1, rule1).setSeverity(BLOCKER);
ActiveRuleDto activeRule2 = createFor(profile1, rule2).setSeverity(BLOCKER);
underTest.insert(dbTester.getSession(), activeRule1);
underTest.insert(dbTester.getSession(), activeRule2);
dbSession.commit();
underTest.insert(dbSession, activeRule1);
underTest.insert(dbSession, activeRule2);

assertThat(underTest.selectByProfileKey(dbSession, profile1.getKee())).hasSize(2);
assertThat(underTest.selectByProfileKey(dbSession, profile2.getKee())).isEmpty();
List<OrgActiveRuleDto> result = underTest.selectByProfile(dbSession, profile1);
assertThat(result)
.hasSize(2)
.extracting(OrgActiveRuleDto::getOrganizationUuid, OrgActiveRuleDto::getProfileUuid, OrgActiveRuleDto::getProfileId)
.containsOnly(tuple(organization.getUuid(), profile1.getKee(), profile1.getId()));

assertThat(underTest.selectByProfile(dbSession, profile2)).isEmpty();
}

@Test
public void select_by_profile_ignore_removed_rules() throws Exception {
public void selectByProfileUuid_ignores_removed_rules() throws Exception {
ActiveRuleDto activeRule = createFor(profile1, removedRule).setSeverity(BLOCKER);
underTest.insert(dbTester.getSession(), activeRule);
dbSession.commit();
underTest.insert(dbSession, activeRule);

assertThat(underTest.selectByProfileKey(dbSession, profile1.getKee())).isEmpty();
assertThat(underTest.selectByProfile(dbSession, profile1)).isEmpty();
}

@Test
@@ -202,12 +165,12 @@ public class ActiveRuleDaoTest {
.setInheritance(INHERITED)
.setCreatedAt(1000L)
.setUpdatedAt(2000L);
underTest.insert(dbTester.getSession(), activeRule);
underTest.insert(dbSession, activeRule);
dbSession.commit();

ActiveRuleDto result = underTest.selectOrFailByKey(dbSession, activeRule.getKey());
ActiveRuleDto result = underTest.selectByKey(dbSession, activeRule.getKey()).get();
assertThat(result.getId()).isEqualTo(activeRule.getId());
assertThat(result.getKey()).isEqualTo(ActiveRuleKey.of(profile1.getKee(), rule1.getKey()));
assertThat(result.getKey()).isEqualTo(ActiveRuleKey.of(profile1, rule1.getKey()));
assertThat(result.getRuleId()).isEqualTo(rule1.getId());
assertThat(result.getProfileId()).isEqualTo(profile1.getId());
assertThat(result.getSeverityString()).isEqualTo(BLOCKER);
@@ -221,7 +184,7 @@ public class ActiveRuleDaoTest {
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("Quality profile is not persisted (missing id)");

underTest.insert(dbTester.getSession(), createFor(profile1, rule1).setProfileId(null));
underTest.insert(dbSession, createFor(profile1, rule1).setProfileId(null));
}

@Test
@@ -229,7 +192,7 @@ public class ActiveRuleDaoTest {
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("Rule is not persisted");

underTest.insert(dbTester.getSession(), createFor(profile1, rule1).setRuleId(null));
underTest.insert(dbSession, createFor(profile1, rule1).setRuleId(null));
}

@Test
@@ -237,7 +200,7 @@ public class ActiveRuleDaoTest {
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("ActiveRule is already persisted");

underTest.insert(dbTester.getSession(), createFor(profile1, rule1).setId(100));
underTest.insert(dbSession, createFor(profile1, rule1).setId(100));
}

@Test
@@ -247,7 +210,7 @@ public class ActiveRuleDaoTest {
.setInheritance(INHERITED)
.setCreatedAt(1000L)
.setUpdatedAt(2000L);
underTest.insert(dbTester.getSession(), activeRule);
underTest.insert(dbSession, activeRule);
dbSession.commit();

ActiveRuleDto activeRuleUpdated = activeRule
@@ -256,12 +219,12 @@ public class ActiveRuleDaoTest {
// created at should not be updated
.setCreatedAt(3000L)
.setUpdatedAt(4000L);
underTest.update(dbTester.getSession(), activeRuleUpdated);
underTest.update(dbSession, activeRuleUpdated);
dbSession.commit();

ActiveRuleDto result = underTest.selectOrFailByKey(dbSession, ActiveRuleKey.of(profile1.getKee(), rule1.getKey()));
ActiveRuleDto result = underTest.selectByKey(dbSession, ActiveRuleKey.of(profile1, rule1.getKey())).get();
assertThat(result.getId()).isEqualTo(activeRule.getId());
assertThat(result.getKey()).isEqualTo(ActiveRuleKey.of(profile1.getKee(), rule1.getKey()));
assertThat(result.getKey()).isEqualTo(ActiveRuleKey.of(profile1, rule1.getKey()));
assertThat(result.getRuleId()).isEqualTo(rule1.getId());
assertThat(result.getProfileId()).isEqualTo(profile1.getId());
assertThat(result.getSeverityString()).isEqualTo(MAJOR);
@@ -275,7 +238,7 @@ public class ActiveRuleDaoTest {
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("Quality profile is not persisted (missing id)");

underTest.update(dbTester.getSession(), createFor(profile1, rule1).setId(100).setProfileId(null));
underTest.update(dbSession, createFor(profile1, rule1).setId(100).setProfileId(null));
}

@Test
@@ -283,7 +246,7 @@ public class ActiveRuleDaoTest {
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("Rule is not persisted");

underTest.update(dbTester.getSession(), createFor(profile1, rule1).setId(100).setRuleId(null));
underTest.update(dbSession, createFor(profile1, rule1).setId(100).setRuleId(null));
}

@Test
@@ -291,7 +254,7 @@ public class ActiveRuleDaoTest {
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("ActiveRule is not persisted");

underTest.update(dbTester.getSession(), createFor(profile1, rule1).setId(null));
underTest.update(dbSession, createFor(profile1, rule1).setId(null));
}

@Test
@@ -305,33 +268,33 @@ public class ActiveRuleDaoTest {

underTest.delete(dbSession, activeRule.getKey());

assertThat(underTest.selectByKey(dbSession, ActiveRuleKey.of(profile1.getKee(), rule1.getKey()))).isAbsent();
assertThat(underTest.selectByKey(dbSession, ActiveRuleKey.of(profile1, rule1.getKey()))).isEmpty();
}

@Test
public void delete_does_not_fail_when_active_rule_does_not_exist() {
underTest.delete(dbSession, ActiveRuleKey.of(profile1.getKee(), rule1.getKey()));
underTest.delete(dbSession, ActiveRuleKey.of(profile1, rule1.getKey()));
}

@Test
public void deleteByKeys_deletes_rows_from_table() {
public void deleteByRuleProfileUuids_deletes_rows_from_table() {
underTest.insert(dbSession, newRow(profile1, rule1));
underTest.insert(dbSession, newRow(profile1, rule2));
underTest.insert(dbSession, newRow(profile2, rule1));

underTest.deleteByProfileKeys(dbSession, asList(profile1.getKee()));
underTest.deleteByRuleProfileUuids(dbSession, asList(profile1.getRulesProfileUuid()));

assertThat(dbTester.countRowsOfTable(dbSession, "active_rules")).isEqualTo(1);
assertThat(underTest.selectByKey(dbSession, ActiveRuleKey.of(profile2.getKee(), rule1.getKey()))).isPresent();
assertThat(db.countRowsOfTable(dbSession, "active_rules")).isEqualTo(1);
assertThat(underTest.selectByKey(dbSession, ActiveRuleKey.of(profile2, rule1.getKey()))).isPresent();
}

@Test
public void deleteByKeys_does_not_fail_when_profile_with_specified_key_does_not_exist() {
public void deleteByRuleProfileUuids_does_not_fail_when_rules_profile_with_specified_key_does_not_exist() {
underTest.insert(dbSession, newRow(profile1, rule1));

underTest.deleteByProfileKeys(dbSession, asList("does_not_exist"));
underTest.deleteByRuleProfileUuids(dbSession, asList("does_not_exist"));

assertThat(dbTester.countRowsOfTable(dbSession, "active_rules")).isEqualTo(1);
assertThat(db.countRowsOfTable(dbSession, "active_rules")).isEqualTo(1);
}

private static ActiveRuleDto newRow(QProfileDto profile, RuleDefinitionDto rule) {
@@ -341,7 +304,7 @@ public class ActiveRuleDaoTest {
@Test
public void select_params_by_active_rule_id() {
ActiveRuleDto activeRule = createFor(profile1, rule1).setSeverity(BLOCKER);
underTest.insert(dbTester.getSession(), activeRule);
underTest.insert(dbSession, activeRule);
ActiveRuleParamDto activeRuleParam1 = ActiveRuleParamDto.createFor(rule1Param1);
underTest.insertParam(dbSession, activeRule, activeRuleParam1);
ActiveRuleParamDto activeRuleParam2 = ActiveRuleParamDto.createFor(rule1Param2);
@@ -354,12 +317,12 @@ public class ActiveRuleDaoTest {
@Test
public void select_params_by_active_rule_ids() {
ActiveRuleDto activeRule1 = createFor(profile1, rule1).setSeverity(BLOCKER);
underTest.insert(dbTester.getSession(), activeRule1);
underTest.insert(dbSession, activeRule1);
underTest.insertParam(dbSession, activeRule1, ActiveRuleParamDto.createFor(rule1Param1));
underTest.insertParam(dbSession, activeRule1, ActiveRuleParamDto.createFor(rule1Param2));

ActiveRuleDto activeRule2 = createFor(profile1, rule2).setSeverity(BLOCKER);
underTest.insert(dbTester.getSession(), activeRule2);
underTest.insert(dbSession, activeRule2);
underTest.insertParam(dbSession, activeRule2, ActiveRuleParamDto.createFor(rule2Param1));
dbSession.commit();

@@ -367,100 +330,70 @@ public class ActiveRuleDaoTest {
}

@Test
public void select_param_by_key_and_name() {
ActiveRuleDto activeRule = createFor(profile1, rule1).setSeverity(BLOCKER);
underTest.insert(dbTester.getSession(), activeRule);
ActiveRuleParamDto activeRuleParam1 = ActiveRuleParamDto.createFor(rule1Param1).setValue("activeValue1");
underTest.insertParam(dbSession, activeRule, activeRuleParam1);
underTest.insertParam(dbSession, activeRule, ActiveRuleParamDto.createFor(rule1Param2));
dbSession.commit();

assertThat(underTest.selectParamByKeyAndName(activeRule.getKey(), activeRuleParam1.getKey(), dbSession)).isNotNull();

assertThat(underTest.selectParamByKeyAndName(activeRule.getKey(), "unknown", dbSession)).isNull();
assertThat(underTest.selectParamByKeyAndName(ActiveRuleKey.of(profile2.getKee(), rule1.getKey()), "unknown", dbSession)).isNull();
}

@Test
public void select_all_params() {
ActiveRuleDto activeRule1 = createFor(profile1, rule1).setSeverity(BLOCKER);
underTest.insert(dbTester.getSession(), activeRule1);
underTest.insertParam(dbSession, activeRule1, ActiveRuleParamDto.createFor(rule1Param1));
underTest.insertParam(dbSession, activeRule1, ActiveRuleParamDto.createFor(rule1Param2));

ActiveRuleDto activeRule2 = createFor(profile1, rule2).setSeverity(BLOCKER);
underTest.insert(dbTester.getSession(), activeRule2);
underTest.insertParam(dbSession, activeRule2, ActiveRuleParamDto.createFor(rule2Param1));
dbSession.commit();

assertThat(underTest.selectAllParams(dbSession)).hasSize(3);
}

@Test
public void insert_param() {
ActiveRuleDto activeRule = createFor(profile1, rule1).setSeverity(BLOCKER);
underTest.insert(dbTester.getSession(), activeRule);
ActiveRuleParamDto activeRuleParam1 = ActiveRuleParamDto.createFor(rule1Param1).setValue("activeValue1");
underTest.insertParam(dbSession, activeRule, activeRuleParam1);
dbSession.commit();
public void insertParam() {
ActiveRuleDto activeRule = createFor(profile1, rule1).setSeverity(Severity.CRITICAL);
underTest.insert(dbSession, activeRule);

ActiveRuleParamDto result = underTest.selectParamByKeyAndName(activeRule.getKey(), activeRuleParam1.getKey(), dbSession);
assertThat(result).isNotNull();
ActiveRuleParamDto activeRuleParam = ActiveRuleParamDto.createFor(rule1Param1).setValue("foo");
underTest.insertParam(dbSession, activeRule, activeRuleParam);

assertThat(result.getId()).isEqualTo(activeRuleParam1.getId());
assertThat(result.getKey()).isEqualTo(activeRuleParam1.getKey());
assertThat(result.getActiveRuleId()).isEqualTo(activeRule.getId());
assertThat(result.getRulesParameterId()).isEqualTo(rule1Param1.getId());
assertThat(result.getValue()).isEqualTo("activeValue1");
List<ActiveRuleParamDto> reloaded = underTest.selectParamsByActiveRuleId(dbSession, activeRule.getId());
assertThat(reloaded).hasSize(1);
assertThat(reloaded.get(0))
.matches(p -> Objects.equals(p.getId(), activeRuleParam.getId()))
.matches(p -> p.getKey().equals(activeRuleParam.getKey()))
.matches(p -> p.getActiveRuleId().equals(activeRule.getId()))
.matches(p -> p.getRulesParameterId().equals(rule1Param1.getId()))
.matches(p -> p.getValue().equals("foo"));
}

@Test
public void fail_to_insert_param_when_active_rule_id_is_null() {
public void insertParam_fails_when_active_rule_id_is_null() {
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("ActiveRule is not persisted");

underTest.insertParam(dbTester.getSession(),
underTest.insertParam(dbSession,
createFor(profile1, rule1).setId(null),
ActiveRuleParamDto.createFor(rule1Param1).setValue("activeValue1"));
}

@Test
public void fail_to_insert_param_when_active_rule_param_id_is_null() {
public void insertParam_fails_when_active_rule_param_id_is_null() {
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("ActiveRuleParam is already persisted");

underTest.insertParam(dbTester.getSession(),
underTest.insertParam(dbSession,
createFor(profile1, rule1).setId(100),
ActiveRuleParamDto.createFor(rule1Param1).setValue("activeValue1").setId(100));
}

@Test
public void fail_to_insert_param_when_id_is_not_null() {
public void insertParam_fails_when_id_is_not_null() {
thrown.expect(NullPointerException.class);
thrown.expectMessage("Rule param is not persisted");

underTest.insertParam(dbTester.getSession(),
underTest.insertParam(dbSession,
createFor(profile1, rule1).setId(100),
ActiveRuleParamDto.createFor(rule1Param1).setValue("activeValue1").setRulesParameterId(null));
}

@Test
public void update_param() {
ActiveRuleDto activeRule = createFor(profile1, rule1).setSeverity(BLOCKER);
underTest.insert(dbTester.getSession(), activeRule);
ActiveRuleParamDto activeRuleParam1 = ActiveRuleParamDto.createFor(rule1Param1).setValue("activeValue");
underTest.insertParam(dbSession, activeRule, activeRuleParam1);
dbSession.commit();
public void updateParam() {
ActiveRuleDto activeRule = createFor(profile1, rule1).setSeverity(Severity.CRITICAL);
underTest.insert(dbSession, activeRule);
ActiveRuleParamDto activeRuleParam = ActiveRuleParamDto.createFor(rule1Param1).setValue("foo");
underTest.insertParam(dbSession, activeRule, activeRuleParam);

underTest.updateParam(dbSession, activeRule, activeRuleParam1.setValue("updatedActiveValue"));
dbSession.commit();
underTest.updateParam(dbSession, activeRuleParam.setValue("bar"));

ActiveRuleParamDto result = underTest.selectParamByKeyAndName(activeRule.getKey(), activeRuleParam1.getKey(), dbSession);
assertThat(result.getId()).isEqualTo(activeRuleParam1.getId());
assertThat(result.getKey()).isEqualTo(activeRuleParam1.getKey());
assertThat(result.getActiveRuleId()).isEqualTo(activeRule.getId());
assertThat(result.getRulesParameterId()).isEqualTo(rule1Param1.getId());
assertThat(result.getValue()).isEqualTo("updatedActiveValue");
List<ActiveRuleParamDto> reloaded = underTest.selectParamsByActiveRuleId(dbSession, activeRule.getId());
assertThat(reloaded).hasSize(1);
assertThat(reloaded.get(0))
.matches(p -> Objects.equals(p.getId(), activeRuleParam.getId()))
.matches(p -> p.getKey().equals(activeRuleParam.getKey()))
.matches(p -> p.getActiveRuleId().equals(activeRule.getId()))
.matches(p -> p.getRulesParameterId().equals(rule1Param1.getId()))
.matches(p -> p.getValue().equals("bar"));
}

@Test
@@ -470,13 +403,13 @@ public class ActiveRuleDaoTest {
ActiveRuleParamDto param = ActiveRuleParamDto.createFor(rule1Param1).setValue("foo");
underTest.insertParam(dbSession, activeRule, param);

underTest.deleteParam(dbSession, activeRule, param);
underTest.deleteParam(dbSession, param);

assertThat(underTest.selectParamByKeyAndName(activeRule.getKey(), param.getKey(), dbSession)).isNull();
assertThat(underTest.selectParamsByActiveRuleId(dbSession, activeRule.getId())).hasSize(0);
}

@Test
public void deleteParametersByProfileKeys_deletes_rows_by_profile_keys() {
public void deleteParametersByRuleProfileUuids_deletes_rows_by_rule_profile_uuids() {
ActiveRuleDto activeRuleInProfile1 = newRow(profile1, rule1);
underTest.insert(dbSession, activeRuleInProfile1);
ActiveRuleParamDto param1 = ActiveRuleParamDto.createFor(rule1Param1).setValue("foo");
@@ -486,102 +419,54 @@ public class ActiveRuleDaoTest {
ActiveRuleParamDto param2 = ActiveRuleParamDto.createFor(rule1Param1).setValue("bar");
underTest.insertParam(dbSession, activeRuleInProfile2, param2);

underTest.deleteParametersByProfileKeys(dbSession, asList(profile1.getKee(), "does_not_exist"));
underTest.deleteParametersByRuleProfileUuids(dbSession, asList(profile1.getRulesProfileUuid(), "does_not_exist"));

List<ActiveRuleParamDto> params = underTest.selectAllParams(dbSession);
assertThat(params).hasSize(1);
assertThat(params.get(0).getActiveRuleId()).isEqualTo(activeRuleInProfile2.getId());
assertThat(underTest.selectParamsByActiveRuleId(dbSession, activeRuleInProfile1.getId())).isEmpty();
assertThat(underTest.selectParamsByActiveRuleId(dbSession, activeRuleInProfile2.getId()))
.extracting(ActiveRuleParamDto::getKey, ActiveRuleParamDto::getValue)
.containsExactly(tuple(rule1Param1.getName(), "bar"));
}

@Test
public void deleteParametersByProfileKeys_does_nothing_if_keys_are_empty() {
public void deleteParametersByRuleProfileUuids_does_nothing_if_keys_are_empty() {
ActiveRuleDto activeRuleInProfile1 = newRow(profile1, rule1);
underTest.insert(dbSession, activeRuleInProfile1);
ActiveRuleParamDto param1 = ActiveRuleParamDto.createFor(rule1Param1).setValue("foo");
underTest.insertParam(dbSession, activeRuleInProfile1, param1);

underTest.deleteParametersByProfileKeys(dbSession, emptyList());

List<ActiveRuleParamDto> params = underTest.selectAllParams(dbSession);
assertThat(params).hasSize(1);
assertThat(params.get(0).getActiveRuleId()).isEqualTo(activeRuleInProfile1.getId());
}

@Test
public void deleteParamByKeyAndName_deletes_rows_by_key_and_name() {
ActiveRuleDto activeRule = createFor(profile1, rule1).setSeverity(BLOCKER);
underTest.insert(dbTester.getSession(), activeRule);
ActiveRuleParamDto activeRuleParam1 = ActiveRuleParamDto.createFor(rule1Param1).setValue("activeValue1");
underTest.insertParam(dbSession, activeRule, activeRuleParam1);
dbSession.commit();

underTest.deleteParamByKeyAndName(dbSession, activeRule.getKey(), rule1Param1.getName());
dbSession.commit();
underTest.deleteParametersByRuleProfileUuids(dbSession, emptyList());

assertThat(underTest.selectParamByKeyAndName(activeRule.getKey(), activeRuleParam1.getKey(), dbSession)).isNull();
assertThat(underTest.selectParamsByActiveRuleId(dbSession, activeRuleInProfile1.getId()))
.hasSize(1);
}

@Test
public void does_not_fail_to_delete_param_by_key_and_name_when_active_rule_does_not_exist() {
underTest.deleteParamByKeyAndName(dbSession, ActiveRuleKey.of(profile1.getKee(), rule1.getKey()), rule1Param1.getName());
}

@Test
public void does_not_fail_to_delete_param_by_key_and_name_when_active_rule_param_does_not_exist() {
ActiveRuleDto activeRule = createFor(profile1, rule1).setSeverity(BLOCKER);
underTest.insert(dbTester.getSession(), activeRule);
ActiveRuleParamDto activeRuleParam1 = ActiveRuleParamDto.createFor(rule1Param1).setValue("activeValue1");
underTest.insertParam(dbSession, activeRule, activeRuleParam1);
dbSession.commit();

underTest.deleteParamByKeyAndName(dbSession, activeRule.getKey(), "unknown");
}

@Test
public void delete_param_by_rule_param() {
public void deleteParamsByRuleParamOfAllOrganizations() {
ActiveRuleDto activeRule1 = createFor(profile1, rule1).setSeverity(BLOCKER);
underTest.insert(dbTester.getSession(), activeRule1);
ActiveRuleParamDto activeRuleParam1 = ActiveRuleParamDto.createFor(rule1Param1).setValue("activeValue1");
underTest.insert(dbSession, activeRule1);
ActiveRuleParamDto activeRuleParam1 = ActiveRuleParamDto.createFor(rule1Param1).setValue("foo");
underTest.insertParam(dbSession, activeRule1, activeRuleParam1);

ActiveRuleDto activeRule2 = createFor(profile2, rule1).setSeverity(BLOCKER);
underTest.insert(dbTester.getSession(), activeRule2);
ActiveRuleParamDto activeRuleParam2 = ActiveRuleParamDto.createFor(rule1Param1).setValue("activeValue2");
underTest.insert(dbSession, activeRule2);
ActiveRuleParamDto activeRuleParam2 = ActiveRuleParamDto.createFor(rule1Param1).setValue("bar");
underTest.insertParam(dbSession, activeRule2, activeRuleParam2);

dbSession.commit();
List<Integer> activeRuleIds = asList(activeRule1.getId(), activeRule2.getId());
assertThat(underTest.selectParamsByActiveRuleIds(dbSession, activeRuleIds)).hasSize(2);

underTest.deleteParamsByRuleParamOfAllOrganizations(dbSession, rule1.getId(), rule1Param1.getName());
dbSession.commit();

assertThat(underTest.selectParamByKeyAndName(activeRule1.getKey(), activeRuleParam1.getKey(), dbSession)).isNull();
assertThat(underTest.selectParamByKeyAndName(activeRule2.getKey(), activeRuleParam2.getKey(), dbSession)).isNull();
}

@Test
public void does_not_fail_to_delete_param_by_rule_param_when_active_param_name_not_found() {
ActiveRuleDto activeRule1 = createFor(profile1, rule1).setSeverity(BLOCKER);
underTest.insert(dbTester.getSession(), activeRule1);
ActiveRuleParamDto activeRuleParam1 = ActiveRuleParamDto.createFor(rule1Param1).setValue("activeValue1");
underTest.insertParam(dbSession, activeRule1, activeRuleParam1);

ActiveRuleDto activeRule2 = createFor(profile2, rule1).setSeverity(BLOCKER);
underTest.insert(dbTester.getSession(), activeRule2);
ActiveRuleParamDto activeRuleParam2 = ActiveRuleParamDto.createFor(rule1Param1).setValue("activeValue2");
underTest.insertParam(dbSession, activeRule2, activeRuleParam2);

dbSession.commit();
underTest.deleteParamsByRuleParamOfAllOrganizations(dbSession, rule1Param1);

underTest.deleteParamsByRuleParamOfAllOrganizations(dbSession, rule1.getId(), "unknown");
assertThat(underTest.selectParamsByActiveRuleIds(dbSession, activeRuleIds)).isEmpty();
}

@Test
public void test_countActiveRulesByProfileKey_for_a_specified_organization() {
dbTester.qualityProfiles().activateRule(profile1, rule1);
dbTester.qualityProfiles().activateRule(profile1, rule2);
dbTester.qualityProfiles().activateRule(profile2, rule1);
db.qualityProfiles().activateRule(profile1, rule1);
db.qualityProfiles().activateRule(profile1, rule2);
db.qualityProfiles().activateRule(profile2, rule1);

Map<String, Long> counts = underTest.countActiveRulesByProfileKey(dbSession, organization);
Map<String, Long> counts = underTest.countActiveRulesByProfileUuid(dbSession, organization);

assertThat(counts).containsOnly(
entry(profile1.getKee(), 2L),
@@ -590,86 +475,86 @@ public class ActiveRuleDaoTest {

@Test
public void countActiveRulesByProfileKey_returns_empty_map_if_organization_does_not_exist() {
Map<String, Long> counts = underTest.countActiveRulesByProfileKey(dbSession, OrganizationTesting.newOrganizationDto());
Map<String, Long> counts = underTest.countActiveRulesByProfileUuid(dbSession, OrganizationTesting.newOrganizationDto());

assertThat(counts).isEmpty();
}

@Test
public void countActiveRulesByProfileKey_returns_empty_map_if_profile_does_not_have_active_rules() {
Map<String, Long> counts = underTest.countActiveRulesByProfileKey(dbSession, organization);
Map<String, Long> counts = underTest.countActiveRulesByProfileUuid(dbSession, organization);

assertThat(counts).isEmpty();
}

@Test
public void countActiveRulesByProfileKey_ignores_removed_rules() {
dbTester.qualityProfiles().activateRule(profile1, rule1);
dbTester.qualityProfiles().activateRule(profile1, removedRule);
db.qualityProfiles().activateRule(profile1, rule1);
db.qualityProfiles().activateRule(profile1, removedRule);

Map<String, Long> counts = underTest.countActiveRulesByProfileKey(dbSession, organization);
Map<String, Long> counts = underTest.countActiveRulesByProfileUuid(dbSession, organization);

assertThat(counts).containsExactly(entry(profile1.getKee(), 1L));
}

@Test
public void test_countActiveRulesForRuleStatusByProfileKey_for_a_specified_organization() {
RuleDefinitionDto betaRule1 = dbTester.rules().insertRule(RuleTesting.newRuleDto().setStatus(RuleStatus.BETA)).getDefinition();
RuleDefinitionDto betaRule2 = dbTester.rules().insertRule(RuleTesting.newRuleDto().setStatus(RuleStatus.BETA)).getDefinition();
dbTester.qualityProfiles().activateRule(profile1, rule1);
dbTester.qualityProfiles().activateRule(profile2, betaRule1);
dbTester.qualityProfiles().activateRule(profile2, betaRule2);
RuleDefinitionDto betaRule1 = db.rules().insertRule(RuleTesting.newRuleDto().setStatus(RuleStatus.BETA)).getDefinition();
RuleDefinitionDto betaRule2 = db.rules().insertRule(RuleTesting.newRuleDto().setStatus(RuleStatus.BETA)).getDefinition();
db.qualityProfiles().activateRule(profile1, rule1);
db.qualityProfiles().activateRule(profile2, betaRule1);
db.qualityProfiles().activateRule(profile2, betaRule2);

Map<String, Long> counts = underTest.countActiveRulesForRuleStatusByProfileKey(dbSession, organization, RuleStatus.BETA);
Map<String, Long> counts = underTest.countActiveRulesForRuleStatusByProfileUuid(dbSession, organization, RuleStatus.BETA);

assertThat(counts).containsOnly(entry(profile2.getKee(), 2L));
}

@Test
public void countActiveRulesForRuleStatusByProfileKey_returns_empty_map_if_organization_does_not_exist() {
Map<String, Long> counts = underTest.countActiveRulesForRuleStatusByProfileKey(dbSession, OrganizationTesting.newOrganizationDto(), RuleStatus.READY);
Map<String, Long> counts = underTest.countActiveRulesForRuleStatusByProfileUuid(dbSession, OrganizationTesting.newOrganizationDto(), RuleStatus.READY);

assertThat(counts).isEmpty();
}

@Test
public void countActiveRulesForRuleStatusByProfileKey_returns_empty_map_if_profile_does_not_have_rules_with_specified_status() {
Map<String, Long> counts = underTest.countActiveRulesForRuleStatusByProfileKey(dbSession, organization, RuleStatus.DEPRECATED);
Map<String, Long> counts = underTest.countActiveRulesForRuleStatusByProfileUuid(dbSession, organization, RuleStatus.DEPRECATED);

assertThat(counts).isEmpty();
}

@Test
public void test_countActiveRulesForInheritanceByProfileKey_for_a_specified_organization() {
dbTester.qualityProfiles().activateRule(profile1, rule1);
dbTester.qualityProfiles().activateRule(profile2, rule1, ar -> ar.setInheritance(ActiveRuleDto.OVERRIDES));
dbTester.qualityProfiles().activateRule(profile2, rule2, ar -> ar.setInheritance(ActiveRuleDto.INHERITED));
db.qualityProfiles().activateRule(profile1, rule1);
db.qualityProfiles().activateRule(profile2, rule1, ar -> ar.setInheritance(ActiveRuleDto.OVERRIDES));
db.qualityProfiles().activateRule(profile2, rule2, ar -> ar.setInheritance(ActiveRuleDto.INHERITED));

Map<String, Long> counts = underTest.countActiveRulesForInheritanceByProfileKey(dbSession, organization, ActiveRuleDto.OVERRIDES);
Map<String, Long> counts = underTest.countActiveRulesForInheritanceByProfileUuid(dbSession, organization, ActiveRuleDto.OVERRIDES);

assertThat(counts).containsOnly(entry(profile2.getKee(), 1L));
}

@Test
public void countActiveRulesForInheritanceByProfileKey_returns_empty_map_if_organization_does_not_exist() {
Map<String, Long> counts = underTest.countActiveRulesForInheritanceByProfileKey(dbSession, OrganizationTesting.newOrganizationDto(), ActiveRuleDto.OVERRIDES);
Map<String, Long> counts = underTest.countActiveRulesForInheritanceByProfileUuid(dbSession, OrganizationTesting.newOrganizationDto(), ActiveRuleDto.OVERRIDES);

assertThat(counts).isEmpty();
}

@Test
public void countActiveRulesForInheritanceByProfileKey_returns_empty_map_if_profile_does_not_have_rules_with_specified_status() {
Map<String, Long> counts = underTest.countActiveRulesForInheritanceByProfileKey(dbSession, organization, ActiveRuleDto.OVERRIDES);
Map<String, Long> counts = underTest.countActiveRulesForInheritanceByProfileUuid(dbSession, organization, ActiveRuleDto.OVERRIDES);

assertThat(counts).isEmpty();
}

@Test
public void countActiveRulesForInheritanceByProfileKey_ignores_removed_rules() {
dbTester.qualityProfiles().activateRule(profile1, rule1, ar -> ar.setInheritance(ActiveRuleDto.OVERRIDES));
dbTester.qualityProfiles().activateRule(profile1, removedRule, ar -> ar.setInheritance(ActiveRuleDto.OVERRIDES));
db.qualityProfiles().activateRule(profile1, rule1, ar -> ar.setInheritance(ActiveRuleDto.OVERRIDES));
db.qualityProfiles().activateRule(profile1, removedRule, ar -> ar.setInheritance(ActiveRuleDto.OVERRIDES));

Map<String, Long> counts = underTest.countActiveRulesForInheritanceByProfileKey(dbSession, organization, ActiveRuleDto.OVERRIDES);
Map<String, Long> counts = underTest.countActiveRulesForInheritanceByProfileUuid(dbSession, organization, ActiveRuleDto.OVERRIDES);

assertThat(counts).containsOnly(entry(profile1.getKee(), 1L));
}

+ 14
- 31
server/sonar-db-dao/src/test/java/org/sonar/db/qualityprofile/ActiveRuleKeyTest.java View File

@@ -24,53 +24,36 @@ import org.sonar.api.rule.RuleKey;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.fail;
import static org.sonar.db.qualityprofile.QualityProfileTesting.newQualityProfileDto;

public class ActiveRuleKeyTest {

@Test
public void of() {
RuleKey ruleKey = RuleKey.of("xoo", "R1");
ActiveRuleKey key = ActiveRuleKey.of("P1", ruleKey);
assertThat(key.qProfile()).isEqualTo("P1");
assertThat(key.ruleKey()).isSameAs(ruleKey);
assertThat(key.toString()).isEqualTo("P1:xoo:R1");
QProfileDto profile = newQualityProfileDto();
ActiveRuleKey key = ActiveRuleKey.of(profile, ruleKey);
assertThat(key.getRuleProfileUuid()).isEqualTo(profile.getRulesProfileUuid());
assertThat(key.getRuleKey()).isSameAs(ruleKey);
assertThat(key.toString()).isEqualTo(profile.getRulesProfileUuid() + ":xoo:R1");
}

@Test
public void rule_key_can_contain_colons() {
RuleKey ruleKey = RuleKey.of("squid", "Key:With:Some::Colons");
ActiveRuleKey key = ActiveRuleKey.of("P1", ruleKey);
assertThat(key.qProfile()).isEqualTo("P1");
assertThat(key.ruleKey()).isSameAs(ruleKey);
assertThat(key.toString()).isEqualTo("P1:squid:Key:With:Some::Colons");
}

@Test
public void profile_must_not_be_null() {
try {
ActiveRuleKey.of(null, RuleKey.of("xoo", "R1"));
fail();
} catch (NullPointerException e) {
assertThat(e).hasMessage("QProfile is missing");
}
}

@Test
public void rule_key_must_not_be_null() {
try {
ActiveRuleKey.of("P1", null);
fail();
} catch (NullPointerException e) {
assertThat(e).hasMessage("RuleKey is missing");
}
QProfileDto profile = newQualityProfileDto();
ActiveRuleKey key = ActiveRuleKey.of(profile, ruleKey);
assertThat(key.getRuleProfileUuid()).isEqualTo(profile.getRulesProfileUuid());
assertThat(key.getRuleKey()).isSameAs(ruleKey);
assertThat(key.toString()).isEqualTo(profile.getRulesProfileUuid() + ":squid:Key:With:Some::Colons");
}

@Test
public void parse() {
ActiveRuleKey key = ActiveRuleKey.parse("P1:xoo:R1");
assertThat(key.qProfile()).isEqualTo("P1");
assertThat(key.ruleKey().repository()).isEqualTo("xoo");
assertThat(key.ruleKey().rule()).isEqualTo("R1");
assertThat(key.getRuleProfileUuid()).isEqualTo("P1");
assertThat(key.getRuleKey().repository()).isEqualTo("xoo");
assertThat(key.getRuleKey().rule()).isEqualTo("R1");
}

@Test

+ 128
- 123
server/sonar-db-dao/src/test/java/org/sonar/db/qualityprofile/QProfileChangeDaoTest.java View File

@@ -26,66 +26,53 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.utils.System2;
import org.sonar.api.utils.internal.AlwaysIncreasingSystem2;
import org.sonar.core.util.SequenceUuidFactory;
import org.sonar.core.util.UuidFactory;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;

import static java.util.Arrays.asList;
import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class QProfileChangeDaoTest {

private static final long A_DATE = 1_500_000_000_000L;

private System2 system2 = mock(System2.class);
private System2 system2 = new AlwaysIncreasingSystem2();

@Rule
public ExpectedException expectedException = ExpectedException.none();

@Rule
public DbTester dbTester = DbTester.create(system2);
public DbTester db = DbTester.create(system2);

private DbSession dbSession = dbTester.getSession();
private UuidFactory uuidFactory = mock(UuidFactory.class);
private DbSession dbSession = db.getSession();
private UuidFactory uuidFactory = new SequenceUuidFactory();
private QProfileChangeDao underTest = new QProfileChangeDao(system2, uuidFactory);

@Test
public void test_insert_without_null_fields() {
when(system2.now()).thenReturn(A_DATE);
when(uuidFactory.create()).thenReturn("C1");

String profileKey = "P1";
String login = "marcel";
String type = "ACTIVATED";
String data = "some_data";
insertChange(profileKey, type, login, data);
public void insert() {
QProfileChangeDto dto = insertChange("P1", "ACTIVATED", "marcel", "some_data");

Map<String, Object> row = selectChangeByKey("C1");
assertThat(row.get("qprofileKey")).isEqualTo(profileKey);
assertThat(row.get("createdAt")).isEqualTo(A_DATE);
assertThat(row.get("login")).isEqualTo(login);
assertThat(row.get("changeType")).isEqualTo(type);
assertThat(row.get("changeData")).isEqualTo(data);
verifyInserted(dto);
}

/**
* user_login and data can be null
*/
@Test
public void test_insert_with_nullable_fields() {
when(system2.now()).thenReturn(A_DATE);
when(uuidFactory.create()).thenReturn("C1");
public void test_insert_with_null_fields() {
QProfileChangeDto dto = insertChange("P1", "ACTIVATED", null, null);

insertChange("P1", "ACTIVATED", null, null);
verifyInserted(dto);
}

Map<String, Object> row = selectChangeByKey("C1");
assertThat(row.get("qprofileKey")).isEqualTo("P1");
assertThat(row.get("createdAt")).isEqualTo(A_DATE);
assertThat(row.get("changeType")).isEqualTo("ACTIVATED");
assertThat(row.get("login")).isNull();
assertThat(row.get("changeData")).isNull();
private void verifyInserted(QProfileChangeDto dto) {
QProfileChangeDto reloaded = selectChangeByUuid(dto.getUuid());
assertThat(reloaded.getUuid()).isEqualTo(dto.getUuid());
assertThat(reloaded.getChangeType()).isEqualTo(dto.getChangeType());
assertThat(reloaded.getData()).isEqualTo(dto.getData());
assertThat(reloaded.getLogin()).isEqualTo(dto.getLogin());
assertThat(reloaded.getRulesProfileUuid()).isEqualTo(dto.getRulesProfileUuid());
assertThat(reloaded.getCreatedAt()).isPositive();
}

@Test
@@ -97,151 +84,169 @@ public class QProfileChangeDaoTest {
}

@Test
public void selectByQuery_returns_empty_list_if_no_profile_changes() {
public void selectByQuery_returns_empty_list_if_profile_does_not_exist() {
List<QProfileChangeDto> changes = underTest.selectByQuery(dbSession, new QProfileChangeQuery("P1"));

assertThat(changes).isEmpty();
}

@Test
public void selectByQuery_returns_changes_ordered_by_descending_date() {
when(system2.now()).thenReturn(A_DATE, A_DATE + 1, A_DATE + 2);
when(uuidFactory.create()).thenReturn("C1", "C2", "C3");
QProfileDto profile1 = db.qualityProfiles().insert(db.getDefaultOrganization());
QProfileDto profile2 = db.qualityProfiles().insert(db.getDefaultOrganization());

// profile P1
insertChange("P1", "ACTIVATED", null, null);// key: C1
insertChange("P1", "ACTIVATED", null, null);// key: C2
// profile P2: C3
insertChange("P2", "ACTIVATED", null, null);// key: C3
QProfileChangeDto change1OnP1 = insertChange(profile1, "ACTIVATED", null, null);
QProfileChangeDto change2OnP1 = insertChange(profile1, "ACTIVATED", null, null);
QProfileChangeDto changeOnP2 = insertChange(profile2, "ACTIVATED", null, null);

List<QProfileChangeDto> changes = underTest.selectByQuery(dbSession, new QProfileChangeQuery("P1"));
assertThat(changes).extracting(QProfileChangeDto::getKey).containsExactly("C2", "C1");
List<QProfileChangeDto> changes = underTest.selectByQuery(dbSession, new QProfileChangeQuery(profile1.getKee()));
assertThat(changes)
.extracting(QProfileChangeDto::getUuid)
.containsExactly(change2OnP1.getUuid(), change1OnP1.getUuid());
}

@Test
public void selectByQuery_supports_pagination_of_changes() {
when(system2.now()).thenReturn(A_DATE, A_DATE + 10, A_DATE + 20, A_DATE + 30);
when(uuidFactory.create()).thenReturn("C1", "C2", "C3", "C4");
insertChange("P1", "ACTIVATED", null, null);// key: C1
insertChange("P1", "ACTIVATED", null, null);// key: C2
insertChange("P1", "ACTIVATED", null, null);// key: C3
insertChange("P1", "ACTIVATED", null, null);// key: C4

QProfileChangeQuery query = new QProfileChangeQuery("P1");
QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization());
QProfileChangeDto change1 = insertChange(profile, "ACTIVATED", null, null);
QProfileChangeDto change2 = insertChange(profile, "ACTIVATED", null, null);
QProfileChangeDto change3 = insertChange(profile, "ACTIVATED", null, null);
QProfileChangeDto change4 = insertChange(profile, "ACTIVATED", null, null);

QProfileChangeQuery query = new QProfileChangeQuery(profile.getKee());
query.setOffset(2);
query.setLimit(1);
List<QProfileChangeDto> changes = underTest.selectByQuery(dbSession, query);
assertThat(changes).extracting(QProfileChangeDto::getKey).containsExactly("C2");
assertThat(changes)
.extracting(QProfileChangeDto::getUuid)
.containsExactly(change2.getUuid());
}

@Test
public void selectByQuery_returns_changes_after_given_date() {
when(system2.now()).thenReturn(A_DATE, A_DATE + 10, A_DATE + 20);
when(uuidFactory.create()).thenReturn("C1", "C2", "C3", "C4");
insertChange("P1", "ACTIVATED", null, null);// key: C1
insertChange("P1", "ACTIVATED", null, null);// key: C2
insertChange("P1", "ACTIVATED", null, null);// key: C3

QProfileChangeQuery query = new QProfileChangeQuery("P1");
query.setFromIncluded(A_DATE + 10);
List<QProfileChangeDto> changes = underTest.selectByQuery(dbSession, query);
assertThat(changes).extracting(QProfileChangeDto::getKey).containsExactly("C3", "C2");
QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization());
QProfileChangeDto change1 = insertChange(profile, "ACTIVATED", null, null);
QProfileChangeDto change2 = insertChange(profile, "ACTIVATED", null, null);
QProfileChangeDto change3 = insertChange(profile, "ACTIVATED", null, null);

QProfileChangeQuery query = new QProfileChangeQuery(profile.getKee());
query.setFromIncluded(change1.getCreatedAt() + 1);

assertThat(underTest.selectByQuery(dbSession, query))
.extracting(QProfileChangeDto::getUuid)
.containsExactly(change3.getUuid(), change2.getUuid());
}

@Test
public void selectByQuery_returns_changes_before_given_date() {
when(system2.now()).thenReturn(A_DATE, A_DATE + 10, A_DATE + 20);
when(uuidFactory.create()).thenReturn("C1", "C2", "C3", "C4");
insertChange("P1", "ACTIVATED", null, null);// key: C1
insertChange("P1", "ACTIVATED", null, null);// key: C2
insertChange("P1", "ACTIVATED", null, null);// key: C3

QProfileChangeQuery query = new QProfileChangeQuery("P1");
query.setToExcluded(A_DATE + 12);
List<QProfileChangeDto> changes = underTest.selectByQuery(dbSession, query);
assertThat(changes).extracting(QProfileChangeDto::getKey).containsExactly("C2", "C1");
QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization());
QProfileChangeDto change1 = insertChange(profile, "ACTIVATED", null, null);
QProfileChangeDto change2 = insertChange(profile, "ACTIVATED", null, null);
QProfileChangeDto change3 = insertChange(profile, "ACTIVATED", null, null);

QProfileChangeQuery query = new QProfileChangeQuery(profile.getKee());
query.setToExcluded(change2.getCreatedAt() + 1);

assertThat(underTest.selectByQuery(dbSession, query))
.extracting(QProfileChangeDto::getUuid)
.containsExactly(change2.getUuid(), change1.getUuid());
}

@Test
public void selectByQuery_returns_changes_in_a_range_of_dates() {
when(system2.now()).thenReturn(A_DATE, A_DATE + 10, A_DATE + 20, A_DATE + 30);
when(uuidFactory.create()).thenReturn("C1", "C2", "C3", "C4");
insertChange("P1", "ACTIVATED", null, null);// key: C1
insertChange("P1", "ACTIVATED", null, null);// key: C2
insertChange("P1", "ACTIVATED", null, null);// key: C3
insertChange("P1", "ACTIVATED", null, null);// key: C4

QProfileChangeQuery query = new QProfileChangeQuery("P1");
query.setFromIncluded(A_DATE + 8);
query.setToExcluded(A_DATE + 22);
List<QProfileChangeDto> changes = underTest.selectByQuery(dbSession, query);
assertThat(changes).extracting(QProfileChangeDto::getKey).containsExactly("C3", "C2");
QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization());
QProfileChangeDto change1 = insertChange(profile, "ACTIVATED", null, null);
QProfileChangeDto change2 = insertChange(profile, "ACTIVATED", null, null);
QProfileChangeDto change3 = insertChange(profile, "ACTIVATED", null, null);
QProfileChangeDto change4 = insertChange(profile, "ACTIVATED", null, null);

QProfileChangeQuery query = new QProfileChangeQuery(profile.getKee());
query.setFromIncluded(change1.getCreatedAt() + 1);
query.setToExcluded(change4.getCreatedAt());

assertThat(underTest.selectByQuery(dbSession, query))
.extracting(QProfileChangeDto::getUuid)
.containsExactly(change3.getUuid(), change2.getUuid());
}

@Test
public void selectByQuery_mapping() {
when(system2.now()).thenReturn(A_DATE);
when(uuidFactory.create()).thenReturn("C1");
insertChange("P1", "ACTIVATED", "Oscar", "data");
public void test_selectByQuery_mapping() {
QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization());
QProfileChangeDto inserted = insertChange(profile, "ACTIVATED", "theLogin", "theData");

List<QProfileChangeDto> result = underTest.selectByQuery(dbSession, new QProfileChangeQuery("P1"));
List<QProfileChangeDto> result = underTest.selectByQuery(dbSession, new QProfileChangeQuery(profile.getKee()));

assertThat(result).hasSize(1);
QProfileChangeDto change = result.get(0);
assertThat(change.getProfileKey()).isEqualTo("P1");
assertThat(change.getLogin()).isEqualTo("Oscar");
assertThat(change.getData()).isEqualTo("data");
assertThat(change.getChangeType()).isEqualTo("ACTIVATED");
assertThat(change.getKey()).isEqualTo("C1");
assertThat(change.getCreatedAt()).isEqualTo(A_DATE);
assertThat(change.getRulesProfileUuid()).isEqualTo(inserted.getRulesProfileUuid());
assertThat(change.getLogin()).isEqualTo(inserted.getLogin());
assertThat(change.getData()).isEqualTo(inserted.getData());
assertThat(change.getChangeType()).isEqualTo(inserted.getChangeType());
assertThat(change.getUuid()).isEqualTo(inserted.getUuid());
assertThat(change.getCreatedAt()).isEqualTo(inserted.getCreatedAt());
}

@Test
public void test_countForProfileKey() {
when(system2.now()).thenReturn(A_DATE, A_DATE + 10);
when(uuidFactory.create()).thenReturn("C1", "C2");

insertChange("P1", "ACTIVATED", null, null);// key: C1
insertChange("P1", "ACTIVATED", null, null);// key: C2

assertThat(underTest.countForProfileUuid(dbSession, "P1")).isEqualTo(2);
assertThat(underTest.countForProfileUuid(dbSession, "P2")).isEqualTo(0);
public void countForQProfileUuid() {
QProfileDto profile1 = db.qualityProfiles().insert(db.getDefaultOrganization());
QProfileDto profile2 = db.qualityProfiles().insert(db.getDefaultOrganization());
insertChange(profile1, "ACTIVATED", null, null);
insertChange(profile1, "ACTIVATED", null, null);
insertChange(profile2, "ACTIVATED", null, null);

assertThat(underTest.countForQProfileUuid(dbSession, profile1.getKee())).isEqualTo(2);
assertThat(underTest.countForQProfileUuid(dbSession, profile2.getKee())).isEqualTo(1);
assertThat(underTest.countForQProfileUuid(dbSession, "does_not_exist")).isEqualTo(0);
}

@Test
public void deleteByProfileKeys_deletes_rows_with_specified_keys() {
when(uuidFactory.create()).thenReturn("C1", "C2", "C3");
insertChange("P1", "ACTIVATED", null, null);// key: C1
insertChange("P1", "ACTIVATED", null, null);// key: C2
insertChange("P2", "ACTIVATED", null, null);// key: C3
public void deleteByRulesProfileUuids() {
QProfileDto profile1 = db.qualityProfiles().insert(db.getDefaultOrganization());
QProfileDto profile2 = db.qualityProfiles().insert(db.getDefaultOrganization());
insertChange(profile1, "ACTIVATED", null, null);
insertChange(profile1, "ACTIVATED", null, null);
insertChange(profile2, "ACTIVATED", null, null);

underTest.deleteByProfileKeys(dbSession, asList("P1"));
underTest.deleteByRulesProfileUuids(dbSession, asList(profile1.getRulesProfileUuid()));

assertThat(underTest.countForProfileUuid(dbSession, "P1")).isEqualTo(0);
assertThat(underTest.countForProfileUuid(dbSession, "P2")).isEqualTo(1);
assertThat(underTest.countForQProfileUuid(dbSession, profile1.getKee())).isEqualTo(0);
assertThat(underTest.countForQProfileUuid(dbSession, profile2.getKee())).isEqualTo(1);
}

@Test
public void deleteByProfileKeys_does_nothing_if_row_with_specified_key_does_not_exist() {
when(uuidFactory.create()).thenReturn("C1");
insertChange("P1", "ACTIVATED", null, null);
QProfileDto profile1 = db.qualityProfiles().insert(db.getDefaultOrganization());
insertChange(profile1.getRulesProfileUuid(), "ACTIVATED", null, null);

underTest.deleteByProfileKeys(dbSession, asList("does_not_exist"));
underTest.deleteByRulesProfileUuids(dbSession, asList("does not exist"));

assertThat(underTest.countForQProfileUuid(dbSession, profile1.getKee())).isEqualTo(1);
}

assertThat(underTest.countForProfileUuid(dbSession, "P1")).isEqualTo(1);
private QProfileChangeDto insertChange(QProfileDto profile, String type, @Nullable String login, @Nullable String data) {
return insertChange(profile.getRulesProfileUuid(), type, login, data);
}

private void insertChange(String profileKey, String type, @Nullable String login, @Nullable String data) {
private QProfileChangeDto insertChange(String rulesProfileUuid, String type, @Nullable String login, @Nullable String data) {
QProfileChangeDto dto = new QProfileChangeDto()
.setProfileKey(profileKey)
.setRulesProfileUuid(rulesProfileUuid)
.setLogin(login)
.setChangeType(type)
.setData(data);
underTest.insert(dbSession, dto);
return dto;
}

private Map<String, Object> selectChangeByKey(String key) {
return dbTester.selectFirst(dbSession,
"select qprofile_key as \"qprofileKey\", created_at as \"createdAt\", user_login as \"login\", change_type as \"changeType\", change_data as \"changeData\" from qprofile_changes where kee='"
+ key + "'");
private QProfileChangeDto selectChangeByUuid(String uuid) {
Map<String, Object> map = db.selectFirst(dbSession,
"select kee as \"uuid\", qprofile_key as \"rulesProfileUuid\", created_at as \"createdAt\", user_login as \"login\", change_type as \"changeType\", change_data as \"changeData\" from qprofile_changes where kee='"
+ uuid + "'");
return new QProfileChangeDto()
.setUuid((String) map.get("uuid"))
.setRulesProfileUuid((String) map.get("rulesProfileUuid"))
.setCreatedAt((long) map.get("createdAt"))
.setLogin((String) map.get("login"))
.setChangeType((String) map.get("changeType"))
.setData((String) map.get("changeData"));
}
}

+ 178
- 134
server/sonar-db-dao/src/test/java/org/sonar/db/qualityprofile/QualityProfileDaoTest.java View File

@@ -32,6 +32,7 @@ import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.utils.System2;
import org.sonar.core.util.UtcDateUtils;
import org.sonar.core.util.Uuids;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDto;
@@ -43,6 +44,7 @@ import static com.google.common.collect.Lists.newArrayList;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;
import static org.mockito.Mockito.mock;
@@ -54,16 +56,16 @@ public class QualityProfileDaoTest {
private System2 system = mock(System2.class);

@Rule
public DbTester dbTester = DbTester.create(system);
public DbTester db = DbTester.create(system);

private DbSession dbSession = dbTester.getSession();
private QualityProfileDao underTest = dbTester.getDbClient().qualityProfileDao();
private DbSession dbSession = db.getSession();
private QualityProfileDao underTest = db.getDbClient().qualityProfileDao();
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");
organization = db.organizations().insertForUuid("QualityProfileDaoTest-ORG");
}

@After
@@ -73,7 +75,9 @@ public class QualityProfileDaoTest {

@Test
public void test_insert() {
QProfileDto dto = QProfileDto.createFor("theUuid")
QProfileDto dto = new QProfileDto()
.setKee("theUuid")
.setRulesProfileUuid("theRulesProfileUuid")
.setOrganizationUuid(organization.getUuid())
.setName("theName")
.setLanguage("theLang")
@@ -87,6 +91,7 @@ public class QualityProfileDaoTest {

QProfileDto reloaded = underTest.selectByUuid(dbSession, dto.getKee());
assertThat(reloaded.getKee()).isEqualTo(dto.getKee());
assertThat(reloaded.getRulesProfileUuid()).isEqualTo(dto.getRulesProfileUuid());
assertThat(reloaded.getId()).isNotNull().isNotZero();
assertThat(reloaded.getLanguage()).isEqualTo(dto.getLanguage());
assertThat(reloaded.getName()).isEqualTo(dto.getName());
@@ -99,7 +104,9 @@ public class QualityProfileDaoTest {

@Test
public void test_update() {
QProfileDto initial = QProfileDto.createFor("theUuid")
QProfileDto initial = new QProfileDto()
.setKee("theUuid")
.setRulesProfileUuid("theRulesProfileUuid")
.setOrganizationUuid(organization.getUuid())
.setName("theName")
.setLanguage("theLang")
@@ -110,7 +117,9 @@ public class QualityProfileDaoTest {
.setIsBuiltIn(true);
underTest.insert(dbSession, initial);

QProfileDto update = QProfileDto.createFor(initial.getKee())
QProfileDto update = new QProfileDto()
.setKee(initial.getKee())
.setRulesProfileUuid(initial.getRulesProfileUuid())
.setName("theNewName")
.setLanguage("theNewLang")
.setLastUsed(11_000L)
@@ -137,41 +146,59 @@ public class QualityProfileDaoTest {
}

@Test
public void test_deleteByUuids() {
QProfileDto p1 = dbTester.qualityProfiles().insert(organization);
QProfileDto p2 = dbTester.qualityProfiles().insert(organization);
QProfileDto p3 = dbTester.qualityProfiles().insert(organization);
public void deleteRulesProfilesByUuids() {
RulesProfileDto rp1 = insertRulesProfile();
RulesProfileDto rp2 = insertRulesProfile();

underTest.deleteByUuids(dbSession, asList(p1.getKee(), p3.getKee(), "does_not_exist"));
underTest.deleteRulesProfilesByUuids(dbSession, asList(rp1.getKee()));

List<QProfileDto> profiles = underTest.selectAll(dbSession, organization);
assertThat(profiles).extracting(QProfileDto::getKee).containsExactly(p2.getKee());
List<Map<String, Object>> uuids = db.select(dbSession, "select kee as \"uuid\" from rules_profiles");
assertThat(uuids).hasSize(1);
assertThat(uuids.get(0).get("uuid")).isEqualTo(rp2.getKee());
}

@Test
public void deleteByUuids_does_nothing_if_empty_uuids() {
dbTester.qualityProfiles().insert(organization);
public void deleteRulesProfilesByUuids_does_nothing_if_empty_input() {
insertRulesProfile();

underTest.deleteByUuids(dbSession, Collections.emptyList());
underTest.deleteRulesProfilesByUuids(dbSession, emptyList());

assertThat(dbTester.countRowsOfTable(dbSession, "rules_profiles")).isEqualTo(1);
assertThat(dbTester.countRowsOfTable(dbSession, "org_qprofiles")).isEqualTo(1);
assertThat(db.countRowsOfTable(dbSession, "rules_profiles")).isEqualTo(1);
}

@Test
public void deleteRulesProfilesByUuids_does_nothing_if_specified_uuid_does_not_exist() {
insertRulesProfile();

underTest.deleteRulesProfilesByUuids(dbSession, asList("does_not_exist"));

assertThat(db.countRowsOfTable(dbSession, "rules_profiles")).isEqualTo(1);
}

private RulesProfileDto insertRulesProfile() {
RulesProfileDto dto = new RulesProfileDto()
.setName(randomAlphanumeric(10))
.setLanguage(randomAlphanumeric(3))
.setKee(Uuids.createFast())
.setIsBuiltIn(false);
db.getDbClient().qualityProfileDao().insert(dbSession, dto);
return dto;
}

@Test
public void test_deleteProjectAssociationsByProfileUuids() {
QProfileDto profile1 = dbTester.qualityProfiles().insert(organization);
QProfileDto profile2 = dbTester.qualityProfiles().insert(organization);
ComponentDto project1 = dbTester.components().insertPrivateProject(organization);
ComponentDto project2 = dbTester.components().insertPrivateProject(organization);
ComponentDto project3 = dbTester.components().insertPrivateProject(organization);
dbTester.qualityProfiles().associateWithProject(project1, profile1);
dbTester.qualityProfiles().associateWithProject(project2, profile1);
dbTester.qualityProfiles().associateWithProject(project3, profile2);
QProfileDto profile1 = db.qualityProfiles().insert(organization);
QProfileDto profile2 = db.qualityProfiles().insert(organization);
ComponentDto project1 = db.components().insertPrivateProject(organization);
ComponentDto project2 = db.components().insertPrivateProject(organization);
ComponentDto project3 = db.components().insertPrivateProject(organization);
db.qualityProfiles().associateWithProject(project1, profile1);
db.qualityProfiles().associateWithProject(project2, profile1);
db.qualityProfiles().associateWithProject(project3, profile2);

underTest.deleteProjectAssociationsByProfileUuids(dbSession, asList(profile1.getKee(), "does_not_exist"));

List<Map<String, Object>> rows = dbTester.select(dbSession, "select project_uuid as \"projectUuid\", profile_key as \"profileKey\" from project_qprofiles");
List<Map<String, Object>> rows = db.select(dbSession, "select project_uuid as \"projectUuid\", profile_key as \"profileKey\" from project_qprofiles");
assertThat(rows).hasSize(1);
assertThat(rows.get(0).get("projectUuid")).isEqualTo(project3.uuid());
assertThat(rows.get(0).get("profileKey")).isEqualTo(profile2.getKee());
@@ -179,20 +206,20 @@ public class QualityProfileDaoTest {

@Test
public void deleteProjectAssociationsByProfileUuids_does_nothing_if_empty_uuids() {
QProfileDto profile = dbTester.qualityProfiles().insert(organization);
ComponentDto project = dbTester.components().insertPrivateProject();
dbTester.qualityProfiles().associateWithProject(project, profile);
QProfileDto profile = db.qualityProfiles().insert(organization);
ComponentDto project = db.components().insertPrivateProject();
db.qualityProfiles().associateWithProject(project, profile);

underTest.deleteProjectAssociationsByProfileUuids(dbSession, Collections.emptyList());

assertThat(dbTester.countRowsOfTable(dbSession, "project_qprofiles")).isEqualTo(1);
assertThat(db.countRowsOfTable(dbSession, "project_qprofiles")).isEqualTo(1);
}

@Test
public void test_selectAll() {
List<QProfileDto> sharedData = createSharedData();

List<QProfileDto> reloadeds = underTest.selectAll(dbSession, organization);
List<QProfileDto> reloadeds = underTest.selectOrderedByOrganizationUuid(dbSession, organization);

assertThat(reloadeds).hasSize(sharedData.size());

@@ -212,13 +239,14 @@ public class QualityProfileDaoTest {
assertThat(reloaded.getLastUsed()).isEqualTo(original.getLastUsed());
assertThat(reloaded.getUserUpdatedAt()).isEqualTo(original.getUserUpdatedAt());
assertThat(reloaded.isBuiltIn()).isEqualTo(original.isBuiltIn());
}
);
});
}

@Test
public void find_all_is_sorted_by_profile_name() {
QProfileDto dto1 = QProfileDto.createFor("js_first")
QProfileDto dto1 = new QProfileDto()
.setKee("js_first")
.setRulesProfileUuid("rp-js_first")
.setOrganizationUuid(organization.getUuid())
.setName("First")
.setLanguage("js")
@@ -228,7 +256,9 @@ public class QualityProfileDaoTest {
.setIsBuiltIn(false);
underTest.insert(dbSession, dto1);

QProfileDto dto2 = QProfileDto.createFor("js_second")
QProfileDto dto2 = new QProfileDto()
.setKee("js_second")
.setRulesProfileUuid("rp-js_second")
.setOrganizationUuid(organization.getUuid())
.setName("Second")
.setLanguage("js")
@@ -238,7 +268,9 @@ public class QualityProfileDaoTest {
.setIsBuiltIn(false);
underTest.insert(dbSession, dto2);

QProfileDto dto3 = QProfileDto.createFor("js_third")
QProfileDto dto3 = new QProfileDto()
.setKee("js_third")
.setRulesProfileUuid("rp-js_third")
.setOrganizationUuid(organization.getUuid())
.setName("Third")
.setLanguage("js")
@@ -248,30 +280,28 @@ public class QualityProfileDaoTest {
.setIsBuiltIn(false);
underTest.insert(dbSession, dto3);

List<QProfileDto> dtos = underTest.selectAll(dbSession, organization);
List<QProfileDto> dtos = underTest.selectOrderedByOrganizationUuid(dbSession, organization);

assertThat(dtos).hasSize(3);
assertThat(dtos.get(0).getName()).isEqualTo("First");
assertThat(dtos.get(1).getName()).isEqualTo("Second");
assertThat(dtos.get(2).getName()).isEqualTo("Third");

underTest.deleteByUuids(dbSession, Arrays.asList("js_first", "js_second", "js_third"));
}

@Test
public void get_default_profile() {
public void selectDefaultProfile() {
List<QProfileDto> sharedData = createSharedData();

QProfileDto java = underTest.selectDefaultProfile(dbSession, organization, "java");
assertThat(java).isNotNull();
assertThat(java.getKee()).isEqualTo("java_sonar_way");

assertThat(underTest.selectDefaultProfile(dbSession, dbTester.organizations().insert(), "java")).isNull();
assertThat(underTest.selectDefaultProfile(dbSession, db.organizations().insert(), "java")).isNull();
assertThat(underTest.selectDefaultProfile(dbSession, organization, "js")).isNull();
}

@Test
public void get_default_profiles() {
public void selectDefaultProfiles() {
List<QProfileDto> sharedData = createSharedData();

List<QProfileDto> java = underTest.selectDefaultProfiles(dbSession, organization, singletonList("java"));
@@ -312,7 +342,7 @@ public class QualityProfileDaoTest {
}

@Test
public void should_find_by_language() {
public void selectByLanguage() {
QProfileDto profile = QualityProfileTesting.newQualityProfileDto()
.setOrganizationUuid(organization.getUuid());
underTest.insert(dbSession, profile);
@@ -326,6 +356,7 @@ public class QualityProfileDaoTest {
assertThat(result.getKee()).isEqualTo(profile.getKee());
assertThat(result.getLanguage()).isEqualTo(profile.getLanguage());
assertThat(result.getOrganizationUuid()).isEqualTo(profile.getOrganizationUuid());
assertThat(result.getRulesProfileUuid()).isEqualTo(profile.getRulesProfileUuid());
}

@Test
@@ -348,10 +379,11 @@ public class QualityProfileDaoTest {
assertThat(results).isEmpty();
}


@Test
public void find_children() {
QProfileDto original1 = QProfileDto.createFor("java_child1")
QProfileDto original1 = new QProfileDto()
.setKee("java_child1")
.setRulesProfileUuid("rp-java_child1")
.setOrganizationUuid(organization.getUuid())
.setName("Child1")
.setLanguage("java")
@@ -362,7 +394,9 @@ public class QualityProfileDaoTest {
.setIsBuiltIn(false);
underTest.insert(dbSession, original1);

QProfileDto original2 = QProfileDto.createFor("java_child2")
QProfileDto original2 = new QProfileDto()
.setKee("java_child2")
.setRulesProfileUuid("rp-java_child2")
.setOrganizationUuid(organization.getUuid())
.setName("Child2")
.setLanguage("java")
@@ -373,7 +407,9 @@ public class QualityProfileDaoTest {
.setIsBuiltIn(false);
underTest.insert(dbSession, original2);

QProfileDto original3 = QProfileDto.createFor("java_parent")
QProfileDto original3 = new QProfileDto()
.setKee("java_parent")
.setRulesProfileUuid("rp-java_parent")
.setOrganizationUuid(organization.getUuid())
.setName("Parent")
.setLanguage("java")
@@ -383,7 +419,9 @@ public class QualityProfileDaoTest {
.setIsBuiltIn(false);
underTest.insert(dbSession, original3);

QProfileDto original4 = QProfileDto.createFor("js_child1")
QProfileDto original4 = new QProfileDto()
.setKee("js_child1")
.setRulesProfileUuid("rp-js_child1")
.setOrganizationUuid(organization.getUuid())
.setName("Child1")
.setLanguage("js")
@@ -394,7 +432,9 @@ public class QualityProfileDaoTest {
.setIsBuiltIn(false);
underTest.insert(dbSession, original4);

QProfileDto original5 = QProfileDto.createFor("js_child2")
QProfileDto original5 = new QProfileDto()
.setKee("js_child2")
.setRulesProfileUuid("rp-js_child2")
.setOrganizationUuid(organization.getUuid())
.setName("Child2")
.setLanguage("js")
@@ -405,7 +445,9 @@ public class QualityProfileDaoTest {
.setIsBuiltIn(false);
underTest.insert(dbSession, original5);

QProfileDto original6 = QProfileDto.createFor("js_parent")
QProfileDto original6 = new QProfileDto()
.setKee("js_parent")
.setRulesProfileUuid("rp-js_parent")
.setOrganizationUuid(organization.getUuid())
.setName("Parent")
.setLanguage("js")
@@ -415,7 +457,7 @@ public class QualityProfileDaoTest {
.setIsBuiltIn(false);
underTest.insert(dbSession, original6);

List<QProfileDto> dtos = underTest.selectChildren(dbSession, "java_parent");
List<QProfileDto> dtos = underTest.selectChildren(dbSession, original3);

assertThat(dtos).hasSize(2);

@@ -428,23 +470,21 @@ public class QualityProfileDaoTest {
assertThat(dto2.getName()).isEqualTo("Child2");
assertThat(dto2.getLanguage()).isEqualTo("java");
assertThat(dto2.getParentKee()).isEqualTo("java_parent");

underTest.deleteByUuids(dbSession, Arrays.asList("java_parent", "java_child1", "java_child2", "js_parent", "js_child1", "js_child2"));
}

@Test
public void countProjectsByProfileKey() {
QProfileDto profileWithoutProjects = dbTester.qualityProfiles().insert(organization);
QProfileDto profileWithProjects = dbTester.qualityProfiles().insert(organization);
ComponentDto project1 = dbTester.components().insertPrivateProject(organization);
ComponentDto project2 = dbTester.components().insertPrivateProject(organization);
dbTester.qualityProfiles().associateWithProject(project1, profileWithProjects);
dbTester.qualityProfiles().associateWithProject(project2, profileWithProjects);
OrganizationDto otherOrg = dbTester.organizations().insert();
QProfileDto profileInOtherOrg = dbTester.qualityProfiles().insert(otherOrg);
ComponentDto projectInOtherOrg = dbTester.components().insertPrivateProject(otherOrg);
dbTester.qualityProfiles().associateWithProject(projectInOtherOrg, profileInOtherOrg);
QProfileDto profileWithoutProjects = db.qualityProfiles().insert(organization);
QProfileDto profileWithProjects = db.qualityProfiles().insert(organization);
ComponentDto project1 = db.components().insertPrivateProject(organization);
ComponentDto project2 = db.components().insertPrivateProject(organization);
db.qualityProfiles().associateWithProject(project1, profileWithProjects);
db.qualityProfiles().associateWithProject(project2, profileWithProjects);
OrganizationDto otherOrg = db.organizations().insert();
QProfileDto profileInOtherOrg = db.qualityProfiles().insert(otherOrg);
ComponentDto projectInOtherOrg = db.components().insertPrivateProject(otherOrg);
db.qualityProfiles().associateWithProject(projectInOtherOrg, profileInOtherOrg);

assertThat(underTest.countProjectsByProfileUuid(dbSession, organization)).containsOnly(
MapEntry.entry(profileWithProjects.getKee(), 2L));
@@ -452,12 +492,12 @@ public class QualityProfileDaoTest {

@Test
public void test_selectAssociatedToProjectAndLanguage() {
OrganizationDto org = dbTester.organizations().insert();
ComponentDto project1 = dbTester.components().insertPublicProject(org);
ComponentDto project2 = dbTester.components().insertPublicProject(org);
QProfileDto javaProfile = dbTester.qualityProfiles().insert(org, p -> p.setLanguage("java"));
QProfileDto jsProfile = dbTester.qualityProfiles().insert(org, p -> p.setLanguage("js"));
dbTester.qualityProfiles().associateWithProject(project1, javaProfile, jsProfile);
OrganizationDto org = db.organizations().insert();
ComponentDto project1 = db.components().insertPublicProject(org);
ComponentDto project2 = db.components().insertPublicProject(org);
QProfileDto javaProfile = db.qualityProfiles().insert(org, p -> p.setLanguage("java"));
QProfileDto jsProfile = db.qualityProfiles().insert(org, p -> p.setLanguage("js"));
db.qualityProfiles().associateWithProject(project1, javaProfile, jsProfile);

assertThat(underTest.selectAssociatedToProjectAndLanguage(dbSession, project1, "java").getKee())
.isEqualTo(javaProfile.getKee());
@@ -471,12 +511,12 @@ public class QualityProfileDaoTest {

@Test
public void test_selectAssociatedToProjectUuidAndLanguages() {
OrganizationDto org = dbTester.organizations().insert();
ComponentDto project1 = dbTester.components().insertPublicProject(org);
ComponentDto project2 = dbTester.components().insertPublicProject(org);
QProfileDto javaProfile = dbTester.qualityProfiles().insert(org, p -> p.setLanguage("java"));
QProfileDto jsProfile = dbTester.qualityProfiles().insert(org, p -> p.setLanguage("js"));
dbTester.qualityProfiles().associateWithProject(project1, javaProfile, jsProfile);
OrganizationDto org = db.organizations().insert();
ComponentDto project1 = db.components().insertPublicProject(org);
ComponentDto project2 = db.components().insertPublicProject(org);
QProfileDto javaProfile = db.qualityProfiles().insert(org, p -> p.setLanguage("java"));
QProfileDto jsProfile = db.qualityProfiles().insert(org, p -> p.setLanguage("js"));
db.qualityProfiles().associateWithProject(project1, javaProfile, jsProfile);

assertThat(underTest.selectAssociatedToProjectUuidAndLanguages(dbSession, project1, singletonList("java")))
.extracting(QProfileDto::getKee).containsOnly(javaProfile.getKee());
@@ -492,12 +532,12 @@ public class QualityProfileDaoTest {

@Test
public void test_updateProjectProfileAssociation() {
OrganizationDto org = dbTester.organizations().insert();
ComponentDto project = dbTester.components().insertPrivateProject(org);
QProfileDto javaProfile1 = dbTester.qualityProfiles().insert(org, p -> p.setLanguage("java"));
QProfileDto jsProfile = dbTester.qualityProfiles().insert(org, p -> p.setLanguage("js"));
QProfileDto javaProfile2 = dbTester.qualityProfiles().insert(org, p -> p.setLanguage("java"));
dbTester.qualityProfiles().associateWithProject(project, javaProfile1, jsProfile);
OrganizationDto org = db.organizations().insert();
ComponentDto project = db.components().insertPrivateProject(org);
QProfileDto javaProfile1 = db.qualityProfiles().insert(org, p -> p.setLanguage("java"));
QProfileDto jsProfile = db.qualityProfiles().insert(org, p -> p.setLanguage("js"));
QProfileDto javaProfile2 = db.qualityProfiles().insert(org, p -> p.setLanguage("java"));
db.qualityProfiles().associateWithProject(project, javaProfile1, jsProfile);

underTest.updateProjectProfileAssociation(dbSession, project, javaProfile2.getKee(), javaProfile1.getKee());

@@ -507,7 +547,7 @@ public class QualityProfileDaoTest {

@Test
public void selectByKeys() {
dbTester.qualityProfiles().insert(newQualityProfileDto().setKey("qp-key-1"), newQualityProfileDto().setKee("qp-key-2"), newQualityProfileDto().setKee("qp-key-3"));
db.qualityProfiles().insert(newQualityProfileDto().setKee("qp-key-1"), newQualityProfileDto().setKee("qp-key-2"), newQualityProfileDto().setKee("qp-key-3"));

assertThat(underTest.selectOrFailByUuid(dbSession, "qp-key-1")).isNotNull();
assertThat(underTest.selectByUuid(dbSession, "qp-key-1")).isNotNull();
@@ -520,20 +560,20 @@ public class QualityProfileDaoTest {

@Test
public void select_selected_projects() throws Exception {
ComponentDto project1 = dbTester.components().insertPrivateProject(t -> t.setName("Project1 name"), t -> t.setOrganizationUuid(organization.getUuid()));
ComponentDto project2 = dbTester.components().insertPrivateProject(t -> t.setName("Project2 name"), t -> t.setOrganizationUuid(organization.getUuid()));
ComponentDto project3 = dbTester.components().insertPrivateProject(t -> t.setName("Project3 name"), t -> t.setOrganizationUuid(organization.getUuid()));
OrganizationDto organization2 = dbTester.organizations().insert();
ComponentDto project4 = dbTester.components().insertPrivateProject(t -> t.setName("Project4 name"), t -> t.setOrganizationUuid(organization2.getUuid()));
ComponentDto project1 = db.components().insertPrivateProject(t -> t.setName("Project1 name"), t -> t.setOrganizationUuid(organization.getUuid()));
ComponentDto project2 = db.components().insertPrivateProject(t -> t.setName("Project2 name"), t -> t.setOrganizationUuid(organization.getUuid()));
ComponentDto project3 = db.components().insertPrivateProject(t -> t.setName("Project3 name"), t -> t.setOrganizationUuid(organization.getUuid()));
OrganizationDto organization2 = db.organizations().insert();
ComponentDto project4 = db.components().insertPrivateProject(t -> t.setName("Project4 name"), t -> t.setOrganizationUuid(organization2.getUuid()));

QProfileDto profile1 = newQualityProfileDto();
dbTester.qualityProfiles().insert(profile1);
dbTester.qualityProfiles().associateWithProject(project1, profile1);
dbTester.qualityProfiles().associateWithProject(project2, profile1);
db.qualityProfiles().insert(profile1);
db.qualityProfiles().associateWithProject(project1, profile1);
db.qualityProfiles().associateWithProject(project2, profile1);

QProfileDto profile2 = newQualityProfileDto();
dbTester.qualityProfiles().insert(profile2);
dbTester.qualityProfiles().associateWithProject(project3, profile2);
db.qualityProfiles().insert(profile2);
db.qualityProfiles().associateWithProject(project3, profile2);
QProfileDto profile3 = newQualityProfileDto();

assertThat(underTest.selectSelectedProjects(dbSession, organization, profile1, null))
@@ -548,19 +588,19 @@ public class QualityProfileDaoTest {

@Test
public void select_deselected_projects() throws Exception {
ComponentDto project1 = dbTester.components().insertPrivateProject(t -> t.setName("Project1 name"), t -> t.setOrganizationUuid(organization.getUuid()));
ComponentDto project2 = dbTester.components().insertPrivateProject(t -> t.setName("Project2 name"), t -> t.setOrganizationUuid(organization.getUuid()));
ComponentDto project3 = dbTester.components().insertPrivateProject(t -> t.setName("Project3 name"), t -> t.setOrganizationUuid(organization.getUuid()));
OrganizationDto organization2 = dbTester.organizations().insert();
ComponentDto project4 = dbTester.components().insertPrivateProject(t -> t.setName("Project4 name"), t -> t.setOrganizationUuid(organization2.getUuid()));
ComponentDto project1 = db.components().insertPrivateProject(t -> t.setName("Project1 name"), t -> t.setOrganizationUuid(organization.getUuid()));
ComponentDto project2 = db.components().insertPrivateProject(t -> t.setName("Project2 name"), t -> t.setOrganizationUuid(organization.getUuid()));
ComponentDto project3 = db.components().insertPrivateProject(t -> t.setName("Project3 name"), t -> t.setOrganizationUuid(organization.getUuid()));
OrganizationDto organization2 = db.organizations().insert();
ComponentDto project4 = db.components().insertPrivateProject(t -> t.setName("Project4 name"), t -> t.setOrganizationUuid(organization2.getUuid()));

QProfileDto profile1 = newQualityProfileDto();
dbTester.qualityProfiles().insert(profile1);
dbTester.qualityProfiles().associateWithProject(project1, profile1);
db.qualityProfiles().insert(profile1);
db.qualityProfiles().associateWithProject(project1, profile1);

QProfileDto profile2 = newQualityProfileDto();
dbTester.qualityProfiles().insert(profile2);
dbTester.qualityProfiles().associateWithProject(project2, profile2);
db.qualityProfiles().insert(profile2);
db.qualityProfiles().associateWithProject(project2, profile2);
QProfileDto profile3 = newQualityProfileDto();

assertThat(underTest.selectDeselectedProjects(dbSession, organization, profile1, null))
@@ -575,19 +615,19 @@ public class QualityProfileDaoTest {

@Test
public void select_project_associations() throws Exception {
ComponentDto project1 = dbTester.components().insertPrivateProject(t -> t.setName("Project1 name"), t -> t.setOrganizationUuid(organization.getUuid()));
ComponentDto project2 = dbTester.components().insertPrivateProject(t -> t.setName("Project2 name"), t -> t.setOrganizationUuid(organization.getUuid()));
ComponentDto project3 = dbTester.components().insertPrivateProject(t -> t.setName("Project3 name"), t -> t.setOrganizationUuid(organization.getUuid()));
OrganizationDto organization2 = dbTester.organizations().insert();
ComponentDto project4 = dbTester.components().insertPrivateProject(t -> t.setName("Project4 name"), t -> t.setOrganizationUuid(organization2.getUuid()));
ComponentDto project1 = db.components().insertPrivateProject(t -> t.setName("Project1 name"), t -> t.setOrganizationUuid(organization.getUuid()));
ComponentDto project2 = db.components().insertPrivateProject(t -> t.setName("Project2 name"), t -> t.setOrganizationUuid(organization.getUuid()));
ComponentDto project3 = db.components().insertPrivateProject(t -> t.setName("Project3 name"), t -> t.setOrganizationUuid(organization.getUuid()));
OrganizationDto organization2 = db.organizations().insert();
ComponentDto project4 = db.components().insertPrivateProject(t -> t.setName("Project4 name"), t -> t.setOrganizationUuid(organization2.getUuid()));

QProfileDto profile1 = newQualityProfileDto();
dbTester.qualityProfiles().insert(profile1);
dbTester.qualityProfiles().associateWithProject(project1, profile1);
db.qualityProfiles().insert(profile1);
db.qualityProfiles().associateWithProject(project1, profile1);

QProfileDto profile2 = newQualityProfileDto();
dbTester.qualityProfiles().insert(profile2);
dbTester.qualityProfiles().associateWithProject(project2, profile2);
db.qualityProfiles().insert(profile2);
db.qualityProfiles().associateWithProject(project2, profile2);
QProfileDto profile3 = newQualityProfileDto();

assertThat(underTest.selectProjectAssociations(dbSession, organization, profile1, null))
@@ -602,19 +642,19 @@ public class QualityProfileDaoTest {
}

@Test
public void selectOutdatedProfiles_returns_the_custom_profiles_with_specified_name() {
OrganizationDto org1 = dbTester.organizations().insert();
OrganizationDto org2 = dbTester.organizations().insert();
OrganizationDto org3 = dbTester.organizations().insert();
QProfileDto outdatedProfile1 = dbTester.qualityProfiles().insert(org1, p -> p.setIsBuiltIn(false).setLanguage("java").setName("foo"));
QProfileDto outdatedProfile2 = dbTester.qualityProfiles().insert(org2, p -> p.setIsBuiltIn(false).setLanguage("java").setName("foo"));
QProfileDto builtInProfile = dbTester.qualityProfiles().insert(org3, p -> p.setIsBuiltIn(true).setLanguage("java").setName("foo"));
QProfileDto differentLanguage = dbTester.qualityProfiles().insert(org1, p -> p.setIsBuiltIn(false).setLanguage("cobol").setName("foo"));
QProfileDto differentName = dbTester.qualityProfiles().insert(org1, p -> p.setIsBuiltIn(false).setLanguage("java").setName("bar"));
public void selectUuidsOfCustomRulesProfiles_returns_the_custom_profiles_with_specified_name() {
OrganizationDto org1 = db.organizations().insert();
OrganizationDto org2 = db.organizations().insert();
OrganizationDto org3 = db.organizations().insert();
QProfileDto outdatedProfile1 = db.qualityProfiles().insert(org1, p -> p.setIsBuiltIn(false).setLanguage("java").setName("foo"));
QProfileDto outdatedProfile2 = db.qualityProfiles().insert(org2, p -> p.setIsBuiltIn(false).setLanguage("java").setName("foo"));
QProfileDto builtInProfile = db.qualityProfiles().insert(org3, p -> p.setIsBuiltIn(true).setLanguage("java").setName("foo"));
QProfileDto differentLanguage = db.qualityProfiles().insert(org1, p -> p.setIsBuiltIn(false).setLanguage("cobol").setName("foo"));
QProfileDto differentName = db.qualityProfiles().insert(org1, p -> p.setIsBuiltIn(false).setLanguage("java").setName("bar"));

Collection<String> keys = underTest.selectUuidsOfCustomRulesProfiles(dbSession, "java", "foo");

assertThat(keys).containsExactlyInAnyOrder(outdatedProfile1.getKee(), outdatedProfile2.getKee());
assertThat(keys).containsExactlyInAnyOrder(outdatedProfile1.getRulesProfileUuid(), outdatedProfile2.getRulesProfileUuid());
}

@Test
@@ -624,13 +664,13 @@ public class QualityProfileDaoTest {

@Test
public void renameAndCommit_updates_name_of_specified_profiles() {
OrganizationDto org1 = dbTester.organizations().insert();
OrganizationDto org2 = dbTester.organizations().insert();
QProfileDto fooInOrg1 = dbTester.qualityProfiles().insert(org1, p -> p.setName("foo"));
QProfileDto fooInOrg2 = dbTester.qualityProfiles().insert(org2, p -> p.setName("foo"));
QProfileDto bar = dbTester.qualityProfiles().insert(org1, p -> p.setName("bar"));
OrganizationDto org1 = db.organizations().insert();
OrganizationDto org2 = db.organizations().insert();
QProfileDto fooInOrg1 = db.qualityProfiles().insert(org1, p -> p.setName("foo"));
QProfileDto fooInOrg2 = db.qualityProfiles().insert(org2, p -> p.setName("foo"));
QProfileDto bar = db.qualityProfiles().insert(org1, p -> p.setName("bar"));

underTest.renameRulesProfilesAndCommit(dbSession, asList(fooInOrg1.getKee(), fooInOrg2.getKee()), "foo (copy)");
underTest.renameRulesProfilesAndCommit(dbSession, asList(fooInOrg1.getRulesProfileUuid(), fooInOrg2.getRulesProfileUuid()), "foo (copy)");

assertThat(underTest.selectOrFailByUuid(dbSession, fooInOrg1.getKee()).getName()).isEqualTo("foo (copy)");
assertThat(underTest.selectOrFailByUuid(dbSession, fooInOrg2.getKee()).getName()).isEqualTo("foo (copy)");
@@ -639,8 +679,8 @@ public class QualityProfileDaoTest {

@Test
public void renameAndCommit_does_nothing_if_empty_keys() {
OrganizationDto org = dbTester.organizations().insert();
QProfileDto profile = dbTester.qualityProfiles().insert(org, p -> p.setName("foo"));
OrganizationDto org = db.organizations().insert();
QProfileDto profile = db.qualityProfiles().insert(org, p -> p.setName("foo"));

underTest.renameRulesProfilesAndCommit(dbSession, Collections.emptyList(), "foo (copy)");

@@ -648,7 +688,9 @@ public class QualityProfileDaoTest {
}

private List<QProfileDto> createSharedData() {
QProfileDto dto1 = QProfileDto.createFor("java_sonar_way")
QProfileDto dto1 = new QProfileDto()
.setKee("java_sonar_way")
.setRulesProfileUuid("rp-java_sonar_way")
.setOrganizationUuid(organization.getUuid())
.setName("Sonar Way")
.setLanguage("java")
@@ -658,7 +700,9 @@ public class QualityProfileDaoTest {
.setIsBuiltIn(true);
underTest.insert(dbSession, dto1);

QProfileDto dto2 = QProfileDto.createFor("js_sonar_way")
QProfileDto dto2 = new QProfileDto()
.setKee("js_sonar_way")
.setRulesProfileUuid("rp-js_sonar_way")
.setOrganizationUuid(organization.getUuid())
.setName("Sonar Way")
.setLanguage("js")
@@ -672,7 +716,7 @@ public class QualityProfileDaoTest {
.setQProfileUuid(dto1.getKee())
.setLanguage(dto1.getLanguage())
.setOrganizationUuid(organization.getUuid());
dbTester.getDbClient().defaultQProfileDao().insertOrUpdate(dbSession, DefaultQProfileDto.from(dto1));
db.getDbClient().defaultQProfileDao().insertOrUpdate(dbSession, DefaultQProfileDto.from(dto1));

return Arrays.asList(dto1, dto2);
}

+ 5
- 3
server/sonar-db-dao/src/test/java/org/sonar/db/qualityprofile/QualityProfileTesting.java View File

@@ -35,7 +35,9 @@ public class QualityProfileTesting {
*/
public static QProfileDto newQualityProfileDto() {
String uuid = Uuids.createFast();
return QProfileDto.createFor(uuid)
return new QProfileDto()
.setKee(uuid)
.setRulesProfileUuid(Uuids.createFast())
.setOrganizationUuid(randomAlphanumeric(40))
.setName(uuid)
.setLanguage(randomAlphanumeric(20))
@@ -48,8 +50,8 @@ public class QualityProfileTesting {
*/
public static QProfileChangeDto newQProfileChangeDto() {
return new QProfileChangeDto()
.setKey(randomAlphanumeric(40))
.setProfileKey(randomAlphanumeric(40))
.setUuid(randomAlphanumeric(40))
.setRulesProfileUuid(randomAlphanumeric(40))
.setCreatedAt(nextLong())
.setChangeType("ACTIVATED")
.setLogin(randomAlphanumeric(10));

+ 2
- 2
server/sonar-db-dao/src/test/java/org/sonar/db/rule/RuleTesting.java View File

@@ -302,8 +302,8 @@ public class RuleTesting {
return rule -> rule.setSystemTags(copyOf(tags));
}

public static Consumer<RuleMetadataDto> setOrganizationUuid(String organizationUuid) {
return rule -> rule.setOrganizationUuid(organizationUuid);
public static Consumer<RuleMetadataDto> setOrganization(OrganizationDto organization) {
return rule -> rule.setOrganizationUuid(organization.getUuid());
}

public static Consumer<RuleMetadataDto> setTags(String... tags) {

+ 4
- 1
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v65/DbVersion65.java View File

@@ -50,6 +50,9 @@ public class DbVersion65 implements DbVersion {
.add(1721, "Drop rules_profiles.is_default", DropIsDefaultColumnFromRulesProfiles.class)
.add(1722, "Create table qprofiles", CreateTableQProfiles.class)
.add(1723, "Populate table qprofiles", PopulateQProfiles.class)
.add(1724, "Drop columns organization_uuid and parent_kee from rules_profiles", DropOrgUuidAndParentKeeFromRulesProfiles.class);
.add(1724, "Drop columns organization_uuid and parent_kee from rules_profiles", DropOrgUuidAndParentKeeFromRulesProfiles.class)
.add(1725, "Mark rules_profiles.is_built_in to true for default organization", SetRulesProfilesIsBuiltInToTrueForDefaultOrganization.class)
.add(1726, "Update OrgQProfiles to point to built-in profiles", UpdateOrgQProfilesToPointToBuiltInProfiles.class)
.add(1727, "Delete orphans rules_profiles table and associated tables", DeleteOrphansFromRulesProfiles.class);
}
}

+ 110
- 0
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v65/DeleteOrphansFromRulesProfiles.java View File

@@ -0,0 +1,110 @@
/*
* 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.v65;

import java.sql.SQLException;
import org.sonar.db.Database;
import org.sonar.server.platform.db.migration.step.DataChange;
import org.sonar.server.platform.db.migration.step.MassUpdate;

public class DeleteOrphansFromRulesProfiles extends DataChange {

public DeleteOrphansFromRulesProfiles(Database db) {
super(db);
}

@Override
protected void execute(Context context) throws SQLException {
deleteOrphansFromRulesProfiles(context);
deleteOrphansFromActiveRules(context);
deleteOrphansFromActiveRuleParameters(context);
deleteOrphansFromQProfileChanges(context);
}

private static void deleteOrphansFromRulesProfiles(Context context) throws SQLException {
MassUpdate massUpdate = context.prepareMassUpdate()
.rowPluralName("rules profiles");

massUpdate.select("select rp.kee " +
" from rules_profiles rp" +
" where not exists " +
" ( select 1 from org_qprofiles oqp where oqp.rules_profile_uuid = rp.kee )");

massUpdate.update("delete from rules_profiles where kee = ?")
.execute((row, update) -> {
String kee = row.getString(1);
update.setString(1, kee);
return true;
});
}

private static void deleteOrphansFromActiveRules(Context context) throws SQLException {
MassUpdate massUpdate = context.prepareMassUpdate()
.rowPluralName("active rules");

massUpdate.select("select ar.id " +
" from active_rules ar " +
" where not exists " +
" ( select 1 from rules_profiles rp where ar.profile_id = rp.id )");

massUpdate.update("delete from active_rules where id = ?")
.execute((row, update) -> {
int id = row.getInt(1);
update.setInt(1, id);
return true;
});
}

private static void deleteOrphansFromActiveRuleParameters(Context context) throws SQLException {
MassUpdate massUpdate = context.prepareMassUpdate()
.rowPluralName("active rule parameters");

massUpdate.select("select arp.id " +
" from active_rule_parameters arp " +
" where not exists " +
" ( select 1 from active_rules ar where ar.id = arp.active_rule_id )");

massUpdate.update("delete from active_rule_parameters where id = ?")
.execute((row, update) -> {
int id = row.getInt(1);
update.setInt(1, id);
return true;
});
}

private static void deleteOrphansFromQProfileChanges(Context context) throws SQLException {
MassUpdate massUpdate = context.prepareMassUpdate()
.rowPluralName("qprofile changes");

massUpdate.select("select qpc.kee " +
" from qprofile_changes qpc" +
" where not exists " +
" ( select 1 from rules_profiles rp where qpc.qprofile_key = rp.kee )");

massUpdate.update("delete from qprofile_changes where kee = ?")
.execute((row, update) -> {
String kee = row.getString(1);
update.setString(1, kee);
return true;
});
}

}

+ 78
- 0
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v65/SetRulesProfilesIsBuiltInToTrueForDefaultOrganization.java View File

@@ -0,0 +1,78 @@
/*
* 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.v65;

import java.sql.SQLException;
import org.sonar.db.Database;
import org.sonar.server.platform.db.migration.step.DataChange;
import org.sonar.server.platform.db.migration.step.MassUpdate;

import static com.google.common.base.Preconditions.checkState;

public class SetRulesProfilesIsBuiltInToTrueForDefaultOrganization extends DataChange {
private static final String PROP_DEFAULT_ORGANIZATION_UUID = "organization.default";
private static final String PROP_ORGANIZATION_ENABLED = "organization.enabled";

public SetRulesProfilesIsBuiltInToTrueForDefaultOrganization(Database db) {
super(db);
}

@Override
protected void execute(Context context) throws SQLException {
if (!isOrganizationEnabled(context)) {
return;
}

String defaultOrganizationUuid = getDefaultOrganizationUuid(context);
checkState(defaultOrganizationUuid!=null, "Missing internal property: '%s'", PROP_DEFAULT_ORGANIZATION_UUID);

MassUpdate massUpdate = context.prepareMassUpdate()
.rowPluralName("rules profiles");
massUpdate.select("select rp.kee " +
"from rules_profiles rp " +
"inner join org_qprofiles oqp on rp.kee = oqp.rules_profile_uuid " +
"where oqp.organization_uuid = ? ")
.setString(1, defaultOrganizationUuid);

massUpdate.update("update rules_profiles " +
"set is_built_in=? " +
"where kee=?").execute((row, update) -> {
String rulesProfilesUuid = row.getString(1);
update.setBoolean(1, true);
update.setString(2, rulesProfilesUuid);
return true;
});
}

private static String getDefaultOrganizationUuid(Context context) throws SQLException {
return context.prepareSelect("select text_value from internal_properties where kee=?")
.setString(1, PROP_DEFAULT_ORGANIZATION_UUID)
.get(row -> row.getString(1));
}

private static boolean isOrganizationEnabled(Context context) throws SQLException {
String value = context.prepareSelect("select text_value from internal_properties where kee=?")
.setString(1, PROP_ORGANIZATION_ENABLED)
.get(row -> row.getNullableString(1));

return "true".equals(value);
}
}

+ 124
- 0
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v65/UpdateOrgQProfilesToPointToBuiltInProfiles.java View File

@@ -0,0 +1,124 @@
/*
* 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.v65;

import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
import java.sql.SQLException;
import org.sonar.db.Database;
import org.sonar.server.platform.db.migration.step.DataChange;
import org.sonar.server.platform.db.migration.step.MassUpdate;

import static com.google.common.base.Preconditions.checkState;

public class UpdateOrgQProfilesToPointToBuiltInProfiles extends DataChange {
private static final String PROP_DEFAULT_ORGANIZATION_UUID = "organization.default";
private static final String PROP_ORGANIZATION_ENABLED = "organization.enabled";

public UpdateOrgQProfilesToPointToBuiltInProfiles(Database db) {
super(db);
}

@Override
protected void execute(Context context) throws SQLException {
if (!isOrganizationEnabled(context)) {
return;
}

String defaultOrganizationUuid = getDefaultOrganizationUuid(context);
BuiltInRulesProfiles builtInRulesProfiles = retrieveBuiltInRulesProfiles(context);

MassUpdate massUpdate = context.prepareMassUpdate()
.rowPluralName("org qprofiles");

massUpdate.select("select oqp.uuid, rp.language, rp.name " +
" from org_qprofiles oqp " +
" inner join rules_profiles rp on rp.kee = oqp.rules_profile_uuid " +
" where oqp.organization_uuid <> ? " +
" and rp.is_built_in = ? " +
" and rp.user_updated_at is null")
.setString(1, defaultOrganizationUuid)
.setBoolean(2, false);

massUpdate.update("update org_qprofiles " +
"set rules_profile_uuid = ? " +
"where uuid=?")
.execute((row, update) -> {
String orgQProfileUuid = row.getString(1);
String language = row.getString(2);
String name = row.getString(3);
if (!builtInRulesProfiles.contains(name, language)) {
return false;
}

update.setString(1, builtInRulesProfiles.get(name, language));
update.setString(2, orgQProfileUuid);
return true;
});
}

private static String getDefaultOrganizationUuid(Context context) throws SQLException {
String defaultOrganizationUuid = context.prepareSelect("select text_value from internal_properties where kee=?")
.setString(1, PROP_DEFAULT_ORGANIZATION_UUID)
.get(row -> row.getString(1));

checkState(defaultOrganizationUuid != null, "Missing internal property: '%s'", PROP_DEFAULT_ORGANIZATION_UUID);

return defaultOrganizationUuid;
}

private static boolean isOrganizationEnabled(Context context) throws SQLException {
String value = context.prepareSelect("select text_value from internal_properties where kee=?")
.setString(1, PROP_ORGANIZATION_ENABLED)
.get(row -> row.getNullableString(1));

return "true".equals(value);
}

private static BuiltInRulesProfiles retrieveBuiltInRulesProfiles(Context context) throws SQLException {
BuiltInRulesProfiles result = new BuiltInRulesProfiles();

context.prepareSelect("select name, language, kee" +
" from rules_profiles " +
" where is_built_in = ? ")
.setBoolean(1, true)
.list(row -> result.put(row.getString(1), row.getString(2), row.getString(3)));

return result;
}

private static class BuiltInRulesProfiles {
private Table<String, String, String> table = HashBasedTable.create();

private String put(String name, String language, String rulesProfileUuid) {
return table.put(name, language, rulesProfileUuid);
}

private boolean contains(String name, String language) {
return table.contains(name, language);
}

private String get(String name, String language) {
return table.get(name, language);
}
}

}

+ 1
- 1
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v65/DbVersion65Test.java View File

@@ -35,6 +35,6 @@ public class DbVersion65Test {

@Test
public void verify_migration_count() {
verifyMigrationCount(underTest, 25);
verifyMigrationCount(underTest, 28);
}
}

+ 277
- 0
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v65/DeleteOrphansFromRulesProfilesTest.java View File

@@ -0,0 +1,277 @@
/*
* 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.v65;

import java.sql.Date;
import java.sql.SQLException;
import java.util.List;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.core.util.stream.MoreCollectors;
import org.sonar.db.CoreDbTester;

import static java.lang.String.format;
import static org.assertj.core.api.Assertions.assertThat;

public class DeleteOrphansFromRulesProfilesTest {

@Rule
public CoreDbTester db = CoreDbTester.createForSchema(DeleteOrphansFromRulesProfilesTest.class, "initial.sql");

private DeleteOrphansFromRulesProfiles underTest = new DeleteOrphansFromRulesProfiles(db.database());


@Test
public void migration() throws SQLException {
long rulesProfileId1 = insertRulesProfile("RP_UUID_1", "Sonar Way", "Java", 1_000L, true);
long rulesProfileId2 = insertRulesProfile("RP_UUID_2", "Sonar Way", "JavaScript", 1_000L, false);
insertRulesProfile("RP_UUID_3", "Sonar Way", "PL/SQL", 1_000L, false);
insertRulesProfile("RP_UUID_4", "Sonar Way", "Cobol", 1_000L, false);
insertRulesProfile("RP_UUID_5", "Sonar Way", "Cobol", 1_000L, false);
insertRulesProfile("RP_UUID_6", "Sonar Way", "Cobol", 1_000L, true);

insertOrgQProfile("ORG_QP_UUID_1", "ORG_UUID_1", "RP_UUID_1");
insertOrgQProfile("ORG_QP_UUID_2", "ORG_UUID_1", "RP_UUID_2");

long activeRuleId1 = insertActiveRule(rulesProfileId1, 1);
long activeRuleId2 = insertActiveRule(rulesProfileId2, 1);
insertActiveRule(-1, 1);
insertActiveRule(-2, 1);

long param1 = insertActiveRuleParameter(activeRuleId1, 1);
long param2 = insertActiveRuleParameter(activeRuleId1, 2);
long param3 = insertActiveRuleParameter(activeRuleId2, 2);
insertActiveRuleParameter(-1, 1);
insertActiveRuleParameter(-2, 1);

insertQProfileChange("QPC_UUID1", "RP_UUID_1", "A");
insertQProfileChange("QPC_UUID2", "RP_UUID_2", "B");
insertQProfileChange("QPC_UUID3", "RP_UUID_3", "A");
insertQProfileChange("QPC_UUID4", "RP_UUID_4", "A");

underTest.execute();

assertThat(selectRulesProfiles()).containsExactlyInAnyOrder("RP_UUID_1", "RP_UUID_2");
assertThat(selectActiveRules()).containsExactlyInAnyOrder(activeRuleId1, activeRuleId2);
assertThat(selectActiveRuleParameters()).containsExactlyInAnyOrder(param1, param2, param3);
assertThat(selectQProfileChanges()).containsExactlyInAnyOrder("QPC_UUID1", "QPC_UUID2");
}

@Test
public void delete_rules_profiles_without_reference_in_qprofiles() throws SQLException {
insertRulesProfile("RP_UUID_1", "Sonar Way", "Java", 1_000L, true);
insertRulesProfile("RP_UUID_2", "Sonar Way", "JavaScript", 1_000L, false);
insertRulesProfile("RP_UUID_5", "Sonar Way", "Cobol", 1_000L, false);
insertRulesProfile("RP_UUID_6", "Sonar Way", "Cobol", 1_000L, true);
insertOrgQProfile("ORG_QP_UUID_1", "ORG_UUID_1", "RP_UUID_5");
insertOrgQProfile("ORG_QP_UUID_2", "ORG_UUID_1", "RP_UUID_6");

underTest.execute();

assertThat(selectRulesProfiles()).containsExactlyInAnyOrder("RP_UUID_5", "RP_UUID_6");
}

@Test
public void delete_active_rules_without_rules_profiles() throws SQLException {
long rulesProfileId1 = insertRulesProfile("RP_UUID_1", "Sonar Way", "Java", 1_000L, true);
long rulesProfileId2 = insertRulesProfile("RP_UUID_2", "Sonar Way", "JavaScript", 1_000L, false);

insertOrgQProfile("ORG_QP_UUID_1", "ORG_UUID_1", "RP_UUID_1");
insertOrgQProfile("ORG_QP_UUID_2", "ORG_UUID_1", "RP_UUID_2");

long activeRule1 = insertActiveRule(rulesProfileId1, 1);
long activeRule2 = insertActiveRule(rulesProfileId2, 1);
insertActiveRule(-1, 1);
insertActiveRule(-2, 1);

underTest.execute();

assertThat(selectActiveRules()).containsExactlyInAnyOrder(activeRule1, activeRule2);
}

@Test
public void delete_active_rule_parameters_without_active_rules() throws SQLException {
long rulesProfileId1 = insertRulesProfile("RP_UUID_1", "Sonar Way", "Java", 1_000L, true);
long rulesProfileId2 = insertRulesProfile("RP_UUID_2", "Sonar Way", "JavaScript", 1_000L, false);

insertOrgQProfile("ORG_QP_UUID_1", "ORG_UUID_1", "RP_UUID_1");
insertOrgQProfile("ORG_QP_UUID_2", "ORG_UUID_1", "RP_UUID_2");

long activeRuleId1 = insertActiveRule(rulesProfileId1, 1);
long activeRuleId2 = insertActiveRule(rulesProfileId2, 1);

long param1 = insertActiveRuleParameter(activeRuleId1, 1);
long param2 = insertActiveRuleParameter(activeRuleId1, 2);
long param3 = insertActiveRuleParameter(activeRuleId2, 2);

insertActiveRuleParameter(-1, 1);
insertActiveRuleParameter(-2, 1);

underTest.execute();

assertThat(selectActiveRuleParameters()).containsExactlyInAnyOrder(param1, param2, param3);
}

@Test
public void delete_qprofile_changes_without_rules_profiles() throws SQLException {
long rulesProfileId1 = insertRulesProfile("RP_UUID_1", "Sonar Way", "Java", 1_000L, true);
long rulesProfileId2 = insertRulesProfile("RP_UUID_2", "Sonar Way", "JavaScript", 1_000L, false);

insertOrgQProfile("ORG_QP_UUID_1", "ORG_UUID_1", "RP_UUID_1");
insertOrgQProfile("ORG_QP_UUID_2", "ORG_UUID_1", "RP_UUID_2");

insertQProfileChange("QPC_UUID1", "RP_UUID_1", "A");
insertQProfileChange("QPC_UUID2", "RP_UUID_2", "B");
insertQProfileChange("QPC_UUID3", "RP_UUID_3", "A");
insertQProfileChange("QPC_UUID4", "RP_UUID_4", "A");

underTest.execute();

assertThat(selectQProfileChanges()).containsExactlyInAnyOrder("QPC_UUID1", "QPC_UUID2");
}

@Test
public void reentrant_migration() throws SQLException {
long rulesProfileId1 = insertRulesProfile("RP_UUID_1", "Sonar Way", "Java", 1_000L, true);
long rulesProfileId2 = insertRulesProfile("RP_UUID_2", "Sonar Way", "JavaScript", 1_000L, false);
insertRulesProfile("RP_UUID_3", "Sonar Way", "PL/SQL", 1_000L, false);
insertRulesProfile("RP_UUID_4", "Sonar Way", "Cobol", 1_000L, false);
insertRulesProfile("RP_UUID_5", "Sonar Way", "Cobol", 1_000L, false);
insertRulesProfile("RP_UUID_6", "Sonar Way", "Cobol", 1_000L, true);

insertOrgQProfile("ORG_QP_UUID_1", "ORG_UUID_1", "RP_UUID_1");
insertOrgQProfile("ORG_QP_UUID_2", "ORG_UUID_1", "RP_UUID_2");

long activeRuleId1 = insertActiveRule(rulesProfileId1, 1);
long activeRuleId2 = insertActiveRule(rulesProfileId2, 1);
insertActiveRule(-1, 1);
insertActiveRule(-2, 1);

insertActiveRuleParameter(activeRuleId1, 1);
insertActiveRuleParameter(activeRuleId1, 2);
insertActiveRuleParameter(activeRuleId2, 2);
insertActiveRuleParameter(-1, 1);
insertActiveRuleParameter(-2, 1);

insertQProfileChange("QPC_UUID1", "RP_UUID_1", "A");
insertQProfileChange("QPC_UUID2", "RP_UUID_2", "B");
insertQProfileChange("QPC_UUID3", "RP_UUID_3", "A");
insertQProfileChange("QPC_UUID4", "RP_UUID_4", "A");

underTest.execute();
underTest.execute();

assertThat(countRows("rules_profiles")).isEqualTo(2);
assertThat(countRows("active_rules")).isEqualTo(2);
assertThat(countRows("active_rule_parameters")).isEqualTo(3);
assertThat(countRows("qprofile_changes")).isEqualTo(2);
}

private int countRows(String table) {
return db.countSql(format("select count(*) from %s", table));
}

private List<String> selectRulesProfiles() {
return db.select("select kee as \"kee\" from rules_profiles")
.stream()
.map(row -> (String) row.get("kee"))
.collect(MoreCollectors.toList());
}

private List<String> selectQProfileChanges() {
return db.select("select kee as \"kee\" from qprofile_changes")
.stream()
.map(row -> (String) row.get("kee"))
.collect(MoreCollectors.toList());
}

private List<Long> selectActiveRules() {
return db.select("select id as \"id\" from active_rules")
.stream()
.map(row -> (Long) row.get("id"))
.collect(MoreCollectors.toList());
}

private List<Long> selectActiveRuleParameters() {
return db.select("select id as \"id\" from active_rule_parameters")
.stream()
.map(row -> (Long) row.get("id"))
.collect(MoreCollectors.toList());
}

private long insertRulesProfile(String rulesProfileUuid, String name, String language, Long userUpdatedAt, boolean isBuiltIn) {
db.executeInsert("RULES_PROFILES",
"NAME", name,
"LANGUAGE", language,
"KEE", rulesProfileUuid,
"USER_UPDATED_AT", userUpdatedAt,
"IS_BUILT_IN", isBuiltIn,
"LAST_USED", 1_000L,
"CREATED_AT", new Date(1_000L),
"UPDATED_AT", new Date(1_000L));

return (Long) db.selectFirst(
format("select id as \"id\" from rules_profiles where kee='%s'", rulesProfileUuid)).get("id");
}

private void insertOrgQProfile(String orgQProfileUuid, String orgUuid, String rulesProfileUuid) {
db.executeInsert("ORG_QPROFILES",
"UUID", orgQProfileUuid,
"ORGANIZATION_UUID", orgUuid,
"RULES_PROFILE_UUID", rulesProfileUuid,
"CREATED_AT", 1_000L,
"UPDATED_AT", 2_000L);
}

private long insertActiveRule(long profileId, long ruleId) {
db.executeInsert("ACTIVE_RULES",
"PROFILE_ID", profileId,
"RULE_ID", ruleId,
"FAILURE_LEVEL", 1,
"INHERITANCE", "",
"CREATED_AT", 1_000L,
"UPDATED_AT", 2_000L);

return (Long) db.selectFirst(
format("select id as \"id\" from active_rules where profile_id = %d and rule_id = %d", profileId, ruleId)).get("id");
}

private long insertActiveRuleParameter(long activeRuleId, long rulesParameterId) {
db.executeInsert("ACTIVE_RULE_PARAMETERS",
"ACTIVE_RULE_ID", activeRuleId,
"RULES_PARAMETER_ID", rulesParameterId,
"RULES_PARAMETER_KEY", "",
"VALUE", "");

return (Long) db.selectFirst(
format("select id as \"id\" from active_rule_parameters where active_rule_id=%d and rules_parameter_id=%d", activeRuleId, rulesParameterId)).get("id");
}

private void insertQProfileChange(String uuid, String rulesProfileUuid, String changeType) {
db.executeInsert("QPROFILE_CHANGES",
"KEE", uuid,
"QPROFILE_KEY", rulesProfileUuid,
"CHANGE_TYPE", changeType,
"USER_LOGIN", "",
"CHANGE_DATA", "",
"CREATED_AT", 1_000L);
}
}

+ 158
- 0
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v65/SetRulesProfilesIsBuiltInToTrueForDefaultOrganizationTest.java View File

@@ -0,0 +1,158 @@
/*
* 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.v65;

import java.sql.SQLException;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.db.CoreDbTester;

import static org.assertj.core.api.Assertions.assertThat;

public class SetRulesProfilesIsBuiltInToTrueForDefaultOrganizationTest {

@Rule
public ExpectedException expectedException = ExpectedException.none();

@Rule
public CoreDbTester db = CoreDbTester.createForSchema(SetRulesProfilesIsBuiltInToTrueForDefaultOrganizationTest.class, "initial.sql");

private SetRulesProfilesIsBuiltInToTrueForDefaultOrganization underTest = new SetRulesProfilesIsBuiltInToTrueForDefaultOrganization(db.database());

@Test
public void has_no_effect_if_table_is_empty() throws SQLException {
underTest.execute();

assertThat(db.countRowsOfTable("rules_profiles")).isEqualTo(0);
}

@Test
public void mark_rules_profiles_of_default_org_as_built_in() throws SQLException {
enableOrganization();
String defaultOrganizationUuid = "ORG_UUID_1";
setDefaultOrganization(defaultOrganizationUuid);
IntStream.rangeClosed(1, 3).forEach(i -> {
insertProfile(defaultOrganizationUuid, "RP_UUID_" + i, false);
insertProfile("ORG_UUID_404", "RP_UUID_404_" + i, false);
});

underTest.execute();

assertThat(selectRulesProfiles(true)).containsExactlyInAnyOrder("RP_UUID_1", "RP_UUID_2", "RP_UUID_3");
assertThat(selectRulesProfiles(false)).containsExactlyInAnyOrder("RP_UUID_404_1", "RP_UUID_404_2", "RP_UUID_404_3");
}

@Test
public void do_nothing_if_org_disabled() throws SQLException {
String defaultOrganizationUuid = "ORG_UUID_1";
setDefaultOrganization(defaultOrganizationUuid);
IntStream.rangeClosed(1, 3).forEach(i -> {
insertProfile(defaultOrganizationUuid, "RP_UUID_" + i, false);
insertProfile("ORG_UUID_404", "RP_UUID_404_" + i, false);
});

underTest.execute();

assertThat(selectRulesProfiles(false)).containsExactlyInAnyOrder("RP_UUID_1", "RP_UUID_2", "RP_UUID_3", "RP_UUID_404_1", "RP_UUID_404_2", "RP_UUID_404_3");
}

@Test
public void reentrant_migration() throws SQLException {
enableOrganization();
String defaultOrganizationUuid = "ORG_UUID_1";
setDefaultOrganization(defaultOrganizationUuid);
IntStream.rangeClosed(1, 3).forEach(i -> {
insertProfile(defaultOrganizationUuid, "RP_UUID_" + i, false);
insertProfile("ORG_UUID_404", "RP_UUID_404_" + i, false);
});

underTest.execute();
underTest.execute();

assertThat(selectRulesProfiles(true)).containsExactlyInAnyOrder("RP_UUID_1", "RP_UUID_2", "RP_UUID_3");
assertThat(selectRulesProfiles(false)).containsExactlyInAnyOrder("RP_UUID_404_1", "RP_UUID_404_2", "RP_UUID_404_3");
}

@Test
public void reentrant_of_crashed_migration() throws SQLException {
enableOrganization();
String defaultOrganizationUuid = "ORG_UUID_1";
setDefaultOrganization(defaultOrganizationUuid);
insertProfile(defaultOrganizationUuid, "RP_UUID_1", true);
insertProfile(defaultOrganizationUuid, "RP_UUID_2", false);
insertProfile(defaultOrganizationUuid, "RP_UUID_3", false);

underTest.execute();

assertThat(selectRulesProfiles(true)).containsExactlyInAnyOrder("RP_UUID_1", "RP_UUID_2", "RP_UUID_3");
}

@Test
public void fail_if_no_default_org_and_org_activated() throws SQLException {
enableOrganization();
insertProfile("ORG_UUID_1", "RP_UUID_1", false);

expectedException.expect(IllegalStateException.class);
expectedException.expectMessage("Missing internal property: 'organization.default'");

underTest.execute();
}

private Set<String> selectRulesProfiles(boolean isBuiltIn) {
return db.select("select rp.kee as \"uuid\", rp.is_built_in as \"isBuiltIn\" from rules_profiles rp")
.stream()
.filter(row -> (boolean) row.get("isBuiltIn") == isBuiltIn)
.map(row -> (String) row.get("uuid"))
.collect(Collectors.toSet());
}

private void enableOrganization() {
db.executeInsert("INTERNAL_PROPERTIES",
"KEE", "organization.enabled",
"TEXT_VALUE", "true",
"IS_EMPTY", false);
}

private void setDefaultOrganization(String uuid) {
db.executeInsert("INTERNAL_PROPERTIES",
"KEE", "organization.default",
"TEXT_VALUE", uuid,
"IS_EMPTY", false);
}

private void insertProfile(String orgUuid, String rulesProfileUuid, boolean isBuiltIn) {
db.executeInsert("ORG_QPROFILES",
"ORGANIZATION_UUID", orgUuid,
"UUID", "OQP_UUID_" + rulesProfileUuid,
"RULES_PROFILE_UUID", rulesProfileUuid,
"CREATED_AT", 1_000L,
"UPDATED_AT", 2_000L);
db.executeInsert("RULES_PROFILES",
"NAME", "name_" + rulesProfileUuid,
"KEE", rulesProfileUuid,
"LANGUAGE", "LANG_" + rulesProfileUuid,
"IS_BUILT_IN", isBuiltIn);
}
}

+ 201
- 0
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v65/UpdateOrgQProfilesToPointToBuiltInProfilesTest.java View File

@@ -0,0 +1,201 @@
/*
* 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.v65;

import java.sql.SQLException;
import java.util.List;
import javax.annotation.Nullable;
import org.assertj.core.groups.Tuple;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.core.util.stream.MoreCollectors;
import org.sonar.db.CoreDbTester;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;

public class UpdateOrgQProfilesToPointToBuiltInProfilesTest {

@Rule
public ExpectedException expectedException = ExpectedException.none();

@Rule
public CoreDbTester db = CoreDbTester.createForSchema(UpdateOrgQProfilesToPointToBuiltInProfilesTest.class, "initial.sql");

private UpdateOrgQProfilesToPointToBuiltInProfiles underTest = new UpdateOrgQProfilesToPointToBuiltInProfiles(db.database());

@Test
public void has_no_effect_if_table_is_empty() throws SQLException {
underTest.execute();

assertThat(db.countRowsOfTable("rules_profiles")).isEqualTo(0);
}

@Test
public void has_no_effect_if_organization_are_disabled() throws SQLException {
String defaultOrgUuid = "DEFAULT_ORG_UUID";
setDefaultOrganization(defaultOrgUuid);
String sonarWayJava = "RP_UUID_1";
String sonarWayJavascript = "RP_UUID_2";
insertProfile(defaultOrgUuid, "OQP_UUID_1", sonarWayJava, "Sonar way", "Java", true, 1_000_000_000L);
insertProfile(defaultOrgUuid, "OQP_UUID_2", sonarWayJavascript, "Sonar way", "Javascript", true, null);
insertProfile(defaultOrgUuid, "OQP_UUID_3", "RP_UUID_3", "Sonar way", "Cobol", true, null);
insertProfile(defaultOrgUuid, "OQP_UUID_4", "RP_UUID_4", "My Sonar way", "Java", false, null);

underTest.execute();

assertThat(selectRulesProfiles()).containsExactlyInAnyOrder(
tuple("OQP_UUID_1", sonarWayJava),
tuple("OQP_UUID_2", sonarWayJavascript),
tuple("OQP_UUID_3", "RP_UUID_3"),
tuple("OQP_UUID_4", "RP_UUID_4"));
}

@Test
public void update_org_qprofiles_to_point_to_built_in_rules_profiles() throws SQLException {
enableOrganization();
String defaultOrgUuid = "DEFAULT_ORG_UUID";
setDefaultOrganization(defaultOrgUuid);
String sonarWayJava = "RP_UUID_1";
String sonarWayJavascript = "RP_UUID_2";
insertProfile(defaultOrgUuid, "OQP_UUID_1", sonarWayJava, "Sonar way", "Java", true, 1_000_000_000L);
insertProfile(defaultOrgUuid, "OQP_UUID_2", sonarWayJavascript, "Sonar way", "Javascript", true, null);
insertProfile(defaultOrgUuid, "OQP_UUID_3", "RP_UUID_3", "Sonar way", "Cobol", true, null);
insertProfile("ORG_UUID_1", "OQP_UUID_4", "RP_UUID_4", "Sonar way", "Java", false, null);
insertProfile("ORG_UUID_1", "OQP_UUID_5", "RP_UUID_5", "My Sonar way", "Java", false, null);
insertProfile("ORG_UUID_2", "OQP_UUID_6", "RP_UUID_6", "Sonar way", "Javascript", false, null);
insertProfile("ORG_UUID_2", "OQP_UUID_7", "RP_UUID_7", "Sonar way", "Python", false, null);
insertProfile("ORG_UUID_2", "OQP_UUID_8", "RP_UUID_8", "Sonar way", "Java", false, 2_000_000_000L);

underTest.execute();

assertThat(selectRulesProfiles()).containsExactlyInAnyOrder(
tuple("OQP_UUID_1", sonarWayJava),
tuple("OQP_UUID_2", sonarWayJavascript),
tuple("OQP_UUID_3", "RP_UUID_3"),
tuple("OQP_UUID_4", sonarWayJava),
tuple("OQP_UUID_5", "RP_UUID_5"),
tuple("OQP_UUID_6", sonarWayJavascript),
tuple("OQP_UUID_7", "RP_UUID_7"),
tuple("OQP_UUID_8", "RP_UUID_8"));
}

@Test
public void migration_is_reentrant() throws SQLException {
enableOrganization();
String defaultOrgUuid = "DEFAULT_ORG_UUID";
setDefaultOrganization(defaultOrgUuid);
String sonarWayJava = "RP_UUID_1";
String sonarWayJavascript = "RP_UUID_2";
insertProfile(defaultOrgUuid, "OQP_UUID_1", sonarWayJava, "Sonar way", "Java", true, 1_000_000_000L);
insertProfile(defaultOrgUuid, "OQP_UUID_2", sonarWayJavascript, "Sonar way", "Javascript", true, null);
insertProfile("ORG_UUID_1", "OQP_UUID_4", "RP_UUID_4", "Sonar way", "Java", false, null);
insertProfile("ORG_UUID_1", "OQP_UUID_5", "RP_UUID_5", "My Sonar way", "Java", false, null);

underTest.execute();
underTest.execute();

assertThat(selectRulesProfiles()).containsExactlyInAnyOrder(
tuple("OQP_UUID_1", sonarWayJava),
tuple("OQP_UUID_2", sonarWayJavascript),
tuple("OQP_UUID_4", sonarWayJava),
tuple("OQP_UUID_5", "RP_UUID_5"));
}

@Test
public void crashed_migration_is_reentrant() throws SQLException {
enableOrganization();
String defaultOrgUuid = "DEFAULT_ORG_UUID";
setDefaultOrganization(defaultOrgUuid);
String sonarWayJava = "RP_UUID_1";
String sonarWayJavascript = "RP_UUID_2";
insertProfile(defaultOrgUuid, "OQP_UUID_1", sonarWayJava, "Sonar way", "Java", true, 1_000_000_000L);
insertProfile(defaultOrgUuid, "OQP_UUID_2", sonarWayJavascript, "Sonar way", "Javascript", true, null);
insertOrgQProfile("ORG_UUID_1", "OQP_UUID_3", sonarWayJava);
insertProfile("ORG_UUID_1", "OQP_UUID_4", "RP_UUID_4", "Sonar way", "Javascript", false, null);
insertProfile("ORG_UUID_1", "OQP_UUID_5", "RP_UUID_5", "My Sonar way", "Java", false, null);

underTest.execute();

assertThat(selectRulesProfiles()).containsExactlyInAnyOrder(
tuple("OQP_UUID_1", sonarWayJava),
tuple("OQP_UUID_2", sonarWayJavascript),
tuple("OQP_UUID_3", sonarWayJava),
tuple("OQP_UUID_4", sonarWayJavascript),
tuple("OQP_UUID_5", "RP_UUID_5"));
}

@Test
public void fail_if_no_default_org_and_org_activated() throws SQLException {
enableOrganization();

expectedException.expect(IllegalStateException.class);
expectedException.expectMessage("Missing internal property: 'organization.default'");

underTest.execute();
}

private List<Tuple> selectRulesProfiles() {
return db.select("select oqp.uuid as \"uuid\", oqp.rules_profile_uuid as \"rulesProfileUuid\" from org_qprofiles oqp")
.stream()
.map(row -> tuple(row.get("uuid"), row.get("rulesProfileUuid")))
.collect(MoreCollectors.toList());
}

private void enableOrganization() {
db.executeInsert("INTERNAL_PROPERTIES",
"KEE", "organization.enabled",
"TEXT_VALUE", "true",
"IS_EMPTY", false);
}

private void setDefaultOrganization(String uuid) {
db.executeInsert("INTERNAL_PROPERTIES",
"KEE", "organization.default",
"TEXT_VALUE", uuid,
"IS_EMPTY", false);
}

private void insertProfile(String orgUuid, String orgQProfileUuid, String rulesProfileUuid, String name, String language, boolean isBuiltIn, @Nullable Long userUpdatedAt) {
db.executeInsert("ORG_QPROFILES",
"ORGANIZATION_UUID", orgUuid,
"UUID", orgQProfileUuid,
"RULES_PROFILE_UUID", rulesProfileUuid,
"CREATED_AT", 1_000L,
"UPDATED_AT", 2_000L);
db.executeInsert("RULES_PROFILES",
"NAME", name,
"KEE", rulesProfileUuid,
"LANGUAGE", language,
"IS_BUILT_IN", isBuiltIn,
"USER_UPDATED_AT", userUpdatedAt);
}

private void insertOrgQProfile(String orgUuid, String orgQProfileUuid, String rulesProfileUuid) {
db.executeInsert("ORG_QPROFILES",
"ORGANIZATION_UUID", orgUuid,
"UUID", orgQProfileUuid,
"RULES_PROFILE_UUID", rulesProfileUuid,
"CREATED_AT", 1_000L,
"UPDATED_AT", 2_000L);
}
}

+ 57
- 0
server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v65/DeleteOrphansFromRulesProfilesTest/initial.sql View File

@@ -0,0 +1,57 @@
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),
"KEE" VARCHAR(255) NOT NULL,
"RULES_UPDATED_AT" VARCHAR(100),
"CREATED_AT" TIMESTAMP,
"UPDATED_AT" TIMESTAMP,
"LAST_USED" BIGINT,
"USER_UPDATED_AT" BIGINT,
"IS_BUILT_IN" BOOLEAN NOT NULL
);
CREATE UNIQUE INDEX "UNIQ_QPROF_KEY" ON "RULES_PROFILES" ("KEE");

CREATE TABLE "ORG_QPROFILES" (
"UUID" VARCHAR(40) NOT NULL PRIMARY KEY,
"ORGANIZATION_UUID" VARCHAR(40) NOT NULL,
"RULES_PROFILE_UUID" VARCHAR(40) NOT NULL,
"PARENT_UUID" VARCHAR(40),
"CREATED_AT" BIGINT NOT NULL,
"UPDATED_AT" BIGINT NOT NULL
);
CREATE INDEX "ORG_QPROFILES_ORG_UUID" ON "ORG_QPROFILES" ("ORGANIZATION_UUID");
CREATE INDEX "ORG_QPROFILES_RP_UUID" ON "ORG_QPROFILES" ("RULES_PROFILE_UUID");


CREATE TABLE "ACTIVE_RULES" (
"ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
"PROFILE_ID" INTEGER NOT NULL,
"RULE_ID" INTEGER NOT NULL,
"FAILURE_LEVEL" INTEGER NOT NULL,
"INHERITANCE" VARCHAR(10),
"CREATED_AT" BIGINT,
"UPDATED_AT" BIGINT
);
CREATE UNIQUE INDEX "ACTIVE_RULES_UNIQUE" ON "ACTIVE_RULES" ("PROFILE_ID","RULE_ID");


CREATE TABLE "ACTIVE_RULE_PARAMETERS" (
"ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
"ACTIVE_RULE_ID" INTEGER NOT NULL,
"RULES_PARAMETER_ID" INTEGER NOT NULL,
"RULES_PARAMETER_KEY" VARCHAR(128),
"VALUE" VARCHAR(4000)
);
CREATE INDEX "IX_ARP_ON_ACTIVE_RULE_ID" ON "ACTIVE_RULE_PARAMETERS" ("ACTIVE_RULE_ID");


CREATE TABLE "QPROFILE_CHANGES" (
"KEE" VARCHAR(40) NOT NULL PRIMARY KEY,
"QPROFILE_KEY" VARCHAR(255) NOT NULL,
"CHANGE_TYPE" VARCHAR(20) NOT NULL,
"CREATED_AT" BIGINT NOT NULL,
"USER_LOGIN" VARCHAR(255),
"CHANGE_DATA" CLOB
);
CREATE INDEX "QPROFILE_CHANGES_QPROFILE_KEY" ON "QPROFILE_CHANGES" ("QPROFILE_KEY");

+ 34
- 0
server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v65/SetRulesProfilesIsBuiltInToTrueForDefaultOrganizationTest/initial.sql View File

@@ -0,0 +1,34 @@
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),
"KEE" VARCHAR(255) NOT NULL,
"RULES_UPDATED_AT" VARCHAR(100),
"CREATED_AT" TIMESTAMP,
"UPDATED_AT" TIMESTAMP,
"LAST_USED" BIGINT,
"USER_UPDATED_AT" BIGINT,
"IS_BUILT_IN" BOOLEAN NOT NULL
);
CREATE UNIQUE INDEX "UNIQ_QPROF_KEY" ON "RULES_PROFILES" ("KEE");

CREATE TABLE "ORG_QPROFILES" (
"UUID" VARCHAR(40) NOT NULL PRIMARY KEY,
"ORGANIZATION_UUID" VARCHAR(40) NOT NULL,
"RULES_PROFILE_UUID" VARCHAR(40) NOT NULL,
"PARENT_UUID" VARCHAR(40),
"CREATED_AT" BIGINT NOT NULL,
"UPDATED_AT" BIGINT NOT NULL
);
CREATE INDEX "ORG_QPROFILES_ORG_UUID" ON "ORG_QPROFILES" ("ORGANIZATION_UUID");
CREATE INDEX "ORG_QPROFILES_RP_UUID" ON "ORG_QPROFILES" ("RULES_PROFILE_UUID");


CREATE TABLE "INTERNAL_PROPERTIES" (
"KEE" VARCHAR(50) NOT NULL PRIMARY KEY,
"IS_EMPTY" BOOLEAN NOT NULL,
"TEXT_VALUE" VARCHAR(4000),
"CLOB_VALUE" CLOB,
"CREATED_AT" BIGINT
);
CREATE UNIQUE INDEX "UNIQ_INTERNAL_PROPERTIES" ON "INTERNAL_PROPERTIES" ("KEE");

+ 33
- 0
server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v65/UpdateOrgQProfilesToPointToBuiltInProfilesTest/initial.sql View File

@@ -0,0 +1,33 @@
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),
"KEE" VARCHAR(255) NOT NULL,
"RULES_UPDATED_AT" VARCHAR(100),
"CREATED_AT" TIMESTAMP,
"UPDATED_AT" TIMESTAMP,
"LAST_USED" BIGINT,
"USER_UPDATED_AT" BIGINT,
"IS_BUILT_IN" BOOLEAN NOT NULL
);
CREATE UNIQUE INDEX "UNIQ_QPROF_KEY" ON "RULES_PROFILES" ("KEE");

CREATE TABLE "ORG_QPROFILES" (
"UUID" VARCHAR(40) NOT NULL PRIMARY KEY,
"ORGANIZATION_UUID" VARCHAR(40) NOT NULL,
"RULES_PROFILE_UUID" VARCHAR(40) NOT NULL,
"PARENT_UUID" VARCHAR(40),
"CREATED_AT" BIGINT NOT NULL,
"UPDATED_AT" BIGINT NOT NULL
);
CREATE INDEX "ORG_QPROFILES_ORG_UUID" ON "ORG_QPROFILES" ("ORGANIZATION_UUID");
CREATE INDEX "ORG_QPROFILES_RP_UUID" ON "ORG_QPROFILES" ("RULES_PROFILE_UUID");

CREATE TABLE "INTERNAL_PROPERTIES" (
"KEE" VARCHAR(50) NOT NULL PRIMARY KEY,
"IS_EMPTY" BOOLEAN NOT NULL,
"TEXT_VALUE" VARCHAR(4000),
"CLOB_VALUE" CLOB,
"CREATED_AT" BIGINT
);
CREATE UNIQUE INDEX "UNIQ_INTERNAL_PROPERTIES" ON "INTERNAL_PROPERTIES" ("KEE");

+ 2
- 3
server/sonar-server/src/main/java/org/sonar/server/es/BaseDoc.java View File

@@ -20,12 +20,11 @@
package org.sonar.server.es;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;

import static com.google.common.collect.Maps.newHashMap;

/**
* Base implementation for business objects based on elasticsearch document
*/
@@ -34,7 +33,7 @@ public abstract class BaseDoc {
protected final Map<String, Object> fields;

protected BaseDoc() {
this.fields = newHashMap();
this.fields = new HashMap<>();
}

protected BaseDoc(Map<String, Object> fields) {

+ 1
- 1
server/sonar-server/src/main/java/org/sonar/server/es/BulkIndexer.java View File

@@ -140,7 +140,7 @@ public class BulkIndexer implements Startable {
}

public void addDeletion(IndexType indexType, String id) {
add(client.prepareDelete(indexType, id).request());
add(client.prepareDelete(indexType, id).setRouting(id).request());
}

public void addDeletion(IndexType indexType, String id, String routing) {

+ 1
- 1
server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIteratorFactory.java View File

@@ -32,7 +32,7 @@ public class IssueIteratorFactory {
}

public IssueIterator createForAll() {
return createForProject((String) null);
return createForProject(null);
}

public IssueIterator createForProject(@Nullable String projectUuid) {

+ 33
- 22
server/sonar-server/src/main/java/org/sonar/server/organization/OrganizationCreationImpl.java View File

@@ -19,14 +19,15 @@
*/
package org.sonar.server.organization;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Consumer;
import javax.annotation.Nullable;
import org.sonar.api.config.Settings;
import org.sonar.api.utils.System2;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.core.config.CorePropertyDefinitions;
import org.sonar.core.util.UuidFactory;
import org.sonar.db.DbClient;
@@ -39,13 +40,14 @@ import org.sonar.db.permission.OrganizationPermission;
import org.sonar.db.permission.UserPermissionDto;
import org.sonar.db.permission.template.PermissionTemplateCharacteristicDto;
import org.sonar.db.permission.template.PermissionTemplateDto;
import org.sonar.db.qualityprofile.DefaultQProfileDto;
import org.sonar.db.qualityprofile.OrgQProfileDto;
import org.sonar.db.user.GroupDto;
import org.sonar.db.user.UserDto;
import org.sonar.db.user.UserGroupDto;
import org.sonar.server.qualityprofile.BuiltInQProfile;
import org.sonar.server.qualityprofile.BuiltInQProfileInsert;
import org.sonar.server.qualityprofile.BuiltInQProfileRepository;
import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
import org.sonar.server.qualityprofile.QProfileName;
import org.sonar.server.user.index.UserIndexer;
import org.sonar.server.usergroups.DefaultGroupCreator;

@@ -56,11 +58,11 @@ import static org.sonar.api.web.UserRole.ADMIN;
import static org.sonar.api.web.UserRole.CODEVIEWER;
import static org.sonar.api.web.UserRole.ISSUE_ADMIN;
import static org.sonar.api.web.UserRole.USER;
import static org.sonar.core.util.stream.MoreCollectors.uniqueIndex;
import static org.sonar.db.permission.OrganizationPermission.SCAN;
import static org.sonar.server.organization.OrganizationCreation.NewOrganization.newOrganizationBuilder;

public class OrganizationCreationImpl implements OrganizationCreation {
private static final Logger LOGGER = Loggers.get(OrganizationCreationImpl.class);

private final DbClient dbClient;
private final System2 system2;
@@ -68,15 +70,13 @@ public class OrganizationCreationImpl implements OrganizationCreation {
private final OrganizationValidation organizationValidation;
private final Settings settings;
private final BuiltInQProfileRepository builtInQProfileRepository;
private final BuiltInQProfileInsert builtInQProfileInsert;
private final DefaultGroupCreator defaultGroupCreator;
private final UserIndexer userIndexer;
private final ActiveRuleIndexer activeRuleIndexer;

public OrganizationCreationImpl(DbClient dbClient, System2 system2, UuidFactory uuidFactory,
OrganizationValidation organizationValidation, Settings settings, UserIndexer userIndexer,
BuiltInQProfileRepository builtInQProfileRepository, BuiltInQProfileInsert builtInQProfileInsert,
DefaultGroupCreator defaultGroupCreator, ActiveRuleIndexer activeRuleIndexer) {
BuiltInQProfileRepository builtInQProfileRepository,
DefaultGroupCreator defaultGroupCreator) {
this.dbClient = dbClient;
this.system2 = system2;
this.uuidFactory = uuidFactory;
@@ -84,9 +84,7 @@ public class OrganizationCreationImpl implements OrganizationCreation {
this.settings = settings;
this.userIndexer = userIndexer;
this.builtInQProfileRepository = builtInQProfileRepository;
this.builtInQProfileInsert = builtInQProfileInsert;
this.defaultGroupCreator = defaultGroupCreator;
this.activeRuleIndexer = activeRuleIndexer;
}

@Override
@@ -111,7 +109,6 @@ public class OrganizationCreationImpl implements OrganizationCreation {
dbSession.commit();
batchDbSession.commit();

activeRuleIndexer.index();
// Elasticsearch is updated when DB session is committed
userIndexer.index(userCreator.getLogin());

@@ -150,7 +147,6 @@ public class OrganizationCreationImpl implements OrganizationCreation {
dbSession.commit();
batchDbSession.commit();

activeRuleIndexer.index();
// Elasticsearch is updated when DB session is committed
userIndexer.index(newUser.getLogin());

@@ -268,16 +264,31 @@ public class OrganizationCreationImpl implements OrganizationCreation {
}

private void insertQualityProfiles(DbSession dbSession, DbSession batchDbSession, OrganizationDto organization) {
builtInQProfileRepository.getQProfilesByLanguage().entrySet()
.stream()
.flatMap(entry -> entry.getValue().stream())
.forEach(profile -> insertQualityProfile(dbSession, batchDbSession, profile, organization));
}

private void insertQualityProfile(DbSession regularSession, DbSession batchDbSession, BuiltInQProfile profile, OrganizationDto organization) {
LOGGER.debug("Creating quality profile {} for language {} for organization {}", profile.getName(), profile.getLanguage(), organization.getKey());
Map<QProfileName, BuiltInQProfile> builtInsPerName = builtInQProfileRepository.get().stream()
.collect(uniqueIndex(BuiltInQProfile::getQProfileName));

List<DefaultQProfileDto> defaults = new ArrayList<>();
dbClient.qualityProfileDao().selectBuiltInRulesProfiles(dbSession).forEach(rulesProfile -> {
OrgQProfileDto dto = new OrgQProfileDto()
.setOrganizationUuid(organization.getUuid())
.setRulesProfileUuid(rulesProfile.getKee())
.setUuid(uuidFactory.create());

QProfileName name = new QProfileName(rulesProfile.getLanguage(), rulesProfile.getName());
BuiltInQProfile builtIn = builtInsPerName.get(name);
if (builtIn != null && builtIn.isDefault()) {
// rows of table default_qprofiles must be inserted after org_qprofiles
// in order to benefit from batch SQL inserts
defaults.add(new DefaultQProfileDto()
.setQProfileUuid(dto.getUuid())
.setOrganizationUuid(organization.getUuid())
.setLanguage(builtIn.getLanguage()));
}

dbClient.qualityProfileDao().insert(batchDbSession, dto);
});

builtInQProfileInsert.create(regularSession, batchDbSession, profile, organization);
defaults.forEach(defaultQProfileDto -> dbClient.defaultQProfileDao().insertOrUpdate(dbSession, defaultQProfileDto));
}

/**

+ 2
- 7
server/sonar-server/src/main/java/org/sonar/server/organization/ws/DeleteAction.java View File

@@ -23,7 +23,6 @@ import java.util.List;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
import org.sonar.core.util.stream.MoreCollectors;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDto;
@@ -134,12 +133,8 @@ public class DeleteAction implements OrganizationsWsAction {
}

private void deleteQualityProfiles(DbSession dbSession, OrganizationDto organization) {
List<QProfileDto> profiles = dbClient.qualityProfileDao().selectAll(dbSession, organization);
List<String> profileKeys = profiles.stream()
.map(QProfileDto::getKee)
.collect(MoreCollectors.toArrayList(profiles.size()));
qProfileFactory.deleteByKeys(dbSession, profileKeys);
dbSession.commit();
List<QProfileDto> profiles = dbClient.qualityProfileDao().selectOrderedByOrganizationUuid(dbSession, organization);
qProfileFactory.delete(dbSession, profiles);
}

private void deleteOrganization(DbSession dbSession, OrganizationDto organization) {

+ 2
- 2
server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java View File

@@ -141,7 +141,6 @@ import org.sonar.server.projecttag.ws.ProjectTagsWsModule;
import org.sonar.server.property.InternalPropertiesImpl;
import org.sonar.server.property.ws.PropertiesWs;
import org.sonar.server.qualitygate.QualityGateModule;
import org.sonar.server.qualityprofile.BuiltInQProfileInsertImpl;
import org.sonar.server.qualityprofile.BuiltInQProfileRepositoryImpl;
import org.sonar.server.qualityprofile.QProfileBackuperImpl;
import org.sonar.server.qualityprofile.QProfileComparison;
@@ -153,6 +152,7 @@ import org.sonar.server.qualityprofile.QProfileResetImpl;
import org.sonar.server.qualityprofile.RuleActivator;
import org.sonar.server.qualityprofile.RuleActivatorContextFactory;
import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
import org.sonar.server.qualityprofile.index.ActiveRuleIteratorFactory;
import org.sonar.server.qualityprofile.ws.OldRestoreAction;
import org.sonar.server.qualityprofile.ws.ProfilesWs;
import org.sonar.server.qualityprofile.ws.QProfilesWsModule;
@@ -260,7 +260,7 @@ public class PlatformLevel4 extends PlatformLevel {

// quality profile
BuiltInQProfileRepositoryImpl.class,
BuiltInQProfileInsertImpl.class,
ActiveRuleIteratorFactory.class,
ActiveRuleIndexer.class,
XMLProfileParser.class,
XMLProfileSerializer.class,

+ 2
- 0
server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevelStartup.java View File

@@ -25,6 +25,7 @@ import org.sonar.server.organization.DefaultOrganizationEnforcer;
import org.sonar.server.platform.ServerLifecycleNotifier;
import org.sonar.server.platform.web.RegisterServletFilters;
import org.sonar.server.qualitygate.RegisterQualityGates;
import org.sonar.server.qualityprofile.BuiltInQProfileInsertImpl;
import org.sonar.server.qualityprofile.BuiltInQProfileLoader;
import org.sonar.server.qualityprofile.RegisterQualityProfiles;
import org.sonar.server.rule.RegisterRules;
@@ -56,6 +57,7 @@ public class PlatformLevelStartup extends PlatformLevel {
RegisterRules.class);
add(BuiltInQProfileLoader.class);
addIfStartupLeader(
BuiltInQProfileInsertImpl.class,
RegisterQualityProfiles.class,
RegisterPermissionTemplates.class,
RenameDeprecatedPropertyKeys.class,

+ 23
- 10
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ActiveRuleChange.java View File

@@ -20,17 +20,19 @@
package org.sonar.server.qualityprofile;

import com.google.common.base.MoreObjects;
import com.google.common.collect.Maps;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.apache.commons.lang.StringUtils;
import org.sonar.db.qualityprofile.ActiveRuleDto;
import org.sonar.db.qualityprofile.ActiveRuleKey;
import org.sonar.db.qualityprofile.QProfileChangeDto;

public class ActiveRuleChange {

private ActiveRuleDto activeRule;

public enum Type {
ACTIVATED, DEACTIVATED, UPDATED
}
@@ -39,9 +41,15 @@ public class ActiveRuleChange {
private final ActiveRuleKey key;
private String severity = null;
private ActiveRule.Inheritance inheritance = null;
private Map<String, String> parameters = Maps.newHashMap();
private final Map<String, String> parameters = new HashMap<>();

public ActiveRuleChange(Type type, ActiveRuleDto activeRule) {
this.type = type;
this.key = activeRule.getKey();
this.activeRule = activeRule;
}

private ActiveRuleChange(Type type, ActiveRuleKey key) {
public ActiveRuleChange(Type type, ActiveRuleKey key) {
this.type = type;
this.key = key;
}
@@ -89,14 +97,23 @@ public class ActiveRuleChange {
return this;
}

@CheckForNull
public ActiveRuleDto getActiveRule() {
return activeRule;
}

public ActiveRuleChange setActiveRule(@Nullable ActiveRuleDto activeRule) {
this.activeRule = activeRule;
return this;
}

public QProfileChangeDto toDto(@Nullable String login) {
QProfileChangeDto dto = new QProfileChangeDto();
dto.setChangeType(type.name());
dto.setProfileKey(getKey().qProfile());
dto.setRulesProfileUuid(getKey().getRuleProfileUuid());
dto.setLogin(login);
Map<String, String> data = new HashMap<>();
data.put("key", getKey().toString());
data.put("ruleKey", getKey().ruleKey().toString());
data.put("ruleKey", getKey().getRuleKey().toString());

parameters.entrySet().stream()
.filter(param -> !param.getKey().isEmpty())
@@ -112,10 +129,6 @@ public class ActiveRuleChange {
return dto;
}

public static ActiveRuleChange createFor(Type type, ActiveRuleKey key) {
return new ActiveRuleChange(type, key);
}

@Override
public String toString() {
return MoreObjects.toStringHelper(this)

+ 1
- 1
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfile.java View File

@@ -35,7 +35,7 @@ public final class BuiltInQProfile {
private final List<org.sonar.api.rules.ActiveRule> activeRules;

private BuiltInQProfile(Builder builder) {
this.qProfileName = new QProfileName(builder.language, builder.getName());
this.qProfileName = new QProfileName(builder.language, builder.name);
this.isDefault = builder.declaredDefault || builder.computedDefault;
this.activeRules = ImmutableList.copyOf(builder.activeRules);
}

+ 5
- 2
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileInsert.java View File

@@ -20,8 +20,11 @@
package org.sonar.server.qualityprofile;

import org.sonar.db.DbSession;
import org.sonar.db.organization.OrganizationDto;

public interface BuiltInQProfileInsert {
void create(DbSession session, DbSession batchSession, BuiltInQProfile builtInQProfile, OrganizationDto organization);
/**
* Persist a built-in profile and associate it to all existing organizations.
* Db sessions are committed.
*/
void create(DbSession session, DbSession batchSession, BuiltInQProfile builtInQProfile);
}

+ 73
- 37
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileInsertImpl.java View File

@@ -22,6 +22,7 @@ package org.sonar.server.qualityprofile;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
@@ -42,14 +43,15 @@ import org.sonar.core.util.UuidFactory;
import org.sonar.core.util.stream.MoreCollectors;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.qualityprofile.ActiveRuleDto;
import org.sonar.db.qualityprofile.ActiveRuleKey;
import org.sonar.db.qualityprofile.ActiveRuleParamDto;
import org.sonar.db.qualityprofile.DefaultQProfileDto;
import org.sonar.db.qualityprofile.QProfileDto;
import org.sonar.db.qualityprofile.OrgQProfileDto;
import org.sonar.db.qualityprofile.RulesProfileDto;
import org.sonar.db.rule.RuleDefinitionDto;
import org.sonar.db.rule.RuleParamDto;
import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
import org.sonar.server.util.TypeValidations;

import static com.google.common.base.MoreObjects.firstNonNull;
@@ -61,64 +63,98 @@ public class BuiltInQProfileInsertImpl implements BuiltInQProfileInsert {
private final System2 system2;
private final UuidFactory uuidFactory;
private final TypeValidations typeValidations;
private final ActiveRuleIndexer activeRuleIndexer;
private RuleRepository ruleRepository;

public BuiltInQProfileInsertImpl(DbClient dbClient, System2 system2, UuidFactory uuidFactory, TypeValidations typeValidations) {
public BuiltInQProfileInsertImpl(DbClient dbClient, System2 system2, UuidFactory uuidFactory, TypeValidations typeValidations, ActiveRuleIndexer activeRuleIndexer) {
this.dbClient = dbClient;
this.system2 = system2;
this.uuidFactory = uuidFactory;
this.typeValidations = typeValidations;
this.activeRuleIndexer = activeRuleIndexer;
}

@Override
public void create(DbSession session, DbSession batchSession, BuiltInQProfile builtInQProfile, OrganizationDto organization) {
initRuleRepository(batchSession);
public void create(DbSession dbSession, DbSession batchDbSession, BuiltInQProfile builtInQProfile) {
initRuleRepository(batchDbSession);

Date now = new Date(system2.now());
QProfileDto profileDto = insertQualityProfile(session, builtInQProfile, organization, now);
RulesProfileDto ruleProfile = insertRulesProfile(dbSession, builtInQProfile, now);

List<ActiveRuleChange> localChanges = builtInQProfile.getActiveRules()
.stream()
.map(activeRule -> insertActiveRule(session, profileDto, activeRule, now.getTime()))
.map(activeRule -> insertActiveRule(dbSession, ruleProfile, activeRule, now.getTime()))
.collect(MoreCollectors.toList());

localChanges.forEach(change -> dbClient.qProfileChangeDao().insert(batchSession, change.toDto(null)));
localChanges.forEach(change -> dbClient.qProfileChangeDao().insert(batchDbSession, change.toDto(null)));

associateToOrganizations(dbSession, batchDbSession, builtInQProfile, ruleProfile);

dbSession.commit();
batchDbSession.commit();

activeRuleIndexer.indexRuleProfile(dbSession, ruleProfile);
}

private void initRuleRepository(DbSession session) {
private void associateToOrganizations(DbSession dbSession, DbSession batchDbSession, BuiltInQProfile builtInQProfile, RulesProfileDto rulesProfileDto) {
List<String> orgUuids = dbClient.organizationDao().selectAllUuids(dbSession);

List<DefaultQProfileDto> defaults = new ArrayList<>();
orgUuids.forEach(orgUuid -> {
OrgQProfileDto dto = new OrgQProfileDto()
.setOrganizationUuid(orgUuid)
.setRulesProfileUuid(rulesProfileDto.getKee())
.setUuid(uuidFactory.create());

if (builtInQProfile.isDefault()) {
// rows of table default_qprofiles must be inserted after
// in order to benefit from batch SQL inserts
defaults.add(new DefaultQProfileDto()
.setQProfileUuid(dto.getUuid())
.setOrganizationUuid(orgUuid)
.setLanguage(builtInQProfile.getLanguage()));
}

dbClient.qualityProfileDao().insert(batchDbSession, dto);
});

defaults.forEach(defaultQProfileDto -> dbClient.defaultQProfileDao().insertOrUpdate(dbSession, defaultQProfileDto));
}

private void initRuleRepository(DbSession dbSession) {
if (ruleRepository == null) {
ruleRepository = new RuleRepository(dbClient, session);
ruleRepository = new RuleRepository(dbClient, dbSession);
}
}

private QProfileDto insertQualityProfile(DbSession dbSession, BuiltInQProfile builtInQProfile, OrganizationDto organization, Date now) {
QProfileDto profileDto = QProfileDto.createFor(uuidFactory.create())
.setName(builtInQProfile.getName())
.setOrganizationUuid(organization.getUuid())
.setLanguage(builtInQProfile.getLanguage())
private RulesProfileDto insertRulesProfile(DbSession dbSession, BuiltInQProfile builtIn, Date now) {
RulesProfileDto dto = new RulesProfileDto()
.setKee(uuidFactory.create())
.setName(builtIn.getName())
.setLanguage(builtIn.getLanguage())
.setIsBuiltIn(true)
.setRulesUpdatedAtAsDate(now);
dbClient.qualityProfileDao().insert(dbSession, profileDto);
if (builtInQProfile.isDefault()) {
dbClient.defaultQProfileDao().insertOrUpdate(dbSession, DefaultQProfileDto.from(profileDto));
}
return profileDto;
dbClient.qualityProfileDao().insert(dbSession, dto);
return dto;
}

private ActiveRuleChange insertActiveRule(DbSession session, QProfileDto profileDto, org.sonar.api.rules.ActiveRule activeRule, long now) {
private ActiveRuleChange insertActiveRule(DbSession dbSession, RulesProfileDto rulesProfileDto, org.sonar.api.rules.ActiveRule activeRule, long now) {
RuleKey ruleKey = RuleKey.of(activeRule.getRepositoryKey(), activeRule.getRuleKey());
RuleDefinitionDto ruleDefinitionDto = ruleRepository.getDefinition(ruleKey)
.orElseThrow(() -> new IllegalStateException("RuleDefinition not found for key " + ruleKey));

ActiveRuleDto dto = ActiveRuleDto.createFor(profileDto, ruleDefinitionDto);
ActiveRuleDto dto = new ActiveRuleDto();
dto.setProfileId(rulesProfileDto.getId());
dto.setRuleId(ruleDefinitionDto.getId());
dto.setKey(ActiveRuleKey.of(rulesProfileDto, ruleDefinitionDto.getKey()));
dto.setSeverity(firstNonNull(activeRule.getSeverity().name(), ruleDefinitionDto.getSeverityString()));
dto.setUpdatedAt(now);
dto.setCreatedAt(now);
dbClient.activeRuleDao().insert(session, dto);
dbClient.activeRuleDao().insert(dbSession, dto);

List<ActiveRuleParamDto> paramDtos = insertActiveRuleParams(session, activeRule, ruleKey, dto);
List<ActiveRuleParamDto> paramDtos = insertActiveRuleParams(dbSession, activeRule, ruleKey, dto);

ActiveRuleChange change = ActiveRuleChange.createFor(ActiveRuleChange.Type.ACTIVATED, ActiveRuleKey.of(profileDto.getKee(), ruleKey));
ActiveRuleChange change = new ActiveRuleChange(ActiveRuleChange.Type.ACTIVATED, dto);
change.setSeverity(dto.getSeverityString());
paramDtos.forEach(paramDto -> change.setParameter(paramDto.getKey(), paramDto.getValue()));
return change;
@@ -161,20 +197,20 @@ public class BuiltInQProfileInsertImpl implements BuiltInQProfileInsert {
return value;
}

public static class RuleRepository {
private final Map<RuleKey, RuleDefinitionDto> ruleDefinitions;
private final Map<RuleKey, Set<RuleParamDto>> ruleParams;
private static class RuleRepository {
private final Map<RuleKey, RuleDefinitionDto> definitions;
private final Map<RuleKey, Set<RuleParamDto>> params;

private RuleRepository(DbClient dbClient, DbSession session) {
this.ruleDefinitions = dbClient.ruleDao().selectAllDefinitions(session)
this.definitions = dbClient.ruleDao().selectAllDefinitions(session)
.stream()
.collect(Collectors.toMap(RuleDefinitionDto::getKey, Function.identity()));
Map<Integer, RuleKey> ruleIdsByKey = ruleDefinitions.values()
Map<Integer, RuleKey> ruleIdsByKey = definitions.values()
.stream()
.collect(MoreCollectors.uniqueIndex(RuleDefinitionDto::getId, RuleDefinitionDto::getKey));
this.ruleParams = new HashMap<>(ruleIdsByKey.size());
dbClient.ruleDao().selectRuleParamsByRuleKeys(session, ruleDefinitions.keySet())
.forEach(ruleParam -> ruleParams.compute(
this.params = new HashMap<>(ruleIdsByKey.size());
dbClient.ruleDao().selectRuleParamsByRuleKeys(session, definitions.keySet())
.forEach(ruleParam -> params.compute(
ruleIdsByKey.get(ruleParam.getRuleId()),
(key, value) -> {
if (value == null) {
@@ -184,12 +220,12 @@ public class BuiltInQProfileInsertImpl implements BuiltInQProfileInsert {
}));
}

Optional<RuleDefinitionDto> getDefinition(RuleKey ruleKey) {
return Optional.ofNullable(ruleDefinitions.get(requireNonNull(ruleKey, "RuleKey can't be null")));
private Optional<RuleDefinitionDto> getDefinition(RuleKey ruleKey) {
return Optional.ofNullable(definitions.get(requireNonNull(ruleKey, "RuleKey can't be null")));
}

Set<RuleParamDto> getRuleParams(RuleKey ruleKey) {
Set<RuleParamDto> res = ruleParams.get(requireNonNull(ruleKey, "RuleKey can't be null"));
private Set<RuleParamDto> getRuleParams(RuleKey ruleKey) {
Set<RuleParamDto> res = params.get(requireNonNull(ruleKey, "RuleKey can't be null"));
return res == null ? Collections.emptySet() : res;
}
}

+ 2
- 3
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileRepository.java View File

@@ -20,7 +20,6 @@
package org.sonar.server.qualityprofile;

import java.util.List;
import java.util.Map;

public interface BuiltInQProfileRepository {
/**
@@ -34,9 +33,9 @@ public interface BuiltInQProfileRepository {
void initialize();

/**
* @return an immutable map containing immutable lists.
* @return an immutable list
*
* @throws IllegalStateException if {@link #initialize()} has not been called
*/
Map<String, List<BuiltInQProfile>> getQProfilesByLanguage();
List<BuiltInQProfile> get();
}

+ 10
- 8
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileRepositoryImpl.java View File

@@ -52,7 +52,7 @@ public class BuiltInQProfileRepositoryImpl implements BuiltInQProfileRepository

private final Languages languages;
private final List<ProfileDefinition> definitions;
private Map<String, List<BuiltInQProfile>> qProfilesByLanguage;
private List<BuiltInQProfile> qProfiles;

/**
* Requires for pico container when no {@link ProfileDefinition} is defined at all
@@ -68,20 +68,20 @@ public class BuiltInQProfileRepositoryImpl implements BuiltInQProfileRepository

@Override
public void initialize() {
checkState(qProfilesByLanguage == null, "initialize must be called only once");
checkState(qProfiles == null, "initialize must be called only once");

Profiler profiler = Profiler.create(Loggers.get(getClass())).startInfo("Load quality profiles");
ListMultimap<String, RulesProfile> rulesProfilesByLanguage = buildRulesProfilesByLanguage();
validateAndClean(rulesProfilesByLanguage);
this.qProfilesByLanguage = toQualityProfilesByLanguage(rulesProfilesByLanguage);
this.qProfiles = toFlatList(rulesProfilesByLanguage);
profiler.stopDebug();
}

@Override
public Map<String, List<BuiltInQProfile>> getQProfilesByLanguage() {
checkState(qProfilesByLanguage != null, "initialize must be called first");
public List<BuiltInQProfile> get() {
checkState(qProfiles != null, "initialize must be called first");

return qProfilesByLanguage;
return qProfiles;
}

/**
@@ -125,7 +125,7 @@ public class BuiltInQProfileRepositoryImpl implements BuiltInQProfileRepository
});
}

private static Map<String, List<BuiltInQProfile>> toQualityProfilesByLanguage(ListMultimap<String, RulesProfile> rulesProfilesByLanguage) {
private static List<BuiltInQProfile> toFlatList(ListMultimap<String, RulesProfile> rulesProfilesByLanguage) {
Map<String, List<BuiltInQProfile.Builder>> buildersByLanguage = Multimaps.asMap(rulesProfilesByLanguage)
.entrySet()
.stream()
@@ -134,7 +134,9 @@ public class BuiltInQProfileRepositoryImpl implements BuiltInQProfileRepository
.entrySet()
.stream()
.filter(BuiltInQProfileRepositoryImpl::ensureAtMostOneDeclaredDefault)
.collect(MoreCollectors.uniqueIndex(Map.Entry::getKey, entry -> toQualityProfiles(entry.getValue()), buildersByLanguage.size()));
.map(entry -> toQualityProfiles(entry.getValue()))
.flatMap(Collection::stream)
.collect(MoreCollectors.toList());
}

/**

+ 9
- 8
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileBackuperImpl.java View File

@@ -47,6 +47,7 @@ import org.sonar.db.DbSession;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.qualityprofile.ActiveRuleDto;
import org.sonar.db.qualityprofile.ActiveRuleParamDto;
import org.sonar.db.qualityprofile.OrgActiveRuleDto;
import org.sonar.db.qualityprofile.QProfileDto;

import static com.google.common.base.Preconditions.checkArgument;
@@ -82,13 +83,13 @@ public class QProfileBackuperImpl implements QProfileBackuper {
}

@Override
public void backup(DbSession dbSession, QProfileDto profileDto, Writer writer) {
List<ActiveRuleDto> activeRules = db.activeRuleDao().selectByProfileKey(dbSession, profileDto.getKee());
public void backup(DbSession dbSession, QProfileDto profile, Writer writer) {
List<OrgActiveRuleDto> activeRules = db.activeRuleDao().selectByProfile(dbSession, profile);
activeRules.sort(BackupActiveRuleComparator.INSTANCE);
writeXml(dbSession, writer, profileDto, activeRules.iterator());
writeXml(dbSession, writer, profile, activeRules.iterator());
}

private void writeXml(DbSession dbSession, Writer writer, QProfileDto profile, Iterator<ActiveRuleDto> activeRules) {
private void writeXml(DbSession dbSession, Writer writer, QProfileDto profile, Iterator<OrgActiveRuleDto> activeRules) {
XmlWriter xml = XmlWriter.of(writer).declaration();
xml.begin(ATTRIBUTE_PROFILE);
xml.prop(ATTRIBUTE_NAME, profile.getName());
@@ -97,8 +98,8 @@ public class QProfileBackuperImpl implements QProfileBackuper {
while (activeRules.hasNext()) {
ActiveRuleDto activeRule = activeRules.next();
xml.begin(ATTRIBUTE_RULE);
xml.prop(ATTRIBUTE_REPOSITORY_KEY, activeRule.getKey().ruleKey().repository());
xml.prop(ATTRIBUTE_KEY, activeRule.getKey().ruleKey().rule());
xml.prop(ATTRIBUTE_REPOSITORY_KEY, activeRule.getRuleKey().repository());
xml.prop(ATTRIBUTE_KEY, activeRule.getRuleKey().rule());
xml.prop(ATTRIBUTE_PRIORITY, activeRule.getSeverityString());
xml.begin(ATTRIBUTE_PARAMETERS);
for (ActiveRuleParamDto param : db.activeRuleDao().selectParamsByActiveRuleId(dbSession, activeRule.getId())) {
@@ -247,8 +248,8 @@ public class QProfileBackuperImpl implements QProfileBackuper {
@Override
public int compare(ActiveRuleDto o1, ActiveRuleDto o2) {
return new CompareToBuilder()
.append(o1.getKey().ruleKey().repository(), o2.getKey().ruleKey().repository())
.append(o1.getKey().ruleKey().rule(), o2.getKey().ruleKey().rule())
.append(o1.getRuleKey().repository(), o2.getRuleKey().repository())
.append(o1.getRuleKey().rule(), o2.getRuleKey().rule())
.toComparison();
}
}

+ 7
- 6
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileComparison.java View File

@@ -36,6 +36,7 @@ import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.qualityprofile.ActiveRuleDto;
import org.sonar.db.qualityprofile.ActiveRuleParamDto;
import org.sonar.db.qualityprofile.OrgActiveRuleDto;
import org.sonar.db.qualityprofile.QProfileDto;

@ServerSide
@@ -49,8 +50,8 @@ public class QProfileComparison {
}

public QProfileComparisonResult compare(DbSession dbSession, QProfileDto left, QProfileDto right) {
Map<RuleKey, ActiveRuleDto> leftActiveRulesByRuleKey = loadActiveRules(dbSession, left);
Map<RuleKey, ActiveRuleDto> rightActiveRulesByRuleKey = loadActiveRules(dbSession, right);
Map<RuleKey, OrgActiveRuleDto> leftActiveRulesByRuleKey = loadActiveRules(dbSession, left);
Map<RuleKey, OrgActiveRuleDto> rightActiveRulesByRuleKey = loadActiveRules(dbSession, right);

Set<RuleKey> allRules = Sets.newHashSet();
allRules.addAll(leftActiveRulesByRuleKey.keySet());
@@ -70,7 +71,7 @@ public class QProfileComparison {
}

private void compareActivationParams(DbSession session, ActiveRuleDto leftRule, ActiveRuleDto rightRule, QProfileComparisonResult result) {
RuleKey key = leftRule.getKey().ruleKey();
RuleKey key = leftRule.getRuleKey();
Map<String, String> leftParams = paramDtoToMap(dbClient.activeRuleDao().selectParamsByActiveRuleId(session, leftRule.getId()));
Map<String, String> rightParams = paramDtoToMap(dbClient.activeRuleDao().selectParamsByActiveRuleId(session, rightRule.getId()));
if (leftParams.equals(rightParams) && leftRule.getSeverityString().equals(rightRule.getSeverityString())) {
@@ -86,8 +87,8 @@ public class QProfileComparison {
}
}

private Map<RuleKey, ActiveRuleDto> loadActiveRules(DbSession session, QProfileDto profile) {
return Maps.uniqueIndex(dbClient.activeRuleDao().selectByProfileKey(session, profile.getKee()), ActiveRuleToRuleKey.INSTANCE);
private Map<RuleKey, OrgActiveRuleDto> loadActiveRules(DbSession dbSession, QProfileDto profile) {
return Maps.uniqueIndex(dbClient.activeRuleDao().selectByProfile(dbSession, profile), ActiveRuleToRuleKey.INSTANCE);
}

public static class QProfileComparisonResult {
@@ -161,7 +162,7 @@ public class QProfileComparison {

@Override
public RuleKey apply(@Nonnull ActiveRuleDto input) {
return input.getKey().ruleKey();
return input.getRuleKey();
}
}


+ 17
- 18
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileExporters.java View File

@@ -44,6 +44,7 @@ import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.qualityprofile.ActiveRuleDto;
import org.sonar.db.qualityprofile.ActiveRuleParamDto;
import org.sonar.db.qualityprofile.OrgActiveRuleDto;
import org.sonar.db.qualityprofile.QProfileDto;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.NotFoundException;
@@ -103,29 +104,27 @@ public class QProfileExporters {
return exporter.getMimeType();
}

public void export(QProfileDto profile, String exporterKey, Writer writer) {
public void export(DbSession dbSession, QProfileDto profile, String exporterKey, Writer writer) {
ProfileExporter exporter = findExporter(exporterKey);
exporter.exportProfile(wrap(profile), writer);
exporter.exportProfile(wrap(dbSession, profile), writer);
}

private RulesProfile wrap(QProfileDto profile) {
try (DbSession dbSession = dbClient.openSession(false)) {
RulesProfile target = new RulesProfile(profile.getName(), profile.getLanguage());
List<ActiveRuleDto> activeRuleDtos = dbClient.activeRuleDao().selectByProfileKey(dbSession, profile.getKee());
List<ActiveRuleParamDto> activeRuleParamDtos = dbClient.activeRuleDao().selectParamsByActiveRuleIds(dbSession, Lists.transform(activeRuleDtos, ActiveRuleDto::getId));
ListMultimap<Integer, ActiveRuleParamDto> activeRuleParamsByActiveRuleId = FluentIterable.from(activeRuleParamDtos).index(ActiveRuleParamDto::getActiveRuleId);

for (ActiveRuleDto activeRule : activeRuleDtos) {
// TODO all rules should be loaded by using one query with all active rule keys as parameter
Rule rule = ruleFinder.findByKey(activeRule.getKey().ruleKey());
org.sonar.api.rules.ActiveRule wrappedActiveRule = target.activateRule(rule, RulePriority.valueOf(activeRule.getSeverityString()));
List<ActiveRuleParamDto> paramDtos = activeRuleParamsByActiveRuleId.get(activeRule.getId());
for (ActiveRuleParamDto activeRuleParamDto : paramDtos) {
wrappedActiveRule.setParameter(activeRuleParamDto.getKey(), activeRuleParamDto.getValue());
}
private RulesProfile wrap(DbSession dbSession, QProfileDto profile) {
RulesProfile target = new RulesProfile(profile.getName(), profile.getLanguage());
List<OrgActiveRuleDto> activeRuleDtos = dbClient.activeRuleDao().selectByProfile(dbSession, profile);
List<ActiveRuleParamDto> activeRuleParamDtos = dbClient.activeRuleDao().selectParamsByActiveRuleIds(dbSession, Lists.transform(activeRuleDtos, ActiveRuleDto::getId));
ListMultimap<Integer, ActiveRuleParamDto> activeRuleParamsByActiveRuleId = FluentIterable.from(activeRuleParamDtos).index(ActiveRuleParamDto::getActiveRuleId);

for (ActiveRuleDto activeRule : activeRuleDtos) {
// TODO all rules should be loaded by using one query with all active rule keys as parameter
Rule rule = ruleFinder.findByKey(activeRule.getRuleKey());
org.sonar.api.rules.ActiveRule wrappedActiveRule = target.activateRule(rule, RulePriority.valueOf(activeRule.getSeverityString()));
List<ActiveRuleParamDto> paramDtos = activeRuleParamsByActiveRuleId.get(activeRule.getId());
for (ActiveRuleParamDto activeRuleParamDto : paramDtos) {
wrappedActiveRule.setParameter(activeRuleParamDto.getKey(), activeRuleParamDto.getValue());
}
return target;
}
return target;
}

private ProfileExporter findExporter(String exporterKey) {

+ 43
- 26
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileFactory.java View File

@@ -19,9 +19,13 @@
*/
package org.sonar.server.qualityprofile;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import javax.annotation.Nullable;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.utils.System2;
@@ -85,21 +89,14 @@ public class QProfileFactory {
return doCreate(dbSession, organization, name, false, false);
}

/**
* Create the quality profile in DB with the specified name.
*
* A DB error will be thrown if the quality profile already exists.
*/
public QProfileDto createBuiltIn(DbSession dbSession, OrganizationDto organization, QProfileName name, boolean isDefault) {
return doCreate(dbSession, requireNonNull(organization), name, isDefault, true);
}

private QProfileDto doCreate(DbSession dbSession, OrganizationDto organization, QProfileName name, boolean isDefault, boolean isBuiltIn) {
if (StringUtils.isEmpty(name.getName())) {
throw BadRequestException.create("quality_profiles.profile_name_cant_be_blank");
}
Date now = new Date(system2.now());
QProfileDto dto = QProfileDto.createFor(uuidFactory.create())
QProfileDto dto = new QProfileDto()
.setKee(uuidFactory.create())
.setRulesProfileUuid(uuidFactory.create())
.setName(name.getName())
.setOrganizationUuid(organization.getUuid())
.setLanguage(name.getLanguage())
@@ -113,24 +110,44 @@ public class QProfileFactory {
}

// ------------- DELETION

/**
* Deletes the profiles with specified keys from database and Elasticsearch.
* All related information are deleted. The profiles marked as "default"
* are deleted too. Deleting a parent profile does not delete descendants
* if their keys are not listed.
* Deletes the specified profiles from database and Elasticsearch.
* All information related to custom profiles are deleted. Only association
* with built-in profiles are deleted.
* The profiles marked as "default" are deleted too. Deleting a parent profile
* does not delete descendants if the latter are not listed.
*/
public void deleteByKeys(DbSession dbSession, Collection<String> profileUuids) {
if (!profileUuids.isEmpty()) {
db.qualityProfileDao().deleteProjectAssociationsByProfileUuids(dbSession, profileUuids);
db.activeRuleDao().deleteParametersByProfileKeys(dbSession, profileUuids);
db.activeRuleDao().deleteByProfileKeys(dbSession, profileUuids);
db.qProfileChangeDao().deleteByProfileKeys(dbSession, profileUuids);
db.defaultQProfileDao().deleteByQProfileUuids(dbSession, profileUuids);
db.qualityProfileDao().deleteByUuids(dbSession, profileUuids);
dbSession.commit();
activeRuleIndexer.deleteByProfileKeys(profileUuids);
public void delete(DbSession dbSession, Collection<QProfileDto> profiles) {
if (profiles.isEmpty()) {
return;
}
}

Set<String> uuids = new HashSet<>();
List<QProfileDto> customProfiles = new ArrayList<>();
Set<String> rulesProfileUuidsOfCustomProfiles = new HashSet<>();
profiles.forEach(p -> {
uuids.add(p.getKee());
if (!p.isBuiltIn()) {
customProfiles.add(p);
rulesProfileUuidsOfCustomProfiles.add(p.getRulesProfileUuid());
}
});

// tables org_qprofiles, default_qprofiles and project_qprofiles
// are deleted whatever custom or built-in
db.qualityProfileDao().deleteProjectAssociationsByProfileUuids(dbSession, uuids);
db.defaultQProfileDao().deleteByQProfileUuids(dbSession, uuids);
db.qualityProfileDao().deleteOrgQProfilesByUuids(dbSession, uuids);

// tables related to rules_profiles and active_rules are deleted
// only for custom profiles
if (!rulesProfileUuidsOfCustomProfiles.isEmpty()) {
db.activeRuleDao().deleteParametersByRuleProfileUuids(dbSession, rulesProfileUuidsOfCustomProfiles);
db.activeRuleDao().deleteByRuleProfileUuids(dbSession, rulesProfileUuidsOfCustomProfiles);
db.qProfileChangeDao().deleteByRulesProfileUuids(dbSession, rulesProfileUuidsOfCustomProfiles);
db.qualityProfileDao().deleteRulesProfilesByUuids(dbSession, rulesProfileUuidsOfCustomProfiles);
}
dbSession.commit();
activeRuleIndexer.deleteByProfiles(customProfiles);
}
}

+ 1
- 1
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileLookup.java View File

@@ -39,7 +39,7 @@ public class QProfileLookup {
}

public List<QProfileDto> allProfiles(DbSession dbSession, OrganizationDto organization) {
return db.qualityProfileDao().selectAll(dbSession, organization);
return db.qualityProfileDao().selectOrderedByOrganizationUuid(dbSession, organization);
}

public Collection<QProfileDto> profiles(DbSession dbSession, String language, OrganizationDto organization) {

+ 5
- 6
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileResetImpl.java View File

@@ -29,7 +29,6 @@ import org.sonar.api.server.ServerSide;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.qualityprofile.ActiveRuleDto;
import org.sonar.db.qualityprofile.ActiveRuleKey;
import org.sonar.db.qualityprofile.QProfileDto;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
@@ -57,16 +56,16 @@ public class QProfileResetImpl implements QProfileReset {
BulkChangeResult result = new BulkChangeResult();
Set<RuleKey> ruleToBeDeactivated = Sets.newHashSet();
// Keep reference to all the activated rules before backup restore
for (ActiveRuleDto activeRuleDto : db.activeRuleDao().selectByProfileKey(dbSession, profile.getKee())) {
for (ActiveRuleDto activeRuleDto : db.activeRuleDao().selectByProfile(dbSession, profile)) {
if (activeRuleDto.getInheritance() == null) {
// inherited rules can't be deactivated
ruleToBeDeactivated.add(activeRuleDto.getKey().ruleKey());
ruleToBeDeactivated.add(activeRuleDto.getRuleKey());
}
}

for (RuleActivation activation : activations) {
try {
List<ActiveRuleChange> changes = activator.activate(dbSession, activation, profile.getKee());
List<ActiveRuleChange> changes = activator.activate(dbSession, activation, profile);
ruleToBeDeactivated.remove(activation.getRuleKey());
result.incrementSucceeded();
result.addChanges(changes);
@@ -80,13 +79,13 @@ public class QProfileResetImpl implements QProfileReset {
changes.addAll(result.getChanges());
for (RuleKey ruleKey : ruleToBeDeactivated) {
try {
changes.addAll(activator.deactivate(dbSession, ActiveRuleKey.of(profile.getKee(), ruleKey)));
changes.addAll(activator.deactivate(dbSession, profile, ruleKey));
} catch (BadRequestException e) {
// ignore, probably a rule inherited from parent that can't be deactivated
}
}
dbSession.commit();
activeRuleIndexer.index(changes);
activeRuleIndexer.indexChanges(dbSession, changes);
return result;
}


+ 21
- 33
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RegisterQualityProfiles.java View File

@@ -21,14 +21,14 @@ package org.sonar.server.qualityprofile;

import java.util.Collection;
import java.util.List;
import java.util.Set;
import org.sonar.api.server.ServerSide;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.api.utils.log.Profiler;
import org.sonar.core.util.stream.MoreCollectors;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;

import static java.lang.String.format;

@@ -43,55 +43,41 @@ public class RegisterQualityProfiles {
private final BuiltInQProfileRepository builtInQProfileRepository;
private final DbClient dbClient;
private final BuiltInQProfileInsert builtInQProfileInsert;
private final ActiveRuleIndexer activeRuleIndexer;

public RegisterQualityProfiles(BuiltInQProfileRepository builtInQProfileRepository,
DbClient dbClient, BuiltInQProfileInsert builtInQProfileInsert, ActiveRuleIndexer activeRuleIndexer) {
DbClient dbClient, BuiltInQProfileInsert builtInQProfileInsert) {
this.builtInQProfileRepository = builtInQProfileRepository;
this.dbClient = dbClient;
this.builtInQProfileInsert = builtInQProfileInsert;
this.activeRuleIndexer = activeRuleIndexer;
}

public void start() {
Profiler profiler = Profiler.create(Loggers.get(getClass())).startInfo("Register quality profiles");
if (builtInQProfileRepository.getQProfilesByLanguage().isEmpty()) {
List<BuiltInQProfile> builtInQProfiles = builtInQProfileRepository.get();
if (builtInQProfiles.isEmpty()) {
return;
}

try (DbSession session = dbClient.openSession(false);
DbSession batchSession = dbClient.openSession(true)) {
builtInQProfileRepository.getQProfilesByLanguage()
.forEach((key, value) -> registerPerLanguage(session, batchSession, value));
activeRuleIndexer.index();
profiler.stopDebug();
}
}
Profiler profiler = Profiler.create(Loggers.get(getClass())).startInfo("Register quality profiles");
try (DbSession dbSession = dbClient.openSession(false);
DbSession batchDbSession = dbClient.openSession(true)) {

Set<QProfileName> namesExistingInDb = dbClient.qualityProfileDao().selectBuiltInRulesProfiles(dbSession).stream()
.map(dto -> new QProfileName(dto.getLanguage(), dto.getName()))
.collect(MoreCollectors.toSet());

private void registerPerLanguage(DbSession session, DbSession batchSession, List<BuiltInQProfile> qualityProfiles) {
qualityProfiles.forEach(qp -> registerPerQualityProfile(session, batchSession, qp));
builtInQProfiles.stream()
.filter(p -> !namesExistingInDb.contains(p.getQProfileName()))
.forEach(profile -> register(dbSession, batchDbSession, profile));
}
profiler.stopDebug();
}

private void registerPerQualityProfile(DbSession dbSession, DbSession batchSession, BuiltInQProfile builtInProfile) {
private void register(DbSession dbSession, DbSession batchDbSession, BuiltInQProfile builtInProfile) {
LOGGER.info("Register profile {}", builtInProfile.getQProfileName());

Profiler profiler = Profiler.create(Loggers.get(getClass()));
renameOutdatedProfiles(dbSession, builtInProfile);

dbClient.organizationDao().selectWithoutQualityProfile(dbSession, builtInProfile.getLanguage(), builtInProfile.getName()).forEach(
organization -> registerProfileOnOrganization(dbSession, batchSession, builtInProfile, organization, profiler));
}

private void registerProfileOnOrganization(DbSession session, DbSession batchSession,
BuiltInQProfile builtInQProfile, OrganizationDto organization, Profiler profiler) {
profiler.start();

builtInQProfileInsert.create(session, batchSession, builtInQProfile, organization);

session.commit();
batchSession.commit();

profiler.stopDebug(format("Register profile %s for organization %s", builtInQProfile.getQProfileName(), organization.getKey()));
builtInQProfileInsert.create(dbSession, batchDbSession, builtInProfile);
}

/**
@@ -108,8 +94,10 @@ public class RegisterQualityProfiles {
if (uuids.isEmpty()) {
return;
}
Profiler profiler = Profiler.createIfDebug(Loggers.get(getClass())).start();
String newName = profile.getName() + " (outdated copy)";
LOGGER.info("Rename Quality profiles [{}/{}] to [{}] in {} organizations", profile.getLanguage(), profile.getName(), newName, uuids.size());
dbClient.qualityProfileDao().renameRulesProfilesAndCommit(dbSession, uuids, newName);
profiler.stopDebug(format("%d Quality profiles renamed to [%s]", uuids.size(), newName));
}
}

+ 81
- 107
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivator.java View File

@@ -36,7 +36,6 @@ import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.qualityprofile.ActiveRuleDao;
import org.sonar.db.qualityprofile.ActiveRuleDto;
import org.sonar.db.qualityprofile.ActiveRuleKey;
import org.sonar.db.qualityprofile.ActiveRuleParamDto;
import org.sonar.db.qualityprofile.QProfileDto;
import org.sonar.db.rule.RuleDefinitionDto;
@@ -77,11 +76,6 @@ public class RuleActivator {
this.userSession = userSession;
}

public List<ActiveRuleChange> activate(DbSession dbSession, RuleActivation activation, String profileKey) {
RuleActivatorContext context = contextFactory.create(profileKey, activation.getRuleKey(), dbSession);
return doActivate(dbSession, activation, context);
}

public List<ActiveRuleChange> activate(DbSession dbSession, RuleActivation activation, QProfileDto profileDto) {
RuleActivatorContext context = contextFactory.create(profileDto, activation.getRuleKey(), dbSession);
return doActivate(dbSession, activation, context);
@@ -100,7 +94,7 @@ public class RuleActivator {
return changes;
}
// new activation
change = ActiveRuleChange.createFor(ActiveRuleChange.Type.ACTIVATED, context.activeRuleKey());
change = new ActiveRuleChange(ActiveRuleChange.Type.ACTIVATED, context.activeRuleKey());
applySeverityAndParamToChange(activation, context, change);
if (activation.isCascade() || context.isSameAsParent(change)) {
change.setInheritance(ActiveRule.Inheritance.INHERITED);
@@ -111,7 +105,7 @@ public class RuleActivator {
// propagating to descendants, but child profile already overrides rule -> stop propagation
return changes;
}
change = ActiveRuleChange.createFor(ActiveRuleChange.Type.UPDATED, context.activeRuleKey());
change = new ActiveRuleChange(ActiveRuleChange.Type.UPDATED, context.activeRuleKey());
if (activation.isCascade() && activeRule.getInheritance() == null) {
// activate on child, then on parent -> mark child as overriding parent
change.setInheritance(ActiveRule.Inheritance.OVERRIDES);
@@ -224,21 +218,19 @@ public class RuleActivator {
return null;
}

private List<ActiveRuleChange> cascadeActivation(DbSession session, RuleActivation activation, QProfileDto qProfileDto) {
List<ActiveRuleChange> changes = Lists.newArrayList();
private List<ActiveRuleChange> cascadeActivation(DbSession dbSession, RuleActivation activation, QProfileDto profile) {
List<ActiveRuleChange> changes = new ArrayList<>();

// get all inherited profiles
String qualityProfileKey = qProfileDto.getKee();
List<QProfileDto> children = getChildren(session, qualityProfileKey);
for (QProfileDto child : children) {
getChildren(dbSession, profile).forEach(child -> {
RuleActivation childActivation = new RuleActivation(activation).setCascade(true);
changes.addAll(activate(session, childActivation, child));
}
changes.addAll(activate(dbSession, childActivation, child));
});
return changes;
}

protected List<QProfileDto> getChildren(DbSession session, String qualityProfileKey) {
return db.qualityProfileDao().selectChildren(session, qualityProfileKey);
protected List<QProfileDto> getChildren(DbSession session, QProfileDto profile) {
return db.qualityProfileDao().selectChildren(session, profile);
}

private ActiveRuleDto persist(ActiveRuleChange change, RuleActivatorContext context, DbSession dbSession) {
@@ -247,12 +239,12 @@ public class RuleActivator {
activeRule = doInsert(change, context, dbSession);
} else if (change.getType() == ActiveRuleChange.Type.DEACTIVATED) {
ActiveRuleDao dao = db.activeRuleDao();
dao.delete(dbSession, change.getKey());
activeRule = dao.delete(dbSession, change.getKey()).orElse(null);

} else if (change.getType() == ActiveRuleChange.Type.UPDATED) {
activeRule = doUpdate(change, context, dbSession);
}
change.setActiveRule(activeRule);
db.qProfileChangeDao().insert(dbSession, change.toDto(userSession.getLogin()));
return activeRule;
}
@@ -309,9 +301,9 @@ public class RuleActivator {
} else {
if (param.getValue() != null) {
activeRuleParamDto.setValue(param.getValue());
dao.updateParam(dbSession, activeRule, activeRuleParamDto);
dao.updateParam(dbSession, activeRuleParamDto);
} else {
dao.deleteParam(dbSession, activeRule, activeRuleParamDto);
dao.deleteParam(dbSession, activeRuleParamDto);
}
}
}
@@ -323,28 +315,27 @@ public class RuleActivator {
* Deactivate a rule on a Quality profile. Does nothing if the rule is not activated, but
* fails (fast) if the rule or the profile does not exist.
*/
public List<ActiveRuleChange> deactivateAndUpdateIndex(DbSession dbSession, ActiveRuleKey key) {
List<ActiveRuleChange> changes = deactivate(dbSession, key);
public void deactivateAndUpdateIndex(DbSession dbSession, QProfileDto profile, RuleKey ruleKey) {
List<ActiveRuleChange> changes = deactivate(dbSession, profile, ruleKey);
dbSession.commit();
activeRuleIndexer.index(changes);
return changes;
activeRuleIndexer.indexChanges(dbSession, changes);
}

/**
* Deactivate a rule on a Quality profile WITHOUT committing db session and WITHOUT checking permissions
*/
List<ActiveRuleChange> deactivate(DbSession dbSession, ActiveRuleKey key) {
return deactivate(dbSession, key, false);
List<ActiveRuleChange> deactivate(DbSession dbSession, QProfileDto profile, RuleKey ruleKey) {
return deactivate(dbSession, profile, ruleKey, false);
}

/**
* Deactivate a rule on a Quality profile WITHOUT committing db session, WITHOUT checking permissions, and forcing removal of inherited rules
*/
public List<ActiveRuleChange> deactivateOfAllOrganizations(DbSession dbSession, RuleDefinitionDto ruleDto) {
List<ActiveRuleChange> changes = Lists.newArrayList();
List<ActiveRuleDto> activeRules = db.activeRuleDao().selectByRuleIdOfAllOrganizations(dbSession, ruleDto.getId());
public List<ActiveRuleChange> deactivateOfAllOrganizations(DbSession dbSession, RuleDefinitionDto rule) {
List<ActiveRuleChange> changes = new ArrayList<>();
List<ActiveRuleDto> activeRules = db.activeRuleDao().selectByRuleIdOfAllOrganizations(dbSession, rule.getId());
for (ActiveRuleDto activeRule : activeRules) {
changes.addAll(deactivate(dbSession, activeRule.getKey(), true));
// FIXME changes.addAll(deactivate(dbSession, activeRule.getKey(), rule.getKey(), true));
}
return changes;
}
@@ -352,30 +343,26 @@ public class RuleActivator {
/**
* @param force if true then inherited rules are deactivated
*/
public List<ActiveRuleChange> deactivate(DbSession dbSession, ActiveRuleKey key, boolean force) {
return cascadeDeactivation(key, dbSession, false, force);
public List<ActiveRuleChange> deactivate(DbSession dbSession, QProfileDto profile, RuleKey ruleKey, boolean force) {
return cascadeDeactivation(dbSession, profile, ruleKey, false, force);
}

private List<ActiveRuleChange> cascadeDeactivation(ActiveRuleKey key, DbSession dbSession, boolean isCascade, boolean force) {
List<ActiveRuleChange> changes = Lists.newArrayList();
RuleActivatorContext context = contextFactory.create(key.qProfile(), key.ruleKey(), dbSession);
private List<ActiveRuleChange> cascadeDeactivation(DbSession dbSession, QProfileDto profile, RuleKey ruleKey, boolean isCascade, boolean force) {
List<ActiveRuleChange> changes = new ArrayList<>();
RuleActivatorContext context = contextFactory.create(profile, ruleKey, dbSession);
ActiveRuleChange change;
ActiveRuleDto activeRuleDto = context.activeRule();
if (activeRuleDto == null) {
return changes;
}
checkRequest(force || isCascade || activeRuleDto.getInheritance() == null, "Cannot deactivate inherited rule '%s'", key.ruleKey());
change = ActiveRuleChange.createFor(ActiveRuleChange.Type.DEACTIVATED, key);
checkRequest(force || isCascade || activeRuleDto.getInheritance() == null, "Cannot deactivate inherited rule '%s'", ruleKey);
change = new ActiveRuleChange(ActiveRuleChange.Type.DEACTIVATED, activeRuleDto);
changes.add(change);
persist(change, context, dbSession);

// get all inherited profiles
List<QProfileDto> profiles = getChildren(dbSession, key.qProfile());

for (QProfileDto profile : profiles) {
ActiveRuleKey activeRuleKey = ActiveRuleKey.of(profile.getKee(), key.ruleKey());
changes.addAll(cascadeDeactivation(activeRuleKey, dbSession, true, force));
}
getChildren(dbSession, profile).forEach(child -> changes.addAll(cascadeDeactivation(dbSession, child, ruleKey, true, force)));

if (!changes.isEmpty()) {
updateProfileDates(dbSession, context);
@@ -398,83 +385,70 @@ public class RuleActivator {
return value;
}

public BulkChangeResult bulkActivate(RuleQuery ruleQuery, String profileKey, @Nullable String severity) {
DbSession dbSession = db.openSession(false);
public BulkChangeResult bulkActivate(DbSession dbSession, RuleQuery ruleQuery, QProfileDto profile, @Nullable String severity) {
BulkChangeResult result = new BulkChangeResult();
try {
Iterator<RuleKey> rules = ruleIndex.searchAll(ruleQuery);
while (rules.hasNext()) {
RuleKey ruleKey = rules.next();
try {
RuleActivation activation = new RuleActivation(ruleKey);
activation.setSeverity(severity);
List<ActiveRuleChange> changes = activate(dbSession, activation, profileKey);
result.addChanges(changes);
if (!changes.isEmpty()) {
result.incrementSucceeded();
}

} catch (BadRequestException e) {
// other exceptions stop the bulk activation
result.incrementFailed();
result.getErrors().addAll(e.errors());
Iterator<RuleKey> rules = ruleIndex.searchAll(ruleQuery);
while (rules.hasNext()) {
RuleKey ruleKey = rules.next();
try {
RuleActivation activation = new RuleActivation(ruleKey);
activation.setSeverity(severity);
List<ActiveRuleChange> changes = activate(dbSession, activation, profile);
result.addChanges(changes);
if (!changes.isEmpty()) {
result.incrementSucceeded();
}

} catch (BadRequestException e) {
// other exceptions stop the bulk activation
result.incrementFailed();
result.getErrors().addAll(e.errors());
}
dbSession.commit();
activeRuleIndexer.index(result.getChanges());
} finally {
dbSession.close();
}
dbSession.commit();
activeRuleIndexer.indexChanges(dbSession, result.getChanges());
return result;
}

public BulkChangeResult bulkDeactivate(RuleQuery ruleQuery, String profile) {
DbSession dbSession = db.openSession(false);
public BulkChangeResult bulkDeactivate(DbSession dbSession, RuleQuery ruleQuery, QProfileDto profile) {
BulkChangeResult result = new BulkChangeResult();
try {
Iterator<RuleKey> rules = ruleIndex.searchAll(ruleQuery);
while (rules.hasNext()) {
try {
RuleKey ruleKey = rules.next();
ActiveRuleKey key = ActiveRuleKey.of(profile, ruleKey);
List<ActiveRuleChange> changes = deactivate(dbSession, key);
result.addChanges(changes);
if (!changes.isEmpty()) {
result.incrementSucceeded();
}
} catch (BadRequestException e) {
// other exceptions stop the bulk activation
result.incrementFailed();
result.getErrors().addAll(e.errors());
Iterator<RuleKey> rules = ruleIndex.searchAll(ruleQuery);
while (rules.hasNext()) {
try {
RuleKey ruleKey = rules.next();
List<ActiveRuleChange> changes = deactivate(dbSession, profile, ruleKey);
result.addChanges(changes);
if (!changes.isEmpty()) {
result.incrementSucceeded();
}
} catch (BadRequestException e) {
// other exceptions stop the bulk activation
result.incrementFailed();
result.getErrors().addAll(e.errors());
}
dbSession.commit();
activeRuleIndexer.index(result.getChanges());
return result;
} finally {
dbSession.close();
}
dbSession.commit();
activeRuleIndexer.indexChanges(dbSession, result.getChanges());
return result;
}

public List<ActiveRuleChange> setParent(DbSession dbSession, String profileKey, @Nullable String parentKey) {
QProfileDto profile = db.qualityProfileDao().selectOrFailByUuid(dbSession, profileKey);
public List<ActiveRuleChange> setParent(DbSession dbSession, QProfileDto profile, @Nullable QProfileDto parent) {
List<ActiveRuleChange> changes = new ArrayList<>();
if (parentKey == null) {
if (parent == null) {
// unset if parent is defined, else nothing to do
changes.addAll(removeParent(dbSession, profile));

} else if (profile.getParentKee() == null || !parentKey.equals(profile.getParentKee())) {
QProfileDto parentProfile = db.qualityProfileDao().selectOrFailByUuid(dbSession, parentKey);
checkRequest(!isDescendant(dbSession, profile, parentProfile), "Descendant profile '%s' can not be selected as parent of '%s'", parentKey, profileKey);
} else if (profile.getParentKee() == null || !parent.getKee().equals(profile.getParentKee())) {
checkRequest(!isDescendant(dbSession, profile, parent), "Descendant profile '%s' can not be selected as parent of '%s'", parent.getKee(), profile.getKee());
changes.addAll(removeParent(dbSession, profile));

// set new parent
profile.setParentKee(parentKey);
profile.setParentKee(parent.getKee());
db.qualityProfileDao().update(dbSession, profile);
for (ActiveRuleDto parentActiveRule : db.activeRuleDao().selectByProfileKey(dbSession, parentKey)) {
for (ActiveRuleDto parentActiveRule : db.activeRuleDao().selectByProfile(dbSession, parent)) {
try {
RuleActivation activation = new RuleActivation(parentActiveRule.getKey().ruleKey());
changes.addAll(activate(dbSession, activation, profileKey));
RuleActivation activation = new RuleActivation(parentActiveRule.getRuleKey());
changes.addAll(activate(dbSession, activation, profile));
} catch (BadRequestException e) {
// for example because rule status is REMOVED
// TODO return errors
@@ -482,26 +456,26 @@ public class RuleActivator {
}
}
dbSession.commit();
activeRuleIndexer.index(changes);
activeRuleIndexer.indexChanges(dbSession, changes);
return changes;
}

/**
* Does not commit
*/
private List<ActiveRuleChange> removeParent(DbSession dbSession, QProfileDto profileDto) {
if (profileDto.getParentKee() != null) {
private List<ActiveRuleChange> removeParent(DbSession dbSession, QProfileDto profile) {
if (profile.getParentKee() != null) {
List<ActiveRuleChange> changes = new ArrayList<>();
profileDto.setParentKee(null);
db.qualityProfileDao().update(dbSession, profileDto);
for (ActiveRuleDto activeRule : db.activeRuleDao().selectByProfileKey(dbSession, profileDto.getKee())) {
profile.setParentKee(null);
db.qualityProfileDao().update(dbSession, profile);
for (ActiveRuleDto activeRule : db.activeRuleDao().selectByProfile(dbSession, profile)) {
if (ActiveRuleDto.INHERITED.equals(activeRule.getInheritance())) {
changes.addAll(deactivate(dbSession, activeRule.getKey(), true));
changes.addAll(deactivate(dbSession, profile, activeRule.getRuleKey(), true));
} else if (ActiveRuleDto.OVERRIDES.equals(activeRule.getInheritance())) {
activeRule.setInheritance(null);
activeRule.setUpdatedAt(system2.now());
db.activeRuleDao().update(dbSession, activeRule);
changes.add(ActiveRuleChange.createFor(ActiveRuleChange.Type.UPDATED, activeRule.getKey()).setInheritance(null));
changes.add(new ActiveRuleChange(ActiveRuleChange.Type.UPDATED, activeRule).setInheritance(null));
}
}
return changes;
@@ -509,7 +483,7 @@ public class RuleActivator {
return Collections.emptyList();
}

boolean isDescendant(DbSession dbSession, QProfileDto childProfile, @Nullable QProfileDto parentProfile) {
private boolean isDescendant(DbSession dbSession, QProfileDto childProfile, @Nullable QProfileDto parentProfile) {
QProfileDto currentParent = parentProfile;
while (currentParent != null) {
if (childProfile.getName().equals(currentParent.getName())) {

+ 1
- 1
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivatorContext.java View File

@@ -51,7 +51,7 @@ class RuleActivatorContext {
}

ActiveRuleKey activeRuleKey() {
return ActiveRuleKey.of(profile.getKee(), rule.getKey());
return ActiveRuleKey.of(profile, rule.getKey());
}

RuleDefinitionDto rule() {

+ 11
- 18
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivatorContextFactory.java View File

@@ -44,24 +44,17 @@ public class RuleActivatorContextFactory {
this.db = db;
}

RuleActivatorContext create(String profileKey, RuleKey ruleKey, DbSession session) {
RuleActivatorContext context = new RuleActivatorContext();
QProfileDto profile = getQualityProfileDto(session, profileKey);
checkRequest(profile != null, "Quality profile not found: %s", profileKey);
context.setProfile(profile);
return create(ruleKey, session, context);
}

RuleActivatorContext create(QProfileDto profile, RuleKey ruleKey, DbSession session) {
return create(ruleKey, session, new RuleActivatorContext().setProfile(profile));
}

private RuleActivatorContext create(RuleKey ruleKey, DbSession session, RuleActivatorContext context) {
initRule(ruleKey, context, session);
initActiveRules(context.profile().getKee(), ruleKey, context, session, false);
private RuleActivatorContext create(RuleKey ruleKey, DbSession dbSession, RuleActivatorContext context) {
initRule(ruleKey, context, dbSession);
initActiveRules(context.profile(), ruleKey, context, dbSession, false);
String parentKee = context.profile().getParentKee();
if (parentKee != null) {
initActiveRules(parentKee, ruleKey, context, session, true);
QProfileDto parent = getQualityProfileDto(dbSession, parentKee);
initActiveRules(parent, ruleKey, context, dbSession, true);
}
return context;
}
@@ -75,8 +68,8 @@ public class RuleActivatorContextFactory {
return ruleDefinitionDto;
}

private void initActiveRules(String profileKey, RuleKey ruleKey, RuleActivatorContext context, DbSession session, boolean parent) {
ActiveRuleKey key = ActiveRuleKey.of(profileKey, ruleKey);
private void initActiveRules(QProfileDto profile, RuleKey ruleKey, RuleActivatorContext context, DbSession session, boolean parent) {
ActiveRuleKey key = ActiveRuleKey.of(profile, ruleKey);
Optional<ActiveRuleDto> activeRule = getActiveRule(session, key);
Collection<ActiveRuleParamDto> activeRuleParams = null;
if (activeRule.isPresent()) {
@@ -103,11 +96,11 @@ public class RuleActivatorContextFactory {
return db.ruleDao().selectRuleParamsByRuleKey(dbSession, ruleDefinitionDto.getKey());
}

Optional<ActiveRuleDto> getActiveRule(DbSession session, ActiveRuleKey key) {
return Optional.ofNullable(db.activeRuleDao().selectByKey(session, key).orNull());
Optional<ActiveRuleDto> getActiveRule(DbSession dbSession, ActiveRuleKey key) {
return db.activeRuleDao().selectByKey(dbSession, key);
}

List<ActiveRuleParamDto> getActiveRuleParams(DbSession session, ActiveRuleDto activeRuleDto) {
return db.activeRuleDao().selectParamsByActiveRuleId(session, activeRuleDto.getId());
List<ActiveRuleParamDto> getActiveRuleParams(DbSession dbSession, ActiveRuleDto activeRuleDto) {
return db.activeRuleDao().selectParamsByActiveRuleId(dbSession, activeRuleDto.getId());
}
}

+ 32
- 37
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/index/ActiveRuleDoc.java View File

@@ -20,39 +20,33 @@
package org.sonar.server.qualityprofile.index;

import com.google.common.collect.Maps;
import java.util.Map;
import javax.annotation.Nullable;
import org.sonar.db.qualityprofile.ActiveRuleKey;
import org.sonar.api.rule.RuleKey;
import org.sonar.server.es.BaseDoc;
import org.sonar.server.qualityprofile.ActiveRule;

import static com.google.common.base.Preconditions.checkNotNull;
import static org.apache.commons.lang.StringUtils.containsIgnoreCase;
import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_RULE_INHERITANCE;
import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_RULE_KEY;
import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_RULE_ORGANIZATION_UUID;
import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_RULE_PROFILE_KEY;
import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_RULE_PROFILE_UUID;
import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_RULE_REPOSITORY;
import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_RULE_RULE_KEY;
import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_RULE_SEVERITY;
import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_RULE_UPDATED_AT;

public class ActiveRuleDoc extends BaseDoc {

private final ActiveRuleKey key;

public ActiveRuleDoc(ActiveRuleKey key) {
public ActiveRuleDoc(String id) {
super(Maps.newHashMapWithExpectedSize(9));
checkNotNull(key, "ActiveRuleKey cannot be null");
this.key = key;
setField(FIELD_ACTIVE_RULE_KEY, key.toString());
setField(FIELD_ACTIVE_RULE_PROFILE_KEY, key.qProfile());
setField(FIELD_ACTIVE_RULE_RULE_KEY, key.ruleKey().toString());
setField(FIELD_ACTIVE_RULE_REPOSITORY, key.ruleKey().repository());
setField("_id", id);
}

public ActiveRuleDoc(Map<String,Object> source) {
super(source);
}

@Override
public String getId() {
return key().toString();
return getField("_id");
}

@Override
@@ -62,32 +56,42 @@ public class ActiveRuleDoc extends BaseDoc {

@Override
public String getParent() {
return key.ruleKey().toString();
return getRuleKey().toString();
}

public ActiveRuleKey key() {
return key;
RuleKey getRuleKey() {
return RuleKey.parse(getField(FIELD_ACTIVE_RULE_RULE_KEY));
}

String organizationUuid() {
return getField(FIELD_ACTIVE_RULE_ORGANIZATION_UUID);
String getRuleRepository() {
return getField(FIELD_ACTIVE_RULE_REPOSITORY);
}

public ActiveRuleDoc setOrganizationUuid(String s) {
setField(FIELD_ACTIVE_RULE_ORGANIZATION_UUID, s);
String getSeverity() {
return getNullableField(FIELD_ACTIVE_RULE_SEVERITY);
}

ActiveRuleDoc setSeverity(@Nullable String s) {
setField(FIELD_ACTIVE_RULE_SEVERITY, s);
return this;
}

String severity() {
return getNullableField(FIELD_ACTIVE_RULE_SEVERITY);
ActiveRuleDoc setRuleKey(RuleKey ruleKey) {
setField(FIELD_ACTIVE_RULE_RULE_KEY, ruleKey.toString());
setField(FIELD_ACTIVE_RULE_REPOSITORY, ruleKey.repository());
return this;
}

public ActiveRuleDoc setSeverity(@Nullable String s) {
setField(FIELD_ACTIVE_RULE_SEVERITY, s);
String getRuleProfileUuid() {
return getField(FIELD_ACTIVE_RULE_PROFILE_UUID);
}

ActiveRuleDoc setRuleProfileUuid(String s) {
setField(FIELD_ACTIVE_RULE_PROFILE_UUID, s);
return this;
}

ActiveRule.Inheritance inheritance() {
ActiveRule.Inheritance getInheritance() {
String inheritance = getNullableField(FIELD_ACTIVE_RULE_INHERITANCE);
if (inheritance == null || inheritance.isEmpty() ||
containsIgnoreCase(inheritance, "none")) {
@@ -105,13 +109,4 @@ public class ActiveRuleDoc extends BaseDoc {
setField(FIELD_ACTIVE_RULE_INHERITANCE, s);
return this;
}

long updatedAt() {
return (Long) getField(FIELD_ACTIVE_RULE_UPDATED_AT);
}

public ActiveRuleDoc setUpdatedAt(@Nullable Long l) {
setField(FIELD_ACTIVE_RULE_UPDATED_AT, l);
return this;
}
}

+ 75
- 54
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/index/ActiveRuleIndexer.java View File

@@ -19,107 +19,128 @@
*/
package org.sonar.server.qualityprofile.index;

import com.google.common.collect.ImmutableSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.sonar.api.utils.System2;
import org.sonar.core.util.stream.MoreCollectors;
import org.sonar.api.rule.RuleKey;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.qualityprofile.ActiveRuleKey;
import org.sonar.server.es.BaseIndexer;
import org.sonar.db.qualityprofile.QProfileDto;
import org.sonar.db.qualityprofile.RulesProfileDto;
import org.sonar.server.es.BulkIndexer;
import org.sonar.server.es.BulkIndexer.Size;
import org.sonar.server.es.EsClient;
import org.sonar.server.es.IndexType;
import org.sonar.server.es.StartupIndexer;
import org.sonar.server.qualityprofile.ActiveRuleChange;
import org.sonar.server.rule.index.RuleIndexDefinition;

import static org.elasticsearch.index.query.QueryBuilders.termsQuery;
import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_RULE_KEY;
import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_RULE_PROFILE_KEY;
import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_RULE_UPDATED_AT;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_RULE_PROFILE_UUID;
import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_RULE_RULE_KEY;
import static org.sonar.server.rule.index.RuleIndexDefinition.INDEX_TYPE_ACTIVE_RULE;

public class ActiveRuleIndexer extends BaseIndexer {
public class ActiveRuleIndexer implements StartupIndexer {

private final DbClient dbClient;
private final EsClient esClient;
private final ActiveRuleIteratorFactory activeRuleIteratorFactory;

public ActiveRuleIndexer(System2 system2, DbClient dbClient, EsClient esClient) {
super(system2, esClient, 300, INDEX_TYPE_ACTIVE_RULE, FIELD_ACTIVE_RULE_UPDATED_AT);
public ActiveRuleIndexer(DbClient dbClient, EsClient esClient, ActiveRuleIteratorFactory activeRuleIteratorFactory) {
this.dbClient = dbClient;
this.esClient = esClient;
this.activeRuleIteratorFactory = activeRuleIteratorFactory;
}

@Override
protected long doIndex(long lastUpdatedAt) {
return doIndex(createBulkIndexer(), lastUpdatedAt);
public void indexOnStartup(Set<IndexType> emptyIndexTypes) {
try (DbSession dbSession = dbClient.openSession(false)) {
ActiveRuleIterator dbCursor = activeRuleIteratorFactory.createForAll(dbSession);
scrollDbAndIndex(dbCursor, Size.LARGE);
}
}

public void index(Iterator<ActiveRuleDoc> rules) {
doIndex(createBulkIndexer(), rules);
@Override
public Set<IndexType> getIndexTypes() {
return ImmutableSet.of(RuleIndexDefinition.INDEX_TYPE_ACTIVE_RULE);
}

private long doIndex(BulkIndexer bulk, long lastUpdatedAt) {
long maxDate;
try (DbSession dbSession = dbClient.openSession(false)) {
ActiveRuleResultSetIterator rowIt = ActiveRuleResultSetIterator.create(dbClient, dbSession, lastUpdatedAt);
maxDate = doIndex(bulk, rowIt);
rowIt.close();
return maxDate;
/**
* Important - the existing documents are not deleted, so this method
* does not guarantee consistency of index.
*/
public void indexRuleProfile(DbSession dbSession, RulesProfileDto ruleProfile) {
try (ActiveRuleIterator dbCursor = activeRuleIteratorFactory.createForRuleProfile(dbSession, ruleProfile)) {
scrollDbAndIndex(dbCursor, Size.REGULAR);
}
}

private static long doIndex(BulkIndexer bulk, Iterator<ActiveRuleDoc> activeRules) {
public void indexChanges(DbSession dbSession, List<ActiveRuleChange> changes) {
BulkIndexer bulk = createBulkIndexer(Size.REGULAR);
bulk.start();
long maxDate = 0L;
while (activeRules.hasNext()) {
ActiveRuleDoc activeRule = activeRules.next();
bulk.add(newIndexRequest(activeRule));

// it's more efficient to sort programmatically than in SQL on some databases (MySQL for instance)
maxDate = Math.max(maxDate, activeRule.updatedAt());
List<Integer> idsOfTouchedActiveRules = new ArrayList<>();
changes.stream()
.filter(c -> c.getActiveRule() != null)
.forEach(c -> {
if (c.getType().equals(ActiveRuleChange.Type.DEACTIVATED)) {
bulk.addDeletion(INDEX_TYPE_ACTIVE_RULE, String.valueOf(c.getActiveRule().getId()));
} else {
idsOfTouchedActiveRules.add(c.getActiveRule().getId());
}
});
try (ActiveRuleIterator dbCursor = activeRuleIteratorFactory.createForActiveRules(dbSession, idsOfTouchedActiveRules)) {
while (dbCursor.hasNext()) {
ActiveRuleDoc activeRule = dbCursor.next();
bulk.add(newIndexRequest(activeRule));
}
}
bulk.stop();
return maxDate;
}

public void index(List<ActiveRuleChange> changes) {
deleteKeys(changes.stream()
.filter(c -> c.getType().equals(ActiveRuleChange.Type.DEACTIVATED))
.map(ActiveRuleChange::getKey)
.collect(MoreCollectors.toList(changes.size())));

index();
}

public void deleteByProfileKeys(Collection<String> profileKeys) {
BulkIndexer bulk = createBulkIndexer();
public void deleteByProfiles(Collection<QProfileDto> profiles) {
BulkIndexer bulk = createBulkIndexer(Size.REGULAR);
bulk.start();
profileKeys.forEach(profileKey -> {
profiles.forEach(profile -> {
SearchRequestBuilder search = esClient.prepareSearch(INDEX_TYPE_ACTIVE_RULE)
.setQuery(QueryBuilders.boolQuery().must(termsQuery(FIELD_ACTIVE_RULE_PROFILE_KEY, profileKey)));
.setQuery(QueryBuilders.boolQuery().must(termQuery(FIELD_ACTIVE_RULE_PROFILE_UUID, profile.getRulesProfileUuid())));
bulk.addDeletion(search);
});
bulk.stop();
}

private void deleteKeys(List<ActiveRuleKey> keys) {
BulkIndexer bulk = createBulkIndexer();
public void deleteByRuleKeys(Collection<RuleKey> ruleKeys) {
BulkIndexer bulk = createBulkIndexer(Size.REGULAR);
bulk.start();
SearchRequestBuilder search = esClient.prepareSearch(INDEX_TYPE_ACTIVE_RULE)
.setQuery(QueryBuilders.boolQuery().must(termsQuery(FIELD_ACTIVE_RULE_KEY, keys)));
bulk.addDeletion(search);
ruleKeys.forEach(ruleKey -> {
SearchRequestBuilder search = esClient.prepareSearch(INDEX_TYPE_ACTIVE_RULE)
.setQuery(QueryBuilders.boolQuery().must(termQuery(FIELD_ACTIVE_RULE_RULE_KEY, ruleKey.toString())));
bulk.addDeletion(search);
});
bulk.stop();
}

private BulkIndexer createBulkIndexer() {
return new BulkIndexer(esClient, INDEX_TYPE_ACTIVE_RULE.getIndex(), Size.REGULAR);
private BulkIndexer createBulkIndexer(Size size) {
return new BulkIndexer(esClient, INDEX_TYPE_ACTIVE_RULE.getIndex(), size);
}

private static IndexRequest newIndexRequest(ActiveRuleDoc doc) {
return new IndexRequest(INDEX_TYPE_ACTIVE_RULE.getIndex(), INDEX_TYPE_ACTIVE_RULE.getType(), doc.key().toString())
.parent(doc.key().ruleKey().toString())
return new IndexRequest(INDEX_TYPE_ACTIVE_RULE.getIndex(), INDEX_TYPE_ACTIVE_RULE.getType(), doc.getId())
.parent(doc.getRuleKey().toString())
.source(doc.getFields());
}

private void scrollDbAndIndex(ActiveRuleIterator dbCursor, Size size) {
BulkIndexer bulk = new BulkIndexer(esClient, INDEX_TYPE_ACTIVE_RULE.getIndex(), size);
bulk.start();
while (dbCursor.hasNext()) {
ActiveRuleDoc activeRule = dbCursor.next();
bulk.add(newIndexRequest(activeRule));
}
bulk.stop();
}
}

server/sonar-server/src/test/java/org/sonar/server/qualityprofile/index/ActiveRuleDocTesting.java → server/sonar-server/src/main/java/org/sonar/server/qualityprofile/index/ActiveRuleIterator.java View File

@@ -19,23 +19,9 @@
*/
package org.sonar.server.qualityprofile.index;

import org.sonar.api.rule.Severity;
import org.sonar.db.qualityprofile.ActiveRuleKey;
import org.sonar.db.rule.RuleTesting;
import java.util.Iterator;

import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;

public class ActiveRuleDocTesting {

public static ActiveRuleDoc newDoc() {
return newDoc(ActiveRuleKey.of("sonar-way", RuleTesting.XOO_X1));
}

public static ActiveRuleDoc newDoc(ActiveRuleKey key) {
return new ActiveRuleDoc(key)
.setOrganizationUuid(randomAlphabetic(40))
.setSeverity(Severity.CRITICAL)
.setInheritance(null)
.setUpdatedAt(1_600_000_000L);
}
public interface ActiveRuleIterator extends Iterator<ActiveRuleDoc>, AutoCloseable {
@Override
void close();
}

+ 48
- 0
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/index/ActiveRuleIteratorFactory.java View File

@@ -0,0 +1,48 @@
/*
* 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.index;

import java.util.Collection;
import org.sonar.api.server.ServerSide;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.qualityprofile.RulesProfileDto;

@ServerSide
public class ActiveRuleIteratorFactory {

private final DbClient dbClient;

public ActiveRuleIteratorFactory(DbClient dbClient) {
this.dbClient = dbClient;
}

public ActiveRuleIterator createForAll(DbSession dbSession) {
return new ActiveRuleIteratorForSingleChunk(dbClient, dbSession);
}

public ActiveRuleIterator createForRuleProfile(DbSession dbSession, RulesProfileDto ruleProfile) {
return new ActiveRuleIteratorForSingleChunk(dbClient, dbSession, ruleProfile);
}

public ActiveRuleIterator createForActiveRules(DbSession dbSession, Collection<Integer> activeRuleIds) {
return new ActiveRuleIteratorForMultipleChunks(dbClient, dbSession, activeRuleIds);
}
}

+ 69
- 0
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/index/ActiveRuleIteratorForMultipleChunks.java View File

@@ -0,0 +1,69 @@
/*
* 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.index;

import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.sonar.db.DatabaseUtils;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;

import static java.util.Optional.ofNullable;

public class ActiveRuleIteratorForMultipleChunks implements ActiveRuleIterator {

private final DbClient dbClient;
private final DbSession dbSession;
private final Iterator<List<Integer>> iteratorOverChunks;
private ActiveRuleIteratorForSingleChunk currentChunk;

public ActiveRuleIteratorForMultipleChunks(DbClient dbClient, DbSession dbSession, Collection<Integer> activeRuleIds) {
this.dbClient = dbClient;
this.dbSession = dbSession;
this.iteratorOverChunks = DatabaseUtils.toUniqueAndSortedPartitions(activeRuleIds).iterator();
}

@Override
public boolean hasNext() {
if (currentChunk != null && currentChunk.hasNext()) {
return true;
}
return iteratorOverChunks.hasNext();
}

@Override
public ActiveRuleDoc next() {
if (currentChunk == null || !currentChunk.hasNext()) {
currentChunk = nextChunk();
}
return currentChunk.next();
}

private ActiveRuleIteratorForSingleChunk nextChunk() {
List<Integer> nextInput = iteratorOverChunks.next();
return new ActiveRuleIteratorForSingleChunk(dbClient, dbSession, nextInput);
}

@Override
public void close() {
ofNullable(currentChunk).ifPresent(ActiveRuleIterator::close);
}
}

+ 132
- 0
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/index/ActiveRuleIteratorForSingleChunk.java View File

@@ -0,0 +1,132 @@
/*
* 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.index;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.rule.RuleKey;
import org.sonar.db.DatabaseUtils;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.ResultSetIterator;
import org.sonar.db.qualityprofile.RulesProfileDto;
import org.sonar.db.rule.SeverityUtil;
import org.sonar.server.qualityprofile.ActiveRule;

import static org.apache.commons.lang.StringUtils.repeat;

/**
* Scrolls over table ISSUES and reads documents to populate
* the issues index
*/
class ActiveRuleIteratorForSingleChunk implements ActiveRuleIterator {

private static final String[] COLUMNS = {
"ar.id",
"ar.failure_level",
"ar.inheritance",
"r.plugin_name",
"r.plugin_rule_key",
"rp.kee"
};

private static final String SQL_ALL = "select " + StringUtils.join(COLUMNS, ",") + " from active_rules ar " +
" inner join rules_profiles rp on rp.id = ar.profile_id " +
" inner join rules r on r.id = ar.rule_id ";

private final PreparedStatement stmt;
private final ResultSetIterator<ActiveRuleDoc> iterator;

ActiveRuleIteratorForSingleChunk(DbClient dbClient, DbSession dbSession) {
try {
stmt = dbClient.getMyBatis().newScrollingSelectStatement(dbSession, SQL_ALL);
iterator = new ActiveRuleIteratorInternal(stmt);
} catch (Exception e) {
throw new IllegalStateException("Fail to prepare SQL request to select all active_rules", e);
}
}

ActiveRuleIteratorForSingleChunk(DbClient dbClient, DbSession dbSession, RulesProfileDto ruleProfile) {
try {
stmt = dbClient.getMyBatis().newScrollingSelectStatement(dbSession, SQL_ALL + " where rp.kee = ?");
stmt.setString(1, ruleProfile.getKee());
iterator = new ActiveRuleIteratorInternal(stmt);
} catch (Exception e) {
throw new IllegalStateException("Fail to prepare SQL request to select active_rules of profile " + ruleProfile.getKee(), e);
}
}

ActiveRuleIteratorForSingleChunk(DbClient dbClient, DbSession dbSession, List<Integer> activeRuleIds) {
try {
stmt = dbClient.getMyBatis().newScrollingSelectStatement(dbSession, SQL_ALL + " where ar.id in (" + repeat("?", ",", activeRuleIds.size()) + ")");
for (int i = 0; i < activeRuleIds.size(); i++) {
stmt.setInt(i + 1, activeRuleIds.get(i));
}
iterator = new ActiveRuleIteratorInternal(stmt);
} catch (Exception e) {
throw new IllegalStateException("Fail to prepare SQL request to select active_rules", e);
}
}

@Override
public boolean hasNext() {
return iterator.hasNext();
}

@Override
public ActiveRuleDoc next() {
return iterator.next();
}

@Override
public void close() {
try {
iterator.close();
} finally {
DatabaseUtils.closeQuietly(stmt);
}
}

private static final class ActiveRuleIteratorInternal extends ResultSetIterator<ActiveRuleDoc> {

ActiveRuleIteratorInternal(PreparedStatement stmt) throws SQLException {
super(stmt);
}

@Override
protected ActiveRuleDoc read(ResultSet rs) throws SQLException {
long activeRuleId = rs.getLong(1);
int severity = rs.getInt(2);
String inheritance = rs.getString(3);
RuleKey ruleKey = RuleKey.of(rs.getString(4), rs.getString(5));
String ruleProfileUuid = rs.getString(6);

return new ActiveRuleDoc(String.valueOf(activeRuleId))
.setRuleProfileUuid(ruleProfileUuid)
.setRuleKey(ruleKey)
// all the fields must be present, even if value is null
.setSeverity(SeverityUtil.getSeverityFromOrdinal(severity))
.setInheritance(inheritance == null ? ActiveRule.Inheritance.NONE.name() : inheritance);
}
}
}

+ 0
- 93
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/index/ActiveRuleResultSetIterator.java View File

@@ -1,93 +0,0 @@
/*
* 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.index;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.rule.RuleKey;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.ResultSetIterator;
import org.sonar.db.qualityprofile.ActiveRuleKey;
import org.sonar.db.rule.SeverityUtil;
import org.sonar.server.qualityprofile.ActiveRule;

/**
* Scrolls over table ACTIVE_RULES and reads documents to populate the active rules index
*/
public class ActiveRuleResultSetIterator extends ResultSetIterator<ActiveRuleDoc> {

private static final String[] FIELDS = {
"ar.failure_level",
"ar.inheritance",
"r.plugin_name",
"r.plugin_rule_key",
"oqp.organization_uuid",
"oqp.uuid",
"ar.updated_at"
};

private static final String SQL_ALL = "select " + StringUtils.join(FIELDS, ",") + " from active_rules ar " +
" inner join rules_profiles rp on rp.id = ar.profile_id " +
" inner join org_qprofiles oqp on oqp.uuid = rp.kee " +
" inner join rules r on r.id = ar.rule_id ";

private static final String SQL_AFTER_DATE = SQL_ALL + " where ar.updated_at>?";

private ActiveRuleResultSetIterator(PreparedStatement stmt) throws SQLException {
super(stmt);
}

static ActiveRuleResultSetIterator create(DbClient dbClient, DbSession session, long afterDate) {
try {
String sql = afterDate > 0L ? SQL_AFTER_DATE : SQL_ALL;
PreparedStatement stmt = dbClient.getMyBatis().newScrollingSelectStatement(session, sql);
if (afterDate > 0L) {
stmt.setLong(1, afterDate);
}
return new ActiveRuleResultSetIterator(stmt);
} catch (SQLException e) {
throw new IllegalStateException("Fail to prepare SQL request to select all active rules", e);
}
}

@Override
protected ActiveRuleDoc read(ResultSet rs) throws SQLException {
int severity = rs.getInt(1);
String inheritance = rs.getString(2);
RuleKey ruleKey = RuleKey.of(rs.getString(3), rs.getString(4));
String organizationUuid = rs.getString(5);
String profileKey = rs.getString(6);
ActiveRuleKey activeRuleKey = ActiveRuleKey.of(profileKey, ruleKey);

ActiveRuleDoc doc = new ActiveRuleDoc(activeRuleKey);
doc.setOrganizationUuid(organizationUuid);
// all the fields must be present, even if value is null
doc.setSeverity(SeverityUtil.getSeverityFromOrdinal(severity));

doc.setInheritance(inheritance == null ? ActiveRule.Inheritance.NONE.name() : inheritance);

doc.setUpdatedAt(rs.getLong(7));
return doc;
}

}

+ 2
- 2
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ActivateRuleAction.java View File

@@ -110,9 +110,9 @@ public class ActivateRuleAction implements QProfileWsAction {
QProfileDto profile = wsSupport.getProfile(dbSession, QProfileReference.fromKey(profileKey));
wsSupport.checkPermission(dbSession, profile);
wsSupport.checkNotBuiltInt(profile);
List<ActiveRuleChange> changes = ruleActivator.activate(dbSession, activation, profileKey);
List<ActiveRuleChange> changes = ruleActivator.activate(dbSession, activation, profile);
dbSession.commit();
activeRuleIndexer.index(changes);
activeRuleIndexer.indexChanges(dbSession, changes);
}
response.noContent();
}

+ 1
- 1
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ActivateRulesAction.java View File

@@ -86,7 +86,7 @@ public class ActivateRulesAction implements QProfileWsAction {
QProfileDto profile = wsSupport.getProfile(dbSession, fromKey(qualityProfileKey));
wsSupport.checkPermission(dbSession, profile);
wsSupport.checkNotBuiltInt(profile);
result = ruleActivator.bulkActivate(ruleQueryFactory.createRuleQuery(dbSession, request), qualityProfileKey, request.param(SEVERITY));
result = ruleActivator.bulkActivate(dbSession, ruleQueryFactory.createRuleQuery(dbSession, request), profile, request.param(SEVERITY));
}
BulkChangeWsResponse.writeResponse(result, response);
}

+ 2
- 2
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ChangeParentAction.java View File

@@ -95,13 +95,13 @@ public class ChangeParentAction implements QProfileWsAction {
String parentKey = request.param(PARAM_PARENT_KEY);
String parentName = request.param(PARAM_PARENT_NAME);
if (isEmpty(parentKey) && isEmpty(parentName)) {
ruleActivator.setParent(dbSession, profile.getKee(), null);
ruleActivator.setParent(dbSession, profile, null);
} else {
String parentOrganizationKey = parentKey == null ? organization.getKey() : null;
String parentLanguage = parentKey == null ? request.param(PARAM_LANGUAGE) : null;
QProfileReference parentRef = QProfileReference.from(parentKey, parentOrganizationKey, parentLanguage, parentName);
QProfileDto parent = wsSupport.getProfile(dbSession, parentRef);
ruleActivator.setParent(dbSession, profile.getKee(), parent.getKee());
ruleActivator.setParent(dbSession, profile, parent);
}
response.noContent();
}

+ 1
- 1
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ChangelogAction.java View File

@@ -125,7 +125,7 @@ public class ChangelogAction implements QProfileWsAction {
json.endObject().close();
}

private void writeParameters(JsonWriter json, ChangelogLoader.Change change) {
private static void writeParameters(JsonWriter json, ChangelogLoader.Change change) {
json.name("params").beginObject()
.prop("severity", change.getSeverity());
for (Map.Entry<String, String> param : change.getParams().entrySet()) {

+ 2
- 2
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ChangelogLoader.java View File

@@ -58,7 +58,7 @@ public class ChangelogLoader {
.collect(MoreCollectors.toList(dtos.size()));
completeUserAndRuleNames(dbSession, changes);

int total = dbClient.qProfileChangeDao().countForProfileUuid(dbSession, query.getProfileUuid());
int total = dbClient.qProfileChangeDao().countForQProfileUuid(dbSession, query.getProfileUuid());
return new Changelog(total, changes);
}

@@ -158,7 +158,7 @@ public class ChangelogLoader {
private static Change from(QProfileChangeDto dto) {
Map<String, String> data = dto.getDataAsMap();
Change change = new Change();
change.key = dto.getKey();
change.key = dto.getUuid();
change.userLogin = dto.getLogin();
change.type = dto.getChangeType();
change.at = dto.getCreatedAt();

+ 1
- 1
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/CreateAction.java View File

@@ -134,7 +134,7 @@ public class CreateAction implements QProfileWsAction {
}
}
dbSession.commit();
activeRuleIndexer.index(result.getChanges());
activeRuleIndexer.indexChanges(dbSession, result.getChanges());
return buildResponse(result, organization);
}


+ 1
- 3
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/DeactivateRuleAction.java View File

@@ -27,7 +27,6 @@ import org.sonar.api.server.ws.WebService;
import org.sonar.core.util.Uuids;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.qualityprofile.ActiveRuleKey;
import org.sonar.db.qualityprofile.QProfileDto;
import org.sonar.server.qualityprofile.RuleActivator;
import org.sonar.server.user.UserSession;
@@ -79,8 +78,7 @@ public class DeactivateRuleAction implements QProfileWsAction {
QProfileDto profile = wsSupport.getProfile(dbSession, QProfileReference.fromKey(qualityProfileKey));
wsSupport.checkPermission(dbSession, profile);
wsSupport.checkNotBuiltInt(profile);
ActiveRuleKey activeRuleKey = ActiveRuleKey.of(qualityProfileKey, ruleKey);
ruleActivator.deactivateAndUpdateIndex(dbSession, activeRuleKey);
ruleActivator.deactivateAndUpdateIndex(dbSession, profile, ruleKey);
}
response.noContent();
}

+ 1
- 1
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/DeactivateRulesAction.java View File

@@ -80,7 +80,7 @@ public class DeactivateRulesAction implements QProfileWsAction {
QProfileDto profile = wsSupport.getProfile(dbSession, QProfileReference.fromKey(qualityProfileKey));
wsSupport.checkPermission(dbSession, profile);
wsSupport.checkNotBuiltInt(profile);
result = ruleActivator.bulkDeactivate(ruleQueryFactory.createRuleQuery(dbSession, request), qualityProfileKey);
result = ruleActivator.bulkDeactivate(dbSession, ruleQueryFactory.createRuleQuery(dbSession, request), profile);
}
BulkChangeWsResponse.writeResponse(result, response);
}

+ 3
- 4
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/DeleteAction.java View File

@@ -79,14 +79,14 @@ public class DeleteAction implements QProfileWsAction {
List<QProfileDto> descendants = selectDescendants(dbSession, profile);
ensureNoneIsMarkedAsDefault(dbSession, profile, descendants);

profileFactory.deleteByKeys(dbSession, toKeys(profile, descendants));
profileFactory.delete(dbSession, merge(profile, descendants));
dbSession.commit();
}
response.noContent();
}

private List<QProfileDto> selectDescendants(DbSession dbSession, QProfileDto profile) {
return dbClient.qualityProfileDao().selectDescendants(dbSession, profile.getKee());
return dbClient.qualityProfileDao().selectDescendants(dbSession, profile);
}

private void ensureNoneIsMarkedAsDefault(DbSession dbSession, QProfileDto profile, List<QProfileDto> descendants) {
@@ -105,9 +105,8 @@ public class DeleteAction implements QProfileWsAction {
});
}

private static List<String> toKeys(QProfileDto profile, List<QProfileDto> descendants) {
private static List<QProfileDto> merge(QProfileDto profile, List<QProfileDto> descendants) {
return Stream.concat(Stream.of(profile), descendants.stream())
.map(QProfileDto::getKee)
.collect(MoreCollectors.toList(descendants.size() + 1));
}
}

+ 1
- 1
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ExportAction.java View File

@@ -126,7 +126,7 @@ public class ExportAction implements QProfileWsAction {
backuper.backup(dbSession, profile, writer);
} else {
stream.setMediaType(exporters.mimeType(exporterKey));
exporters.export(profile, exporterKey, writer);
exporters.export(dbSession, profile, exporterKey, writer);
}
}
}

+ 3
- 3
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/InheritanceAction.java View File

@@ -76,7 +76,7 @@ public class InheritanceAction implements QProfileWsAction {
OrganizationDto organization = dbClient.organizationDao().selectByUuid(dbSession, organizationUuid)
.orElseThrow(() -> new IllegalStateException(String.format("Could not find organization with uuid '%s' for quality profile '%s'", organizationUuid, profile.getKee())));
List<QProfileDto> ancestors = profileLookup.ancestors(profile, dbSession);
List<QProfileDto> children = dbClient.qualityProfileDao().selectChildren(dbSession, profile.getKee());
List<QProfileDto> children = dbClient.qualityProfileDao().selectChildren(dbSession, profile);
Statistics statistics = new Statistics(dbSession, organization);

writeProtobuf(buildResponse(profile, ancestors, children, statistics), request, response);
@@ -121,8 +121,8 @@ public class InheritanceAction implements QProfileWsAction {

private Statistics(DbSession dbSession, OrganizationDto organization) {
ActiveRuleDao dao = dbClient.activeRuleDao();
countRulesByProfileKey = dao.countActiveRulesByProfileKey(dbSession, organization);
countOverridingRulesByProfileKey = dao.countActiveRulesForInheritanceByProfileKey(dbSession, organization, ActiveRuleDto.OVERRIDES);
countRulesByProfileKey = dao.countActiveRulesByProfileUuid(dbSession, organization);
countOverridingRulesByProfileKey = dao.countActiveRulesForInheritanceByProfileUuid(dbSession, organization, ActiveRuleDto.OVERRIDES);
}
}
}

+ 2
- 2
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/SearchAction.java View File

@@ -162,8 +162,8 @@ public class SearchAction implements QProfileWsAction {
return new SearchData()
.setOrganization(organization)
.setProfiles(profiles)
.setActiveRuleCountByProfileKey(dbClient.activeRuleDao().countActiveRulesByProfileKey(dbSession, organization))
.setActiveDeprecatedRuleCountByProfileKey(dbClient.activeRuleDao().countActiveRulesForRuleStatusByProfileKey(dbSession, organization, RuleStatus.DEPRECATED))
.setActiveRuleCountByProfileKey(dbClient.activeRuleDao().countActiveRulesByProfileUuid(dbSession, organization))
.setActiveDeprecatedRuleCountByProfileKey(dbClient.activeRuleDao().countActiveRulesForRuleStatusByProfileUuid(dbSession, organization, RuleStatus.DEPRECATED))
.setProjectCountByProfileKey(dbClient.qualityProfileDao().countProjectsByProfileUuid(dbSession, organization))
.setDefaultProfileKeys(defaultProfiles);
}

+ 11
- 11
server/sonar-server/src/main/java/org/sonar/server/rule/RegisterRules.java View File

@@ -96,12 +96,12 @@ public class RegisterRules implements Startable {
@Override
public void start() {
Profiler profiler = Profiler.create(LOG).startInfo("Register rules");
try (DbSession session = dbClient.openSession(false)) {
Map<RuleKey, RuleDefinitionDto> allRules = loadRules(session);
try (DbSession dbSession = dbClient.openSession(false)) {
Map<RuleKey, RuleDefinitionDto> allRules = loadRules(dbSession);
List<RuleKey> keysToIndex = new ArrayList<>();

RulesDefinition.Context context = defLoader.load();
boolean orgsEnabled = organizationFlags.isEnabled(session);
boolean orgsEnabled = organizationFlags.isEnabled(dbSession);
for (RulesDefinition.ExtendedRepository repoDef : getRepositories(context)) {
if (languages.get(repoDef.language()) != null) {
for (RulesDefinition.Rule ruleDef : repoDef.rules()) {
@@ -116,22 +116,22 @@ public class RegisterRules implements Startable {
}
continue;
}
boolean relevantForIndex = registerRule(ruleDef, allRules, session);
boolean relevantForIndex = registerRule(ruleDef, allRules, dbSession);
if (relevantForIndex) {
keysToIndex.add(ruleKey);
}
}
session.commit();
dbSession.commit();
}
}
List<RuleDefinitionDto> removedRules = processRemainingDbRules(allRules.values(), session);
List<ActiveRuleChange> changes = removeActiveRulesOnStillExistingRepositories(session, removedRules, context);
session.commit();
List<RuleDefinitionDto> removedRules = processRemainingDbRules(allRules.values(), dbSession);
List<ActiveRuleChange> changes = removeActiveRulesOnStillExistingRepositories(dbSession, removedRules, context);
dbSession.commit();
keysToIndex.addAll(removedRules.stream().map(RuleDefinitionDto::getKey).collect(Collectors.toList()));

persistRepositories(session, context.repositories());
persistRepositories(dbSession, context.repositories());
ruleIndexer.indexRuleDefinitions(keysToIndex);
activeRuleIndexer.index(changes);
activeRuleIndexer.indexChanges(dbSession, changes);
profiler.stopDebug();

webServerRuleFinder.startCaching();
@@ -336,7 +336,7 @@ public class RegisterRules implements Startable {
RulesDefinition.Param paramDef = ruleDef.param(paramDto.getName());
if (paramDef == null) {
profiler.start();
dbClient.activeRuleDao().deleteParamsByRuleParamOfAllOrganizations(session, rule.getId(), paramDto.getName());
dbClient.activeRuleDao().deleteParamsByRuleParamOfAllOrganizations(session, paramDto);
profiler.stopDebug(format("Propagate deleted param with name %s to active rules of rule %s", paramDto.getName(), rule.getKey()));
dbClient.ruleDao().deleteRuleParam(session, paramDto.getId());
} else {

+ 7
- 6
server/sonar-server/src/main/java/org/sonar/server/rule/RuleUpdater.java View File

@@ -43,6 +43,7 @@ import org.sonar.db.DbSession;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.qualityprofile.ActiveRuleDto;
import org.sonar.db.qualityprofile.ActiveRuleParamDto;
import org.sonar.db.qualityprofile.OrgActiveRuleDto;
import org.sonar.db.rule.RuleDefinitionDto;
import org.sonar.db.rule.RuleDto;
import org.sonar.db.rule.RuleParamDto;
@@ -232,8 +233,8 @@ public class RuleUpdater {
}

private Multimap<ActiveRuleDto, ActiveRuleParamDto> getActiveRuleParamsByActiveRule(DbSession dbSession, OrganizationDto organization, RuleDto customRule) {
List<ActiveRuleDto> activeRuleDtos = dbClient.activeRuleDao().selectByRuleId(dbSession, organization, customRule.getId());
Map<Integer, ActiveRuleDto> activeRuleById = from(activeRuleDtos).uniqueIndex(ActiveRuleDto::getId);
List<OrgActiveRuleDto> activeRuleDtos = dbClient.activeRuleDao().selectByRuleId(dbSession, organization, customRule.getId());
Map<Integer, OrgActiveRuleDto> activeRuleById = from(activeRuleDtos).uniqueIndex(ActiveRuleDto::getId);
List<Integer> activeRuleIds = Lists.transform(activeRuleDtos, ActiveRuleDto::getId);
List<ActiveRuleParamDto> activeRuleParamDtos = dbClient.activeRuleDao().selectParamsByActiveRuleIds(dbSession, activeRuleIds);
return from(activeRuleParamDtos)
@@ -272,14 +273,14 @@ public class RuleUpdater {
}

private static class ActiveRuleParamToActiveRule implements Function<ActiveRuleParamDto, ActiveRuleDto> {
private final Map<Integer, ActiveRuleDto> activeRuleById;
private final Map<Integer, OrgActiveRuleDto> activeRuleById;

private ActiveRuleParamToActiveRule(Map<Integer, ActiveRuleDto> activeRuleById) {
private ActiveRuleParamToActiveRule(Map<Integer, OrgActiveRuleDto> activeRuleById) {
this.activeRuleById = activeRuleById;
}

@Override
public ActiveRuleDto apply(@Nonnull ActiveRuleParamDto input) {
public OrgActiveRuleDto apply(@Nonnull ActiveRuleParamDto input) {
return activeRuleById.get(input.getActiveRuleId());
}
}
@@ -303,7 +304,7 @@ public class RuleUpdater {
.uniqueIndex(ActiveRuleParamDto::getKey);
ActiveRuleParamDto activeRuleParamDto = activeRuleParamByKey.get(ruleParamDto.getName());
if (activeRuleParamDto != null) {
dbClient.activeRuleDao().updateParam(dbSession, activeRuleDto, activeRuleParamDto.setValue(ruleParamDto.getDefaultValue()));
dbClient.activeRuleDao().updateParam(dbSession, activeRuleParamDto.setValue(ruleParamDto.getDefaultValue()));
} else {
dbClient.activeRuleDao().insertParam(dbSession, activeRuleDto, ActiveRuleParamDto.createFor(ruleParamDto).setValue(ruleParamDto.getDefaultValue()));
}

+ 7
- 11
server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleIndex.java View File

@@ -76,8 +76,7 @@ import static org.sonar.server.es.EsUtils.SCROLL_TIME_IN_MINUTES;
import static org.sonar.server.es.EsUtils.escapeSpecialRegexChars;
import static org.sonar.server.es.EsUtils.scrollIds;
import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_RULE_INHERITANCE;
import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_RULE_ORGANIZATION_UUID;
import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_RULE_PROFILE_KEY;
import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_RULE_PROFILE_UUID;
import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_RULE_SEVERITY;
import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_RULE_CREATED_AT;
import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_RULE_EXTENSION_SCOPE;
@@ -251,11 +250,10 @@ public class RuleIndex {

if (isNotEmpty(query.getTags())) {
BoolQueryBuilder q = boolQuery();
String organizationUuid = query.getOrganizationUuid();
query.getTags().stream()
.map(tag -> boolQuery()
.filter(QueryBuilders.termQuery(FIELD_RULE_EXTENSION_TAGS, tag))
.filter(termsQuery(FIELD_RULE_EXTENSION_SCOPE, RuleExtensionScope.system().getScope(), RuleExtensionScope.organization(organizationUuid).getScope())))
.filter(termsQuery(FIELD_RULE_EXTENSION_SCOPE, RuleExtensionScope.system().getScope(), RuleExtensionScope.organization(query.getOrganization()).getScope())))
.map(childQuery -> QueryBuilders.hasChildQuery(INDEX_TYPE_RULE_EXTENSION.getType(), childQuery))
.forEach(q::filter);
filters.put(FIELD_RULE_EXTENSION_TAGS, q);
@@ -293,14 +291,13 @@ public class RuleIndex {
}

/* Implementation of activation query */
if (query.getActivation() != null) {
if (query.getActivation() != null && query.getQProfile() != null) {

// ActiveRule Filter (profile and inheritance)
BoolQueryBuilder childrenFilter = boolQuery();
addTermFilter(childrenFilter, FIELD_ACTIVE_RULE_PROFILE_KEY, query.getQProfileKey());
addTermFilter(childrenFilter, FIELD_ACTIVE_RULE_PROFILE_UUID, query.getQProfile().getRulesProfileUuid());
addTermFilter(childrenFilter, FIELD_ACTIVE_RULE_INHERITANCE, query.getInheritance());
addTermFilter(childrenFilter, FIELD_ACTIVE_RULE_SEVERITY, query.getActiveSeverities());
addTermFilter(childrenFilter, FIELD_ACTIVE_RULE_ORGANIZATION_UUID, query.getOrganizationUuid());

// ChildQuery
QueryBuilder childQuery;
@@ -370,15 +367,14 @@ public class RuleIndex {
}
if (options.getFacets().contains(FACET_TAGS) || options.getFacets().contains(FACET_OLD_DEFAULT)) {
Collection<String> tags = query.getTags();
String organizationUuid = query.getOrganizationUuid();
checkArgument(organizationUuid != null, "Cannot use tags facet, if no organization is specified.", query.getTags());
checkArgument(query.getOrganization() != null, "Cannot use tags facet, if no organization is specified.", query.getTags());

Function<TermsBuilder, AggregationBuilder<?>> childFeature = termsAggregation -> {

FilterAggregationBuilder scopeAggregation = AggregationBuilders.filter("scope_filter_for_" + FACET_TAGS).filter(
termsQuery(FIELD_RULE_EXTENSION_SCOPE,
RuleExtensionScope.system().getScope(),
RuleExtensionScope.organization(organizationUuid).getScope()))
RuleExtensionScope.organization(query.getOrganization()).getScope()))
.subAggregation(termsAggregation);

return AggregationBuilders.children("children_for_" + termsAggregation.getName())
@@ -433,7 +429,7 @@ public class RuleIndex {

// Rebuilding the active rule filter without severities
BoolQueryBuilder childrenFilter = boolQuery();
addTermFilter(childrenFilter, FIELD_ACTIVE_RULE_PROFILE_KEY, query.getQProfileKey());
addTermFilter(childrenFilter, FIELD_ACTIVE_RULE_PROFILE_UUID, query.getQProfile().getRulesProfileUuid());
RuleIndex.addTermFilter(childrenFilter, FIELD_ACTIVE_RULE_INHERITANCE, query.getInheritance());
QueryBuilder activeRuleFilter;
if (childrenFilter.hasClauses()) {

+ 20
- 12
server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleIndexDefinition.java View File

@@ -71,19 +71,30 @@ public class RuleIndexDefinition implements IndexDefinition {

// Active rule fields
public static final IndexType INDEX_TYPE_ACTIVE_RULE = new IndexType(INDEX, "activeRule");
public static final String FIELD_ACTIVE_RULE_ORGANIZATION_UUID = "organizationUuid";
public static final String FIELD_ACTIVE_RULE_KEY = "key";
public static final String FIELD_ACTIVE_RULE_REPOSITORY = "repo";
public static final String FIELD_ACTIVE_RULE_INHERITANCE = "inheritance";
public static final String FIELD_ACTIVE_RULE_PROFILE_KEY = "profile";
public static final String FIELD_ACTIVE_RULE_PROFILE_UUID = "ruleProfile";
public static final String FIELD_ACTIVE_RULE_SEVERITY = "severity";
public static final String FIELD_ACTIVE_RULE_RULE_KEY = "ruleKey";
public static final String FIELD_ACTIVE_RULE_UPDATED_AT = "updatedAt";

private final Settings settings;
private final boolean enableSource;

public RuleIndexDefinition(Settings settings) {
this(settings, false);
}

private RuleIndexDefinition(Settings settings, boolean enableSource) {
this.settings = settings;
this.enableSource = enableSource;
}

/**
* Keep the document sources in index so that indexer tests can verify content
* of indexed documents.
*/
public static RuleIndexDefinition createForTest(Settings settings) {
return new RuleIndexDefinition(settings, true);
}

@Override
@@ -95,21 +106,18 @@ public class RuleIndexDefinition implements IndexDefinition {

// Active rule type
NewIndex.NewIndexType activeRuleMapping = index.createType(INDEX_TYPE_ACTIVE_RULE.getType());
activeRuleMapping.setEnableSource(false);
activeRuleMapping.setEnableSource(enableSource);
activeRuleMapping.setAttribute("_parent", ImmutableMap.of("type", INDEX_TYPE_RULE.getType()));

activeRuleMapping.stringFieldBuilder(FIELD_ACTIVE_RULE_ORGANIZATION_UUID).disableNorms().build();
activeRuleMapping.stringFieldBuilder(FIELD_ACTIVE_RULE_KEY).addSubFields(SORTABLE_ANALYZER).build();
activeRuleMapping.stringFieldBuilder(FIELD_ACTIVE_RULE_RULE_KEY).addSubFields(SORTABLE_ANALYZER).build();
activeRuleMapping.stringFieldBuilder(FIELD_ACTIVE_RULE_REPOSITORY).build();
activeRuleMapping.stringFieldBuilder(FIELD_ACTIVE_RULE_PROFILE_KEY).disableNorms().build();
activeRuleMapping.stringFieldBuilder(FIELD_ACTIVE_RULE_PROFILE_UUID).disableNorms().build();
activeRuleMapping.stringFieldBuilder(FIELD_ACTIVE_RULE_INHERITANCE).disableNorms().build();
activeRuleMapping.stringFieldBuilder(FIELD_ACTIVE_RULE_SEVERITY).disableNorms().build();
activeRuleMapping.createLongField(FIELD_ACTIVE_RULE_UPDATED_AT);

// Rule extension type
NewIndex.NewIndexType ruleExtensionType = index.createType(INDEX_TYPE_RULE_EXTENSION.getType());
ruleExtensionType.setEnableSource(false);
ruleExtensionType.setEnableSource(enableSource);
ruleExtensionType.setAttribute("_parent", ImmutableMap.of("type", INDEX_TYPE_RULE.getType()));

ruleExtensionType.stringFieldBuilder(FIELD_RULE_EXTENSION_SCOPE).disableNorms().build();
@@ -118,7 +126,7 @@ public class RuleIndexDefinition implements IndexDefinition {

// Rule type
NewIndex.NewIndexType ruleMapping = index.createType(INDEX_TYPE_RULE.getType());
ruleMapping.setEnableSource(false);
ruleMapping.setEnableSource(enableSource);

ruleMapping.stringFieldBuilder(FIELD_RULE_KEY).addSubFields(SORTABLE_ANALYZER).build();
ruleMapping.stringFieldBuilder(FIELD_RULE_RULE_KEY).addSubFields(SORTABLE_ANALYZER).build();
@@ -137,7 +145,7 @@ public class RuleIndexDefinition implements IndexDefinition {

ruleMapping.createBooleanField(FIELD_RULE_IS_TEMPLATE);
ruleMapping.stringFieldBuilder(FIELD_RULE_TEMPLATE_KEY).disableNorms().build();
ruleMapping.stringFieldBuilder(FIELD_RULE_TYPE).disableNorms().build();

ruleMapping.createLongField(FIELD_RULE_CREATED_AT);

+ 3
- 3
server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleIteratorForSingleChunk.java View File

@@ -49,8 +49,8 @@ public class RuleIteratorForSingleChunk implements RuleIterator {

private static final String[] FIELDS = {
// column 1
"r.plugin_rule_key",
"r.plugin_name",
"r.plugin_rule_key",
"r.name",
"r.description",
"r.description_format",
@@ -159,8 +159,8 @@ public class RuleIteratorForSingleChunk implements RuleIterator {
RuleDoc doc = new RuleDoc();
RuleExtensionDoc extensionDoc = new RuleExtensionDoc().setScope(RuleExtensionScope.system());

String ruleKey = rs.getString(1);
String repositoryKey = rs.getString(2);
String repositoryKey = rs.getString(1);
String ruleKey = rs.getString(2);
RuleKey key = RuleKey.of(repositoryKey, ruleKey);
extensionDoc.setRuleKey(key);


+ 2
- 2
server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleMetadataIterator.java View File

@@ -109,8 +109,8 @@ public class RuleMetadataIterator implements Iterator<RuleExtensionDoc>, AutoClo
protected RuleExtensionDoc read(ResultSet rs) throws SQLException {
RuleExtensionDoc doc = new RuleExtensionDoc();

String ruleKey = rs.getString(1);
String repositoryKey = rs.getString(2);
String repositoryKey = rs.getString(1);
String ruleKey = rs.getString(2);
RuleKey key = RuleKey.of(repositoryKey, ruleKey);
doc.setRuleKey(key);
doc.setScope(RuleExtensionScope.organization(rs.getString(3)));

+ 0
- 0
server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleQuery.java View File


Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save