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.

ExportActionTest.java 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  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 java.io.IOException;
  22. import java.io.Reader;
  23. import java.io.Writer;
  24. import javax.annotation.Nullable;
  25. import org.apache.commons.lang.StringUtils;
  26. import org.junit.Rule;
  27. import org.junit.Test;
  28. import org.junit.rules.ExpectedException;
  29. import org.sonar.api.profiles.ProfileExporter;
  30. import org.sonar.api.profiles.RulesProfile;
  31. import org.sonar.api.server.ws.WebService;
  32. import org.sonar.api.utils.System2;
  33. import org.sonar.db.DbClient;
  34. import org.sonar.db.DbSession;
  35. import org.sonar.db.DbTester;
  36. import org.sonar.db.organization.OrganizationDto;
  37. import org.sonar.db.qualityprofile.QProfileDto;
  38. import org.sonar.db.user.UserDto;
  39. import org.sonar.server.exceptions.BadRequestException;
  40. import org.sonar.server.exceptions.ForbiddenException;
  41. import org.sonar.server.exceptions.NotFoundException;
  42. import org.sonar.server.language.LanguageTesting;
  43. import org.sonar.server.organization.TestDefaultOrganizationProvider;
  44. import org.sonar.server.qualityprofile.QProfileBackuper;
  45. import org.sonar.server.qualityprofile.QProfileExporters;
  46. import org.sonar.server.qualityprofile.QProfileRestoreSummary;
  47. import org.sonar.server.tester.UserSessionRule;
  48. import org.sonar.server.ws.WsActionTester;
  49. import static java.lang.String.format;
  50. import static org.assertj.core.api.Assertions.assertThat;
  51. import static org.sonar.db.organization.OrganizationDto.Subscription.PAID;
  52. import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_KEY;
  53. import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_LANGUAGE;
  54. import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_ORGANIZATION;
  55. import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_QUALITY_PROFILE;
  56. public class ExportActionTest {
  57. private static final String XOO_LANGUAGE = "xoo";
  58. private static final String JAVA_LANGUAGE = "java";
  59. @Rule
  60. public DbTester db = DbTester.create(System2.INSTANCE);
  61. @Rule
  62. public UserSessionRule userSession = UserSessionRule.standalone();
  63. @Rule
  64. public ExpectedException expectedException = ExpectedException.none();
  65. private DbClient dbClient = db.getDbClient();
  66. private QProfileBackuper backuper = new TestBackuper();
  67. private QProfileWsSupport wsSupport = new QProfileWsSupport(dbClient, userSession, TestDefaultOrganizationProvider.from(db));
  68. @Test
  69. public void export_profile_with_key() {
  70. QProfileDto profile = createProfile(db.getDefaultOrganization(), false);
  71. WsActionTester tester = newWsActionTester(newExporter("polop"), newExporter("palap"));
  72. String result = tester.newRequest()
  73. .setParam(PARAM_KEY, profile.getKee())
  74. .setParam("exporterKey", "polop")
  75. .execute()
  76. .getInput();
  77. assertThat(result).isEqualTo("Profile " + profile.getLanguage() + "/" + profile.getName() + " exported by polop");
  78. }
  79. @Test
  80. public void export_profile_in_default_organization() {
  81. QProfileDto profile = createProfile(db.getDefaultOrganization(), false);
  82. WsActionTester tester = newWsActionTester(newExporter("polop"), newExporter("palap"));
  83. String result = tester.newRequest()
  84. .setParam("language", profile.getLanguage())
  85. .setParam("qualityProfile", profile.getName())
  86. .setParam("exporterKey", "polop").execute()
  87. .getInput();
  88. assertThat(result).isEqualTo("Profile " + profile.getLanguage() + "/" + profile.getName() + " exported by polop");
  89. }
  90. @Test
  91. public void export_profile_in_specified_organization() {
  92. OrganizationDto organization = db.organizations().insert();
  93. QProfileDto profile = createProfile(organization, false);
  94. WsActionTester tester = newWsActionTester(newExporter("polop"), newExporter("palap"));
  95. String result = tester.newRequest()
  96. .setParam("organization", organization.getKey())
  97. .setParam("language", profile.getLanguage())
  98. .setParam("qualityProfile", profile.getName())
  99. .setParam("exporterKey", "polop").execute()
  100. .getInput();
  101. assertThat(result).isEqualTo("Profile " + profile.getLanguage() + "/" + profile.getName() + " exported by polop");
  102. }
  103. @Test
  104. public void export_default_profile() {
  105. QProfileDto nonDefaultProfile = createProfile(db.getDefaultOrganization(), false);
  106. QProfileDto defaultProfile = createProfile(db.getDefaultOrganization(), true);
  107. WsActionTester tester = newWsActionTester(newExporter("polop"), newExporter("palap"));
  108. String result = tester.newRequest()
  109. .setParam("language", XOO_LANGUAGE)
  110. .setParam("exporterKey", "polop")
  111. .execute()
  112. .getInput();
  113. assertThat(result).isEqualTo("Profile " + defaultProfile.getLanguage() + "/" + defaultProfile.getName() + " exported by polop");
  114. }
  115. @Test
  116. public void return_backup_when_exporter_is_not_specified() {
  117. OrganizationDto organization = db.getDefaultOrganization();
  118. QProfileDto profile = createProfile(organization, false);
  119. String result = newWsActionTester(newExporter("polop")).newRequest()
  120. .setParam("language", profile.getLanguage())
  121. .setParam("qualityProfile", profile.getName())
  122. .execute()
  123. .getInput();
  124. assertThat(result).isEqualTo("Backup of " + profile.getLanguage() + "/" + profile.getKee());
  125. }
  126. @Test
  127. public void do_not_mismatch_profiles_with_other_organizations_and_languages() {
  128. OrganizationDto org1 = db.organizations().insert();
  129. OrganizationDto org2 = db.organizations().insert();
  130. QProfileDto defaultJavaInOrg1 = db.qualityProfiles().insert(org1, p -> p.setLanguage(JAVA_LANGUAGE).setName("Sonar Way"));
  131. QProfileDto nonDefaultJavaInOrg1 = db.qualityProfiles().insert(org1, p -> p.setLanguage(JAVA_LANGUAGE).setName("My Way"));
  132. QProfileDto defaultXooInOrg1 = db.qualityProfiles().insert(org1, p -> p.setLanguage(XOO_LANGUAGE).setName("Sonar Way"));
  133. QProfileDto nonDefaultXooInOrg1 = db.qualityProfiles().insert(org1, p -> p.setLanguage(XOO_LANGUAGE).setName("My Way"));
  134. QProfileDto defaultJavaInOrg2 = db.qualityProfiles().insert(org2, p -> p.setLanguage(JAVA_LANGUAGE).setName("Sonar Way"));
  135. QProfileDto nonDefaultJavaInOrg2 = db.qualityProfiles().insert(org2, p -> p.setLanguage(JAVA_LANGUAGE).setName("My Way"));
  136. QProfileDto defaultXooInOrg2 = db.qualityProfiles().insert(org2, p -> p.setLanguage(XOO_LANGUAGE).setName("Sonar Way"));
  137. QProfileDto nonDefaultXooInOrg2 = db.qualityProfiles().insert(org2, p -> p.setLanguage(XOO_LANGUAGE).setName("My Way"));
  138. db.qualityProfiles().setAsDefault(defaultJavaInOrg1, defaultJavaInOrg2, defaultXooInOrg1, defaultXooInOrg2);
  139. WsActionTester tester = newWsActionTester();
  140. // default profile for specified organization and language
  141. assertThat(tester.newRequest()
  142. .setParam("organization", org1.getKey())
  143. .setParam("language", defaultJavaInOrg1.getLanguage())
  144. .execute()
  145. .getInput())
  146. .isEqualTo("Backup of java/" + defaultJavaInOrg1.getKee());
  147. // profile for specified organization, language and name --> do not mix with Xoo profile or profile with same lang/name on other
  148. // organization
  149. assertThat(tester.newRequest()
  150. .setParam("organization", org1.getKey())
  151. .setParam("language", defaultJavaInOrg1.getLanguage())
  152. .setParam("name", defaultJavaInOrg1.getName())
  153. .execute()
  154. .getInput())
  155. .isEqualTo("Backup of java/" + defaultJavaInOrg1.getKee());
  156. }
  157. @Test
  158. public void export_profile_in_paid_organization() {
  159. OrganizationDto organization = db.organizations().insert(o -> o.setSubscription(PAID));
  160. QProfileDto profile = createProfile(organization, false);
  161. UserDto user = db.users().insertUser();
  162. userSession.logIn(user).addMembership(organization);
  163. WsActionTester tester = newWsActionTester(newExporter("polop"));
  164. String result = tester.newRequest()
  165. .setParam("organization", organization.getKey())
  166. .setParam("language", profile.getLanguage())
  167. .setParam("qualityProfile", profile.getName())
  168. .setParam("exporterKey", "polop").execute()
  169. .getInput();
  170. assertThat(result).isEqualTo("Profile " + profile.getLanguage() + "/" + profile.getName() + " exported by polop");
  171. }
  172. @Test
  173. public void throw_NotFoundException_if_profile_with_specified_name_does_not_exist_in_default_organization() {
  174. expectedException.expect(NotFoundException.class);
  175. newWsActionTester().newRequest()
  176. .setParam("language", XOO_LANGUAGE)
  177. .setParam("exporterKey", "polop").execute();
  178. }
  179. @Test
  180. public void throw_IAE_if_export_with_specified_key_does_not_exist() {
  181. QProfileDto profile = createProfile(db.getDefaultOrganization(), true);
  182. expectedException.expect(IllegalArgumentException.class);
  183. expectedException.expectMessage("Value of parameter 'exporterKey' (unknown) must be one of: [polop, palap]");
  184. newWsActionTester(newExporter("polop"), newExporter("palap")).newRequest()
  185. .setParam("language", XOO_LANGUAGE)
  186. .setParam("exporterKey", "unknown").execute();
  187. }
  188. @Test
  189. public void throw_NotFoundException_if_specified_organization_does_not_exist() {
  190. WsActionTester tester = newWsActionTester(newExporter("foo"));
  191. expectedException.expect(NotFoundException.class);
  192. expectedException.expectMessage("No organization with key 'does_not_exist'");
  193. tester.newRequest()
  194. .setParam("organization", "does_not_exist")
  195. .setParam("language", XOO_LANGUAGE)
  196. .setParam("name", "bar")
  197. .setParam("exporterKey", "foo")
  198. .execute();
  199. }
  200. @Test
  201. public void fail_if_profile_key_is_unknown() {
  202. expectedException.expect(NotFoundException.class);
  203. expectedException.expectMessage("Could not find profile with key 'PROFILE-KEY-404'");
  204. WsActionTester ws = newWsActionTester(newExporter("polop"), newExporter("palap"));
  205. ws.newRequest()
  206. .setParam(PARAM_KEY, "PROFILE-KEY-404")
  207. .setParam("exporterKey", "polop").execute()
  208. .getInput();
  209. }
  210. @Test
  211. public void fail_if_profile_key_and_language_provided() {
  212. QProfileDto profile = createProfile(db.getDefaultOrganization(), false);
  213. expectedException.expect(BadRequestException.class);
  214. expectedException.expectMessage("Either 'key' or 'language' must be provided");
  215. WsActionTester ws = newWsActionTester(newExporter("polop"), newExporter("palap"));
  216. ws.newRequest()
  217. .setParam(PARAM_KEY, profile.getKee())
  218. .setParam(PARAM_LANGUAGE, profile.getLanguage())
  219. .setParam("exporterKey", "polop").execute()
  220. .getInput();
  221. }
  222. @Test
  223. public void fail_on_paid_organization_when_not_member() {
  224. WsActionTester tester = newWsActionTester(newExporter("foo"));
  225. OrganizationDto organization = db.organizations().insert(o -> o.setSubscription(PAID));
  226. QProfileDto qualityProfile = db.qualityProfiles().insert(organization, p -> p.setLanguage(XOO_LANGUAGE));
  227. expectedException.expect(ForbiddenException.class);
  228. expectedException.expectMessage(format("You're not member of organization '%s'", organization.getKey()));
  229. tester.newRequest()
  230. .setParam(PARAM_ORGANIZATION, organization.getKey())
  231. .setParam(PARAM_QUALITY_PROFILE, qualityProfile.getName())
  232. .setParam(PARAM_LANGUAGE, XOO_LANGUAGE)
  233. .setParam("exporterKey", "foo")
  234. .execute();
  235. }
  236. @Test
  237. public void definition_without_exporters() {
  238. WebService.Action definition = newWsActionTester().getDef();
  239. assertThat(definition.isPost()).isFalse();
  240. assertThat(definition.isInternal()).isFalse();
  241. assertThat(definition.params()).extracting(WebService.Param::key).containsExactlyInAnyOrder("key", "language", "qualityProfile", "organization");
  242. WebService.Param organizationParam = definition.param("organization");
  243. assertThat(organizationParam.since()).isEqualTo("6.4");
  244. assertThat(organizationParam.isInternal()).isTrue();
  245. WebService.Param key = definition.param("key");
  246. assertThat(key.since()).isEqualTo("6.5");
  247. assertThat(key.deprecatedSince()).isEqualTo("6.6");
  248. WebService.Param name = definition.param("qualityProfile");
  249. assertThat(name.deprecatedSince()).isNullOrEmpty();
  250. assertThat(name.deprecatedKey()).isEqualTo("name");
  251. WebService.Param language = definition.param("language");
  252. assertThat(language.deprecatedSince()).isNullOrEmpty();
  253. }
  254. @Test
  255. public void definition_with_exporters() {
  256. WebService.Action definition = newWsActionTester(newExporter("polop"), newExporter("palap")).getDef();
  257. assertThat(definition.isPost()).isFalse();
  258. assertThat(definition.isInternal()).isFalse();
  259. assertThat(definition.params()).extracting("key").containsExactlyInAnyOrder("key", "language", "qualityProfile", "organization", "exporterKey");
  260. WebService.Param exportersParam = definition.param("exporterKey");
  261. assertThat(exportersParam.possibleValues()).containsOnly("polop", "palap");
  262. assertThat(exportersParam.deprecatedKey()).isEqualTo("format");
  263. assertThat(exportersParam.deprecatedKeySince()).isEqualTo("6.3");
  264. assertThat(exportersParam.isInternal()).isFalse();
  265. }
  266. private QProfileDto createProfile(OrganizationDto organization, boolean isDefault) {
  267. QProfileDto profile = db.qualityProfiles().insert(organization, p -> p.setLanguage(XOO_LANGUAGE));
  268. if (isDefault) {
  269. db.qualityProfiles().setAsDefault(profile);
  270. }
  271. return profile;
  272. }
  273. private WsActionTester newWsActionTester(ProfileExporter... profileExporters) {
  274. QProfileExporters exporters = new QProfileExporters(dbClient, null, null, profileExporters, null);
  275. return new WsActionTester(new ExportAction(dbClient, backuper, exporters, LanguageTesting.newLanguages(XOO_LANGUAGE, JAVA_LANGUAGE), wsSupport));
  276. }
  277. private static ProfileExporter newExporter(String key) {
  278. return new ProfileExporter(key, StringUtils.capitalize(key)) {
  279. @Override
  280. public String getMimeType() {
  281. return "text/plain+" + key;
  282. }
  283. @Override
  284. public void exportProfile(RulesProfile profile, Writer writer) {
  285. try {
  286. writer.write(format("Profile %s/%s exported by %s", profile.getLanguage(), profile.getName(), key));
  287. } catch (IOException ioe) {
  288. throw new RuntimeException(ioe);
  289. }
  290. }
  291. };
  292. }
  293. private static class TestBackuper implements QProfileBackuper {
  294. @Override
  295. public void backup(DbSession dbSession, QProfileDto profile, Writer backupWriter) {
  296. try {
  297. backupWriter.write(format("Backup of %s/%s", profile.getLanguage(), profile.getKee()));
  298. } catch (IOException e) {
  299. throw new IllegalStateException(e);
  300. }
  301. }
  302. @Override
  303. public QProfileRestoreSummary restore(DbSession dbSession, Reader backup, OrganizationDto organization, @Nullable String overriddenProfileName) {
  304. throw new UnsupportedOperationException();
  305. }
  306. @Override
  307. public QProfileRestoreSummary restore(DbSession dbSession, Reader backup, QProfileDto profile) {
  308. throw new UnsupportedOperationException();
  309. }
  310. }
  311. }