]> source.dussan.org Git - sonarqube.git/blob
1b84a8198006aeff4acb7b76a5ad5700bb58196c
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2022 SonarSource SA
4  * mailto:info AT sonarsource DOT com
5  *
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.
10  *
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.
15  *
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.
19  */
20 package org.sonar.server.qualityprofile;
21
22 import java.util.ArrayList;
23 import java.util.List;
24 import java.util.Map;
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.sonar.api.PropertyType;
32 import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
33 import org.sonar.api.rule.RuleStatus;
34 import org.sonar.api.rule.Severity;
35 import org.sonar.api.utils.System2;
36 import org.sonar.db.DbTester;
37 import org.sonar.db.qualityprofile.ActiveRuleParamDto;
38 import org.sonar.db.qualityprofile.OrgActiveRuleDto;
39 import org.sonar.db.qualityprofile.QProfileDto;
40 import org.sonar.db.rule.RuleDefinitionDto;
41 import org.sonar.db.rule.RuleDto;
42 import org.sonar.db.rule.RuleParamDto;
43 import org.sonar.server.es.EsTester;
44 import org.sonar.server.es.SearchOptions;
45 import org.sonar.server.exceptions.BadRequestException;
46 import org.sonar.server.pushapi.qualityprofile.QualityProfileChangeEventService;
47 import org.sonar.server.qualityprofile.builtin.RuleActivator;
48 import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
49 import org.sonar.server.rule.index.RuleIndex;
50 import org.sonar.server.rule.index.RuleIndexer;
51 import org.sonar.server.rule.index.RuleQuery;
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;
56
57 import static com.google.common.collect.ImmutableMap.of;
58 import static java.util.Arrays.asList;
59 import static java.util.Collections.emptyMap;
60 import static java.util.Collections.singleton;
61 import static java.util.Collections.singletonList;
62 import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
63 import static org.assertj.core.api.Assertions.assertThat;
64 import static org.assertj.core.api.Assertions.assertThatThrownBy;
65 import static org.junit.Assert.fail;
66 import static org.mockito.ArgumentMatchers.any;
67 import static org.mockito.ArgumentMatchers.eq;
68 import static org.mockito.Mockito.mock;
69 import static org.mockito.Mockito.verify;
70 import static org.mockito.Mockito.verifyNoInteractions;
71 import static org.sonar.api.rule.Severity.BLOCKER;
72 import static org.sonar.api.rule.Severity.CRITICAL;
73 import static org.sonar.api.rule.Severity.MAJOR;
74 import static org.sonar.api.rule.Severity.MINOR;
75 import static org.sonar.db.rule.RuleTesting.newCustomRule;
76 import static org.sonar.server.qualityprofile.ActiveRuleInheritance.INHERITED;
77
78 public class QProfileRuleImplTest {
79
80   private System2 system2 = new AlwaysIncreasingSystem2();
81   @Rule
82   public DbTester db = DbTester.create(system2);
83   @Rule
84   public EsTester es = EsTester.create();
85   @Rule
86   public UserSessionRule userSession = UserSessionRule.standalone();
87   private RuleIndex ruleIndex = new RuleIndex(es.client(), system2);
88   private ActiveRuleIndexer activeRuleIndexer = new ActiveRuleIndexer(db.getDbClient(), es.client());
89   private RuleIndexer ruleIndexer = new RuleIndexer(es.client(), db.getDbClient());
90   private TypeValidations typeValidations = new TypeValidations(asList(new StringTypeValidation(), new IntegerTypeValidation()));
91   private QualityProfileChangeEventService qualityProfileChangeEventService = mock(QualityProfileChangeEventService.class);
92
93   private RuleActivator ruleActivator = new RuleActivator(system2, db.getDbClient(), typeValidations, userSession);
94   private QProfileRules underTest = new QProfileRulesImpl(db.getDbClient(), ruleActivator, ruleIndex, activeRuleIndexer, qualityProfileChangeEventService);
95
96   @Test
97   public void system_activates_rule_without_parameters() {
98     RuleDefinitionDto rule = createRule();
99     QProfileDto profile = createProfile(rule);
100     RuleActivation activation = RuleActivation.create(rule.getUuid(), BLOCKER, null);
101     List<ActiveRuleChange> changes = activate(profile, activation);
102
103     assertThatRuleIsActivated(profile, rule, changes, BLOCKER, null, emptyMap());
104     assertThatProfileIsUpdatedBySystem(profile);
105     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), any(), eq(profile.getLanguage()));
106   }
107
108   @Test
109   public void user_activates_rule_without_parameters() {
110     userSession.logIn();
111     RuleDefinitionDto rule = createRule();
112     QProfileDto profile = createProfile(rule);
113     RuleActivation activation = RuleActivation.create(rule.getUuid(), BLOCKER, null);
114     List<ActiveRuleChange> changes = activate(profile, activation);
115
116     assertThatRuleIsActivated(profile, rule, changes, BLOCKER, null, emptyMap());
117     assertThatProfileIsUpdatedByUser(profile);
118     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), any(), eq(profile.getLanguage()));
119   }
120
121   @Test
122   public void activate_rule_with_default_severity_and_parameters() {
123     RuleDefinitionDto rule = createRule();
124     RuleParamDto ruleParam = db.rules().insertRuleParam(rule, p -> p.setName("min").setDefaultValue("10"));
125     QProfileDto profile = createProfile(rule);
126
127     RuleActivation activation = RuleActivation.create(rule.getUuid());
128     List<ActiveRuleChange> changes = activate(profile, activation);
129
130     assertThatRuleIsActivated(profile, rule, changes, rule.getSeverityString(), null, of("min", "10"));
131     assertThatProfileIsUpdatedBySystem(profile);
132     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), any(), eq(profile.getLanguage()));
133   }
134
135   @Test
136   public void activate_rule_with_parameters() {
137     RuleDefinitionDto rule = createRule();
138     RuleParamDto ruleParam = db.rules().insertRuleParam(rule, p -> p.setName("min").setDefaultValue("10"));
139     QProfileDto profile = createProfile(rule);
140
141     RuleActivation activation = RuleActivation.create(rule.getUuid(), null, of(ruleParam.getName(), "15"));
142     List<ActiveRuleChange> changes = activate(profile, activation);
143
144     assertThatRuleIsActivated(profile, rule, changes, rule.getSeverityString(), null, of("min", "15"));
145     assertThatProfileIsUpdatedBySystem(profile);
146     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), any(), eq(profile.getLanguage()));
147   }
148
149   @Test
150   public void activate_rule_with_default_severity() {
151     RuleDefinitionDto rule = createRule();
152     QProfileDto profile = createProfile(rule);
153
154     RuleActivation activation = RuleActivation.create(rule.getUuid());
155     List<ActiveRuleChange> changes = activate(profile, activation);
156
157     assertThatRuleIsActivated(profile, rule, changes, rule.getSeverityString(), null, emptyMap());
158     assertThatProfileIsUpdatedBySystem(profile);
159     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), any(), eq(profile.getLanguage()));
160   }
161
162   /**
163    * SONAR-5841
164    */
165   @Test
166   public void activate_rule_with_empty_parameter_having_no_default_value() {
167     RuleDefinitionDto rule = createRule();
168     RuleParamDto ruleParam = db.rules().insertRuleParam(rule, p -> p.setName("min").setDefaultValue("10"));
169     QProfileDto profile = createProfile(rule);
170
171     RuleActivation activation = RuleActivation.create(rule.getUuid(), null, of("min", ""));
172     List<ActiveRuleChange> changes = activate(profile, activation);
173
174     assertThatRuleIsActivated(profile, rule, changes, rule.getSeverityString(), null, of("min", "10"));
175     assertThatProfileIsUpdatedBySystem(profile);
176     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), any(), eq(profile.getLanguage()));
177   }
178
179   /**
180    * //   * SONAR-5840
181    * //
182    */
183   @Test
184   public void activate_rule_with_negative_integer_value_on_parameter_having_no_default_value() {
185     RuleDefinitionDto rule = createRule();
186     RuleParamDto paramWithoutDefault = db.rules().insertRuleParam(rule, p -> p.setName("min").setDefaultValue(null));
187     RuleParamDto paramWithDefault = db.rules().insertRuleParam(rule, p -> p.setName("max").setDefaultValue("10"));
188     QProfileDto profile = createProfile(rule);
189
190     RuleActivation activation = RuleActivation.create(rule.getUuid(), null, of(paramWithoutDefault.getName(), "-10"));
191     List<ActiveRuleChange> changes = activate(profile, activation);
192
193     assertThatRuleIsActivated(profile, rule, changes, rule.getSeverityString(), null,
194       of(paramWithoutDefault.getName(), "-10", paramWithDefault.getName(), paramWithDefault.getDefaultValue()));
195     assertThatProfileIsUpdatedBySystem(profile);
196     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), any(), eq(profile.getLanguage()));
197   }
198
199   @Test
200   public void activation_ignores_unsupported_parameters() {
201     RuleDefinitionDto rule = createRule();
202     RuleParamDto param = db.rules().insertRuleParam(rule, p -> p.setName("max").setDefaultValue("10"));
203     QProfileDto profile = createProfile(rule);
204
205     RuleActivation activation = RuleActivation.create(rule.getUuid(), null, of("xxx", "yyy"));
206     List<ActiveRuleChange> changes = activate(profile, activation);
207
208     assertThatRuleIsActivated(profile, rule, changes, rule.getSeverityString(), null, of(param.getName(), param.getDefaultValue()));
209     assertThatProfileIsUpdatedBySystem(profile);
210     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), any(), eq(profile.getLanguage()));
211   }
212
213   @Test
214   public void update_an_already_activated_rule() {
215     RuleDefinitionDto rule = createRule();
216     RuleParamDto param = db.rules().insertRuleParam(rule, p -> p.setName("max").setDefaultValue("10"));
217     QProfileDto profile = createProfile(rule);
218
219     // initial activation
220     RuleActivation activation = RuleActivation.create(rule.getUuid(), MAJOR, null);
221     List<ActiveRuleChange> changes = activate(profile, activation);
222     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(profile.getLanguage()));
223
224     // update
225     RuleActivation updateActivation = RuleActivation.create(rule.getUuid(), CRITICAL, of(param.getName(), "20"));
226     changes = activate(profile, updateActivation);
227
228     assertThatRuleIsUpdated(profile, rule, CRITICAL, null, of(param.getName(), "20"));
229     assertThatProfileIsUpdatedBySystem(profile);
230     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(profile.getLanguage()));
231   }
232
233   @Test
234   public void update_activation_with_parameter_without_default_value() {
235     RuleDefinitionDto rule = createRule();
236     RuleParamDto paramWithoutDefault = db.rules().insertRuleParam(rule, p -> p.setName("min").setDefaultValue(null));
237     RuleParamDto paramWithDefault = db.rules().insertRuleParam(rule, p -> p.setName("max").setDefaultValue("10"));
238     QProfileDto profile = createProfile(rule);
239
240     // initial activation -> param "max" has a default value
241     RuleActivation activation = RuleActivation.create(rule.getUuid());
242     List<ActiveRuleChange> changes = activate(profile, activation);
243
244     // update param "min", which has no default value
245     RuleActivation updateActivation = RuleActivation.create(rule.getUuid(), MAJOR, of(paramWithoutDefault.getName(), "3"));
246     changes = activate(profile, updateActivation);
247     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(profile.getLanguage()));
248
249     assertThatRuleIsUpdated(profile, rule, MAJOR, null, of(paramWithDefault.getName(), "10", paramWithoutDefault.getName(), "3"));
250     assertThatProfileIsUpdatedBySystem(profile);
251     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(profile.getLanguage()));
252   }
253
254   @Test
255   public void reset_parameter_to_default_value() {
256     RuleDefinitionDto rule = createRule();
257     RuleParamDto paramWithDefault = db.rules().insertRuleParam(rule, p -> p.setName("max").setDefaultValue("10"));
258     QProfileDto profile = createProfile(rule);
259
260     // initial activation -> param "max" has a default value
261     RuleActivation activation = RuleActivation.create(rule.getUuid(), null, of(paramWithDefault.getName(), "20"));
262     List<ActiveRuleChange> changes = activate(profile, activation);
263     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(profile.getLanguage()));
264
265     // reset to default_value
266     RuleActivation updateActivation = RuleActivation.create(rule.getUuid(), null, of(paramWithDefault.getName(), ""));
267     changes = activate(profile, updateActivation);
268
269     assertThatRuleIsUpdated(profile, rule, rule.getSeverityString(), null, of(paramWithDefault.getName(), "10"));
270     assertThat(changes).hasSize(1);
271     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(profile.getLanguage()));
272   }
273
274   @Test
275   public void update_activation_removes_parameter_without_default_value() {
276     RuleDefinitionDto rule = createRule();
277     RuleParamDto paramWithoutDefault = db.rules().insertRuleParam(rule, p -> p.setName("min").setDefaultValue(null));
278     RuleParamDto paramWithDefault = db.rules().insertRuleParam(rule, p -> p.setName("max").setDefaultValue("10"));
279     QProfileDto profile = createProfile(rule);
280
281     // initial activation -> param "max" has a default value
282     RuleActivation activation = RuleActivation.create(rule.getUuid(), null, of(paramWithoutDefault.getName(), "20"));
283     List<ActiveRuleChange> changes = activate(profile, activation);
284     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(profile.getLanguage()));
285
286     // remove parameter
287     RuleActivation updateActivation = RuleActivation.create(rule.getUuid(), null, of(paramWithoutDefault.getName(), ""));
288     changes = activate(profile, updateActivation);
289
290     assertThatRuleIsUpdated(profile, rule, rule.getSeverityString(), null, of(paramWithDefault.getName(), paramWithDefault.getDefaultValue()));
291     assertThat(changes).hasSize(1);
292     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(profile.getLanguage()));
293   }
294
295   @Test
296   public void update_activation_with_new_parameter() {
297     RuleDefinitionDto rule = createRule();
298     RuleParamDto param = db.rules().insertRuleParam(rule, p -> p.setName("max").setDefaultValue("10"));
299     QProfileDto profile = createProfile(rule);
300
301     // initial activation -> param "max" has a default value
302     RuleActivation activation = RuleActivation.create(rule.getUuid());
303     List<ActiveRuleChange> changes = activate(profile, activation);
304     db.getDbClient().activeRuleDao().deleteParametersByRuleProfileUuids(db.getSession(), asList(profile.getRulesProfileUuid()));
305     assertThatRuleIsActivated(profile, rule, changes, rule.getSeverityString(), null, emptyMap());
306     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(profile.getLanguage()));
307
308     // contrary to activerule, the param is supposed to be inserted but not updated
309     RuleActivation updateActivation = RuleActivation.create(rule.getUuid(), null, of(param.getName(), ""));
310     changes = activate(profile, updateActivation);
311
312     assertThatRuleIsUpdated(profile, rule, rule.getSeverityString(), null, of(param.getName(), param.getDefaultValue()));
313     assertThat(changes).hasSize(1);
314     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(profile.getLanguage()));
315   }
316
317   @Test
318   public void ignore_activation_without_changes() {
319     RuleDefinitionDto rule = createRule();
320     QProfileDto profile = createProfile(rule);
321
322     // initial activation
323     RuleActivation activation = RuleActivation.create(rule.getUuid());
324     List<ActiveRuleChange> changes = activate(profile, activation);
325     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(profile.getLanguage()));
326
327     // update with exactly the same severity and params
328     activation = RuleActivation.create(rule.getUuid());
329     changes = activate(profile, activation);
330
331     assertThat(changes).isEmpty();
332     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(profile.getLanguage()));
333   }
334
335   @Test
336   public void do_not_change_severity_and_params_if_unset_and_already_activated() {
337     RuleDefinitionDto rule = createRule();
338     RuleParamDto param = db.rules().insertRuleParam(rule, p -> p.setName("max").setDefaultValue("10"));
339     QProfileDto profile = createProfile(rule);
340
341     // initial activation -> param "max" has a default value
342     RuleActivation activation = RuleActivation.create(rule.getUuid(), BLOCKER, of(param.getName(), "20"));
343     List<ActiveRuleChange> changes = activate(profile, activation);
344     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(profile.getLanguage()));
345
346
347     // update without any severity or params => keep
348     RuleActivation update = RuleActivation.create(rule.getUuid());
349     changes = activate(profile, update);
350
351     assertThat(changes).isEmpty();
352     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(profile.getLanguage()));
353   }
354
355   @Test
356   public void fail_to_activate_rule_if_profile_is_on_different_languages() {
357     RuleDefinitionDto rule = createJavaRule();
358     QProfileDto profile = db.qualityProfiles().insert(p -> p.setLanguage("js"));
359     RuleActivation activation = RuleActivation.create(rule.getUuid());
360
361     expectFailure("java rule " + rule.getKey() + " cannot be activated on js profile " + profile.getKee(), () -> activate(profile, activation));
362     verifyNoInteractions(qualityProfileChangeEventService);
363   }
364
365   @Test
366   public void fail_to_activate_rule_if_rule_has_REMOVED_status() {
367     RuleDefinitionDto rule = db.rules().insert(r -> r.setStatus(RuleStatus.REMOVED));
368     QProfileDto profile = createProfile(rule);
369     RuleActivation activation = RuleActivation.create(rule.getUuid());
370
371     expectFailure("Rule was removed: " + rule.getKey(), () -> activate(profile, activation));
372     verifyNoInteractions(qualityProfileChangeEventService);
373   }
374
375   @Test
376   public void fail_to_activate_if_template() {
377     RuleDefinitionDto rule = db.rules().insert(r -> r.setIsTemplate(true));
378     QProfileDto profile = createProfile(rule);
379     RuleActivation activation = RuleActivation.create(rule.getUuid());
380
381     expectFailure("Rule template can't be activated on a Quality profile: " + rule.getKey(), () -> activate(profile, activation));
382     verifyNoInteractions(qualityProfileChangeEventService);
383   }
384
385   @Test
386   public void fail_to_activate_if_invalid_parameter() {
387     RuleDefinitionDto rule = createRule();
388     RuleParamDto param = db.rules().insertRuleParam(rule, p -> p.setName("max").setDefaultValue("10").setType(PropertyType.INTEGER.name()));
389     QProfileDto profile = createProfile(rule);
390
391     RuleActivation activation = RuleActivation.create(rule.getUuid(), null, of(param.getName(), "foo"));
392     expectFailure("Value 'foo' must be an integer.", () -> activate(profile, activation));
393     verifyNoInteractions(qualityProfileChangeEventService);
394   }
395
396   @Test
397   public void ignore_parameters_when_activating_custom_rule() {
398     RuleDefinitionDto templateRule = db.rules().insert(r -> r.setIsTemplate(true));
399     RuleParamDto templateParam = db.rules().insertRuleParam(templateRule, p -> p.setName("format"));
400     RuleDefinitionDto customRule = db.rules().insert(newCustomRule(templateRule));
401     RuleParamDto customParam = db.rules().insertRuleParam(customRule, p -> p.setName("format").setDefaultValue("txt"));
402     QProfileDto profile = createProfile(customRule);
403
404     // initial activation
405     RuleActivation activation = RuleActivation.create(customRule.getUuid(), MAJOR, emptyMap());
406     List<ActiveRuleChange> changes = activate(profile, activation);
407     assertThatRuleIsActivated(profile, customRule, null, MAJOR, null, of("format", "txt"));
408     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(profile.getLanguage()));
409
410     // update -> parameter is not changed
411     RuleActivation updateActivation = RuleActivation.create(customRule.getUuid(), BLOCKER, of("format", "xml"));
412     changes = activate(profile, updateActivation);
413     assertThatRuleIsActivated(profile, customRule, null, BLOCKER, null, of("format", "txt"));
414     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(profile.getLanguage()));
415   }
416
417   @Test
418   public void user_deactivates_a_rule() {
419     userSession.logIn();
420     RuleDefinitionDto rule = createRule();
421     QProfileDto profile = createProfile(rule);
422     RuleActivation activation = RuleActivation.create(rule.getUuid());
423     List<ActiveRuleChange> changes = activate(profile, activation);
424     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(profile.getLanguage()));
425
426     changes = deactivate(profile, rule);
427     verifyNoActiveRules();
428     assertThatProfileIsUpdatedByUser(profile);
429     assertThat(changes).hasSize(1);
430     assertThat(changes.get(0).getType()).isEqualTo(ActiveRuleChange.Type.DEACTIVATED);
431     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(profile.getLanguage()));
432   }
433
434   @Test
435   public void system_deactivates_a_rule() {
436     RuleDefinitionDto rule = createRule();
437     QProfileDto profile = createProfile(rule);
438     RuleActivation activation = RuleActivation.create(rule.getUuid());
439     List<ActiveRuleChange> changes = activate(profile, activation);
440     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(profile.getLanguage()));
441
442     changes = deactivate(profile, rule);
443     verifyNoActiveRules();
444     assertThatProfileIsUpdatedBySystem(profile);
445     assertThatChangeIsDeactivation(changes, rule);
446     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(profile.getLanguage()));
447   }
448
449   private void assertThatChangeIsDeactivation(List<ActiveRuleChange> changes, RuleDefinitionDto rule) {
450     assertThat(changes).hasSize(1);
451     ActiveRuleChange change = changes.get(0);
452     assertThat(change.getType()).isEqualTo(ActiveRuleChange.Type.DEACTIVATED);
453     assertThat(change.getKey().getRuleKey()).isEqualTo(rule.getKey());
454   }
455
456   @Test
457   public void ignore_deactivation_if_rule_is_not_activated() {
458     RuleDefinitionDto rule = createRule();
459     QProfileDto profile = createProfile(rule);
460
461     List<ActiveRuleChange> changes = deactivate(profile, rule);
462     verifyNoActiveRules();
463     assertThat(changes).isEmpty();
464     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), any(), eq(profile.getLanguage()));
465   }
466
467   @Test
468   public void deactivate_rule_that_has_REMOVED_status() {
469     RuleDefinitionDto rule = createRule();
470     QProfileDto profile = createProfile(rule);
471     RuleActivation activation = RuleActivation.create(rule.getUuid());
472     List<ActiveRuleChange> changes = activate(profile, activation);
473     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(profile.getLanguage()));
474
475     rule.setStatus(RuleStatus.REMOVED);
476     db.getDbClient().ruleDao().update(db.getSession(), rule);
477
478     changes = deactivate(profile, rule);
479     verifyNoActiveRules();
480     assertThatChangeIsDeactivation(changes, rule);
481     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(profile.getLanguage()));
482   }
483
484   @Test
485   public void activation_on_child_profile_is_propagated_to_descendants() {
486     RuleDefinitionDto rule = createRule();
487     QProfileDto parentProfile = createProfile(rule);
488     QProfileDto childProfile = createChildProfile(parentProfile);
489     QProfileDto grandChildProfile = createChildProfile(childProfile);
490
491     List<ActiveRuleChange> changes = activate(childProfile, RuleActivation.create(rule.getUuid()));
492     assertThatProfileHasNoActiveRules(parentProfile);
493     assertThatRuleIsActivated(childProfile, rule, changes, rule.getSeverityString(), null, emptyMap());
494     assertThatRuleIsActivated(grandChildProfile, rule, changes, rule.getSeverityString(), INHERITED, emptyMap());
495     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), any(), eq(childProfile.getLanguage()));
496   }
497
498   @Test
499   public void update_on_child_profile_is_propagated_to_descendants() {
500     RuleDefinitionDto rule = createRule();
501     RuleParamDto param = db.rules().insertRuleParam(rule);
502     QProfileDto parentProfile = createProfile(rule);
503     QProfileDto childProfile = createChildProfile(parentProfile);
504     QProfileDto grandChildProfile = createChildProfile(childProfile);
505
506     System.out.println("ACTIVATE ON " + childProfile.getName());
507     RuleActivation initialActivation = RuleActivation.create(rule.getUuid(), MAJOR, of(param.getName(), "foo"));
508     List<ActiveRuleChange> changes = activate(childProfile, initialActivation);
509     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(childProfile.getLanguage()));
510
511     System.out.println("---------------");
512     System.out.println("ACTIVATE ON " + childProfile.getName());
513     RuleActivation updateActivation = RuleActivation.create(rule.getUuid(), CRITICAL, of(param.getName(), "bar"));
514     changes = activate(childProfile, updateActivation);
515     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(childProfile.getLanguage()));
516
517     assertThatProfileHasNoActiveRules(parentProfile);
518     assertThatRuleIsUpdated(childProfile, rule, CRITICAL, null, of(param.getName(), "bar"));
519     assertThatRuleIsUpdated(grandChildProfile, rule, CRITICAL, INHERITED, of(param.getName(), "bar"));
520     assertThat(changes).hasSize(2);
521     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(childProfile.getLanguage()));
522   }
523
524   @Test
525   public void override_activation_of_inherited_profile() {
526     RuleDefinitionDto rule = createRule();
527     RuleParamDto param = db.rules().insertRuleParam(rule);
528     QProfileDto parentProfile = createProfile(rule);
529     QProfileDto childProfile = createChildProfile(parentProfile);
530     QProfileDto grandChildProfile = createChildProfile(childProfile);
531
532     RuleActivation initialActivation = RuleActivation.create(rule.getUuid(), MAJOR, of(param.getName(), "foo"));
533     List<ActiveRuleChange> changes = activate(childProfile, initialActivation);
534     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(childProfile.getLanguage()));
535
536     RuleActivation overrideActivation = RuleActivation.create(rule.getUuid(), CRITICAL, of(param.getName(), "bar"));
537     changes = activate(grandChildProfile, overrideActivation);
538
539     assertThatProfileHasNoActiveRules(parentProfile);
540     assertThatRuleIsUpdated(childProfile, rule, MAJOR, null, of(param.getName(), "foo"));
541     assertThatRuleIsUpdated(grandChildProfile, rule, CRITICAL, ActiveRuleInheritance.OVERRIDES, of(param.getName(), "bar"));
542     assertThat(changes).hasSize(1);
543     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(childProfile.getLanguage()));
544   }
545
546   @Test
547   public void updated_activation_on_parent_is_not_propagated_to_overridden_profiles() {
548     RuleDefinitionDto rule = createRule();
549     RuleParamDto param = db.rules().insertRuleParam(rule);
550     QProfileDto parentProfile = createProfile(rule);
551     QProfileDto childProfile = createChildProfile(parentProfile);
552     QProfileDto grandChildProfile = createChildProfile(childProfile);
553
554     RuleActivation initialActivation = RuleActivation.create(rule.getUuid(), MAJOR, of(param.getName(), "foo"));
555     List<ActiveRuleChange> changes = activate(childProfile, initialActivation);
556     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(childProfile.getLanguage()));
557
558     RuleActivation overrideActivation = RuleActivation.create(rule.getUuid(), CRITICAL, of(param.getName(), "bar"));
559     changes = activate(grandChildProfile, overrideActivation);
560     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(grandChildProfile.getLanguage()));
561
562     // update child --> do not touch grandChild
563     RuleActivation updateActivation = RuleActivation.create(rule.getUuid(), BLOCKER, of(param.getName(), "baz"));
564     changes = activate(childProfile, updateActivation);
565
566     assertThatProfileHasNoActiveRules(parentProfile);
567     assertThatRuleIsUpdated(childProfile, rule, BLOCKER, null, of(param.getName(), "baz"));
568     assertThatRuleIsUpdated(grandChildProfile, rule, CRITICAL, ActiveRuleInheritance.OVERRIDES, of(param.getName(), "bar"));
569     assertThat(changes).hasSize(1);
570     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(childProfile.getLanguage()));
571   }
572
573   @Test
574   public void reset_on_parent_is_not_propagated_to_overridden_profiles() {
575     RuleDefinitionDto rule = createRule();
576     RuleParamDto param = db.rules().insertRuleParam(rule);
577     QProfileDto parentProfile = createProfile(rule);
578     QProfileDto childProfile = createChildProfile(parentProfile);
579     QProfileDto grandChildProfile = createChildProfile(childProfile);
580
581     RuleActivation initialActivation = RuleActivation.create(rule.getUuid(), MAJOR, of(param.getName(), "foo"));
582     List<ActiveRuleChange> changes = activate(parentProfile, initialActivation);
583     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(parentProfile.getLanguage()));
584
585     RuleActivation overrideActivation = RuleActivation.create(rule.getUuid(), CRITICAL, of(param.getName(), "bar"));
586     changes = activate(grandChildProfile, overrideActivation);
587     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(grandChildProfile.getLanguage()));
588
589     // reset parent --> touch child but not grandChild
590     RuleActivation updateActivation = RuleActivation.createReset(rule.getUuid());
591     changes = activate(parentProfile, updateActivation);
592
593     assertThatRuleIsUpdated(parentProfile, rule, rule.getSeverityString(), null, of(param.getName(), param.getDefaultValue()));
594     assertThatRuleIsUpdated(childProfile, rule, rule.getSeverityString(), INHERITED, of(param.getName(), param.getDefaultValue()));
595     assertThatRuleIsUpdated(grandChildProfile, rule, CRITICAL, ActiveRuleInheritance.OVERRIDES, of(param.getName(), "bar"));
596     assertThat(changes).hasSize(2);
597     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(parentProfile.getLanguage()));
598   }
599
600   @Test
601   public void active_on_parent_a_rule_already_activated_on_child() {
602     RuleDefinitionDto rule = createRule();
603     RuleParamDto param = db.rules().insertRuleParam(rule);
604     QProfileDto parentProfile = createProfile(rule);
605     QProfileDto childProfile = createChildProfile(parentProfile);
606
607     RuleActivation childActivation = RuleActivation.create(rule.getUuid(), MAJOR, of(param.getName(), "foo"));
608     List<ActiveRuleChange> changes = activate(childProfile, childActivation);
609     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(childProfile.getLanguage()));
610
611     RuleActivation parentActivation = RuleActivation.create(rule.getUuid(), CRITICAL, of(param.getName(), "bar"));
612     changes = activate(parentProfile, parentActivation);
613
614     assertThatRuleIsUpdated(parentProfile, rule, CRITICAL, null, of(param.getName(), "bar"));
615     assertThatRuleIsUpdated(childProfile, rule, MAJOR, ActiveRuleInheritance.OVERRIDES, of(param.getName(), "foo"));
616     assertThat(changes).hasSize(2);
617     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(parentProfile.getLanguage()));
618   }
619
620   @Test
621   public void do_not_mark_as_overridden_if_same_values_than_parent() {
622     RuleDefinitionDto rule = createRule();
623     RuleParamDto param = db.rules().insertRuleParam(rule);
624     QProfileDto parentProfile = createProfile(rule);
625     QProfileDto childProfile = createChildProfile(parentProfile);
626
627     RuleActivation parentActivation = RuleActivation.create(rule.getUuid(), MAJOR, of(param.getName(), "foo"));
628     List<ActiveRuleChange> changes = activate(parentProfile, parentActivation);
629     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(parentProfile.getLanguage()));
630
631     RuleActivation overrideActivation = RuleActivation.create(rule.getUuid(), MAJOR, of(param.getName(), "foo"));
632     changes = activate(childProfile, overrideActivation);
633
634     assertThatRuleIsUpdated(childProfile, rule, MAJOR, INHERITED, of(param.getName(), "foo"));
635     assertThat(changes).isEmpty();
636     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(childProfile.getLanguage()));
637   }
638
639   @Test
640   public void propagate_deactivation_on_children() {
641     RuleDefinitionDto rule = createRule();
642     QProfileDto parentProfile = createProfile(rule);
643     QProfileDto childProfile = createChildProfile(parentProfile);
644
645     RuleActivation activation = RuleActivation.create(rule.getUuid());
646     List<ActiveRuleChange> changes = activate(parentProfile, activation);
647     assertThatRuleIsActivated(parentProfile, rule, changes, rule.getSeverityString(), null, emptyMap());
648     assertThatRuleIsActivated(childProfile, rule, changes, rule.getSeverityString(), INHERITED, emptyMap());
649     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(parentProfile.getLanguage()));
650
651     changes = deactivate(parentProfile, rule);
652     assertThatProfileHasNoActiveRules(parentProfile);
653     assertThatProfileHasNoActiveRules(childProfile);
654     assertThat(changes).hasSize(2);
655     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(parentProfile.getLanguage()));
656   }
657
658   @Test
659   public void propagate_deactivation_on_children_even_when_overridden() {
660     RuleDefinitionDto rule = createRule();
661     QProfileDto parentProfile = createProfile(rule);
662     QProfileDto childProfile = createChildProfile(parentProfile);
663
664     RuleActivation activation = RuleActivation.create(rule.getUuid());
665     List<ActiveRuleChange> changes = activate(parentProfile, activation);
666     assertThatRuleIsActivated(parentProfile, rule, changes, rule.getSeverityString(), null, emptyMap());
667     assertThatRuleIsActivated(childProfile, rule, changes, rule.getSeverityString(), INHERITED, emptyMap());
668     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(parentProfile.getLanguage()));
669
670     activation = RuleActivation.create(rule.getUuid(), CRITICAL, null);
671     changes = activate(childProfile, activation);
672     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(childProfile.getLanguage()));
673
674     changes = deactivate(parentProfile, rule);
675     assertThatProfileHasNoActiveRules(parentProfile);
676     assertThatProfileHasNoActiveRules(childProfile);
677     assertThat(changes).hasSize(2);
678     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(parentProfile.getLanguage()));
679   }
680
681   @Test
682   public void cannot_deactivate_rule_inherited() {
683     RuleDefinitionDto rule = createRule();
684     QProfileDto parentProfile = createProfile(rule);
685     QProfileDto childProfile = createChildProfile(parentProfile);
686
687     RuleActivation activation = RuleActivation.create(rule.getUuid());
688     List<ActiveRuleChange> changes = activate(parentProfile, activation);
689     assertThatRuleIsActivated(parentProfile, rule, changes, rule.getSeverityString(), null, emptyMap());
690     assertThatRuleIsActivated(childProfile, rule, changes, rule.getSeverityString(), INHERITED, emptyMap());
691
692     assertThatThrownBy(() -> deactivate(childProfile, rule))
693       .isInstanceOf(BadRequestException.class)
694       .hasMessageContaining("Cannot deactivate inherited rule");
695     verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), any(), eq(parentProfile.getLanguage()));
696   }
697
698   @Test
699   public void reset_child_profile_do_not_change_parent() {
700     RuleDefinitionDto rule = createRule();
701     QProfileDto parentProfile = createProfile(rule);
702     QProfileDto childProfile = createChildProfile(parentProfile);
703
704     RuleActivation activation = RuleActivation.create(rule.getUuid(), CRITICAL, null);
705     List<ActiveRuleChange> changes = activate(parentProfile, activation);
706     assertThatRuleIsActivated(parentProfile, rule, changes, CRITICAL, null, emptyMap());
707     assertThatRuleIsActivated(childProfile, rule, changes, CRITICAL, INHERITED, emptyMap());
708     assertThat(changes).hasSize(2);
709
710     RuleActivation childActivation = RuleActivation.create(rule.getUuid(), BLOCKER, null);
711     changes = activate(childProfile, childActivation);
712     assertThatRuleIsUpdated(childProfile, rule, BLOCKER, ActiveRuleInheritance.OVERRIDES, emptyMap());
713     assertThat(changes).hasSize(1);
714
715     RuleActivation resetActivation = RuleActivation.createReset(rule.getUuid());
716     changes = activate(childProfile, resetActivation);
717     assertThatRuleIsUpdated(childProfile, rule, CRITICAL, INHERITED, emptyMap());
718     assertThatRuleIsUpdated(parentProfile, rule, CRITICAL, null, emptyMap());
719     assertThat(changes).hasSize(1);
720
721   }
722
723   @Test
724   public void reset_parent_is_not_propagated_when_child_overrides() {
725     RuleDefinitionDto rule = createRule();
726     QProfileDto baseProfile = createProfile(rule);
727     QProfileDto childProfile = createChildProfile(baseProfile);
728     QProfileDto grandChildProfile = createChildProfile(childProfile);
729
730     RuleActivation activation = RuleActivation.create(rule.getUuid(), CRITICAL, null);
731     List<ActiveRuleChange> changes = activate(baseProfile, activation);
732     assertThatRuleIsActivated(baseProfile, rule, changes, CRITICAL, null, emptyMap());
733     assertThatRuleIsActivated(childProfile, rule, changes, CRITICAL, INHERITED, emptyMap());
734     assertThatRuleIsActivated(grandChildProfile, rule, changes, CRITICAL, INHERITED, emptyMap());
735     assertThat(changes).hasSize(3);
736
737     RuleActivation childActivation = RuleActivation.create(rule.getUuid(), BLOCKER, null);
738     changes = activate(childProfile, childActivation);
739     assertThatRuleIsUpdated(childProfile, rule, BLOCKER, ActiveRuleInheritance.OVERRIDES, emptyMap());
740     assertThatRuleIsUpdated(grandChildProfile, rule, BLOCKER, INHERITED, emptyMap());
741     assertThat(changes).hasSize(2);
742
743     // Reset on parent do not change child nor grandchild
744     RuleActivation resetActivation = RuleActivation.createReset(rule.getUuid());
745     changes = activate(baseProfile, resetActivation);
746     assertThatRuleIsUpdated(baseProfile, rule, rule.getSeverityString(), null, emptyMap());
747     assertThatRuleIsUpdated(childProfile, rule, BLOCKER, ActiveRuleInheritance.OVERRIDES, emptyMap());
748     assertThatRuleIsUpdated(grandChildProfile, rule, BLOCKER, INHERITED, emptyMap());
749     assertThat(changes).hasSize(1);
750
751     // Reset on child change grandchild
752     resetActivation = RuleActivation.createReset(rule.getUuid());
753     changes = activate(childProfile, resetActivation);
754     assertThatRuleIsUpdated(baseProfile, rule, rule.getSeverityString(), null, emptyMap());
755     assertThatRuleIsUpdated(childProfile, rule, rule.getSeverityString(), INHERITED, emptyMap());
756     assertThatRuleIsUpdated(grandChildProfile, rule, rule.getSeverityString(), INHERITED, emptyMap());
757     assertThat(changes).hasSize(2);
758   }
759
760   @Test
761   public void ignore_reset_if_not_activated() {
762     RuleDefinitionDto rule = createRule();
763     QProfileDto parentProfile = createProfile(rule);
764     createChildProfile(parentProfile);
765
766     RuleActivation resetActivation = RuleActivation.createReset(rule.getUuid());
767     List<ActiveRuleChange> changes = activate(parentProfile, resetActivation);
768     verifyNoActiveRules();
769     assertThat(changes).isEmpty();
770   }
771
772   @Test
773   public void bulk_activation() {
774     int bulkSize = SearchOptions.MAX_PAGE_SIZE + 10 + new Random().nextInt(100);
775     String language = randomAlphanumeric(10);
776     String repositoryKey = randomAlphanumeric(10);
777     QProfileDto profile = db.qualityProfiles().insert(p -> p.setLanguage(language));
778
779     List<RuleDto> rules = new ArrayList<>();
780     IntStream.rangeClosed(1, bulkSize).forEach(
781       i -> rules.add(db.rules().insertRule(r -> r.setLanguage(language).setRepositoryKey(repositoryKey))));
782
783     verifyNoActiveRules();
784     ruleIndexer.indexAll();
785
786     RuleQuery ruleQuery = new RuleQuery()
787       .setRepositories(singletonList(repositoryKey));
788
789     BulkChangeResult bulkChangeResult = underTest.bulkActivateAndCommit(db.getSession(), profile, ruleQuery, MINOR);
790
791     assertThat(bulkChangeResult.countFailed()).isZero();
792     assertThat(bulkChangeResult.countSucceeded()).isEqualTo(bulkSize);
793     assertThat(bulkChangeResult.getChanges()).hasSize(bulkSize);
794     assertThat(db.getDbClient().activeRuleDao().selectByProfile(db.getSession(), profile)).hasSize(bulkSize);
795     rules.stream().forEach(
796       r -> assertThatRuleIsActivated(profile, r.getDefinition(), null, MINOR, null, emptyMap()));
797   }
798
799   @Test
800   public void bulk_deactivation() {
801     int bulkSize = SearchOptions.MAX_PAGE_SIZE + 10 + new Random().nextInt(100);
802     String language = randomAlphanumeric(10);
803     String repositoryKey = randomAlphanumeric(10);
804     QProfileDto profile = db.qualityProfiles().insert(p -> p.setLanguage(language));
805
806     List<RuleDto> rules = new ArrayList<>();
807     IntStream.rangeClosed(1, bulkSize).forEach(
808       i -> rules.add(db.rules().insertRule(r -> r.setLanguage(language).setRepositoryKey(repositoryKey))));
809
810     verifyNoActiveRules();
811     ruleIndexer.indexAll();
812
813     RuleQuery ruleQuery = new RuleQuery()
814       .setRepositories(singletonList(repositoryKey));
815
816     BulkChangeResult bulkChangeResult = underTest.bulkActivateAndCommit(db.getSession(), profile, ruleQuery, MINOR);
817
818     assertThat(bulkChangeResult.countFailed()).isZero();
819     assertThat(bulkChangeResult.countSucceeded()).isEqualTo(bulkSize);
820     assertThat(bulkChangeResult.getChanges()).hasSize(bulkSize);
821     assertThat(db.getDbClient().activeRuleDao().selectByProfile(db.getSession(), profile)).hasSize(bulkSize);
822
823     // Now deactivate all rules
824     bulkChangeResult = underTest.bulkDeactivateAndCommit(db.getSession(), profile, ruleQuery);
825
826     assertThat(bulkChangeResult.countFailed()).isZero();
827     assertThat(bulkChangeResult.countSucceeded()).isEqualTo(bulkSize);
828     assertThat(bulkChangeResult.getChanges()).hasSize(bulkSize);
829     assertThat(db.getDbClient().activeRuleDao().selectByProfile(db.getSession(), profile)).isEmpty();
830     rules.stream().forEach(
831       r -> assertThatRuleIsNotPresent(profile, r.getDefinition()));
832   }
833
834   @Test
835   public void bulk_deactivation_ignores_errors() {
836     RuleDefinitionDto rule = createRule();
837     QProfileDto parentProfile = createProfile(rule);
838     QProfileDto childProfile = createChildProfile(parentProfile);
839
840     List<ActiveRuleChange> changes = activate(parentProfile, RuleActivation.create(rule.getUuid()));
841     assertThatRuleIsActivated(parentProfile, rule, null, rule.getSeverityString(), null, emptyMap());
842     assertThatRuleIsActivated(childProfile, rule, null, rule.getSeverityString(), INHERITED, emptyMap());
843
844     ruleIndexer.indexAll();
845
846     RuleQuery ruleQuery = new RuleQuery()
847       .setQProfile(childProfile);
848     BulkChangeResult bulkChangeResult = underTest.bulkDeactivateAndCommit(db.getSession(), childProfile, ruleQuery);
849
850     assertThat(bulkChangeResult.countFailed()).isOne();
851     assertThat(bulkChangeResult.countSucceeded()).isZero();
852     assertThat(bulkChangeResult.getChanges()).isEmpty();
853     assertThatRuleIsActivated(parentProfile, rule, null, rule.getSeverityString(), null, emptyMap());
854     assertThatRuleIsActivated(childProfile, rule, null, rule.getSeverityString(), INHERITED, emptyMap());
855   }
856
857   @Test
858   public void bulk_change_severity() {
859     RuleDefinitionDto rule1 = createJavaRule();
860     RuleDefinitionDto rule2 = createJavaRule();
861     QProfileDto parentProfile = createProfile(rule1);
862     QProfileDto childProfile = createChildProfile(parentProfile);
863     QProfileDto grandchildProfile = createChildProfile(childProfile);
864
865     activate(parentProfile, RuleActivation.create(rule1.getUuid()));
866     activate(parentProfile, RuleActivation.create(rule2.getUuid()));
867
868     ruleIndexer.indexAll();
869
870     RuleQuery query = new RuleQuery()
871       .setRuleKey(rule1.getRuleKey())
872       .setQProfile(parentProfile);
873     BulkChangeResult result = underTest.bulkActivateAndCommit(db.getSession(), parentProfile, query, "BLOCKER");
874
875     assertThat(result.getChanges()).hasSize(3);
876     assertThat(result.countSucceeded()).isOne();
877     assertThat(result.countFailed()).isZero();
878
879     // Rule1 must be activated with BLOCKER on all profiles
880     assertThatRuleIsActivated(parentProfile, rule1, null, BLOCKER, null, emptyMap());
881     assertThatRuleIsActivated(childProfile, rule1, null, BLOCKER, INHERITED, emptyMap());
882     assertThatRuleIsActivated(grandchildProfile, rule1, null, BLOCKER, INHERITED, emptyMap());
883
884     // Rule2 did not changed
885     assertThatRuleIsActivated(parentProfile, rule2, null, rule2.getSeverityString(), null, emptyMap());
886     assertThatRuleIsActivated(childProfile, rule2, null, rule2.getSeverityString(), INHERITED, emptyMap());
887     assertThatRuleIsActivated(grandchildProfile, rule2, null, rule2.getSeverityString(), INHERITED, emptyMap());
888   }
889
890   @Test
891   public void delete_rule_from_all_profiles() {
892     RuleDefinitionDto rule = createRule();
893     QProfileDto parentProfile = createProfile(rule);
894     QProfileDto childProfile = createChildProfile(parentProfile);
895     QProfileDto grandChildProfile = createChildProfile(childProfile);
896
897     RuleActivation activation = RuleActivation.create(rule.getUuid(), CRITICAL, null);
898     activate(parentProfile, activation);
899
900     RuleActivation overrideActivation = RuleActivation.create(rule.getUuid(), BLOCKER, null);
901     activate(grandChildProfile, overrideActivation);
902
903     // Reset on parent do not change child nor grandchild
904     List<ActiveRuleChange> changes = underTest.deleteRule(db.getSession(), rule);
905
906     assertThatRuleIsNotPresent(parentProfile, rule);
907     assertThatRuleIsNotPresent(childProfile, rule);
908     assertThatRuleIsNotPresent(grandChildProfile, rule);
909     assertThat(changes)
910       .extracting(ActiveRuleChange::getType)
911       .containsOnly(ActiveRuleChange.Type.DEACTIVATED)
912       .hasSize(3);
913   }
914
915   @Test
916   public void activation_fails_when_profile_is_built_in() {
917     RuleDefinitionDto rule = createRule();
918     QProfileDto builtInProfile = db.qualityProfiles().insert(p -> p.setLanguage(rule.getLanguage()).setIsBuiltIn(true));
919
920     assertThatThrownBy(() -> {
921       underTest.activateAndCommit(db.getSession(), builtInProfile, singleton(RuleActivation.create(rule.getUuid())));
922     })
923       .isInstanceOf(IllegalArgumentException.class)
924       .hasMessage("The built-in profile " + builtInProfile.getName() + " is read-only and can't be updated");
925   }
926
927   private void assertThatProfileHasNoActiveRules(QProfileDto profile) {
928     List<OrgActiveRuleDto> activeRules = db.getDbClient().activeRuleDao().selectByProfile(db.getSession(), profile);
929     assertThat(activeRules).isEmpty();
930   }
931
932   private List<ActiveRuleChange> deactivate(QProfileDto profile, RuleDefinitionDto rule) {
933     return underTest.deactivateAndCommit(db.getSession(), profile, singleton(rule.getUuid()));
934   }
935
936   private List<ActiveRuleChange> activate(QProfileDto profile, RuleActivation activation) {
937     return underTest.activateAndCommit(db.getSession(), profile, singleton(activation));
938   }
939
940   private QProfileDto createProfile(RuleDefinitionDto rule) {
941     return db.qualityProfiles().insert(p -> p.setLanguage(rule.getLanguage()));
942   }
943
944   private QProfileDto createChildProfile(QProfileDto parent) {
945     return db.qualityProfiles().insert(p -> p
946       .setLanguage(parent.getLanguage())
947       .setParentKee(parent.getKee())
948       .setName("Child of " + parent.getName()));
949   }
950
951   private void assertThatProfileIsUpdatedByUser(QProfileDto profile) {
952     QProfileDto loaded = db.getDbClient().qualityProfileDao().selectByUuid(db.getSession(), profile.getKee());
953     assertThat(loaded.getUserUpdatedAt()).isNotNull();
954     assertThat(loaded.getRulesUpdatedAt()).isNotEmpty();
955   }
956
957   private void assertThatProfileIsUpdatedBySystem(QProfileDto profile) {
958     QProfileDto loaded = db.getDbClient().qualityProfileDao().selectByUuid(db.getSession(), profile.getKee());
959     assertThat(loaded.getUserUpdatedAt()).isNull();
960     assertThat(loaded.getRulesUpdatedAt()).isNotEmpty();
961   }
962
963   private void assertThatRuleIsActivated(QProfileDto profile, RuleDefinitionDto rule, @Nullable List<ActiveRuleChange> changes,
964     String expectedSeverity, @Nullable ActiveRuleInheritance expectedInheritance, Map<String, String> expectedParams) {
965     OrgActiveRuleDto activeRule = db.getDbClient().activeRuleDao().selectByProfile(db.getSession(), profile)
966       .stream()
967       .filter(ar -> ar.getRuleKey().equals(rule.getKey()))
968       .findFirst()
969       .orElseThrow(IllegalStateException::new);
970
971     assertThat(activeRule.getSeverityString()).isEqualTo(expectedSeverity);
972     assertThat(activeRule.getInheritance()).isEqualTo(expectedInheritance != null ? expectedInheritance.name() : null);
973
974     List<ActiveRuleParamDto> params = db.getDbClient().activeRuleDao().selectParamsByActiveRuleUuid(db.getSession(), activeRule.getUuid());
975     assertThat(params).hasSize(expectedParams.size());
976
977     if (changes != null) {
978       ActiveRuleChange change = changes.stream()
979         .filter(c -> c.getActiveRule().getUuid().equals(activeRule.getUuid()))
980         .findFirst().orElseThrow(IllegalStateException::new);
981       assertThat(change.getInheritance()).isEqualTo(expectedInheritance);
982       assertThat(change.getSeverity()).isEqualTo(expectedSeverity);
983       assertThat(change.getType()).isEqualTo(ActiveRuleChange.Type.ACTIVATED);
984     }
985   }
986
987   private void assertThatRuleIsNotPresent(QProfileDto profile, RuleDefinitionDto rule) {
988     Optional<OrgActiveRuleDto> activeRule = db.getDbClient().activeRuleDao().selectByProfile(db.getSession(), profile)
989       .stream()
990       .filter(ar -> ar.getRuleKey().equals(rule.getKey()))
991       .findFirst();
992
993     assertThat(activeRule).isEmpty();
994   }
995
996   private void assertThatRuleIsUpdated(QProfileDto profile, RuleDefinitionDto rule,
997     String expectedSeverity, @Nullable ActiveRuleInheritance expectedInheritance, Map<String, String> expectedParams) {
998     OrgActiveRuleDto activeRule = db.getDbClient().activeRuleDao().selectByProfile(db.getSession(), profile)
999       .stream()
1000       .filter(ar -> ar.getRuleKey().equals(rule.getKey()))
1001       .findFirst()
1002       .orElseThrow(IllegalStateException::new);
1003
1004     assertThat(activeRule.getSeverityString()).isEqualTo(expectedSeverity);
1005     assertThat(activeRule.getInheritance()).isEqualTo(expectedInheritance != null ? expectedInheritance.name() : null);
1006
1007     List<ActiveRuleParamDto> params = db.getDbClient().activeRuleDao().selectParamsByActiveRuleUuid(db.getSession(), activeRule.getUuid());
1008     assertThat(params).hasSize(expectedParams.size());
1009   }
1010
1011   private void expectFailure(String expectedMessage, Runnable runnable) {
1012     try {
1013       runnable.run();
1014       fail();
1015     } catch (BadRequestException e) {
1016       assertThat(e.getMessage()).isEqualTo(expectedMessage);
1017     }
1018     verifyNoActiveRules();
1019   }
1020
1021   private void verifyNoActiveRules() {
1022     assertThat(db.countRowsOfTable(db.getSession(), "active_rules")).isZero();
1023   }
1024
1025   private RuleDefinitionDto createRule() {
1026     return db.rules().insert(r -> r.setSeverity(Severity.MAJOR));
1027   }
1028
1029   private RuleDefinitionDto createJavaRule() {
1030     return db.rules().insert(r -> r.setSeverity(Severity.MAJOR).setLanguage("java"));
1031   }
1032 }