diff options
author | Sébastien Lesaint <sebastien.lesaint@sonarsource.com> | 2015-10-21 18:00:29 +0200 |
---|---|---|
committer | Julien Lancelot <julien.lancelot@sonarsource.com> | 2015-10-23 10:44:16 +0200 |
commit | b9fef5c3876d9f1a1ab4d279f842d648a5c3362f (patch) | |
tree | 4a338aeced78cd7a2bb8685facaae77ed4fe532f | |
parent | 48f46a23436ebb543ac56ad708853324c950ae4e (diff) | |
download | sonarqube-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
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; + } +} |