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