You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ChangelogActionIT.java 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2023 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. import com.google.common.collect.ImmutableMap;
  22. import java.util.Arrays;
  23. import java.util.Map;
  24. import java.util.function.Consumer;
  25. import javax.annotation.Nullable;
  26. import org.junit.Rule;
  27. import org.junit.Test;
  28. import org.sonar.api.impl.utils.TestSystem2;
  29. import org.sonar.api.resources.Languages;
  30. import org.sonar.api.rule.RuleKey;
  31. import org.sonar.api.server.ws.WebService;
  32. import org.sonar.api.utils.DateUtils;
  33. import org.sonar.db.DbTester;
  34. import org.sonar.db.qualityprofile.QProfileChangeDto;
  35. import org.sonar.db.qualityprofile.QProfileDto;
  36. import org.sonar.db.rule.RuleDto;
  37. import org.sonar.db.user.UserDto;
  38. import org.sonar.server.qualityprofile.ActiveRuleChange;
  39. import org.sonar.server.qualityprofile.ActiveRuleInheritance;
  40. import org.sonar.server.tester.UserSessionRule;
  41. import org.sonar.server.ws.WsActionTester;
  42. import static org.assertj.core.api.Assertions.assertThat;
  43. import static org.sonar.test.JsonAssert.assertJson;
  44. import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_LANGUAGE;
  45. import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_QUALITY_PROFILE;
  46. import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_SINCE;
  47. public class ChangelogActionIT {
  48. private static final String DATE = "2011-04-25T01:15:42+0100";
  49. private final TestSystem2 system2 = new TestSystem2().setNow(DateUtils.parseDateTime(DATE).getTime());
  50. @Rule
  51. public DbTester db = DbTester.create(system2);
  52. @Rule
  53. public UserSessionRule userSession = UserSessionRule.standalone();
  54. private final QProfileWsSupport wsSupport = new QProfileWsSupport(db.getDbClient(), userSession);
  55. private final WsActionTester ws = new WsActionTester(new ChangelogAction(wsSupport, new Languages(), db.getDbClient()));
  56. @Test
  57. public void return_change_with_all_fields() {
  58. QProfileDto profile = db.qualityProfiles().insert();
  59. UserDto user = db.users().insertUser();
  60. RuleDto rule = db.rules().insert(RuleKey.of("java", "S001"));
  61. insertChange(profile, ActiveRuleChange.Type.ACTIVATED, user, ImmutableMap.of(
  62. "ruleUuid", rule.getUuid(),
  63. "severity", "MINOR",
  64. "inheritance", ActiveRuleInheritance.INHERITED.name(),
  65. "param_foo", "foo_value",
  66. "param_bar", "bar_value"));
  67. String response = ws.newRequest()
  68. .setParam(PARAM_LANGUAGE, profile.getLanguage())
  69. .setParam(PARAM_QUALITY_PROFILE, profile.getName())
  70. .execute()
  71. .getInput();
  72. assertJson(response).isSimilarTo("{\n" +
  73. " \"total\": 1,\n" +
  74. " \"p\": 1,\n" +
  75. " \"ps\": 50,\n" +
  76. " \"paging\": {\n" +
  77. " \"pageIndex\": 1,\n" +
  78. " \"pageSize\": 50,\n" +
  79. " \"total\": 1\n" +
  80. " }," +
  81. " \"events\": [\n" +
  82. " {\n" +
  83. " \"date\": \"" + DATE + "\",\n" +
  84. " \"authorLogin\": \"" + user.getLogin() + "\",\n" +
  85. " \"authorName\": \"" + user.getName() + "\",\n" +
  86. " \"action\": \"ACTIVATED\",\n" +
  87. " \"ruleKey\": \"" + rule.getKey() + "\",\n" +
  88. " \"ruleName\": \"" + rule.getName() + "\",\n" +
  89. " \"params\": {\n" +
  90. " \"severity\": \"MINOR\",\n" +
  91. " \"bar\": \"bar_value\",\n" +
  92. " \"foo\": \"foo_value\"\n" +
  93. " }\n" +
  94. " }\n" +
  95. " ]\n" +
  96. "}");
  97. }
  98. @Test
  99. public void find_changelog_by_profile_key() {
  100. QProfileDto profile = db.qualityProfiles().insert();
  101. RuleDto rule = db.rules().insert();
  102. UserDto user = db.users().insertUser();
  103. insertChange(profile, ActiveRuleChange.Type.ACTIVATED, user,
  104. ImmutableMap.of(
  105. "ruleUuid", rule.getUuid(),
  106. "severity", "MINOR"));
  107. String response = ws.newRequest()
  108. .setParam(PARAM_LANGUAGE, profile.getLanguage())
  109. .setParam(PARAM_QUALITY_PROFILE, profile.getName())
  110. .execute()
  111. .getInput();
  112. assertJson(response).isSimilarTo("{\n" +
  113. " \"events\": [\n" +
  114. " {\n" +
  115. " \"date\": \"" + DATE + "\",\n" +
  116. " \"authorLogin\": \"" + user.getLogin() + "\",\n" +
  117. " \"action\": \"ACTIVATED\",\n" +
  118. " \"ruleKey\": \"" + rule.getKey() + "\",\n" +
  119. " \"ruleName\": \"" + rule.getName() + "\",\n" +
  120. " \"params\": {\n" +
  121. " \"severity\": \"MINOR\"\n" +
  122. " }\n" +
  123. " }\n" +
  124. " ]\n" +
  125. "}");
  126. }
  127. @Test
  128. public void find_changelog_by_language_and_name() {
  129. QProfileDto qualityProfile = db.qualityProfiles().insert();
  130. RuleDto rule = db.rules().insert();
  131. UserDto user = db.users().insertUser();
  132. insertChange(qualityProfile, ActiveRuleChange.Type.ACTIVATED, user,
  133. ImmutableMap.of(
  134. "ruleUuid", rule.getUuid(),
  135. "severity", "MINOR"));
  136. String response = ws.newRequest()
  137. .setParam(PARAM_LANGUAGE, qualityProfile.getLanguage())
  138. .setParam(PARAM_QUALITY_PROFILE, qualityProfile.getName())
  139. .execute()
  140. .getInput();
  141. assertJson(response).isSimilarTo("{\n" +
  142. " \"events\": [\n" +
  143. " {\n" +
  144. " \"date\": \"" + DATE + "\",\n" +
  145. " \"authorLogin\": \"" + user.getLogin() + "\",\n" +
  146. " \"action\": \"ACTIVATED\",\n" +
  147. " \"ruleKey\": \"" + rule.getKey() + "\",\n" +
  148. " \"ruleName\": \"" + rule.getName() + "\",\n" +
  149. " \"params\": {\n" +
  150. " \"severity\": \"MINOR\"\n" +
  151. " }\n" +
  152. " }\n" +
  153. " ]\n" +
  154. "}");
  155. }
  156. @Test
  157. public void changelog_empty() {
  158. QProfileDto qualityProfile = db.qualityProfiles().insert();
  159. String response = ws.newRequest()
  160. .setParam(PARAM_LANGUAGE, qualityProfile.getLanguage())
  161. .setParam(PARAM_QUALITY_PROFILE, qualityProfile.getName())
  162. .execute()
  163. .getInput();
  164. assertJson(response).isSimilarTo("{\"total\":0,\"p\":1,\"ps\":50,\"paging\":{\"pageIndex\":1,\"pageSize\":50,\"total\":0},\"events\":[]}");
  165. }
  166. @Test
  167. public void changelog_filter_by_since() {
  168. QProfileDto qualityProfile = db.qualityProfiles().insert();
  169. system2.setNow(DateUtils.parseDateTime("2011-04-25T01:15:42+0100").getTime());
  170. RuleDto rule = db.rules().insert();
  171. UserDto user = db.users().insertUser();
  172. insertChange(qualityProfile, ActiveRuleChange.Type.ACTIVATED, user,
  173. ImmutableMap.of(
  174. "ruleUuid", rule.getUuid(),
  175. "severity", "MINOR"));
  176. assertJson(ws.newRequest()
  177. .setParam(PARAM_LANGUAGE, qualityProfile.getLanguage())
  178. .setParam(PARAM_QUALITY_PROFILE, qualityProfile.getName())
  179. .setParam(PARAM_SINCE, "2011-04-25T01:15:42+0100")
  180. .execute()
  181. .getInput()).isSimilarTo("{\n" +
  182. " \"events\": [\n" +
  183. " {\n" +
  184. " \"date\": \"2011-04-25T01:15:42+0100\",\n" +
  185. " \"authorLogin\": \"" + user.getLogin() + "\",\n" +
  186. " \"action\": \"ACTIVATED\",\n" +
  187. " \"ruleKey\": \"" + rule.getKey() + "\",\n" +
  188. " \"ruleName\": \"" + rule.getName() + "\",\n" +
  189. " }\n" +
  190. " ]\n" +
  191. "}");
  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:43+0100")
  196. .execute()
  197. .getInput()).isSimilarTo("{\n" +
  198. " \"events\": []\n" +
  199. "}");
  200. }
  201. @Test
  202. public void sort_changelog_events_in_reverse_chronological_order() {
  203. QProfileDto profile = db.qualityProfiles().insert();
  204. system2.setNow(DateUtils.parseDateTime("2011-04-25T01:15:42+0100").getTime());
  205. RuleDto rule1 = db.rules().insert();
  206. insertChange(profile, ActiveRuleChange.Type.ACTIVATED, null,
  207. ImmutableMap.of(
  208. "ruleUuid", rule1.getUuid(),
  209. "severity", "MINOR"));
  210. system2.setNow(DateUtils.parseDateTime("2011-04-25T01:15:43+0100").getTime());
  211. UserDto user = db.users().insertUser();
  212. RuleDto rule2 = db.rules().insert();
  213. insertChange(profile, ActiveRuleChange.Type.DEACTIVATED, user,
  214. ImmutableMap.of("ruleUuid", rule2.getUuid()));
  215. String response = ws.newRequest()
  216. .setParam(PARAM_LANGUAGE, profile.getLanguage())
  217. .setParam(PARAM_QUALITY_PROFILE, profile.getName())
  218. .execute()
  219. .getInput();
  220. assertJson(response).isSimilarTo("{\n" +
  221. "\"events\": [\n" +
  222. " {\n" +
  223. " \"date\": \"2011-04-25T02:15:43+0200\",\n" +
  224. " \"action\": \"DEACTIVATED\",\n" +
  225. " \"authorLogin\": \"" + user.getLogin() + "\",\n" +
  226. " \"ruleKey\": \"" + rule2.getKey() + "\",\n" +
  227. " \"ruleName\": \"" + rule2.getName() + "\",\n" +
  228. " \"params\": {}\n" +
  229. " },\n" +
  230. " {\n" +
  231. " \"date\": \"2011-04-25T02:15:42+0200\",\n" +
  232. " \"action\": \"ACTIVATED\",\n" +
  233. " \"ruleKey\": \"" + rule1.getKey() + "\",\n" +
  234. " \"ruleName\": \"" + rule1.getName() + "\",\n" +
  235. " \"params\": {\n" +
  236. " \"severity\": \"MINOR\"\n" +
  237. " }\n" +
  238. " }\n" +
  239. " ]" +
  240. "}");
  241. }
  242. @Test
  243. public void changelog_on_no_more_existing_rule() {
  244. QProfileDto qualityProfile = db.qualityProfiles().insert();
  245. UserDto user = db.users().insertUser();
  246. insertChange(qualityProfile, ActiveRuleChange.Type.ACTIVATED, user,
  247. ImmutableMap.of("ruleUuid", "123"));
  248. String response = ws.newRequest()
  249. .setParam(PARAM_LANGUAGE, qualityProfile.getLanguage())
  250. .setParam(PARAM_QUALITY_PROFILE, qualityProfile.getName())
  251. .execute()
  252. .getInput();
  253. assertJson(response).isSimilarTo("{\n" +
  254. " \"events\": [\n" +
  255. " {\n" +
  256. " \"date\": \"" + DATE + "\",\n" +
  257. " \"action\": \"ACTIVATED\",\n" +
  258. " \"params\": {}\n" +
  259. " }\n" +
  260. " ]\n" +
  261. "}");
  262. assertThat(response).doesNotContain("ruleKey", "ruleName");
  263. }
  264. @Test
  265. public void changelog_on_no_more_existing_user() {
  266. QProfileDto qualityProfile = db.qualityProfiles().insert();
  267. RuleDto rule = db.rules().insert();
  268. insertChange(c -> c.setRulesProfileUuid(qualityProfile.getRulesProfileUuid())
  269. .setUserUuid("UNKNOWN")
  270. .setChangeType(ActiveRuleChange.Type.ACTIVATED.name())
  271. .setData(ImmutableMap.of("ruleUuid", rule.getUuid())));
  272. String response = ws.newRequest()
  273. .setParam(PARAM_LANGUAGE, qualityProfile.getLanguage())
  274. .setParam(PARAM_QUALITY_PROFILE, qualityProfile.getName())
  275. .execute()
  276. .getInput();
  277. assertJson(response).isSimilarTo("{\n" +
  278. " \"events\": [\n" +
  279. " {\n" +
  280. " \"date\": \"" + DATE + "\",\n" +
  281. " \"ruleKey\": \"" + rule.getKey() + "\",\n" +
  282. " \"ruleName\": \"" + rule.getName() + "\",\n" +
  283. " \"action\": \"ACTIVATED\",\n" +
  284. " \"params\": {}\n" +
  285. " }\n" +
  286. " ]\n" +
  287. "}");
  288. assertThat(response).doesNotContain("authorLogin", "authorName");
  289. }
  290. @Test
  291. public void changelog_example() {
  292. QProfileDto profile = db.qualityProfiles().insert();
  293. String profileUuid = profile.getRulesProfileUuid();
  294. system2.setNow(DateUtils.parseDateTime("2015-02-23T17:58:39+0100").getTime());
  295. RuleDto rule1 = db.rules().insert(RuleKey.of("java", "S2438"), r -> r.setName("\"Threads\" should not be used where \"Runnables\" are expected"));
  296. UserDto user1 = db.users().insertUser(u -> u.setLogin("anakin.skywalker").setName("Anakin Skywalker"));
  297. insertChange(c -> c.setRulesProfileUuid(profileUuid)
  298. .setUserUuid(user1.getUuid())
  299. .setChangeType(ActiveRuleChange.Type.ACTIVATED.name())
  300. .setData(ImmutableMap.of("severity", "CRITICAL", "ruleUuid", rule1.getUuid())));
  301. system2.setNow(DateUtils.parseDateTime("2015-02-23T17:58:18+0100").getTime());
  302. RuleDto rule2 = db.rules().insert(RuleKey.of("java", "S2162"), r -> r.setName("\"equals\" methods should be symmetric and work for subclasses"));
  303. UserDto user2 = db.users().insertUser(u -> u.setLogin("padme.amidala").setName("Padme Amidala"));
  304. insertChange(c -> c.setRulesProfileUuid(profileUuid)
  305. .setUserUuid(user2.getUuid())
  306. .setChangeType(ActiveRuleChange.Type.DEACTIVATED.name())
  307. .setData(ImmutableMap.of("ruleUuid", rule2.getUuid())));
  308. system2.setNow(DateUtils.parseDateTime("2014-09-12T15:20:46+0200").getTime());
  309. RuleDto rule3 = db.rules().insert(RuleKey.of("java", "S00101"), r -> r.setName("Class names should comply with a naming convention"));
  310. UserDto user3 = db.users().insertUser(u -> u.setLogin("obiwan.kenobi").setName("Obiwan Kenobi"));
  311. insertChange(c -> c.setRulesProfileUuid(profileUuid)
  312. .setUserUuid(user3.getUuid())
  313. .setChangeType(ActiveRuleChange.Type.ACTIVATED.name())
  314. .setData(ImmutableMap.of("severity", "MAJOR", "param_format", "^[A-Z][a-zA-Z0-9]*$", "ruleUuid", rule3.getUuid())));
  315. ws.newRequest()
  316. .setMethod("GET")
  317. .setParam(PARAM_LANGUAGE, profile.getLanguage())
  318. .setParam(PARAM_QUALITY_PROFILE, profile.getName())
  319. .setParam("ps", "10")
  320. .execute()
  321. .assertJson(this.getClass(), "changelog_example.json");
  322. }
  323. @Test
  324. public void definition() {
  325. WebService.Action definition = ws.getDef();
  326. assertThat(definition.isPost()).isFalse();
  327. assertThat(definition.responseExampleAsString()).isNotEmpty();
  328. assertThat(definition.params()).extracting(WebService.Param::key)
  329. .containsExactlyInAnyOrder("qualityProfile", "language", "since", "to", "p", "ps");
  330. WebService.Param profileName = definition.param("qualityProfile");
  331. assertThat(profileName.deprecatedSince()).isNullOrEmpty();
  332. WebService.Param language = definition.param("language");
  333. assertThat(language.deprecatedSince()).isNullOrEmpty();
  334. }
  335. private QProfileChangeDto insertChange(QProfileDto profile, ActiveRuleChange.Type type, @Nullable UserDto user, @Nullable Map<String, Object> data) {
  336. return insertChange(c -> c.setRulesProfileUuid(profile.getRulesProfileUuid())
  337. .setUserUuid(user == null ? null : user.getUuid())
  338. .setChangeType(type.name())
  339. .setData(data));
  340. }
  341. @SafeVarargs
  342. private final QProfileChangeDto insertChange(Consumer<QProfileChangeDto>... consumers) {
  343. QProfileChangeDto dto = new QProfileChangeDto();
  344. Arrays.stream(consumers).forEach(c -> c.accept(dto));
  345. db.getDbClient().qProfileChangeDao().insert(db.getSession(), dto);
  346. db.commit();
  347. return dto;
  348. }
  349. }