]> source.dussan.org Git - sonarqube.git/blob
7c8b2b93bcc3db9991df095ad0a33818a8b4117f
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2019 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 com.google.common.collect.ImmutableMap;
23 import java.util.Arrays;
24 import java.util.Map;
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.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.api.impl.utils.TestSystem2;
35 import org.sonar.db.DbTester;
36 import org.sonar.db.organization.OrganizationDto;
37 import org.sonar.db.qualityprofile.QProfileChangeDto;
38 import org.sonar.db.qualityprofile.QProfileDto;
39 import org.sonar.db.rule.RuleDefinitionDto;
40 import org.sonar.db.user.UserDto;
41 import org.sonar.server.exceptions.ForbiddenException;
42 import org.sonar.server.exceptions.NotFoundException;
43 import org.sonar.server.organization.TestDefaultOrganizationProvider;
44 import org.sonar.server.qualityprofile.ActiveRuleChange;
45 import org.sonar.server.qualityprofile.ActiveRuleInheritance;
46 import org.sonar.server.tester.UserSessionRule;
47 import org.sonar.server.ws.WsActionTester;
48
49 import static java.lang.String.format;
50 import static java.lang.String.valueOf;
51 import static org.assertj.core.api.Assertions.assertThat;
52 import static org.sonar.db.organization.OrganizationDto.Subscription.PAID;
53 import static org.sonar.test.JsonAssert.assertJson;
54 import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_KEY;
55 import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_LANGUAGE;
56 import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_ORGANIZATION;
57 import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_QUALITY_PROFILE;
58 import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_SINCE;
59
60 public class ChangelogActionTest {
61
62   private static final String DATE = "2011-04-25T01:15:42+0100";
63
64   private TestSystem2 system2 = new TestSystem2().setNow(DateUtils.parseDateTime(DATE).getTime());
65
66   @Rule
67   public DbTester db = DbTester.create(system2);
68   @Rule
69   public UserSessionRule userSession = UserSessionRule.standalone();
70   @Rule
71   public ExpectedException expectedException = ExpectedException.none();
72
73   private QProfileWsSupport wsSupport = new QProfileWsSupport(db.getDbClient(), userSession, TestDefaultOrganizationProvider.from(db));
74   private WsActionTester ws = new WsActionTester(
75     new ChangelogAction(wsSupport, new Languages(), db.getDbClient()));
76
77   @Test
78   public void return_change_with_all_fields() {
79     OrganizationDto organization = db.organizations().insert();
80     QProfileDto profile = db.qualityProfiles().insert(organization);
81     UserDto user = db.users().insertUser();
82     RuleDefinitionDto rule = db.rules().insert(RuleKey.of("java", "S001"));
83     insertChange(profile, ActiveRuleChange.Type.ACTIVATED, user, ImmutableMap.of(
84       "ruleId", valueOf(rule.getId()),
85       "severity", "MINOR",
86       "inheritance", ActiveRuleInheritance.INHERITED.name(),
87       "param_foo", "foo_value",
88       "param_bar", "bar_value"));
89
90     String response = ws.newRequest()
91       .setParam(PARAM_KEY, profile.getKee())
92       .execute()
93       .getInput();
94
95     assertJson(response).isSimilarTo("{\n" +
96       "  \"total\": 1,\n" +
97       "  \"p\": 1,\n" +
98       "  \"ps\": 50,\n" +
99       "  \"events\": [\n" +
100       "    {\n" +
101       "      \"date\": \"" + DATE + "\",\n" +
102       "      \"authorLogin\": \"" + user.getLogin() + "\",\n" +
103       "      \"authorName\": \"" + user.getName() + "\",\n" +
104       "      \"action\": \"ACTIVATED\",\n" +
105       "      \"ruleKey\": \"" + rule.getKey() + "\",\n" +
106       "      \"ruleName\": \"" + rule.getName() + "\",\n" +
107       "      \"params\": {\n" +
108       "        \"severity\": \"MINOR\",\n" +
109       "        \"bar\": \"bar_value\",\n" +
110       "        \"foo\": \"foo_value\"\n" +
111       "      }\n" +
112       "    }\n" +
113       "  ]\n" +
114       "}");
115   }
116
117   @Test
118   public void find_changelog_by_profile_key() {
119     OrganizationDto organization = db.organizations().insert();
120     QProfileDto profile = db.qualityProfiles().insert(organization);
121     RuleDefinitionDto rule = db.rules().insert();
122     UserDto user = db.users().insertUser();
123     insertChange(profile, ActiveRuleChange.Type.ACTIVATED, user,
124       ImmutableMap.of(
125         "ruleId", valueOf(rule.getId()),
126         "severity", "MINOR"));
127
128     String response = ws.newRequest()
129       .setParam(PARAM_KEY, profile.getKee())
130       .execute()
131       .getInput();
132
133     assertJson(response).isSimilarTo("{\n" +
134       "  \"events\": [\n" +
135       "    {\n" +
136       "      \"date\": \"" + DATE + "\",\n" +
137       "      \"authorLogin\": \"" + user.getLogin() + "\",\n" +
138       "      \"action\": \"ACTIVATED\",\n" +
139       "      \"ruleKey\": \"" + rule.getKey() + "\",\n" +
140       "      \"ruleName\": \"" + rule.getName() + "\",\n" +
141       "      \"params\": {\n" +
142       "        \"severity\": \"MINOR\"\n" +
143       "      }\n" +
144       "    }\n" +
145       "  ]\n" +
146       "}");
147   }
148
149   @Test
150   public void find_changelog_by_language_and_name() {
151     QProfileDto qualityProfile = db.qualityProfiles().insert(db.getDefaultOrganization());
152     RuleDefinitionDto rule = db.rules().insert();
153     UserDto user = db.users().insertUser();
154     insertChange(qualityProfile, ActiveRuleChange.Type.ACTIVATED, user,
155       ImmutableMap.of(
156         "ruleId", valueOf(rule.getId()),
157         "severity", "MINOR"));
158
159     String response = ws.newRequest()
160       .setParam(PARAM_LANGUAGE, qualityProfile.getLanguage())
161       .setParam(PARAM_QUALITY_PROFILE, qualityProfile.getName())
162       .execute()
163       .getInput();
164
165     assertJson(response).isSimilarTo("{\n" +
166       "  \"events\": [\n" +
167       "    {\n" +
168       "      \"date\": \"" + DATE + "\",\n" +
169       "      \"authorLogin\": \"" + user.getLogin() + "\",\n" +
170       "      \"action\": \"ACTIVATED\",\n" +
171       "      \"ruleKey\": \"" + rule.getKey() + "\",\n" +
172       "      \"ruleName\": \"" + rule.getName() + "\",\n" +
173       "      \"params\": {\n" +
174       "        \"severity\": \"MINOR\"\n" +
175       "      }\n" +
176       "    }\n" +
177       "  ]\n" +
178       "}");
179   }
180
181   @Test
182   public void find_changelog_by_organization_and_language_and_name() {
183     OrganizationDto organization = db.organizations().insert();
184     QProfileDto qualityProfile = db.qualityProfiles().insert(organization);
185     RuleDefinitionDto rule = db.rules().insert();
186     UserDto user = db.users().insertUser();
187     insertChange(qualityProfile, ActiveRuleChange.Type.ACTIVATED, user,
188       ImmutableMap.of(
189         "ruleId", valueOf(rule.getId()),
190         "severity", "MINOR"));
191
192     String response = ws.newRequest()
193       .setParam(PARAM_LANGUAGE, qualityProfile.getLanguage())
194       .setParam(PARAM_QUALITY_PROFILE, qualityProfile.getName())
195       .setParam(PARAM_ORGANIZATION, organization.getKey())
196       .execute()
197       .getInput();
198
199     assertJson(response).isSimilarTo("{\n" +
200       "  \"events\": [\n" +
201       "    {\n" +
202       "      \"date\": \"" + DATE + "\",\n" +
203       "      \"authorLogin\": \"" + user.getLogin() + "\",\n" +
204       "      \"action\": \"ACTIVATED\",\n" +
205       "      \"ruleKey\": \"" + rule.getKey() + "\",\n" +
206       "      \"ruleName\": \"" + rule.getName() + "\",\n" +
207       "      \"params\": {\n" +
208       "        \"severity\": \"MINOR\"\n" +
209       "      }\n" +
210       "    }\n" +
211       "  ]\n" +
212       "}");
213   }
214
215   @Test
216   public void changelog_empty() {
217     OrganizationDto organization = db.organizations().insert();
218     QProfileDto qualityProfile = db.qualityProfiles().insert(organization);
219
220     String response = ws.newRequest()
221       .setParam(PARAM_KEY, qualityProfile.getKee())
222       .execute()
223       .getInput();
224
225     assertJson(response).isSimilarTo("{\"total\":0,\"p\":1,\"ps\":50,\"events\":[]}");
226   }
227
228   @Test
229   public void changelog_filter_by_since() {
230     OrganizationDto organization = db.organizations().insert();
231     QProfileDto qualityProfile = db.qualityProfiles().insert(organization);
232     system2.setNow(DateUtils.parseDateTime("2011-04-25T01:15:42+0100").getTime());
233     RuleDefinitionDto rule = db.rules().insert();
234     UserDto user = db.users().insertUser();
235     insertChange(qualityProfile, ActiveRuleChange.Type.ACTIVATED, user,
236       ImmutableMap.of(
237         "ruleId", valueOf(rule.getId()),
238         "severity", "MINOR"));
239
240     assertJson(ws.newRequest()
241       .setParam(PARAM_KEY, qualityProfile.getKee())
242       .setParam(PARAM_SINCE, "2011-04-25T01:15:42+0100")
243       .execute()
244       .getInput()).isSimilarTo("{\n" +
245         "  \"events\": [\n" +
246         "    {\n" +
247         "      \"date\": \"2011-04-25T01:15:42+0100\",\n" +
248         "      \"authorLogin\": \"" + user.getLogin() + "\",\n" +
249         "      \"action\": \"ACTIVATED\",\n" +
250         "      \"ruleKey\": \"" + rule.getKey() + "\",\n" +
251         "      \"ruleName\": \"" + rule.getName() + "\",\n" +
252         "    }\n" +
253         "  ]\n" +
254         "}");
255
256     assertJson(ws.newRequest()
257       .setParam(PARAM_KEY, qualityProfile.getKee())
258       .setParam(PARAM_SINCE, "2011-04-25T01:15:43+0100")
259       .execute()
260       .getInput()).isSimilarTo("{\n" +
261         "  \"events\": []\n" +
262         "}");
263   }
264
265   @Test
266   public void sort_changelog_events_in_reverse_chronological_order() {
267     OrganizationDto organization = db.organizations().insert();
268     QProfileDto profile = db.qualityProfiles().insert(organization);
269     system2.setNow(DateUtils.parseDateTime("2011-04-25T01:15:42+0100").getTime());
270     RuleDefinitionDto rule1 = db.rules().insert();
271     insertChange(profile, ActiveRuleChange.Type.ACTIVATED, null,
272       ImmutableMap.of(
273         "ruleId", valueOf(rule1.getId()),
274         "severity", "MINOR"));
275     system2.setNow(DateUtils.parseDateTime("2011-04-25T01:15:43+0100").getTime());
276     UserDto user = db.users().insertUser();
277     RuleDefinitionDto rule2 = db.rules().insert();
278     insertChange(profile, ActiveRuleChange.Type.DEACTIVATED, user,
279       ImmutableMap.of("ruleId", valueOf(rule2.getId())));
280
281     String response = ws.newRequest()
282       .setParam(PARAM_KEY, profile.getKee())
283       .execute()
284       .getInput();
285
286     assertJson(response).isSimilarTo("{\n" +
287       "\"events\": [\n" +
288       "    {\n" +
289       "      \"date\": \"2011-04-25T02:15:43+0200\",\n" +
290       "      \"action\": \"DEACTIVATED\",\n" +
291       "      \"authorLogin\": \"" + user.getLogin() + "\",\n" +
292       "      \"ruleKey\": \"" + rule2.getKey() + "\",\n" +
293       "      \"ruleName\": \"" + rule2.getName() + "\",\n" +
294       "      \"params\": {}\n" +
295       "    },\n" +
296       "    {\n" +
297       "      \"date\": \"2011-04-25T02:15:42+0200\",\n" +
298       "      \"action\": \"ACTIVATED\",\n" +
299       "      \"ruleKey\": \"" + rule1.getKey() + "\",\n" +
300       "      \"ruleName\": \"" + rule1.getName() + "\",\n" +
301       "      \"params\": {\n" +
302       "        \"severity\": \"MINOR\"\n" +
303       "      }\n" +
304       "    }\n" +
305       "  ]" +
306       "}");
307   }
308
309   @Test
310   public void changelog_on_no_more_existing_rule() {
311     OrganizationDto organization = db.organizations().insert();
312     QProfileDto qualityProfile = db.qualityProfiles().insert(organization);
313     UserDto user = db.users().insertUser();
314     insertChange(qualityProfile, ActiveRuleChange.Type.ACTIVATED, user,
315       ImmutableMap.of("ruleId", "123"));
316
317     String response = ws.newRequest()
318       .setParam(PARAM_LANGUAGE, qualityProfile.getLanguage())
319       .setParam(PARAM_QUALITY_PROFILE, qualityProfile.getName())
320       .setParam(PARAM_ORGANIZATION, organization.getKey())
321       .execute()
322       .getInput();
323
324     assertJson(response).isSimilarTo("{\n" +
325       "  \"events\": [\n" +
326       "    {\n" +
327       "      \"date\": \"" + DATE + "\",\n" +
328       "      \"action\": \"ACTIVATED\",\n" +
329       "      \"params\": {}\n" +
330       "    }\n" +
331       "  ]\n" +
332       "}");
333     assertThat(response).doesNotContain("ruleKey", "ruleName");
334   }
335
336   @Test
337   public void changelog_on_no_more_existing_user() {
338     OrganizationDto organization = db.organizations().insert();
339     QProfileDto qualityProfile = db.qualityProfiles().insert(organization);
340     RuleDefinitionDto rule = db.rules().insert();
341     insertChange(c -> c.setRulesProfileUuid(qualityProfile.getRulesProfileUuid())
342       .setUserUuid("UNKNOWN")
343       .setChangeType(ActiveRuleChange.Type.ACTIVATED.name())
344       .setData(ImmutableMap.of("ruleId", rule.getId())));
345
346     String response = ws.newRequest()
347       .setParam(PARAM_LANGUAGE, qualityProfile.getLanguage())
348       .setParam(PARAM_QUALITY_PROFILE, qualityProfile.getName())
349       .setParam(PARAM_ORGANIZATION, organization.getKey())
350       .execute()
351       .getInput();
352
353     assertJson(response).isSimilarTo("{\n" +
354       "  \"events\": [\n" +
355       "    {\n" +
356       "      \"date\": \"" + DATE + "\",\n" +
357       "      \"ruleKey\": \"" + rule.getKey() + "\",\n" +
358       "      \"ruleName\": \"" + rule.getName() + "\",\n" +
359       "      \"action\": \"ACTIVATED\",\n" +
360       "      \"params\": {}\n" +
361       "    }\n" +
362       "  ]\n" +
363       "}");
364     assertThat(response).doesNotContain("authorLogin", "authorName");
365   }
366
367   @Test
368   public void changelog_on_paid_organization() {
369     OrganizationDto organization = db.organizations().insert(o -> o.setSubscription(PAID));
370     UserDto user = db.users().insertUser();
371     userSession.logIn(user).addMembership(organization);
372     QProfileDto qualityProfile = db.qualityProfiles().insert(organization);
373     RuleDefinitionDto rule = db.rules().insert();
374     insertChange(qualityProfile, ActiveRuleChange.Type.ACTIVATED, db.users().insertUser(),
375       ImmutableMap.of(
376         "ruleId", valueOf(rule.getId()),
377         "severity", "MINOR"));
378
379     String response = ws.newRequest()
380       .setParam(PARAM_LANGUAGE, qualityProfile.getLanguage())
381       .setParam(PARAM_QUALITY_PROFILE, qualityProfile.getName())
382       .setParam(PARAM_ORGANIZATION, organization.getKey())
383       .execute()
384       .getInput();
385
386     assertJson(response).isSimilarTo("{\n" +
387       "  \"events\": [\n" +
388       "    {\n" +
389       "      \"ruleKey\": \"" + rule.getKey() + "\",\n" +
390       "    }\n" +
391       "  ]\n" +
392       "}");
393   }
394
395   @Test
396   public void do_not_find_changelog_by_wrong_organization_and_language_and_name() {
397     OrganizationDto organization1 = db.organizations().insert();
398     OrganizationDto organization2 = db.organizations().insert();
399     QProfileDto qualityProfile = db.qualityProfiles().insert(organization1);
400     RuleDefinitionDto rule = db.rules().insert();
401     UserDto user = db.users().insertUser();
402     insertChange(qualityProfile, ActiveRuleChange.Type.ACTIVATED, user,
403       ImmutableMap.of(
404         "ruleId", valueOf(rule.getId()),
405         "severity", "MINOR"));
406
407     expectedException.expect(NotFoundException.class);
408
409     ws.newRequest()
410       .setParam(PARAM_LANGUAGE, qualityProfile.getLanguage())
411       .setParam(PARAM_QUALITY_PROFILE, qualityProfile.getName())
412       .setParam(PARAM_ORGANIZATION, organization2.getKey())
413       .execute();
414   }
415
416   @Test
417   public void fail_on_paid_organization_when_not_member() {
418     OrganizationDto organization = db.organizations().insert(o -> o.setSubscription(PAID));
419     QProfileDto qualityProfile = db.qualityProfiles().insert(organization);
420
421     expectedException.expect(ForbiddenException.class);
422     expectedException.expectMessage(format("You're not member of organization '%s'", organization.getKey()));
423
424     ws.newRequest()
425       .setParam(PARAM_LANGUAGE, qualityProfile.getLanguage())
426       .setParam(PARAM_QUALITY_PROFILE, qualityProfile.getName())
427       .setParam(PARAM_ORGANIZATION, organization.getKey())
428       .execute();
429   }
430
431   @Test
432   public void example() {
433     OrganizationDto organization = db.organizations().insert();
434     QProfileDto profile = db.qualityProfiles().insert(organization);
435     String profileUuid = profile.getRulesProfileUuid();
436
437     system2.setNow(DateUtils.parseDateTime("2015-02-23T17:58:39+0100").getTime());
438     RuleDefinitionDto rule1 = db.rules().insert(RuleKey.of("squid", "S2438"), r -> r.setName("\"Threads\" should not be used where \"Runnables\" are expected"));
439     UserDto user1 = db.users().insertUser(u -> u.setLogin("anakin.skywalker").setName("Anakin Skywalker"));
440     insertChange(c -> c.setRulesProfileUuid(profileUuid)
441       .setUserUuid(user1.getUuid())
442       .setChangeType(ActiveRuleChange.Type.ACTIVATED.name())
443       .setData(ImmutableMap.of("severity", "CRITICAL", "ruleId", valueOf(rule1.getId()))));
444
445     system2.setNow(DateUtils.parseDateTime("2015-02-23T17:58:18+0100").getTime());
446     RuleDefinitionDto rule2 = db.rules().insert(RuleKey.of("squid", "S2162"), r -> r.setName("\"equals\" methods should be symmetric and work for subclasses"));
447     UserDto user2 = db.users().insertUser(u -> u.setLogin("padme.amidala").setName("Padme Amidala"));
448     QProfileChangeDto change2 = insertChange(c -> c.setRulesProfileUuid(profileUuid)
449       .setUserUuid(user2.getUuid())
450       .setChangeType(ActiveRuleChange.Type.DEACTIVATED.name())
451       .setData(ImmutableMap.of("ruleId", valueOf(rule2.getId()))));
452
453     system2.setNow(DateUtils.parseDateTime("2014-09-12T15:20:46+0200").getTime());
454     RuleDefinitionDto rule3 = db.rules().insert(RuleKey.of("squid", "S00101"), r -> r.setName("Class names should comply with a naming convention"));
455     UserDto user3 = db.users().insertUser(u -> u.setLogin("obiwan.kenobi").setName("Obiwan Kenobi"));
456     QProfileChangeDto change3 = insertChange(c -> c.setRulesProfileUuid(profileUuid)
457       .setUserUuid(user3.getUuid())
458       .setChangeType(ActiveRuleChange.Type.ACTIVATED.name())
459       .setData(ImmutableMap.of("severity", "MAJOR", "param_format", "^[A-Z][a-zA-Z0-9]*$", "ruleId", valueOf(rule3.getId()))));
460
461     String response = ws.newRequest()
462       .setMethod("GET")
463       .setParam(PARAM_KEY, profile.getKee())
464       .setParam("ps", "10")
465       .execute()
466       .getInput();
467
468     assertJson(response).isSimilarTo(getClass().getResource("changelog-example.json"));
469   }
470
471   @Test
472   public void definition() {
473     WebService.Action definition = ws.getDef();
474
475     assertThat(definition.isPost()).isFalse();
476     assertThat(definition.responseExampleAsString()).isNotEmpty();
477     assertThat(definition.params()).extracting(WebService.Param::key)
478       .containsExactlyInAnyOrder("key", "qualityProfile", "language", "organization", "since", "to", "p", "ps");
479     WebService.Param profileName = definition.param("qualityProfile");
480     assertThat(profileName.deprecatedSince()).isNullOrEmpty();
481     WebService.Param language = definition.param("language");
482     assertThat(language.deprecatedSince()).isNullOrEmpty();
483   }
484
485   private QProfileChangeDto insertChange(QProfileDto profile, ActiveRuleChange.Type type, @Nullable UserDto user, @Nullable Map<String, Object> data) {
486     return insertChange(c -> c.setRulesProfileUuid(profile.getRulesProfileUuid())
487       .setUserUuid(user == null ? null : user.getUuid())
488       .setChangeType(type.name())
489       .setData(data));
490   }
491
492   @SafeVarargs
493   private final QProfileChangeDto insertChange(Consumer<QProfileChangeDto>... consumers) {
494     QProfileChangeDto dto = new QProfileChangeDto();
495     Arrays.stream(consumers).forEach(c -> c.accept(dto));
496     db.getDbClient().qProfileChangeDao().insert(db.getSession(), dto);
497     db.commit();
498     return dto;
499   }
500 }