3 * Copyright (C) 2009-2022 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;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.io.Reader;
25 import java.io.StringWriter;
26 import java.io.Writer;
27 import java.util.Collection;
28 import org.junit.Before;
29 import org.junit.Test;
30 import org.mockito.ArgumentCaptor;
31 import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
32 import org.sonar.api.profiles.ProfileExporter;
33 import org.sonar.api.profiles.ProfileImporter;
34 import org.sonar.api.profiles.RulesProfile;
35 import org.sonar.api.rules.Rule;
36 import org.sonar.api.rules.RuleFinder;
37 import org.sonar.api.rules.RulePriority;
38 import org.sonar.api.utils.System2;
39 import org.sonar.api.utils.ValidationMessages;
40 import org.sonar.db.DbSession;
41 import org.sonar.db.DbTester;
42 import org.sonar.db.qualityprofile.QProfileDto;
43 import org.sonar.db.rule.RuleDefinitionDto;
44 import org.sonar.server.exceptions.BadRequestException;
45 import org.sonar.server.exceptions.NotFoundException;
46 import org.sonar.server.rule.DefaultRuleFinder;
47 import org.sonar.server.tester.UserSessionRule;
49 import static java.nio.charset.StandardCharsets.UTF_8;
50 import static org.apache.commons.io.IOUtils.toInputStream;
51 import static org.assertj.core.api.Assertions.assertThat;
52 import static org.assertj.core.api.Assertions.assertThatThrownBy;
53 import static org.mockito.ArgumentMatchers.any;
54 import static org.mockito.Mockito.mock;
55 import static org.mockito.Mockito.verify;
56 import static org.sonar.db.qualityprofile.QualityProfileTesting.newQualityProfileDto;
58 public class QProfileExportersTest {
61 public UserSessionRule userSessionRule = UserSessionRule.standalone();
63 private final System2 system2 = new AlwaysIncreasingSystem2();
66 public DbTester db = DbTester.create(system2);
68 private final RuleFinder ruleFinder = new DefaultRuleFinder(db.getDbClient());
69 private final ProfileExporter[] exporters = new ProfileExporter[] {
70 new StandardExporter(), new XooExporter()};
71 private final ProfileImporter[] importers = new ProfileImporter[] {
72 new XooProfileImporter(), new XooProfileImporterWithMessages(), new XooProfileImporterWithError()};
73 private RuleDefinitionDto rule;
74 private final QProfileRules qProfileRules = mock(QProfileRules.class);
75 private final QProfileExporters underTest = new QProfileExporters(db.getDbClient(), ruleFinder, qProfileRules, exporters, importers);
79 rule = db.rules().insert(r -> r.setLanguage("xoo").setRepositoryKey("SonarXoo").setRuleKey("R1"));
83 public void exportersForLanguage() {
84 assertThat(underTest.exportersForLanguage("xoo")).hasSize(2);
85 assertThat(underTest.exportersForLanguage("java")).hasSize(1);
86 assertThat(underTest.exportersForLanguage("java").get(0)).isInstanceOf(StandardExporter.class);
90 public void mimeType() {
91 assertThat(underTest.mimeType("xootool")).isEqualTo("plain/custom");
94 assertThat(underTest.mimeType("standard")).isEqualTo("text/plain");
98 public void import_xml() {
99 QProfileDto profile = createProfile();
101 underTest.importXml(profile, "XooProfileImporter", toInputStream("<xml/>", UTF_8), db.getSession());
103 ArgumentCaptor<QProfileDto> profileCapture = ArgumentCaptor.forClass(QProfileDto.class);
104 Class<Collection<RuleActivation>> collectionClass = (Class<Collection<RuleActivation>>) (Class) Collection.class;
105 ArgumentCaptor<Collection<RuleActivation>> activationCapture = ArgumentCaptor.forClass(collectionClass);
106 verify(qProfileRules).activateAndCommit(any(DbSession.class), profileCapture.capture(), activationCapture.capture());
108 assertThat(profileCapture.getValue().getKee()).isEqualTo(profile.getKee());
109 Collection<RuleActivation> activations = activationCapture.getValue();
110 assertThat(activations).hasSize(1);
111 RuleActivation activation = activations.iterator().next();
112 assertThat(activation.getRuleUuid()).isEqualTo(rule.getUuid());
113 assertThat(activation.getSeverity()).isEqualTo("CRITICAL");
117 public void import_xml_return_messages() {
118 QProfileDto profile = createProfile();
120 QProfileResult result = underTest.importXml(profile, "XooProfileImporterWithMessages", toInputStream("<xml/>", UTF_8), db.getSession());
122 assertThat(result.infos()).containsOnly("an info");
123 assertThat(result.warnings()).containsOnly("a warning");
127 public void fail_to_import_xml_when_error_in_importer() {
128 QProfileDto qProfileDto = newQualityProfileDto();
129 InputStream inputStream = toInputStream("<xml/>", UTF_8);
130 DbSession dbSession = db.getSession();
131 assertThatThrownBy(() -> underTest.importXml(
132 qProfileDto, "XooProfileImporterWithError", inputStream, dbSession))
133 .isInstanceOf(BadRequestException.class)
134 .hasMessage("error!");
138 public void fail_to_import_xml_on_unknown_importer() {
139 QProfileDto qProfileDto = newQualityProfileDto();
140 InputStream inputStream = toInputStream("<xml/>", UTF_8);
141 DbSession dbSession = db.getSession();
142 assertThatThrownBy(() -> underTest.importXml(qProfileDto, "Unknown", inputStream, dbSession))
143 .isInstanceOf(BadRequestException.class)
144 .hasMessage("No such importer : Unknown");
148 public void export_empty_profile() {
149 QProfileDto profile = createProfile();
151 StringWriter writer = new StringWriter();
152 underTest.export(db.getSession(), profile, "standard", writer);
153 assertThat(writer.toString()).isEqualTo("standard -> " + profile.getName() + " -> 0");
155 writer = new StringWriter();
156 underTest.export(db.getSession(), profile, "xootool", writer);
157 assertThat(writer.toString()).isEqualTo("xoo -> " + profile.getName() + " -> 0");
161 public void export_profile() {
162 QProfileDto profile = createProfile();
163 db.qualityProfiles().activateRule(profile, rule);
165 StringWriter writer = new StringWriter();
166 underTest.export(db.getSession(), profile, "standard", writer);
167 assertThat(writer.toString()).isEqualTo("standard -> " + profile.getName() + " -> 1");
169 writer = new StringWriter();
170 underTest.export(db.getSession(), profile, "xootool", writer);
171 assertThat(writer.toString()).isEqualTo("xoo -> " + profile.getName() + " -> 1");
175 public void export_throws_NotFoundException_if_exporter_does_not_exist() {
176 QProfileDto profile = createProfile();
178 assertThatThrownBy(() -> {
179 underTest.export(db.getSession(), profile, "does_not_exist", new StringWriter());
181 .isInstanceOf(NotFoundException.class)
182 .hasMessage("Unknown quality profile exporter: does_not_exist");
185 private QProfileDto createProfile() {
186 return db.qualityProfiles().insert(p -> p.setLanguage(rule.getLanguage()));
189 public static class XooExporter extends ProfileExporter {
190 public XooExporter() {
191 super("xootool", "Xoo Tool");
195 public String[] getSupportedLanguages() {
196 return new String[] {"xoo"};
200 public String getMimeType() {
201 return "plain/custom";
205 public void exportProfile(RulesProfile profile, Writer writer) {
207 writer.write("xoo -> " + profile.getName() + " -> " + profile.getActiveRules().size());
208 } catch (IOException e) {
209 throw new IllegalStateException(e);
214 public static class StandardExporter extends ProfileExporter {
215 public StandardExporter() {
216 super("standard", "Standard");
220 public void exportProfile(RulesProfile profile, Writer writer) {
222 writer.write("standard -> " + profile.getName() + " -> " + profile.getActiveRules().size());
223 } catch (IOException e) {
224 throw new IllegalStateException(e);
229 public class XooProfileImporter extends ProfileImporter {
230 public XooProfileImporter() {
231 super("XooProfileImporter", "Xoo Profile Importer");
235 public String[] getSupportedLanguages() {
236 return new String[] {"xoo"};
240 public RulesProfile importProfile(Reader reader, ValidationMessages messages) {
241 RulesProfile rulesProfile = RulesProfile.create();
242 rulesProfile.activateRule(Rule.create(rule.getRepositoryKey(), rule.getRuleKey()), RulePriority.CRITICAL);
247 public static class XooProfileImporterWithMessages extends ProfileImporter {
248 public XooProfileImporterWithMessages() {
249 super("XooProfileImporterWithMessages", "Xoo Profile Importer With Message");
253 public String[] getSupportedLanguages() {
254 return new String[] {};
258 public RulesProfile importProfile(Reader reader, ValidationMessages messages) {
259 messages.addWarningText("a warning");
260 messages.addInfoText("an info");
261 return RulesProfile.create();
265 public static class XooProfileImporterWithError extends ProfileImporter {
266 public XooProfileImporterWithError() {
267 super("XooProfileImporterWithError", "Xoo Profile Importer With Error");
271 public RulesProfile importProfile(Reader reader, ValidationMessages messages) {
272 messages.addErrorText("error!");
273 return RulesProfile.create();