]> source.dussan.org Git - sonarqube.git/blob
c185e40e7f909bc9e1ebd92640eaa48f94235450
[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.Collections;
23 import java.util.Set;
24 import org.assertj.core.api.AbstractObjectAssert;
25 import org.assertj.core.api.ThrowableAssert.ThrowingCallable;
26 import org.junit.Before;
27 import org.junit.Rule;
28 import org.junit.Test;
29 import org.mockito.ArgumentCaptor;
30 import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
31 import org.sonar.api.rule.Severity;
32 import org.sonar.api.utils.System2;
33 import org.sonar.core.util.SequenceUuidFactory;
34 import org.sonar.core.util.Uuids;
35 import org.sonar.db.DbSession;
36 import org.sonar.db.DbTester;
37 import org.sonar.db.project.ProjectDto;
38 import org.sonar.db.qualityprofile.ActiveRuleDto;
39 import org.sonar.db.qualityprofile.ActiveRuleParamDto;
40 import org.sonar.db.qualityprofile.OrgQProfileDto;
41 import org.sonar.db.qualityprofile.QProfileChangeDto;
42 import org.sonar.db.qualityprofile.QProfileDto;
43 import org.sonar.db.qualityprofile.RulesProfileDto;
44 import org.sonar.db.rule.RuleDefinitionDto;
45 import org.sonar.db.rule.RuleParamDto;
46 import org.sonar.db.user.GroupDto;
47 import org.sonar.db.user.UserDto;
48 import org.sonar.server.exceptions.BadRequestException;
49 import org.sonar.server.qualityprofile.builtin.QProfileName;
50 import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
51
52 import static java.util.Arrays.asList;
53 import static org.assertj.core.api.Assertions.assertThat;
54 import static org.assertj.core.api.Assertions.assertThatThrownBy;
55 import static org.mockito.ArgumentMatchers.any;
56 import static org.mockito.ArgumentMatchers.anyCollection;
57 import static org.mockito.Mockito.mock;
58 import static org.mockito.Mockito.never;
59 import static org.mockito.Mockito.verify;
60 import static org.mockito.Mockito.verifyNoInteractions;
61
62 public class QProfileFactoryImplTest {
63
64   private System2 system2 = new AlwaysIncreasingSystem2();
65
66   @Rule
67   public DbTester db = DbTester.create(system2);
68
69   private DbSession dbSession = db.getSession();
70   private ActiveRuleIndexer activeRuleIndexer = mock(ActiveRuleIndexer.class);
71   private QProfileFactory underTest = new QProfileFactoryImpl(db.getDbClient(), new SequenceUuidFactory(), system2, activeRuleIndexer);
72   private RuleDefinitionDto rule;
73   private RuleParamDto ruleParam;
74
75   @Before
76   public void setUp() {
77     rule = db.rules().insert();
78     ruleParam = db.rules().insertRuleParam(rule);
79   }
80
81   @Test
82   public void checkAndCreateCustom() {
83     QProfileDto profile = underTest.checkAndCreateCustom(dbSession, new QProfileName("xoo", "P1"));
84
85     assertThat(profile.getKee()).isNotEmpty();
86     assertThat(profile.getName()).isEqualTo("P1");
87     assertThat(profile.getLanguage()).isEqualTo("xoo");
88     assertThat(profile.getRulesProfileUuid()).isNotNull();
89     assertThat(profile.isBuiltIn()).isFalse();
90
91     QProfileDto reloaded = db.getDbClient().qualityProfileDao().selectByNameAndLanguage(dbSession, profile.getName(), profile.getLanguage());
92     assertEqual(profile, reloaded);
93     assertThat(db.getDbClient().qualityProfileDao().selectAll(dbSession)).extracting(QProfileDto::getKee).containsExactly(profile.getKee());
94   }
95
96   @Test
97   public void checkAndCreateCustom_throws_BadRequestException_if_name_null() {
98     QProfileName name = new QProfileName("xoo", null);
99
100     expectBadRequestException(() -> underTest.checkAndCreateCustom(dbSession, name), "quality_profiles.profile_name_cant_be_blank");
101   }
102
103   @Test
104   public void checkAndCreateCustom_throws_BadRequestException_if_name_empty() {
105     QProfileName name = new QProfileName("xoo", "");
106
107     expectBadRequestException(() -> underTest.checkAndCreateCustom(dbSession, name), "quality_profiles.profile_name_cant_be_blank");
108   }
109
110   @Test
111   public void checkAndCreateCustom_throws_BadRequestException_if_already_exists() {
112     QProfileName name = new QProfileName("xoo", "P1");
113
114     underTest.checkAndCreateCustom(dbSession, name);
115     dbSession.commit();
116
117     expectBadRequestException(() -> underTest.checkAndCreateCustom(dbSession, name), "Quality profile already exists: xoo/P1");
118   }
119
120   @Test
121   public void delete_custom_profiles() {
122     QProfileDto profile1 = createCustomProfile();
123     QProfileDto profile2 = createCustomProfile();
124     QProfileDto profile3 = createCustomProfile();
125
126     underTest.delete(dbSession, asList(profile1, profile2));
127
128     verifyCallActiveRuleIndexerDelete(profile1.getKee(), profile2.getKee());
129     assertThatCustomProfileDoesNotExist(profile1);
130     assertThatCustomProfileDoesNotExist(profile2);
131     assertThatCustomProfileExists(profile3);
132   }
133
134   @Test
135   public void delete_removes_custom_profile_marked_as_default() {
136     QProfileDto profile = createCustomProfile();
137     db.qualityProfiles().setAsDefault(profile);
138
139     underTest.delete(dbSession, asList(profile));
140
141     assertThatCustomProfileDoesNotExist(profile);
142   }
143
144   @Test
145   public void delete_removes_custom_profile_from_project_associations() {
146     QProfileDto profile = createCustomProfile();
147     ProjectDto project = db.components().insertPrivateProjectDto();
148     db.qualityProfiles().associateWithProject(project, profile);
149
150     underTest.delete(dbSession, asList(profile));
151
152     assertThatCustomProfileDoesNotExist(profile);
153   }
154
155   @Test
156   public void delete_builtin_profile() {
157     RulesProfileDto builtInProfile = createBuiltInProfile();
158     QProfileDto profile = associateBuiltInProfile(builtInProfile);
159
160     underTest.delete(dbSession, asList(profile));
161
162     verifyNoCallsActiveRuleIndexerDelete();
163
164     // remove only from org_qprofiles
165     assertThat(db.getDbClient().qualityProfileDao().selectAll(dbSession)).isEmpty();
166
167     assertThatRulesProfileExists(builtInProfile);
168   }
169
170   @Test
171   public void delete_builtin_profile_associated_to_project() {
172     RulesProfileDto builtInProfile = createBuiltInProfile();
173     ProjectDto project = db.components().insertPrivateProjectDto();
174     QProfileDto profile = associateBuiltInProfile(builtInProfile);
175     db.qualityProfiles().associateWithProject(project, profile);
176     assertThat(db.getDbClient().qualityProfileDao().selectAssociatedToProjectAndLanguage(dbSession, project, profile.getLanguage())).isNotNull();
177
178     underTest.delete(dbSession, asList(profile));
179
180     verifyNoCallsActiveRuleIndexerDelete();
181
182     // remove only from org_qprofiles and project_qprofiles
183     assertThat(db.getDbClient().qualityProfileDao().selectAll(dbSession)).isEmpty();
184     assertThat(db.getDbClient().qualityProfileDao().selectAssociatedToProjectAndLanguage(dbSession, project, profile.getLanguage())).isNull();
185     assertThatRulesProfileExists(builtInProfile);
186   }
187
188   @Test
189   public void delete_builtin_profile_marked_as_default() {
190     RulesProfileDto builtInProfile = createBuiltInProfile();
191     QProfileDto profile = associateBuiltInProfile(builtInProfile);
192     db.qualityProfiles().setAsDefault(profile);
193
194     underTest.delete(dbSession, asList(profile));
195
196     verifyNoCallsActiveRuleIndexerDelete();
197
198     // remove only from org_qprofiles and default_qprofiles
199     assertThat(db.getDbClient().qualityProfileDao().selectAll(dbSession)).isEmpty();
200     assertThat(db.getDbClient().qualityProfileDao().selectDefaultProfile(dbSession, profile.getLanguage())).isNull();
201     assertThatRulesProfileExists(builtInProfile);
202   }
203
204   @Test
205   public void delete_accepts_empty_list_of_keys() {
206     QProfileDto profile = createCustomProfile();
207
208     underTest.delete(dbSession, Collections.emptyList());
209
210     verifyNoInteractions(activeRuleIndexer);
211     assertQualityProfileFromDb(profile).isNotNull();
212   }
213
214   @Test
215   public void delete_removes_qprofile_edit_permissions() {
216     QProfileDto profile = db.qualityProfiles().insert();
217     UserDto user = db.users().insertUser();
218     db.qualityProfiles().addUserPermission(profile, user);
219     GroupDto group = db.users().insertGroup();
220     db.qualityProfiles().addGroupPermission(profile, group);
221
222     underTest.delete(dbSession, asList(profile));
223
224     assertThat(db.countRowsOfTable(dbSession, "qprofile_edit_users")).isZero();
225     assertThat(db.countRowsOfTable(dbSession, "qprofile_edit_groups")).isZero();
226   }
227
228   private QProfileDto createCustomProfile() {
229     QProfileDto profile = db.qualityProfiles().insert(p -> p.setLanguage("xoo").setIsBuiltIn(false));
230     ActiveRuleDto activeRuleDto = db.qualityProfiles().activateRule(profile, rule);
231
232     ActiveRuleParamDto activeRuleParam = new ActiveRuleParamDto()
233       .setRulesParameterUuid(ruleParam.getUuid())
234       .setKey("foo")
235       .setValue("bar");
236     db.getDbClient().activeRuleDao().insertParam(dbSession, activeRuleDto, activeRuleParam);
237
238     db.getDbClient().qProfileChangeDao().insert(dbSession, new QProfileChangeDto()
239       .setChangeType(ActiveRuleChange.Type.ACTIVATED.name())
240       .setRulesProfileUuid(profile.getRulesProfileUuid()));
241     db.commit();
242     return profile;
243   }
244
245   private RulesProfileDto createBuiltInProfile() {
246     RulesProfileDto rulesProfileDto = new RulesProfileDto()
247       .setIsBuiltIn(true)
248       .setUuid(Uuids.createFast())
249       .setLanguage("xoo")
250       .setName("Sonar way");
251     db.getDbClient().qualityProfileDao().insert(dbSession, rulesProfileDto);
252     ActiveRuleDto activeRuleDto = new ActiveRuleDto()
253       .setProfileUuid(rulesProfileDto.getUuid())
254       .setRuleUuid(rule.getUuid())
255       .setSeverity(Severity.BLOCKER);
256     db.getDbClient().activeRuleDao().insert(dbSession, activeRuleDto);
257
258     ActiveRuleParamDto activeRuleParam = new ActiveRuleParamDto()
259       .setRulesParameterUuid(ruleParam.getUuid())
260       .setKey("foo")
261       .setValue("bar");
262     db.getDbClient().activeRuleDao().insertParam(dbSession, activeRuleDto, activeRuleParam);
263
264     db.getDbClient().qProfileChangeDao().insert(dbSession, new QProfileChangeDto()
265       .setChangeType(ActiveRuleChange.Type.ACTIVATED.name())
266       .setRulesProfileUuid(rulesProfileDto.getUuid()));
267
268     db.commit();
269     return rulesProfileDto;
270   }
271
272   private QProfileDto associateBuiltInProfile(RulesProfileDto rulesProfile) {
273     OrgQProfileDto orgQProfileDto = new OrgQProfileDto()
274       .setUuid(Uuids.createFast())
275       .setRulesProfileUuid(rulesProfile.getUuid());
276
277     db.getDbClient().qualityProfileDao().insert(dbSession, orgQProfileDto);
278     db.commit();
279     return QProfileDto.from(orgQProfileDto, rulesProfile);
280   }
281
282   private AbstractObjectAssert<?, QProfileDto> assertQualityProfileFromDb(QProfileDto profile) {
283     return assertThat(db.getDbClient().qualityProfileDao().selectByUuid(dbSession, profile.getKee()));
284   }
285
286   private void verifyNoCallsActiveRuleIndexerDelete() {
287     verify(activeRuleIndexer, never()).commitDeletionOfProfiles(any(DbSession.class), anyCollection());
288   }
289
290   private void verifyCallActiveRuleIndexerDelete(String... expectedRuleProfileUuids) {
291     Class<Set<QProfileDto>> setClass = (Class<Set<QProfileDto>>) (Class) Set.class;
292     ArgumentCaptor<Set<QProfileDto>> setCaptor = ArgumentCaptor.forClass(setClass);
293     verify(activeRuleIndexer).commitDeletionOfProfiles(any(DbSession.class), setCaptor.capture());
294
295     assertThat(setCaptor.getValue())
296       .extracting(QProfileDto::getKee)
297       .containsExactlyInAnyOrder(expectedRuleProfileUuids);
298   }
299
300   private void assertThatRulesProfileExists(RulesProfileDto rulesProfile) {
301     assertThat(db.getDbClient().qualityProfileDao().selectBuiltInRuleProfiles(dbSession))
302       .extracting(RulesProfileDto::getUuid)
303       .containsExactly(rulesProfile.getUuid());
304     assertThat(db.countRowsOfTable(dbSession, "active_rules")).isPositive();
305     assertThat(db.countRowsOfTable(dbSession, "active_rule_parameters")).isPositive();
306     assertThat(db.countRowsOfTable(dbSession, "qprofile_changes")).isPositive();
307   }
308
309   private void assertThatCustomProfileDoesNotExist(QProfileDto profile) {
310     assertThat(db.countSql(dbSession, "select count(*) from org_qprofiles where uuid = '" + profile.getKee() + "'")).isZero();
311     assertThat(db.countSql(dbSession, "select count(*) from project_qprofiles where profile_key = '" + profile.getKee() + "'")).isZero();
312     assertThat(db.countSql(dbSession, "select count(*) from default_qprofiles where qprofile_uuid = '" + profile.getKee() + "'")).isZero();
313     assertThat(db.countSql(dbSession, "select count(*) from rules_profiles where uuid = '" + profile.getRulesProfileUuid() + "'")).isZero();
314     assertThat(db.countSql(dbSession, "select count(*) from active_rules where profile_uuid = '" + profile.getRulesProfileUuid() + "'")).isZero();
315     assertThat(db.countSql(dbSession, "select count(*) from qprofile_changes where rules_profile_uuid = '" + profile.getRulesProfileUuid() + "'")).isZero();
316     // TODO active_rule_parameters
317   }
318
319   private void assertThatCustomProfileExists(QProfileDto profile) {
320     assertThat(db.countSql(dbSession, "select count(*) from org_qprofiles where uuid = '" + profile.getKee() + "'")).isPositive();
321     // assertThat(db.countSql(dbSession, "select count(*) from project_qprofiles where profile_key = '" + profile.getKee() +
322     // "'")).isPositive();
323     // assertThat(db.countSql(dbSession, "select count(*) from default_qprofiles where qprofile_uuid = '" + profile.getKee() +
324     // "'")).isPositive();
325     assertThat(db.countSql(dbSession, "select count(*) from rules_profiles where uuid = '" + profile.getRulesProfileUuid() + "'")).isOne();
326     assertThat(db.countSql(dbSession, "select count(*) from active_rules where profile_uuid = '" + profile.getRulesProfileUuid() + "'")).isPositive();
327     assertThat(db.countSql(dbSession, "select count(*) from qprofile_changes where rules_profile_uuid = '" + profile.getRulesProfileUuid() + "'")).isPositive();
328     // TODO active_rule_parameters
329   }
330
331   private static void assertEqual(QProfileDto p1, QProfileDto p2) {
332     assertThat(p2.getName()).isEqualTo(p1.getName());
333     assertThat(p2.getKee()).startsWith(p1.getKee());
334     assertThat(p2.getLanguage()).isEqualTo(p1.getLanguage());
335     assertThat(p2.getRulesProfileUuid()).isEqualTo(p1.getRulesProfileUuid());
336     assertThat(p2.getParentKee()).isEqualTo(p1.getParentKee());
337   }
338
339   private void expectBadRequestException(ThrowingCallable callback, String message) {
340     assertThatThrownBy(callback)
341       .isInstanceOf(BadRequestException.class)
342       .hasMessage(message);
343   }
344 }