]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-1809: Export / import alerts attached to a quality profile
authorGodin <mandrikov@gmail.com>
Wed, 8 Dec 2010 19:22:18 +0000 (19:22 +0000)
committerGodin <mandrikov@gmail.com>
Wed, 8 Dec 2010 19:22:18 +0000 (19:22 +0000)
plugins/sonar-checkstyle-plugin/src/test/java/org/sonar/plugins/checkstyle/SonarWayProfileTest.java
plugins/sonar-checkstyle-plugin/src/test/java/org/sonar/plugins/checkstyle/SonarWayWithFindbugsProfileTest.java
plugins/sonar-checkstyle-plugin/src/test/java/org/sonar/plugins/checkstyle/SunConventionsProfileTest.java
sonar-plugin-api/src/main/java/org/sonar/api/profiles/XMLProfileParser.java
sonar-plugin-api/src/main/java/org/sonar/api/profiles/XMLProfileSerializer.java
sonar-plugin-api/src/test/java/org/sonar/api/profiles/XMLProfileParserTest.java
sonar-plugin-api/src/test/java/org/sonar/api/profiles/XMLProfileSerializerTest.java
sonar-plugin-api/src/test/resources/org/sonar/api/profiles/XMLProfileParserTest/importProfileWithAlerts.xml [new file with mode: 0644]
sonar-plugin-api/src/test/resources/org/sonar/api/profiles/XMLProfileSerializerTest/exportAlerts.xml [new file with mode: 0644]

index 23a396505175ea34704fa7b8edb38aae807ef771..fef7df549a443c53e83a436ce386f0329a868eee 100644 (file)
@@ -22,6 +22,7 @@ package org.sonar.plugins.checkstyle;
 import org.junit.Test;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
+import org.sonar.api.measures.MetricFinder;
 import org.sonar.api.profiles.ProfileDefinition;
 import org.sonar.api.profiles.RulesProfile;
 import org.sonar.api.profiles.XMLProfileParser;
@@ -40,7 +41,7 @@ public class SonarWayProfileTest {
 
   @Test
   public void shouldCreateProfile() {
-    ProfileDefinition sonarWay = new SonarWayProfile(new XMLProfileParser(newRuleFinder()));
+    ProfileDefinition sonarWay = new SonarWayProfile(new XMLProfileParser(newRuleFinder(), mock(MetricFinder.class)));
     ValidationMessages validation = ValidationMessages.create();
     RulesProfile profile = sonarWay.createProfile(validation);
     assertThat(profile.getActiveRulesByRepository(CheckstyleConstants.REPOSITORY_KEY).size(), greaterThan(1));
@@ -49,7 +50,7 @@ public class SonarWayProfileTest {
 
   private RuleFinder newRuleFinder() {
     RuleFinder ruleFinder = mock(RuleFinder.class);
-    when(ruleFinder.findByKey(anyString(), anyString())).thenAnswer(new Answer<Rule>(){
+    when(ruleFinder.findByKey(anyString(), anyString())).thenAnswer(new Answer<Rule>() {
       public Rule answer(InvocationOnMock iom) throws Throwable {
         return Rule.create((String) iom.getArguments()[0], (String) iom.getArguments()[1], (String) iom.getArguments()[1]);
       }
index d5af6c0b2367ad6bdc916b30040e14f60ae6cc0f..c53eff084caa72a171ccb080c95ced14dc3b195e 100644 (file)
@@ -22,6 +22,7 @@ package org.sonar.plugins.checkstyle;
 import org.junit.Test;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
+import org.sonar.api.measures.MetricFinder;
 import org.sonar.api.profiles.RulesProfile;
 import org.sonar.api.profiles.XMLProfileParser;
 import org.sonar.api.rules.Rule;
@@ -39,7 +40,7 @@ public class SonarWayWithFindbugsProfileTest {
   @Test
   public void shouldBeSameAsSonarWay() {
     RuleFinder ruleFinder = newRuleFinder();
-    SonarWayProfile sonarWay = new SonarWayProfile(new XMLProfileParser(ruleFinder));
+    SonarWayProfile sonarWay = new SonarWayProfile(new XMLProfileParser(ruleFinder, mock(MetricFinder.class)));
     RulesProfile withoutFindbugs = sonarWay.createProfile(ValidationMessages.create());
     RulesProfile withFindbugs = new SonarWayWithFindbugsProfile(sonarWay).createProfile(ValidationMessages.create());
     assertThat(withFindbugs.getActiveRules().size(), is(withoutFindbugs.getActiveRules().size()));
index 147006e30eb764dd0d109fcb9060786d1ef584c1..4f2bb9361d8e555eacef7f74839f7fc4c96904e2 100644 (file)
@@ -23,6 +23,7 @@ import org.hamcrest.core.Is;
 import org.junit.Test;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
+import org.sonar.api.measures.MetricFinder;
 import org.sonar.api.profiles.ProfileDefinition;
 import org.sonar.api.profiles.RulesProfile;
 import org.sonar.api.profiles.XMLProfileParser;
@@ -39,7 +40,7 @@ import static org.mockito.Mockito.when;
 public class SunConventionsProfileTest {
   @Test
   public void shouldCreateProfile() {
-    ProfileDefinition definition = new SunConventionsProfile(new XMLProfileParser(newRuleFinder()));
+    ProfileDefinition definition = new SunConventionsProfile(new XMLProfileParser(newRuleFinder(), mock(MetricFinder.class)));
     ValidationMessages validation = ValidationMessages.create();
     RulesProfile sunProfile = definition.createProfile(validation);
     assertThat(sunProfile.getActiveRulesByRepository(CheckstyleConstants.REPOSITORY_KEY).size(), greaterThan(1));
index 571e2fd6d9b40d46c40cbefad1b2845ae300be8b..3ecff6e74fb999617755616cc4ae137e841374ab 100644 (file)
@@ -27,29 +27,34 @@ import org.codehaus.staxmate.SMInputFactory;
 import org.codehaus.staxmate.in.SMHierarchicCursor;
 import org.codehaus.staxmate.in.SMInputCursor;
 import org.sonar.api.ServerComponent;
+import org.sonar.api.measures.Metric;
+import org.sonar.api.measures.MetricFinder;
 import org.sonar.api.rules.ActiveRule;
 import org.sonar.api.rules.Rule;
 import org.sonar.api.rules.RuleFinder;
 import org.sonar.api.rules.RulePriority;
 import org.sonar.api.utils.ValidationMessages;
 
-import javax.xml.stream.XMLInputFactory;
-import javax.xml.stream.XMLStreamException;
 import java.io.InputStreamReader;
 import java.io.Reader;
 import java.nio.charset.Charset;
 import java.util.HashMap;
 import java.util.Map;
 
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+
 /**
  * @since 2.3
  */
 public final class XMLProfileParser implements ServerComponent {
 
   private RuleFinder ruleFinder;
+  private MetricFinder metricFinder;
 
-  public XMLProfileParser(RuleFinder ruleFinder) {
+  public XMLProfileParser(RuleFinder ruleFinder, MetricFinder metricFinder) {
     this.ruleFinder = ruleFinder;
+    this.metricFinder = metricFinder;
   }
 
   public RulesProfile parseResource(ClassLoader classloader, String xmlClassPath, ValidationMessages messages) {
@@ -75,6 +80,10 @@ public final class XMLProfileParser implements ServerComponent {
           SMInputCursor rulesCursor = cursor.childElementCursor("rule");
           processRules(rulesCursor, profile, messages);
 
+        } else if (StringUtils.equals("alerts", nodeName)) {
+          SMInputCursor alertsCursor = cursor.childElementCursor("alert");
+          processAlerts(alertsCursor, profile, messages);
+
         } else if (StringUtils.equals("name", nodeName)) {
           profile.setName(StringUtils.trim(cursor.collectDescendantText(false)));
 
@@ -105,8 +114,7 @@ public final class XMLProfileParser implements ServerComponent {
     // just so it won't try to load DTD in if there's DOCTYPE
     xmlFactory.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE);
     xmlFactory.setProperty(XMLInputFactory.IS_VALIDATING, Boolean.FALSE);
-    SMInputFactory inputFactory = new SMInputFactory(xmlFactory);
-    return inputFactory;
+    return new SMInputFactory(xmlFactory);
   }
 
   private void processRules(SMInputCursor rulesCursor, RulesProfile profile, ValidationMessages messages) throws XMLStreamException {
@@ -144,7 +152,8 @@ public final class XMLProfileParser implements ServerComponent {
         ActiveRule activeRule = profile.activateRule(rule, priority);
         for (Map.Entry<String, String> entry : parameters.entrySet()) {
           if (rule.getParam(entry.getKey()) == null) {
-            messages.addWarningText("The parameter '" + entry.getKey() + "' does not exist in the rule: [repository=" + repositoryKey + ", key=" + key + "]");
+            messages.addWarningText("The parameter '" + entry.getKey() + "' does not exist in the rule: [repository=" + repositoryKey
+                + ", key=" + key + "]");
           } else {
             activeRule.setParameter(entry.getKey(), entry.getValue());
           }
@@ -173,5 +182,41 @@ public final class XMLProfileParser implements ServerComponent {
     }
   }
 
+  private void processAlerts(SMInputCursor alertsCursor, RulesProfile profile, ValidationMessages messages) throws XMLStreamException {
+    while (alertsCursor.getNext() != null) {
+      SMInputCursor alertCursor = alertsCursor.childElementCursor();
+
+      String metricKey = null, operator = "", valueError = "", valueWarning = "";
+
+      while (alertCursor.getNext() != null) {
+        String nodeName = alertCursor.getLocalName();
+
+        if (StringUtils.equals("metric", nodeName)) {
+          metricKey = StringUtils.trim(alertCursor.collectDescendantText(false));
+
+        } else if (StringUtils.equals("operator", nodeName)) {
+          operator = StringUtils.trim(alertCursor.collectDescendantText(false));
+
+        } else if (StringUtils.equals("warning", nodeName)) {
+          valueWarning = StringUtils.trim(alertCursor.collectDescendantText(false));
+
+        } else if (StringUtils.equals("error", nodeName)) {
+          valueError = StringUtils.trim(alertCursor.collectDescendantText(false));
+        }
+      }
+
+      Metric metric = metricFinder.findByKey(metricKey);
+      if (metric == null) {
+        messages.addWarningText("Metric '" + metricKey + "' does not exist");
+      } else {
+        Alert alert = new Alert();
+        alert.setMetric(metric);
+        alert.setOperator(operator);
+        alert.setValueError(valueError);
+        alert.setValueWarning(valueWarning);
+        profile.getAlerts().add(alert);
+      }
+    }
+  }
 
 }
index 263c8171f010f42594ea391de401d1c495ac89f8..e462aa809f3c3e4f67d7086b09b4666ebd7db0c2 100644 (file)
@@ -38,6 +38,7 @@ public final class XMLProfileSerializer implements ServerComponent {
     try {
       appendHeader(profile, writer);
       appendRules(profile, writer);
+      appendAlerts(profile, writer);
       appendFooter(writer);
 
     } catch (IOException e) {
@@ -101,6 +102,28 @@ public final class XMLProfileSerializer implements ServerComponent {
     }
   }
 
+  private void appendAlerts(RulesProfile profile, Writer writer) throws IOException {
+    if (!profile.getAlerts().isEmpty()) {
+      writer.append("<alerts>");
+      for (Alert alert : profile.getAlerts()) {
+        appendAlert(alert, writer);
+      }
+      writer.append("</alerts>");
+    }
+  }
+
+  private void appendAlert(Alert alert, Writer writer) throws IOException {
+    writer.append("<alert><metric>");
+    StringEscapeUtils.escapeXml(writer, alert.getMetric().getKey());
+    writer.append("</metric><operator>");
+    StringEscapeUtils.escapeXml(writer, alert.getOperator());
+    writer.append("</operator><warning>");
+    StringEscapeUtils.escapeXml(writer, alert.getValueWarning());
+    writer.append("</warning><error>");
+    StringEscapeUtils.escapeXml(writer, alert.getValueError());
+    writer.append("</error></alert>");
+  }
+
   private void appendFooter(Writer writer) throws IOException {
     writer.append("</profile>");
   }
index 6c31b9d268855cd6a249c5cb2d24eda2bcb50b9d..6a6ca1af8da88c8fb37b06e72c1d3f246c1f2eba 100644 (file)
@@ -22,6 +22,8 @@ package org.sonar.api.profiles;
 import org.junit.Test;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
+import org.sonar.api.measures.Metric;
+import org.sonar.api.measures.MetricFinder;
 import org.sonar.api.rules.ActiveRule;
 import org.sonar.api.rules.Rule;
 import org.sonar.api.rules.RuleFinder;
@@ -44,8 +46,7 @@ public class XMLProfileParserTest {
   @Test
   public void importProfile() throws UnsupportedEncodingException {
     ValidationMessages validation = ValidationMessages.create();
-    RuleFinder ruleFinder = newRuleFinder();
-    RulesProfile profile = new XMLProfileParser(ruleFinder).parseResource(getClass().getClassLoader(), "org/sonar/api/profiles/XMLProfileParserTest/importProfile.xml", validation);
+    RulesProfile profile = parse("importProfile.xml", validation);
 
     assertThat(profile.getLanguage(), is("java"));
     assertThat(profile.getName(), is("sonar way"));
@@ -57,8 +58,7 @@ public class XMLProfileParserTest {
   @Test
   public void nameAndLanguageShouldBeMandatory() throws UnsupportedEncodingException {
     ValidationMessages validation = ValidationMessages.create();
-    RuleFinder ruleFinder = newRuleFinder();
-    RulesProfile profile = new XMLProfileParser(ruleFinder).parseResource(getClass().getClassLoader(), "org/sonar/api/profiles/XMLProfileParserTest/nameAndLanguageShouldBeMandatory.xml", validation);
+    parse("nameAndLanguageShouldBeMandatory.xml", validation);
 
     assertThat(validation.getErrors().size(), is(2));
     assertThat(validation.getErrors().get(0), containsString(""));
@@ -68,8 +68,7 @@ public class XMLProfileParserTest {
   @Test
   public void importProfileWithRuleParameters() throws UnsupportedEncodingException {
     ValidationMessages validation = ValidationMessages.create();
-    RuleFinder ruleFinder = newRuleFinder();
-    RulesProfile profile = new XMLProfileParser(ruleFinder).parseResource(getClass().getClassLoader(), "org/sonar/api/profiles/XMLProfileParserTest/importProfileWithRuleParameters.xml", validation);
+    RulesProfile profile = parse("importProfileWithRuleParameters.xml", validation);
 
     assertThat(validation.hasErrors(), is(false));
     assertThat(validation.hasWarnings(), is(false));
@@ -81,14 +80,41 @@ public class XMLProfileParserTest {
   @Test
   public void importProfileWithUnknownRuleParameter() throws UnsupportedEncodingException {
     ValidationMessages validation = ValidationMessages.create();
-    RuleFinder ruleFinder = newRuleFinder();
-    RulesProfile profile = new XMLProfileParser(ruleFinder).parseResource(getClass().getClassLoader(), "org/sonar/api/profiles/XMLProfileParserTest/importProfileWithUnknownRuleParameter.xml", validation);
+    RulesProfile profile = parse("importProfileWithUnknownRuleParameter.xml", validation);
 
     assertThat(validation.getWarnings().size(), is(1));
     ActiveRule rule = profile.getActiveRule("checkstyle", "IllegalRegexp");
     assertThat(rule.getParameter("unknown"), nullValue());
   }
 
+  @Test
+  public void importProfileWithAlerts() {
+    ValidationMessages validation = ValidationMessages.create();
+    RulesProfile profile = parse("importProfileWithAlerts.xml", validation);
+
+    assertThat(profile.getAlerts().size(), is(1));
+    Alert alert = profile.getAlerts().get(0);
+    assertThat(alert.getMetric().getKey(), is("complexity"));
+    assertThat(alert.getOperator(), is(Alert.OPERATOR_GREATER));
+    assertThat(alert.getValueWarning(), is("10"));
+    assertThat(alert.getValueError(), is("12"));
+  }
+
+  private RulesProfile parse(String resource, ValidationMessages validation) {
+    return new XMLProfileParser(newRuleFinder(), newMetricFinder())
+        .parseResource(getClass().getClassLoader(), "org/sonar/api/profiles/XMLProfileParserTest/" + resource, validation);
+  }
+
+  private MetricFinder newMetricFinder() {
+    MetricFinder metricFinder = mock(MetricFinder.class);
+    when(metricFinder.findByKey(anyString())).thenAnswer(new Answer<Metric>() {
+      public Metric answer(InvocationOnMock iom) throws Throwable {
+        return new Metric((String) iom.getArguments()[0]);
+      }
+    });
+    return metricFinder;
+  }
+
   private RuleFinder newRuleFinder() {
     RuleFinder ruleFinder = mock(RuleFinder.class);
     when(ruleFinder.findByKey(anyString(), anyString())).thenAnswer(new Answer<Rule>() {
index 90169f10dab5d8a016944958e21a8e8cb8a09961..e63801dea3b48e634fb319a0be25d47a0c175c28 100644 (file)
@@ -24,6 +24,7 @@ import org.apache.commons.lang.CharUtils;
 import org.custommonkey.xmlunit.Diff;
 import org.custommonkey.xmlunit.XMLUnit;
 import org.junit.Test;
+import org.sonar.api.measures.Metric;
 import org.sonar.api.rules.ActiveRule;
 import org.sonar.api.rules.Rule;
 import org.sonar.api.rules.RulePriority;
@@ -75,6 +76,21 @@ public class XMLProfileSerializerTest {
     assertSimilarXml("/org/sonar/api/profiles/XMLProfileSerializerTest/exportRuleParameters.xml", writer.toString());
   }
 
+  @Test
+  public void exportAlerts() throws Exception {
+    Writer writer = new StringWriter();
+    RulesProfile profile = RulesProfile.create("sonar way", "java");
+    Alert alert = new Alert();
+    alert.setMetric(new Metric("coverage"));
+    alert.setOperator(Alert.OPERATOR_SMALLER);
+    alert.setValueError("60");
+    alert.setValueWarning("80");
+    profile.getAlerts().add(alert);
+    new XMLProfileSerializer().write(profile, writer);
+
+    assertSimilarXml("/org/sonar/api/profiles/XMLProfileSerializerTest/exportAlerts.xml", writer.toString());
+  }
+
   public static void assertSimilarXml(String pathToExpectedXml, String xml) throws IOException, SAXException {
     InputStream stream = XMLProfileSerializerTest.class.getResourceAsStream(pathToExpectedXml);
     try {
diff --git a/sonar-plugin-api/src/test/resources/org/sonar/api/profiles/XMLProfileParserTest/importProfileWithAlerts.xml b/sonar-plugin-api/src/test/resources/org/sonar/api/profiles/XMLProfileParserTest/importProfileWithAlerts.xml
new file mode 100644 (file)
index 0000000..3a34a30
--- /dev/null
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated by Sonar -->
+<profile>
+  <name>sonar way</name>
+  <language>java</language>
+  <rules>
+    <rule>
+      <repositoryKey>checkstyle</repositoryKey>
+      <key>IllegalRegexp</key>
+      <priority>CRITICAL</priority>
+    </rule>
+  </rules>
+  <alerts>
+    <alert>
+      <metric>complexity</metric>
+      <operator>&gt;</operator>
+      <error>12</error>
+      <warning>10</warning>
+    </alert>
+  </alerts>
+</profile>
\ No newline at end of file
diff --git a/sonar-plugin-api/src/test/resources/org/sonar/api/profiles/XMLProfileSerializerTest/exportAlerts.xml b/sonar-plugin-api/src/test/resources/org/sonar/api/profiles/XMLProfileSerializerTest/exportAlerts.xml
new file mode 100644 (file)
index 0000000..1a18598
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated by Sonar -->
+<profile>
+  <name>sonar way</name>
+  <language>java</language>
+  <alerts>
+    <alert>
+      <metric>coverage</metric>
+      <operator>&lt;</operator>
+      <error>60</error>
+      <warning>80</warning>
+    </alert>
+  </alerts>
+</profile>
\ No newline at end of file