]> source.dussan.org Git - sonarqube.git/blob
7caf79e84ea07691e7dda84c5bfeea468637a585
[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.ws;
21
22 import java.util.Collections;
23 import java.util.List;
24 import org.junit.Before;
25 import org.junit.Rule;
26 import org.junit.Test;
27 import org.sonar.api.resources.Language;
28 import org.sonar.api.resources.Languages;
29 import org.sonar.api.rule.RuleKey;
30 import org.sonar.api.rule.RuleStatus;
31 import org.sonar.api.rule.Severity;
32 import org.sonar.api.server.ws.WebService;
33 import org.sonar.api.server.ws.WebService.Param;
34 import org.sonar.api.utils.System2;
35 import org.sonar.db.DbClient;
36 import org.sonar.db.DbSession;
37 import org.sonar.db.DbTester;
38 import org.sonar.db.qualityprofile.ActiveRuleDto;
39 import org.sonar.db.qualityprofile.OrgActiveRuleDto;
40 import org.sonar.db.qualityprofile.QProfileDto;
41 import org.sonar.db.qualityprofile.QualityProfileTesting;
42 import org.sonar.db.rule.RuleDefinitionDto;
43 import org.sonar.db.rule.RuleTesting;
44 import org.sonar.db.user.UserDto;
45 import org.sonar.server.es.EsClient;
46 import org.sonar.server.es.EsTester;
47 import org.sonar.server.es.SearchOptions;
48 import org.sonar.server.exceptions.BadRequestException;
49 import org.sonar.server.exceptions.ForbiddenException;
50 import org.sonar.server.language.LanguageTesting;
51 import org.sonar.server.qualityprofile.QProfileTreeImpl;
52 import org.sonar.server.qualityprofile.RuleActivator;
53 import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
54 import org.sonar.server.rule.index.RuleIndex;
55 import org.sonar.server.rule.index.RuleIndexer;
56 import org.sonar.server.rule.index.RuleQuery;
57 import org.sonar.server.tester.UserSessionRule;
58 import org.sonar.server.util.TypeValidations;
59 import org.sonar.server.ws.TestRequest;
60 import org.sonar.server.ws.WsActionTester;
61 import org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters;
62
63 import static java.util.Arrays.asList;
64 import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
65 import static org.assertj.core.api.Assertions.assertThat;
66 import static org.assertj.core.api.Assertions.assertThatThrownBy;
67 import static org.sonar.db.permission.GlobalPermission.ADMINISTER_QUALITY_PROFILES;
68 import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_LANGUAGE;
69 import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_PARENT_QUALITY_PROFILE;
70 import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_QUALITY_PROFILE;
71
72 public class ChangeParentActionTest {
73
74   @Rule
75   public DbTester db = DbTester.create(System2.INSTANCE);
76   @Rule
77   public EsTester es = EsTester.create();
78   @Rule
79   public UserSessionRule userSession = UserSessionRule.standalone();
80
81   private DbClient dbClient;
82   private DbSession dbSession;
83   private RuleIndex ruleIndex;
84   private RuleIndexer ruleIndexer;
85   private ActiveRuleIndexer activeRuleIndexer;
86   private WsActionTester ws;
87   private Language language = LanguageTesting.newLanguage(randomAlphanumeric(20));
88   private String ruleRepository = randomAlphanumeric(5);
89   private QProfileTreeImpl qProfileTree;
90
91   @Before
92   public void setUp() {
93     dbClient = db.getDbClient();
94     dbSession = db.getSession();
95     EsClient esClient = es.client();
96     ruleIndex = new RuleIndex(esClient, System2.INSTANCE);
97     ruleIndexer = new RuleIndexer(esClient, dbClient);
98     activeRuleIndexer = new ActiveRuleIndexer(dbClient, esClient);
99     TypeValidations typeValidations = new TypeValidations(Collections.emptyList());
100     RuleActivator ruleActivator = new RuleActivator(System2.INSTANCE, dbClient, typeValidations, userSession);
101     qProfileTree = new QProfileTreeImpl(dbClient, ruleActivator, System2.INSTANCE, activeRuleIndexer);
102     ChangeParentAction underTest = new ChangeParentAction(
103       dbClient,
104       qProfileTree,
105       new Languages(),
106       new QProfileWsSupport(
107         dbClient,
108         userSession),
109       userSession);
110
111     ws = new WsActionTester(underTest);
112     userSession.logIn().addPermission(ADMINISTER_QUALITY_PROFILES);
113   }
114
115   @Test
116   public void definition() {
117     WebService.Action definition = ws.getDef();
118     assertThat(definition.isPost()).isTrue();
119     assertThat(definition.params()).extracting(Param::key).containsExactlyInAnyOrder(
120       "qualityProfile", "language", "parentQualityProfile");
121   }
122
123   @Test
124   public void change_parent_with_no_parent_before() {
125     QProfileDto parent1 = createProfile();
126     QProfileDto child = createProfile();
127
128     RuleDefinitionDto rule1 = createRule();
129     createActiveRule(rule1, parent1);
130     ruleIndexer.commitAndIndex(dbSession, rule1.getUuid());
131     activeRuleIndexer.indexAll();
132
133     assertThat(dbClient.activeRuleDao().selectByProfileUuid(dbSession, child.getKee())).isEmpty();
134
135     // Set parent
136     ws.newRequest()
137       .setMethod("POST")
138       .setParam(PARAM_LANGUAGE, child.getLanguage())
139       .setParam(PARAM_QUALITY_PROFILE, child.getName())
140       .setParam(PARAM_PARENT_QUALITY_PROFILE, parent1.getName())
141       .execute();
142
143     // Check rule 1 enabled
144     List<OrgActiveRuleDto> activeRules1 = dbClient.activeRuleDao().selectByProfile(dbSession, child);
145     assertThat(activeRules1).hasSize(1);
146     assertThat(activeRules1.get(0).getKey().getRuleKey().rule()).isEqualTo(rule1.getRuleKey());
147
148     assertThat(ruleIndex.search(new RuleQuery().setActivation(true).setQProfile(child), new SearchOptions()).getUuids()).hasSize(1);
149   }
150
151   @Test
152   public void replace_existing_parent() {
153     QProfileDto parent1 = createProfile();
154     QProfileDto parent2 = createProfile();
155     QProfileDto child = createProfile();
156
157     RuleDefinitionDto rule1 = createRule();
158     RuleDefinitionDto rule2 = createRule();
159     createActiveRule(rule1, parent1);
160     createActiveRule(rule2, parent2);
161     ruleIndexer.commitAndIndex(dbSession, asList(rule1.getUuid(), rule2.getUuid()));
162     activeRuleIndexer.indexAll();
163
164     // Set parent 1
165     qProfileTree.setParentAndCommit(dbSession, child, parent1);
166
167     // Set parent 2 through WS
168     ws.newRequest()
169       .setMethod("POST")
170       .setParam(PARAM_LANGUAGE, child.getLanguage())
171       .setParam(PARAM_QUALITY_PROFILE, child.getName())
172       .setParam(PARAM_PARENT_QUALITY_PROFILE, parent2.getName())
173       .execute();
174
175     // Check rule 2 enabled
176     List<OrgActiveRuleDto> activeRules2 = dbClient.activeRuleDao().selectByProfile(dbSession, child);
177     assertThat(activeRules2).hasSize(1);
178     assertThat(activeRules2.get(0).getKey().getRuleKey().rule()).isEqualTo(rule2.getRuleKey());
179
180     assertThat(ruleIndex.search(new RuleQuery().setActivation(true).setQProfile(child), new SearchOptions()).getUuids()).hasSize(1);
181   }
182
183   @Test
184   public void remove_parent() {
185     QProfileDto parent = createProfile();
186     QProfileDto child = createProfile();
187
188     RuleDefinitionDto rule1 = createRule();
189     createActiveRule(rule1, parent);
190     ruleIndexer.commitAndIndex(dbSession, rule1.getUuid());
191     activeRuleIndexer.indexAll();
192
193     // Set parent
194     qProfileTree.setParentAndCommit(dbSession, child, parent);
195
196     // Remove parent through WS
197     ws.newRequest()
198       .setMethod("POST")
199       .setParam(PARAM_LANGUAGE, child.getLanguage())
200       .setParam(PARAM_QUALITY_PROFILE, child.getName())
201       .execute();
202
203     // Check no rule enabled
204     assertThat(dbClient.activeRuleDao().selectByProfile(dbSession, child)).isEmpty();
205
206     assertThat(ruleIndex.search(new RuleQuery().setActivation(true).setQProfile(child), new SearchOptions()).getUuids()).isEmpty();
207   }
208
209   @Test
210   public void change_parent_with_names() {
211     QProfileDto parent1 = createProfile();
212     QProfileDto parent2 = createProfile();
213     QProfileDto child = createProfile();
214
215     RuleDefinitionDto rule1 = createRule();
216     RuleDefinitionDto rule2 = createRule();
217     createActiveRule(rule1, parent1);
218     createActiveRule(rule2, parent2);
219     ruleIndexer.commitAndIndex(dbSession, rule1.getUuid());
220     activeRuleIndexer.indexAll();
221
222     assertThat(dbClient.activeRuleDao().selectByProfileUuid(dbSession, child.getKee())).isEmpty();
223
224     // 1. Set parent 1
225     ws.newRequest()
226       .setMethod("POST")
227       .setParam(PARAM_LANGUAGE, child.getLanguage())
228       .setParam(PARAM_QUALITY_PROFILE, child.getName())
229       .setParam(PARAM_PARENT_QUALITY_PROFILE, parent1.getName())
230       .execute();
231
232     // 1. check rule 1 enabled
233     List<OrgActiveRuleDto> activeRules1 = dbClient.activeRuleDao().selectByProfile(dbSession, child);
234     assertThat(activeRules1).hasSize(1);
235     assertThat(activeRules1.get(0).getKey().getRuleKey().rule()).isEqualTo(rule1.getRuleKey());
236     assertThat(ruleIndex.search(new RuleQuery().setActivation(true).setQProfile(child), new SearchOptions()).getUuids()).hasSize(1);
237
238     // 2. Set parent 2
239     ws.newRequest()
240       .setMethod("POST")
241       .setParam(PARAM_LANGUAGE, child.getLanguage())
242       .setParam(PARAM_QUALITY_PROFILE, child.getName())
243       .setParam(QualityProfileWsParameters.PARAM_PARENT_QUALITY_PROFILE, parent2.getName())
244       .execute();
245
246     // 2. check rule 2 enabled
247     List<OrgActiveRuleDto> activeRules2 = dbClient.activeRuleDao().selectByProfile(dbSession, child);
248     assertThat(activeRules2).hasSize(1);
249     assertThat(activeRules2.get(0).getKey().getRuleKey().rule()).isEqualTo(rule2.getRuleKey());
250
251     // 3. Remove parent
252     ws.newRequest()
253       .setMethod("POST")
254       .setParam(PARAM_LANGUAGE, child.getLanguage())
255       .setParam(PARAM_QUALITY_PROFILE, child.getName())
256       .setParam(QualityProfileWsParameters.PARAM_PARENT_QUALITY_PROFILE, "")
257       .execute();
258
259     // 3. check no rule enabled
260     List<OrgActiveRuleDto> activeRules = dbClient.activeRuleDao().selectByProfile(dbSession, child);
261     assertThat(activeRules).isEmpty();
262     assertThat(ruleIndex.search(new RuleQuery().setActivation(true).setQProfile(child), new SearchOptions()).getUuids()).isEmpty();
263   }
264
265   @Test
266   public void remove_parent_with_empty_key() {
267     QProfileDto parent = createProfile();
268     QProfileDto child = createProfile();
269
270     RuleDefinitionDto rule1 = createRule();
271     createActiveRule(rule1, parent);
272     ruleIndexer.commitAndIndex(dbSession, rule1.getUuid());
273     activeRuleIndexer.indexAll();
274
275     assertThat(dbClient.activeRuleDao().selectByProfileUuid(dbSession, child.getKee())).isEmpty();
276
277     // Set parent
278     qProfileTree.setParentAndCommit(dbSession, child, parent);
279
280     // Remove parent
281     ws.newRequest()
282       .setMethod("POST")
283       .setParam(PARAM_LANGUAGE, child.getLanguage())
284       .setParam(PARAM_QUALITY_PROFILE, child.getName())
285       .setParam(PARAM_PARENT_QUALITY_PROFILE, "")
286       .execute();
287
288     // Check no rule enabled
289     assertThat(dbClient.activeRuleDao().selectByProfile(dbSession, child)).isEmpty();
290     assertThat(ruleIndex.search(new RuleQuery().setActivation(true).setQProfile(child), new SearchOptions()).getUuids()).isEmpty();
291   }
292
293   @Test
294   public void as_qprofile_editor() {
295     QProfileDto parent1 = createProfile();
296     QProfileDto parent2 = createProfile();
297     QProfileDto child = createProfile();
298
299     RuleDefinitionDto rule1 = createRule();
300     RuleDefinitionDto rule2 = createRule();
301     createActiveRule(rule1, parent1);
302     createActiveRule(rule2, parent2);
303     ruleIndexer.commitAndIndex(dbSession, asList(rule1.getUuid(), rule2.getUuid()));
304     activeRuleIndexer.indexAll();
305     // Set parent 1
306     qProfileTree.setParentAndCommit(dbSession, child, parent1);
307     UserDto user = db.users().insertUser();
308     db.qualityProfiles().addUserPermission(child, user);
309     userSession.logIn(user);
310
311     ws.newRequest()
312       .setMethod("POST")
313       .setParam(PARAM_LANGUAGE, child.getLanguage())
314       .setParam(PARAM_QUALITY_PROFILE, child.getName())
315       .setParam(PARAM_PARENT_QUALITY_PROFILE, parent2.getName())
316       .execute();
317
318     List<OrgActiveRuleDto> activeRules2 = dbClient.activeRuleDao().selectByProfile(dbSession, child);
319     assertThat(activeRules2).hasSize(1);
320     assertThat(activeRules2.get(0).getKey().getRuleKey().rule()).isEqualTo(rule2.getRuleKey());
321
322     assertThat(ruleIndex.search(new RuleQuery().setActivation(true).setQProfile(child), new SearchOptions()).getUuids()).hasSize(1);
323   }
324
325   @Test
326   public void fail_if_built_in_profile() {
327     QProfileDto child = db.qualityProfiles().insert(p -> p
328       .setLanguage(language.getKey())
329       .setIsBuiltIn(true));
330
331     assertThat(dbClient.activeRuleDao().selectByProfileUuid(dbSession, child.getKee())).isEmpty();
332     assertThat(ruleIndex.search(new RuleQuery().setActivation(true).setQProfile(child), new SearchOptions()).getUuids()).isEmpty();
333
334     TestRequest request = ws.newRequest()
335       .setMethod("POST")
336       .setParam(PARAM_LANGUAGE, child.getLanguage())
337       .setParam(PARAM_QUALITY_PROFILE, child.getName())
338       .setParam(PARAM_PARENT_QUALITY_PROFILE, "palap");
339
340     assertThatThrownBy(request::execute)
341       .isInstanceOf(BadRequestException.class);
342   }
343
344   @Test
345   public void fail_if_missing_permission() {
346     userSession.logIn(db.users().insertUser());
347
348     QProfileDto child = createProfile();
349
350     TestRequest request = ws.newRequest()
351       .setMethod("POST")
352       .setParam(PARAM_LANGUAGE, child.getLanguage())
353       .setParam(PARAM_QUALITY_PROFILE, child.getName());
354
355     assertThatThrownBy(request::execute)
356       .isInstanceOf(ForbiddenException.class)
357       .hasMessage("Insufficient privileges");
358   }
359
360   private QProfileDto createProfile() {
361     QProfileDto profile = QualityProfileTesting.newQualityProfileDto()
362       .setLanguage(language.getKey());
363     dbClient.qualityProfileDao().insert(dbSession, profile);
364     dbSession.commit();
365     return profile;
366   }
367
368   private RuleDefinitionDto createRule() {
369     RuleDefinitionDto rule = RuleTesting.newRule(RuleKey.of(ruleRepository, randomAlphanumeric(5)))
370       .setLanguage(language.getKey())
371       .setSeverity(Severity.BLOCKER)
372       .setStatus(RuleStatus.READY);
373     dbClient.ruleDao().insert(dbSession, rule);
374     dbSession.commit();
375     return rule;
376   }
377
378   private ActiveRuleDto createActiveRule(RuleDefinitionDto rule, QProfileDto profile) {
379     ActiveRuleDto activeRule = ActiveRuleDto.createFor(profile, rule)
380       .setSeverity(rule.getSeverityString());
381     dbClient.activeRuleDao().insert(dbSession, activeRule);
382     dbSession.commit();
383     return activeRule;
384   }
385 }