summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSébastien Lesaint <sebastien.lesaint@sonarsource.com>2015-10-21 18:00:29 +0200
committerJulien Lancelot <julien.lancelot@sonarsource.com>2015-10-23 10:44:16 +0200
commitb9fef5c3876d9f1a1ab4d279f842d648a5c3362f (patch)
tree4a338aeced78cd7a2bb8685facaae77ed4fe532f
parent48f46a23436ebb543ac56ad708853324c950ae4e (diff)
downloadsonarqube-b9fef5c3876d9f1a1ab4d279f842d648a5c3362f.tar.gz
sonarqube-b9fef5c3876d9f1a1ab4d279f842d648a5c3362f.zip
add ProjectAnalysisRule + use it in issues package
rule avoid code factoring by static code + remove code duplication + add auto reset features also fixed licence headers in issues package
-rw-r--r--it/it-tests/src/test/java/issue/suite/CommonRulesTest.java22
-rw-r--r--it/it-tests/src/test/java/issue/suite/CustomRulesTest.java42
-rw-r--r--it/it-tests/src/test/java/issue/suite/IssueActionTest.java51
-rw-r--r--it/it-tests/src/test/java/issue/suite/IssueBulkChangeTest.java43
-rw-r--r--it/it-tests/src/test/java/issue/suite/IssueChangelogTest.java21
-rw-r--r--it/it-tests/src/test/java/issue/suite/IssueFilterExtensionTest.java41
-rw-r--r--it/it-tests/src/test/java/issue/suite/IssuePurgeTest.java69
-rw-r--r--it/it-tests/src/test/java/issue/suite/IssueWorkflowTest.java67
-rw-r--r--it/it-tests/src/test/java/issue/suite/ManualRulesTest.java18
-rw-r--r--it/it-tests/src/test/java/util/LoadedProfiles.java87
-rw-r--r--it/it-tests/src/test/java/util/LoadedProjects.java82
-rw-r--r--it/it-tests/src/test/java/util/Profile.java49
-rw-r--r--it/it-tests/src/test/java/util/ProjectAnalysis.java51
-rw-r--r--it/it-tests/src/test/java/util/ProjectAnalysisRule.java228
-rw-r--r--it/it-tests/src/test/java/util/ProjectState.java71
15 files changed, 788 insertions, 154 deletions
diff --git a/it/it-tests/src/test/java/issue/suite/CommonRulesTest.java b/it/it-tests/src/test/java/issue/suite/CommonRulesTest.java
index 8805d2bfdba..ba6d871245d 100644
--- a/it/it-tests/src/test/java/issue/suite/CommonRulesTest.java
+++ b/it/it-tests/src/test/java/issue/suite/CommonRulesTest.java
@@ -1,7 +1,21 @@
/*
- * Copyright (C) 2009-2014 SonarSource SA
- * All rights reserved
+ * 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 issue.suite;
@@ -33,8 +47,8 @@ public class CommonRulesTest {
orchestrator.getServer().provisionProject("common-rules-project", "Sample");
orchestrator.getServer().associateProjectToQualityProfile("common-rules-project", "xoo", "xoo-common-rules");
runProjectAnalysis(orchestrator, "issue/common-rules",
- "sonar.cpd.xoo.minimumTokens", "2",
- "sonar.cpd.xoo.minimumLines", "2");
+ "sonar.cpd.xoo.minimumTokens", "2",
+ "sonar.cpd.xoo.minimumLines", "2");
}
@Test
diff --git a/it/it-tests/src/test/java/issue/suite/CustomRulesTest.java b/it/it-tests/src/test/java/issue/suite/CustomRulesTest.java
index 2271dc3f951..66671a40912 100644
--- a/it/it-tests/src/test/java/issue/suite/CustomRulesTest.java
+++ b/it/it-tests/src/test/java/issue/suite/CustomRulesTest.java
@@ -1,35 +1,56 @@
/*
- * Copyright (C) 2009-2014 SonarSource SA
- * All rights reserved
+ * 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 issue.suite;
import com.sonar.orchestrator.Orchestrator;
-import com.sonar.orchestrator.locator.FileLocation;
import java.util.List;
import org.junit.Before;
import org.junit.ClassRule;
+import org.junit.Rule;
import org.junit.Test;
import org.sonar.wsclient.issue.Issue;
+import util.ProjectAnalysis;
+import util.ProjectAnalysisRule;
import static issue.suite.IssueTestSuite.searchIssues;
import static org.assertj.core.api.Assertions.assertThat;
-import static util.ItUtils.runProjectAnalysis;
public class CustomRulesTest {
@ClassRule
public static Orchestrator orchestrator = IssueTestSuite.ORCHESTRATOR;
+ @Rule
+ public final ProjectAnalysisRule projectAnalysisRule = ProjectAnalysisRule.from(orchestrator);
+
+ private ProjectAnalysis xooSampleAnalysis;
@Before
- public void deleteData() {
- orchestrator.resetData();
+ public void setup() {
+ String profileKey = projectAnalysisRule.registerProfile("/issue/suite/CustomRulesTest/custom.xml");
+ String projectKey = projectAnalysisRule.registerProject("shared/xoo-sample");
+ this.xooSampleAnalysis = projectAnalysisRule.newProjectAnalysis(projectKey)
+ .withQualityProfile(profileKey);
}
@Test
public void analyzeProjectWithCustomRules() throws Exception {
-
orchestrator.getServer().adminWsClient().post("api/rules/create",
"template_key", "xoo:TemplateRule",
"custom_key", "MyCustomRule",
@@ -38,12 +59,7 @@ public class CustomRulesTest {
"severity", "BLOCKER",
"params", "line=2");
- orchestrator.getServer().restoreProfile(FileLocation.ofClasspath("/issue/suite/CustomRulesTest/custom.xml"));
-
- orchestrator.getServer().provisionProject("sample", "Sample");
- orchestrator.getServer().associateProjectToQualityProfile("sample", "xoo", "Custom");
-
- runProjectAnalysis(orchestrator, "shared/xoo-sample");
+ xooSampleAnalysis.run();
List<Issue> issues = searchIssues();
assertThat(issues).hasSize(1);
diff --git a/it/it-tests/src/test/java/issue/suite/IssueActionTest.java b/it/it-tests/src/test/java/issue/suite/IssueActionTest.java
index 8ea2c10b601..cb0de90b12c 100644
--- a/it/it-tests/src/test/java/issue/suite/IssueActionTest.java
+++ b/it/it-tests/src/test/java/issue/suite/IssueActionTest.java
@@ -20,11 +20,10 @@
package issue.suite;
import com.sonar.orchestrator.Orchestrator;
-import com.sonar.orchestrator.build.SonarRunner;
-import com.sonar.orchestrator.locator.FileLocation;
import java.util.List;
import org.junit.Before;
import org.junit.ClassRule;
+import org.junit.Rule;
import org.junit.Test;
import org.sonar.wsclient.base.HttpException;
import org.sonar.wsclient.issue.ActionPlan;
@@ -34,6 +33,8 @@ import org.sonar.wsclient.issue.IssueComment;
import org.sonar.wsclient.issue.IssueQuery;
import org.sonar.wsclient.issue.Issues;
import org.sonar.wsclient.issue.NewActionPlan;
+import util.ProjectAnalysis;
+import util.ProjectAnalysisRule;
import static issue.suite.IssueTestSuite.ORCHESTRATOR;
import static issue.suite.IssueTestSuite.adminIssueClient;
@@ -43,7 +44,6 @@ import static issue.suite.IssueTestSuite.searchIssues;
import static issue.suite.IssueTestSuite.searchRandomIssue;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.fail;
-import static util.ItUtils.runProjectAnalysis;
import static util.ItUtils.toDate;
import static util.ItUtils.verifyHttpException;
@@ -51,27 +51,20 @@ public class IssueActionTest {
@ClassRule
public static Orchestrator orchestrator = ORCHESTRATOR;
+ @Rule
+ public final ProjectAnalysisRule projectAnalysisRule = ProjectAnalysisRule.from(orchestrator);
Issue issue;
- SonarRunner scan;
-
- private static List<Issue> searchIssuesBySeverities(String componentKey, String... severities) {
- return searchIssues(IssueQuery.create().componentRoots(componentKey).severities(severities));
- }
-
- private static ActionPlanClient adminActionPlanClient() {
- return orchestrator.getServer().adminWsClient().actionPlanClient();
- }
+ ProjectAnalysis projectAnalysis;
@Before
- public void resetData() {
- orchestrator.resetData();
- orchestrator.getServer().restoreProfile(FileLocation.ofClasspath("/issue/suite/IssueActionTest/xoo-one-issue-per-line-profile.xml"));
- orchestrator.getServer().provisionProject("sample", "Sample");
- orchestrator.getServer().associateProjectToQualityProfile("sample", "xoo", "xoo-one-issue-per-line-profile");
-
- scan = runProjectAnalysis(orchestrator, "shared/xoo-sample");
- issue = searchRandomIssue();
+ public void setup() {
+ String qualityProfileKey = projectAnalysisRule.registerProfile("/issue/suite/IssueActionTest/xoo-one-issue-per-line-profile.xml");
+ String projectKey = projectAnalysisRule.registerProject("shared/xoo-sample");
+
+ this.projectAnalysis = projectAnalysisRule.newProjectAnalysis(projectKey).withQualityProfile(qualityProfileKey);
+ this.projectAnalysis.run();
+ this.issue = searchRandomIssue();
}
@Test
@@ -127,7 +120,7 @@ public class IssueActionTest {
assertThat(searchIssuesBySeverities(componentKey, "BLOCKER")).hasSize(1);
- orchestrator.executeBuild(scan);
+ projectAnalysis.run();
Issue reloaded = searchIssueByKey(issue.key());
assertThat(reloaded.severity()).isEqualTo("BLOCKER");
assertThat(reloaded.status()).isEqualTo("OPEN");
@@ -148,7 +141,7 @@ public class IssueActionTest {
adminIssueClient().assign(issue.key(), "admin");
assertThat(searchIssues(IssueQuery.create().assignees("admin"))).hasSize(1);
- orchestrator.executeBuild(scan);
+ projectAnalysis.run();
Issue reloaded = searchIssueByKey(issue.key());
assertThat(reloaded.assignee()).isEqualTo("admin");
assertThat(reloaded.creationDate()).isEqualTo(issue.creationDate());
@@ -192,7 +185,7 @@ public class IssueActionTest {
adminIssueClient().plan(issue.key(), newActionPlan.key());
assertThat(search(IssueQuery.create().actionPlans(newActionPlan.key())).list()).hasSize(1);
- orchestrator.executeBuild(scan);
+ projectAnalysis.run();
Issue reloaded = searchIssueByKey(issue.key());
assertThat(reloaded.actionPlan()).isEqualTo(newActionPlan.key());
assertThat(reloaded.creationDate()).isEqualTo(issue.creationDate());
@@ -227,7 +220,7 @@ public class IssueActionTest {
adminIssueClient().plan(issue.key(), null);
assertThat(search(IssueQuery.create().actionPlans(newActionPlan.key())).list()).hasSize(0);
- orchestrator.executeBuild(scan);
+ projectAnalysis.run();
Issue reloaded = searchIssueByKey(issue.key());
assertThat(reloaded.actionPlan()).isNull();
assertThat(reloaded.creationDate()).isEqualTo(issue.creationDate());
@@ -264,10 +257,18 @@ public class IssueActionTest {
adminIssueClient().doAction(issue.key(), "fake");
assertThat(adminIssueClient().actions(issue.key())).doesNotContain("fake");
- orchestrator.executeBuild(scan);
+ projectAnalysis.run();
// Fake action is no more available if the issue attribute is still there
assertThat(adminIssueClient().actions(issue.key())).doesNotContain("fake");
}
+ private static List<Issue> searchIssuesBySeverities(String componentKey, String... severities) {
+ return searchIssues(IssueQuery.create().componentRoots(componentKey).severities(severities));
+ }
+
+ private static ActionPlanClient adminActionPlanClient() {
+ return orchestrator.getServer().adminWsClient().actionPlanClient();
+ }
+
}
diff --git a/it/it-tests/src/test/java/issue/suite/IssueBulkChangeTest.java b/it/it-tests/src/test/java/issue/suite/IssueBulkChangeTest.java
index b1d4ca7177b..f5b438a7ef4 100644
--- a/it/it-tests/src/test/java/issue/suite/IssueBulkChangeTest.java
+++ b/it/it-tests/src/test/java/issue/suite/IssueBulkChangeTest.java
@@ -22,10 +22,10 @@ package issue.suite;
import com.google.common.base.Function;
import com.google.common.collect.FluentIterable;
import com.sonar.orchestrator.Orchestrator;
-import com.sonar.orchestrator.locator.FileLocation;
import java.util.List;
import org.junit.Before;
import org.junit.ClassRule;
+import org.junit.Rule;
import org.junit.Test;
import org.sonar.wsclient.base.HttpException;
import org.sonar.wsclient.issue.ActionPlan;
@@ -35,12 +35,13 @@ import org.sonar.wsclient.issue.BulkChangeQuery;
import org.sonar.wsclient.issue.Issue;
import org.sonar.wsclient.issue.NewActionPlan;
import util.ItUtils;
+import util.ProjectAnalysis;
+import util.ProjectAnalysisRule;
import static issue.suite.IssueTestSuite.ORCHESTRATOR;
import static issue.suite.IssueTestSuite.adminIssueClient;
import static issue.suite.IssueTestSuite.issueClient;
import static org.assertj.core.api.Assertions.assertThat;
-import static util.ItUtils.runProjectAnalysis;
/**
* SONAR-4421
@@ -53,15 +54,22 @@ public class IssueBulkChangeTest {
@ClassRule
public static Orchestrator orchestrator = ORCHESTRATOR;
+ @Rule
+ public final ProjectAnalysisRule projectAnalysisRule = ProjectAnalysisRule.from(orchestrator);
+
+ private ProjectAnalysis xooSampleLittleIssuesAnalysis;
@Before
- public void resetData() {
- orchestrator.resetData();
+ public void setUp() throws Exception {
+ String qualityProfileKey = projectAnalysisRule.registerProfile("/issue/suite/IssueBulkChangeTest/one-issue-per-line-profile.xml");
+ String projectKey = projectAnalysisRule.registerProject("shared/xoo-sample");
+ this.xooSampleLittleIssuesAnalysis = projectAnalysisRule.newProjectAnalysis(projectKey)
+ .withQualityProfile(qualityProfileKey);
}
@Test
public void should_change_severity() {
- analyzeSampleProjectWillSmallNumberOfIssues();
+ xooSampleLittleIssuesAnalysis.run();
String newSeverity = "BLOCKER";
String[] issueKeys = searchIssueKeys(BULK_EDITED_ISSUE_COUNT);
@@ -73,7 +81,7 @@ public class IssueBulkChangeTest {
@Test
public void should_do_transition() {
- analyzeSampleProjectWillSmallNumberOfIssues();
+ xooSampleLittleIssuesAnalysis.run();
String[] issueKeys = searchIssueKeys(BULK_EDITED_ISSUE_COUNT);
BulkChange bulkChange = bulkTransitionStatusOfIssues(issueKeys, "confirm");
@@ -83,7 +91,7 @@ public class IssueBulkChangeTest {
@Test
public void should_assign() {
- analyzeSampleProjectWillSmallNumberOfIssues();
+ xooSampleLittleIssuesAnalysis.run();
String[] issueKeys = searchIssueKeys(BULK_EDITED_ISSUE_COUNT);
BulkChange bulkChange = buldChangeAssigneeOfIssues(issueKeys, "admin");
@@ -96,7 +104,7 @@ public class IssueBulkChangeTest {
@Test
public void should_plan() {
- analyzeSampleProjectWillSmallNumberOfIssues();
+ xooSampleLittleIssuesAnalysis.run();
// Create action plan
ActionPlan newActionPlan = adminActionPlanClient().create(
@@ -118,7 +126,7 @@ public class IssueBulkChangeTest {
@Test
public void should_setSeverity_add_comment_in_single_WS_call() {
- analyzeSampleProjectWillSmallNumberOfIssues();
+ xooSampleLittleIssuesAnalysis.run();
String newSeverity = "BLOCKER";
String[] issueKeys = searchIssueKeys(BULK_EDITED_ISSUE_COUNT);
@@ -140,7 +148,7 @@ public class IssueBulkChangeTest {
@Test
public void should_apply_bulk_change_on_many_actions() {
- analyzeSampleProjectWillSmallNumberOfIssues();
+ xooSampleLittleIssuesAnalysis.run();
String newSeverity = "BLOCKER";
String[] issueKeys = searchIssueKeys(BULK_EDITED_ISSUE_COUNT);
@@ -167,7 +175,7 @@ public class IssueBulkChangeTest {
@Test
public void should_not_apply_bulk_change_if_not_logged() {
- analyzeSampleProjectWillSmallNumberOfIssues();
+ xooSampleLittleIssuesAnalysis.run();
String newSeverity = "BLOCKER";
String[] issueKeys = searchIssueKeys(BULK_EDITED_ISSUE_COUNT);
@@ -181,7 +189,7 @@ public class IssueBulkChangeTest {
@Test
public void should_not_apply_bulk_change_if_no_change_to_do() {
- analyzeSampleProjectWillSmallNumberOfIssues();
+ xooSampleLittleIssuesAnalysis.run();
String newSeverity = "BLOCKER";
String[] issueKeys = searchIssueKeys(BULK_EDITED_ISSUE_COUNT);
@@ -207,7 +215,7 @@ public class IssueBulkChangeTest {
@Test
public void should_not_apply_bulk_change_if_action_is_invalid() {
- analyzeSampleProjectWillSmallNumberOfIssues();
+ xooSampleLittleIssuesAnalysis.run();
int limit = BULK_EDITED_ISSUE_COUNT;
String[] issueKeys = searchIssueKeys(limit);
@@ -222,7 +230,7 @@ public class IssueBulkChangeTest {
@Test
public void should_add_comment_only_on_issues_that_will_be_changed() {
- analyzeSampleProjectWillSmallNumberOfIssues();
+ xooSampleLittleIssuesAnalysis.run();
int nbIssues = BULK_EDITED_ISSUE_COUNT;
String[] issueKeys = searchIssueKeys(nbIssues);
@@ -249,13 +257,6 @@ public class IssueBulkChangeTest {
assertThat(nbIssuesWithComment).isEqualTo(1);
}
- private void analyzeSampleProjectWillSmallNumberOfIssues() {
- orchestrator.getServer().restoreProfile(FileLocation.ofClasspath("/issue/suite/IssueBulkChangeTest/one-issue-per-line-profile.xml"));
- orchestrator.getServer().provisionProject("sample", "Sample");
- orchestrator.getServer().associateProjectToQualityProfile("sample", "xoo", "one-issue-per-line");
- runProjectAnalysis(orchestrator, "shared/xoo-sample");
- }
-
private static void assertIssueSeverity(String[] issueKeys, String expectedSeverity) {
for (Issue issue : IssueTestSuite.searchIssues(issueKeys)) {
assertThat(issue.severity()).isEqualTo(expectedSeverity);
diff --git a/it/it-tests/src/test/java/issue/suite/IssueChangelogTest.java b/it/it-tests/src/test/java/issue/suite/IssueChangelogTest.java
index a8b20a5f90f..e141e2af2bf 100644
--- a/it/it-tests/src/test/java/issue/suite/IssueChangelogTest.java
+++ b/it/it-tests/src/test/java/issue/suite/IssueChangelogTest.java
@@ -20,38 +20,39 @@
package issue.suite;
import com.sonar.orchestrator.Orchestrator;
-import com.sonar.orchestrator.build.SonarRunner;
-import com.sonar.orchestrator.locator.FileLocation;
import java.util.List;
import org.junit.Before;
import org.junit.ClassRule;
+import org.junit.Rule;
import org.junit.Test;
import org.sonar.wsclient.issue.Issue;
import org.sonar.wsclient.issue.IssueChange;
import org.sonar.wsclient.issue.IssueChangeDiff;
import org.sonar.wsclient.issue.IssueQuery;
+import util.ProjectAnalysis;
+import util.ProjectAnalysisRule;
import static issue.suite.IssueTestSuite.ORCHESTRATOR;
import static issue.suite.IssueTestSuite.adminIssueClient;
import static issue.suite.IssueTestSuite.issueClient;
import static org.assertj.core.api.Assertions.assertThat;
-import static util.ItUtils.runProjectAnalysis;
public class IssueChangelogTest {
@ClassRule
public static Orchestrator orchestrator = ORCHESTRATOR;
+ @Rule
+ public final ProjectAnalysisRule projectAnalysisRule = ProjectAnalysisRule.from(orchestrator);
Issue issue;
- SonarRunner scan;
+ ProjectAnalysis xooSampleAnalysis;
@Before
public void resetData() {
- orchestrator.resetData();
- orchestrator.getServer().restoreProfile(FileLocation.ofClasspath("/issue/suite/IssueChangelogTest/one-issue-per-line-profile.xml"));
- orchestrator.getServer().provisionProject("sample", "Sample");
- orchestrator.getServer().associateProjectToQualityProfile("sample", "xoo", "one-issue-per-line");
- scan = runProjectAnalysis(orchestrator, "shared/xoo-sample");
+ xooSampleAnalysis = projectAnalysisRule
+ .newProjectAnalysis(projectAnalysisRule.registerProject("shared/xoo-sample"))
+ .withQualityProfile(projectAnalysisRule.registerProfile("/issue/suite/IssueChangelogTest/one-issue-per-line-profile.xml"));
+ xooSampleAnalysis.run();
issue = searchRandomIssue();
}
@@ -79,7 +80,7 @@ public class IssueChangelogTest {
// re analyse the project after resolving an issue in order to reopen it
adminIssueClient().doTransition(issue.key(), "resolve");
- orchestrator.executeBuild(scan);
+ xooSampleAnalysis.run();
List<IssueChange> changes = retrieveChangeForIssue(issue.key());
assertThat(changes).hasSize(2);
diff --git a/it/it-tests/src/test/java/issue/suite/IssueFilterExtensionTest.java b/it/it-tests/src/test/java/issue/suite/IssueFilterExtensionTest.java
index 1104aa27b57..3e00bdfb682 100644
--- a/it/it-tests/src/test/java/issue/suite/IssueFilterExtensionTest.java
+++ b/it/it-tests/src/test/java/issue/suite/IssueFilterExtensionTest.java
@@ -20,44 +20,40 @@
package issue.suite;
import com.sonar.orchestrator.Orchestrator;
-import com.sonar.orchestrator.locator.FileLocation;
import java.util.List;
-import org.junit.Before;
import org.junit.ClassRule;
+import org.junit.Rule;
import org.junit.Test;
import org.sonar.wsclient.issue.Issue;
import org.sonar.wsclient.issue.IssueQuery;
import org.sonar.wsclient.services.Measure;
import org.sonar.wsclient.services.Resource;
import org.sonar.wsclient.services.ResourceQuery;
+import util.ProjectAnalysis;
+import util.ProjectAnalysisRule;
import static issue.suite.IssueTestSuite.ORCHESTRATOR;
import static issue.suite.IssueTestSuite.searchIssues;
import static org.assertj.core.api.Assertions.assertThat;
-import static util.ItUtils.runProjectAnalysis;
/**
* Tests the extension point IssueFilter
*/
public class IssueFilterExtensionTest {
- private static final String MULTI_MODULES_SAMPLE_PROJECT_NAME = "com.sonarsource.it.samples:multi-modules-sample";
-
@ClassRule
public static Orchestrator orchestrator = ORCHESTRATOR;
+ @Rule
+ public final ProjectAnalysisRule projectAnalysisRule = ProjectAnalysisRule.from(orchestrator);
- @Before
- public void resetData() {
- orchestrator.resetData();
- orchestrator.getServer().restoreProfile(FileLocation.ofClasspath("/issue/suite/IssueFilterExtensionTest/xoo-with-many-rules.xml"));
- }
+ private final String manyRuleProfileKey = projectAnalysisRule.registerProfile("/issue/suite/IssueFilterExtensionTest/xoo-with-many-rules.xml");
+ private final String xooMultiModuleProjectKey = projectAnalysisRule.registerProject("shared/xoo-multi-modules-sample");
+ private final ProjectAnalysis analysis = projectAnalysisRule.newProjectAnalysis(xooMultiModuleProjectKey)
+ .withQualityProfile(manyRuleProfileKey);
@Test
public void should_filter_files() throws Exception {
- orchestrator.getServer().provisionProject(MULTI_MODULES_SAMPLE_PROJECT_NAME, "Sonar :: Integration Tests :: Multi-modules Sample");
- orchestrator.getServer().associateProjectToQualityProfile(MULTI_MODULES_SAMPLE_PROJECT_NAME, "xoo", "with-many-rules");
- runProjectAnalysis(orchestrator, "shared/xoo-multi-modules-sample",
- "sonar.exclusions", "**/HelloA1.xoo");
+ analysis.withProperties("sonar.exclusions", "**/HelloA1.xoo").run();
List<Issue> issues = searchIssues();
assertThat(issues).isNotEmpty();
@@ -66,30 +62,27 @@ public class IssueFilterExtensionTest {
assertThat(issue.componentKey()).doesNotContain("HelloA1");
}
- assertThat(getMeasure(MULTI_MODULES_SAMPLE_PROJECT_NAME, "violations").getIntValue()).isEqualTo(issues.size());
+ assertThat(getMeasure(xooMultiModuleProjectKey, "violations").getIntValue()).isEqualTo(issues.size());
}
@Test
public void should_filter_issues() {
- // first analysis without isssue-filter
- orchestrator.getServer().provisionProject(MULTI_MODULES_SAMPLE_PROJECT_NAME, "Sonar :: Integration Tests :: Multi-modules Sample");
- orchestrator.getServer().associateProjectToQualityProfile(MULTI_MODULES_SAMPLE_PROJECT_NAME, "xoo", "with-many-rules");
- runProjectAnalysis(orchestrator, "shared/xoo-multi-modules-sample");
+ // first analysis without issue-filter
+ analysis.run();
// Issue filter removes issues on lines < 5
// Deprecated violation filter removes issues detected by PMD
- List<Issue> unresolvedIssues = searchResolvedIssues(MULTI_MODULES_SAMPLE_PROJECT_NAME);
+ List<Issue> unresolvedIssues = searchResolvedIssues(xooMultiModuleProjectKey);
int issuesBeforeLine5 = countIssuesBeforeLine5(unresolvedIssues);
int pmdIssues = countModuleIssues(unresolvedIssues);
assertThat(issuesBeforeLine5).isGreaterThan(0);
assertThat(pmdIssues).isGreaterThan(0);
// Enable issue filters
- runProjectAnalysis(orchestrator, "shared/xoo-multi-modules-sample",
- "enableIssueFilters", "true");
+ analysis.withProperties("enableIssueFilters", "true").run();
- unresolvedIssues = searchResolvedIssues(MULTI_MODULES_SAMPLE_PROJECT_NAME);
- List<Issue> resolvedIssues = searchUnresolvedIssues(MULTI_MODULES_SAMPLE_PROJECT_NAME);
+ unresolvedIssues = searchResolvedIssues(xooMultiModuleProjectKey);
+ List<Issue> resolvedIssues = searchUnresolvedIssues(xooMultiModuleProjectKey);
assertThat(countIssuesBeforeLine5(unresolvedIssues)).isZero();
assertThat(countModuleIssues(unresolvedIssues)).isZero();
assertThat(countModuleIssues(resolvedIssues)).isGreaterThan(0);
diff --git a/it/it-tests/src/test/java/issue/suite/IssuePurgeTest.java b/it/it-tests/src/test/java/issue/suite/IssuePurgeTest.java
index f7a89303d53..7dfb307d3fc 100644
--- a/it/it-tests/src/test/java/issue/suite/IssuePurgeTest.java
+++ b/it/it-tests/src/test/java/issue/suite/IssuePurgeTest.java
@@ -20,31 +20,39 @@
package issue.suite;
import com.sonar.orchestrator.Orchestrator;
-import com.sonar.orchestrator.locator.FileLocation;
import java.util.List;
import org.junit.Before;
import org.junit.ClassRule;
+import org.junit.Rule;
import org.junit.Test;
import org.sonar.wsclient.issue.Issue;
import org.sonar.wsclient.issue.IssueQuery;
+import util.ProjectAnalysis;
+import util.ProjectAnalysisRule;
import static issue.suite.IssueTestSuite.ORCHESTRATOR;
import static issue.suite.IssueTestSuite.searchIssues;
import static org.assertj.core.api.Assertions.assertThat;
-import static util.ItUtils.runProjectAnalysis;
-import static util.ItUtils.setServerProperty;
public class IssuePurgeTest {
@ClassRule
public static Orchestrator orchestrator = ORCHESTRATOR;
+ @Rule
+ public final ProjectAnalysisRule projectAnalysisRule = ProjectAnalysisRule.from(orchestrator);
+
+ private ProjectAnalysis xooSampleAnalysis;
+ private ProjectAnalysis xooMultiModuleAnalysis;
@Before
- public void deleteAnalysisData() {
- orchestrator.resetData();
- // reset settings before test
- setServerProperty(orchestrator, "sonar.dbcleaner.daysBeforeDeletingClosedIssues", null);
- orchestrator.getServer().restoreProfile(FileLocation.ofClasspath("/issue/suite/IssuePurgeTest/with-many-rules.xml"));
+ public void setUp() throws Exception {
+ String manyRulesProfile = projectAnalysisRule.registerProfile("/issue/suite/IssuePurgeTest/with-many-rules.xml");
+ String xooSampleProjectKey = projectAnalysisRule.registerProject("shared/xoo-sample");
+ this.xooSampleAnalysis = projectAnalysisRule.newProjectAnalysis(xooSampleProjectKey)
+ .withQualityProfile(manyRulesProfile);
+ String xooMultiModuleProjectKey = projectAnalysisRule.registerProject("shared/xoo-multi-modules-sample");
+ this.xooMultiModuleAnalysis = projectAnalysisRule.newProjectAnalysis(xooMultiModuleProjectKey)
+ .withQualityProfile(manyRulesProfile);
}
/**
@@ -52,14 +60,13 @@ public class IssuePurgeTest {
*/
@Test
public void purge_old_closed_issues() throws Exception {
- setServerProperty(orchestrator, "sonar.dbcleaner.daysBeforeDeletingClosedIssues", "5000");
+ projectAnalysisRule.setServerProperty("sonar.dbcleaner.daysBeforeDeletingClosedIssues", "5000");
// Generate some issues
- orchestrator.getServer().provisionProject("sample", "Sample");
- orchestrator.getServer().associateProjectToQualityProfile("sample", "xoo", "with-many-rules");
- runProjectAnalysis(orchestrator, "shared/xoo-sample",
+ xooSampleAnalysis.withProperties(
"sonar.dynamicAnalysis", "false",
- "sonar.projectDate", "2014-10-01");
+ "sonar.projectDate", "2014-10-01")
+ .run();
// All the issues are open
List<Issue> issues = searchIssues();
@@ -69,10 +76,12 @@ public class IssuePurgeTest {
// Second scan with empty profile -> all issues are resolved and closed
// -> Not deleted because less than 5000 days long
- orchestrator.getServer().associateProjectToQualityProfile("sample", "xoo", "empty");
- runProjectAnalysis(orchestrator, "shared/xoo-sample",
- "sonar.dynamicAnalysis", "false",
- "sonar.projectDate", "2014-10-15");
+ xooSampleAnalysis
+ .withXooEmptyProfile()
+ .withProperties(
+ "sonar.dynamicAnalysis", "false",
+ "sonar.projectDate", "2014-10-15")
+ .run();
issues = searchIssues();
assertThat(issues).isNotEmpty();
for (Issue issue : issues) {
@@ -81,11 +90,13 @@ public class IssuePurgeTest {
}
// Third scan -> closed issues are deleted
- setServerProperty(orchestrator, "sonar.dbcleaner.daysBeforeDeletingClosedIssues", "1");
+ projectAnalysisRule.setServerProperty("sonar.dbcleaner.daysBeforeDeletingClosedIssues", "1");
- runProjectAnalysis(orchestrator, "shared/xoo-sample",
- "sonar.dynamicAnalysis", "false",
- "sonar.projectDate", "2014-10-20");
+ xooSampleAnalysis.withXooEmptyProfile()
+ .withProperties(
+ "sonar.dynamicAnalysis", "false",
+ "sonar.projectDate", "2014-10-20")
+ .run();
assertThat(searchIssues(IssueQuery.create())).isEmpty();
}
@@ -94,12 +105,10 @@ public class IssuePurgeTest {
*/
@Test
public void resolve_issues_when_removing_module() throws Exception {
- orchestrator.getServer().provisionProject("com.sonarsource.it.samples:multi-modules-sample", "Sonar :: Integration Tests :: Multi-modules Sample");
- orchestrator.getServer().associateProjectToQualityProfile("com.sonarsource.it.samples:multi-modules-sample", "xoo", "with-many-rules");
-
// Generate some issues
- runProjectAnalysis(orchestrator, "shared/xoo-multi-modules-sample",
- "sonar.dynamicAnalysis", "false");
+ xooMultiModuleAnalysis
+ .withProperties("sonar.dynamicAnalysis", "false")
+ .run();
// All the issues are open
List<Issue> issues = searchIssues();
@@ -112,9 +121,11 @@ public class IssuePurgeTest {
assertThat(issuesOnModuleB).isEqualTo(28);
// Second scan without module B -> issues on module B are resolved as removed and closed
- runProjectAnalysis(orchestrator, "shared/xoo-multi-modules-sample",
- "sonar.dynamicAnalysis", "false",
- "sonar.modules", "module_a");
+ xooMultiModuleAnalysis
+ .withProperties(
+ "sonar.dynamicAnalysis", "false",
+ "sonar.modules", "module_a")
+ .run();
// Resolved should should all be mark as REMOVED and affect to module b
List<Issue> reloadedIssues = searchIssues(IssueQuery.create().resolved(true));
diff --git a/it/it-tests/src/test/java/issue/suite/IssueWorkflowTest.java b/it/it-tests/src/test/java/issue/suite/IssueWorkflowTest.java
index 7070e1d74dc..2e0f567c35b 100644
--- a/it/it-tests/src/test/java/issue/suite/IssueWorkflowTest.java
+++ b/it/it-tests/src/test/java/issue/suite/IssueWorkflowTest.java
@@ -1,40 +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 issue.suite;
import com.sonar.orchestrator.Orchestrator;
-import com.sonar.orchestrator.build.SonarRunner;
-import com.sonar.orchestrator.locator.FileLocation;
import java.util.List;
import org.junit.Before;
import org.junit.ClassRule;
+import org.junit.Rule;
import org.junit.Test;
import org.sonar.wsclient.issue.Issue;
import org.sonar.wsclient.issue.IssueQuery;
+import util.ProjectAnalysis;
+import util.ProjectAnalysisRule;
import static issue.suite.IssueTestSuite.adminIssueClient;
import static issue.suite.IssueTestSuite.searchIssueByKey;
import static issue.suite.IssueTestSuite.searchIssues;
import static issue.suite.IssueTestSuite.searchRandomIssue;
import static org.assertj.core.api.Assertions.assertThat;
-import static util.ItUtils.projectDir;
public class IssueWorkflowTest {
@ClassRule
public static Orchestrator orchestrator = IssueTestSuite.ORCHESTRATOR;
- Issue issue;
- SonarRunner scan;
+ @Rule
+ public final ProjectAnalysisRule projectAnalysisRule = ProjectAnalysisRule.from(orchestrator);
- @Before
- public void resetData() {
- orchestrator.resetData();
-
- orchestrator.getServer().restoreProfile(FileLocation.ofClasspath("/issue/suite/IssueWorkflowTest/xoo-one-issue-per-line-profile.xml"));
- orchestrator.getServer().provisionProject("workflow", "Workflow");
- orchestrator.getServer().associateProjectToQualityProfile("workflow", "xoo", "xoo-one-issue-per-line-profile");
+ private ProjectAnalysis analysisWithIssues;
+ private ProjectAnalysis analysisWithoutIssues;
+ private Issue issue;
- scan = SonarRunner.create(projectDir("issue/workflow"));
- orchestrator.executeBuild(scan);
+ @Before
+ public void before() {
+ String oneIssuePerFileProfileKey = projectAnalysisRule.registerProfile("/issue/suite/IssueWorkflowTest/xoo-one-issue-per-line-profile.xml");
+ String analyzedProjectKey = projectAnalysisRule.registerProject("issue/workflow");
+ analysisWithIssues = projectAnalysisRule.newProjectAnalysis(analyzedProjectKey).withQualityProfile(oneIssuePerFileProfileKey);
+ analysisWithoutIssues = analysisWithIssues.withXooEmptyProfile();
+ analysisWithIssues.run();
issue = searchRandomIssue();
}
@@ -49,8 +69,7 @@ public class IssueWorkflowTest {
assertThat(issues).isNotEmpty();
// re-analyze with profile "empty". The rule is disabled so the issues must be closed
- orchestrator.getServer().associateProjectToQualityProfile("workflow", "xoo", "empty");
- orchestrator.executeBuild(scan);
+ analysisWithoutIssues.run();
issues = searchIssues(IssueQuery.create().rules("xoo:OneIssuePerLine"));
assertThat(issues).isNotEmpty();
for (Issue issue : issues) {
@@ -118,8 +137,7 @@ public class IssueWorkflowTest {
assertThat(falsePositive.creationDate()).isEqualTo(issue.creationDate());
// scan without any rules -> confirmed is closed
- orchestrator.getServer().associateProjectToQualityProfile("workflow", "xoo", "empty");
- orchestrator.executeBuild(scan);
+ analysisWithoutIssues.run();
Issue closed = searchIssueByKey(issue.key());
assertThat(closed.status()).isEqualTo("CLOSED");
assertThat(closed.resolution()).isEqualTo("REMOVED");
@@ -141,7 +159,7 @@ public class IssueWorkflowTest {
assertThat(resolvedIssue.updateDate().before(issue.updateDate())).isFalse();
// re-execute scan, with the same Q profile -> the issue has not been fixed
- orchestrator.executeBuild(scan);
+ analysisWithIssues.run();
// reload issue
Issue reopenedIssue = searchIssueByKey(issue.key());
@@ -167,8 +185,7 @@ public class IssueWorkflowTest {
assertThat(resolvedIssue.closeDate()).isNull();
// re-execute scan without rules -> the issue is removed with resolution "REMOVED"
- orchestrator.getServer().associateProjectToQualityProfile("workflow", "xoo", "empty");
- orchestrator.executeBuild(scan);
+ analysisWithoutIssues.run();
// reload issue
Issue closedIssue = searchIssueByKey(issue.key());
@@ -217,7 +234,7 @@ public class IssueWorkflowTest {
assertThat(falsePositive.creationDate()).isEqualTo(issue.creationDate());
// re-execute the same scan
- orchestrator.executeBuild(scan);
+ analysisWithIssues.run();
// refresh
Issue reloaded = searchIssueByKey(falsePositive.key());
@@ -240,8 +257,7 @@ public class IssueWorkflowTest {
assertThat(falsePositive.creationDate()).isEqualTo(issue.creationDate());
// scan without any rules -> false-positive is closed
- orchestrator.getServer().associateProjectToQualityProfile("workflow", "xoo", "empty");
- orchestrator.executeBuild(scan);
+ analysisWithoutIssues.run();
Issue closed = searchIssueByKey(issue.key());
assertThat(closed.status()).isEqualTo("CLOSED");
assertThat(closed.resolution()).isEqualTo("REMOVED");
@@ -276,8 +292,7 @@ public class IssueWorkflowTest {
adminIssueClient().doTransition(issue.key(), "resolve");
// re-execute scan without rules -> the issue is closed
- orchestrator.getServer().associateProjectToQualityProfile("workflow", "xoo", "empty");
- orchestrator.executeBuild(scan);
+ analysisWithoutIssues.run();
// user try to reopen the issue
assertThat(adminIssueClient().transitions(issue.key())).isEmpty();
diff --git a/it/it-tests/src/test/java/issue/suite/ManualRulesTest.java b/it/it-tests/src/test/java/issue/suite/ManualRulesTest.java
index aa986112501..7efb925dcea 100644
--- a/it/it-tests/src/test/java/issue/suite/ManualRulesTest.java
+++ b/it/it-tests/src/test/java/issue/suite/ManualRulesTest.java
@@ -1,7 +1,21 @@
/*
- * Copyright (C) 2009-2014 SonarSource SA
- * All rights reserved
+ * 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 issue.suite;
diff --git a/it/it-tests/src/test/java/util/LoadedProfiles.java b/it/it-tests/src/test/java/util/LoadedProfiles.java
new file mode 100644
index 00000000000..3f795643eca
--- /dev/null
+++ b/it/it-tests/src/test/java/util/LoadedProfiles.java
@@ -0,0 +1,87 @@
+/*
+ * 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 util;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+final class LoadedProfiles {
+ private final Map<String, Profile> profileStatesPerProfileKey = new HashMap<>();
+
+ public LoadedProfiles() {
+ init();
+ }
+
+ public String loadProfile(String relativePathToProfile) {
+ try {
+ URL resource = getClass().getResource(relativePathToProfile);
+ Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(resource.openStream());
+
+ String profileKey = null;
+ String languageKey = null;
+
+ Element documentElement = document.getDocumentElement();
+ checkArgument("profile".equals(documentElement.getNodeName()), "%s is not a quality profile file. Root node is not %s", resource.toURI().toString());
+ NodeList childNodes = documentElement.getChildNodes();
+ for (int i = 0; i < childNodes.getLength(); i++) {
+ Node childNode = childNodes.item(i);
+ if ("name".equals(childNode.getNodeName())) {
+ profileKey = childNode.getChildNodes().item(0).getNodeValue();
+ } else if ("language".equals(childNode.getNodeName())) {
+ languageKey = childNode.getChildNodes().item(0).getNodeValue();
+ }
+ }
+ checkArgument(profileKey != null, "Quality profile file %s is missing profile key", resource.toURI().toString());
+ checkArgument(languageKey != null, "Quality profile file %s is missing language key", resource.toURI().toString());
+ this.profileStatesPerProfileKey.put(profileKey, new Profile(profileKey, languageKey, relativePathToProfile));
+
+ return profileKey;
+ } catch (URISyntaxException | SAXException | IOException | ParserConfigurationException e) {
+ throw new RuntimeException("Can not load quality profile " + relativePathToProfile, e);
+ }
+ }
+
+ public Profile getState(String qualityProfileKey) {
+ Profile profile = this.profileStatesPerProfileKey.get(qualityProfileKey);
+ checkArgument(profile != null, "Quality Profile with key %s is unknown to %s", qualityProfileKey, ProjectAnalysisRule.class.getSimpleName());
+ return profile;
+ }
+
+ public void reset() {
+ this.profileStatesPerProfileKey.clear();
+ init();
+ }
+
+ private void init() {
+ this.profileStatesPerProfileKey.put(Profile.XOO_EMPTY_PROFILE.getProfileKey(), Profile.XOO_EMPTY_PROFILE);
+ }
+}
diff --git a/it/it-tests/src/test/java/util/LoadedProjects.java b/it/it-tests/src/test/java/util/LoadedProjects.java
new file mode 100644
index 00000000000..c40082d3d1c
--- /dev/null
+++ b/it/it-tests/src/test/java/util/LoadedProjects.java
@@ -0,0 +1,82 @@
+/*
+ * 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 util;
+
+import com.google.common.base.Throwables;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
+
+final class LoadedProjects {
+
+ static final String SONAR_PROJECT_PROPERTIES_FILE_NAME = "sonar-project.properties";
+
+ private final Map<String, ProjectState> projectStatePerProjectKey = new HashMap<>();
+ private final Set<String> knownProjects = new HashSet<>();
+
+ public void reset() {
+ this.projectStatePerProjectKey.clear();
+ this.knownProjects.clear();
+ }
+
+ public String load(String projectRelativePath) {
+ checkState(!knownProjects.contains(projectRelativePath), "Project at location %s already loaded", projectRelativePath);
+
+ File projectDir = ItUtils.projectDir(projectRelativePath);
+ Properties sonarProjectProperties = loadProjectProperties(projectDir);
+ ProjectState projectState = new ProjectState(projectDir, sonarProjectProperties);
+
+ register(projectRelativePath, projectState);
+
+ return projectState.getProjectKey();
+ }
+
+ public ProjectState getProjectState(String projectKey) {
+ ProjectState projectState = this.projectStatePerProjectKey.get(projectKey);
+ checkArgument(projectState != null, "Project with key %s is unknown to %s", projectKey, ProjectAnalysisRule.class.getSimpleName());
+ return projectState;
+ }
+
+ private void register(String projectRelativePath, ProjectState projectState) {
+ this.projectStatePerProjectKey.put(projectState.getProjectKey(), projectState);
+ this.knownProjects.add(projectRelativePath);
+ }
+
+ private static Properties loadProjectProperties(File projectDir) {
+ File sonarPropertiesFile = new File(projectDir, SONAR_PROJECT_PROPERTIES_FILE_NAME);
+ checkArgument(sonarPropertiesFile.exists(), "Can not locate %s in project %s", SONAR_PROJECT_PROPERTIES_FILE_NAME, projectDir.getAbsolutePath());
+
+ Properties properties = new Properties();
+ try {
+ properties.load(new FileReader(sonarPropertiesFile));
+ } catch (IOException e) {
+ Throwables.propagate(e);
+ }
+ return properties;
+ }
+}
diff --git a/it/it-tests/src/test/java/util/Profile.java b/it/it-tests/src/test/java/util/Profile.java
new file mode 100644
index 00000000000..414acac58d6
--- /dev/null
+++ b/it/it-tests/src/test/java/util/Profile.java
@@ -0,0 +1,49 @@
+/*
+ * 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 util;
+
+import javax.annotation.concurrent.Immutable;
+
+@Immutable
+final class Profile {
+ static final Profile XOO_EMPTY_PROFILE = new Profile("empty", "xoo", "n/a");
+
+ private final String profileKey;
+ private final String languageKey;
+ private final String relativePath;
+
+ Profile(String profileKey, String languageKey, String relativePath) {
+ this.profileKey = profileKey;
+ this.languageKey = languageKey;
+ this.relativePath = relativePath;
+ }
+
+ public String getProfileKey() {
+ return profileKey;
+ }
+
+ public String getLanguageKey() {
+ return languageKey;
+ }
+
+ public String getRelativePath() {
+ return relativePath;
+ }
+}
diff --git a/it/it-tests/src/test/java/util/ProjectAnalysis.java b/it/it-tests/src/test/java/util/ProjectAnalysis.java
new file mode 100644
index 00000000000..dbf3eeebb9c
--- /dev/null
+++ b/it/it-tests/src/test/java/util/ProjectAnalysis.java
@@ -0,0 +1,51 @@
+/*
+ * 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 util;
+
+public interface ProjectAnalysis {
+ /**
+ * Creates a new ProjectAnalysis which will use the specified quality profile.
+ *
+ * @throws IllegalArgumentException if the quality profile with the specified key has not been loaded into the Rule
+ * @see {@link ProjectAnalysisRule#registerProfile(String)}
+ */
+ ProjectAnalysis withQualityProfile(String qualityProfileKey);
+
+ /**
+ * Creates a new ProjectAnalysis which will use the built-in Xoo empty profile.
+ */
+ ProjectAnalysis withXooEmptyProfile();
+
+ /**
+ * Creates a new ProjectAnalysis which will have debug logs enabled (or not).
+ */
+ ProjectAnalysis withDebugLogs(boolean enabled);
+
+ /**
+ * Creates a new ProjectAnalysis which will have the specified properties.
+ */
+ ProjectAnalysis withProperties(String... properties);
+
+ /**
+ * Execute the current ProjectAnalysis.
+ * This method can be called any number of time and will run the same analysis again and again.
+ */
+ void run();
+}
diff --git a/it/it-tests/src/test/java/util/ProjectAnalysisRule.java b/it/it-tests/src/test/java/util/ProjectAnalysisRule.java
new file mode 100644
index 00000000000..17710c4eaf1
--- /dev/null
+++ b/it/it-tests/src/test/java/util/ProjectAnalysisRule.java
@@ -0,0 +1,228 @@
+/*
+ * 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 util;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.collect.ImmutableMap;
+import com.sonar.orchestrator.Orchestrator;
+import com.sonar.orchestrator.build.SonarRunner;
+import com.sonar.orchestrator.locator.FileLocation;
+import java.util.HashSet;
+import java.util.Set;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.Immutable;
+import org.junit.rules.ExternalResource;
+import org.sonar.wsclient.services.PropertyDeleteQuery;
+import org.sonar.wsclient.services.PropertyUpdateQuery;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static java.util.Objects.requireNonNull;
+
+/**
+ * Rule wrapping around an {@link Orchestrator} instance which handle:
+ * <ul>
+ * <li>automatic reset of Orchestrator data after each method when used as a {@link org.junit.Rule},
+ * after each class when used as a {@link org.junit.ClassRule}</li>
+ * <li>automatic reset of server properties after each method when used as a {@link org.junit.Rule},
+ * after each class when used as a {@link org.junit.ClassRule}</li>
+ * <li>associating project with a specific Quality Profile before running an analysis</li>
+ * <li>provisioning a project before its first analysis so that a Quality Profile can be associated to it</li>
+ * <li>"restoring" a Quality Profile before an analysis with a specific Quality Profile</li>
+ * </ul>
+ *
+ * This Rule has preparatory methods ({@link #registerProfile(String)} and {@link #registerProject(String)}) which
+ * will allow consequent calls to the rule methods to be based solely on Quality Profile and Project keys. In addition,
+ * these methods returns the Quality Profile and Project key to avoid information duplication (the only magic string
+ * the IT developer has to know is the relative path of the Project or the Quality Profile).
+ *
+ * To run an analysis, use method {@link #newProjectAnalysis(String)} to create a {@link ProjectAnalysis}
+ * object. This object has a {@link ProjectAnalysis#run()} method which will start the analysis.
+ * {@link ProjectAnalysis} can safely be reused to run the same analysis multiple times. In addition, these objects are
+ * immutable. Any call to one of their method which would modify their state will create a new instance which can also
+ * be reused at will.
+ */
+public class ProjectAnalysisRule extends ExternalResource {
+
+ private final Orchestrator orchestrator;
+ private final LoadedProfiles loadedProfiles = new LoadedProfiles();
+ private final LoadedProjects loadedProjects = new LoadedProjects();
+ private final Set<String> serverProperties = new HashSet<>();
+
+ private ProjectAnalysisRule(Orchestrator orchestrator) {
+ this.orchestrator = orchestrator;
+ }
+
+ public static ProjectAnalysisRule from(Orchestrator orchestrator) {
+ return new ProjectAnalysisRule(requireNonNull(orchestrator, "Orchestrator instance can not be null"));
+ }
+
+ /**
+ * @param relativePathToProfile eg.: "/issue/suite/IssueFilterExtensionTest/xoo-with-many-rules.xml"
+ *
+ * @return the quality profile key
+ */
+ public String registerProfile(String relativePathToProfile) {
+ return this.loadedProfiles.loadProfile(relativePathToProfile);
+ }
+
+ /**
+ * @param projectRelativePath path relative to it/it-projects, eg. "shared/xoo-multi-modules-sample"
+ *
+ * @return the project key
+ */
+ public String registerProject(String projectRelativePath) {
+ return this.loadedProjects.load(projectRelativePath);
+ }
+
+ public ProjectAnalysis newProjectAnalysis(String projectKey) {
+ ProjectState projectState = this.loadedProjects.getProjectState(projectKey);
+
+ return new ProjectAnalysisImpl(projectState, null, false);
+ }
+
+ @Override
+ protected void before() throws Throwable {
+ orchestrator.resetData();
+ }
+
+ @Override
+ protected void after() {
+ resetServerProperties();
+ resetRuleState();
+ }
+
+ private void resetServerProperties() {
+ for (String serverProperty : serverProperties) {
+ setServerPropertyImpl(serverProperty, null);
+ }
+ }
+
+ public void setServerPropertyImpl(String key, @Nullable String value) {
+ if (value == null) {
+ orchestrator.getServer().getAdminWsClient().delete(new PropertyDeleteQuery(key));
+ } else {
+ orchestrator.getServer().getAdminWsClient().update(new PropertyUpdateQuery().setKey(key).setValue(value));
+ }
+ }
+
+ public ProjectAnalysisRule setServerProperty(String key, String value) {
+ setServerPropertyImpl(key, value);
+ this.serverProperties.add(key);
+ return this;
+ }
+
+ @Immutable
+ private final class ProjectAnalysisImpl implements ProjectAnalysis {
+ private final ProjectState projectState;
+ @CheckForNull
+ private final Profile qualityProfile;
+ private final boolean debugLogs;
+ @CheckForNull
+ private final String[] properties;
+
+ private ProjectAnalysisImpl(ProjectState projectState, @Nullable Profile qualityProfile, boolean debugLogs, String... properties) {
+ this.projectState = projectState;
+ this.qualityProfile = qualityProfile;
+ this.debugLogs = debugLogs;
+ this.properties = properties;
+ }
+
+ @Override
+ public ProjectAnalysis withQualityProfile(String qualityProfileKey) {
+ checkNotNull(qualityProfileKey, "Specified Quality Profile Key can not be null");
+ if (this.qualityProfile != null && this.qualityProfile.getProfileKey().equals(qualityProfileKey)) {
+ return this;
+ }
+
+ return new ProjectAnalysisImpl(this.projectState, loadedProfiles.getState(qualityProfileKey), this.debugLogs, this.properties);
+ }
+
+ @Override
+ public ProjectAnalysis withXooEmptyProfile() {
+ if (this.qualityProfile == Profile.XOO_EMPTY_PROFILE) {
+ return this;
+ }
+ return new ProjectAnalysisImpl(this.projectState, Profile.XOO_EMPTY_PROFILE, this.debugLogs, this.properties);
+ }
+
+ @Override
+ public ProjectAnalysis withDebugLogs(boolean enabled) {
+ if (this.debugLogs == enabled) {
+ return this;
+ }
+ return new ProjectAnalysisImpl(this.projectState, this.qualityProfile, enabled, this.properties);
+ }
+
+ @Override
+ public ProjectAnalysis withProperties(String... properties) {
+ checkArgument(
+ properties == null || properties.length % 2 == 0,
+ "there must be an even number of String parameters (got %s): key/value pairs must be complete", properties == null ? 0 : properties.length);
+ return new ProjectAnalysisImpl(this.projectState, this.qualityProfile, this.debugLogs, properties);
+ }
+
+ @Override
+ public void run() {
+ provisionIfNecessary();
+ setQualityProfileIfNecessary();
+ runAnalysis();
+ }
+
+ private void setQualityProfileIfNecessary() {
+ if (this.qualityProfile != null) {
+ if (this.qualityProfile != Profile.XOO_EMPTY_PROFILE) {
+ orchestrator.getServer().restoreProfile(FileLocation.ofClasspath(this.qualityProfile.getRelativePath()));
+ }
+ orchestrator.getServer().associateProjectToQualityProfile(
+ this.projectState.getProjectKey(),
+ this.qualityProfile.getLanguageKey(),
+ this.qualityProfile.getProfileKey());
+ }
+ }
+
+ private void provisionIfNecessary() {
+ if (this.qualityProfile != null && !projectState.isProvisioned()) {
+ String projectKey = projectState.getProjectKey();
+ orchestrator.getServer().provisionProject(projectKey, MoreObjects.firstNonNull(projectState.getProjectName(), projectKey));
+ projectState.setProvisioned(true);
+ }
+ }
+
+ private SonarRunner runAnalysis() {
+ SonarRunner sonarRunner = SonarRunner.create(projectState.getProjectDir());
+ ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
+ for (int i = 0; i < this.properties.length; i += 2) {
+ builder.put(this.properties[i], this.properties[i + 1]);
+ }
+ SonarRunner scan = sonarRunner.setDebugLogs(this.debugLogs).setProperties(builder.build());
+ orchestrator.executeBuild(scan);
+ return scan;
+ }
+ }
+
+ private void resetRuleState() {
+ this.loadedProjects.reset();
+ this.loadedProfiles.reset();
+ this.serverProperties.clear();
+ }
+
+}
diff --git a/it/it-tests/src/test/java/util/ProjectState.java b/it/it-tests/src/test/java/util/ProjectState.java
new file mode 100644
index 00000000000..7448a66ee85
--- /dev/null
+++ b/it/it-tests/src/test/java/util/ProjectState.java
@@ -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 util;
+
+import java.io.File;
+import java.util.Properties;
+
+import static com.google.common.base.Preconditions.checkState;
+import static util.LoadedProjects.SONAR_PROJECT_PROPERTIES_FILE_NAME;
+
+final class ProjectState {
+ private static final String SONAR_PROJECT_KEY_PROPERTY_NAME = "sonar.projectKey";
+ private static final String SONAR_PROJECT_NAME_PROPERTY_NAME = "sonar.projectName";
+
+ private final File projectDir;
+ private final Properties properties;
+ private boolean provisioned = false;
+
+ ProjectState(File projectDir, Properties properties) {
+ this.projectDir = projectDir;
+ this.properties = properties;
+ }
+
+ public File getProjectDir() {
+ return projectDir;
+ }
+
+ public Properties getProperties() {
+ return properties;
+ }
+
+ public String getProjectKey() {
+ return getProperty(SONAR_PROJECT_KEY_PROPERTY_NAME);
+ }
+
+ public String getProjectName() {
+ return getProperty(SONAR_PROJECT_NAME_PROPERTY_NAME);
+ }
+
+ private String getProperty(String propertyName) {
+ String value = this.properties.getProperty(propertyName);
+ checkState(value != null, "Property %s is missing in %s file in project directory %s",
+ propertyName, SONAR_PROJECT_PROPERTIES_FILE_NAME, projectDir.getAbsolutePath());
+ return value;
+ }
+
+ public boolean isProvisioned() {
+ return provisioned;
+ }
+
+ public void setProvisioned(boolean provisioned) {
+ this.provisioned = provisioned;
+ }
+}