From 287fbc9aa4a5f78db7dbb42adf422a632b74fa1e Mon Sep 17 00:00:00 2001 From: Julien HENRY Date: Wed, 2 Dec 2015 14:10:44 +0100 Subject: [PATCH] SONAR-7100 Disable WS cache by default in issues mode --- .../test/java/it/analysis/IssuesModeTest.java | 123 ++++++------------ .../analysis/AnalysisWSLoaderProvider.java | 9 +- .../AnalysisWSLoaderProviderTest.java | 19 ++- 3 files changed, 63 insertions(+), 88 deletions(-) diff --git a/it/it-tests/src/test/java/it/analysis/IssuesModeTest.java b/it/it-tests/src/test/java/it/analysis/IssuesModeTest.java index 14749d888fd..bb0b6d10b31 100644 --- a/it/it-tests/src/test/java/it/analysis/IssuesModeTest.java +++ b/it/it-tests/src/test/java/it/analysis/IssuesModeTest.java @@ -5,8 +5,6 @@ */ package it.analysis; -import org.apache.commons.io.FileUtils; -import org.sonar.wsclient.issue.IssueClient; import com.google.common.collect.Maps; import com.sonar.orchestrator.Orchestrator; import com.sonar.orchestrator.build.BuildFailureException; @@ -17,7 +15,6 @@ import com.sonar.orchestrator.config.FileSystem; import com.sonar.orchestrator.locator.FileLocation; import com.sonar.orchestrator.version.Version; import it.Category3Suite; - import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; @@ -29,7 +26,8 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; - +import javax.annotation.Nullable; +import org.apache.commons.io.FileUtils; import org.apache.commons.lang.ObjectUtils; import org.json.simple.JSONArray; import org.json.simple.JSONObject; @@ -41,12 +39,14 @@ import org.junit.rules.ExpectedException; import org.junit.rules.TemporaryFolder; import org.sonar.wsclient.SonarClient; import org.sonar.wsclient.issue.Issue; +import org.sonar.wsclient.issue.IssueClient; import org.sonar.wsclient.issue.IssueQuery; import org.sonar.wsclient.issue.Issues; import org.sonar.wsclient.services.Resource; import org.sonar.wsclient.services.ResourceQuery; import org.sonar.wsclient.user.UserParameters; import util.ItUtils; + import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.fail; @@ -71,7 +71,7 @@ public class IssuesModeTest { restoreProfile("one-issue-per-line.xml"); orchestrator.getServer().provisionProject("sample", "xoo-sample"); orchestrator.getServer().associateProjectToQualityProfile("sample", "xoo", "one-issue-per-line"); - SonarRunner runner = configureRunnerIssues("shared/xoo-sample", "sonar.verbose", "true"); + SonarRunner runner = configureRunnerIssues("shared/xoo-sample", null, "sonar.verbose", "true"); BuildResult result = orchestrator.executeBuild(runner); assertThat(ItUtils.countIssuesInJsonReport(result, true)).isEqualTo(17); } @@ -122,7 +122,7 @@ public class IssuesModeTest { orchestrator.getServer().associateProjectToQualityProfile("sample", "xoo", "with-many-rules"); // do it again, scanning nothing (all files should be unchanged) - runner = configureRunnerIssues("shared/xoo-sample", + runner = configureRunnerIssues("shared/xoo-sample", null, "sonar.verbose", "true"); result = orchestrator.executeBuild(runner); assertThat(result.getLogs()).contains("Scanning only changed files"); @@ -151,7 +151,7 @@ public class IssuesModeTest { issueClient.doTransition(serverIssues.get(1).key(), "wontfix"); // do it again, scanning nothing (all files should be unchanged) - runner = configureRunnerIssues("shared/xoo-sample", + runner = configureRunnerIssues("shared/xoo-sample", null, "sonar.verbose", "true"); result = orchestrator.executeBuild(runner); assertThat(result.getLogs()).contains("Scanning only changed files"); @@ -197,7 +197,7 @@ public class IssuesModeTest { public void non_associated_mode() throws IOException { restoreProfile("one-issue-per-line.xml"); setDefaultQualityProfile("xoo", "one-issue-per-line"); - SonarRunner runner = configureRunnerIssues("shared/xoo-sample-non-associated"); + SonarRunner runner = configureRunnerIssues("shared/xoo-sample-non-associated", null); BuildResult result = orchestrator.executeBuild(runner); assertThat(result.getLogs()).contains("Local analysis"); @@ -220,7 +220,7 @@ public class IssuesModeTest { BuildResult result = orchestrator.executeBuild(runner); assertThat(getResource("sample:my sources/main/xoo/sample/My Sample.xoo")).isNotNull(); - runner = configureRunnerIssues("analysis/xoo-sample-with-spaces/v2"); + runner = configureRunnerIssues("analysis/xoo-sample-with-spaces/v2", null); result = orchestrator.executeBuild(runner); // Analysis is not persisted in database Resource project = getResource("com.sonarsource.it.samples:simple-sample"); @@ -246,7 +246,7 @@ public class IssuesModeTest { assertThat(getResource("sample:src/main/xoo/sample/ClassAdded.xoo")).isNull(); // Re-add ClassAdded.xoo in local workspace - runner = configureRunnerIssues("shared/xoo-history-v2"); + runner = configureRunnerIssues("shared/xoo-history-v2", null); result = orchestrator.executeBuild(runner); assertThat(getResource("sample:src/main/xoo/sample/ClassAdded.xoo")).isNull(); @@ -257,7 +257,7 @@ public class IssuesModeTest { @Test public void should_fail_if_plugin_access_secured_properties() throws IOException { // Test access from task (ie BatchSettings) - SonarRunner runner = configureRunnerIssues("shared/xoo-sample", + SonarRunner runner = configureRunnerIssues("shared/xoo-sample", null, "accessSecuredFromTask", "true"); BuildResult result = orchestrator.executeBuildQuietly(runner); @@ -265,7 +265,7 @@ public class IssuesModeTest { + "The SonarQube plugin which requires this property must be deactivated in issues mode."); // Test access from sensor (ie ModuleSettings) - runner = configureRunnerIssues("shared/xoo-sample", + runner = configureRunnerIssues("shared/xoo-sample", null, "accessSecuredFromSensor", "true"); result = orchestrator.executeBuildQuietly(runner); @@ -275,74 +275,31 @@ public class IssuesModeTest { // SONAR-4602 @Test - public void no_issues_mode_cache_after_new_analysis() throws Exception { - restoreProfile("one-issue-per-line.xml"); - restoreProfile("empty.xml"); - orchestrator.getServer().provisionProject("sample", "xoo-sample"); - - // First run (publish mode) - orchestrator.getServer().associateProjectToQualityProfile("sample", "xoo", "empty"); - SonarRunner runner = configureRunner("shared/xoo-sample"); - orchestrator.executeBuild(runner); + public void no_issues_mode_cache_by_default() throws Exception { + File homeDir = runFirstAnalysisAndFlagIssueAsWontFix(); - // First run issues mode - orchestrator.getServer().associateProjectToQualityProfile("sample", "xoo", "one-issue-per-line"); - runner = configureRunnerIssues("shared/xoo-sample", - "sonar.scanAllFiles", "true"); + // Second issues mode using same cache dir but cache disabled by default + SonarRunner runner = configureRunnerIssues("shared/xoo-sample", homeDir); BuildResult result = orchestrator.executeBuild(runner); - // As many new issue as lines - assertThat(ItUtils.countIssuesInJsonReport(result, true)).isEqualTo(17); - - // Second run (publish mode) should invalidate cache - runner = configureRunner("shared/xoo-sample"); - orchestrator.executeBuild(runner); - - // Second run issues mode - runner = configureRunnerIssues("shared/xoo-sample", - "sonar.report.export.path", "sonar-report.json", - "sonar.scanAllFiles", "true"); - result = orchestrator.executeBuild(runner); - - // No new issue this time - assertThat(ItUtils.countIssuesInJsonReport(result, true)).isEqualTo(0); + // False positive is not returned + assertThat(ItUtils.countIssuesInJsonReport(result, false)).isEqualTo(16); } - // SONAR-4602 + // SONAR-7100 @Test - public void no_issues_mode_cache_after_profile_change() throws Exception { - restoreProfile("one-issue-per-line-empty.xml"); - orchestrator.getServer().provisionProject("sample", "xoo-sample"); - orchestrator.getServer().associateProjectToQualityProfile("sample", "xoo", "one-issue-per-line"); - - // First run (publish mode) - SonarRunner runner = configureRunner("shared/xoo-sample"); - orchestrator.executeBuild(runner); + public void enable_issues_cache() throws Exception { + File homeDir = runFirstAnalysisAndFlagIssueAsWontFix(); - // First issues mode - runner = configureRunnerIssues("shared/xoo-sample", - "sonar.scanAllFiles", "true"); + // Second issues mode using same cache dir and enable cache + SonarRunner runner = configureRunnerIssues("shared/xoo-sample", homeDir, "sonar.useWsCache", "true"); BuildResult result = orchestrator.executeBuild(runner); - // No new issues - assertThat(ItUtils.countIssuesInJsonReport(result, true)).isEqualTo(0); - - // Modification of QP should invalidate cache - restoreProfile("/one-issue-per-line.xml"); - - // Second issues mode - runner = configureRunnerIssues("shared/xoo-sample", - "sonar.report.export.path", "sonar-report.json", - "sonar.scanAllFiles", "true"); - result = orchestrator.executeBuild(runner); - - // As many new issue as lines - assertThat(ItUtils.countIssuesInJsonReport(result, true)).isEqualTo(17); + // False positive is still visible since we are using cached issues + assertThat(ItUtils.countIssuesInJsonReport(result, false)).isEqualTo(17); } - // SONAR-4602 - @Test - public void no_issues_mode_cache_after_issue_change() throws Exception { + private File runFirstAnalysisAndFlagIssueAsWontFix() throws IOException { restoreProfile("one-issue-per-line.xml"); orchestrator.getServer().provisionProject("sample", "xoo-sample"); orchestrator.getServer().associateProjectToQualityProfile("sample", "xoo", "one-issue-per-line"); @@ -352,7 +309,8 @@ public class IssuesModeTest { orchestrator.executeBuild(runner); // First issues mode - runner = configureRunnerIssues("shared/xoo-sample"); + File homeDir = temp.newFolder(); + runner = configureRunnerIssues("shared/xoo-sample", homeDir); BuildResult result = orchestrator.executeBuild(runner); // 17 issues @@ -362,13 +320,7 @@ public class IssuesModeTest { JSONObject obj = ItUtils.getJSONReport(result); String key = ((JSONObject) ((JSONArray) obj.get("issues")).get(0)).get("key").toString(); orchestrator.getServer().adminWsClient().issueClient().doTransition(key, "falsepositive"); - - // Second issues mode - runner = configureRunnerIssues("shared/xoo-sample"); - result = orchestrator.executeBuild(runner); - - // False positive is not returned - assertThat(ItUtils.countIssuesInJsonReport(result, false)).isEqualTo(16); + return homeDir; } // SONAR-6522 @@ -395,7 +347,7 @@ public class IssuesModeTest { client.issueClient().assign(issue.key(), "julien"); // Issues - runner = configureRunnerIssues("shared/xoo-sample"); + runner = configureRunnerIssues("shared/xoo-sample", null); BuildResult result = orchestrator.executeBuild(runner); JSONObject obj = ItUtils.getJSONReport(result); @@ -433,18 +385,19 @@ public class IssuesModeTest { runConcurrentIssues(); } - private void runConcurrentIssues() throws InterruptedException, ExecutionException { + private void runConcurrentIssues() throws Exception { // Install sonar-runner in advance to avoid concurrent unzip issues FileSystem fileSystem = orchestrator.getConfiguration().fileSystem(); new SonarRunnerInstaller(fileSystem).install(Version.create(SonarRunner.DEFAULT_RUNNER_VERSION), fileSystem.workspace()); final int nThreads = 3; ExecutorService executorService = Executors.newFixedThreadPool(nThreads); List> tasks = new ArrayList<>(); + final File homeDir = temp.newFolder(); for (int i = 0; i < nThreads; i++) { tasks.add(new Callable() { public BuildResult call() throws Exception { - SonarRunner runner = configureRunnerIssues("shared/xoo-sample"); + SonarRunner runner = configureRunnerIssues("shared/xoo-sample", homeDir); return orchestrator.executeBuild(runner); } }); @@ -475,12 +428,16 @@ public class IssuesModeTest { return orchestrator.getServer().getWsClient().find(ResourceQuery.createForMetrics(key, "lines")); } - private SonarRunner configureRunnerIssues(String projectDir, String... props) throws IOException { + private SonarRunner configureRunnerIssues(String projectDir, @Nullable File homeDir, String... props) throws IOException { SonarRunner runner = SonarRunner.create(ItUtils.projectDir(projectDir), "sonar.working.directory", temp.newFolder().getAbsolutePath(), "sonar.analysis.mode", "issues", - "sonar.report.export.path", "sonar-report.json", - "sonar.userHome", temp.newFolder().getAbsolutePath()); + "sonar.report.export.path", "sonar-report.json"); + if (homeDir != null) { + runner.setProperty("sonar.userHome", homeDir.getAbsolutePath()); + } else { + runner.setProperty("sonar.userHome", temp.newFolder().getAbsolutePath()); + } runner.setProperties(props); return runner; } diff --git a/sonar-batch/src/main/java/org/sonar/batch/analysis/AnalysisWSLoaderProvider.java b/sonar-batch/src/main/java/org/sonar/batch/analysis/AnalysisWSLoaderProvider.java index 7ca47ae787a..fc3482a2006 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/analysis/AnalysisWSLoaderProvider.java +++ b/sonar-batch/src/main/java/org/sonar/batch/analysis/AnalysisWSLoaderProvider.java @@ -27,19 +27,20 @@ import org.sonar.batch.cache.WSLoader.LoadStrategy; import org.sonar.home.cache.PersistentCache; public class AnalysisWSLoaderProvider extends ProviderAdapter { + static final String SONAR_USE_WS_CACHE = "sonar.useWsCache"; private WSLoader wsLoader; - public WSLoader provide(AnalysisMode mode, PersistentCache cache, BatchWsClient client) { + public WSLoader provide(AnalysisMode mode, PersistentCache cache, BatchWsClient client, AnalysisProperties props) { if (wsLoader == null) { // recreate cache directory if needed for this analysis cache.reconfigure(); - wsLoader = new WSLoader(getStrategy(mode), cache, client); + wsLoader = new WSLoader(getStrategy(mode, props), cache, client); } return wsLoader; } - private static LoadStrategy getStrategy(AnalysisMode mode) { - if (mode.isIssues()) { + private static LoadStrategy getStrategy(AnalysisMode mode, AnalysisProperties props) { + if (mode.isIssues() && "true".equals(props.property(SONAR_USE_WS_CACHE))) { return LoadStrategy.CACHE_ONLY; } diff --git a/sonar-batch/src/test/java/org/sonar/batch/analysis/AnalysisWSLoaderProviderTest.java b/sonar-batch/src/test/java/org/sonar/batch/analysis/AnalysisWSLoaderProviderTest.java index b175faa6bc6..5aa31bd64d5 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/analysis/AnalysisWSLoaderProviderTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/analysis/AnalysisWSLoaderProviderTest.java @@ -19,6 +19,8 @@ */ package org.sonar.batch.analysis; +import com.google.common.collect.ImmutableMap; +import org.assertj.core.util.Maps; import org.junit.Test; import org.sonar.api.batch.AnalysisMode; import org.sonar.batch.bootstrap.BatchWsClient; @@ -28,6 +30,7 @@ import org.sonar.home.cache.PersistentCache; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class AnalysisWSLoaderProviderTest { @@ -39,7 +42,21 @@ public class AnalysisWSLoaderProviderTest { @Test public void testDefault() { - WSLoader loader = underTest.provide(mode, cache, wsClient); + WSLoader loader = underTest.provide(mode, cache, wsClient, new AnalysisProperties(Maps.newHashMap())); assertThat(loader.getDefaultStrategy()).isEqualTo(LoadStrategy.SERVER_ONLY); } + + @Test + public void no_cache_by_default_in_issues_mode() { + when(mode.isIssues()).thenReturn(true); + WSLoader loader = underTest.provide(mode, cache, wsClient, new AnalysisProperties(Maps.newHashMap())); + assertThat(loader.getDefaultStrategy()).isEqualTo(LoadStrategy.SERVER_ONLY); + } + + @Test + public void enable_cache_in_issues_mode() { + when(mode.isIssues()).thenReturn(true); + WSLoader loader = underTest.provide(mode, cache, wsClient, new AnalysisProperties(ImmutableMap.of(AnalysisWSLoaderProvider.SONAR_USE_WS_CACHE, "true"))); + assertThat(loader.getDefaultStrategy()).isEqualTo(LoadStrategy.CACHE_ONLY); + } } -- 2.39.5