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.qualityprofile.builtin;
22 import java.util.List;
23 import javax.annotation.Nullable;
24 import org.junit.jupiter.api.Test;
25 import org.junit.jupiter.api.extension.RegisterExtension;
26 import org.sonar.api.config.Configuration;
27 import org.sonar.api.impl.utils.TestSystem2;
28 import org.sonar.api.rule.RuleKey;
29 import org.sonar.api.rule.Severity;
30 import org.sonar.api.rules.RulePriority;
31 import org.sonar.api.utils.System2;
32 import org.sonar.api.utils.Version;
33 import org.sonar.core.platform.SonarQubeVersion;
34 import org.sonar.db.DbSession;
35 import org.sonar.db.DbTester;
36 import org.sonar.db.qualityprofile.ActiveRuleDto;
37 import org.sonar.db.qualityprofile.ActiveRuleKey;
38 import org.sonar.db.qualityprofile.ActiveRuleParamDto;
39 import org.sonar.db.qualityprofile.QProfileDto;
40 import org.sonar.db.qualityprofile.RulesProfileDto;
41 import org.sonar.db.rule.RuleDto;
42 import org.sonar.db.rule.RuleParamDto;
43 import org.sonar.server.exceptions.BadRequestException;
44 import org.sonar.server.pushapi.qualityprofile.QualityProfileChangeEventService;
45 import org.sonar.server.qualityprofile.ActiveRuleChange;
46 import org.sonar.server.qualityprofile.ActiveRuleInheritance;
47 import org.sonar.server.qualityprofile.RuleActivation;
48 import org.sonar.server.qualityprofile.builtin.DescendantProfilesSupplier.Result;
49 import org.sonar.server.tester.UserSessionRule;
50 import org.sonar.server.util.IntegerTypeValidation;
51 import org.sonar.server.util.StringTypeValidation;
52 import org.sonar.server.util.TypeValidations;
54 import static java.lang.Boolean.TRUE;
55 import static java.util.Arrays.asList;
56 import static java.util.Collections.emptyList;
57 import static java.util.Collections.singletonList;
58 import static java.util.Map.of;
59 import static org.assertj.core.api.Assertions.assertThat;
60 import static org.junit.Assert.assertThrows;
61 import static org.mockito.Mockito.mock;
62 import static org.sonar.server.qualityprofile.ActiveRuleInheritance.INHERITED;
63 import static org.sonar.server.qualityprofile.ActiveRuleInheritance.OVERRIDES;
66 * Class org.sonar.server.qualityprofile.builtin.RuleActivator is mostly covered in
67 * org.sonar.server.qualityprofile.builtin.BuiltInQProfileUpdateImplTest
69 class RuleActivatorIT {
71 public final DbTester db = DbTester.create();
74 public final UserSessionRule userSession = UserSessionRule.standalone();
76 private static final long NOW = 1_000;
77 private static final long PAST = NOW - 100;
78 private final System2 system2 = new TestSystem2().setNow(NOW);
79 private final TypeValidations typeValidations = new TypeValidations(asList(new StringTypeValidation(), new IntegerTypeValidation()));
81 private final QualityProfileChangeEventService qualityProfileChangeEventService = mock(QualityProfileChangeEventService.class);
82 private final SonarQubeVersion sonarQubeVersion = new SonarQubeVersion(Version.create(10, 3));
83 private final RuleActivator underTest = new RuleActivator(system2, db.getDbClient(), typeValidations, userSession,
84 mock(Configuration.class), sonarQubeVersion);
87 void reset_overridden_active_rule() {
88 RuleDto rule = db.rules().insert(r -> r.setLanguage("xoo").setSeverity(Severity.BLOCKER));
89 RuleParamDto ruleParam = db.rules().insertRuleParam(rule, p -> p.setName("min").setDefaultValue("10"));
91 QProfileDto parentProfile = db.qualityProfiles().insert(p -> p.setLanguage(rule.getLanguage()).setIsBuiltIn(true));
92 ActiveRuleDto parentActiveRuleDto = activateRuleInDb(RulesProfileDto.from(parentProfile), rule,
93 RulePriority.valueOf(Severity.BLOCKER), false, null);
94 ActiveRuleParamDto parentActiveRuleParam = activateRuleParamInDb(parentActiveRuleDto, ruleParam, "10");
96 QProfileDto childProfile = createChildProfile(parentProfile);
97 ActiveRuleDto childActiveRuleDto = activateRuleInDb(RulesProfileDto.from(childProfile), rule,
98 RulePriority.valueOf(Severity.MINOR), true, OVERRIDES);
99 ActiveRuleParamDto childActiveRuleParam = activateRuleParamInDb(childActiveRuleDto, ruleParam, "15");
101 DbSession session = db.getSession();
102 RuleActivation resetRequest = RuleActivation.createReset(rule.getUuid());
103 RuleActivationContext context = new RuleActivationContext.Builder()
104 .setProfiles(asList(parentProfile, childProfile))
105 .setBaseProfile(RulesProfileDto.from(childProfile))
107 .setDescendantProfilesSupplier((profiles, ruleUuids) -> new Result(emptyList(), emptyList(), emptyList()))
108 .setRules(singletonList(rule))
109 .setRuleParams(singletonList(ruleParam))
110 .setActiveRules(asList(parentActiveRuleDto, childActiveRuleDto))
111 .setActiveRuleParams(asList(parentActiveRuleParam, childActiveRuleParam))
114 List<ActiveRuleChange> result = underTest.activate(session, resetRequest, context);
116 assertThat(result).hasSize(1);
117 ActiveRuleChange activeRuleResult = result.get(0);
118 assertThat(activeRuleResult.getParameters()).containsEntry("min", "10");
119 assertThat(activeRuleResult.getSeverity()).isEqualTo(Severity.BLOCKER);
120 assertThat(activeRuleResult.isPrioritizedRule()).isFalse();
121 assertThat(activeRuleResult.getInheritance()).isEqualTo(ActiveRuleInheritance.INHERITED);
125 void request_new_severity_and_prioritized_rule_and_param_for_child_rule() {
126 RuleDto rule = db.rules().insert(r -> r.setLanguage("xoo").setSeverity(Severity.BLOCKER));
127 RuleParamDto ruleParam = db.rules().insertRuleParam(rule, p -> p.setName("min").setDefaultValue("10"));
129 QProfileDto parentProfile = db.qualityProfiles().insert(p -> p.setLanguage(rule.getLanguage()).setIsBuiltIn(true));
130 ActiveRuleDto parentActiveRuleDto = activateRuleInDb(RulesProfileDto.from(parentProfile), rule,
131 RulePriority.valueOf(Severity.BLOCKER), null, null);
132 ActiveRuleParamDto parentActiveRuleParam = activateRuleParamInDb(parentActiveRuleDto, ruleParam, "10");
134 QProfileDto childProfile = createChildProfile(parentProfile);
135 ActiveRuleDto childActiveRuleDto = activateRuleInDb(RulesProfileDto.from(childProfile), rule,
136 RulePriority.valueOf(Severity.BLOCKER), null, INHERITED);
137 ActiveRuleParamDto childActiveRuleParam = activateRuleParamInDb(childActiveRuleDto, ruleParam, "10");
139 DbSession session = db.getSession();
140 RuleActivation resetRequest = RuleActivation.create(rule.getUuid(), Severity.MINOR, true, of("min", "15"));
141 RuleActivationContext context = new RuleActivationContext.Builder()
142 .setProfiles(asList(parentProfile, childProfile))
143 .setBaseProfile(RulesProfileDto.from(childProfile))
145 .setDescendantProfilesSupplier((profiles, ruleUuids) -> new Result(emptyList(), emptyList(), emptyList()))
146 .setRules(singletonList(rule))
147 .setRuleParams(singletonList(ruleParam))
148 .setActiveRules(asList(parentActiveRuleDto, childActiveRuleDto))
149 .setActiveRuleParams(asList(parentActiveRuleParam, childActiveRuleParam))
152 List<ActiveRuleChange> result = underTest.activate(session, resetRequest, context);
154 assertThat(result).hasSize(1);
155 ActiveRuleChange activeRuleResult = result.get(0);
156 assertThat(activeRuleResult.getParameters()).containsEntry("min", "15");
157 assertThat(activeRuleResult.getSeverity()).isEqualTo(Severity.MINOR);
158 assertThat(activeRuleResult.isPrioritizedRule()).isTrue();
159 assertThat(activeRuleResult.getInheritance()).isEqualTo(OVERRIDES);
163 void set_severity_and_param_for_child_rule_when_activating() {
164 RuleDto rule = db.rules().insert(r -> r.setLanguage("xoo").setSeverity(Severity.BLOCKER));
165 RuleParamDto ruleParam = db.rules().insertRuleParam(rule, p -> p.setName("min").setDefaultValue("10"));
167 QProfileDto parentProfile = db.qualityProfiles().insert(p -> p.setLanguage(rule.getLanguage()).setIsBuiltIn(true));
169 QProfileDto childProfile = createChildProfile(parentProfile);
171 DbSession session = db.getSession();
172 RuleActivation resetRequest = RuleActivation.create(rule.getUuid());
173 RuleActivationContext context = new RuleActivationContext.Builder()
174 .setProfiles(asList(parentProfile, childProfile))
175 .setBaseProfile(RulesProfileDto.from(childProfile))
177 .setDescendantProfilesSupplier((profiles, ruleUuids) -> new Result(emptyList(), emptyList(), emptyList()))
178 .setRules(singletonList(rule))
179 .setRuleParams(singletonList(ruleParam))
180 .setActiveRules(emptyList())
181 .setActiveRuleParams(emptyList())
184 List<ActiveRuleChange> result = underTest.activate(session, resetRequest, context);
186 assertThat(result).hasSize(1);
187 assertThat(result.get(0).getParameters()).containsEntry("min", "10");
188 assertThat(result.get(0).getSeverity()).isEqualTo(Severity.BLOCKER);
189 assertThat(result.get(0).getInheritance()).isNull();
193 void fail_if_rule_language_doesnt_match_qp() {
194 RuleDto rule = db.rules().insert(r -> r.setLanguage("xoo")
195 .setRepositoryKey("repo")
197 .setSeverity(Severity.BLOCKER));
198 QProfileDto qp = db.qualityProfiles().insert(p -> p.setLanguage("xoo2").setKee("qp").setIsBuiltIn(true));
200 DbSession session = db.getSession();
201 RuleActivation resetRequest = RuleActivation.create(rule.getUuid());
202 RuleActivationContext context = new RuleActivationContext.Builder()
203 .setProfiles(singletonList(qp))
204 .setBaseProfile(RulesProfileDto.from(qp))
206 .setDescendantProfilesSupplier((profiles, ruleUuids) -> new Result(emptyList(), emptyList(), emptyList()))
207 .setRules(singletonList(rule))
208 .setRuleParams(emptyList())
209 .setActiveRules(emptyList())
210 .setActiveRuleParams(emptyList())
214 assertThrows("xoo rule repo:rule cannot be activated on xoo2 profile qp", BadRequestException.class,
215 () -> underTest.activate(session, resetRequest, context));
219 private ActiveRuleDto activateRuleInDb(RulesProfileDto ruleProfile, RuleDto rule, RulePriority severity,
220 @Nullable Boolean prioritizedRule, @Nullable ActiveRuleInheritance inheritance) {
221 ActiveRuleDto dto = new ActiveRuleDto()
222 .setKey(ActiveRuleKey.of(ruleProfile, RuleKey.of(rule.getRepositoryKey(), rule.getRuleKey())))
223 .setProfileUuid(ruleProfile.getUuid())
224 .setSeverity(severity.name())
225 .setPrioritizedRule(TRUE.equals(prioritizedRule))
226 .setRuleUuid(rule.getUuid())
227 .setInheritance(inheritance != null ? inheritance.name() : null)
230 db.getDbClient().activeRuleDao().insert(db.getSession(), dto);
235 private ActiveRuleParamDto activateRuleParamInDb(ActiveRuleDto activeRuleDto, RuleParamDto ruleParamDto, String value) {
236 ActiveRuleParamDto dto = new ActiveRuleParamDto()
237 .setActiveRuleUuid(activeRuleDto.getUuid())
238 .setRulesParameterUuid(ruleParamDto.getUuid())
239 .setKey(ruleParamDto.getName())
241 db.getDbClient().activeRuleDao().insertParam(db.getSession(), activeRuleDto, dto);
246 private QProfileDto createChildProfile(QProfileDto parent) {
247 return db.qualityProfiles().insert(p -> p
248 .setLanguage(parent.getLanguage())
249 .setParentKee(parent.getKee())
250 .setName("Child of " + parent.getName()))
251 .setIsBuiltIn(false);