3 * Copyright (C) 2009-2022 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.Collection;
23 import java.util.List;
25 import java.util.Optional;
26 import javax.annotation.Nullable;
27 import org.assertj.core.groups.Tuple;
28 import org.junit.Before;
29 import org.junit.Rule;
30 import org.junit.Test;
31 import org.sonar.api.impl.utils.TestSystem2;
32 import org.sonar.api.rule.RuleKey;
33 import org.sonar.api.rule.Severity;
34 import org.sonar.api.rules.RulePriority;
35 import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition;
36 import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition.NewBuiltInQualityProfile;
37 import org.sonar.api.utils.System2;
38 import org.sonar.db.DbSession;
39 import org.sonar.db.DbTester;
40 import org.sonar.db.qualityprofile.ActiveRuleDto;
41 import org.sonar.db.qualityprofile.ActiveRuleKey;
42 import org.sonar.db.qualityprofile.ActiveRuleParamDto;
43 import org.sonar.db.qualityprofile.OrgActiveRuleDto;
44 import org.sonar.db.qualityprofile.QProfileDto;
45 import org.sonar.db.qualityprofile.RulesProfileDto;
46 import org.sonar.db.rule.RuleDefinitionDto;
47 import org.sonar.db.rule.RuleParamDto;
48 import org.sonar.server.pushapi.qualityprofile.QualityProfileChangeEventService;
49 import org.sonar.server.qualityprofile.ActiveRuleChange;
50 import org.sonar.server.qualityprofile.ActiveRuleInheritance;
51 import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
52 import org.sonar.server.tester.UserSessionRule;
53 import org.sonar.server.util.IntegerTypeValidation;
54 import org.sonar.server.util.StringTypeValidation;
55 import org.sonar.server.util.TypeValidations;
57 import static java.util.Arrays.asList;
58 import static java.util.Collections.emptyMap;
59 import static java.util.Collections.singletonList;
60 import static org.assertj.core.api.Assertions.assertThat;
61 import static org.assertj.core.groups.Tuple.tuple;
62 import static org.mockito.ArgumentMatchers.any;
63 import static org.mockito.ArgumentMatchers.eq;
64 import static org.mockito.Mockito.mock;
65 import static org.mockito.Mockito.verify;
66 import static org.mockito.Mockito.verifyNoInteractions;
67 import static org.mockito.Mockito.verifyNoMoreInteractions;
68 import static org.sonar.api.rules.RulePriority.BLOCKER;
69 import static org.sonar.api.rules.RulePriority.CRITICAL;
70 import static org.sonar.api.rules.RulePriority.MAJOR;
71 import static org.sonar.api.rules.RulePriority.MINOR;
72 import static org.sonar.db.qualityprofile.QualityProfileTesting.newRuleProfileDto;
73 import static org.sonar.server.qualityprofile.ActiveRuleInheritance.INHERITED;
75 public class BuiltInQProfileUpdateImplTest {
77 private static final long NOW = 1_000;
78 private static final long PAST = NOW - 100;
81 public BuiltInQProfileRepositoryRule builtInProfileRepository = new BuiltInQProfileRepositoryRule();
83 public DbTester db = DbTester.create();
85 public UserSessionRule userSession = UserSessionRule.standalone();
86 private System2 system2 = new TestSystem2().setNow(NOW);
87 private ActiveRuleIndexer activeRuleIndexer = mock(ActiveRuleIndexer.class);
88 private TypeValidations typeValidations = new TypeValidations(asList(new StringTypeValidation(), new IntegerTypeValidation()));
89 private QualityProfileChangeEventService qualityProfileChangeEventService = mock(QualityProfileChangeEventService.class);
90 private RuleActivator ruleActivator = new RuleActivator(system2, db.getDbClient(), typeValidations, userSession);
92 private BuiltInQProfileUpdateImpl underTest = new BuiltInQProfileUpdateImpl(db.getDbClient(), ruleActivator, activeRuleIndexer,
93 qualityProfileChangeEventService);
95 private RulesProfileDto persistedProfile;
99 persistedProfile = newRuleProfileDto(rp -> rp
102 .setRulesUpdatedAt(null));
103 db.getDbClient().qualityProfileDao().insert(db.getSession(), persistedProfile);
108 public void activate_new_rules() {
109 RuleDefinitionDto rule1 = db.rules().insert(r -> r.setLanguage("xoo"));
110 RuleDefinitionDto rule2 = db.rules().insert(r -> r.setLanguage("xoo"));
111 BuiltInQualityProfilesDefinition.Context context = new BuiltInQualityProfilesDefinition.Context();
112 NewBuiltInQualityProfile newQp = context.createBuiltInQualityProfile("Sonar way", "xoo");
113 newQp.activateRule(rule1.getRepositoryKey(), rule1.getRuleKey()).overrideSeverity(Severity.CRITICAL);
114 newQp.activateRule(rule2.getRepositoryKey(), rule2.getRuleKey()).overrideSeverity(Severity.MAJOR);
116 BuiltInQProfile builtIn = builtInProfileRepository.create(context.profile("xoo", "Sonar way"), rule1, rule2);
118 List<ActiveRuleChange> changes = underTest.update(db.getSession(), builtIn, persistedProfile);
120 List<ActiveRuleDto> activeRules = db.getDbClient().activeRuleDao().selectByRuleProfile(db.getSession(), persistedProfile);
121 assertThat(activeRules).hasSize(2);
122 assertThatRuleIsNewlyActivated(activeRules, rule1, CRITICAL);
123 assertThatRuleIsNewlyActivated(activeRules, rule2, MAJOR);
124 assertThatProfileIsMarkedAsUpdated(persistedProfile);
125 verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(persistedProfile.getLanguage()));
129 public void already_activated_rule_is_updated_in_case_of_differences() {
130 RuleDefinitionDto rule = db.rules().insert(r -> r.setLanguage("xoo"));
131 BuiltInQualityProfilesDefinition.Context context = new BuiltInQualityProfilesDefinition.Context();
132 NewBuiltInQualityProfile newQp = context.createBuiltInQualityProfile("Sonar way", "xoo");
133 newQp.activateRule(rule.getRepositoryKey(), rule.getRuleKey()).overrideSeverity(Severity.CRITICAL);
135 BuiltInQProfile builtIn = builtInProfileRepository.create(context.profile("xoo", "Sonar way"), rule);
137 activateRuleInDb(persistedProfile, rule, BLOCKER);
139 List<ActiveRuleChange> changes = underTest.update(db.getSession(), builtIn, persistedProfile);
141 List<ActiveRuleDto> activeRules = db.getDbClient().activeRuleDao().selectByRuleProfile(db.getSession(), persistedProfile);
142 assertThat(activeRules).hasSize(1);
143 assertThatRuleIsUpdated(activeRules, rule, CRITICAL);
144 assertThatProfileIsMarkedAsUpdated(persistedProfile);
145 verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(persistedProfile.getLanguage()));
149 public void already_activated_rule_is_not_touched_if_no_differences() {
150 RuleDefinitionDto rule = db.rules().insert(r -> r.setLanguage("xoo"));
151 BuiltInQualityProfilesDefinition.Context context = new BuiltInQualityProfilesDefinition.Context();
152 NewBuiltInQualityProfile newQp = context.createBuiltInQualityProfile("Sonar way", "xoo");
153 newQp.activateRule(rule.getRepositoryKey(), rule.getRuleKey()).overrideSeverity(Severity.CRITICAL);
155 BuiltInQProfile builtIn = builtInProfileRepository.create(context.profile("xoo", "Sonar way"), rule);
157 activateRuleInDb(persistedProfile, rule, CRITICAL);
159 underTest.update(db.getSession(), builtIn, persistedProfile);
161 List<ActiveRuleDto> activeRules = db.getDbClient().activeRuleDao().selectByRuleProfile(db.getSession(), persistedProfile);
162 assertThat(activeRules).hasSize(1);
163 assertThatRuleIsUntouched(activeRules, rule, CRITICAL);
164 assertThatProfileIsNotMarkedAsUpdated(persistedProfile);
165 verifyNoInteractions(qualityProfileChangeEventService);
169 public void deactivate_rule_that_is_not_in_built_in_definition_anymore() {
170 RuleDefinitionDto rule1 = db.rules().insert(r -> r.setLanguage("xoo"));
171 RuleDefinitionDto rule2 = db.rules().insert(r -> r.setLanguage("xoo"));
172 BuiltInQualityProfilesDefinition.Context context = new BuiltInQualityProfilesDefinition.Context();
173 NewBuiltInQualityProfile newQp = context.createBuiltInQualityProfile("Sonar way", "xoo");
174 newQp.activateRule(rule2.getRepositoryKey(), rule2.getRuleKey()).overrideSeverity(Severity.MAJOR);
176 BuiltInQProfile builtIn = builtInProfileRepository.create(context.profile("xoo", "Sonar way"), rule1, rule2);
178 // built-in definition contains only rule2
179 // so rule1 must be deactivated
180 activateRuleInDb(persistedProfile, rule1, CRITICAL);
182 List<ActiveRuleChange> changes = underTest.update(db.getSession(), builtIn, persistedProfile);
184 List<ActiveRuleDto> activeRules = db.getDbClient().activeRuleDao().selectByRuleProfile(db.getSession(), persistedProfile);
185 assertThat(activeRules).hasSize(1);
186 assertThatRuleIsDeactivated(activeRules, rule1);
187 assertThatProfileIsMarkedAsUpdated(persistedProfile);
188 verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(persistedProfile.getLanguage()));
192 public void activate_deactivate_and_update_three_rules_at_the_same_time() {
193 RuleDefinitionDto rule1 = db.rules().insert(r -> r.setLanguage("xoo"));
194 RuleDefinitionDto rule2 = db.rules().insert(r -> r.setLanguage("xoo"));
195 RuleDefinitionDto rule3 = db.rules().insert(r -> r.setLanguage("xoo"));
197 BuiltInQualityProfilesDefinition.Context context = new BuiltInQualityProfilesDefinition.Context();
198 NewBuiltInQualityProfile newQp = context.createBuiltInQualityProfile("Sonar way", "xoo");
199 newQp.activateRule(rule1.getRepositoryKey(), rule1.getRuleKey()).overrideSeverity(Severity.CRITICAL);
200 newQp.activateRule(rule2.getRepositoryKey(), rule2.getRuleKey()).overrideSeverity(Severity.MAJOR);
202 BuiltInQProfile builtIn = builtInProfileRepository.create(context.profile("xoo", "Sonar way"), rule1, rule2);
204 // rule1 must be updated (blocker to critical)
205 // rule2 must be activated
206 // rule3 must be deactivated
207 activateRuleInDb(persistedProfile, rule1, BLOCKER);
208 activateRuleInDb(persistedProfile, rule3, BLOCKER);
210 List<ActiveRuleChange> changes = underTest.update(db.getSession(), builtIn, persistedProfile);
212 List<ActiveRuleDto> activeRules = db.getDbClient().activeRuleDao().selectByRuleProfile(db.getSession(), persistedProfile);
213 assertThat(activeRules).hasSize(2);
214 assertThatRuleIsUpdated(activeRules, rule1, CRITICAL);
215 assertThatRuleIsNewlyActivated(activeRules, rule2, MAJOR);
216 assertThatRuleIsDeactivated(activeRules, rule3);
217 assertThatProfileIsMarkedAsUpdated(persistedProfile);
218 verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(persistedProfile.getLanguage()));
223 public void activate_rule_on_built_in_profile_resets_severity_to_default_if_not_overridden() {
224 RuleDefinitionDto rule = db.rules().insert(r -> r.setSeverity(Severity.MAJOR).setLanguage("xoo"));
226 BuiltInQualityProfilesDefinition.Context context = new BuiltInQualityProfilesDefinition.Context();
227 NewBuiltInQualityProfile newQp = context.createBuiltInQualityProfile("Sonar way", "xoo");
228 newQp.activateRule(rule.getRepositoryKey(), rule.getRuleKey());
230 BuiltInQProfile builtIn = builtInProfileRepository.create(context.profile("xoo", "Sonar way"), rule);
231 underTest.update(db.getSession(), builtIn, persistedProfile);
233 List<ActiveRuleDto> activeRules = db.getDbClient().activeRuleDao().selectByRuleProfile(db.getSession(), persistedProfile);
234 assertThatRuleIsNewlyActivated(activeRules, rule, MAJOR);
236 // emulate an upgrade of analyzer that changes the default severity of the rule
237 rule.setSeverity(Severity.MINOR);
238 db.rules().update(rule);
240 List<ActiveRuleChange> changes = underTest.update(db.getSession(), builtIn, persistedProfile);
241 activeRules = db.getDbClient().activeRuleDao().selectByRuleProfile(db.getSession(), persistedProfile);
242 assertThatRuleIsNewlyActivated(activeRules, rule, MINOR);
243 verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(persistedProfile.getLanguage()));
247 public void activate_rule_on_built_in_profile_resets_params_to_default_if_not_overridden() {
248 RuleDefinitionDto rule = db.rules().insert(r -> r.setLanguage("xoo"));
249 RuleParamDto ruleParam = db.rules().insertRuleParam(rule, p -> p.setName("min").setDefaultValue("10"));
251 BuiltInQualityProfilesDefinition.Context context = new BuiltInQualityProfilesDefinition.Context();
252 NewBuiltInQualityProfile newQp = context.createBuiltInQualityProfile("Sonar way", rule.getLanguage());
253 newQp.activateRule(rule.getRepositoryKey(), rule.getRuleKey());
255 BuiltInQProfile builtIn = builtInProfileRepository.create(context.profile(newQp.language(), newQp.name()), rule);
256 List<ActiveRuleChange> changes = underTest.update(db.getSession(), builtIn, persistedProfile);
258 List<ActiveRuleDto> activeRules = db.getDbClient().activeRuleDao().selectByRuleProfile(db.getSession(), persistedProfile);
259 assertThat(activeRules).hasSize(1);
260 assertThatRuleHasParams(db, activeRules.get(0), tuple("min", "10"));
261 verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(persistedProfile.getLanguage()));
263 // emulate an upgrade of analyzer that changes the default value of parameter min
264 ruleParam.setDefaultValue("20");
265 db.getDbClient().ruleDao().updateRuleParam(db.getSession(), rule, ruleParam);
267 changes = underTest.update(db.getSession(), builtIn, persistedProfile);
268 activeRules = db.getDbClient().activeRuleDao().selectByRuleProfile(db.getSession(), persistedProfile);
269 assertThat(activeRules).hasSize(1);
270 assertThatRuleHasParams(db, activeRules.get(0), tuple("min", "20"));
271 verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(persistedProfile.getLanguage()));
275 public void propagate_activation_to_descendant_profiles() {
276 RuleDefinitionDto rule = db.rules().insert(r -> r.setLanguage("xoo"));
278 QProfileDto profile = db.qualityProfiles().insert(p -> p.setLanguage(rule.getLanguage()).setIsBuiltIn(true));
279 QProfileDto childProfile = createChildProfile(profile);
280 QProfileDto grandchildProfile = createChildProfile(childProfile);
282 BuiltInQualityProfilesDefinition.Context context = new BuiltInQualityProfilesDefinition.Context();
283 NewBuiltInQualityProfile newQp = context.createBuiltInQualityProfile(profile.getName(), profile.getLanguage());
284 newQp.activateRule(rule.getRepositoryKey(), rule.getRuleKey());
286 BuiltInQProfile builtIn = builtInProfileRepository.create(context.profile(profile.getLanguage(), profile.getName()), rule);
287 List<ActiveRuleChange> changes = underTest.update(db.getSession(), builtIn, RulesProfileDto.from(profile));
289 assertThat(changes).hasSize(3);
290 assertThatRuleIsActivated(profile, rule, changes, rule.getSeverityString(), null, emptyMap());
291 assertThatRuleIsActivated(childProfile, rule, changes, rule.getSeverityString(), INHERITED, emptyMap());
292 assertThatRuleIsActivated(grandchildProfile, rule, changes, rule.getSeverityString(), INHERITED, emptyMap());
293 verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(persistedProfile.getLanguage()));
298 public void propagate_rule_update_to_descendant_active_rule() {
299 RuleDefinitionDto rule = db.rules().insert(r -> r.setLanguage("xoo").setSeverity(Severity.BLOCKER));
301 QProfileDto parentProfile = db.qualityProfiles().insert(p -> p.setLanguage(rule.getLanguage()).setIsBuiltIn(true));
302 activateRuleInDb(RulesProfileDto.from(parentProfile), rule, RulePriority.valueOf(Severity.MINOR), null);
304 QProfileDto childProfile = createChildProfile(parentProfile);
305 activateRuleInDb(RulesProfileDto.from(childProfile), rule, RulePriority.valueOf(Severity.MINOR), INHERITED);
307 BuiltInQualityProfilesDefinition.Context context = new BuiltInQualityProfilesDefinition.Context();
308 NewBuiltInQualityProfile newQp = context.createBuiltInQualityProfile(parentProfile.getName(), parentProfile.getLanguage());
309 newQp.activateRule(rule.getRepositoryKey(), rule.getRuleKey());
311 BuiltInQProfile builtIn = builtInProfileRepository.create(context.profile(parentProfile.getLanguage(), parentProfile.getName()), rule);
312 List<ActiveRuleChange> changes = underTest.update(db.getSession(), builtIn, RulesProfileDto.from(parentProfile));
314 assertThat(changes).hasSize(2);
316 List<ActiveRuleDto> parentActiveRules = db.getDbClient().activeRuleDao().selectByRuleProfile(db.getSession(), RulesProfileDto.from(parentProfile));
317 assertThatRuleIsUpdated(parentActiveRules, rule, RulePriority.BLOCKER, null);
319 List<ActiveRuleDto> childActiveRules = db.getDbClient().activeRuleDao().selectByRuleProfile(db.getSession(), RulesProfileDto.from(childProfile));
320 assertThatRuleIsUpdated(childActiveRules, rule, RulePriority.BLOCKER, INHERITED);
321 verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(persistedProfile.getLanguage()));
325 public void propagate_rule_param_update_to_descendant_active_rule_params() {
326 RuleDefinitionDto rule = db.rules().insert(r -> r.setLanguage("xoo").setSeverity(Severity.BLOCKER));
327 RuleParamDto ruleParam = db.rules().insertRuleParam(rule, p -> p.setName("min").setDefaultValue("10"));
329 QProfileDto parentProfile = db.qualityProfiles().insert(p -> p.setLanguage(rule.getLanguage()).setIsBuiltIn(true));
330 ActiveRuleDto parentActiveRuleDto = activateRuleInDb(RulesProfileDto.from(parentProfile), rule,
331 RulePriority.valueOf(Severity.MINOR), null);
332 activateRuleParamInDb(parentActiveRuleDto, ruleParam, "20");
334 QProfileDto childProfile = createChildProfile(parentProfile);
335 ActiveRuleDto childActiveRuleDto = activateRuleInDb(RulesProfileDto.from(childProfile), rule,
336 RulePriority.valueOf(Severity.MINOR), INHERITED);
337 activateRuleParamInDb(childActiveRuleDto, ruleParam, "20");
339 BuiltInQualityProfilesDefinition.Context context = new BuiltInQualityProfilesDefinition.Context();
340 NewBuiltInQualityProfile newQp = context.createBuiltInQualityProfile(parentProfile.getName(), parentProfile.getLanguage());
341 newQp.activateRule(rule.getRepositoryKey(), rule.getRuleKey());
343 BuiltInQProfile builtIn = builtInProfileRepository.create(context.profile(parentProfile.getLanguage(), parentProfile.getName()), rule);
344 List<ActiveRuleChange> changes = underTest.update(db.getSession(), builtIn, RulesProfileDto.from(parentProfile));
346 assertThat(changes).hasSize(2);
348 assertThatRuleHasParams(db, parentActiveRuleDto, tuple("min", "10"));
349 assertThatRuleHasParams(db, childActiveRuleDto, tuple("min", "10"));
350 verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(persistedProfile.getLanguage()));
354 public void do_not_load_descendants_if_no_changes() {
355 RuleDefinitionDto rule = db.rules().insert(r -> r.setLanguage("xoo"));
357 QProfileDto profile = db.qualityProfiles().insert(p -> p.setLanguage(rule.getLanguage()).setIsBuiltIn(true));
358 QProfileDto childProfile = createChildProfile(profile);
360 BuiltInQualityProfilesDefinition.Context context = new BuiltInQualityProfilesDefinition.Context();
361 NewBuiltInQualityProfile newQp = context.createBuiltInQualityProfile(profile.getName(), profile.getLanguage());
362 newQp.activateRule(rule.getRepositoryKey(), rule.getRuleKey());
366 BuiltInQProfile builtIn = builtInProfileRepository.create(context.profile(profile.getLanguage(), profile.getName()), rule);
367 List<ActiveRuleChange> changes = underTest.update(db.getSession(), builtIn, RulesProfileDto.from(profile));
368 assertThat(changes).hasSize(2).extracting(ActiveRuleChange::getType).containsOnly(ActiveRuleChange.Type.ACTIVATED);
369 verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(persistedProfile.getLanguage()));
371 // second run, without any input changes
372 RuleActivator ruleActivatorWithoutDescendants = new RuleActivator(system2, db.getDbClient(), typeValidations, userSession) {
374 DescendantProfilesSupplier createDescendantProfilesSupplier(DbSession dbSession) {
375 return (profiles, ruleIds) -> {
376 throw new IllegalStateException("BOOM - descendants should not be loaded");
380 changes = new BuiltInQProfileUpdateImpl(db.getDbClient(), ruleActivatorWithoutDescendants, activeRuleIndexer, qualityProfileChangeEventService)
381 .update(db.getSession(), builtIn, RulesProfileDto.from(profile));
382 assertThat(changes).isEmpty();
383 verifyNoMoreInteractions(qualityProfileChangeEventService);
387 public void propagate_deactivation_to_descendant_profiles() {
388 RuleDefinitionDto rule = db.rules().insert(r -> r.setLanguage("xoo"));
390 QProfileDto profile = db.qualityProfiles().insert(p -> p.setLanguage(rule.getLanguage()).setIsBuiltIn(true));
391 QProfileDto childProfile = createChildProfile(profile);
392 QProfileDto grandChildProfile = createChildProfile(childProfile);
394 BuiltInQualityProfilesDefinition.Context context = new BuiltInQualityProfilesDefinition.Context();
395 NewBuiltInQualityProfile newQp = context.createBuiltInQualityProfile(profile.getName(), profile.getLanguage());
396 newQp.activateRule(rule.getRepositoryKey(), rule.getRuleKey());
399 // first run to activate the rule
400 BuiltInQProfile builtIn = builtInProfileRepository.create(context.profile(profile.getLanguage(), profile.getName()), rule);
401 List<ActiveRuleChange> changes = underTest.update(db.getSession(), builtIn, RulesProfileDto.from(profile));
402 assertThat(changes).hasSize(3).extracting(ActiveRuleChange::getType).containsOnly(ActiveRuleChange.Type.ACTIVATED);
403 verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(persistedProfile.getLanguage()));
405 // second run to deactivate the rule
406 context = new BuiltInQualityProfilesDefinition.Context();
407 NewBuiltInQualityProfile updatedQp = context.createBuiltInQualityProfile(profile.getName(), profile.getLanguage());
409 builtIn = builtInProfileRepository.create(context.profile(profile.getLanguage(), profile.getName()), rule);
410 changes = underTest.update(db.getSession(), builtIn, RulesProfileDto.from(profile));
411 assertThat(changes).hasSize(3).extracting(ActiveRuleChange::getType).containsOnly(ActiveRuleChange.Type.DEACTIVATED);
412 verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(persistedProfile.getLanguage()));
414 assertThatRuleIsDeactivated(profile, rule);
415 assertThatRuleIsDeactivated(childProfile, rule);
416 assertThatRuleIsDeactivated(grandChildProfile, rule);
419 private QProfileDto createChildProfile(QProfileDto parent) {
420 return db.qualityProfiles().insert(p -> p
421 .setLanguage(parent.getLanguage())
422 .setParentKee(parent.getKee())
423 .setName("Child of " + parent.getName()))
424 .setIsBuiltIn(false);
427 private void assertThatRuleIsActivated(QProfileDto profile, RuleDefinitionDto rule, @Nullable List<ActiveRuleChange> changes,
428 String expectedSeverity, @Nullable ActiveRuleInheritance expectedInheritance, Map<String, String> expectedParams) {
429 OrgActiveRuleDto activeRule = db.getDbClient().activeRuleDao().selectByProfile(db.getSession(), profile)
431 .filter(ar -> ar.getRuleKey().equals(rule.getKey()))
433 .orElseThrow(IllegalStateException::new);
435 assertThat(activeRule.getSeverityString()).isEqualTo(expectedSeverity);
436 assertThat(activeRule.getInheritance()).isEqualTo(expectedInheritance != null ? expectedInheritance.name() : null);
438 List<ActiveRuleParamDto> params = db.getDbClient().activeRuleDao().selectParamsByActiveRuleUuid(db.getSession(), activeRule.getUuid());
439 assertThat(params).hasSize(expectedParams.size());
441 if (changes != null) {
442 ActiveRuleChange change = changes.stream()
443 .filter(c -> c.getActiveRule().getUuid().equals(activeRule.getUuid()))
444 .findFirst().orElseThrow(IllegalStateException::new);
445 assertThat(change.getInheritance()).isEqualTo(expectedInheritance);
446 assertThat(change.getSeverity()).isEqualTo(expectedSeverity);
447 assertThat(change.getType()).isEqualTo(ActiveRuleChange.Type.ACTIVATED);
451 private static void assertThatRuleHasParams(DbTester db, ActiveRuleDto activeRule, Tuple... expectedParams) {
452 assertThat(db.getDbClient().activeRuleDao().selectParamsByActiveRuleUuid(db.getSession(), activeRule.getUuid()))
453 .extracting(ActiveRuleParamDto::getKey, ActiveRuleParamDto::getValue)
454 .containsExactlyInAnyOrder(expectedParams);
457 private static void assertThatRuleIsNewlyActivated(List<ActiveRuleDto> activeRules, RuleDefinitionDto rule, RulePriority severity) {
458 ActiveRuleDto activeRule = findRule(activeRules, rule).get();
460 assertThat(activeRule.getInheritance()).isNull();
461 assertThat(activeRule.getSeverityString()).isEqualTo(severity.name());
462 assertThat(activeRule.getCreatedAt()).isEqualTo(NOW);
463 assertThat(activeRule.getUpdatedAt()).isEqualTo(NOW);
466 private static void assertThatRuleIsUpdated(List<ActiveRuleDto> activeRules, RuleDefinitionDto rule, RulePriority severity, @Nullable ActiveRuleInheritance expectedInheritance) {
467 ActiveRuleDto activeRule = findRule(activeRules, rule).get();
469 if (expectedInheritance != null) {
470 assertThat(activeRule.getInheritance()).isEqualTo(expectedInheritance.name());
472 assertThat(activeRule.getInheritance()).isNull();
474 assertThat(activeRule.getSeverityString()).isEqualTo(severity.name());
475 assertThat(activeRule.getCreatedAt()).isEqualTo(PAST);
476 assertThat(activeRule.getUpdatedAt()).isEqualTo(NOW);
479 private static void assertThatRuleIsUpdated(List<ActiveRuleDto> activeRules, RuleDefinitionDto rule, RulePriority severity) {
480 assertThatRuleIsUpdated(activeRules, rule, severity, null);
483 private static void assertThatRuleIsUpdated(ActiveRuleDto activeRules, RuleDefinitionDto rule, RulePriority severity, @Nullable ActiveRuleInheritance expectedInheritance) {
484 assertThatRuleIsUpdated(singletonList(activeRules), rule, severity, expectedInheritance);
487 private static void assertThatRuleIsUntouched(List<ActiveRuleDto> activeRules, RuleDefinitionDto rule, RulePriority severity) {
488 ActiveRuleDto activeRule = findRule(activeRules, rule).get();
490 assertThat(activeRule.getInheritance()).isNull();
491 assertThat(activeRule.getSeverityString()).isEqualTo(severity.name());
492 assertThat(activeRule.getCreatedAt()).isEqualTo(PAST);
493 assertThat(activeRule.getUpdatedAt()).isEqualTo(PAST);
496 private void assertThatRuleIsDeactivated(QProfileDto profile, RuleDefinitionDto rule) {
497 Collection<ActiveRuleDto> activeRules = db.getDbClient().activeRuleDao().selectByRulesAndRuleProfileUuids(
498 db.getSession(), singletonList(rule.getUuid()), singletonList(profile.getRulesProfileUuid()));
499 assertThat(activeRules).isEmpty();
502 private static void assertThatRuleIsDeactivated(List<ActiveRuleDto> activeRules, RuleDefinitionDto rule) {
503 assertThat(findRule(activeRules, rule)).isEmpty();
506 private void assertThatProfileIsMarkedAsUpdated(RulesProfileDto dto) {
507 RulesProfileDto reloaded = db.getDbClient().qualityProfileDao().selectBuiltInRuleProfiles(db.getSession())
509 .filter(p -> p.getUuid().equals(dto.getUuid()))
512 assertThat(reloaded.getRulesUpdatedAt()).isNotEmpty();
515 private void assertThatProfileIsNotMarkedAsUpdated(RulesProfileDto dto) {
516 RulesProfileDto reloaded = db.getDbClient().qualityProfileDao().selectBuiltInRuleProfiles(db.getSession())
518 .filter(p -> p.getUuid().equals(dto.getUuid()))
521 assertThat(reloaded.getRulesUpdatedAt()).isNull();
524 private static Optional<ActiveRuleDto> findRule(List<ActiveRuleDto> activeRules, RuleDefinitionDto rule) {
525 return activeRules.stream()
526 .filter(ar -> ar.getRuleKey().equals(rule.getKey()))
530 private ActiveRuleDto activateRuleInDb(RulesProfileDto profile, RuleDefinitionDto rule, RulePriority severity) {
531 return activateRuleInDb(profile, rule, severity, null);
534 private ActiveRuleDto activateRuleInDb(RulesProfileDto ruleProfile, RuleDefinitionDto rule, RulePriority severity, @Nullable ActiveRuleInheritance inheritance) {
535 ActiveRuleDto dto = new ActiveRuleDto()
536 .setKey(ActiveRuleKey.of(ruleProfile, RuleKey.of(rule.getRepositoryKey(), rule.getRuleKey())))
537 .setProfileUuid(ruleProfile.getUuid())
538 .setSeverity(severity.name())
539 .setRuleUuid(rule.getUuid())
540 .setInheritance(inheritance != null ? inheritance.name() : null)
543 db.getDbClient().activeRuleDao().insert(db.getSession(), dto);
548 private void activateRuleParamInDb(ActiveRuleDto activeRuleDto, RuleParamDto ruleParamDto, String value) {
549 ActiveRuleParamDto dto = new ActiveRuleParamDto()
550 .setActiveRuleUuid(activeRuleDto.getUuid())
551 .setRulesParameterUuid(ruleParamDto.getUuid())
552 .setKey(ruleParamDto.getName())
554 db.getDbClient().activeRuleDao().insertParam(db.getSession(), activeRuleDto, dto);