3 * Copyright (C) 2009-2022 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 com.google.common.collect.ImmutableMap;
23 import java.util.Arrays;
25 import java.util.function.Consumer;
26 import javax.annotation.Nullable;
27 import org.junit.Rule;
28 import org.junit.Test;
29 import org.sonar.api.impl.utils.TestSystem2;
30 import org.sonar.api.resources.Languages;
31 import org.sonar.api.rule.RuleKey;
32 import org.sonar.api.server.ws.WebService;
33 import org.sonar.api.utils.DateUtils;
34 import org.sonar.db.DbTester;
35 import org.sonar.db.qualityprofile.QProfileChangeDto;
36 import org.sonar.db.qualityprofile.QProfileDto;
37 import org.sonar.db.rule.RuleDto;
38 import org.sonar.db.user.UserDto;
39 import org.sonar.server.qualityprofile.ActiveRuleChange;
40 import org.sonar.server.qualityprofile.ActiveRuleInheritance;
41 import org.sonar.server.tester.UserSessionRule;
42 import org.sonar.server.ws.WsActionTester;
44 import static org.assertj.core.api.Assertions.assertThat;
45 import static org.sonar.test.JsonAssert.assertJson;
46 import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_LANGUAGE;
47 import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_QUALITY_PROFILE;
48 import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_SINCE;
50 public class ChangelogActionTest {
52 private static final String DATE = "2011-04-25T01:15:42+0100";
54 private final TestSystem2 system2 = new TestSystem2().setNow(DateUtils.parseDateTime(DATE).getTime());
57 public DbTester db = DbTester.create(system2);
59 public UserSessionRule userSession = UserSessionRule.standalone();
61 private final QProfileWsSupport wsSupport = new QProfileWsSupport(db.getDbClient(), userSession);
62 private final WsActionTester ws = new WsActionTester(new ChangelogAction(wsSupport, new Languages(), db.getDbClient()));
65 public void return_change_with_all_fields() {
66 QProfileDto profile = db.qualityProfiles().insert();
67 UserDto user = db.users().insertUser();
68 RuleDto rule = db.rules().insert(RuleKey.of("java", "S001"));
69 insertChange(profile, ActiveRuleChange.Type.ACTIVATED, user, ImmutableMap.of(
70 "ruleUuid", rule.getUuid(),
72 "inheritance", ActiveRuleInheritance.INHERITED.name(),
73 "param_foo", "foo_value",
74 "param_bar", "bar_value"));
76 String response = ws.newRequest()
77 .setParam(PARAM_LANGUAGE, profile.getLanguage())
78 .setParam(PARAM_QUALITY_PROFILE, profile.getName())
82 assertJson(response).isSimilarTo("{\n" +
88 " \"date\": \"" + DATE + "\",\n" +
89 " \"authorLogin\": \"" + user.getLogin() + "\",\n" +
90 " \"authorName\": \"" + user.getName() + "\",\n" +
91 " \"action\": \"ACTIVATED\",\n" +
92 " \"ruleKey\": \"" + rule.getKey() + "\",\n" +
93 " \"ruleName\": \"" + rule.getName() + "\",\n" +
95 " \"severity\": \"MINOR\",\n" +
96 " \"bar\": \"bar_value\",\n" +
97 " \"foo\": \"foo_value\"\n" +
105 public void find_changelog_by_profile_key() {
106 QProfileDto profile = db.qualityProfiles().insert();
107 RuleDto rule = db.rules().insert();
108 UserDto user = db.users().insertUser();
109 insertChange(profile, ActiveRuleChange.Type.ACTIVATED, user,
111 "ruleUuid", rule.getUuid(),
112 "severity", "MINOR"));
114 String response = ws.newRequest()
115 .setParam(PARAM_LANGUAGE, profile.getLanguage())
116 .setParam(PARAM_QUALITY_PROFILE, profile.getName())
120 assertJson(response).isSimilarTo("{\n" +
123 " \"date\": \"" + DATE + "\",\n" +
124 " \"authorLogin\": \"" + user.getLogin() + "\",\n" +
125 " \"action\": \"ACTIVATED\",\n" +
126 " \"ruleKey\": \"" + rule.getKey() + "\",\n" +
127 " \"ruleName\": \"" + rule.getName() + "\",\n" +
129 " \"severity\": \"MINOR\"\n" +
137 public void find_changelog_by_language_and_name() {
138 QProfileDto qualityProfile = db.qualityProfiles().insert();
139 RuleDto rule = db.rules().insert();
140 UserDto user = db.users().insertUser();
141 insertChange(qualityProfile, ActiveRuleChange.Type.ACTIVATED, user,
143 "ruleUuid", rule.getUuid(),
144 "severity", "MINOR"));
146 String response = ws.newRequest()
147 .setParam(PARAM_LANGUAGE, qualityProfile.getLanguage())
148 .setParam(PARAM_QUALITY_PROFILE, qualityProfile.getName())
152 assertJson(response).isSimilarTo("{\n" +
155 " \"date\": \"" + DATE + "\",\n" +
156 " \"authorLogin\": \"" + user.getLogin() + "\",\n" +
157 " \"action\": \"ACTIVATED\",\n" +
158 " \"ruleKey\": \"" + rule.getKey() + "\",\n" +
159 " \"ruleName\": \"" + rule.getName() + "\",\n" +
161 " \"severity\": \"MINOR\"\n" +
169 public void changelog_empty() {
170 QProfileDto qualityProfile = db.qualityProfiles().insert();
172 String response = ws.newRequest()
173 .setParam(PARAM_LANGUAGE, qualityProfile.getLanguage())
174 .setParam(PARAM_QUALITY_PROFILE, qualityProfile.getName())
178 assertJson(response).isSimilarTo("{\"total\":0,\"p\":1,\"ps\":50,\"events\":[]}");
182 public void changelog_filter_by_since() {
183 QProfileDto qualityProfile = db.qualityProfiles().insert();
184 system2.setNow(DateUtils.parseDateTime("2011-04-25T01:15:42+0100").getTime());
185 RuleDto rule = db.rules().insert();
186 UserDto user = db.users().insertUser();
187 insertChange(qualityProfile, ActiveRuleChange.Type.ACTIVATED, user,
189 "ruleUuid", rule.getUuid(),
190 "severity", "MINOR"));
192 assertJson(ws.newRequest()
193 .setParam(PARAM_LANGUAGE, qualityProfile.getLanguage())
194 .setParam(PARAM_QUALITY_PROFILE, qualityProfile.getName())
195 .setParam(PARAM_SINCE, "2011-04-25T01:15:42+0100")
197 .getInput()).isSimilarTo("{\n" +
200 " \"date\": \"2011-04-25T01:15:42+0100\",\n" +
201 " \"authorLogin\": \"" + user.getLogin() + "\",\n" +
202 " \"action\": \"ACTIVATED\",\n" +
203 " \"ruleKey\": \"" + rule.getKey() + "\",\n" +
204 " \"ruleName\": \"" + rule.getName() + "\",\n" +
209 assertJson(ws.newRequest()
210 .setParam(PARAM_LANGUAGE, qualityProfile.getLanguage())
211 .setParam(PARAM_QUALITY_PROFILE, qualityProfile.getName())
212 .setParam(PARAM_SINCE, "2011-04-25T01:15:43+0100")
214 .getInput()).isSimilarTo("{\n" +
215 " \"events\": []\n" +
220 public void sort_changelog_events_in_reverse_chronological_order() {
221 QProfileDto profile = db.qualityProfiles().insert();
222 system2.setNow(DateUtils.parseDateTime("2011-04-25T01:15:42+0100").getTime());
223 RuleDto rule1 = db.rules().insert();
224 insertChange(profile, ActiveRuleChange.Type.ACTIVATED, null,
226 "ruleUuid", rule1.getUuid(),
227 "severity", "MINOR"));
228 system2.setNow(DateUtils.parseDateTime("2011-04-25T01:15:43+0100").getTime());
229 UserDto user = db.users().insertUser();
230 RuleDto rule2 = db.rules().insert();
231 insertChange(profile, ActiveRuleChange.Type.DEACTIVATED, user,
232 ImmutableMap.of("ruleUuid", rule2.getUuid()));
234 String response = ws.newRequest()
235 .setParam(PARAM_LANGUAGE, profile.getLanguage())
236 .setParam(PARAM_QUALITY_PROFILE, profile.getName())
240 assertJson(response).isSimilarTo("{\n" +
243 " \"date\": \"2011-04-25T02:15:43+0200\",\n" +
244 " \"action\": \"DEACTIVATED\",\n" +
245 " \"authorLogin\": \"" + user.getLogin() + "\",\n" +
246 " \"ruleKey\": \"" + rule2.getKey() + "\",\n" +
247 " \"ruleName\": \"" + rule2.getName() + "\",\n" +
248 " \"params\": {}\n" +
251 " \"date\": \"2011-04-25T02:15:42+0200\",\n" +
252 " \"action\": \"ACTIVATED\",\n" +
253 " \"ruleKey\": \"" + rule1.getKey() + "\",\n" +
254 " \"ruleName\": \"" + rule1.getName() + "\",\n" +
256 " \"severity\": \"MINOR\"\n" +
264 public void changelog_on_no_more_existing_rule() {
265 QProfileDto qualityProfile = db.qualityProfiles().insert();
266 UserDto user = db.users().insertUser();
267 insertChange(qualityProfile, ActiveRuleChange.Type.ACTIVATED, user,
268 ImmutableMap.of("ruleUuid", "123"));
270 String response = ws.newRequest()
271 .setParam(PARAM_LANGUAGE, qualityProfile.getLanguage())
272 .setParam(PARAM_QUALITY_PROFILE, qualityProfile.getName())
276 assertJson(response).isSimilarTo("{\n" +
279 " \"date\": \"" + DATE + "\",\n" +
280 " \"action\": \"ACTIVATED\",\n" +
281 " \"params\": {}\n" +
285 assertThat(response).doesNotContain("ruleKey", "ruleName");
289 public void changelog_on_no_more_existing_user() {
290 QProfileDto qualityProfile = db.qualityProfiles().insert();
291 RuleDto rule = db.rules().insert();
292 insertChange(c -> c.setRulesProfileUuid(qualityProfile.getRulesProfileUuid())
293 .setUserUuid("UNKNOWN")
294 .setChangeType(ActiveRuleChange.Type.ACTIVATED.name())
295 .setData(ImmutableMap.of("ruleUuid", rule.getUuid())));
297 String response = ws.newRequest()
298 .setParam(PARAM_LANGUAGE, qualityProfile.getLanguage())
299 .setParam(PARAM_QUALITY_PROFILE, qualityProfile.getName())
303 assertJson(response).isSimilarTo("{\n" +
306 " \"date\": \"" + DATE + "\",\n" +
307 " \"ruleKey\": \"" + rule.getKey() + "\",\n" +
308 " \"ruleName\": \"" + rule.getName() + "\",\n" +
309 " \"action\": \"ACTIVATED\",\n" +
310 " \"params\": {}\n" +
314 assertThat(response).doesNotContain("authorLogin", "authorName");
318 public void example() {
319 QProfileDto profile = db.qualityProfiles().insert();
320 String profileUuid = profile.getRulesProfileUuid();
322 system2.setNow(DateUtils.parseDateTime("2015-02-23T17:58:39+0100").getTime());
323 RuleDto rule1 = db.rules().insert(RuleKey.of("java", "S2438"), r -> r.setName("\"Threads\" should not be used where \"Runnables\" are expected"));
324 UserDto user1 = db.users().insertUser(u -> u.setLogin("anakin.skywalker").setName("Anakin Skywalker"));
325 insertChange(c -> c.setRulesProfileUuid(profileUuid)
326 .setUserUuid(user1.getUuid())
327 .setChangeType(ActiveRuleChange.Type.ACTIVATED.name())
328 .setData(ImmutableMap.of("severity", "CRITICAL", "ruleUuid", rule1.getUuid())));
330 system2.setNow(DateUtils.parseDateTime("2015-02-23T17:58:18+0100").getTime());
331 RuleDto rule2 = db.rules().insert(RuleKey.of("java", "S2162"), r -> r.setName("\"equals\" methods should be symmetric and work for subclasses"));
332 UserDto user2 = db.users().insertUser(u -> u.setLogin("padme.amidala").setName("Padme Amidala"));
333 insertChange(c -> c.setRulesProfileUuid(profileUuid)
334 .setUserUuid(user2.getUuid())
335 .setChangeType(ActiveRuleChange.Type.DEACTIVATED.name())
336 .setData(ImmutableMap.of("ruleUuid", rule2.getUuid())));
338 system2.setNow(DateUtils.parseDateTime("2014-09-12T15:20:46+0200").getTime());
339 RuleDto rule3 = db.rules().insert(RuleKey.of("java", "S00101"), r -> r.setName("Class names should comply with a naming convention"));
340 UserDto user3 = db.users().insertUser(u -> u.setLogin("obiwan.kenobi").setName("Obiwan Kenobi"));
341 insertChange(c -> c.setRulesProfileUuid(profileUuid)
342 .setUserUuid(user3.getUuid())
343 .setChangeType(ActiveRuleChange.Type.ACTIVATED.name())
344 .setData(ImmutableMap.of("severity", "MAJOR", "param_format", "^[A-Z][a-zA-Z0-9]*$", "ruleUuid", rule3.getUuid())));
346 String response = ws.newRequest()
348 .setParam(PARAM_LANGUAGE, profile.getLanguage())
349 .setParam(PARAM_QUALITY_PROFILE, profile.getName())
350 .setParam("ps", "10")
354 assertJson(response).isSimilarTo(getClass().getResource("changelog-example.json"));
358 public void definition() {
359 WebService.Action definition = ws.getDef();
361 assertThat(definition.isPost()).isFalse();
362 assertThat(definition.responseExampleAsString()).isNotEmpty();
363 assertThat(definition.params()).extracting(WebService.Param::key)
364 .containsExactlyInAnyOrder("qualityProfile", "language", "since", "to", "p", "ps");
365 WebService.Param profileName = definition.param("qualityProfile");
366 assertThat(profileName.deprecatedSince()).isNullOrEmpty();
367 WebService.Param language = definition.param("language");
368 assertThat(language.deprecatedSince()).isNullOrEmpty();
371 private QProfileChangeDto insertChange(QProfileDto profile, ActiveRuleChange.Type type, @Nullable UserDto user, @Nullable Map<String, Object> data) {
372 return insertChange(c -> c.setRulesProfileUuid(profile.getRulesProfileUuid())
373 .setUserUuid(user == null ? null : user.getUuid())
374 .setChangeType(type.name())
379 private final QProfileChangeDto insertChange(Consumer<QProfileChangeDto>... consumers) {
380 QProfileChangeDto dto = new QProfileChangeDto();
381 Arrays.stream(consumers).forEach(c -> c.accept(dto));
382 db.getDbClient().qProfileChangeDao().insert(db.getSession(), dto);