3 * Copyright (C) 2009-2020 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;
22 import java.util.ArrayList;
23 import java.util.List;
25 import java.util.Optional;
26 import java.util.Random;
27 import java.util.stream.IntStream;
28 import javax.annotation.Nullable;
29 import org.junit.Rule;
30 import org.junit.Test;
31 import org.junit.rules.ExpectedException;
32 import org.sonar.api.PropertyType;
33 import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
34 import org.sonar.api.rule.RuleStatus;
35 import org.sonar.api.rule.Severity;
36 import org.sonar.api.utils.System2;
37 import org.sonar.db.DbTester;
38 import org.sonar.db.qualityprofile.ActiveRuleParamDto;
39 import org.sonar.db.qualityprofile.OrgActiveRuleDto;
40 import org.sonar.db.qualityprofile.QProfileDto;
41 import org.sonar.db.rule.RuleDefinitionDto;
42 import org.sonar.db.rule.RuleDto;
43 import org.sonar.db.rule.RuleParamDto;
44 import org.sonar.server.es.EsTester;
45 import org.sonar.server.es.SearchOptions;
46 import org.sonar.server.exceptions.BadRequestException;
47 import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
48 import org.sonar.server.rule.index.RuleIndex;
49 import org.sonar.server.rule.index.RuleIndexer;
50 import org.sonar.server.rule.index.RuleQuery;
51 import org.sonar.server.tester.UserSessionRule;
52 import org.sonar.server.util.IntegerTypeValidation;
53 import org.sonar.server.util.StringTypeValidation;
54 import org.sonar.server.util.TypeValidations;
56 import static com.google.common.collect.ImmutableMap.of;
57 import static java.util.Arrays.asList;
58 import static java.util.Collections.emptyMap;
59 import static java.util.Collections.singleton;
60 import static java.util.Collections.singletonList;
61 import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
62 import static org.assertj.core.api.Assertions.assertThat;
63 import static org.junit.Assert.fail;
64 import static org.sonar.api.rule.Severity.BLOCKER;
65 import static org.sonar.api.rule.Severity.CRITICAL;
66 import static org.sonar.api.rule.Severity.MAJOR;
67 import static org.sonar.api.rule.Severity.MINOR;
68 import static org.sonar.db.rule.RuleTesting.newCustomRule;
69 import static org.sonar.server.qualityprofile.ActiveRuleInheritance.INHERITED;
71 public class QProfileRuleImplTest {
74 public ExpectedException expectedException = ExpectedException.none();
76 private System2 system2 = new AlwaysIncreasingSystem2();
78 public DbTester db = DbTester.create(system2);
80 public EsTester es = EsTester.create();
82 public UserSessionRule userSession = UserSessionRule.standalone();
83 private RuleIndex ruleIndex = new RuleIndex(es.client(), system2);
84 private ActiveRuleIndexer activeRuleIndexer = new ActiveRuleIndexer(db.getDbClient(), es.client());
85 private RuleIndexer ruleIndexer = new RuleIndexer(es.client(), db.getDbClient());
86 private TypeValidations typeValidations = new TypeValidations(asList(new StringTypeValidation(), new IntegerTypeValidation()));
88 private RuleActivator ruleActivator = new RuleActivator(system2, db.getDbClient(), typeValidations, userSession);
89 private QProfileRules underTest = new QProfileRulesImpl(db.getDbClient(), ruleActivator, ruleIndex, activeRuleIndexer);
92 public void system_activates_rule_without_parameters() {
93 RuleDefinitionDto rule = createRule();
94 QProfileDto profile = createProfile(rule);
95 RuleActivation activation = RuleActivation.create(rule.getUuid(), BLOCKER, null);
96 List<ActiveRuleChange> changes = activate(profile, activation);
98 assertThatRuleIsActivated(profile, rule, changes, BLOCKER, null, emptyMap());
99 assertThatProfileIsUpdatedBySystem(profile);
103 public void user_activates_rule_without_parameters() {
105 RuleDefinitionDto rule = createRule();
106 QProfileDto profile = createProfile(rule);
107 RuleActivation activation = RuleActivation.create(rule.getUuid(), BLOCKER, null);
108 List<ActiveRuleChange> changes = activate(profile, activation);
110 assertThatRuleIsActivated(profile, rule, changes, BLOCKER, null, emptyMap());
111 assertThatProfileIsUpdatedByUser(profile);
115 public void activate_rule_with_default_severity_and_parameters() {
116 RuleDefinitionDto rule = createRule();
117 RuleParamDto ruleParam = db.rules().insertRuleParam(rule, p -> p.setName("min").setDefaultValue("10"));
118 QProfileDto profile = createProfile(rule);
120 RuleActivation activation = RuleActivation.create(rule.getUuid());
121 List<ActiveRuleChange> changes = activate(profile, activation);
123 assertThatRuleIsActivated(profile, rule, changes, rule.getSeverityString(), null, of("min", "10"));
124 assertThatProfileIsUpdatedBySystem(profile);
128 public void activate_rule_with_parameters() {
129 RuleDefinitionDto rule = createRule();
130 RuleParamDto ruleParam = db.rules().insertRuleParam(rule, p -> p.setName("min").setDefaultValue("10"));
131 QProfileDto profile = createProfile(rule);
133 RuleActivation activation = RuleActivation.create(rule.getUuid(), null, of(ruleParam.getName(), "15"));
134 List<ActiveRuleChange> changes = activate(profile, activation);
136 assertThatRuleIsActivated(profile, rule, changes, rule.getSeverityString(), null, of("min", "15"));
137 assertThatProfileIsUpdatedBySystem(profile);
141 public void activate_rule_with_default_severity() {
142 RuleDefinitionDto rule = createRule();
143 QProfileDto profile = createProfile(rule);
145 RuleActivation activation = RuleActivation.create(rule.getUuid());
146 List<ActiveRuleChange> changes = activate(profile, activation);
148 assertThatRuleIsActivated(profile, rule, changes, rule.getSeverityString(), null, emptyMap());
149 assertThatProfileIsUpdatedBySystem(profile);
156 public void activate_rule_with_empty_parameter_having_no_default_value() {
157 RuleDefinitionDto rule = createRule();
158 RuleParamDto ruleParam = db.rules().insertRuleParam(rule, p -> p.setName("min").setDefaultValue("10"));
159 QProfileDto profile = createProfile(rule);
161 RuleActivation activation = RuleActivation.create(rule.getUuid(), null, of("min", ""));
162 List<ActiveRuleChange> changes = activate(profile, activation);
164 assertThatRuleIsActivated(profile, rule, changes, rule.getSeverityString(), null, of("min", "10"));
165 assertThatProfileIsUpdatedBySystem(profile);
173 public void activate_rule_with_negative_integer_value_on_parameter_having_no_default_value() {
174 RuleDefinitionDto rule = createRule();
175 RuleParamDto paramWithoutDefault = db.rules().insertRuleParam(rule, p -> p.setName("min").setDefaultValue(null));
176 RuleParamDto paramWithDefault = db.rules().insertRuleParam(rule, p -> p.setName("max").setDefaultValue("10"));
177 QProfileDto profile = createProfile(rule);
179 RuleActivation activation = RuleActivation.create(rule.getUuid(), null, of(paramWithoutDefault.getName(), "-10"));
180 List<ActiveRuleChange> changes = activate(profile, activation);
182 assertThatRuleIsActivated(profile, rule, changes, rule.getSeverityString(), null,
183 of(paramWithoutDefault.getName(), "-10", paramWithDefault.getName(), paramWithDefault.getDefaultValue()));
184 assertThatProfileIsUpdatedBySystem(profile);
188 public void activation_ignores_unsupported_parameters() {
189 RuleDefinitionDto rule = createRule();
190 RuleParamDto param = db.rules().insertRuleParam(rule, p -> p.setName("max").setDefaultValue("10"));
191 QProfileDto profile = createProfile(rule);
193 RuleActivation activation = RuleActivation.create(rule.getUuid(), null, of("xxx", "yyy"));
194 List<ActiveRuleChange> changes = activate(profile, activation);
196 assertThatRuleIsActivated(profile, rule, changes, rule.getSeverityString(), null, of(param.getName(), param.getDefaultValue()));
197 assertThatProfileIsUpdatedBySystem(profile);
201 public void update_an_already_activated_rule() {
202 RuleDefinitionDto rule = createRule();
203 RuleParamDto param = db.rules().insertRuleParam(rule, p -> p.setName("max").setDefaultValue("10"));
204 QProfileDto profile = createProfile(rule);
206 // initial activation
207 RuleActivation activation = RuleActivation.create(rule.getUuid(), MAJOR, null);
208 activate(profile, activation);
211 RuleActivation updateActivation = RuleActivation.create(rule.getUuid(), CRITICAL, of(param.getName(), "20"));
212 List<ActiveRuleChange> changes = activate(profile, updateActivation);
214 assertThatRuleIsUpdated(profile, rule, CRITICAL, null, of(param.getName(), "20"));
215 assertThatProfileIsUpdatedBySystem(profile);
219 public void update_activation_with_parameter_without_default_value() {
220 RuleDefinitionDto rule = createRule();
221 RuleParamDto paramWithoutDefault = db.rules().insertRuleParam(rule, p -> p.setName("min").setDefaultValue(null));
222 RuleParamDto paramWithDefault = db.rules().insertRuleParam(rule, p -> p.setName("max").setDefaultValue("10"));
223 QProfileDto profile = createProfile(rule);
225 // initial activation -> param "max" has a default value
226 RuleActivation activation = RuleActivation.create(rule.getUuid());
227 activate(profile, activation);
229 // update param "min", which has no default value
230 RuleActivation updateActivation = RuleActivation.create(rule.getUuid(), MAJOR, of(paramWithoutDefault.getName(), "3"));
231 List<ActiveRuleChange> changes = activate(profile, updateActivation);
233 assertThatRuleIsUpdated(profile, rule, MAJOR, null, of(paramWithDefault.getName(), "10", paramWithoutDefault.getName(), "3"));
234 assertThatProfileIsUpdatedBySystem(profile);
238 public void reset_parameter_to_default_value() {
239 RuleDefinitionDto rule = createRule();
240 RuleParamDto paramWithDefault = db.rules().insertRuleParam(rule, p -> p.setName("max").setDefaultValue("10"));
241 QProfileDto profile = createProfile(rule);
243 // initial activation -> param "max" has a default value
244 RuleActivation activation = RuleActivation.create(rule.getUuid(), null, of(paramWithDefault.getName(), "20"));
245 activate(profile, activation);
247 // reset to default_value
248 RuleActivation updateActivation = RuleActivation.create(rule.getUuid(), null, of(paramWithDefault.getName(), ""));
249 List<ActiveRuleChange> changes = activate(profile, updateActivation);
251 assertThatRuleIsUpdated(profile, rule, rule.getSeverityString(), null, of(paramWithDefault.getName(), "10"));
252 assertThat(changes).hasSize(1);
256 public void update_activation_removes_parameter_without_default_value() {
257 RuleDefinitionDto rule = createRule();
258 RuleParamDto paramWithoutDefault = db.rules().insertRuleParam(rule, p -> p.setName("min").setDefaultValue(null));
259 RuleParamDto paramWithDefault = db.rules().insertRuleParam(rule, p -> p.setName("max").setDefaultValue("10"));
260 QProfileDto profile = createProfile(rule);
262 // initial activation -> param "max" has a default value
263 RuleActivation activation = RuleActivation.create(rule.getUuid(), null, of(paramWithoutDefault.getName(), "20"));
264 activate(profile, activation);
267 RuleActivation updateActivation = RuleActivation.create(rule.getUuid(), null, of(paramWithoutDefault.getName(), ""));
268 List<ActiveRuleChange> changes = activate(profile, updateActivation);
270 assertThatRuleIsUpdated(profile, rule, rule.getSeverityString(), null, of(paramWithDefault.getName(), paramWithDefault.getDefaultValue()));
271 assertThat(changes).hasSize(1);
275 public void update_activation_with_new_parameter() {
276 RuleDefinitionDto rule = createRule();
277 RuleParamDto param = db.rules().insertRuleParam(rule, p -> p.setName("max").setDefaultValue("10"));
278 QProfileDto profile = createProfile(rule);
280 // initial activation -> param "max" has a default value
281 RuleActivation activation = RuleActivation.create(rule.getUuid());
282 List<ActiveRuleChange> changes = activate(profile, activation);
283 db.getDbClient().activeRuleDao().deleteParametersByRuleProfileUuids(db.getSession(), asList(profile.getRulesProfileUuid()));
284 assertThatRuleIsActivated(profile, rule, changes, rule.getSeverityString(), null, emptyMap());
286 // contrary to activerule, the param is supposed to be inserted but not updated
287 RuleActivation updateActivation = RuleActivation.create(rule.getUuid(), null, of(param.getName(), ""));
288 changes = activate(profile, updateActivation);
290 assertThatRuleIsUpdated(profile, rule, rule.getSeverityString(), null, of(param.getName(), param.getDefaultValue()));
291 assertThat(changes).hasSize(1);
295 public void ignore_activation_without_changes() {
296 RuleDefinitionDto rule = createRule();
297 QProfileDto profile = createProfile(rule);
299 // initial activation
300 RuleActivation activation = RuleActivation.create(rule.getUuid());
301 activate(profile, activation);
303 // update with exactly the same severity and params
304 activation = RuleActivation.create(rule.getUuid());
305 List<ActiveRuleChange> changes = activate(profile, activation);
307 assertThat(changes).isEmpty();
311 public void do_not_change_severity_and_params_if_unset_and_already_activated() {
312 RuleDefinitionDto rule = createRule();
313 RuleParamDto param = db.rules().insertRuleParam(rule, p -> p.setName("max").setDefaultValue("10"));
314 QProfileDto profile = createProfile(rule);
316 // initial activation -> param "max" has a default value
317 RuleActivation activation = RuleActivation.create(rule.getUuid(), BLOCKER, of(param.getName(), "20"));
318 activate(profile, activation);
320 // update without any severity or params => keep
321 RuleActivation update = RuleActivation.create(rule.getUuid());
322 List<ActiveRuleChange> changes = activate(profile, update);
324 assertThat(changes).isEmpty();
328 public void fail_to_activate_rule_if_profile_is_on_different_languages() {
329 RuleDefinitionDto rule = createJavaRule();
330 QProfileDto profile = db.qualityProfiles().insert(p -> p.setLanguage("js"));
331 RuleActivation activation = RuleActivation.create(rule.getUuid());
333 expectFailure("java rule " + rule.getKey() + " cannot be activated on js profile " + profile.getKee(), () -> activate(profile, activation));
337 public void fail_to_activate_rule_if_rule_has_REMOVED_status() {
338 RuleDefinitionDto rule = db.rules().insert(r -> r.setStatus(RuleStatus.REMOVED));
339 QProfileDto profile = createProfile(rule);
340 RuleActivation activation = RuleActivation.create(rule.getUuid());
342 expectFailure("Rule was removed: " + rule.getKey(), () -> activate(profile, activation));
346 public void fail_to_activate_if_template() {
347 RuleDefinitionDto rule = db.rules().insert(r -> r.setIsTemplate(true));
348 QProfileDto profile = createProfile(rule);
349 RuleActivation activation = RuleActivation.create(rule.getUuid());
351 expectFailure("Rule template can't be activated on a Quality profile: " + rule.getKey(), () -> activate(profile, activation));
355 public void fail_to_activate_if_invalid_parameter() {
356 RuleDefinitionDto rule = createRule();
357 RuleParamDto param = db.rules().insertRuleParam(rule, p -> p.setName("max").setDefaultValue("10").setType(PropertyType.INTEGER.name()));
358 QProfileDto profile = createProfile(rule);
360 RuleActivation activation = RuleActivation.create(rule.getUuid(), null, of(param.getName(), "foo"));
361 expectFailure("Value 'foo' must be an integer.", () -> activate(profile, activation));
365 public void ignore_parameters_when_activating_custom_rule() {
366 RuleDefinitionDto templateRule = db.rules().insert(r -> r.setIsTemplate(true));
367 RuleParamDto templateParam = db.rules().insertRuleParam(templateRule, p -> p.setName("format"));
368 RuleDefinitionDto customRule = db.rules().insert(newCustomRule(templateRule));
369 RuleParamDto customParam = db.rules().insertRuleParam(customRule, p -> p.setName("format").setDefaultValue("txt"));
370 QProfileDto profile = createProfile(customRule);
372 // initial activation
373 RuleActivation activation = RuleActivation.create(customRule.getUuid(), MAJOR, emptyMap());
374 activate(profile, activation);
375 assertThatRuleIsActivated(profile, customRule, null, MAJOR, null, of("format", "txt"));
377 // update -> parameter is not changed
378 RuleActivation updateActivation = RuleActivation.create(customRule.getUuid(), BLOCKER, of("format", "xml"));
379 activate(profile, updateActivation);
380 assertThatRuleIsActivated(profile, customRule, null, BLOCKER, null, of("format", "txt"));
384 public void user_deactivates_a_rule() {
386 RuleDefinitionDto rule = createRule();
387 QProfileDto profile = createProfile(rule);
388 RuleActivation activation = RuleActivation.create(rule.getUuid());
389 activate(profile, activation);
391 List<ActiveRuleChange> changes = deactivate(profile, rule);
392 verifyNoActiveRules();
393 assertThatProfileIsUpdatedByUser(profile);
394 assertThat(changes).hasSize(1);
395 assertThat(changes.get(0).getType()).isEqualTo(ActiveRuleChange.Type.DEACTIVATED);
399 public void system_deactivates_a_rule() {
400 RuleDefinitionDto rule = createRule();
401 QProfileDto profile = createProfile(rule);
402 RuleActivation activation = RuleActivation.create(rule.getUuid());
403 activate(profile, activation);
405 List<ActiveRuleChange> changes = deactivate(profile, rule);
406 verifyNoActiveRules();
407 assertThatProfileIsUpdatedBySystem(profile);
408 assertThatChangeIsDeactivation(changes, rule);
411 private void assertThatChangeIsDeactivation(List<ActiveRuleChange> changes, RuleDefinitionDto rule) {
412 assertThat(changes).hasSize(1);
413 ActiveRuleChange change = changes.get(0);
414 assertThat(change.getType()).isEqualTo(ActiveRuleChange.Type.DEACTIVATED);
415 assertThat(change.getKey().getRuleKey()).isEqualTo(rule.getKey());
419 public void ignore_deactivation_if_rule_is_not_activated() {
420 RuleDefinitionDto rule = createRule();
421 QProfileDto profile = createProfile(rule);
423 List<ActiveRuleChange> changes = deactivate(profile, rule);
424 verifyNoActiveRules();
425 assertThat(changes).hasSize(0);
429 public void deactivate_rule_that_has_REMOVED_status() {
430 RuleDefinitionDto rule = createRule();
431 QProfileDto profile = createProfile(rule);
432 RuleActivation activation = RuleActivation.create(rule.getUuid());
433 activate(profile, activation);
435 rule.setStatus(RuleStatus.REMOVED);
436 db.getDbClient().ruleDao().update(db.getSession(), rule);
438 List<ActiveRuleChange> changes = deactivate(profile, rule);
439 verifyNoActiveRules();
440 assertThatChangeIsDeactivation(changes, rule);
444 public void activation_on_child_profile_is_propagated_to_descendants() {
445 RuleDefinitionDto rule = createRule();
446 QProfileDto parentProfile = createProfile(rule);
447 QProfileDto childProfile = createChildProfile(parentProfile);
448 QProfileDto grandChildProfile = createChildProfile(childProfile);
450 List<ActiveRuleChange> changes = activate(childProfile, RuleActivation.create(rule.getUuid()));
451 assertThatProfileHasNoActiveRules(parentProfile);
452 assertThatRuleIsActivated(childProfile, rule, changes, rule.getSeverityString(), null, emptyMap());
453 assertThatRuleIsActivated(grandChildProfile, rule, changes, rule.getSeverityString(), INHERITED, emptyMap());
457 public void update_on_child_profile_is_propagated_to_descendants() {
458 RuleDefinitionDto rule = createRule();
459 RuleParamDto param = db.rules().insertRuleParam(rule);
460 QProfileDto parentProfile = createProfile(rule);
461 QProfileDto childProfile = createChildProfile(parentProfile);
462 QProfileDto grandChildProfile = createChildProfile(childProfile);
464 System.out.println("ACTIVATE ON " + childProfile.getName());
465 RuleActivation initialActivation = RuleActivation.create(rule.getUuid(), MAJOR, of(param.getName(), "foo"));
466 activate(childProfile, initialActivation);
468 System.out.println("---------------");
469 System.out.println("ACTIVATE ON " + childProfile.getName());
470 RuleActivation updateActivation = RuleActivation.create(rule.getUuid(), CRITICAL, of(param.getName(), "bar"));
471 List<ActiveRuleChange> changes = activate(childProfile, updateActivation);
473 assertThatProfileHasNoActiveRules(parentProfile);
474 assertThatRuleIsUpdated(childProfile, rule, CRITICAL, null, of(param.getName(), "bar"));
475 assertThatRuleIsUpdated(grandChildProfile, rule, CRITICAL, INHERITED, of(param.getName(), "bar"));
476 assertThat(changes).hasSize(2);
480 public void override_activation_of_inherited_profile() {
481 RuleDefinitionDto rule = createRule();
482 RuleParamDto param = db.rules().insertRuleParam(rule);
483 QProfileDto parentProfile = createProfile(rule);
484 QProfileDto childProfile = createChildProfile(parentProfile);
485 QProfileDto grandChildProfile = createChildProfile(childProfile);
487 RuleActivation initialActivation = RuleActivation.create(rule.getUuid(), MAJOR, of(param.getName(), "foo"));
488 activate(childProfile, initialActivation);
490 RuleActivation overrideActivation = RuleActivation.create(rule.getUuid(), CRITICAL, of(param.getName(), "bar"));
491 List<ActiveRuleChange> changes = activate(grandChildProfile, overrideActivation);
493 assertThatProfileHasNoActiveRules(parentProfile);
494 assertThatRuleIsUpdated(childProfile, rule, MAJOR, null, of(param.getName(), "foo"));
495 assertThatRuleIsUpdated(grandChildProfile, rule, CRITICAL, ActiveRuleInheritance.OVERRIDES, of(param.getName(), "bar"));
496 assertThat(changes).hasSize(1);
500 public void updated_activation_on_parent_is_not_propagated_to_overridden_profiles() {
501 RuleDefinitionDto rule = createRule();
502 RuleParamDto param = db.rules().insertRuleParam(rule);
503 QProfileDto parentProfile = createProfile(rule);
504 QProfileDto childProfile = createChildProfile(parentProfile);
505 QProfileDto grandChildProfile = createChildProfile(childProfile);
507 RuleActivation initialActivation = RuleActivation.create(rule.getUuid(), MAJOR, of(param.getName(), "foo"));
508 activate(childProfile, initialActivation);
510 RuleActivation overrideActivation = RuleActivation.create(rule.getUuid(), CRITICAL, of(param.getName(), "bar"));
511 activate(grandChildProfile, overrideActivation);
513 // update child --> do not touch grandChild
514 RuleActivation updateActivation = RuleActivation.create(rule.getUuid(), BLOCKER, of(param.getName(), "baz"));
515 List<ActiveRuleChange> changes = activate(childProfile, updateActivation);
517 assertThatProfileHasNoActiveRules(parentProfile);
518 assertThatRuleIsUpdated(childProfile, rule, BLOCKER, null, of(param.getName(), "baz"));
519 assertThatRuleIsUpdated(grandChildProfile, rule, CRITICAL, ActiveRuleInheritance.OVERRIDES, of(param.getName(), "bar"));
520 assertThat(changes).hasSize(1);
524 public void reset_on_parent_is_not_propagated_to_overridden_profiles() {
525 RuleDefinitionDto rule = createRule();
526 RuleParamDto param = db.rules().insertRuleParam(rule);
527 QProfileDto parentProfile = createProfile(rule);
528 QProfileDto childProfile = createChildProfile(parentProfile);
529 QProfileDto grandChildProfile = createChildProfile(childProfile);
531 RuleActivation initialActivation = RuleActivation.create(rule.getUuid(), MAJOR, of(param.getName(), "foo"));
532 activate(parentProfile, initialActivation);
534 RuleActivation overrideActivation = RuleActivation.create(rule.getUuid(), CRITICAL, of(param.getName(), "bar"));
535 activate(grandChildProfile, overrideActivation);
537 // reset parent --> touch child but not grandChild
538 RuleActivation updateActivation = RuleActivation.createReset(rule.getUuid());
539 List<ActiveRuleChange> changes = activate(parentProfile, updateActivation);
541 assertThatRuleIsUpdated(parentProfile, rule, rule.getSeverityString(), null, of(param.getName(), param.getDefaultValue()));
542 assertThatRuleIsUpdated(childProfile, rule, rule.getSeverityString(), INHERITED, of(param.getName(), param.getDefaultValue()));
543 assertThatRuleIsUpdated(grandChildProfile, rule, CRITICAL, ActiveRuleInheritance.OVERRIDES, of(param.getName(), "bar"));
544 assertThat(changes).hasSize(2);
548 public void active_on_parent_a_rule_already_activated_on_child() {
549 RuleDefinitionDto rule = createRule();
550 RuleParamDto param = db.rules().insertRuleParam(rule);
551 QProfileDto parentProfile = createProfile(rule);
552 QProfileDto childProfile = createChildProfile(parentProfile);
554 RuleActivation childActivation = RuleActivation.create(rule.getUuid(), MAJOR, of(param.getName(), "foo"));
555 activate(childProfile, childActivation);
557 RuleActivation parentActivation = RuleActivation.create(rule.getUuid(), CRITICAL, of(param.getName(), "bar"));
558 List<ActiveRuleChange> changes = activate(parentProfile, parentActivation);
560 assertThatRuleIsUpdated(parentProfile, rule, CRITICAL, null, of(param.getName(), "bar"));
561 assertThatRuleIsUpdated(childProfile, rule, MAJOR, ActiveRuleInheritance.OVERRIDES, of(param.getName(), "foo"));
562 assertThat(changes).hasSize(2);
566 public void do_not_mark_as_overridden_if_same_values_than_parent() {
567 RuleDefinitionDto rule = createRule();
568 RuleParamDto param = db.rules().insertRuleParam(rule);
569 QProfileDto parentProfile = createProfile(rule);
570 QProfileDto childProfile = createChildProfile(parentProfile);
572 RuleActivation parentActivation = RuleActivation.create(rule.getUuid(), MAJOR, of(param.getName(), "foo"));
573 activate(parentProfile, parentActivation);
575 RuleActivation overrideActivation = RuleActivation.create(rule.getUuid(), MAJOR, of(param.getName(), "foo"));
576 List<ActiveRuleChange> changes = activate(childProfile, overrideActivation);
578 assertThatRuleIsUpdated(childProfile, rule, MAJOR, INHERITED, of(param.getName(), "foo"));
579 assertThat(changes).hasSize(0);
583 public void propagate_deactivation_on_children() {
584 RuleDefinitionDto rule = createRule();
585 QProfileDto parentProfile = createProfile(rule);
586 QProfileDto childProfile = createChildProfile(parentProfile);
588 RuleActivation activation = RuleActivation.create(rule.getUuid());
589 List<ActiveRuleChange> changes = activate(parentProfile, activation);
590 assertThatRuleIsActivated(parentProfile, rule, changes, rule.getSeverityString(), null, emptyMap());
591 assertThatRuleIsActivated(childProfile, rule, changes, rule.getSeverityString(), INHERITED, emptyMap());
593 changes = deactivate(parentProfile, rule);
594 assertThatProfileHasNoActiveRules(parentProfile);
595 assertThatProfileHasNoActiveRules(childProfile);
596 assertThat(changes).hasSize(2);
600 public void propagate_deactivation_on_children_even_when_overridden() {
601 RuleDefinitionDto rule = createRule();
602 QProfileDto parentProfile = createProfile(rule);
603 QProfileDto childProfile = createChildProfile(parentProfile);
605 RuleActivation activation = RuleActivation.create(rule.getUuid());
606 List<ActiveRuleChange> changes = activate(parentProfile, activation);
607 assertThatRuleIsActivated(parentProfile, rule, changes, rule.getSeverityString(), null, emptyMap());
608 assertThatRuleIsActivated(childProfile, rule, changes, rule.getSeverityString(), INHERITED, emptyMap());
610 activation = RuleActivation.create(rule.getUuid(), CRITICAL, null);
611 activate(childProfile, activation);
613 changes = deactivate(parentProfile, rule);
614 assertThatProfileHasNoActiveRules(parentProfile);
615 assertThatProfileHasNoActiveRules(childProfile);
616 assertThat(changes).hasSize(2);
620 public void cannot_deactivate_rule_inherited() {
621 RuleDefinitionDto rule = createRule();
622 QProfileDto parentProfile = createProfile(rule);
623 QProfileDto childProfile = createChildProfile(parentProfile);
625 RuleActivation activation = RuleActivation.create(rule.getUuid());
626 List<ActiveRuleChange> changes = activate(parentProfile, activation);
627 assertThatRuleIsActivated(parentProfile, rule, changes, rule.getSeverityString(), null, emptyMap());
628 assertThatRuleIsActivated(childProfile, rule, changes, rule.getSeverityString(), INHERITED, emptyMap());
630 expectedException.expect(BadRequestException.class);
631 expectedException.expectMessage("Cannot deactivate inherited rule");
632 deactivate(childProfile, rule);
636 public void reset_child_profile_do_not_change_parent() {
637 RuleDefinitionDto rule = createRule();
638 QProfileDto parentProfile = createProfile(rule);
639 QProfileDto childProfile = createChildProfile(parentProfile);
641 RuleActivation activation = RuleActivation.create(rule.getUuid(), CRITICAL, null);
642 List<ActiveRuleChange> changes = activate(parentProfile, activation);
643 assertThatRuleIsActivated(parentProfile, rule, changes, CRITICAL, null, emptyMap());
644 assertThatRuleIsActivated(childProfile, rule, changes, CRITICAL, INHERITED, emptyMap());
645 assertThat(changes).hasSize(2);
647 RuleActivation childActivation = RuleActivation.create(rule.getUuid(), BLOCKER, null);
648 changes = activate(childProfile, childActivation);
649 assertThatRuleIsUpdated(childProfile, rule, BLOCKER, ActiveRuleInheritance.OVERRIDES, emptyMap());
650 assertThat(changes).hasSize(1);
652 RuleActivation resetActivation = RuleActivation.createReset(rule.getUuid());
653 changes = activate(childProfile, resetActivation);
654 assertThatRuleIsUpdated(childProfile, rule, CRITICAL, INHERITED, emptyMap());
655 assertThatRuleIsUpdated(parentProfile, rule, CRITICAL, null, emptyMap());
656 assertThat(changes).hasSize(1);
660 public void reset_parent_is_not_propagated_when_child_overrides() {
661 RuleDefinitionDto rule = createRule();
662 QProfileDto baseProfile = createProfile(rule);
663 QProfileDto childProfile = createChildProfile(baseProfile);
664 QProfileDto grandChildProfile = createChildProfile(childProfile);
666 RuleActivation activation = RuleActivation.create(rule.getUuid(), CRITICAL, null);
667 List<ActiveRuleChange> changes = activate(baseProfile, activation);
668 assertThatRuleIsActivated(baseProfile, rule, changes, CRITICAL, null, emptyMap());
669 assertThatRuleIsActivated(childProfile, rule, changes, CRITICAL, INHERITED, emptyMap());
670 assertThatRuleIsActivated(grandChildProfile, rule, changes, CRITICAL, INHERITED, emptyMap());
671 assertThat(changes).hasSize(3);
673 RuleActivation childActivation = RuleActivation.create(rule.getUuid(), BLOCKER, null);
674 changes = activate(childProfile, childActivation);
675 assertThatRuleIsUpdated(childProfile, rule, BLOCKER, ActiveRuleInheritance.OVERRIDES, emptyMap());
676 assertThatRuleIsUpdated(grandChildProfile, rule, BLOCKER, INHERITED, emptyMap());
677 assertThat(changes).hasSize(2);
679 // Reset on parent do not change child nor grandchild
680 RuleActivation resetActivation = RuleActivation.createReset(rule.getUuid());
681 changes = activate(baseProfile, resetActivation);
682 assertThatRuleIsUpdated(baseProfile, rule, rule.getSeverityString(), null, emptyMap());
683 assertThatRuleIsUpdated(childProfile, rule, BLOCKER, ActiveRuleInheritance.OVERRIDES, emptyMap());
684 assertThatRuleIsUpdated(grandChildProfile, rule, BLOCKER, INHERITED, emptyMap());
685 assertThat(changes).hasSize(1);
687 // Reset on child change grandchild
688 resetActivation = RuleActivation.createReset(rule.getUuid());
689 changes = activate(childProfile, resetActivation);
690 assertThatRuleIsUpdated(baseProfile, rule, rule.getSeverityString(), null, emptyMap());
691 assertThatRuleIsUpdated(childProfile, rule, rule.getSeverityString(), INHERITED, emptyMap());
692 assertThatRuleIsUpdated(grandChildProfile, rule, rule.getSeverityString(), INHERITED, emptyMap());
693 assertThat(changes).hasSize(2);
697 public void ignore_reset_if_not_activated() {
698 RuleDefinitionDto rule = createRule();
699 QProfileDto parentProfile = createProfile(rule);
700 createChildProfile(parentProfile);
702 RuleActivation resetActivation = RuleActivation.createReset(rule.getUuid());
703 List<ActiveRuleChange> changes = activate(parentProfile, resetActivation);
704 verifyNoActiveRules();
705 assertThat(changes).hasSize(0);
709 public void bulk_activation() {
710 int bulkSize = SearchOptions.MAX_PAGE_SIZE + 10 + new Random().nextInt(100);
711 String language = randomAlphanumeric(10);
712 String repositoryKey = randomAlphanumeric(10);
713 QProfileDto profile = db.qualityProfiles().insert(p -> p.setLanguage(language));
715 List<RuleDto> rules = new ArrayList<>();
716 IntStream.rangeClosed(1, bulkSize).forEach(
717 i -> rules.add(db.rules().insertRule(r -> r.setLanguage(language).setRepositoryKey(repositoryKey))));
719 verifyNoActiveRules();
720 ruleIndexer.indexOnStartup(ruleIndexer.getIndexTypes());
722 RuleQuery ruleQuery = new RuleQuery()
723 .setRepositories(singletonList(repositoryKey));
725 BulkChangeResult bulkChangeResult = underTest.bulkActivateAndCommit(db.getSession(), profile, ruleQuery, MINOR);
727 assertThat(bulkChangeResult.countFailed()).isEqualTo(0);
728 assertThat(bulkChangeResult.countSucceeded()).isEqualTo(bulkSize);
729 assertThat(bulkChangeResult.getChanges()).hasSize(bulkSize);
730 assertThat(db.getDbClient().activeRuleDao().selectByProfile(db.getSession(), profile)).hasSize(bulkSize);
731 rules.stream().forEach(
732 r -> assertThatRuleIsActivated(profile, r.getDefinition(), null, MINOR, null, emptyMap()));
736 public void bulk_deactivation() {
737 int bulkSize = SearchOptions.MAX_PAGE_SIZE + 10 + new Random().nextInt(100);
738 String language = randomAlphanumeric(10);
739 String repositoryKey = randomAlphanumeric(10);
740 QProfileDto profile = db.qualityProfiles().insert(p -> p.setLanguage(language));
742 List<RuleDto> rules = new ArrayList<>();
743 IntStream.rangeClosed(1, bulkSize).forEach(
744 i -> rules.add(db.rules().insertRule(r -> r.setLanguage(language).setRepositoryKey(repositoryKey))));
746 verifyNoActiveRules();
747 ruleIndexer.indexOnStartup(ruleIndexer.getIndexTypes());
749 RuleQuery ruleQuery = new RuleQuery()
750 .setRepositories(singletonList(repositoryKey));
752 BulkChangeResult bulkChangeResult = underTest.bulkActivateAndCommit(db.getSession(), profile, ruleQuery, MINOR);
754 assertThat(bulkChangeResult.countFailed()).isEqualTo(0);
755 assertThat(bulkChangeResult.countSucceeded()).isEqualTo(bulkSize);
756 assertThat(bulkChangeResult.getChanges()).hasSize(bulkSize);
757 assertThat(db.getDbClient().activeRuleDao().selectByProfile(db.getSession(), profile)).hasSize(bulkSize);
759 // Now deactivate all rules
760 bulkChangeResult = underTest.bulkDeactivateAndCommit(db.getSession(), profile, ruleQuery);
762 assertThat(bulkChangeResult.countFailed()).isEqualTo(0);
763 assertThat(bulkChangeResult.countSucceeded()).isEqualTo(bulkSize);
764 assertThat(bulkChangeResult.getChanges()).hasSize(bulkSize);
765 assertThat(db.getDbClient().activeRuleDao().selectByProfile(db.getSession(), profile)).hasSize(0);
766 rules.stream().forEach(
767 r -> assertThatRuleIsNotPresent(profile, r.getDefinition()));
771 public void bulk_deactivation_ignores_errors() {
772 RuleDefinitionDto rule = createRule();
773 QProfileDto parentProfile = createProfile(rule);
774 QProfileDto childProfile = createChildProfile(parentProfile);
776 List<ActiveRuleChange> changes = activate(parentProfile, RuleActivation.create(rule.getUuid()));
777 assertThatRuleIsActivated(parentProfile, rule, null, rule.getSeverityString(), null, emptyMap());
778 assertThatRuleIsActivated(childProfile, rule, null, rule.getSeverityString(), INHERITED, emptyMap());
780 ruleIndexer.indexOnStartup(ruleIndexer.getIndexTypes());
782 RuleQuery ruleQuery = new RuleQuery()
783 .setQProfile(childProfile);
784 BulkChangeResult bulkChangeResult = underTest.bulkDeactivateAndCommit(db.getSession(), childProfile, ruleQuery);
786 assertThat(bulkChangeResult.countFailed()).isEqualTo(1);
787 assertThat(bulkChangeResult.countSucceeded()).isEqualTo(0);
788 assertThat(bulkChangeResult.getChanges()).hasSize(0);
789 assertThatRuleIsActivated(parentProfile, rule, null, rule.getSeverityString(), null, emptyMap());
790 assertThatRuleIsActivated(childProfile, rule, null, rule.getSeverityString(), INHERITED, emptyMap());
794 public void bulk_change_severity() {
795 RuleDefinitionDto rule1 = createJavaRule();
796 RuleDefinitionDto rule2 = createJavaRule();
797 QProfileDto parentProfile = createProfile(rule1);
798 QProfileDto childProfile = createChildProfile(parentProfile);
799 QProfileDto grandchildProfile = createChildProfile(childProfile);
801 activate(parentProfile, RuleActivation.create(rule1.getUuid()));
802 activate(parentProfile, RuleActivation.create(rule2.getUuid()));
804 ruleIndexer.indexOnStartup(ruleIndexer.getIndexTypes());
806 RuleQuery query = new RuleQuery()
807 .setRuleKey(rule1.getRuleKey())
808 .setQProfile(parentProfile);
809 BulkChangeResult result = underTest.bulkActivateAndCommit(db.getSession(), parentProfile, query, "BLOCKER");
811 assertThat(result.getChanges()).hasSize(3);
812 assertThat(result.countSucceeded()).isEqualTo(1);
813 assertThat(result.countFailed()).isEqualTo(0);
815 // Rule1 must be activated with BLOCKER on all profiles
816 assertThatRuleIsActivated(parentProfile, rule1, null, BLOCKER, null, emptyMap());
817 assertThatRuleIsActivated(childProfile, rule1, null, BLOCKER, INHERITED, emptyMap());
818 assertThatRuleIsActivated(grandchildProfile, rule1, null, BLOCKER, INHERITED, emptyMap());
820 // Rule2 did not changed
821 assertThatRuleIsActivated(parentProfile, rule2, null, rule2.getSeverityString(), null, emptyMap());
822 assertThatRuleIsActivated(childProfile, rule2, null, rule2.getSeverityString(), INHERITED, emptyMap());
823 assertThatRuleIsActivated(grandchildProfile, rule2, null, rule2.getSeverityString(), INHERITED, emptyMap());
827 public void delete_rule_from_all_profiles() {
828 RuleDefinitionDto rule = createRule();
829 QProfileDto parentProfile = createProfile(rule);
830 QProfileDto childProfile = createChildProfile(parentProfile);
831 QProfileDto grandChildProfile = createChildProfile(childProfile);
833 RuleActivation activation = RuleActivation.create(rule.getUuid(), CRITICAL, null);
834 activate(parentProfile, activation);
836 RuleActivation overrideActivation = RuleActivation.create(rule.getUuid(), BLOCKER, null);
837 activate(grandChildProfile, overrideActivation);
839 // Reset on parent do not change child nor grandchild
840 List<ActiveRuleChange> changes = underTest.deleteRule(db.getSession(), rule);
842 assertThatRuleIsNotPresent(parentProfile, rule);
843 assertThatRuleIsNotPresent(childProfile, rule);
844 assertThatRuleIsNotPresent(grandChildProfile, rule);
846 .extracting(ActiveRuleChange::getType)
847 .containsOnly(ActiveRuleChange.Type.DEACTIVATED)
852 public void activation_fails_when_profile_is_built_in() {
853 RuleDefinitionDto rule = createRule();
854 QProfileDto builtInProfile = db.qualityProfiles().insert(p -> p.setLanguage(rule.getLanguage()).setIsBuiltIn(true));
856 expectedException.expect(IllegalArgumentException.class);
857 expectedException.expectMessage("The built-in profile " + builtInProfile.getName() + " is read-only and can't be updated");
859 underTest.activateAndCommit(db.getSession(), builtInProfile, singleton(RuleActivation.create(rule.getUuid())));
862 private void assertThatProfileHasNoActiveRules(QProfileDto profile) {
863 List<OrgActiveRuleDto> activeRules = db.getDbClient().activeRuleDao().selectByProfile(db.getSession(), profile);
864 assertThat(activeRules).isEmpty();
867 private List<ActiveRuleChange> deactivate(QProfileDto profile, RuleDefinitionDto rule) {
868 return underTest.deactivateAndCommit(db.getSession(), profile, singleton(rule.getUuid()));
871 private List<ActiveRuleChange> activate(QProfileDto profile, RuleActivation activation) {
872 return underTest.activateAndCommit(db.getSession(), profile, singleton(activation));
875 private QProfileDto createProfile(RuleDefinitionDto rule) {
876 return db.qualityProfiles().insert(p -> p.setLanguage(rule.getLanguage()));
879 private QProfileDto createChildProfile(QProfileDto parent) {
880 return db.qualityProfiles().insert(p -> p
881 .setLanguage(parent.getLanguage())
882 .setParentKee(parent.getKee())
883 .setName("Child of " + parent.getName()));
886 private void assertThatProfileIsUpdatedByUser(QProfileDto profile) {
887 QProfileDto loaded = db.getDbClient().qualityProfileDao().selectByUuid(db.getSession(), profile.getKee());
888 assertThat(loaded.getUserUpdatedAt()).isNotNull();
889 assertThat(loaded.getRulesUpdatedAt()).isNotEmpty();
892 private void assertThatProfileIsUpdatedBySystem(QProfileDto profile) {
893 QProfileDto loaded = db.getDbClient().qualityProfileDao().selectByUuid(db.getSession(), profile.getKee());
894 assertThat(loaded.getUserUpdatedAt()).isNull();
895 assertThat(loaded.getRulesUpdatedAt()).isNotEmpty();
898 private void assertThatRuleIsActivated(QProfileDto profile, RuleDefinitionDto rule, @Nullable List<ActiveRuleChange> changes,
899 String expectedSeverity, @Nullable ActiveRuleInheritance expectedInheritance, Map<String, String> expectedParams) {
900 OrgActiveRuleDto activeRule = db.getDbClient().activeRuleDao().selectByProfile(db.getSession(), profile)
902 .filter(ar -> ar.getRuleKey().equals(rule.getKey()))
904 .orElseThrow(IllegalStateException::new);
906 assertThat(activeRule.getSeverityString()).isEqualTo(expectedSeverity);
907 assertThat(activeRule.getInheritance()).isEqualTo(expectedInheritance != null ? expectedInheritance.name() : null);
908 assertThat(activeRule.getCreatedAt()).isNotNull();
909 assertThat(activeRule.getUpdatedAt()).isNotNull();
911 List<ActiveRuleParamDto> params = db.getDbClient().activeRuleDao().selectParamsByActiveRuleUuid(db.getSession(), activeRule.getUuid());
912 assertThat(params).hasSize(expectedParams.size());
914 if (changes != null) {
915 ActiveRuleChange change = changes.stream()
916 .filter(c -> c.getActiveRule().getUuid().equals(activeRule.getUuid()))
917 .findFirst().orElseThrow(IllegalStateException::new);
918 assertThat(change.getInheritance()).isEqualTo(expectedInheritance);
919 assertThat(change.getSeverity()).isEqualTo(expectedSeverity);
920 assertThat(change.getType()).isEqualTo(ActiveRuleChange.Type.ACTIVATED);
924 private void assertThatRuleIsNotPresent(QProfileDto profile, RuleDefinitionDto rule) {
925 Optional<OrgActiveRuleDto> activeRule = db.getDbClient().activeRuleDao().selectByProfile(db.getSession(), profile)
927 .filter(ar -> ar.getRuleKey().equals(rule.getKey()))
930 assertThat(activeRule).isEmpty();
933 private void assertThatRuleIsUpdated(QProfileDto profile, RuleDefinitionDto rule,
934 String expectedSeverity, @Nullable ActiveRuleInheritance expectedInheritance, Map<String, String> expectedParams) {
935 OrgActiveRuleDto activeRule = db.getDbClient().activeRuleDao().selectByProfile(db.getSession(), profile)
937 .filter(ar -> ar.getRuleKey().equals(rule.getKey()))
939 .orElseThrow(IllegalStateException::new);
941 assertThat(activeRule.getSeverityString()).isEqualTo(expectedSeverity);
942 assertThat(activeRule.getInheritance()).isEqualTo(expectedInheritance != null ? expectedInheritance.name() : null);
943 assertThat(activeRule.getCreatedAt()).isNotNull();
944 assertThat(activeRule.getUpdatedAt()).isNotNull();
946 List<ActiveRuleParamDto> params = db.getDbClient().activeRuleDao().selectParamsByActiveRuleUuid(db.getSession(), activeRule.getUuid());
947 assertThat(params).hasSize(expectedParams.size());
950 private void expectFailure(String expectedMessage, Runnable runnable) {
954 } catch (BadRequestException e) {
955 assertThat(e.getMessage()).isEqualTo(expectedMessage);
957 verifyNoActiveRules();
960 private void verifyNoActiveRules() {
961 assertThat(db.countRowsOfTable(db.getSession(), "active_rules")).isEqualTo(0);
964 private RuleDefinitionDto createRule() {
965 return db.rules().insert(r -> r.setSeverity(Severity.MAJOR));
968 private RuleDefinitionDto createJavaRule() {
969 return db.rules().insert(r -> r.setSeverity(Severity.MAJOR).setLanguage("java"));