diff options
author | Léo Geoffroy <leo.geoffroy@sonarsource.com> | 2024-11-20 17:09:49 +0100 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2024-11-26 20:02:49 +0000 |
commit | 8d96098e30837f5fb8ee7b614dfe39b9486bef26 (patch) | |
tree | 2b306e1752babe076362fda8c3b98857259b5779 | |
parent | d8d9dcff6d1f21b36758a5d543c1f44b7d6e9d42 (diff) | |
download | sonarqube-8d96098e30837f5fb8ee7b614dfe39b9486bef26.tar.gz sonarqube-8d96098e30837f5fb8ee7b614dfe39b9486bef26.zip |
SONAR-23367 Send notification to instance admins about the existence of two modes.
19 files changed, 1040 insertions, 3 deletions
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/permission/AuthorizationDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/permission/AuthorizationDao.java index cc7802e943a..613d3585503 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/permission/AuthorizationDao.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/permission/AuthorizationDao.java @@ -30,6 +30,7 @@ import org.sonar.db.EmailSubscriberDto; import static org.sonar.db.DatabaseUtils.executeLargeInputs; import static org.sonar.db.DatabaseUtils.executeLargeInputsIntoSet; import static org.sonar.db.permission.GlobalPermission.ADMINISTER; +import static org.sonar.db.permission.GlobalPermission.ADMINISTER_QUALITY_GATES; import static org.sonar.db.permission.GlobalPermission.ADMINISTER_QUALITY_PROFILES; /** @@ -152,6 +153,10 @@ public class AuthorizationDao implements Dao { return mapper(dbSession).selectEmailSubscribersWithGlobalPermission(ADMINISTER_QUALITY_PROFILES.getKey()); } + public Set<EmailSubscriberDto> selectQualityGateAdministratorLogins(DbSession dbSession) { + return mapper(dbSession).selectEmailSubscribersWithGlobalPermission(ADMINISTER_QUALITY_GATES.getKey()); + } + public Set<EmailSubscriberDto> selectGlobalAdministerEmailSubscribers(DbSession dbSession) { return mapper(dbSession).selectEmailSubscribersWithGlobalPermission(ADMINISTER.getKey()); } diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/issue/notification/AbstractModeNotification.java b/server/sonar-server-common/src/main/java/org/sonar/server/issue/notification/AbstractModeNotification.java new file mode 100644 index 00000000000..a351049bae1 --- /dev/null +++ b/server/sonar-server-common/src/main/java/org/sonar/server/issue/notification/AbstractModeNotification.java @@ -0,0 +1,59 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 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.issue.notification; + +import org.sonar.api.notifications.Notification; + +public abstract class AbstractModeNotification extends Notification { + private final boolean isMQRModeEnabled; + + protected AbstractModeNotification(String type, boolean isMQRModeEnabled) { + super(type); + this.isMQRModeEnabled = isMQRModeEnabled; + } + + public boolean isMQRModeEnabled() { + return isMQRModeEnabled; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + if (!super.equals(o)) { + return false; + } + + AbstractModeNotification that = (AbstractModeNotification) o; + return isMQRModeEnabled == that.isMQRModeEnabled; + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + Boolean.hashCode(isMQRModeEnabled); + return result; + } +} diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/issue/notification/MQRAndStandardModesExistNotification.java b/server/sonar-server-common/src/main/java/org/sonar/server/issue/notification/MQRAndStandardModesExistNotification.java new file mode 100644 index 00000000000..696b7f9d750 --- /dev/null +++ b/server/sonar-server-common/src/main/java/org/sonar/server/issue/notification/MQRAndStandardModesExistNotification.java @@ -0,0 +1,30 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 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.issue.notification; + +public class MQRAndStandardModesExistNotification extends AbstractModeNotification { + + public static final String TYPE = "modes-exist"; + + public MQRAndStandardModesExistNotification(boolean isMQRModeEnabled) { + super(TYPE, isMQRModeEnabled); + } + +} diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/issue/notification/MQRAndStandardModesExistNotificationHandler.java b/server/sonar-server-common/src/main/java/org/sonar/server/issue/notification/MQRAndStandardModesExistNotificationHandler.java new file mode 100644 index 00000000000..404a8f96480 --- /dev/null +++ b/server/sonar-server-common/src/main/java/org/sonar/server/issue/notification/MQRAndStandardModesExistNotificationHandler.java @@ -0,0 +1,61 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 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.issue.notification; + +import java.util.Collection; +import java.util.Optional; +import java.util.Set; +import org.sonar.db.DbClient; +import org.sonar.db.DbSession; +import org.sonar.server.notification.EmailNotificationHandler; +import org.sonar.server.notification.NotificationDispatcherMetadata; +import org.sonar.server.notification.email.EmailNotificationChannel; + +import static java.util.stream.Collectors.toSet; + +public class MQRAndStandardModesExistNotificationHandler extends EmailNotificationHandler<MQRAndStandardModesExistNotification> { + + private final DbClient dbClient; + + protected MQRAndStandardModesExistNotificationHandler(DbClient dbClient, EmailNotificationChannel emailChannel) { + super(emailChannel); + this.dbClient = dbClient; + } + + @Override + protected Set<EmailNotificationChannel.EmailDeliveryRequest> toEmailDeliveryRequests(Collection<MQRAndStandardModesExistNotification> notifications) { + try (DbSession session = dbClient.openSession(false)) { + return dbClient.authorizationDao().selectGlobalAdministerEmailSubscribers(session) + .stream() + .flatMap(t -> notifications.stream().map(notification -> new EmailNotificationChannel.EmailDeliveryRequest(t.getEmail(), notification))) + .collect(toSet()); + } + } + + @Override + public Optional<NotificationDispatcherMetadata> getMetadata() { + return Optional.empty(); + } + + @Override + public Class<MQRAndStandardModesExistNotification> getNotificationClass() { + return MQRAndStandardModesExistNotification.class; + } +} diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/issue/notification/MQRAndStandardModesExistTemplate.java b/server/sonar-server-common/src/main/java/org/sonar/server/issue/notification/MQRAndStandardModesExistTemplate.java new file mode 100644 index 00000000000..c4b08c8b9d6 --- /dev/null +++ b/server/sonar-server-common/src/main/java/org/sonar/server/issue/notification/MQRAndStandardModesExistTemplate.java @@ -0,0 +1,51 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 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.issue.notification; + +import org.jetbrains.annotations.Nullable; +import org.sonar.api.notifications.Notification; + +public class MQRAndStandardModesExistTemplate implements EmailTemplate { + @Nullable + @Override + public EmailMessage format(Notification notification) { + if (!MQRAndStandardModesExistNotification.TYPE.equals(notification.getType())) { + return null; + } + + boolean isMQREnabled = ((MQRAndStandardModesExistNotification) notification).isMQRModeEnabled(); + String message = """ + In this version of SonarQube Server, there are two options to reflect the health of all the projects: Multi-Quality Rule (MQR) Mode and Standard Experience. + The SonarQube Server documentation explains more. + + Your instance is currently using the %s. + + To change it, go to Administration > Configuration > General Settings > Mode. + """ + .formatted(isMQREnabled ? "Multi-Quality Rule (MQR) Mode" : "Standard Experience"); + + // And finally return the email that will be sent + return new EmailMessage() + .setMessageId(MQRAndStandardModesExistNotification.TYPE) + .setSubject("Your SonarQube Server instance is in %s" + .formatted(isMQREnabled ? "Multi-Quality Rule (MQR) Mode" : "Standard Experience")) + .setPlainTextMessage(message); + } +} diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/issue/notification/NewModesNotificationsModule.java b/server/sonar-server-common/src/main/java/org/sonar/server/issue/notification/NewModesNotificationsModule.java new file mode 100644 index 00000000000..9c830e03af0 --- /dev/null +++ b/server/sonar-server-common/src/main/java/org/sonar/server/issue/notification/NewModesNotificationsModule.java @@ -0,0 +1,39 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 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.issue.notification; + +import org.sonar.core.platform.Module; + +public class NewModesNotificationsModule extends Module { + @Override + protected void configureModule() { + add( + NewModesNotificationsSender.class, + + MQRAndStandardModesExistNotification.class, + MQRAndStandardModesExistNotificationHandler.class, + MQRAndStandardModesExistTemplate.class, + + QualityGateMetricsUpdateNotification.class, + QualityGateMetricsUpdateNotificationHandler.class, + QualityGateMetricsUpdateTemplate.class); + } + +} diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/issue/notification/NewModesNotificationsSender.java b/server/sonar-server-common/src/main/java/org/sonar/server/issue/notification/NewModesNotificationsSender.java new file mode 100644 index 00000000000..6fc280561ed --- /dev/null +++ b/server/sonar-server-common/src/main/java/org/sonar/server/issue/notification/NewModesNotificationsSender.java @@ -0,0 +1,84 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 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.issue.notification; + +import java.util.Map; +import java.util.stream.Collectors; +import org.sonar.api.Startable; +import org.sonar.api.config.Configuration; +import org.sonar.db.DbClient; +import org.sonar.db.DbSession; +import org.sonar.db.metric.MetricDto; +import org.sonar.server.metric.StandardToMQRMetrics; +import org.sonar.server.notification.NotificationManager; +import org.sonar.server.platform.db.migration.history.MigrationHistory; + +import static org.sonar.core.config.MQRModeConstants.MULTI_QUALITY_MODE_DEFAULT_VALUE; +import static org.sonar.core.config.MQRModeConstants.MULTI_QUALITY_MODE_ENABLED; + +public class NewModesNotificationsSender implements Startable { + + public static final int NEW_MODES_SQ_VERSION = 108_000; + private final NotificationManager notificationManager; + private final Configuration configuration; + private final MigrationHistory migrationHistory; + private final DbClient dbClient; + + public NewModesNotificationsSender(NotificationManager notificationManager, Configuration configuration, MigrationHistory migrationHistory, DbClient dbClient) { + this.notificationManager = notificationManager; + this.configuration = configuration; + this.migrationHistory = migrationHistory; + this.dbClient = dbClient; + } + + @Override + public void start() { + if (migrationHistory.getInitialDbVersion() != -1 && migrationHistory.getInitialDbVersion() < NEW_MODES_SQ_VERSION) { + boolean isMQRModeEnabled = configuration.getBoolean(MULTI_QUALITY_MODE_ENABLED).orElse(MULTI_QUALITY_MODE_DEFAULT_VALUE); + sendNewModesNotification(isMQRModeEnabled); + sendQualityGateMetricsUpdateNotification(isMQRModeEnabled); + } + } + + private void sendQualityGateMetricsUpdateNotification(boolean isMQRModeEnabled) { + try (DbSession dbSession = dbClient.openSession(false)) { + + Map<String, String> metricKeysByUuids = dbClient.metricDao().selectAll(dbSession).stream() + .collect(Collectors.toMap(MetricDto::getUuid, MetricDto::getKey)); + + boolean hasConditionsFromOtherMode = dbClient.gateConditionDao().selectAll(dbSession).stream() + .anyMatch(c -> isMQRModeEnabled ? StandardToMQRMetrics.isStandardMetric(metricKeysByUuids.get(c.getMetricUuid())) + : StandardToMQRMetrics.isMQRMetric(metricKeysByUuids.get(c.getMetricUuid()))); + + if (hasConditionsFromOtherMode) { + notificationManager.scheduleForSending(new QualityGateMetricsUpdateNotification(isMQRModeEnabled)); + } + } + } + + private void sendNewModesNotification(boolean isMQRModeEnabled) { + notificationManager.scheduleForSending(new MQRAndStandardModesExistNotification(isMQRModeEnabled)); + } + + @Override + public void stop() { + // Nothing to do + } +} diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/issue/notification/QualityGateMetricsUpdateNotification.java b/server/sonar-server-common/src/main/java/org/sonar/server/issue/notification/QualityGateMetricsUpdateNotification.java new file mode 100644 index 00000000000..a406d4a3eec --- /dev/null +++ b/server/sonar-server-common/src/main/java/org/sonar/server/issue/notification/QualityGateMetricsUpdateNotification.java @@ -0,0 +1,29 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 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.issue.notification; + +public class QualityGateMetricsUpdateNotification extends AbstractModeNotification { + public static final String TYPE = "update-quality-gate-metrics"; + + public QualityGateMetricsUpdateNotification(boolean isMQRModeEnabled) { + super(TYPE, isMQRModeEnabled); + + } +} diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/issue/notification/QualityGateMetricsUpdateNotificationHandler.java b/server/sonar-server-common/src/main/java/org/sonar/server/issue/notification/QualityGateMetricsUpdateNotificationHandler.java new file mode 100644 index 00000000000..81033f72762 --- /dev/null +++ b/server/sonar-server-common/src/main/java/org/sonar/server/issue/notification/QualityGateMetricsUpdateNotificationHandler.java @@ -0,0 +1,62 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 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.issue.notification; + +import java.util.Collection; +import java.util.Optional; +import java.util.Set; +import org.sonar.db.DbClient; +import org.sonar.db.DbSession; +import org.sonar.server.notification.EmailNotificationHandler; +import org.sonar.server.notification.NotificationDispatcherMetadata; +import org.sonar.server.notification.email.EmailNotificationChannel; + +import static java.util.stream.Collectors.toSet; + +public class QualityGateMetricsUpdateNotificationHandler extends EmailNotificationHandler<QualityGateMetricsUpdateNotification> { + private final DbClient dbClient; + + protected QualityGateMetricsUpdateNotificationHandler(DbClient dbClient, EmailNotificationChannel emailChannel) { + super(emailChannel); + this.dbClient = dbClient; + } + + @Override + protected Set<EmailNotificationChannel.EmailDeliveryRequest> toEmailDeliveryRequests(Collection<QualityGateMetricsUpdateNotification> notifications) { + try (DbSession session = dbClient.openSession(false)) { + return dbClient.authorizationDao() + .selectQualityGateAdministratorLogins(session) + .stream() + .flatMap(t -> notifications.stream().map(notification -> new EmailNotificationChannel.EmailDeliveryRequest(t.getEmail(), notification))) + .collect(toSet()); + } + } + + @Override + public Optional<NotificationDispatcherMetadata> getMetadata() { + return Optional.empty(); + } + + @Override + public Class<QualityGateMetricsUpdateNotification> getNotificationClass() { + return QualityGateMetricsUpdateNotification.class; + } + +} diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/issue/notification/QualityGateMetricsUpdateTemplate.java b/server/sonar-server-common/src/main/java/org/sonar/server/issue/notification/QualityGateMetricsUpdateTemplate.java new file mode 100644 index 00000000000..6a06bdd2f3b --- /dev/null +++ b/server/sonar-server-common/src/main/java/org/sonar/server/issue/notification/QualityGateMetricsUpdateTemplate.java @@ -0,0 +1,58 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 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.issue.notification; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.sonar.api.notifications.Notification; + +public class QualityGateMetricsUpdateTemplate implements EmailTemplate { + + private static final String STANDARD_EXPERIENCE = "Standard Experience"; + private static final String MQR_MODE = "Multi-Quality Rule (MQR) Mode"; + + @Nullable + @Override + public EmailMessage format(Notification notification) { + if (!QualityGateMetricsUpdateNotification.TYPE.equals(notification.getType())) { + return null; + } + + String message = retrieveMessage((QualityGateMetricsUpdateNotification) notification); + + // And finally return the email that will be sent + return new EmailMessage() + .setMessageId(MQRAndStandardModesExistNotification.TYPE) + .setSubject("Update your SonarQube Server's Quality Gate metrics") + .setPlainTextMessage(message); + } + + @NotNull + private static String retrieveMessage(QualityGateMetricsUpdateNotification notification) { + StringBuilder message = new StringBuilder(); + message.append("We are sending this message because this version of SonarQube Server is in "); + message.append(notification.isMQRModeEnabled() ? MQR_MODE : STANDARD_EXPERIENCE); + message.append(" and some of your quality gates conditions are using metrics from "); + message.append(notification.isMQRModeEnabled() ? STANDARD_EXPERIENCE : MQR_MODE); + message.append(".\n\nWe recommend you update them to ensure accurate categorization and ranking of your issues.\n\n"); + message.append("Go to the Quality Gates page, and we will guide you through the process."); + return message.toString(); + } +} diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/issue/notification/MQRAndStandardModesExistNotificationHandlerTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/issue/notification/MQRAndStandardModesExistNotificationHandlerTest.java new file mode 100644 index 00000000000..99922fc0897 --- /dev/null +++ b/server/sonar-server-common/src/test/java/org/sonar/server/issue/notification/MQRAndStandardModesExistNotificationHandlerTest.java @@ -0,0 +1,71 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 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.issue.notification; + +import java.util.List; +import java.util.Set; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.sonar.db.DbClient; +import org.sonar.db.DbSession; +import org.sonar.db.EmailSubscriberDto; +import org.sonar.db.permission.AuthorizationDao; +import org.sonar.server.notification.email.EmailNotificationChannel; + +import static org.assertj.core.groups.Tuple.tuple; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class MQRAndStandardModesExistNotificationHandlerTest { + private final DbClient dbClient = mock(DbClient.class); + private final DbSession dbSession = mock(DbSession.class); + private final AuthorizationDao authorizationDao = mock(AuthorizationDao.class); + private final EmailNotificationChannel emailNotificationChannel = mock(EmailNotificationChannel.class); + + private final MQRAndStandardModesExistNotificationHandler underTest = new MQRAndStandardModesExistNotificationHandler(dbClient, emailNotificationChannel); + + @BeforeEach + public void wire_mocks() { + when(dbClient.openSession(false)).thenReturn(dbSession); + when(dbClient.authorizationDao()).thenReturn(authorizationDao); + } + + @Test + void toEmailDeliveryRequests_whenHasAdmins_shouldSendExpectedNotification() { + when(authorizationDao.selectGlobalAdministerEmailSubscribers(dbSession)) + .thenReturn(Set.of(new EmailSubscriberDto().setEmail("email@email.com"), new EmailSubscriberDto().setEmail("email2@email.com"))); + + Assertions.assertThat(underTest.toEmailDeliveryRequests(List.of(new MQRAndStandardModesExistNotification(true)))) + .extracting(EmailNotificationChannel.EmailDeliveryRequest::recipientEmail, EmailNotificationChannel.EmailDeliveryRequest::notification) + .containsExactly(tuple("email@email.com", new MQRAndStandardModesExistNotification(true)), + tuple("email2@email.com", new MQRAndStandardModesExistNotification(true))); + } + + @Test + void toEmailDeliveryRequests_whenHasNoAdmins_shouldNotSendNotification() { + when(authorizationDao.selectGlobalAdministerEmailSubscribers(dbSession)) + .thenReturn(Set.of()); + + Assertions.assertThat(underTest.toEmailDeliveryRequests(List.of(new MQRAndStandardModesExistNotification(true)))) + .isEmpty(); + } + +} diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/issue/notification/MQRAndStandardModesExistNotificationTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/issue/notification/MQRAndStandardModesExistNotificationTest.java new file mode 100644 index 00000000000..0bf9f5928c1 --- /dev/null +++ b/server/sonar-server-common/src/test/java/org/sonar/server/issue/notification/MQRAndStandardModesExistNotificationTest.java @@ -0,0 +1,42 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 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.issue.notification; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; + +class MQRAndStandardModesExistNotificationTest { + + @Test + void isMQRModeEnabled_shouldReturnExpectedValue() { + MQRAndStandardModesExistNotification underTest = new MQRAndStandardModesExistNotification(false); + Assertions.assertThat(underTest.isMQRModeEnabled()).isFalse(); + + underTest = new MQRAndStandardModesExistNotification(true); + Assertions.assertThat(underTest.isMQRModeEnabled()).isTrue(); + } + + @Test + void equals_shouldReturnAsExpected() { + MQRAndStandardModesExistNotification underTest = new MQRAndStandardModesExistNotification(false); + Assertions.assertThat(underTest.equals(new MQRAndStandardModesExistNotification(false))).isTrue(); + Assertions.assertThat(underTest.equals(new MQRAndStandardModesExistNotification(true))).isFalse(); + } +} diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/issue/notification/MQRAndStandardModesExistTemplateTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/issue/notification/MQRAndStandardModesExistTemplateTest.java new file mode 100644 index 00000000000..722001ebbd3 --- /dev/null +++ b/server/sonar-server-common/src/test/java/org/sonar/server/issue/notification/MQRAndStandardModesExistTemplateTest.java @@ -0,0 +1,70 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 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.issue.notification; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; +import org.sonar.api.notifications.Notification; + +class MQRAndStandardModesExistTemplateTest { + + private final MQRAndStandardModesExistTemplate underTest = new MQRAndStandardModesExistTemplate(); + + @Test + void format_whenStandardExperience_shouldReturnExpectEmailMessage() { + Assertions.assertThat(underTest.format(new MQRAndStandardModesExistNotification(false))) + .extracting(EmailMessage::getSubject, EmailMessage::getMessage) + .containsExactly("Your SonarQube Server instance is in Standard Experience", + """ + In this version of SonarQube Server, there are two options to reflect the health of all the projects: Multi-Quality Rule (MQR) Mode and Standard Experience. + The SonarQube Server documentation explains more. + + Your instance is currently using the Standard Experience. + + To change it, go to Administration > Configuration > General Settings > Mode. + """); + } + + @Test + void format_whenMQRMode_shouldReturnExpectEmailMessage() { + Assertions.assertThat(underTest.format(new MQRAndStandardModesExistNotification(true))) + .extracting(EmailMessage::getSubject, EmailMessage::getMessage) + .containsExactly("Your SonarQube Server instance is in Multi-Quality Rule (MQR) Mode", + """ + In this version of SonarQube Server, there are two options to reflect the health of all the projects: Multi-Quality Rule (MQR) Mode and Standard Experience. + The SonarQube Server documentation explains more. + + Your instance is currently using the Multi-Quality Rule (MQR) Mode. + + To change it, go to Administration > Configuration > General Settings > Mode. + """); + } + + @Test + void format_whenInvalidNotification_shouldReturnNull() { + Assertions.assertThat(underTest.format(new TestNotification())).isNull(); + } + + private static class TestNotification extends Notification { + public TestNotification() { + super("test"); + } + } +} diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/issue/notification/NewModesNotificationsModuleTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/issue/notification/NewModesNotificationsModuleTest.java new file mode 100644 index 00000000000..4ac667ea5cc --- /dev/null +++ b/server/sonar-server-common/src/test/java/org/sonar/server/issue/notification/NewModesNotificationsModuleTest.java @@ -0,0 +1,35 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 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.issue.notification; + +import org.junit.jupiter.api.Test; +import org.sonar.core.platform.ListContainer; + +import static org.assertj.core.api.Assertions.assertThat; + +class NewModesNotificationsModuleTest { + + @Test + void configure_shouldReturnExpectedNumberOfComponents() { + ListContainer container = new ListContainer(); + new NewModesNotificationsModule().configure(container); + assertThat(container.getAddedObjects()).hasSize(7); + } +} diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/issue/notification/NewModesNotificationsSenderTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/issue/notification/NewModesNotificationsSenderTest.java new file mode 100644 index 00000000000..6583ff25599 --- /dev/null +++ b/server/sonar-server-common/src/test/java/org/sonar/server/issue/notification/NewModesNotificationsSenderTest.java @@ -0,0 +1,160 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 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.issue.notification; + +import java.util.List; +import java.util.Optional; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.sonar.api.config.Configuration; +import org.sonar.api.measures.CoreMetrics; +import org.sonar.api.notifications.Notification; +import org.sonar.core.metric.SoftwareQualitiesMetrics; +import org.sonar.db.DbClient; +import org.sonar.db.DbSession; +import org.sonar.db.metric.MetricDao; +import org.sonar.db.metric.MetricDto; +import org.sonar.db.qualitygate.QualityGateConditionDao; +import org.sonar.db.qualitygate.QualityGateConditionDto; +import org.sonar.server.notification.NotificationManager; +import org.sonar.server.platform.db.migration.history.MigrationHistory; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; +import static org.mockito.Mockito.when; +import static org.sonar.core.config.MQRModeConstants.MULTI_QUALITY_MODE_ENABLED; + +class NewModesNotificationsSenderTest { + private static final String METRIC_UUID = "metricUuid"; + private static final String METRIC_UUID_2 = "metricUuid2"; + private final NotificationManager notificationManager = mock(NotificationManager.class); + private final Configuration configuration = mock(Configuration.class); + private final MigrationHistory migrationHistory = mock(MigrationHistory.class); + private final DbClient dbClient = mock(DbClient.class); + private final MetricDao metricDao = mock(MetricDao.class); + private final QualityGateConditionDao qualityGateConditionDao = mock(QualityGateConditionDao.class); + private final NewModesNotificationsSender underTest = new NewModesNotificationsSender(notificationManager, configuration, migrationHistory, dbClient); + private final DbSession dbSession = mock(DbSession.class); + + @BeforeEach + void setUp() { + when(dbClient.metricDao()).thenReturn(metricDao); + when(dbClient.gateConditionDao()).thenReturn(qualityGateConditionDao); + when(dbClient.openSession(false)).thenReturn(dbSession); + } + + @Test + void start_whenOldInstanceAndStandardMode_shouldSendNewModesNotification() { + when(configuration.getBoolean(MULTI_QUALITY_MODE_ENABLED)).thenReturn(Optional.of(false)); + when(migrationHistory.getInitialDbVersion()).thenReturn(9999L); // 9.9 + underTest.start(); + + ArgumentCaptor<MQRAndStandardModesExistNotification> captor = ArgumentCaptor.forClass(MQRAndStandardModesExistNotification.class); + verify(notificationManager, times(1)).scheduleForSending(captor.capture()); + + assertThat(captor.getValue().isMQRModeEnabled()).isFalse(); + } + + @Test + void start_whenOldInstanceAndMQRMode_shouldSendNewModesNotification() { + when(configuration.getBoolean(MULTI_QUALITY_MODE_ENABLED)).thenReturn(Optional.of(true)); + when(migrationHistory.getInitialDbVersion()).thenReturn(102000L); // 10.2 + + underTest.start(); + + ArgumentCaptor<MQRAndStandardModesExistNotification> captor = ArgumentCaptor.forClass(MQRAndStandardModesExistNotification.class); + verify(notificationManager, times(1)).scheduleForSending(captor.capture()); + + assertThat(captor.getValue().isMQRModeEnabled()).isTrue(); + } + + @Test + void start_whenNewInstance_shouldNotSendNewModesNotification() { + when(configuration.getBoolean(MULTI_QUALITY_MODE_ENABLED)).thenReturn(Optional.of(true)); + when(migrationHistory.getInitialDbVersion()).thenReturn(-1L); // New instance + + underTest.start(); + verifyNoInteractions(notificationManager); + } + + @Test + void start_whenOldInstanceInStandardModeWithMQRConditions_shouldSendQualityGateUpdateNotification() { + when(configuration.getBoolean(MULTI_QUALITY_MODE_ENABLED)).thenReturn(Optional.of(false)); + when(migrationHistory.getInitialDbVersion()).thenReturn(9999L); // 9.9 + when(metricDao.selectAll(dbSession)).thenReturn(List.of(new MetricDto().setKey(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_ISSUES_KEY).setUuid(METRIC_UUID))); + when(qualityGateConditionDao.selectAll(dbSession)).thenReturn(List.of(new QualityGateConditionDto().setMetricUuid(METRIC_UUID))); + + underTest.start(); + + ArgumentCaptor<Notification> captor = ArgumentCaptor.forClass(Notification.class); + verify(notificationManager, times(2)).scheduleForSending(captor.capture()); + + assertThat(captor.getAllValues()) + .filteredOn(notification -> notification instanceof QualityGateMetricsUpdateNotification) + .map(notification -> (QualityGateMetricsUpdateNotification) notification) + .hasSize(1) + .extracting(QualityGateMetricsUpdateNotification::isMQRModeEnabled).isEqualTo(List.of(false)); + + } + + @Test + void start_whenOldInstanceInMQRModeWithStandardConditions_shouldSendQualityGateUpdateNotification() { + when(configuration.getBoolean(MULTI_QUALITY_MODE_ENABLED)).thenReturn(Optional.of(true)); + when(migrationHistory.getInitialDbVersion()).thenReturn(9999L); // 9.9 + when(metricDao.selectAll(dbSession)).thenReturn(List.of(new MetricDto().setKey(CoreMetrics.CODE_SMELLS_KEY).setUuid(METRIC_UUID))); + when(qualityGateConditionDao.selectAll(dbSession)).thenReturn(List.of(new QualityGateConditionDto().setMetricUuid(METRIC_UUID))); + + underTest.start(); + + ArgumentCaptor<Notification> captor = ArgumentCaptor.forClass(Notification.class); + verify(notificationManager, times(2)).scheduleForSending(captor.capture()); + + assertThat(captor.getAllValues()) + .filteredOn(notification -> notification instanceof QualityGateMetricsUpdateNotification) + .map(notification -> (QualityGateMetricsUpdateNotification) notification) + .hasSize(1) + .extracting(QualityGateMetricsUpdateNotification::isMQRModeEnabled).isEqualTo(List.of(true)); + } + + @Test + void start_whenOldInstanceInMQRModeWithOtherConditions_shouldNotSendNotification() { + when(configuration.getBoolean(MULTI_QUALITY_MODE_ENABLED)).thenReturn(Optional.of(true)); + when(migrationHistory.getInitialDbVersion()).thenReturn(9999L); // 9.9 + when(metricDao.selectAll(dbSession)).thenReturn(List.of( + new MetricDto().setKey(CoreMetrics.COVERAGE_KEY).setUuid(METRIC_UUID), + new MetricDto().setKey(CoreMetrics.SECURITY_HOTSPOTS_TO_REVIEW_STATUS_KEY).setUuid(METRIC_UUID_2))); + when(qualityGateConditionDao.selectAll(dbSession)).thenReturn(List.of(new QualityGateConditionDto().setMetricUuid(METRIC_UUID), + new QualityGateConditionDto().setMetricUuid(METRIC_UUID_2))); + + underTest.start(); + + ArgumentCaptor<Notification> captor = ArgumentCaptor.forClass(Notification.class); + verify(notificationManager, times(1)).scheduleForSending(captor.capture()); + + assertThat(captor.getAllValues()) + .filteredOn(notification -> notification instanceof QualityGateMetricsUpdateNotification) + .map(notification -> (QualityGateMetricsUpdateNotification) notification) + .isEmpty(); + } +} diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/issue/notification/QualityGateMetricsUpdateNotificationHandlerTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/issue/notification/QualityGateMetricsUpdateNotificationHandlerTest.java new file mode 100644 index 00000000000..6dda1019c1a --- /dev/null +++ b/server/sonar-server-common/src/test/java/org/sonar/server/issue/notification/QualityGateMetricsUpdateNotificationHandlerTest.java @@ -0,0 +1,71 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 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.issue.notification; + +import java.util.List; +import java.util.Set; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.sonar.db.DbClient; +import org.sonar.db.DbSession; +import org.sonar.db.EmailSubscriberDto; +import org.sonar.db.permission.AuthorizationDao; +import org.sonar.server.notification.email.EmailNotificationChannel; + +import static org.assertj.core.groups.Tuple.tuple; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class QualityGateMetricsUpdateNotificationHandlerTest { + private final DbClient dbClient = mock(DbClient.class); + private final DbSession dbSession = mock(DbSession.class); + private final AuthorizationDao authorizationDao = mock(AuthorizationDao.class); + private final EmailNotificationChannel emailNotificationChannel = mock(EmailNotificationChannel.class); + + private final QualityGateMetricsUpdateNotificationHandler underTest = new QualityGateMetricsUpdateNotificationHandler(dbClient, + emailNotificationChannel); + + @BeforeEach + public void wire_mocks() { + when(dbClient.openSession(false)).thenReturn(dbSession); + when(dbClient.authorizationDao()).thenReturn(authorizationDao); + } + + @Test + void toEmailDeliveryRequests_whenHasAdmins_shouldSendExpectedNotification() { + when(authorizationDao.selectQualityGateAdministratorLogins(dbSession)) + .thenReturn(Set.of(new EmailSubscriberDto().setEmail("email@email.com"), new EmailSubscriberDto().setEmail("email2@email.com"))); + + Assertions.assertThat(underTest.toEmailDeliveryRequests(List.of(new QualityGateMetricsUpdateNotification(true)))) + .extracting(EmailNotificationChannel.EmailDeliveryRequest::recipientEmail, EmailNotificationChannel.EmailDeliveryRequest::notification) + .containsExactly(tuple("email@email.com", new QualityGateMetricsUpdateNotification(true)), + tuple("email2@email.com", new QualityGateMetricsUpdateNotification(true))); + } + + @Test + void toEmailDeliveryRequests_whenHasNoAdmins_shouldNotSendNotification() { + when(authorizationDao.selectQualityGateAdministratorLogins(dbSession)) + .thenReturn(Set.of()); + + Assertions.assertThat(underTest.toEmailDeliveryRequests(List.of(new QualityGateMetricsUpdateNotification(true)))) + .isEmpty(); + } +} diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/issue/notification/QualityGateMetricsUpdateNotificationTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/issue/notification/QualityGateMetricsUpdateNotificationTest.java new file mode 100644 index 00000000000..1f9367b6677 --- /dev/null +++ b/server/sonar-server-common/src/test/java/org/sonar/server/issue/notification/QualityGateMetricsUpdateNotificationTest.java @@ -0,0 +1,42 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 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.issue.notification; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; + +class QualityGateMetricsUpdateNotificationTest { + + @Test + void isMQRModeEnabled_shouldReturnExpectedValue() { + QualityGateMetricsUpdateNotification underTest = new QualityGateMetricsUpdateNotification(false); + Assertions.assertThat(underTest.isMQRModeEnabled()).isFalse(); + + underTest = new QualityGateMetricsUpdateNotification(true); + Assertions.assertThat(underTest.isMQRModeEnabled()).isTrue(); + } + + @Test + void equals_shouldReturnAsExpected() { + QualityGateMetricsUpdateNotification underTest = new QualityGateMetricsUpdateNotification(false); + Assertions.assertThat(underTest.equals(new QualityGateMetricsUpdateNotification(false))).isTrue(); + Assertions.assertThat(underTest.equals(new QualityGateMetricsUpdateNotification(true))).isFalse(); + } +} diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/issue/notification/QualityGateMetricsUpdateTemplateTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/issue/notification/QualityGateMetricsUpdateTemplateTest.java new file mode 100644 index 00000000000..c391b19ec82 --- /dev/null +++ b/server/sonar-server-common/src/test/java/org/sonar/server/issue/notification/QualityGateMetricsUpdateTemplateTest.java @@ -0,0 +1,66 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 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.issue.notification; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; +import org.sonar.api.notifications.Notification; + +class QualityGateMetricsUpdateTemplateTest { + + QualityGateMetricsUpdateTemplate underTest = new QualityGateMetricsUpdateTemplate(); + + @Test + void format_whenStandardExperience_shouldReturnExpectEmailMessage() { + Assertions.assertThat(underTest.format(new QualityGateMetricsUpdateNotification(false))) + .extracting(EmailMessage::getSubject, EmailMessage::getMessage) + .containsExactly("Update your SonarQube Server's Quality Gate metrics", + """ + We are sending this message because this version of SonarQube Server is in Standard Experience and some of your quality gates conditions are using metrics from Multi-Quality Rule (MQR) Mode. + + We recommend you update them to ensure accurate categorization and ranking of your issues. + + Go to the Quality Gates page, and we will guide you through the process."""); + } + + @Test + void format_whenMQRMode_shouldReturnExpectEmailMessage() { + Assertions.assertThat(underTest.format(new QualityGateMetricsUpdateNotification(true))) + .extracting(EmailMessage::getSubject, EmailMessage::getMessage) + .containsExactly("Update your SonarQube Server's Quality Gate metrics", + """ + We are sending this message because this version of SonarQube Server is in Multi-Quality Rule (MQR) Mode and some of your quality gates conditions are using metrics from Standard Experience. + + We recommend you update them to ensure accurate categorization and ranking of your issues. + + Go to the Quality Gates page, and we will guide you through the process."""); + } + + @Test + void format_whenInvalidNotification_shouldReturnNull() { + Assertions.assertThat(underTest.format(new TestNotification())).isNull(); + } + + private static class TestNotification extends Notification { + public TestNotification() { + super("test"); + } + } +} diff --git a/server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java b/server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java index 9da8b6da3a4..a09c93f5d68 100644 --- a/server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java +++ b/server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java @@ -41,7 +41,6 @@ import org.sonar.alm.client.gitlab.GitlabApplicationHttpClient; import org.sonar.alm.client.gitlab.GitlabGlobalSettingsValidator; import org.sonar.alm.client.gitlab.GitlabHeaders; import org.sonar.alm.client.gitlab.GitlabPaginatedHttpClient; -import org.sonar.server.component.ComponentTypes; import org.sonar.api.server.rule.RulesDefinitionXmlLoader; import org.sonar.auth.bitbucket.BitbucketModule; import org.sonar.auth.github.GitHubModule; @@ -54,7 +53,6 @@ import org.sonar.ce.task.projectanalysis.taskprocessor.AuditPurgeTaskProcessor; import org.sonar.ce.task.projectanalysis.taskprocessor.IssueSyncTaskProcessor; import org.sonar.ce.task.projectanalysis.taskprocessor.ReportTaskProcessor; import org.sonar.ce.task.projectexport.taskprocessor.ProjectExportTaskProcessor; -import org.sonar.server.component.DefaultComponentTypes; import org.sonar.core.documentation.DefaultDocumentationLinkGenerator; import org.sonar.core.extension.CoreExtensionsInstaller; import org.sonar.core.language.LanguagesProvider; @@ -108,6 +106,8 @@ import org.sonar.server.common.text.MacroInterpreter; import org.sonar.server.component.ComponentCleanerService; import org.sonar.server.component.ComponentFinder; import org.sonar.server.component.ComponentService; +import org.sonar.server.component.ComponentTypes; +import org.sonar.server.component.DefaultComponentTypes; import org.sonar.server.component.index.ComponentIndex; import org.sonar.server.component.index.ComponentIndexDefinition; import org.sonar.server.component.index.EntityDefinitionIndexer; @@ -151,6 +151,7 @@ import org.sonar.server.issue.notification.MyNewIssuesEmailTemplate; import org.sonar.server.issue.notification.MyNewIssuesNotificationHandler; import org.sonar.server.issue.notification.NewIssuesEmailTemplate; import org.sonar.server.issue.notification.NewIssuesNotificationHandler; +import org.sonar.server.issue.notification.NewModesNotificationsModule; import org.sonar.server.issue.ws.IssueWsModule; import org.sonar.server.language.LanguageValidation; import org.sonar.server.language.ws.LanguageWs; @@ -292,8 +293,8 @@ import org.sonar.server.webhook.WebhookQGChangeEventListener; import org.sonar.server.webhook.ws.WebhooksWsModule; import org.sonar.server.ws.WebServiceEngine; import org.sonar.server.ws.ws.WebServicesWsModule; -import org.sonar.telemetry.core.TelemetryClient; import org.sonar.telemetry.TelemetryDaemon; +import org.sonar.telemetry.core.TelemetryClient; import org.sonar.telemetry.legacy.CloudUsageDataProvider; import org.sonar.telemetry.legacy.ProjectLocDistributionDataProvider; import org.sonar.telemetry.legacy.QualityProfileDataProvider; @@ -537,6 +538,7 @@ public class PlatformLevel4 extends PlatformLevel { BuiltInQPChangeNotificationTemplate.class, BuiltInQPChangeNotificationHandler.class, + new NewModesNotificationsModule(), new NotificationModule(), new NotificationWsModule(), new EmailsWsModule(), |