3 * Copyright (C) 2009-2024 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.ws;
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;
67 import static java.util.Arrays.asList;
68 import static org.apache.commons.lang3.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;
77 public class ChangeParentActionIT {
80 public DbTester db = DbTester.create(System2.INSTANCE);
82 public EsTester es = EsTester.create();
84 public UserSessionRule userSession = UserSessionRule.standalone();
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;
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(
113 new QProfileWsSupport(
118 ws = new WsActionTester(underTest);
119 userSession.logIn().addPermission(ADMINISTER_QUALITY_PROFILES);
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");
131 public void change_parent_with_no_parent_before() {
132 QProfileDto parent1 = createProfile();
133 QProfileDto child = createProfile();
135 RuleDto rule1 = createRule();
136 createActiveRule(rule1, parent1);
137 ruleIndexer.commitAndIndex(dbSession, rule1.getUuid());
138 activeRuleIndexer.indexAll();
140 assertThat(dbClient.activeRuleDao().selectByProfileUuid(dbSession, child.getKee())).isEmpty();
145 .setParam(PARAM_LANGUAGE, child.getLanguage())
146 .setParam(PARAM_QUALITY_PROFILE, child.getName())
147 .setParam(PARAM_PARENT_QUALITY_PROFILE, parent1.getName())
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());
155 assertThat(ruleIndex.search(new RuleQuery().setActivation(true).setQProfile(child), new SearchOptions()).getUuids()).hasSize(1);
159 public void replace_existing_parent() {
160 QProfileDto parent1 = createProfile();
161 QProfileDto parent2 = createProfile();
162 QProfileDto child = createProfile();
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();
172 qProfileTree.setParentAndCommit(dbSession, child, parent1);
174 // Set parent 2 through WS
177 .setParam(PARAM_LANGUAGE, child.getLanguage())
178 .setParam(PARAM_QUALITY_PROFILE, child.getName())
179 .setParam(PARAM_PARENT_QUALITY_PROFILE, parent2.getName())
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());
187 assertThat(ruleIndex.search(new RuleQuery().setActivation(true).setQProfile(child), new SearchOptions()).getUuids()).hasSize(1);
191 public void remove_parent() {
192 QProfileDto parent = createProfile();
193 QProfileDto child = createProfile();
195 RuleDto rule1 = createRule();
196 createActiveRule(rule1, parent);
197 ruleIndexer.commitAndIndex(dbSession, rule1.getUuid());
198 activeRuleIndexer.indexAll();
201 qProfileTree.setParentAndCommit(dbSession, child, parent);
203 // Remove parent through WS
206 .setParam(PARAM_LANGUAGE, child.getLanguage())
207 .setParam(PARAM_QUALITY_PROFILE, child.getName())
210 // Check no rule enabled
211 assertThat(dbClient.activeRuleDao().selectByProfile(dbSession, child)).isEmpty();
213 assertThat(ruleIndex.search(new RuleQuery().setActivation(true).setQProfile(child), new SearchOptions()).getUuids()).isEmpty();
217 public void change_parent_with_names() {
218 QProfileDto parent1 = createProfile();
219 QProfileDto parent2 = createProfile();
220 QProfileDto child = createProfile();
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();
229 assertThat(dbClient.activeRuleDao().selectByProfileUuid(dbSession, child.getKee())).isEmpty();
234 .setParam(PARAM_LANGUAGE, child.getLanguage())
235 .setParam(PARAM_QUALITY_PROFILE, child.getName())
236 .setParam(PARAM_PARENT_QUALITY_PROFILE, parent1.getName())
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);
248 .setParam(PARAM_LANGUAGE, child.getLanguage())
249 .setParam(PARAM_QUALITY_PROFILE, child.getName())
250 .setParam(QualityProfileWsParameters.PARAM_PARENT_QUALITY_PROFILE, parent2.getName())
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());
261 .setParam(PARAM_LANGUAGE, child.getLanguage())
262 .setParam(PARAM_QUALITY_PROFILE, child.getName())
263 .setParam(QualityProfileWsParameters.PARAM_PARENT_QUALITY_PROFILE, "")
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();
273 public void remove_parent_with_empty_key() {
274 QProfileDto parent = createProfile();
275 QProfileDto child = createProfile();
277 RuleDto rule1 = createRule();
278 createActiveRule(rule1, parent);
279 ruleIndexer.commitAndIndex(dbSession, rule1.getUuid());
280 activeRuleIndexer.indexAll();
282 assertThat(dbClient.activeRuleDao().selectByProfileUuid(dbSession, child.getKee())).isEmpty();
285 qProfileTree.setParentAndCommit(dbSession, child, parent);
290 .setParam(PARAM_LANGUAGE, child.getLanguage())
291 .setParam(PARAM_QUALITY_PROFILE, child.getName())
292 .setParam(PARAM_PARENT_QUALITY_PROFILE, "")
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();
301 public void as_qprofile_editor() {
302 QProfileDto parent1 = createProfile();
303 QProfileDto parent2 = createProfile();
304 QProfileDto child = createProfile();
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();
313 qProfileTree.setParentAndCommit(dbSession, child, parent1);
314 UserDto user = db.users().insertUser();
315 db.qualityProfiles().addUserPermission(child, user);
316 userSession.logIn(user);
320 .setParam(PARAM_LANGUAGE, child.getLanguage())
321 .setParam(PARAM_QUALITY_PROFILE, child.getName())
322 .setParam(PARAM_PARENT_QUALITY_PROFILE, parent2.getName())
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());
329 assertThat(ruleIndex.search(new RuleQuery().setActivation(true).setQProfile(child), new SearchOptions()).getUuids()).hasSize(1);
333 public void fail_if_built_in_profile() {
334 QProfileDto child = db.qualityProfiles().insert(p -> p
335 .setLanguage(language.getKey())
336 .setIsBuiltIn(true));
338 assertThat(dbClient.activeRuleDao().selectByProfileUuid(dbSession, child.getKee())).isEmpty();
339 assertThat(ruleIndex.search(new RuleQuery().setActivation(true).setQProfile(child), new SearchOptions()).getUuids()).isEmpty();
341 TestRequest request = ws.newRequest()
343 .setParam(PARAM_LANGUAGE, child.getLanguage())
344 .setParam(PARAM_QUALITY_PROFILE, child.getName())
345 .setParam(PARAM_PARENT_QUALITY_PROFILE, "palap");
347 assertThatThrownBy(request::execute)
348 .isInstanceOf(BadRequestException.class);
352 public void fail_if_missing_permission() {
353 userSession.logIn(db.users().insertUser());
355 QProfileDto child = createProfile();
357 TestRequest request = ws.newRequest()
359 .setParam(PARAM_LANGUAGE, child.getLanguage())
360 .setParam(PARAM_QUALITY_PROFILE, child.getName());
362 assertThatThrownBy(request::execute)
363 .isInstanceOf(ForbiddenException.class)
364 .hasMessage("Insufficient privileges");
367 private QProfileDto createProfile() {
368 QProfileDto profile = QualityProfileTesting.newQualityProfileDto()
369 .setLanguage(language.getKey());
370 dbClient.qualityProfileDao().insert(dbSession, profile);
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);
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);