3 * Copyright (C) 2009-2024 SonarSource SA
4 * mailto:info AT sonarsource DOT com
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 3 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 package org.sonar.server.rule.registration;
22 import java.util.List;
24 import org.junit.Before;
25 import org.junit.Test;
26 import org.mockito.ArgumentCaptor;
27 import org.sonar.api.issue.impact.Severity;
28 import org.sonar.api.issue.impact.SoftwareQuality;
29 import org.sonar.api.rules.CleanCodeAttribute;
30 import org.sonar.api.utils.Version;
31 import org.sonar.core.platform.SonarQubeVersion;
32 import org.sonar.core.util.UuidFactoryImpl;
33 import org.sonar.db.DbClient;
34 import org.sonar.db.DbSession;
35 import org.sonar.db.qualityprofile.ActiveRuleDao;
36 import org.sonar.db.qualityprofile.ActiveRuleDto;
37 import org.sonar.db.qualityprofile.QProfileChangeDao;
38 import org.sonar.db.rule.RuleChangeDao;
39 import org.sonar.db.rule.RuleChangeDto;
40 import org.sonar.db.rule.RuleImpactChangeDto;
41 import org.sonar.server.rule.PluginRuleUpdate;
43 import static org.assertj.core.api.Assertions.assertThat;
44 import static org.assertj.core.api.Assertions.tuple;
45 import static org.mockito.ArgumentMatchers.any;
46 import static org.mockito.ArgumentMatchers.argThat;
47 import static org.mockito.Mockito.mock;
48 import static org.mockito.Mockito.times;
49 import static org.mockito.Mockito.verify;
50 import static org.mockito.Mockito.verifyNoInteractions;
51 import static org.mockito.Mockito.when;
53 public class QualityProfileChangesUpdaterTest {
55 public static final String RULE_UUID = "ruleUuid";
56 private final DbClient dbClient = mock();
57 private final DbSession dbSession = mock();
58 private final RuleChangeDao ruleChangeDao = mock();
59 private final QProfileChangeDao qualityProfileChangeDao = mock();
60 private final ActiveRuleDao activeRuleDao = mock();
61 private final SonarQubeVersion sonarQubeVersion = new SonarQubeVersion(Version.create(10, 3));
63 private final QualityProfileChangesUpdater underTest = new QualityProfileChangesUpdater(dbClient, UuidFactoryImpl.INSTANCE, sonarQubeVersion);
66 public void before() {
67 when(dbClient.ruleChangeDao()).thenReturn(ruleChangeDao);
68 when(dbClient.qProfileChangeDao()).thenReturn(qualityProfileChangeDao);
69 when(dbClient.activeRuleDao()).thenReturn(activeRuleDao);
73 public void updateWithoutCommit_whenNoRuleChanges_thenDontInteractWithDatabase() {
74 underTest.createQprofileChangesForRuleUpdates(mock(), Set.of());
76 verifyNoInteractions(dbClient);
80 public void updateWithoutCommit_whenOneRuleChangedItsAttribute_thenInsertRuleChangeButNotImpactChange() {
81 PluginRuleUpdate pluginRuleUpdate = new PluginRuleUpdate();
82 pluginRuleUpdate.setNewCleanCodeAttribute(CleanCodeAttribute.CLEAR);
83 pluginRuleUpdate.setOldCleanCodeAttribute(CleanCodeAttribute.TESTED);
84 pluginRuleUpdate.setRuleUuid(RULE_UUID);
86 underTest.createQprofileChangesForRuleUpdates(dbSession, Set.of(pluginRuleUpdate));
88 verify(ruleChangeDao).insert(argThat(dbSession::equals), argThat(ruleChangeDto ->
89 ruleChangeDto.getNewCleanCodeAttribute() == CleanCodeAttribute.CLEAR
90 && ruleChangeDto.getOldCleanCodeAttribute() == CleanCodeAttribute.TESTED
91 && ruleChangeDto.getRuleUuid().equals(RULE_UUID)
92 && ruleChangeDto.getRuleImpactChanges().isEmpty()));
96 public void updateWithoutCommit_whenTwoRulesChangedTheirImpactsAndAttributes_thenInsertRuleChangeAndImpactChange() {
97 PluginRuleUpdate pluginRuleUpdate = new PluginRuleUpdate();
98 pluginRuleUpdate.setNewCleanCodeAttribute(CleanCodeAttribute.CLEAR);
99 pluginRuleUpdate.setOldCleanCodeAttribute(CleanCodeAttribute.TESTED);
100 pluginRuleUpdate.setRuleUuid(RULE_UUID);
102 //testing here detecting the change with 2 the same software qualities
103 pluginRuleUpdate.addNewImpact(SoftwareQuality.RELIABILITY, Severity.LOW);
104 pluginRuleUpdate.addOldImpact(SoftwareQuality.RELIABILITY, Severity.MEDIUM);
106 PluginRuleUpdate pluginRuleUpdate2 = new PluginRuleUpdate();
107 pluginRuleUpdate2.setNewCleanCodeAttribute(CleanCodeAttribute.EFFICIENT);
108 pluginRuleUpdate2.setOldCleanCodeAttribute(CleanCodeAttribute.DISTINCT);
109 pluginRuleUpdate2.setRuleUuid("ruleUuid2");
111 //testing here detecting the change with 2 the different software qualities
112 pluginRuleUpdate2.addNewImpact(SoftwareQuality.SECURITY, Severity.HIGH);
113 pluginRuleUpdate2.addOldImpact(SoftwareQuality.RELIABILITY, Severity.MEDIUM);
115 underTest.createQprofileChangesForRuleUpdates(dbSession, Set.of(pluginRuleUpdate, pluginRuleUpdate2));
117 ArgumentCaptor<RuleChangeDto> captor = ArgumentCaptor.forClass(RuleChangeDto.class);
118 verify(ruleChangeDao, times(2)).insert(argThat(dbSession::equals), captor.capture());
120 RuleChangeDto firstChange = captor.getAllValues().stream().filter(change -> change.getRuleUuid().equals(RULE_UUID)).findFirst().get();
121 RuleChangeDto secondChange = captor.getAllValues().stream().filter(change -> change.getRuleUuid().equals("ruleUuid2")).findFirst().get();
123 assertThat(firstChange.getNewCleanCodeAttribute()).isEqualTo(CleanCodeAttribute.CLEAR);
124 assertThat(firstChange.getOldCleanCodeAttribute()).isEqualTo(CleanCodeAttribute.TESTED);
125 assertThat(firstChange.getRuleUuid()).isEqualTo(RULE_UUID);
126 assertThat(firstChange.getRuleImpactChanges()).hasSize(1);
127 assertThat(firstChange.getRuleImpactChanges()).extracting(RuleImpactChangeDto::getNewSoftwareQuality,
128 RuleImpactChangeDto::getOldSoftwareQuality, RuleImpactChangeDto::getOldSeverity, RuleImpactChangeDto::getNewSeverity)
129 .containsExactly(tuple(SoftwareQuality.RELIABILITY, SoftwareQuality.RELIABILITY, Severity.MEDIUM, Severity.LOW));
131 assertThat(secondChange.getNewCleanCodeAttribute()).isEqualTo(CleanCodeAttribute.EFFICIENT);
132 assertThat(secondChange.getOldCleanCodeAttribute()).isEqualTo(CleanCodeAttribute.DISTINCT);
133 assertThat(secondChange.getRuleUuid()).isEqualTo("ruleUuid2");
134 assertThat(secondChange.getRuleImpactChanges()).hasSize(1);
135 assertThat(secondChange.getRuleImpactChanges()).extracting(RuleImpactChangeDto::getNewSoftwareQuality,
136 RuleImpactChangeDto::getOldSoftwareQuality, RuleImpactChangeDto::getOldSeverity, RuleImpactChangeDto::getNewSeverity)
137 .containsExactly(tuple(SoftwareQuality.SECURITY, SoftwareQuality.RELIABILITY, Severity.MEDIUM, Severity.HIGH));
141 public void updateWithoutCommit_whenOneRuleBelongingToTwoQualityProfilesChanged_thenInsertOneRuleChangeAndTwoQualityProfileChanges() {
142 List<ActiveRuleDto> activeRuleDtos = List.of(
143 new ActiveRuleDto().setProfileUuid("profileUuid1").setRuleUuid(RULE_UUID),
144 new ActiveRuleDto().setProfileUuid("profileUuid2").setRuleUuid(RULE_UUID));
145 when(activeRuleDao.selectByRuleUuid(any(), any())).thenReturn(activeRuleDtos);
147 PluginRuleUpdate pluginRuleUpdate = new PluginRuleUpdate();
148 pluginRuleUpdate.setNewCleanCodeAttribute(CleanCodeAttribute.CLEAR);
149 pluginRuleUpdate.setOldCleanCodeAttribute(CleanCodeAttribute.TESTED);
150 pluginRuleUpdate.setRuleUuid(RULE_UUID);
152 underTest.createQprofileChangesForRuleUpdates(dbSession, Set.of(pluginRuleUpdate));
154 verify(qualityProfileChangeDao, times(1)).bulkInsert(argThat(dbSession::equals),
155 argThat(qProfileChangeDtos ->
156 qProfileChangeDtos.stream()
157 .allMatch(dto -> "UPDATED".equals(dto.getChangeType()) && dto.getRuleChange() != null)));