diff options
author | Julien Lancelot <julien.lancelot@sonarsource.com> | 2017-06-21 11:18:26 +0200 |
---|---|---|
committer | Julien Lancelot <julien.lancelot@sonarsource.com> | 2017-06-29 17:23:19 +0200 |
commit | a624a9cc04c37176e311c39cf250f5ff19e6cf42 (patch) | |
tree | 4c853fc820b5257f0f6069ab96c17602c6c63286 /server/sonar-server | |
parent | e5eb765a319edacb43ab7cfa5714659deb1fcad0 (diff) | |
download | sonarqube-a624a9cc04c37176e311c39cf250f5ff19e6cf42.tar.gz sonarqube-a624a9cc04c37176e311c39cf250f5ff19e6cf42.zip |
SONAR-9442 Add details of added/updated/disabled rules in notification
Diffstat (limited to 'server/sonar-server')
8 files changed, 368 insertions, 51 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotification.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotification.java index 9c2a906147c..6609ae3d829 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotification.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotification.java @@ -27,6 +27,8 @@ import java.util.stream.IntStream; import org.sonar.api.notifications.Notification; import static com.google.common.base.Preconditions.checkState; +import static java.lang.Integer.parseInt; +import static java.lang.String.format; import static java.util.Objects.requireNonNull; import static org.sonar.server.qualityprofile.BuiltInQualityProfilesNotificationSender.BUILT_IN_QUALITY_PROFILES; @@ -35,6 +37,10 @@ public class BuiltInQualityProfilesNotification { private static final String NUMBER_OF_PROFILES = "numberOfProfiles"; private static final String PROFILE_NAME = ".profileName"; private static final String LANGUAGE = ".language"; + private static final String NEW_RULES = ".newRules"; + private static final String UPDATED_RULES = ".updatedRules"; + private static final String REMOVED_RULES = ".removedRules"; + private final List<Profile> profiles = new ArrayList<>(); public BuiltInQualityProfilesNotification addProfile(Profile profile) { @@ -48,8 +54,11 @@ public class BuiltInQualityProfilesNotification { AtomicInteger count = new AtomicInteger(); profiles.forEach(profile -> { int index = count.getAndIncrement(); - notification.setFieldValue(index + ".profileName", profile.getProfileName()); - notification.setFieldValue(index + ".language", profile.getLanguage()); + notification.setFieldValue(index + PROFILE_NAME, profile.getProfileName()); + notification.setFieldValue(index + LANGUAGE, profile.getLanguage()); + notification.setFieldValue(index + NEW_RULES, String.valueOf(profile.getNewRules())); + notification.setFieldValue(index + UPDATED_RULES, String.valueOf(profile.getUpdatedRules())); + notification.setFieldValue(index + REMOVED_RULES, String.valueOf(profile.getRemovedRules())); }); return notification; } @@ -62,13 +71,22 @@ public class BuiltInQualityProfilesNotification { checkState(numberOfProfilesText != null, "Could not read the built-in quality profile notification"); Integer numberOfProfiles = Integer.valueOf(numberOfProfilesText); IntStream.rangeClosed(0, numberOfProfiles - 1) - .mapToObj(index -> new Profile( - requireNonNull(notification.getFieldValue(index + PROFILE_NAME)), - requireNonNull(notification.getFieldValue(index + LANGUAGE)))) + .mapToObj(index -> Profile.newBuilder( + getNonNullFieldValue(notification, index + PROFILE_NAME), + getNonNullFieldValue(notification, index + LANGUAGE)) + .setNewRules(parseInt(getNonNullFieldValue(notification, index + NEW_RULES))) + .setUpdatedRules(parseInt(getNonNullFieldValue(notification, index + UPDATED_RULES))) + .setRemovedRules(parseInt(getNonNullFieldValue(notification, index + REMOVED_RULES))) + .build()) .forEach(notif::addProfile); return notif; } + private static String getNonNullFieldValue(Notification notification, String key) { + String value = notification.getFieldValue(key); + return requireNonNull(value, format("Notification field '%s' is null", key)); + } + public List<Profile> getProfiles() { return profiles; } @@ -76,10 +94,16 @@ public class BuiltInQualityProfilesNotification { public static class Profile { private final String profileName; private final String language; + private final int newRules; + private final int updatedRules; + private final int removedRules; - public Profile(String profileName, String language) { - this.profileName = profileName; - this.language = language; + public Profile(Builder builder) { + this.profileName = builder.profileName; + this.language = builder.language; + this.newRules = builder.newRules; + this.updatedRules = builder.updatedRules; + this.removedRules = builder.removedRules; } public String getProfileName() { @@ -89,5 +113,56 @@ public class BuiltInQualityProfilesNotification { public String getLanguage() { return language; } + + public int getNewRules() { + return newRules; + } + + public int getUpdatedRules() { + return updatedRules; + } + + public int getRemovedRules() { + return removedRules; + } + + public static Builder newBuilder(String profileName, String language) { + return new Builder(profileName, language); + } + + public static class Builder { + private final String profileName; + private final String language; + private int newRules; + private int updatedRules; + private int removedRules; + + private Builder(String profileName, String language) { + this.profileName = requireNonNull(profileName, "profileName should not be null"); + this.language = requireNonNull(language, "language should not be null"); + } + + public Builder setNewRules(int newRules) { + checkState(newRules >= 0, "newRules should not be negative"); + this.newRules = newRules; + return this; + } + + public Builder setUpdatedRules(int updatedRules) { + checkState(updatedRules >= 0, "updatedRules should not be negative"); + this.updatedRules = updatedRules; + return this; + } + + public Builder setRemovedRules(int removedRules) { + checkState(removedRules >= 0, "removedRules should not be negative"); + this.removedRules = removedRules; + return this; + } + + public Profile build() { + return new Profile(this); + } + } } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotificationSender.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotificationSender.java index 329ad9da3cc..fee337a9832 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotificationSender.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotificationSender.java @@ -20,11 +20,16 @@ package org.sonar.server.qualityprofile; -import java.util.List; +import com.google.common.collect.Multimap; +import java.util.Collection; import org.sonar.api.resources.Languages; import org.sonar.server.notification.NotificationManager; import org.sonar.server.qualityprofile.BuiltInQualityProfilesNotification.Profile; +import static org.sonar.server.qualityprofile.ActiveRuleChange.Type.ACTIVATED; +import static org.sonar.server.qualityprofile.ActiveRuleChange.Type.DEACTIVATED; +import static org.sonar.server.qualityprofile.ActiveRuleChange.Type.UPDATED; + public class BuiltInQualityProfilesNotificationSender { static final String BUILT_IN_QUALITY_PROFILES = "built-in-quality-profiles"; @@ -37,13 +42,21 @@ public class BuiltInQualityProfilesNotificationSender { this.languages = languages; } - void send(List<QProfileName> changedProfiles) { + void send(Multimap<QProfileName, ActiveRuleChange> changedProfiles) { BuiltInQualityProfilesNotification notification = new BuiltInQualityProfilesNotification(); - changedProfiles.stream() + changedProfiles.keySet().stream() .map(changedProfile -> { String profileName = changedProfile.getName(); String languageName = languages.get(changedProfile.getLanguage()).getName(); - return new Profile(profileName, languageName); + Collection<ActiveRuleChange> activeRuleChanges = changedProfiles.get(changedProfile); + int newRules = (int) activeRuleChanges.stream().map(ActiveRuleChange::getType).filter(ACTIVATED::equals).count(); + int updatedRules = (int) activeRuleChanges.stream().map(ActiveRuleChange::getType).filter(UPDATED::equals).count(); + int removedRules = (int) activeRuleChanges.stream().map(ActiveRuleChange::getType).filter(DEACTIVATED::equals).count(); + return Profile.newBuilder(profileName, languageName) + .setNewRules(newRules) + .setUpdatedRules(updatedRules) + .setRemovedRules(removedRules) + .build(); }) .forEach(notification::addProfile); notificationManager.scheduleForSending(notification.serialize()); diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotificationTemplate.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotificationTemplate.java index 222525acfac..82db0ca0b9e 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotificationTemplate.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotificationTemplate.java @@ -40,7 +40,23 @@ public class BuiltInQualityProfilesNotificationTemplate extends EmailTemplate { StringBuilder message = new StringBuilder("Built-in quality profiles have been updated:\n"); profilesNotification.getProfiles().stream() .sorted(Comparator.comparing(Profile::getLanguage).thenComparing(Profile::getProfileName)) - .forEach(profile -> message.append("\"").append(profile.getProfileName()).append("\" - ").append(profile.getLanguage()).append("\n")); + .forEach(profile -> { + message.append("\"") + .append(profile.getProfileName()).append("\" - ") + .append(profile.getLanguage()).append("\n"); + int newRules = profile.getNewRules(); + if (newRules > 0) { + message.append(" ").append(newRules).append(" new rules\n"); + } + int updatedRules = profile.getUpdatedRules(); + if (updatedRules > 0) { + message.append(" ").append(updatedRules).append(" rules have been updated\n"); + } + int removedRules = profile.getRemovedRules(); + if (removedRules > 0) { + message.append(" ").append(removedRules).append(" rules removed\n"); + } + }); message.append( "This is a good time to review your quality profiles and update them to benefit from the latest evolutions."); 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 d343bbf526f..50490dc11b6 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 @@ -19,7 +19,8 @@ */ package org.sonar.server.qualityprofile; -import java.util.ArrayList; +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Multimap; import java.util.Collection; import java.util.List; import java.util.Map; @@ -70,16 +71,14 @@ public class RegisterQualityProfiles { Map<QProfileName, RulesProfileDto> persistedRuleProfiles = loadPersistedProfiles(dbSession); - List<QProfileName> changedProfiles = new ArrayList<>(); + Multimap<QProfileName, ActiveRuleChange> changedProfiles = ArrayListMultimap.create(); builtInQProfiles.forEach(builtIn -> { RulesProfileDto ruleProfile = persistedRuleProfiles.get(builtIn.getQProfileName()); if (ruleProfile == null) { register(dbSession, batchDbSession, builtIn); } else { List<ActiveRuleChange> changes = update(dbSession, builtIn, ruleProfile); - if (!changes.isEmpty()) { - changedProfiles.add(builtIn.getQProfileName()); - } + changedProfiles.putAll(builtIn.getQProfileName(), changes); } }); if (!changedProfiles.isEmpty()) { diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotificationSenderTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotificationSenderTest.java index 819412888d5..9bd803d14bc 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotificationSenderTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotificationSenderTest.java @@ -19,47 +19,118 @@ */ package org.sonar.server.qualityprofile; -import java.util.List; +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Multimap; +import java.util.Random; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import org.assertj.core.groups.Tuple; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.sonar.api.notifications.Notification; +import org.sonar.api.resources.Language; import org.sonar.api.resources.Languages; -import org.sonar.server.language.LanguageTesting; +import org.sonar.db.qualityprofile.ActiveRuleKey; import org.sonar.server.notification.NotificationManager; import org.sonar.server.qualityprofile.BuiltInQualityProfilesNotification.Profile; -import static java.util.Collections.singletonList; import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; import static org.assertj.core.api.Java6Assertions.assertThat; import static org.assertj.core.api.Java6Assertions.tuple; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.sonar.server.language.LanguageTesting.newLanguage; +import static org.sonar.server.qualityprofile.ActiveRuleChange.Type.ACTIVATED; +import static org.sonar.server.qualityprofile.ActiveRuleChange.Type.DEACTIVATED; +import static org.sonar.server.qualityprofile.ActiveRuleChange.Type.UPDATED; public class BuiltInQualityProfilesNotificationSenderTest { + private static final Random RANDOM = new Random(); private NotificationManager notificationManager = mock(NotificationManager.class); @Test - public void add_profile_to_notification() throws Exception { - String profileName = randomLowerCaseText(); - String languageKey = randomLowerCaseText(); - String languageName = randomLowerCaseText(); - List<QProfileName> profileNames = singletonList(new QProfileName(languageKey, profileName)); - Languages languages = new Languages(LanguageTesting.newLanguage(languageKey, languageName)); + public void add_profile_to_notification_for_added_rules() throws Exception { + Multimap<QProfileName, ActiveRuleChange> profiles = ArrayListMultimap.create(); + Languages languages = new Languages(); + Tuple expectedTuple = addProfile(profiles, languages, ACTIVATED); + + BuiltInQualityProfilesNotificationSender underTest = new BuiltInQualityProfilesNotificationSender(notificationManager, languages); + underTest.send(profiles); + + ArgumentCaptor<Notification> notificationArgumentCaptor = ArgumentCaptor.forClass(Notification.class); + verify(notificationManager).scheduleForSending(notificationArgumentCaptor.capture()); + verifyNoMoreInteractions(notificationManager); + assertThat(BuiltInQualityProfilesNotification.parse(notificationArgumentCaptor.getValue()).getProfiles()) + .extracting(Profile::getProfileName, Profile::getLanguage, Profile::getNewRules) + .containsExactlyInAnyOrder(expectedTuple); + } + + @Test + public void add_profile_to_notification_for_updated_rules() throws Exception { + Multimap<QProfileName, ActiveRuleChange> profiles = ArrayListMultimap.create(); + Languages languages = new Languages(); + Tuple expectedTuple = addProfile(profiles, languages, UPDATED); + + BuiltInQualityProfilesNotificationSender underTest = new BuiltInQualityProfilesNotificationSender(notificationManager, languages); + underTest.send(profiles); + + ArgumentCaptor<Notification> notificationArgumentCaptor = ArgumentCaptor.forClass(Notification.class); + verify(notificationManager).scheduleForSending(notificationArgumentCaptor.capture()); + verifyNoMoreInteractions(notificationManager); + assertThat(BuiltInQualityProfilesNotification.parse(notificationArgumentCaptor.getValue()).getProfiles()) + .extracting(Profile::getProfileName, Profile::getLanguage, Profile::getUpdatedRules) + .containsExactlyInAnyOrder(expectedTuple); + } + + @Test + public void add_profile_to_notification_for_removed_rules() throws Exception { + Multimap<QProfileName, ActiveRuleChange> profiles = ArrayListMultimap.create(); + Languages languages = new Languages(); + Tuple expectedTuple = addProfile(profiles, languages, DEACTIVATED); BuiltInQualityProfilesNotificationSender underTest = new BuiltInQualityProfilesNotificationSender(notificationManager, languages); - underTest.send(profileNames); + underTest.send(profiles); ArgumentCaptor<Notification> notificationArgumentCaptor = ArgumentCaptor.forClass(Notification.class); verify(notificationManager).scheduleForSending(notificationArgumentCaptor.capture()); verifyNoMoreInteractions(notificationManager); assertThat(BuiltInQualityProfilesNotification.parse(notificationArgumentCaptor.getValue()).getProfiles()) - .extracting(Profile::getProfileName, Profile::getLanguage) - .containsExactlyInAnyOrder(tuple(profileName, languageName)); + .extracting(Profile::getProfileName, Profile::getLanguage, Profile::getRemovedRules) + .containsExactlyInAnyOrder(expectedTuple); + } + + @Test + public void add_multiple_profiles_to_notification() throws Exception { + Multimap<QProfileName, ActiveRuleChange> profiles = ArrayListMultimap.create(); + Languages languages = new Languages(); + Tuple expectedTuple1 = addProfile(profiles, languages, ACTIVATED); + Tuple expectedTuple2 = addProfile(profiles, languages, ACTIVATED); + + BuiltInQualityProfilesNotificationSender underTest = new BuiltInQualityProfilesNotificationSender(notificationManager, languages); + underTest.send(profiles); + + ArgumentCaptor<Notification> notificationArgumentCaptor = ArgumentCaptor.forClass(Notification.class); + verify(notificationManager).scheduleForSending(notificationArgumentCaptor.capture()); + verifyNoMoreInteractions(notificationManager); + assertThat(BuiltInQualityProfilesNotification.parse(notificationArgumentCaptor.getValue()).getProfiles()) + .extracting(Profile::getProfileName, Profile::getLanguage, Profile::getNewRules) + .containsExactlyInAnyOrder(expectedTuple1, expectedTuple2); + } + + private Tuple addProfile(Multimap<QProfileName, ActiveRuleChange> profiles, Languages languages, ActiveRuleChange.Type type) { + String profileName = randomLowerCaseText(); + Language language = newLanguage(randomLowerCaseText(), randomLowerCaseText()); + languages.add(language); + int numberOfChanges = RANDOM.nextInt(1000); + profiles.putAll( + new QProfileName(language.getKey(), profileName), + IntStream.range(0, numberOfChanges).mapToObj(i -> new ActiveRuleChange(type, ActiveRuleKey.parse("qp:repo:rule" + i))).collect(Collectors.toSet())); + return tuple(profileName, language.getName(), numberOfChanges); } private static String randomLowerCaseText() { return randomAlphanumeric(20).toLowerCase(); } -}
\ No newline at end of file +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotificationTemplateTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotificationTemplateTest.java index 27a65edfb2b..1bd78367688 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotificationTemplateTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotificationTemplateTest.java @@ -32,16 +32,118 @@ public class BuiltInQualityProfilesNotificationTemplateTest { private BuiltInQualityProfilesNotificationTemplate underTest = new BuiltInQualityProfilesNotificationTemplate(); @Test - public void notification_contains_list_of_quality_profiles() { + public void notification_contains_list_of_new_rules() { String profileName = randomAlphanumeric(20); String language = randomAlphanumeric(20); BuiltInQualityProfilesNotification notification = new BuiltInQualityProfilesNotification() - .addProfile(new Profile(profileName, language)); + .addProfile(Profile.newBuilder(profileName, language) + .setNewRules(2) + .build()); EmailMessage emailMessage = underTest.format(notification.serialize()); assertThat(emailMessage.getMessage()).isEqualTo("Built-in quality profiles have been updated:\n" + "\"" + profileName + "\" - " + language + "\n" + + " 2 new rules\n" + "This is a good time to review your quality profiles and update them to benefit from the latest evolutions."); } + + @Test + public void notification_contains_list_of_updated_rules() { + String profileName = randomAlphanumeric(20); + String language = randomAlphanumeric(20); + BuiltInQualityProfilesNotification notification = new BuiltInQualityProfilesNotification() + .addProfile(Profile.newBuilder(profileName, language) + .setUpdatedRules(2) + .build()); + + EmailMessage emailMessage = underTest.format(notification.serialize()); + + assertThat(emailMessage.getMessage()).isEqualTo("Built-in quality profiles have been updated:\n" + + "\"" + profileName + "\" - " + language + "\n" + + " 2 rules have been updated\n" + + "This is a good time to review your quality profiles and update them to benefit from the latest evolutions."); + } + + @Test + public void notification_contains_list_of_removed_rules() { + String profileName = randomAlphanumeric(20); + String language = randomAlphanumeric(20); + BuiltInQualityProfilesNotification notification = new BuiltInQualityProfilesNotification() + .addProfile(Profile.newBuilder(profileName, language) + .setRemovedRules(2) + .build()); + + EmailMessage emailMessage = underTest.format(notification.serialize()); + + assertThat(emailMessage.getMessage()).isEqualTo("Built-in quality profiles have been updated:\n" + + "\"" + profileName + "\" - " + language + "\n" + + " 2 rules removed\n" + + "This is a good time to review your quality profiles and update them to benefit from the latest evolutions."); + } + + @Test + public void notification_contains_list_of_new_updated_and_removed_rules() { + String profileName = randomAlphanumeric(20); + String language = randomAlphanumeric(20); + BuiltInQualityProfilesNotification notification = new BuiltInQualityProfilesNotification() + .addProfile(Profile.newBuilder(profileName, language) + .setNewRules(2) + .setUpdatedRules(3) + .setRemovedRules(4) + .build()); + + EmailMessage emailMessage = underTest.format(notification.serialize()); + + assertThat(emailMessage.getMessage()).isEqualTo("Built-in quality profiles have been updated:\n" + + "\"" + profileName + "\" - " + language + "\n" + + " 2 new rules\n" + + " 3 rules have been updated\n" + + " 4 rules removed\n" + + "This is a good time to review your quality profiles and update them to benefit from the latest evolutions."); + } + + @Test + public void notification_contains_many_profiles() { + String profileName1 = "profile1_" + randomAlphanumeric(20); + String language1 = "lang1_" + randomAlphanumeric(20); + String profileName2 = "profile1_" + randomAlphanumeric(20); + String language2 = "lang2_" + randomAlphanumeric(20); + BuiltInQualityProfilesNotification notification = new BuiltInQualityProfilesNotification() + .addProfile(Profile.newBuilder(profileName1, language1) + .setNewRules(2) + .build()) + .addProfile(Profile.newBuilder(profileName2, language2) + .setNewRules(13) + .build()); + + EmailMessage emailMessage = underTest.format(notification.serialize()); + + assertThat(emailMessage.getMessage()).isEqualTo("Built-in quality profiles have been updated:\n" + + "\"" + profileName1 + "\" - " + language1 + "\n" + + " 2 new rules\n" + + "\"" + profileName2 + "\" - " + language2 + "\n" + + " 13 new rules\n" + + "This is a good time to review your quality profiles and update them to benefit from the latest evolutions."); + } + + @Test + public void notification_contains_profiles_sorted_by_language_then_by_profile_name() { + String language1 = "lang1_" + randomAlphanumeric(20); + String language2 = "lang2_" + randomAlphanumeric(20); + String profileName1 = "profile1_" + randomAlphanumeric(20); + String profileName2 = "profile2_" + randomAlphanumeric(20); + String profileName3 = "profile3_" + randomAlphanumeric(20); + BuiltInQualityProfilesNotification notification = new BuiltInQualityProfilesNotification() + .addProfile(Profile.newBuilder(profileName3, language2).build()) + .addProfile(Profile.newBuilder(profileName2, language1).build()) + .addProfile(Profile.newBuilder(profileName1, language2).build()); + + EmailMessage emailMessage = underTest.format(notification.serialize()); + + assertThat(emailMessage.getMessage()).containsSequence( + "\"" + profileName2 + "\" - " + language1, + "\"" + profileName1 + "\" - " + language2, + "\"" + profileName3 + "\" - " + language2); + } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotificationTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotificationTest.java index 7ea0b93b029..9180e904311 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotificationTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotificationTest.java @@ -50,11 +50,17 @@ public class BuiltInQualityProfilesNotificationTest { String profileName = randomAlphanumeric(20); String language = randomAlphanumeric(20); - Notification notification = new BuiltInQualityProfilesNotification().addProfile(new Profile(profileName, language)).serialize(); + Notification notification = new BuiltInQualityProfilesNotification() + .addProfile(Profile.newBuilder(profileName, language) + .setNewRules(3) + .setUpdatedRules(5) + .setRemovedRules(7) + .build()) + .serialize(); BuiltInQualityProfilesNotification result = BuiltInQualityProfilesNotification.parse(notification); - assertThat(result.getProfiles()).extracting(Profile::getProfileName, Profile::getLanguage) - .containsExactlyInAnyOrder(tuple(profileName, language)); + assertThat(result.getProfiles()).extracting(Profile::getProfileName, Profile::getLanguage, Profile::getNewRules, Profile::getUpdatedRules, Profile::getRemovedRules) + .containsExactlyInAnyOrder(tuple(profileName, language, 3, 5, 7)); } @Test @@ -65,8 +71,8 @@ public class BuiltInQualityProfilesNotificationTest { String language2 = randomAlphanumeric(20); Notification notification = new BuiltInQualityProfilesNotification() - .addProfile(new Profile(profileName1, language1)) - .addProfile(new Profile(profileName2, language2)) + .addProfile(Profile.newBuilder(profileName1, language1).build()) + .addProfile(Profile.newBuilder(profileName2, language2).build()) .serialize(); BuiltInQualityProfilesNotification result = BuiltInQualityProfilesNotification.parse(notification); 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 index 362486e0fec..e11f76806f9 100644 --- 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 @@ -19,8 +19,8 @@ */ package org.sonar.server.qualityprofile; +import com.google.common.collect.Multimap; import java.util.Arrays; -import java.util.List; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -53,6 +53,8 @@ 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; +import static org.sonar.server.qualityprofile.ActiveRuleChange.Type.ACTIVATED; +import static org.sonar.server.qualityprofile.ActiveRuleChange.Type.DEACTIVATED; public class RegisterQualityProfilesNotificationTest { @@ -116,40 +118,73 @@ public class RegisterQualityProfilesNotificationTest { underTest.start(); - ArgumentCaptor<List> captor = ArgumentCaptor.forClass(List.class); + ArgumentCaptor<Multimap> captor = ArgumentCaptor.forClass(Multimap.class); verify(builtInQualityProfilesNotification).send(captor.capture()); - List<QProfileName> updatedProfiles = captor.<List<QProfileName>>getValue(); - assertThat(updatedProfiles) + Multimap<QProfileName, ActiveRuleChange> updatedProfiles = captor.<Multimap<QProfileName, ActiveRuleChange>>getValue(); + assertThat(updatedProfiles.keySet()) .extracting(QProfileName::getName, QProfileName::getLanguage) .containsExactlyInAnyOrder(tuple(dbProfile.getName(), dbProfile.getLanguage())); + assertThat(updatedProfiles.values()) + .extracting(value -> value.getActiveRule().getRuleId(), ActiveRuleChange::getType) + .containsExactlyInAnyOrder(tuple(newRule.getId(), ACTIVATED)); } @Test - public void only_send_one_notification_when_several_built_in_profiles_contain_new_rules() { + public void send_notification_when_built_in_profile_contains_deactivated_rule() { String language = newLanguageKey(); RuleDefinitionDto existingRule = db.rules().insert(r -> r.setLanguage(language)); - RuleDefinitionDto newRule = db.rules().insert(r -> r.setLanguage(language)); + RulesProfileDto dbProfile = insertBuiltInProfile(language); + activateRuleInDb(dbProfile, existingRule, MAJOR); + addPluginProfile(dbProfile); + builtInQProfileRepositoryRule.initialize(); + + underTest.start(); + + ArgumentCaptor<Multimap> captor = ArgumentCaptor.forClass(Multimap.class); + verify(builtInQualityProfilesNotification).send(captor.capture()); + Multimap<QProfileName, ActiveRuleChange> updatedProfiles = captor.<Multimap<QProfileName, ActiveRuleChange>>getValue(); + assertThat(updatedProfiles.keySet()) + .extracting(QProfileName::getName, QProfileName::getLanguage) + .containsExactlyInAnyOrder(tuple(dbProfile.getName(), dbProfile.getLanguage())); + assertThat(updatedProfiles.values()) + .extracting(value -> value.getActiveRule().getRuleId(), ActiveRuleChange::getType) + .containsExactlyInAnyOrder(tuple(existingRule.getId(), DEACTIVATED)); + } + @Test + public void only_send_one_notification_when_several_built_in_profiles_contain_new_rules() { + String language = newLanguageKey(); + + RuleDefinitionDto existingRule1 = db.rules().insert(r -> r.setLanguage(language)); + RuleDefinitionDto newRule1 = db.rules().insert(r -> r.setLanguage(language)); RulesProfileDto dbProfile1 = insertBuiltInProfile(language); - activateRuleInDb(dbProfile1, existingRule, MAJOR); - addPluginProfile(dbProfile1, existingRule, newRule); + activateRuleInDb(dbProfile1, existingRule1, MAJOR); + addPluginProfile(dbProfile1, existingRule1, newRule1); + RuleDefinitionDto existingRule2 = db.rules().insert(r -> r.setLanguage(language)); + RuleDefinitionDto newRule2 = db.rules().insert(r -> r.setLanguage(language)); RulesProfileDto dbProfile2 = insertBuiltInProfile(language); - activateRuleInDb(dbProfile2, existingRule, MAJOR); - addPluginProfile(dbProfile2, existingRule, newRule); + activateRuleInDb(dbProfile2, existingRule2, MAJOR); + addPluginProfile(dbProfile2, existingRule2, newRule2); builtInQProfileRepositoryRule.initialize(); underTest.start(); - ArgumentCaptor<List> captor = ArgumentCaptor.forClass(List.class); + ArgumentCaptor<Multimap> captor = ArgumentCaptor.forClass(Multimap.class); verify(builtInQualityProfilesNotification).send(captor.capture()); - List<QProfileName> updatedProfiles = captor.<List<QProfileName>>getValue(); - assertThat(updatedProfiles) + Multimap<QProfileName, ActiveRuleChange> updatedProfiles = captor.<Multimap<QProfileName, ActiveRuleChange>>getValue(); + assertThat(updatedProfiles.keySet()) .extracting(QProfileName::getName, QProfileName::getLanguage) .containsExactlyInAnyOrder( tuple(dbProfile1.getName(), dbProfile1.getLanguage()), tuple(dbProfile2.getName(), dbProfile2.getLanguage()) ); + assertThat(updatedProfiles.values()) + .extracting(value -> value.getActiveRule().getRuleId(), ActiveRuleChange::getType) + .containsExactlyInAnyOrder( + tuple(newRule1.getId(), ACTIVATED), + tuple(newRule2.getId(), ACTIVATED) + ); } private void addPluginProfile(RulesProfileDto dbProfile, RuleDefinitionDto... dbRules) { |