3 * Copyright (C) 2009-2020 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.junit.rules.ExpectedException;
30 import org.sonar.api.impl.utils.TestSystem2;
31 import org.sonar.api.resources.Languages;
32 import org.sonar.api.rule.RuleKey;
33 import org.sonar.api.server.ws.WebService;
34 import org.sonar.api.utils.DateUtils;
35 import org.sonar.db.DbTester;
36 import org.sonar.db.qualityprofile.QProfileChangeDto;
37 import org.sonar.db.qualityprofile.QProfileDto;
38 import org.sonar.db.rule.RuleDefinitionDto;
39 import org.sonar.db.user.UserDto;
40 import org.sonar.server.qualityprofile.ActiveRuleChange;
41 import org.sonar.server.qualityprofile.ActiveRuleInheritance;
42 import org.sonar.server.tester.UserSessionRule;
43 import org.sonar.server.ws.WsActionTester;
45 import static org.assertj.core.api.Assertions.assertThat;
46 import static org.sonar.test.JsonAssert.assertJson;
47 import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_LANGUAGE;
48 import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_QUALITY_PROFILE;
49 import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_SINCE;
51 public class ChangelogActionTest {
53 private static final String DATE = "2011-04-25T01:15:42+0100";
55 private TestSystem2 system2 = new TestSystem2().setNow(DateUtils.parseDateTime(DATE).getTime());
58 public DbTester db = DbTester.create(system2);
60 public UserSessionRule userSession = UserSessionRule.standalone();
62 public ExpectedException expectedException = ExpectedException.none();
64 private QProfileWsSupport wsSupport = new QProfileWsSupport(db.getDbClient(), userSession);
65 private WsActionTester ws = new WsActionTester(new ChangelogAction(wsSupport, new Languages(), db.getDbClient()));
68 public void return_change_with_all_fields() {
69 QProfileDto profile = db.qualityProfiles().insert();
70 UserDto user = db.users().insertUser();
71 RuleDefinitionDto rule = db.rules().insert(RuleKey.of("java", "S001"));
72 insertChange(profile, ActiveRuleChange.Type.ACTIVATED, user, ImmutableMap.of(
73 "ruleUuid", rule.getUuid(),
75 "inheritance", ActiveRuleInheritance.INHERITED.name(),
76 "param_foo", "foo_value",
77 "param_bar", "bar_value"));
79 String response = ws.newRequest()
80 .setParam(PARAM_LANGUAGE, profile.getLanguage())
81 .setParam(PARAM_QUALITY_PROFILE, profile.getName())
85 assertJson(response).isSimilarTo("{\n" +
91 " \"date\": \"" + DATE + "\",\n" +
92 " \"authorLogin\": \"" + user.getLogin() + "\",\n" +
93 " \"authorName\": \"" + user.getName() + "\",\n" +
94 " \"action\": \"ACTIVATED\",\n" +
95 " \"ruleKey\": \"" + rule.getKey() + "\",\n" +
96 " \"ruleName\": \"" + rule.getName() + "\",\n" +
98 " \"severity\": \"MINOR\",\n" +
99 " \"bar\": \"bar_value\",\n" +
100 " \"foo\": \"foo_value\"\n" +
108 public void find_changelog_by_profile_key() {
109 QProfileDto profile = db.qualityProfiles().insert();
110 RuleDefinitionDto rule = db.rules().insert();
111 UserDto user = db.users().insertUser();
112 insertChange(profile, ActiveRuleChange.Type.ACTIVATED, user,
114 "ruleUuid", rule.getUuid(),
115 "severity", "MINOR"));
117 String response = ws.newRequest()
118 .setParam(PARAM_LANGUAGE, profile.getLanguage())
119 .setParam(PARAM_QUALITY_PROFILE, profile.getName())
123 assertJson(response).isSimilarTo("{\n" +
126 " \"date\": \"" + DATE + "\",\n" +
127 " \"authorLogin\": \"" + user.getLogin() + "\",\n" +
128 " \"action\": \"ACTIVATED\",\n" +
129 " \"ruleKey\": \"" + rule.getKey() + "\",\n" +
130 " \"ruleName\": \"" + rule.getName() + "\",\n" +
132 " \"severity\": \"MINOR\"\n" +
140 public void find_changelog_by_language_and_name() {
141 QProfileDto qualityProfile = db.qualityProfiles().insert();
142 RuleDefinitionDto rule = db.rules().insert();
143 UserDto user = db.users().insertUser();
144 insertChange(qualityProfile, ActiveRuleChange.Type.ACTIVATED, user,
146 "ruleUuid", rule.getUuid(),
147 "severity", "MINOR"));
149 String response = ws.newRequest()
150 .setParam(PARAM_LANGUAGE, qualityProfile.getLanguage())
151 .setParam(PARAM_QUALITY_PROFILE, qualityProfile.getName())
155 assertJson(response).isSimilarTo("{\n" +
158 " \"date\": \"" + DATE + "\",\n" +
159 " \"authorLogin\": \"" + user.getLogin() + "\",\n" +
160 " \"action\": \"ACTIVATED\",\n" +
161 " \"ruleKey\": \"" + rule.getKey() + "\",\n" +
162 " \"ruleName\": \"" + rule.getName() + "\",\n" +
164 " \"severity\": \"MINOR\"\n" +
172 public void find_changelog_by_organization_and_language_and_name() {
173 QProfileDto qualityProfile = db.qualityProfiles().insert();
174 RuleDefinitionDto rule = db.rules().insert();
175 UserDto user = db.users().insertUser();
176 insertChange(qualityProfile, ActiveRuleChange.Type.ACTIVATED, user,
178 "ruleUuid", rule.getUuid(),
179 "severity", "MINOR"));
181 String response = ws.newRequest()
182 .setParam(PARAM_LANGUAGE, qualityProfile.getLanguage())
183 .setParam(PARAM_QUALITY_PROFILE, qualityProfile.getName())
187 assertJson(response).isSimilarTo("{\n" +
190 " \"date\": \"" + DATE + "\",\n" +
191 " \"authorLogin\": \"" + user.getLogin() + "\",\n" +
192 " \"action\": \"ACTIVATED\",\n" +
193 " \"ruleKey\": \"" + rule.getKey() + "\",\n" +
194 " \"ruleName\": \"" + rule.getName() + "\",\n" +
196 " \"severity\": \"MINOR\"\n" +
204 public void changelog_empty() {
205 QProfileDto qualityProfile = db.qualityProfiles().insert();
207 String response = ws.newRequest()
208 .setParam(PARAM_LANGUAGE, qualityProfile.getLanguage())
209 .setParam(PARAM_QUALITY_PROFILE, qualityProfile.getName())
213 assertJson(response).isSimilarTo("{\"total\":0,\"p\":1,\"ps\":50,\"events\":[]}");
217 public void changelog_filter_by_since() {
218 QProfileDto qualityProfile = db.qualityProfiles().insert();
219 system2.setNow(DateUtils.parseDateTime("2011-04-25T01:15:42+0100").getTime());
220 RuleDefinitionDto rule = db.rules().insert();
221 UserDto user = db.users().insertUser();
222 insertChange(qualityProfile, ActiveRuleChange.Type.ACTIVATED, user,
224 "ruleUuid", rule.getUuid(),
225 "severity", "MINOR"));
227 assertJson(ws.newRequest()
228 .setParam(PARAM_LANGUAGE, qualityProfile.getLanguage())
229 .setParam(PARAM_QUALITY_PROFILE, qualityProfile.getName())
230 .setParam(PARAM_SINCE, "2011-04-25T01:15:42+0100")
232 .getInput()).isSimilarTo("{\n" +
235 " \"date\": \"2011-04-25T01:15:42+0100\",\n" +
236 " \"authorLogin\": \"" + user.getLogin() + "\",\n" +
237 " \"action\": \"ACTIVATED\",\n" +
238 " \"ruleKey\": \"" + rule.getKey() + "\",\n" +
239 " \"ruleName\": \"" + rule.getName() + "\",\n" +
244 assertJson(ws.newRequest()
245 .setParam(PARAM_LANGUAGE, qualityProfile.getLanguage())
246 .setParam(PARAM_QUALITY_PROFILE, qualityProfile.getName())
247 .setParam(PARAM_SINCE, "2011-04-25T01:15:43+0100")
249 .getInput()).isSimilarTo("{\n" +
250 " \"events\": []\n" +
255 public void sort_changelog_events_in_reverse_chronological_order() {
256 QProfileDto profile = db.qualityProfiles().insert();
257 system2.setNow(DateUtils.parseDateTime("2011-04-25T01:15:42+0100").getTime());
258 RuleDefinitionDto rule1 = db.rules().insert();
259 insertChange(profile, ActiveRuleChange.Type.ACTIVATED, null,
261 "ruleUuid", rule1.getUuid(),
262 "severity", "MINOR"));
263 system2.setNow(DateUtils.parseDateTime("2011-04-25T01:15:43+0100").getTime());
264 UserDto user = db.users().insertUser();
265 RuleDefinitionDto rule2 = db.rules().insert();
266 insertChange(profile, ActiveRuleChange.Type.DEACTIVATED, user,
267 ImmutableMap.of("ruleUuid", rule2.getUuid()));
269 String response = ws.newRequest()
270 .setParam(PARAM_LANGUAGE, profile.getLanguage())
271 .setParam(PARAM_QUALITY_PROFILE, profile.getName())
275 assertJson(response).isSimilarTo("{\n" +
278 " \"date\": \"2011-04-25T02:15:43+0200\",\n" +
279 " \"action\": \"DEACTIVATED\",\n" +
280 " \"authorLogin\": \"" + user.getLogin() + "\",\n" +
281 " \"ruleKey\": \"" + rule2.getKey() + "\",\n" +
282 " \"ruleName\": \"" + rule2.getName() + "\",\n" +
283 " \"params\": {}\n" +
286 " \"date\": \"2011-04-25T02:15:42+0200\",\n" +
287 " \"action\": \"ACTIVATED\",\n" +
288 " \"ruleKey\": \"" + rule1.getKey() + "\",\n" +
289 " \"ruleName\": \"" + rule1.getName() + "\",\n" +
291 " \"severity\": \"MINOR\"\n" +
299 public void changelog_on_no_more_existing_rule() {
300 QProfileDto qualityProfile = db.qualityProfiles().insert();
301 UserDto user = db.users().insertUser();
302 insertChange(qualityProfile, ActiveRuleChange.Type.ACTIVATED, user,
303 ImmutableMap.of("ruleUuid", "123"));
305 String response = ws.newRequest()
306 .setParam(PARAM_LANGUAGE, qualityProfile.getLanguage())
307 .setParam(PARAM_QUALITY_PROFILE, qualityProfile.getName())
311 assertJson(response).isSimilarTo("{\n" +
314 " \"date\": \"" + DATE + "\",\n" +
315 " \"action\": \"ACTIVATED\",\n" +
316 " \"params\": {}\n" +
320 assertThat(response).doesNotContain("ruleKey", "ruleName");
324 public void changelog_on_no_more_existing_user() {
325 QProfileDto qualityProfile = db.qualityProfiles().insert();
326 RuleDefinitionDto rule = db.rules().insert();
327 insertChange(c -> c.setRulesProfileUuid(qualityProfile.getRulesProfileUuid())
328 .setUserUuid("UNKNOWN")
329 .setChangeType(ActiveRuleChange.Type.ACTIVATED.name())
330 .setData(ImmutableMap.of("ruleUuid", rule.getUuid())));
332 String response = ws.newRequest()
333 .setParam(PARAM_LANGUAGE, qualityProfile.getLanguage())
334 .setParam(PARAM_QUALITY_PROFILE, qualityProfile.getName())
338 assertJson(response).isSimilarTo("{\n" +
341 " \"date\": \"" + DATE + "\",\n" +
342 " \"ruleKey\": \"" + rule.getKey() + "\",\n" +
343 " \"ruleName\": \"" + rule.getName() + "\",\n" +
344 " \"action\": \"ACTIVATED\",\n" +
345 " \"params\": {}\n" +
349 assertThat(response).doesNotContain("authorLogin", "authorName");
353 public void example() {
354 QProfileDto profile = db.qualityProfiles().insert();
355 String profileUuid = profile.getRulesProfileUuid();
357 system2.setNow(DateUtils.parseDateTime("2015-02-23T17:58:39+0100").getTime());
358 RuleDefinitionDto rule1 = db.rules().insert(RuleKey.of("squid", "S2438"), r -> r.setName("\"Threads\" should not be used where \"Runnables\" are expected"));
359 UserDto user1 = db.users().insertUser(u -> u.setLogin("anakin.skywalker").setName("Anakin Skywalker"));
360 insertChange(c -> c.setRulesProfileUuid(profileUuid)
361 .setUserUuid(user1.getUuid())
362 .setChangeType(ActiveRuleChange.Type.ACTIVATED.name())
363 .setData(ImmutableMap.of("severity", "CRITICAL", "ruleUuid", rule1.getUuid())));
365 system2.setNow(DateUtils.parseDateTime("2015-02-23T17:58:18+0100").getTime());
366 RuleDefinitionDto rule2 = db.rules().insert(RuleKey.of("squid", "S2162"), r -> r.setName("\"equals\" methods should be symmetric and work for subclasses"));
367 UserDto user2 = db.users().insertUser(u -> u.setLogin("padme.amidala").setName("Padme Amidala"));
368 insertChange(c -> c.setRulesProfileUuid(profileUuid)
369 .setUserUuid(user2.getUuid())
370 .setChangeType(ActiveRuleChange.Type.DEACTIVATED.name())
371 .setData(ImmutableMap.of("ruleUuid", rule2.getUuid())));
373 system2.setNow(DateUtils.parseDateTime("2014-09-12T15:20:46+0200").getTime());
374 RuleDefinitionDto rule3 = db.rules().insert(RuleKey.of("squid", "S00101"), r -> r.setName("Class names should comply with a naming convention"));
375 UserDto user3 = db.users().insertUser(u -> u.setLogin("obiwan.kenobi").setName("Obiwan Kenobi"));
376 insertChange(c -> c.setRulesProfileUuid(profileUuid)
377 .setUserUuid(user3.getUuid())
378 .setChangeType(ActiveRuleChange.Type.ACTIVATED.name())
379 .setData(ImmutableMap.of("severity", "MAJOR", "param_format", "^[A-Z][a-zA-Z0-9]*$", "ruleUuid", rule3.getUuid())));
381 String response = ws.newRequest()
383 .setParam(PARAM_LANGUAGE, profile.getLanguage())
384 .setParam(PARAM_QUALITY_PROFILE, profile.getName())
385 .setParam("ps", "10")
389 assertJson(response).isSimilarTo(getClass().getResource("changelog-example.json"));
393 public void definition() {
394 WebService.Action definition = ws.getDef();
396 assertThat(definition.isPost()).isFalse();
397 assertThat(definition.responseExampleAsString()).isNotEmpty();
398 assertThat(definition.params()).extracting(WebService.Param::key)
399 .containsExactlyInAnyOrder("qualityProfile", "language", "since", "to", "p", "ps");
400 WebService.Param profileName = definition.param("qualityProfile");
401 assertThat(profileName.deprecatedSince()).isNullOrEmpty();
402 WebService.Param language = definition.param("language");
403 assertThat(language.deprecatedSince()).isNullOrEmpty();
406 private QProfileChangeDto insertChange(QProfileDto profile, ActiveRuleChange.Type type, @Nullable UserDto user, @Nullable Map<String, Object> data) {
407 return insertChange(c -> c.setRulesProfileUuid(profile.getRulesProfileUuid())
408 .setUserUuid(user == null ? null : user.getUuid())
409 .setChangeType(type.name())
414 private final QProfileChangeDto insertChange(Consumer<QProfileChangeDto>... consumers) {
415 QProfileChangeDto dto = new QProfileChangeDto();
416 Arrays.stream(consumers).forEach(c -> c.accept(dto));
417 db.getDbClient().qProfileChangeDao().insert(db.getSession(), dto);