Browse Source

First draft of integration tests

tags/5.2-RC1
Simon Brandhof 9 years ago
parent
commit
81abdbffd8

+ 32
- 0
it/plugins/pom.xml View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.sonarsource.it</groupId>
<artifactId>it-parent</artifactId>
<version>5.2-SNAPSHOT</version>
</parent>
<artifactId>plugins</artifactId>
<name>SonarQube Integration Tests :: Plugins</name>
<description>The fake plugins used by integration tests</description>
<packaging>pom</packaging>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>

<modules>

</modules>

</project>

+ 37
- 0
it/pom.xml View File

@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.codehaus.sonar</groupId>
<artifactId>sonar</artifactId>
<version>5.2-SNAPSHOT</version>
</parent>

<groupId>org.sonarsource.it</groupId>
<artifactId>it-parent</artifactId>
<version>5.2-SNAPSHOT</version>
<name>SonarQube Integration Tests</name>
<packaging>pom</packaging>

<modules>
<module>plugins</module>
<module>tests</module>
</modules>

<dependencies>
<dependency>
<groupId>org.codehaus.sonar.plugins</groupId>
<artifactId>sonar-xoo-plugin</artifactId>
<version>${pom.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.codehaus.sonar</groupId>
<artifactId>sonar-application</artifactId>
<version>${pom.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

+ 5
- 0
it/projects/qualitygate/xoo-sample/sonar-project.properties View File

@@ -0,0 +1,5 @@
sonar.projectKey=sample
sonar.projectName=Sample
sonar.projectVersion=1.0-SNAPSHOT
sonar.sources=src
sonar.language=xoo

+ 12
- 0
it/projects/qualitygate/xoo-sample/src/sample/Sample.xoo View File

@@ -0,0 +1,12 @@
package sample;

public class Sample {
public Sample(int i) {
int j = i++;
}
private String myMethod() {
return "hello";
}
}

+ 11
- 0
it/projects/qualitygate/xoo-sample/src/sample/Sample.xoo.measures View File

@@ -0,0 +1,11 @@
ncloc:13
complexity:7
coverage:89.0
test_execution_time:630
sqale_index:4830
#Used by dashboard/widgets tests
complexity_in_classes:3
classes:1
comment_lines:3
public_api:5
public_undocumented_api:2

+ 12
- 0
it/projects/qualitygate/xoo-sample/src/sample/Sample2.xoo View File

@@ -0,0 +1,12 @@
package sample;

public class Sample {
public Sample(int i) {
int j = i++;
}
private String myMethod2() {
return "hello";
}
}

+ 10
- 0
it/projects/qualitygate/xoo-sample/src/sample/Sample2.xoo.measures View File

@@ -0,0 +1,10 @@
ncloc:13
complexity:7
coverage:89.0
test_execution_time:630
sqale_index:4830
complexity_in_classes:3
classes:1
comment_lines:3
public_api:5
public_undocumented_api:2

+ 94
- 0
it/tests/pom.xml View File

@@ -0,0 +1,94 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.sonarsource.it</groupId>
<artifactId>it-parent</artifactId>
<version>5.2-SNAPSHOT</version>
</parent>
<artifactId>tests</artifactId>
<name>SonarQube Integration Tests :: Tests</name>

<properties>
<category>*</category>
<surefire.argLine>-Xmx128m -server</surefire.argLine>
</properties>

<dependencies>
<dependency>
<groupId>org.codehaus.sonar</groupId>
<artifactId>sonar-ws-client</artifactId>
<version>5.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.sonarsource.orchestrator</groupId>
<artifactId>sonar-orchestrator</artifactId>
<version>3.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
<version>1.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.skyscreamer</groupId>
<artifactId>jsonassert</artifactId>
<version>1.2.0</version>
<scope>test</scope>
</dependency>


<!-- Email notifications -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-email</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.subethamail</groupId>
<artifactId>subethasmtp</artifactId>
<version>3.1.6</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<includes>
<include>org/sonar/it/${category}/suite/*TestSuite.java</include>
<!-- not included in suites -->
<include>org/sonar/it/${category}/*Test.java</include>
</includes>
<excludes>
<!-- included into suites -->
<exclude>org/sonar/it/*/suite/*Test.java</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>

</project>

+ 63
- 0
it/tests/src/test/java/org/sonar/it/ItUtils.java View File

@@ -0,0 +1,63 @@
/*
* Copyright (C) 2009-2014 SonarSource SA
* All rights reserved
* mailto:contact AT sonarsource DOT com
*/
package org.sonar.it;

import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.sonar.orchestrator.locator.FileLocation;
import java.io.File;
import org.apache.commons.io.FileUtils;

public class ItUtils {

private ItUtils() {
}

private static final Supplier<File> HOME_DIR = Suppliers.memoize(new Supplier<File>() {
@Override
public File get() {
File dir = new File("it");

// intellij way
if (dir.exists() && dir.isDirectory()) {
return dir.getParentFile();
}

// maven way
dir = new File("../it");
if (dir.exists() && dir.isDirectory()) {
return dir.getParentFile();
}

throw new IllegalStateException("Fail to locate home directory");
}
});

public static FileLocation xooPlugin() {
File target = new File(HOME_DIR.get(), "plugins/sonar-xoo-plugin/target");
if (target.exists()) {
for (File jar : FileUtils.listFiles(target, new String[] {"jar"}, false)) {
if (jar.getName().startsWith("sonar-xoo-plugin-") && !jar.getName().contains("-source")) {
return FileLocation.of(jar);
}
}
}
throw new IllegalStateException("XOO plugin is not built");
}

/**
* Locate the directory of sample project
*
* @param relativePath path related to the directory it/projects, for example "qualitygate/xoo-sample"
*/
public static File projectDir(String relativePath) {
File dir = new File(HOME_DIR.get(), "it/projects/" + relativePath);
if (!dir.exists() || !dir.isDirectory()) {
throw new IllegalStateException("Directory does not exist: " + dir.getAbsolutePath());
}
return dir;
}
}

+ 194
- 0
it/tests/src/test/java/org/sonar/it/qualitygate/QualityGateTest.java View File

@@ -0,0 +1,194 @@
/*
* Copyright (C) 2009-2014 SonarSource SA
* All rights reserved
* mailto:contact AT sonarsource DOT com
*/
package org.sonar.it.qualitygate;

import com.sonar.orchestrator.Orchestrator;
import com.sonar.orchestrator.build.SonarRunner;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Test;
import org.sonar.it.ItUtils;
import org.sonar.wsclient.project.NewProject;
import org.sonar.wsclient.qualitygate.NewCondition;
import org.sonar.wsclient.qualitygate.QualityGate;
import org.sonar.wsclient.qualitygate.QualityGateClient;
import org.sonar.wsclient.services.Measure;
import org.sonar.wsclient.services.Resource;
import org.sonar.wsclient.services.ResourceQuery;

import static org.assertj.core.api.Assertions.assertThat;
import static org.sonar.it.ItUtils.projectDir;

public class QualityGateTest {

private static final String PROJECT_KEY = "sample";

private long provisionnedProjectId = -1L;

@ClassRule
public static Orchestrator orchestrator = Orchestrator.builderEnv()
.addPlugin(ItUtils.xooPlugin())
.build();

@Before
public void cleanUp() throws Exception {
orchestrator.resetData();
provisionnedProjectId = Long.parseLong(orchestrator.getServer().adminWsClient().projectClient().create(NewProject.create().key(PROJECT_KEY).name("Sample")).id());
}

@Test
public void do_not_compute_status_if_no_gate() {
SonarRunner build = SonarRunner.create(projectDir("qualitygate/xoo-sample"));
orchestrator.executeBuild(build);

assertThat(fetchResourceWithGateStatus()).isNull();
}

@Test
public void status_ok_if_empty_gate() {
QualityGate empty = qgClient().create("Empty");
qgClient().setDefault(empty.id());

try {
SonarRunner build = SonarRunner.create(projectDir("qualitygate/xoo-sample"));
orchestrator.executeBuild(build);

assertThat(fetchGateStatus().getData()).isEqualTo("OK");
} finally {
qgClient().unsetDefault();
qgClient().destroy(empty.id());
}
}

@Test
public void test_status_ok() {
QualityGate simple = qgClient().create("SimpleWithHighThreshold");
qgClient().setDefault(simple.id());
qgClient().createCondition(NewCondition.create(simple.id()).metricKey("ncloc").operator("GT").warningThreshold("40"));

try {
SonarRunner build = SonarRunner.create(projectDir("qualitygate/xoo-sample"));
orchestrator.executeBuild(build);

assertThat(fetchGateStatus().getData()).isEqualTo("OK");
} finally {
qgClient().unsetDefault();
qgClient().destroy(simple.id());
}
}

@Test
public void test_status_warning() {
QualityGate simple = qgClient().create("SimpleWithLowThreshold");
qgClient().setDefault(simple.id());
qgClient().createCondition(NewCondition.create(simple.id()).metricKey("ncloc").operator("GT").warningThreshold("10"));

try {
SonarRunner build = SonarRunner.create(projectDir("qualitygate/xoo-sample"));
orchestrator.executeBuild(build);

assertThat(fetchGateStatus().getData()).isEqualTo("WARN");
} finally {
qgClient().unsetDefault();
qgClient().destroy(simple.id());
}

}

@Test
public void test_status_error() {
QualityGate simple = qgClient().create("SimpleWithLowThreshold");
qgClient().setDefault(simple.id());
qgClient().createCondition(NewCondition.create(simple.id()).metricKey("ncloc").operator("GT").errorThreshold("10"));

try {
SonarRunner build = SonarRunner.create(projectDir("qualitygate/xoo-sample"));
orchestrator.executeBuild(build);

assertThat(fetchGateStatus().getData()).isEqualTo("ERROR");
} finally {
qgClient().unsetDefault();
qgClient().destroy(simple.id());
}
}

@Test
public void use_server_settings_instead_of_default_gate() {
QualityGate alert = qgClient().create("AlertWithLowThreshold");
qgClient().createCondition(NewCondition.create(alert.id()).metricKey("ncloc").operator("GT").warningThreshold("10"));
QualityGate error = qgClient().create("ErrorWithLowThreshold");
qgClient().createCondition(NewCondition.create(error.id()).metricKey("ncloc").operator("GT").errorThreshold("10"));

qgClient().setDefault(alert.id());
qgClient().selectProject(error.id(), provisionnedProjectId);

try {
SonarRunner build = SonarRunner.create(projectDir("qualitygate/xoo-sample"));
orchestrator.executeBuild(build);

assertThat(fetchGateStatus().getData()).isEqualTo("ERROR");
} finally {
qgClient().unsetDefault();
qgClient().destroy(alert.id());
qgClient().destroy(error.id());
}
}

@Test
public void conditions_on_multiple_metric_types() {
QualityGate allTypes = qgClient().create("AllMetricTypes");
qgClient().createCondition(NewCondition.create(allTypes.id()).metricKey("ncloc").operator("GT").warningThreshold("10"));
qgClient().createCondition(NewCondition.create(allTypes.id()).metricKey("duplicated_lines_density").operator("GT").warningThreshold("20"));
qgClient().setDefault(allTypes.id());

try {
SonarRunner build = SonarRunner.create(projectDir("qualitygate/xoo-sample"))
.setProperty("sonar.cpd.xoo.minimumLines", "2")
.setProperty("sonar.cpd.xoo.minimumTokens", "5");
orchestrator.executeBuild(build);

Measure alertStatus = fetchGateStatus();
assertThat(alertStatus.getData()).isEqualTo("WARN");
assertThat(alertStatus.getAlertText())
.contains("Lines of code > 10")
.contains("Duplicated lines (%) > 20");
} finally {
qgClient().unsetDefault();
qgClient().destroy(allTypes.id());
}
}

@Test
public void compute_gate_status_on_metric_variation() {
QualityGate simple = qgClient().create("SimpleWithDifferential");
qgClient().setDefault(simple.id());
qgClient().createCondition(NewCondition.create(simple.id()).metricKey("ncloc").period(1).operator("EQ").warningThreshold("0"));

try {
SonarRunner build = SonarRunner.create(projectDir("qualitygate/xoo-sample"));
orchestrator.executeBuild(build);
assertThat(fetchGateStatus().getData()).isEqualTo("OK");

orchestrator.executeBuild(build);
assertThat(fetchGateStatus().getData()).isEqualTo("WARN");
} finally {
qgClient().unsetDefault();
qgClient().destroy(simple.id());
}
}

private Measure fetchGateStatus() {
return fetchResourceWithGateStatus().getMeasure("alert_status");
}

private Resource fetchResourceWithGateStatus() {
return orchestrator.getServer().getWsClient().find(ResourceQuery.createForMetrics(PROJECT_KEY, "alert_status").setIncludeAlerts(true));
}

private static QualityGateClient qgClient() {
return orchestrator.getServer().adminWsClient().qualityGateClient();
}
}

+ 71
- 0
plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/AbstractDeprecatedXooRuleSensor.java View File

@@ -0,0 +1,71 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* SonarQube is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.xoo.rule;

import org.sonar.api.batch.Sensor;
import org.sonar.api.batch.SensorContext;
import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.rule.ActiveRules;
import org.sonar.api.resources.File;
import org.sonar.api.resources.Project;
import org.sonar.api.rule.RuleKey;
import org.sonar.xoo.Xoo;

/**
* @deprecated to be replaced by {@link org.sonar.api.batch.sensor.Sensor}
*/
public abstract class AbstractDeprecatedXooRuleSensor implements Sensor {

private final FileSystem fs;
private final ActiveRules activeRules;

public AbstractDeprecatedXooRuleSensor(FileSystem fs, ActiveRules activeRules) {
this.fs = fs;
this.activeRules = activeRules;
}

protected abstract String getRuleKey();

@Override
public boolean shouldExecuteOnProject(Project project) {
return fs.hasFiles(fs.predicates().hasLanguages(Xoo.KEY))
&& (activeRules.find(RuleKey.of(XooRulesDefinition.XOO_REPOSITORY, getRuleKey())) != null);
}

@Override
public final void analyse(Project project, SensorContext context) {
doAnalyse(context, Xoo.KEY);
}

private void doAnalyse(SensorContext context, String languageKey) {
RuleKey ruleKey = RuleKey.of(XooRulesDefinition.XOO_REPOSITORY, getRuleKey());
if (activeRules.find(ruleKey) == null) {
return;
}
for (InputFile inputFile : fs.inputFiles(fs.predicates().hasLanguage(languageKey))) {
File sonarFile = File.create(inputFile.relativePath());
sonarFile = context.getResource(sonarFile);
processFile(inputFile, sonarFile, context, ruleKey, languageKey);
}
}

protected abstract void processFile(InputFile inputFile, File sonarFile, SensorContext context, RuleKey ruleKey, String languageKey);
}

+ 59
- 0
plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/CustomMessageSensor.java View File

@@ -0,0 +1,59 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* SonarQube is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.xoo.rule;

import org.sonar.api.batch.SensorContext;
import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.rule.ActiveRules;
import org.sonar.api.component.ResourcePerspectives;
import org.sonar.api.config.Settings;
import org.sonar.api.issue.Issuable;
import org.sonar.api.rule.RuleKey;

public class CustomMessageSensor extends AbstractDeprecatedXooRuleSensor {

public static final String RULE_KEY = "CustomMessage";

private static final String MESSAGE_PROPERTY = "sonar.customMessage.message";

private final ResourcePerspectives perspectives;
private final Settings settings;

public CustomMessageSensor(ResourcePerspectives perspectives, Settings settings, FileSystem fs, ActiveRules activeRules) {
super(fs, activeRules);
this.perspectives = perspectives;
this.settings = settings;
}

@Override
protected String getRuleKey() {
return RULE_KEY;
}

@Override
protected void processFile(InputFile inputFile, org.sonar.api.resources.File sonarFile, SensorContext context, RuleKey ruleKey, String languageKey) {
Issuable issuable = perspectives.as(Issuable.class, sonarFile);
issuable.addIssue(issuable.newIssueBuilder()
.ruleKey(ruleKey)
.message(settings.getString(MESSAGE_PROPERTY))
.build());
}
}

+ 85
- 0
plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/HasTagSensor.java View File

@@ -0,0 +1,85 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* SonarQube is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.xoo.rule;

import java.io.IOException;
import java.util.List;
import org.apache.commons.io.FileUtils;
import org.sonar.api.batch.SensorContext;
import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.rule.ActiveRules;
import org.sonar.api.component.ResourcePerspectives;
import org.sonar.api.config.Settings;
import org.sonar.api.issue.Issuable;
import org.sonar.api.rule.RuleKey;

/**
* Generate issues on all the occurrences of a given tag in xoo sources.
*/
public class HasTagSensor extends AbstractDeprecatedXooRuleSensor {

public static final String RULE_KEY = "HasTag";

private static final String EFFORT_TO_FIX_PROPERTY = "sonar.hasTag.effortToFix";

private final ResourcePerspectives perspectives;
private final Settings settings;
private final ActiveRules activeRules;

private FileSystem fs;

public HasTagSensor(FileSystem fs, ResourcePerspectives perspectives, Settings settings, ActiveRules activeRules) {
super(fs, activeRules);
this.fs = fs;
this.perspectives = perspectives;
this.settings = settings;
this.activeRules = activeRules;
}

@Override
protected String getRuleKey() {
return RULE_KEY;
}

@Override
protected void processFile(InputFile inputFile, org.sonar.api.resources.File sonarFile, SensorContext context, RuleKey ruleKey, String languageKey) {
org.sonar.api.batch.rule.ActiveRule activeRule = activeRules.find(ruleKey);
String tag = activeRule.param("tag");
if (tag == null) {
throw new IllegalStateException("Rule is badly configured. The parameter 'tag' is missing.");
}
try {
Issuable issuable = perspectives.as(Issuable.class, sonarFile);
List<String> lines = FileUtils.readLines(inputFile.file(), fs.encoding().name());
for (int index = 0; index < lines.size(); index++) {
if (lines.get(index).contains(tag)) {
issuable.addIssue(issuable.newIssueBuilder()
.effortToFix(settings.getDouble(EFFORT_TO_FIX_PROPERTY))
.line(index + 1)
.ruleKey(ruleKey)
.build());
}
}
} catch (IOException e) {
throw new IllegalStateException("Fail to process " + inputFile, e);
}
}
}

+ 57
- 0
plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OneBlockerIssuePerFileSensor.java View File

@@ -0,0 +1,57 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* SonarQube is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.xoo.rule;

import org.sonar.api.batch.SensorContext;
import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.rule.ActiveRules;
import org.sonar.api.component.ResourcePerspectives;
import org.sonar.api.issue.Issuable;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.Severity;

public class OneBlockerIssuePerFileSensor extends AbstractDeprecatedXooRuleSensor {

public static final String RULE_KEY = "OneBlockerIssuePerFile";

private final ResourcePerspectives perspectives;

public OneBlockerIssuePerFileSensor(ResourcePerspectives perspectives, FileSystem fs, ActiveRules activeRules) {
super(fs, activeRules);
this.perspectives = perspectives;
}

@Override
protected String getRuleKey() {
return RULE_KEY;
}

@Override
protected void processFile(InputFile inputFile, org.sonar.api.resources.File sonarFile, SensorContext context, RuleKey ruleKey, String languageKey) {
Issuable issuable = perspectives.as(Issuable.class, sonarFile);
issuable.addIssue(issuable.newIssueBuilder()
.ruleKey(ruleKey)
.severity(Severity.BLOCKER)
.message("This issue is generated on each file. Severity is blocker, whatever quality profile")
.build());
}

}

+ 60
- 0
plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OneIssuePerFileSensor.java View File

@@ -0,0 +1,60 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* SonarQube is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.xoo.rule;

import org.sonar.api.batch.SensorContext;
import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.rule.ActiveRules;
import org.sonar.api.component.ResourcePerspectives;
import org.sonar.api.config.Settings;
import org.sonar.api.issue.Issuable;
import org.sonar.api.rule.RuleKey;

public class OneIssuePerFileSensor extends AbstractDeprecatedXooRuleSensor {

public static final String RULE_KEY = "OneIssuePerFile";

private static final String EFFORT_TO_FIX_PROPERTY = "sonar.oneIssuePerFile.effortToFix";

private final ResourcePerspectives perspectives;
private final Settings settings;

public OneIssuePerFileSensor(ResourcePerspectives perspectives, Settings settings, FileSystem fs, ActiveRules activeRules) {
super(fs, activeRules);
this.perspectives = perspectives;
this.settings = settings;
}

@Override
protected String getRuleKey() {
return RULE_KEY;
}

@Override
protected void processFile(InputFile inputFile, org.sonar.api.resources.File sonarFile, SensorContext context, RuleKey ruleKey, String languageKey) {
Issuable issuable = perspectives.as(Issuable.class, sonarFile);
issuable.addIssue(issuable.newIssueBuilder()
.ruleKey(ruleKey)
.effortToFix(settings.getDouble(EFFORT_TO_FIX_PROPERTY))
.message("This issue is generated on each file")
.build());
}
}

+ 59
- 0
plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OneIssuePerModuleSensor.java View File

@@ -0,0 +1,59 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* SonarQube is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.xoo.rule;

import org.sonar.api.batch.Sensor;
import org.sonar.api.batch.SensorContext;
import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.batch.rule.ActiveRules;
import org.sonar.api.component.ResourcePerspectives;
import org.sonar.api.issue.Issuable;
import org.sonar.api.resources.Project;
import org.sonar.api.rule.RuleKey;
import org.sonar.xoo.Xoo;

public class OneIssuePerModuleSensor implements Sensor {

public static final String RULE_KEY = "OneIssuePerModule";

private final ResourcePerspectives perspectives;
private final FileSystem fs;
private final ActiveRules activeRules;

public OneIssuePerModuleSensor(ResourcePerspectives perspectives, FileSystem fs, ActiveRules activeRules) {
this.perspectives = perspectives;
this.fs = fs;
this.activeRules = activeRules;
}

@Override
public void analyse(Project project, SensorContext context) {
Issuable issuable = perspectives.as(Issuable.class, project);
issuable.addIssue(issuable.newIssueBuilder()
.ruleKey(RuleKey.of(XooRulesDefinition.XOO_REPOSITORY, RULE_KEY))
.message("This issue is generated on each module")
.build());
}

@Override
public boolean shouldExecuteOnProject(Project project) {
return fs.hasFiles(fs.predicates().hasLanguages(Xoo.KEY)) && (activeRules.find(RuleKey.of(XooRulesDefinition.XOO_REPOSITORY, RULE_KEY)) != null);
}
}

+ 1
- 1
plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/XooQualityProfile.java View File

@@ -32,7 +32,7 @@ public class XooQualityProfile extends ProfileDefinition {
public RulesProfile createProfile(ValidationMessages validation) {
final RulesProfile profile = RulesProfile.create("Basic", Xoo.KEY);

profile.activateRule(Rule.create(XooRulesDefinition.XOO_REPOSITORY, "x1"), RulePriority.MAJOR);
profile.activateRule(Rule.create(XooRulesDefinition.XOO_REPOSITORY, HasTagSensor.RULE_KEY), RulePriority.MAJOR);

return profile;
}

+ 36
- 31
plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/XooRulesDefinition.java View File

@@ -19,13 +19,9 @@
*/
package org.sonar.xoo.rule;

import org.sonar.api.rule.RuleStatus;
import org.sonar.api.rule.Severity;
import org.sonar.api.server.rule.RuleParamType;
import org.sonar.api.server.rule.RulesDefinition;
import org.sonar.api.server.rule.RulesDefinitionAnnotationLoader;
import org.sonar.xoo.Xoo;
import org.sonar.xoo.checks.Check;

/**
* Define all the coding rules that are supported on the repository named "xoo".
@@ -36,41 +32,50 @@ public class XooRulesDefinition implements RulesDefinition {

@Override
public void define(Context context) {
NewRepository repository = context.createRepository(XOO_REPOSITORY, Xoo.KEY).setName("Xoo");
NewRepository repo = context.createRepository(XOO_REPOSITORY, Xoo.KEY).setName("Xoo");

// Load checks
new RulesDefinitionAnnotationLoader().load(repository, Check.ALL);
NewRule hasTag = repo.createRule(HasTagSensor.RULE_KEY).setName("Has Tag")
.setHtmlDescription("Search for a given tag in Xoo files");
hasTag.setDebtSubCharacteristic(RulesDefinition.SubCharacteristics.READABILITY)
.setDebtRemediationFunction(hasTag.debtRemediationFunctions().constantPerIssue("2min"));
hasTag.createParam("tag")
.setDefaultValue("xoo")
.setDescription("The tag to search for");

// define a single rule programmatically. Note that rules
// can be loaded from JSON or XML files too.
NewRule x1Rule = repository.createRule("x1")
.setName("No empty line")
.setMarkdownDescription("Generate an issue on *empty* lines of Xoo source files")
NewRule ruleWithParameters = repo.createRule("RuleWithParameters").setName("Rule with parameters")
.setHtmlDescription("Rule containing parameter of different types : boolean, integer, etc. For information, no issue will be linked to this rule.");
ruleWithParameters.createParam("string").setType(RuleParamType.STRING);
ruleWithParameters.createParam("text").setType(RuleParamType.TEXT);
ruleWithParameters.createParam("boolean").setType(RuleParamType.BOOLEAN);
ruleWithParameters.createParam("integer").setType(RuleParamType.INTEGER);
ruleWithParameters.createParam("float").setType(RuleParamType.FLOAT);

// optional tags
.setTags("style", "security")
NewRule oneIssuePerLine = repo.createRule(OneIssuePerLineSensor.RULE_KEY).setName("One Issue Per Line")
.setHtmlDescription("Generate an issue on each line of a file. It requires the metric \"lines\".");
oneIssuePerLine.setDebtSubCharacteristic(RulesDefinition.SubCharacteristics.MEMORY_EFFICIENCY)
.setDebtRemediationFunction(hasTag.debtRemediationFunctions().linear("1min"))
.setEffortToFixDescription("It takes about 1 minute to an experienced software craftsman to remove a line of code");

// optional status. Default value is READY.
.setStatus(RuleStatus.BETA)
NewRule oneIssuePerFile = repo.createRule(OneIssuePerFileSensor.RULE_KEY).setName("One Issue Per File")
.setHtmlDescription("Generate an issue on each file");
oneIssuePerFile.setDebtSubCharacteristic(RulesDefinition.SubCharacteristics.ARCHITECTURE_CHANGEABILITY)
.setDebtRemediationFunction(hasTag.debtRemediationFunctions().linear("10min"));

// default severity when the rule is activated on a Quality profile. Default value is MAJOR.
.setSeverity(Severity.MINOR);
NewRule oneIssuePerModule = repo.createRule(OneIssuePerModuleSensor.RULE_KEY).setName("One Issue Per Module")
.setHtmlDescription("Generate an issue on each module");
oneIssuePerModule.setDebtSubCharacteristic(RulesDefinition.SubCharacteristics.API_ABUSE)
.setDebtRemediationFunction(hasTag.debtRemediationFunctions().linearWithOffset("25min", "1h"))
.setEffortToFixDescription("A certified architect will need roughly half an hour to start working on removal of modules, " +
"then it's about one hour per module.");

// debt-related information
x1Rule
.setDebtSubCharacteristic(SubCharacteristics.INTEGRATION_TESTABILITY)
.setDebtRemediationFunction(x1Rule.debtRemediationFunctions().linearWithOffset("1h", "30min"))
.setEffortToFixDescription("Effort to fix issue on one line");
repo.createRule(OneBlockerIssuePerFileSensor.RULE_KEY).setName("One Blocker Issue Per File")
.setHtmlDescription("Generate a blocker issue on each file, whatever the severity declared in the Quality profile");

x1Rule.createParam("acceptWhitespace")
.setDefaultValue("false")
.setType(RuleParamType.BOOLEAN)
.setDescription("= Accept whitespace (``\\s|\\t``) on the line\nThis property is available so that a line containing only whitespace is not considered empty.\n"
+ "== Example with property set to ``false``\n``xoo\n <- One issue here\n<- And one here\n``\n\n"
+ "== Example with property set to ``true``\n``xoo\n <- No issue here\n<- But one here\n``\n");
repo.createRule(CustomMessageSensor.RULE_KEY).setName("Issue With Custom Message")
.setHtmlDescription("Generate an issue on each file with a custom message");

repo.done();

// don't forget to call done() to finalize the definition
repository.done();
}

}

+ 8
- 11
plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/rule/XooRulesDefinitionTest.java View File

@@ -37,17 +37,14 @@ public class XooRulesDefinitionTest {
assertThat(repo).isNotNull();
assertThat(repo.name()).isEqualTo("Xoo");
assertThat(repo.language()).isEqualTo("xoo");
assertThat(repo.rules()).hasSize(2);
assertThat(repo.rules()).hasSize(7);

RulesDefinition.Rule x1 = repo.rule("x1");
assertThat(x1.key()).isEqualTo("x1");
assertThat(x1.tags()).containsOnly("style", "security");
assertThat(x1.markdownDescription()).isNotEmpty();

assertThat(x1.debtSubCharacteristic()).isEqualTo(RulesDefinition.SubCharacteristics.INTEGRATION_TESTABILITY);
assertThat(x1.debtRemediationFunction().type()).isEqualTo(DebtRemediationFunction.Type.LINEAR_OFFSET);
assertThat(x1.debtRemediationFunction().coefficient()).isEqualTo("1h");
assertThat(x1.debtRemediationFunction().offset()).isEqualTo("30min");
assertThat(x1.effortToFixDescription()).isEqualTo("Effort to fix issue on one line");
RulesDefinition.Rule rule = repo.rule(OneIssuePerLineSensor.RULE_KEY);
assertThat(rule.name()).isNotEmpty();
assertThat(rule.debtSubCharacteristic()).isEqualTo(RulesDefinition.SubCharacteristics.MEMORY_EFFICIENCY);
assertThat(rule.debtRemediationFunction().type()).isEqualTo(DebtRemediationFunction.Type.LINEAR);
assertThat(rule.debtRemediationFunction().coefficient()).isEqualTo("1min");
assertThat(rule.debtRemediationFunction().offset()).isNull();
assertThat(rule.effortToFixDescription()).isNotEmpty();
}
}

+ 10
- 2
pom.xml View File

@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

<modelVersion>4.0.0</modelVersion>
<groupId>org.codehaus.sonar</groupId>
@@ -1134,7 +1135,6 @@
</dependency>



<!-- tomcat -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
@@ -1613,6 +1613,14 @@
<coveragePerTest>true</coveragePerTest>
</properties>
</profile>

<profile>
<!-- integration tests -->
<id>it</id>
<modules>
<module>it</module>
</modules>
</profile>
</profiles>

</project>

Loading…
Cancel
Save