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.

ShowActionTest.java 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  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. import org.junit.Rule;
  22. import org.junit.Test;
  23. import org.junit.rules.ExpectedException;
  24. import org.sonar.api.resources.Language;
  25. import org.sonar.api.resources.Languages;
  26. import org.sonar.api.server.ws.WebService;
  27. import org.sonar.api.utils.DateUtils;
  28. import org.sonar.api.utils.System2;
  29. import org.sonar.db.DbTester;
  30. import org.sonar.db.organization.OrganizationDto;
  31. import org.sonar.db.qualityprofile.QProfileDto;
  32. import org.sonar.db.rule.RuleDefinitionDto;
  33. import org.sonar.db.user.UserDto;
  34. import org.sonar.server.es.EsTester;
  35. import org.sonar.server.exceptions.ForbiddenException;
  36. import org.sonar.server.exceptions.NotFoundException;
  37. import org.sonar.server.organization.TestDefaultOrganizationProvider;
  38. import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
  39. import org.sonar.server.rule.index.RuleIndex;
  40. import org.sonar.server.rule.index.RuleIndexer;
  41. import org.sonar.server.tester.UserSessionRule;
  42. import org.sonar.server.ws.TestRequest;
  43. import org.sonar.server.ws.WsActionTester;
  44. import org.sonarqube.ws.MediaTypes;
  45. import org.sonarqube.ws.Qualityprofiles.ShowResponse;
  46. import org.sonarqube.ws.Qualityprofiles.ShowResponse.CompareToSonarWay;
  47. import org.sonarqube.ws.Qualityprofiles.ShowResponse.QualityProfile;
  48. import static java.lang.String.format;
  49. import static java.util.stream.IntStream.range;
  50. import static org.assertj.core.api.Assertions.assertThat;
  51. import static org.sonar.api.rule.RuleStatus.DEPRECATED;
  52. import static org.sonar.api.utils.DateUtils.parseDateTime;
  53. import static org.sonar.db.organization.OrganizationDto.Subscription.PAID;
  54. import static org.sonar.server.language.LanguageTesting.newLanguage;
  55. import static org.sonar.test.JsonAssert.assertJson;
  56. import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_COMPARE_TO_SONAR_WAY;
  57. import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_KEY;
  58. public class ShowActionTest {
  59. private static Language XOO1 = newLanguage("xoo1");
  60. private static Language XOO2 = newLanguage("xoo2");
  61. private static Languages LANGUAGES = new Languages(XOO1, XOO2);
  62. @Rule
  63. public EsTester es = EsTester.create();
  64. @Rule
  65. public DbTester db = DbTester.create();
  66. @Rule
  67. public UserSessionRule userSession = UserSessionRule.standalone();
  68. @Rule
  69. public ExpectedException expectedException = ExpectedException.none();
  70. private RuleIndexer ruleIndexer = new RuleIndexer(es.client(), db.getDbClient());
  71. private ActiveRuleIndexer activeRuleIndexer = new ActiveRuleIndexer(db.getDbClient(), es.client());
  72. private RuleIndex ruleIndex = new RuleIndex(es.client(), System2.INSTANCE);
  73. private WsActionTester ws = new WsActionTester(
  74. new ShowAction(db.getDbClient(), new QProfileWsSupport(db.getDbClient(), userSession, TestDefaultOrganizationProvider.from(db)), LANGUAGES, ruleIndex));
  75. @Test
  76. public void profile_info() {
  77. QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(XOO1.getKey()));
  78. ShowResponse result = call(ws.newRequest().setParam(PARAM_KEY, profile.getKee()));
  79. assertThat(result.getProfile())
  80. .extracting(QualityProfile::getKey, QualityProfile::getName, QualityProfile::getIsBuiltIn, QualityProfile::getLanguage, QualityProfile::getLanguageName,
  81. QualityProfile::getIsInherited)
  82. .containsExactly(profile.getKee(), profile.getName(), profile.isBuiltIn(), profile.getLanguage(), XOO1.getName(), false);
  83. }
  84. @Test
  85. public void default_profile() {
  86. QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(XOO1.getKey()));
  87. db.qualityProfiles().setAsDefault(profile);
  88. ShowResponse result = call(ws.newRequest().setParam(PARAM_KEY, profile.getKee()));
  89. assertThat(result.getProfile().getIsDefault()).isTrue();
  90. }
  91. @Test
  92. public void non_default_profile() {
  93. QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(XOO1.getKey()));
  94. QProfileDto defaultProfile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(XOO1.getKey()));
  95. db.qualityProfiles().setAsDefault(defaultProfile);
  96. ShowResponse result = call(ws.newRequest().setParam(PARAM_KEY, profile.getKee()));
  97. assertThat(result.getProfile().getIsDefault()).isFalse();
  98. }
  99. @Test
  100. public void map_dates() {
  101. long time = DateUtils.parseDateTime("2016-12-22T19:10:03+0100").getTime();
  102. QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p
  103. .setLanguage(XOO1.getKey())
  104. .setRulesUpdatedAt("2016-12-21T19:10:03+0100")
  105. .setLastUsed(time)
  106. .setUserUpdatedAt(time));
  107. ShowResponse result = call(ws.newRequest().setParam(PARAM_KEY, profile.getKee()));
  108. assertThat(result.getProfile().getRulesUpdatedAt()).isEqualTo("2016-12-21T19:10:03+0100");
  109. assertThat(parseDateTime(result.getProfile().getLastUsed()).getTime()).isEqualTo(time);
  110. assertThat(parseDateTime(result.getProfile().getUserUpdatedAt()).getTime()).isEqualTo(time);
  111. }
  112. @Test
  113. public void statistics() {
  114. QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(XOO1.getKey()));
  115. // Active rules
  116. range(0, 10)
  117. .mapToObj(i -> db.rules().insertRule(r -> r.setLanguage(XOO1.getKey())).getDefinition())
  118. .forEach(r -> db.qualityProfiles().activateRule(profile, r));
  119. // Deprecated rules
  120. range(0, 3)
  121. .mapToObj(i -> db.rules().insertRule(r -> r.setLanguage(XOO1.getKey()).setStatus(DEPRECATED)).getDefinition())
  122. .forEach(r -> db.qualityProfiles().activateRule(profile, r));
  123. // Projects
  124. range(0, 7)
  125. .mapToObj(i -> db.components().insertPrivateProject())
  126. .forEach(project -> db.qualityProfiles().associateWithProject(project, profile));
  127. ShowResponse result = call(ws.newRequest().setParam(PARAM_KEY, profile.getKee()));
  128. assertThat(result.getProfile())
  129. .extracting(QualityProfile::getActiveRuleCount, QualityProfile::getActiveDeprecatedRuleCount, QualityProfile::getProjectCount)
  130. .containsExactly(13L, 3L, 7L);
  131. }
  132. @Test
  133. public void compare_to_sonar_way_profile() {
  134. QProfileDto sonarWayProfile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setIsBuiltIn(true).setName("Sonar way").setLanguage(XOO1.getKey()));
  135. QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(XOO1.getKey()));
  136. RuleDefinitionDto commonRule = db.rules().insertRule(r -> r.setLanguage(XOO1.getKey())).getDefinition();
  137. RuleDefinitionDto sonarWayRule1 = db.rules().insertRule(r -> r.setLanguage(XOO1.getKey())).getDefinition();
  138. RuleDefinitionDto sonarWayRule2 = db.rules().insertRule(r -> r.setLanguage(XOO1.getKey())).getDefinition();
  139. RuleDefinitionDto profileRule1 = db.rules().insertRule(r -> r.setLanguage(XOO1.getKey())).getDefinition();
  140. RuleDefinitionDto profileRule2 = db.rules().insertRule(r -> r.setLanguage(XOO1.getKey())).getDefinition();
  141. RuleDefinitionDto profileRule3 = db.rules().insertRule(r -> r.setLanguage(XOO1.getKey())).getDefinition();
  142. db.qualityProfiles().activateRule(profile, commonRule);
  143. db.qualityProfiles().activateRule(profile, profileRule1);
  144. db.qualityProfiles().activateRule(profile, profileRule2);
  145. db.qualityProfiles().activateRule(profile, profileRule3);
  146. db.qualityProfiles().activateRule(sonarWayProfile, commonRule);
  147. db.qualityProfiles().activateRule(sonarWayProfile, sonarWayRule1);
  148. db.qualityProfiles().activateRule(sonarWayProfile, sonarWayRule2);
  149. ruleIndexer.indexOnStartup(ruleIndexer.getIndexTypes());
  150. activeRuleIndexer.indexOnStartup(activeRuleIndexer.getIndexTypes());
  151. CompareToSonarWay result = call(ws.newRequest()
  152. .setParam(PARAM_KEY, profile.getKee())
  153. .setParam(PARAM_COMPARE_TO_SONAR_WAY, "true"))
  154. .getCompareToSonarWay();
  155. assertThat(result)
  156. .extracting(CompareToSonarWay::getProfile, CompareToSonarWay::getProfileName, CompareToSonarWay::getMissingRuleCount)
  157. .containsExactly(sonarWayProfile.getKee(), sonarWayProfile.getName(), 2L);
  158. }
  159. @Test
  160. public void compare_to_sonar_way_profile_when_same_active_rules() {
  161. QProfileDto sonarWayProfile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setIsBuiltIn(true).setName("Sonar way").setLanguage(XOO1.getKey()));
  162. QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(XOO1.getKey()));
  163. RuleDefinitionDto commonRule = db.rules().insertRule(r -> r.setLanguage(XOO1.getKey())).getDefinition();
  164. db.qualityProfiles().activateRule(profile, commonRule);
  165. db.qualityProfiles().activateRule(sonarWayProfile, commonRule);
  166. ruleIndexer.indexOnStartup(ruleIndexer.getIndexTypes());
  167. activeRuleIndexer.indexOnStartup(activeRuleIndexer.getIndexTypes());
  168. CompareToSonarWay result = call(ws.newRequest()
  169. .setParam(PARAM_KEY, profile.getKee())
  170. .setParam(PARAM_COMPARE_TO_SONAR_WAY, "true"))
  171. .getCompareToSonarWay();
  172. assertThat(result)
  173. .extracting(CompareToSonarWay::getProfile, CompareToSonarWay::getProfileName, CompareToSonarWay::getMissingRuleCount)
  174. .containsExactly(sonarWayProfile.getKee(), sonarWayProfile.getName(), 0L);
  175. }
  176. @Test
  177. public void no_comparison_when_sonar_way_does_not_exist() {
  178. QProfileDto anotherSonarWayProfile = db.qualityProfiles().insert(db.getDefaultOrganization(),
  179. p -> p.setIsBuiltIn(true).setName("Another Sonar way").setLanguage(XOO1.getKey()));
  180. QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(XOO1.getKey()));
  181. ShowResponse result = call(ws.newRequest()
  182. .setParam(PARAM_KEY, profile.getKee())
  183. .setParam(PARAM_COMPARE_TO_SONAR_WAY, "true"));
  184. assertThat(result.hasCompareToSonarWay()).isFalse();
  185. }
  186. @Test
  187. public void no_comparison_when_profile_is_built_in() {
  188. QProfileDto sonarWayProfile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setIsBuiltIn(true).setName("Sonar way").setLanguage(XOO1.getKey()));
  189. QProfileDto anotherBuiltInProfile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setIsBuiltIn(true).setLanguage(XOO1.getKey()));
  190. ShowResponse result = call(ws.newRequest()
  191. .setParam(PARAM_KEY, anotherBuiltInProfile.getKee())
  192. .setParam(PARAM_COMPARE_TO_SONAR_WAY, "true"));
  193. assertThat(result.hasCompareToSonarWay()).isFalse();
  194. }
  195. @Test
  196. public void no_comparison_if_sonar_way_is_not_built_in() {
  197. QProfileDto sonarWayProfile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setIsBuiltIn(false).setName("Sonar way").setLanguage(XOO1.getKey()));
  198. QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(XOO1.getKey()));
  199. ShowResponse result = call(ws.newRequest()
  200. .setParam(PARAM_KEY, profile.getKee())
  201. .setParam(PARAM_COMPARE_TO_SONAR_WAY, "true"));
  202. assertThat(result.hasCompareToSonarWay()).isFalse();
  203. }
  204. @Test
  205. public void no_comparison_when_param_is_false() {
  206. QProfileDto sonarWayProfile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setIsBuiltIn(true).setName("Sonar way").setLanguage(XOO1.getKey()));
  207. QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(XOO1.getKey()));
  208. ShowResponse result = call(ws.newRequest()
  209. .setParam(PARAM_KEY, profile.getKee())
  210. .setParam(PARAM_COMPARE_TO_SONAR_WAY, "false"));
  211. assertThat(result.hasCompareToSonarWay()).isFalse();
  212. }
  213. @Test
  214. public void compare_to_sonarqube_way_profile() {
  215. QProfileDto sonarWayProfile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setIsBuiltIn(true).setName("SonarQube way").setLanguage(XOO1.getKey()));
  216. QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(XOO1.getKey()));
  217. CompareToSonarWay result = call(ws.newRequest()
  218. .setParam(PARAM_KEY, profile.getKee())
  219. .setParam(PARAM_COMPARE_TO_SONAR_WAY, "true"))
  220. .getCompareToSonarWay();
  221. assertThat(result)
  222. .extracting(CompareToSonarWay::getProfile, CompareToSonarWay::getProfileName)
  223. .containsExactly(sonarWayProfile.getKee(), sonarWayProfile.getName());
  224. }
  225. @Test
  226. public void compare_to_sonar_way_over_sonarqube_way() {
  227. QProfileDto sonarWayProfile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setIsBuiltIn(true).setName("Sonar way").setLanguage(XOO1.getKey()));
  228. QProfileDto sonarQubeWayProfile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setIsBuiltIn(true).setName("SonarQube way").setLanguage(XOO1.getKey()));
  229. QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(XOO1.getKey()));
  230. CompareToSonarWay result = call(ws.newRequest()
  231. .setParam(PARAM_KEY, profile.getKee())
  232. .setParam(PARAM_COMPARE_TO_SONAR_WAY, "true"))
  233. .getCompareToSonarWay();
  234. assertThat(result)
  235. .extracting(CompareToSonarWay::getProfile, CompareToSonarWay::getProfileName)
  236. .containsExactly(sonarWayProfile.getKee(), sonarWayProfile.getName());
  237. }
  238. @Test
  239. public void show_on_paid_organization() {
  240. OrganizationDto organization = db.organizations().insert();
  241. QProfileDto qualityProfile = db.qualityProfiles().insert(organization, p -> p.setLanguage(XOO1.getKey()));
  242. UserDto user = db.users().insertUser();
  243. db.organizations().addMember(organization, user);
  244. userSession.logIn(user);
  245. ShowResponse result = call(ws.newRequest().setParam(PARAM_KEY, qualityProfile.getKee()));
  246. assertThat(result.getProfile())
  247. .extracting(QualityProfile::getKey)
  248. .isEqualTo(qualityProfile.getKee());
  249. }
  250. @Test
  251. public void fail_if_profile_language_is_not_supported() {
  252. QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setKee("unknown-profile").setLanguage("kotlin"));
  253. expectedException.expect(NotFoundException.class);
  254. expectedException.expectMessage("Quality Profile with key 'unknown-profile' does not exist");
  255. call(ws.newRequest().setParam(PARAM_KEY, profile.getKee()));
  256. }
  257. @Test
  258. public void fail_if_profile_does_not_exist() {
  259. expectedException.expect(NotFoundException.class);
  260. expectedException.expectMessage("Quality Profile with key 'unknown-profile' does not exist");
  261. call(ws.newRequest().setParam(PARAM_KEY, "unknown-profile"));
  262. }
  263. @Test
  264. public void fail_on_paid_organization_when_not_member() {
  265. OrganizationDto organization = db.organizations().insert(o -> o.setSubscription(PAID));
  266. QProfileDto qualityProfile = db.qualityProfiles().insert(organization);
  267. expectedException.expect(ForbiddenException.class);
  268. expectedException.expectMessage(format("You're not member of organization '%s'", organization.getKey()));
  269. call(ws.newRequest().setParam(PARAM_KEY, qualityProfile.getKee()));
  270. }
  271. @Test
  272. public void json_example() {
  273. Language cs = newLanguage("cs", "C#");
  274. QProfileDto parentProfile = db.qualityProfiles().insert(db.getDefaultOrganization(),
  275. p -> p.setKee("AU-TpxcA-iU5OvuD2FL1")
  276. .setName("Parent Company Profile")
  277. .setLanguage(cs.getKey()));
  278. QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p
  279. .setKee("AU-TpxcA-iU5OvuD2FL3")
  280. .setName("My Company Profile")
  281. .setLanguage(cs.getKey())
  282. .setIsBuiltIn(false)
  283. .setRulesUpdatedAt("2016-12-22T19:10:03+0100")
  284. .setParentKee(parentProfile.getKee()));
  285. // Active rules
  286. range(0, 10)
  287. .mapToObj(i -> db.rules().insertRule(r -> r.setLanguage(cs.getKey())).getDefinition())
  288. .forEach(r -> db.qualityProfiles().activateRule(profile, r));
  289. // Projects
  290. range(0, 7)
  291. .mapToObj(i -> db.components().insertPrivateProject())
  292. .forEach(project -> db.qualityProfiles().associateWithProject(project, profile));
  293. ws = new WsActionTester(
  294. new ShowAction(db.getDbClient(), new QProfileWsSupport(db.getDbClient(), userSession, TestDefaultOrganizationProvider.from(db)), new Languages(cs), ruleIndex));
  295. String result = ws.newRequest().setParam(PARAM_KEY, profile.getKee()).execute().getInput();
  296. assertJson(result).ignoreFields("rulesUpdatedAt", "lastUsed", "userUpdatedAt").isSimilarTo(ws.getDef().responseExampleAsString());
  297. }
  298. @Test
  299. public void test_definition() {
  300. WebService.Action action = ws.getDef();
  301. assertThat(action.key()).isEqualTo("show");
  302. assertThat(action.responseExampleAsString()).isNotEmpty();
  303. assertThat(action.isPost()).isFalse();
  304. assertThat(action.since()).isEqualTo("6.5");
  305. WebService.Param profile = action.param("key");
  306. assertThat(profile.isRequired()).isTrue();
  307. assertThat(profile.isInternal()).isFalse();
  308. assertThat(profile.description()).isNotEmpty();
  309. WebService.Param compareToSonarWay = action.param("compareToSonarWay");
  310. assertThat(compareToSonarWay.isRequired()).isFalse();
  311. assertThat(compareToSonarWay.isInternal()).isTrue();
  312. assertThat(compareToSonarWay.description()).isNotEmpty();
  313. assertThat(compareToSonarWay.defaultValue()).isEqualTo("false");
  314. assertThat(compareToSonarWay.possibleValues()).contains("true", "false");
  315. }
  316. private ShowResponse call(TestRequest request) {
  317. TestRequest wsRequest = request.setMediaType(MediaTypes.PROTOBUF);
  318. return wsRequest.executeProtobuf(ShowResponse.class);
  319. }
  320. }