3 * Copyright (C) 2009-2019 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 java.io.IOException;
23 import java.io.Reader;
24 import java.io.Writer;
25 import javax.annotation.Nullable;
26 import org.apache.commons.lang.StringUtils;
27 import org.junit.Rule;
28 import org.junit.Test;
29 import org.junit.rules.ExpectedException;
30 import org.sonar.api.profiles.ProfileExporter;
31 import org.sonar.api.profiles.RulesProfile;
32 import org.sonar.api.server.ws.WebService;
33 import org.sonar.api.utils.System2;
34 import org.sonar.db.DbClient;
35 import org.sonar.db.DbSession;
36 import org.sonar.db.DbTester;
37 import org.sonar.db.organization.OrganizationDto;
38 import org.sonar.db.qualityprofile.QProfileDto;
39 import org.sonar.db.user.UserDto;
40 import org.sonar.server.exceptions.BadRequestException;
41 import org.sonar.server.exceptions.ForbiddenException;
42 import org.sonar.server.exceptions.NotFoundException;
43 import org.sonar.server.language.LanguageTesting;
44 import org.sonar.server.organization.TestDefaultOrganizationProvider;
45 import org.sonar.server.qualityprofile.QProfileBackuper;
46 import org.sonar.server.qualityprofile.QProfileExporters;
47 import org.sonar.server.qualityprofile.QProfileRestoreSummary;
48 import org.sonar.server.tester.UserSessionRule;
49 import org.sonar.server.ws.WsActionTester;
51 import static java.lang.String.format;
52 import static org.assertj.core.api.Assertions.assertThat;
53 import static org.sonar.db.organization.OrganizationDto.Subscription.PAID;
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;
59 public class ExportActionTest {
61 private static final String XOO_LANGUAGE = "xoo";
62 private static final String JAVA_LANGUAGE = "java";
65 public DbTester db = DbTester.create(System2.INSTANCE);
67 public UserSessionRule userSession = UserSessionRule.standalone();
69 public ExpectedException expectedException = ExpectedException.none();
71 private DbClient dbClient = db.getDbClient();
72 private QProfileBackuper backuper = new TestBackuper();
73 private QProfileWsSupport wsSupport = new QProfileWsSupport(dbClient, userSession, TestDefaultOrganizationProvider.from(db));
76 public void export_profile_with_key() {
77 QProfileDto profile = createProfile(db.getDefaultOrganization(), false);
79 WsActionTester tester = newWsActionTester(newExporter("polop"), newExporter("palap"));
80 String result = tester.newRequest()
81 .setParam(PARAM_KEY, profile.getKee())
82 .setParam("exporterKey", "polop")
86 assertThat(result).isEqualTo("Profile " + profile.getLanguage() + "/" + profile.getName() + " exported by polop");
90 public void export_profile_in_default_organization() {
91 QProfileDto profile = createProfile(db.getDefaultOrganization(), false);
93 WsActionTester tester = newWsActionTester(newExporter("polop"), newExporter("palap"));
94 String result = tester.newRequest()
95 .setParam("language", profile.getLanguage())
96 .setParam("qualityProfile", profile.getName())
97 .setParam("exporterKey", "polop").execute()
100 assertThat(result).isEqualTo("Profile " + profile.getLanguage() + "/" + profile.getName() + " exported by polop");
104 public void export_profile_in_specified_organization() {
105 OrganizationDto organization = db.organizations().insert();
106 QProfileDto profile = createProfile(organization, false);
108 WsActionTester tester = newWsActionTester(newExporter("polop"), newExporter("palap"));
109 String result = tester.newRequest()
110 .setParam("organization", organization.getKey())
111 .setParam("language", profile.getLanguage())
112 .setParam("qualityProfile", profile.getName())
113 .setParam("exporterKey", "polop").execute()
116 assertThat(result).isEqualTo("Profile " + profile.getLanguage() + "/" + profile.getName() + " exported by polop");
120 public void export_default_profile() {
121 QProfileDto nonDefaultProfile = createProfile(db.getDefaultOrganization(), false);
122 QProfileDto defaultProfile = createProfile(db.getDefaultOrganization(), true);
124 WsActionTester tester = newWsActionTester(newExporter("polop"), newExporter("palap"));
125 String result = tester.newRequest()
126 .setParam("language", XOO_LANGUAGE)
127 .setParam("exporterKey", "polop")
131 assertThat(result).isEqualTo("Profile " + defaultProfile.getLanguage() + "/" + defaultProfile.getName() + " exported by polop");
135 public void return_backup_when_exporter_is_not_specified() {
136 OrganizationDto organization = db.getDefaultOrganization();
137 QProfileDto profile = createProfile(organization, false);
139 String result = newWsActionTester(newExporter("polop")).newRequest()
140 .setParam("language", profile.getLanguage())
141 .setParam("qualityProfile", profile.getName())
145 assertThat(result).isEqualTo("Backup of " + profile.getLanguage() + "/" + profile.getKee());
149 public void do_not_mismatch_profiles_with_other_organizations_and_languages() {
150 OrganizationDto org1 = db.organizations().insert();
151 OrganizationDto org2 = db.organizations().insert();
152 QProfileDto defaultJavaInOrg1 = db.qualityProfiles().insert(org1, p -> p.setLanguage(JAVA_LANGUAGE).setName("Sonar Way"));
153 QProfileDto nonDefaultJavaInOrg1 = db.qualityProfiles().insert(org1, p -> p.setLanguage(JAVA_LANGUAGE).setName("My Way"));
154 QProfileDto defaultXooInOrg1 = db.qualityProfiles().insert(org1, p -> p.setLanguage(XOO_LANGUAGE).setName("Sonar Way"));
155 QProfileDto nonDefaultXooInOrg1 = db.qualityProfiles().insert(org1, p -> p.setLanguage(XOO_LANGUAGE).setName("My Way"));
156 QProfileDto defaultJavaInOrg2 = db.qualityProfiles().insert(org2, p -> p.setLanguage(JAVA_LANGUAGE).setName("Sonar Way"));
157 QProfileDto nonDefaultJavaInOrg2 = db.qualityProfiles().insert(org2, p -> p.setLanguage(JAVA_LANGUAGE).setName("My Way"));
158 QProfileDto defaultXooInOrg2 = db.qualityProfiles().insert(org2, p -> p.setLanguage(XOO_LANGUAGE).setName("Sonar Way"));
159 QProfileDto nonDefaultXooInOrg2 = db.qualityProfiles().insert(org2, p -> p.setLanguage(XOO_LANGUAGE).setName("My Way"));
160 db.qualityProfiles().setAsDefault(defaultJavaInOrg1, defaultJavaInOrg2, defaultXooInOrg1, defaultXooInOrg2);
162 WsActionTester tester = newWsActionTester();
164 // default profile for specified organization and language
165 assertThat(tester.newRequest()
166 .setParam("organization", org1.getKey())
167 .setParam("language", defaultJavaInOrg1.getLanguage())
170 .isEqualTo("Backup of java/" + defaultJavaInOrg1.getKee());
172 // profile for specified organization, language and name --> do not mix with Xoo profile or profile with same lang/name on other
174 assertThat(tester.newRequest()
175 .setParam("organization", org1.getKey())
176 .setParam("language", defaultJavaInOrg1.getLanguage())
177 .setParam("name", defaultJavaInOrg1.getName())
180 .isEqualTo("Backup of java/" + defaultJavaInOrg1.getKee());
184 public void export_profile_in_paid_organization() {
185 OrganizationDto organization = db.organizations().insert(o -> o.setSubscription(PAID));
186 QProfileDto profile = createProfile(organization, false);
187 UserDto user = db.users().insertUser();
188 userSession.logIn(user).addMembership(organization);
190 WsActionTester tester = newWsActionTester(newExporter("polop"));
191 String result = tester.newRequest()
192 .setParam("organization", organization.getKey())
193 .setParam("language", profile.getLanguage())
194 .setParam("qualityProfile", profile.getName())
195 .setParam("exporterKey", "polop").execute()
198 assertThat(result).isEqualTo("Profile " + profile.getLanguage() + "/" + profile.getName() + " exported by polop");
202 public void throw_NotFoundException_if_profile_with_specified_name_does_not_exist_in_default_organization() {
203 expectedException.expect(NotFoundException.class);
205 newWsActionTester().newRequest()
206 .setParam("language", XOO_LANGUAGE)
207 .setParam("exporterKey", "polop").execute();
211 public void throw_IAE_if_export_with_specified_key_does_not_exist() {
212 QProfileDto profile = createProfile(db.getDefaultOrganization(), true);
214 expectedException.expect(IllegalArgumentException.class);
215 expectedException.expectMessage("Value of parameter 'exporterKey' (unknown) must be one of: [polop, palap]");
217 newWsActionTester(newExporter("polop"), newExporter("palap")).newRequest()
218 .setParam("language", XOO_LANGUAGE)
219 .setParam("exporterKey", "unknown").execute();
223 public void throw_NotFoundException_if_specified_organization_does_not_exist() {
224 WsActionTester tester = newWsActionTester(newExporter("foo"));
226 expectedException.expect(NotFoundException.class);
227 expectedException.expectMessage("No organization with key 'does_not_exist'");
230 .setParam("organization", "does_not_exist")
231 .setParam("language", XOO_LANGUAGE)
232 .setParam("name", "bar")
233 .setParam("exporterKey", "foo")
238 public void fail_if_profile_key_is_unknown() {
239 expectedException.expect(NotFoundException.class);
240 expectedException.expectMessage("Could not find profile with key 'PROFILE-KEY-404'");
242 WsActionTester ws = newWsActionTester(newExporter("polop"), newExporter("palap"));
244 .setParam(PARAM_KEY, "PROFILE-KEY-404")
245 .setParam("exporterKey", "polop").execute()
250 public void fail_if_profile_key_and_language_provided() {
251 QProfileDto profile = createProfile(db.getDefaultOrganization(), false);
253 expectedException.expect(BadRequestException.class);
254 expectedException.expectMessage("Either 'key' or 'language' must be provided");
256 WsActionTester ws = newWsActionTester(newExporter("polop"), newExporter("palap"));
258 .setParam(PARAM_KEY, profile.getKee())
259 .setParam(PARAM_LANGUAGE, profile.getLanguage())
260 .setParam("exporterKey", "polop").execute()
265 public void fail_on_paid_organization_when_not_member() {
266 WsActionTester tester = newWsActionTester(newExporter("foo"));
267 OrganizationDto organization = db.organizations().insert(o -> o.setSubscription(PAID));
268 QProfileDto qualityProfile = db.qualityProfiles().insert(organization, p -> p.setLanguage(XOO_LANGUAGE));
270 expectedException.expect(ForbiddenException.class);
271 expectedException.expectMessage(format("You're not member of organization '%s'", organization.getKey()));
274 .setParam(PARAM_ORGANIZATION, organization.getKey())
275 .setParam(PARAM_QUALITY_PROFILE, qualityProfile.getName())
276 .setParam(PARAM_LANGUAGE, XOO_LANGUAGE)
277 .setParam("exporterKey", "foo")
282 public void definition_without_exporters() {
283 WebService.Action definition = newWsActionTester().getDef();
285 assertThat(definition.isPost()).isFalse();
286 assertThat(definition.isInternal()).isFalse();
287 assertThat(definition.params()).extracting(WebService.Param::key).containsExactlyInAnyOrder("key", "language", "qualityProfile", "organization");
289 WebService.Param organizationParam = definition.param("organization");
290 assertThat(organizationParam.since()).isEqualTo("6.4");
291 assertThat(organizationParam.isInternal()).isTrue();
293 WebService.Param key = definition.param("key");
294 assertThat(key.since()).isEqualTo("6.5");
295 assertThat(key.deprecatedSince()).isEqualTo("6.6");
297 WebService.Param name = definition.param("qualityProfile");
298 assertThat(name.deprecatedSince()).isNullOrEmpty();
299 assertThat(name.deprecatedKey()).isEqualTo("name");
301 WebService.Param language = definition.param("language");
302 assertThat(language.deprecatedSince()).isNullOrEmpty();
306 public void definition_with_exporters() {
307 WebService.Action definition = newWsActionTester(newExporter("polop"), newExporter("palap")).getDef();
309 assertThat(definition.isPost()).isFalse();
310 assertThat(definition.isInternal()).isFalse();
311 assertThat(definition.params()).extracting("key").containsExactlyInAnyOrder("key", "language", "qualityProfile", "organization", "exporterKey");
312 WebService.Param exportersParam = definition.param("exporterKey");
313 assertThat(exportersParam.possibleValues()).containsOnly("polop", "palap");
314 assertThat(exportersParam.deprecatedKey()).isEqualTo("format");
315 assertThat(exportersParam.deprecatedKeySince()).isEqualTo("6.3");
316 assertThat(exportersParam.isInternal()).isFalse();
319 private QProfileDto createProfile(OrganizationDto organization, boolean isDefault) {
320 QProfileDto profile = db.qualityProfiles().insert(organization, p -> p.setLanguage(XOO_LANGUAGE));
322 db.qualityProfiles().setAsDefault(profile);
327 private WsActionTester newWsActionTester(ProfileExporter... profileExporters) {
328 QProfileExporters exporters = new QProfileExporters(dbClient, null, null, profileExporters, null);
329 return new WsActionTester(new ExportAction(dbClient, backuper, exporters, LanguageTesting.newLanguages(XOO_LANGUAGE, JAVA_LANGUAGE), wsSupport));
332 private static ProfileExporter newExporter(String key) {
333 return new ProfileExporter(key, StringUtils.capitalize(key)) {
335 public String getMimeType() {
336 return "text/plain+" + key;
340 public void exportProfile(RulesProfile profile, Writer writer) {
342 writer.write(format("Profile %s/%s exported by %s", profile.getLanguage(), profile.getName(), key));
343 } catch (IOException ioe) {
344 throw new RuntimeException(ioe);
350 private static class TestBackuper implements QProfileBackuper {
353 public void backup(DbSession dbSession, QProfileDto profile, Writer backupWriter) {
355 backupWriter.write(format("Backup of %s/%s", profile.getLanguage(), profile.getKee()));
356 } catch (IOException e) {
357 throw new IllegalStateException(e);
362 public QProfileRestoreSummary restore(DbSession dbSession, Reader backup, OrganizationDto organization, @Nullable String overriddenProfileName) {
363 throw new UnsupportedOperationException();
367 public QProfileRestoreSummary restore(DbSession dbSession, Reader backup, QProfileDto profile) {
368 throw new UnsupportedOperationException();
371 @Override public QProfileRestoreSummary copy(DbSession dbSession, QProfileDto from, QProfileDto to) {
372 throw new UnsupportedOperationException();