From 774b6ef0058220e4e17c250257f3e75cb8914f09 Mon Sep 17 00:00:00 2001 From: Daniel Schwarz Date: Tue, 20 Jun 2017 12:17:17 +0200 Subject: [PATCH] SONAR-9442 Send email to profile admin on each real qprofile update --- .../qualityprofile/BuiltInQProfileUpdate.java | 3 +- .../BuiltInQProfileUpdateImpl.java | 3 +- .../RegisterQualityProfiles.java | 6 +- .../BuiltInQProfileRepositoryRule.java | 4 +- ...gisterQualityProfilesNotificationTest.java | 145 ++++++++++++++++++ .../RegisterQualityProfilesTest.java | 35 +---- 6 files changed, 159 insertions(+), 37 deletions(-) create mode 100644 server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RegisterQualityProfilesNotificationTest.java diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileUpdate.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileUpdate.java index 885833d9d37..507125d1a7c 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileUpdate.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileUpdate.java @@ -19,6 +19,7 @@ */ package org.sonar.server.qualityprofile; +import java.util.List; import org.sonar.db.DbSession; import org.sonar.db.qualityprofile.RulesProfileDto; @@ -27,5 +28,5 @@ public interface BuiltInQProfileUpdate { * Persist a built-in profile and associate it to all existing organizations. * Db sessions are committed. */ - void update(DbSession dbSession, BuiltInQProfile builtInQProfile, RulesProfileDto ruleProfile); + List update(DbSession dbSession, BuiltInQProfile builtInQProfile, RulesProfileDto ruleProfile); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileUpdateImpl.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileUpdateImpl.java index de3c45dd3bc..3338faacb33 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileUpdateImpl.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileUpdateImpl.java @@ -44,7 +44,7 @@ public class BuiltInQProfileUpdateImpl implements BuiltInQProfileUpdate { this.activeRuleIndexer = activeRuleIndexer; } - public void update(DbSession dbSession, BuiltInQProfile builtIn, RulesProfileDto ruleProfile) { + public List update(DbSession dbSession, BuiltInQProfile builtIn, RulesProfileDto ruleProfile) { // Keep reference to all the activated rules before update Set toBeDeactivated = dbClient.activeRuleDao().selectByRuleProfile(dbSession, ruleProfile) .stream() @@ -64,6 +64,7 @@ public class BuiltInQProfileUpdateImpl implements BuiltInQProfileUpdate { dbSession.commit(); activeRuleIndexer.indexChanges(dbSession, changes); + return changes; } private static RuleActivation convert(org.sonar.api.rules.ActiveRule ar) { diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RegisterQualityProfiles.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RegisterQualityProfiles.java index 89c900f9a10..f13a0e6efbe 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RegisterQualityProfiles.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RegisterQualityProfiles.java @@ -97,9 +97,11 @@ public class RegisterQualityProfiles { private void update(DbSession dbSession, BuiltInQProfile builtIn, RulesProfileDto ruleProfile) { LOGGER.info("Update profile {}", builtIn.getQProfileName()); - builtInQProfileUpdate.update(dbSession, builtIn, ruleProfile); + List activeRuleChanges = builtInQProfileUpdate.update(dbSession, builtIn, ruleProfile); - builtInQualityProfilesNotification.send(); + if (!activeRuleChanges.isEmpty()) { + builtInQualityProfilesNotification.send(); + } } /** diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/BuiltInQProfileRepositoryRule.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/BuiltInQProfileRepositoryRule.java index 4320a94ca4f..8c93d260da9 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/BuiltInQProfileRepositoryRule.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/BuiltInQProfileRepositoryRule.java @@ -60,8 +60,8 @@ public class BuiltInQProfileRepositoryRule extends ExternalResource implements B return add(language, profileName, false); } - public BuiltInQProfile add(Language language, String profileName, boolean isDefault) { - BuiltInQProfile builtIn = create(language, profileName, isDefault); + public BuiltInQProfile add(Language language, String profileName, boolean isDefault, org.sonar.api.rules.ActiveRule... rules) { + BuiltInQProfile builtIn = create(language, profileName, isDefault, rules); profiles.add(builtIn); return builtIn; } diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RegisterQualityProfilesNotificationTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RegisterQualityProfilesNotificationTest.java new file mode 100644 index 00000000000..c9fc944106b --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RegisterQualityProfilesNotificationTest.java @@ -0,0 +1,145 @@ +/* + * 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; + +import java.util.Arrays; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.sonar.api.profiles.RulesProfile; +import org.sonar.api.rules.ActiveRule; +import org.sonar.api.rules.RulePriority; +import org.sonar.api.utils.System2; +import org.sonar.api.utils.internal.AlwaysIncreasingSystem2; +import org.sonar.api.utils.log.LogTester; +import org.sonar.core.util.UuidFactoryFast; +import org.sonar.db.DbClient; +import org.sonar.db.DbTester; +import org.sonar.db.qualityprofile.ActiveRuleDto; +import org.sonar.db.qualityprofile.RulesProfileDto; +import org.sonar.db.rule.RuleDefinitionDto; +import org.sonar.server.qualityprofile.index.ActiveRuleIndexer; +import org.sonar.server.rule.index.RuleIndex; +import org.sonar.server.tester.UserSessionRule; +import org.sonar.server.util.TypeValidations; + +import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; +import static org.apache.commons.lang.math.RandomUtils.nextLong; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; +import static org.sonar.api.rules.Rule.create; +import static org.sonar.api.rules.RulePriority.MAJOR; +import static org.sonar.db.qualityprofile.QualityProfileTesting.newRuleProfileDto; +import static org.sonar.server.language.LanguageTesting.newLanguage; + +public class RegisterQualityProfilesNotificationTest { + + private System2 system2 = new AlwaysIncreasingSystem2(); + @Rule + public DbTester db = DbTester.create(system2); + @Rule + public UserSessionRule userSessionRule = UserSessionRule.standalone(); + @Rule + public ExpectedException expectedException = ExpectedException.none(); + @Rule + public BuiltInQProfileRepositoryRule builtInQProfileRepositoryRule = new BuiltInQProfileRepositoryRule(); + @Rule + public LogTester logTester = new LogTester(); + + private DbClient dbClient = db.getDbClient(); + private TypeValidations typeValidations = mock(TypeValidations.class); + private ActiveRuleIndexer activeRuleIndexer = mock(ActiveRuleIndexer.class); + private BuiltInQProfileInsert builtInQProfileInsert = new BuiltInQProfileInsertImpl(dbClient, system2, UuidFactoryFast.getInstance(), typeValidations, activeRuleIndexer); + private RuleActivator ruleActivator = new RuleActivator(system2, dbClient, mock(RuleIndex.class), new RuleActivatorContextFactory(dbClient), typeValidations, activeRuleIndexer, + userSessionRule); + private BuiltInQProfileUpdate builtInQProfileUpdate = new BuiltInQProfileUpdateImpl(dbClient, ruleActivator, activeRuleIndexer); + private BuiltInQualityProfilesNotification builtInQualityProfilesNotification = mock(BuiltInQualityProfilesNotification.class); + private RegisterQualityProfiles underTest = new RegisterQualityProfiles(builtInQProfileRepositoryRule, dbClient, + builtInQProfileInsert, builtInQProfileUpdate, builtInQualityProfilesNotification); + + @Test + public void does_not_send_notification_on_new_profile() { + String language = newLanguageKey(); + builtInQProfileRepositoryRule.add(newLanguage(language), "Sonar way"); + builtInQProfileRepositoryRule.initialize(); + + underTest.start(); + + verifyZeroInteractions(builtInQualityProfilesNotification); + } + + @Test + public void does_not_send_notification_when_built_in_profile_is_not_updated() { + String language = newLanguageKey(); + RuleDefinitionDto dbRule = db.rules().insert(r -> r.setLanguage(language)); + RulesProfileDto dbProfile = insertBuiltInProfile(language); + activateRuleInDb(dbProfile, dbRule, MAJOR); + addPluginProfile(dbProfile, dbRule); + builtInQProfileRepositoryRule.initialize(); + + underTest.start(); + + verifyZeroInteractions(builtInQualityProfilesNotification); + } + + @Test + public void send_notification_when_built_in_profile_contains_new_rule() { + String language = newLanguageKey(); + RuleDefinitionDto existingRule = db.rules().insert(r -> r.setLanguage(language)); + RulesProfileDto dbProfile = insertBuiltInProfile(language); + activateRuleInDb(dbProfile, existingRule, MAJOR); + RuleDefinitionDto newRule = db.rules().insert(r -> r.setLanguage(language)); + addPluginProfile(dbProfile, existingRule, newRule); + builtInQProfileRepositoryRule.initialize(); + + underTest.start(); + + verify(builtInQualityProfilesNotification).send(); + } + + private void addPluginProfile(RulesProfileDto dbProfile, RuleDefinitionDto... dbRules) { + RulesProfile pluginProfile = RulesProfile.create(dbProfile.getName(), dbProfile.getLanguage()); + Arrays.stream(dbRules).forEach(dbRule -> pluginProfile.activateRule(create(dbRule.getRepositoryKey(), dbRule.getRuleKey()), MAJOR)); + builtInQProfileRepositoryRule.add(newLanguage(dbProfile.getLanguage()), dbProfile.getName(), false, pluginProfile.getActiveRules().toArray(new ActiveRule[0])); + } + + private RulesProfileDto insertBuiltInProfile(String language) { + RulesProfileDto ruleProfileDto = newRuleProfileDto(rp -> rp.setIsBuiltIn(true).setLanguage(language)); + db.getDbClient().qualityProfileDao().insert(db.getSession(), ruleProfileDto); + db.commit(); + return ruleProfileDto; + } + + private void activateRuleInDb(RulesProfileDto profile, RuleDefinitionDto rule, RulePriority severity) { + ActiveRuleDto dto = new ActiveRuleDto() + .setProfileId(profile.getId()) + .setSeverity(severity.name()) + .setRuleId(rule.getId()) + .setCreatedAt(nextLong()) + .setUpdatedAt(nextLong()); + db.getDbClient().activeRuleDao().insert(db.getSession(), dto); + db.commit(); + } + + private static String newLanguageKey() { + return randomAlphanumeric(20).toLowerCase(); + } +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RegisterQualityProfilesTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RegisterQualityProfilesTest.java index 205b2939863..3600b290b6a 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RegisterQualityProfilesTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RegisterQualityProfilesTest.java @@ -20,6 +20,7 @@ package org.sonar.server.qualityprofile; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import org.junit.Rule; import org.junit.Test; @@ -39,8 +40,6 @@ import org.sonar.server.tester.UserSessionRule; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; import static org.sonar.db.qualityprofile.QualityProfileTesting.newRuleProfileDto; public class RegisterQualityProfilesTest { @@ -61,11 +60,7 @@ public class RegisterQualityProfilesTest { private DbClient dbClient = db.getDbClient(); private DummyBuiltInQProfileInsert insert = new DummyBuiltInQProfileInsert(); private DummyBuiltInQProfileUpdate update = new DummyBuiltInQProfileUpdate(); - private BuiltInQualityProfilesNotification builtInQualityProfilesNotification = mock(BuiltInQualityProfilesNotification.class); - private RegisterQualityProfiles underTest = new RegisterQualityProfiles( - builtInQProfileRepositoryRule, - dbClient, - insert, update, builtInQualityProfilesNotification); + private RegisterQualityProfiles underTest = new RegisterQualityProfiles(builtInQProfileRepositoryRule, dbClient, insert, update, mock(BuiltInQualityProfilesNotification.class)); @Test public void start_fails_if_BuiltInQProfileRepository_has_not_been_initialized() { @@ -137,29 +132,6 @@ public class RegisterQualityProfilesTest { assertThat(logTester.logs(LoggerLevel.INFO)).contains("Update profile foo/Sonar way"); } - @Test - public void does_not_send_notification_on_new_profile() { - builtInQProfileRepositoryRule.add(FOO_LANGUAGE, "Sonar way"); - builtInQProfileRepositoryRule.initialize(); - - underTest.start(); - - verifyZeroInteractions(builtInQualityProfilesNotification); - } - - @Test - public void send_notification_when_built_in_profile_is_updated() { - RulesProfileDto ruleProfile = newRuleProfileDto(rp -> rp.setIsBuiltIn(true).setName("Sonar way").setLanguage(FOO_LANGUAGE.getKey())); - db.getDbClient().qualityProfileDao().insert(db.getSession(), ruleProfile); - db.commit(); - builtInQProfileRepositoryRule.add(FOO_LANGUAGE, ruleProfile.getName(), false); - builtInQProfileRepositoryRule.initialize(); - - underTest.start(); - - verify(builtInQualityProfilesNotification).send(); - } - private String selectPersistedName(QProfileDto profile) { return db.qualityProfiles().selectByUuid(profile.getKee()).get().getName(); } @@ -186,8 +158,9 @@ public class RegisterQualityProfilesTest { private final List callLogs = new ArrayList<>(); @Override - public void update(DbSession dbSession, BuiltInQProfile builtIn, RulesProfileDto ruleProfile) { + public List update(DbSession dbSession, BuiltInQProfile builtIn, RulesProfileDto ruleProfile) { callLogs.add(builtIn); + return Collections.emptyList(); } } } -- 2.39.5