]> source.dussan.org Git - sonar-scanner-cli.git/commitdiff
Change cache strategy
authorDuarte Meneses <duarte.meneses@sonarsource.com>
Thu, 1 Oct 2015 15:26:34 +0000 (17:26 +0200)
committerDuarte Meneses <duarte.meneses@sonarsource.com>
Thu, 1 Oct 2015 15:50:36 +0000 (17:50 +0200)
13 files changed:
it/src/test/java/com/sonar/runner/it/CacheTest.java
sonar-runner-api/src/main/java/org/sonar/runner/api/EmbeddedRunner.java
sonar-runner-api/src/main/java/org/sonar/runner/cache/FileCacheBuilder.java
sonar-runner-api/src/main/java/org/sonar/runner/impl/IsolatedLauncherFactory.java
sonar-runner-api/src/main/java/org/sonar/runner/impl/Jars.java
sonar-runner-api/src/main/java/org/sonar/runner/impl/ServerConnection.java
sonar-runner-api/src/main/java/org/sonar/runner/impl/SimulatedLauncher.java
sonar-runner-api/src/test/java/org/sonar/runner/api/EmbeddedRunnerTest.java
sonar-runner-api/src/test/java/org/sonar/runner/impl/IsolatedLauncherFactoryTest.java
sonar-runner-api/src/test/java/org/sonar/runner/impl/JarsTest.java
sonar-runner-api/src/test/java/org/sonar/runner/impl/ServerConnectionTest.java
sonar-runner-batch-interface/src/main/java/org/sonar/runner/batch/IsolatedLauncher.java
sonar-runner-batch/src/main/java/org/sonar/runner/batch/BatchIsolatedLauncher.java

index 0e99bf98a8ccd02539eade95941fd8cfd7b354e5..7e9c9532de55a90a3188aa45573e4771529277ca 100644 (file)
@@ -32,6 +32,8 @@ import org.junit.Test;
 import java.io.File;
 import java.io.IOException;
 
+import static org.junit.Assert.fail;
+
 import static org.assertj.core.api.Assertions.assertThat;
 
 public class CacheTest extends RunnerTestCase {
@@ -83,8 +85,11 @@ public class CacheTest extends RunnerTestCase {
     build = createRunner("issues", true, "java-sample");
     try {
       result = orchestrator.executeBuild(build);
+      fail("exception expected");
     } catch (BuildFailureException e) {
-      assertThat(e.getResult().getLogs()).contains("and data is not cached");
+      // this message is specific to the server_first cache strategy
+      assertThat(e.getResult().getLogs()).contains("can not be reached, trying cache");
+      assertThat(e.getResult().getLogs()).contains("can not be reached and data is not cached");
     }
   }
 
index 021e1296d9fe0036cb955b437154f901b7980b63..bfffc510f1bb6c38b6995da9bb8d5ddaedc1c74c 100644 (file)
@@ -183,9 +183,9 @@ public class EmbeddedRunner {
     start(false);
   }
 
-  public void start(boolean forceSync) {
+  public void start(boolean preferCache) {
     initGlobalDefaultValues();
-    doStart(forceSync);
+    doStart(preferCache);
   }
 
   /**
@@ -244,10 +244,10 @@ public class EmbeddedRunner {
     }
   }
 
-  protected void doStart(boolean forceSync) {
+  protected void doStart(boolean preferCache) {
     checkLauncherDoesntExist();
     ClassloadRules rules = new ClassloadRules(classloaderMask, classloaderUnmask);
-    launcher = launcherFactory.createLauncher(globalProperties(), rules);
+    launcher = launcherFactory.createLauncher(globalProperties(), rules, preferCache);
     if (VersionUtils.isAtLeast52(launcher.getVersion())) {
       launcher.start(globalProperties(), new org.sonar.runner.batch.LogOutput() {
 
@@ -256,7 +256,7 @@ public class EmbeddedRunner {
           logOutput.log(formattedMessage, LogOutput.Level.valueOf(level.name()));
         }
 
-      }, forceSync);
+      }, preferCache);
     }
   }
 
index 9be8e11a24fc75daa8fa96cc0d010f00010933fb..0a668b87d6933678a7eebc9cb9289d11dec28e41 100644 (file)
@@ -49,7 +49,7 @@ public class FileCacheBuilder {
     return FileCache.create(cacheDir, logger);
   }
   
-  private File findHome() {
+  private static File findHome() {
     String path = System.getenv("SONAR_USER_HOME");
     if (path == null) {
       // Default
index be92d0208410855f5264bdf716e43912a5a72911..0a1a0c7711d14137b2f03f77b8ea775f835e59e7 100644 (file)
@@ -69,7 +69,7 @@ public class IsolatedLauncherFactory {
     return classloader;
   }
 
-  public IsolatedLauncher createLauncher(Properties props, ClassloadRules rules) {
+  public IsolatedLauncher createLauncher(Properties props, ClassloadRules rules, boolean preferCache) {
     if (props.containsKey(InternalProperties.RUNNER_DUMP_TO_FILE)) {
       String version = props.getProperty(InternalProperties.RUNNER_VERSION_SIMULATION);
       if (version == null) {
@@ -77,7 +77,7 @@ public class IsolatedLauncherFactory {
       }
       return new SimulatedLauncher(version, logger);
     }
-    ServerConnection serverConnection = ServerConnection.create(props, getCache(props), logger);
+    ServerConnection serverConnection = ServerConnection.create(props, getCache(props), logger, preferCache);
     JarDownloader jarDownloader = new JarDownloader(serverConnection, logger, props);
 
     return createLauncher(jarDownloader, rules);
index 972675bbb29fbf9f206b3429159b1265dcd1a58e..d9571294e2f515a329921da3b57dd5eeae4020a8 100644 (file)
@@ -76,7 +76,7 @@ class Jars {
     try {
       List<File> files = new ArrayList<File>();
       logger.debug("Get bootstrap index...");
-      String libs = connection.downloadStringCache(BOOTSTRAP_INDEX_PATH);
+      String libs = connection.loadString(BOOTSTRAP_INDEX_PATH);
       logger.debug("Get bootstrap completed");
       String[] lines = libs.split("[\r\n]+");
       BatchFileDownloader batchFileDownloader = new BatchFileDownloader(connection);
index 30c3cf1bae7603cc42ceb3656e7e69b3e81586b7..8a40f41930553849bbc1a56489be0160aee3201c 100644 (file)
@@ -47,28 +47,30 @@ class ServerConnection {
   private final String userAgent;
 
   private final PersistentCache wsCache;
-  private final boolean isCacheEnable;
+  private final boolean preferCache;
   private final Logger logger;
+  private final boolean isCacheEnabled;
 
-  private ServerConnection(String serverUrl, String app, String appVersion, boolean isCacheEnable, PersistentCache cache, Logger logger) {
+  private ServerConnection(String serverUrl, String app, String appVersion, boolean preferCache, boolean cacheEnabled, PersistentCache cache, Logger logger) {
+    this.isCacheEnabled = cacheEnabled;
     this.logger = logger;
     this.serverUrl = removeEndSlash(serverUrl);
     this.userAgent = app + "/" + appVersion;
     this.wsCache = cache;
-    this.isCacheEnable = isCacheEnable;
+    this.preferCache = preferCache;
   }
 
   private static String removeEndSlash(String url) {
     return url.endsWith("/") ? url.substring(0, url.length() - 1) : url;
   }
 
-  static ServerConnection create(Properties properties, PersistentCache cache, Logger logger) {
+  static ServerConnection create(Properties properties, PersistentCache cache, Logger logger, boolean preferCache) {
     String serverUrl = properties.getProperty("sonar.host.url");
     String app = properties.getProperty(InternalProperties.RUNNER_APP);
     String appVersion = properties.getProperty(InternalProperties.RUNNER_APP_VERSION);
     boolean enableCache = isCacheEnabled(properties);
 
-    return new ServerConnection(serverUrl, app, appVersion, enableCache, cache, logger);
+    return new ServerConnection(serverUrl, app, appVersion, preferCache, enableCache, cache, logger);
   }
 
   private static boolean isCacheEnabled(Properties properties) {
@@ -120,7 +122,7 @@ class ServerConnection {
       httpRequest.receive(toFile);
 
     } catch (Exception e) {
-      if (e.getCause() instanceof ConnectException || e.getCause() instanceof UnknownHostException) {
+      if (isCausedByConnection(e)) {
         logger.error(MessageFormat.format(SONAR_SERVER_CAN_NOT_BE_REACHED, serverUrl));
       }
       FileUtils.deleteQuietly(toFile);
@@ -129,16 +131,45 @@ class ServerConnection {
   }
 
   /**
-   * Tries to fetch from server and falls back to cache. If both attempts fail, it throws the exception 
-   * linked to the server connection failure.
+   * Tries to fetch from cache and server. If both attempts fail, it throws the exception linked to the server connection failure.
    */
-  String downloadStringCache(String path) throws IOException {
+  String loadString(String path) throws IOException {
     String fullUrl = serverUrl + path;
+
+    if (isCacheEnabled && preferCache) {
+      return tryCacheFirst(fullUrl);
+    } else {
+      return tryServerFirst(fullUrl, isCacheEnabled);
+    }
+
+  }
+
+  private String tryCacheFirst(String fullUrl) throws IOException {
+    String cached = getFromCache(fullUrl);
+    if (cached != null) {
+      return cached;
+    }
+
     try {
-      return downloadString(fullUrl, isCacheEnable);
+      return downloadString(fullUrl, preferCache);
+    } catch (Exception e) {
+      logger.error(MessageFormat.format("Data is not cached and " + SONAR_SERVER_CAN_NOT_BE_REACHED, serverUrl));
+      throw e;
+    }
+  }
+
+  private String tryServerFirst(String fullUrl, boolean cacheEnabled) throws IOException {
+    try {
+      return downloadString(fullUrl, cacheEnabled);
     } catch (HttpRequest.HttpRequestException e) {
-      if (isCausedByConnection(e) && isCacheEnable) {
-        return fallbackToCache(fullUrl, e);
+      if (cacheEnabled && isCausedByConnection(e)) {
+        logger.info(MessageFormat.format(SONAR_SERVER_CAN_NOT_BE_REACHED + ", trying cache", serverUrl));
+        String cached = getFromCache(fullUrl);
+        if (cached != null) {
+          return cached;
+        }
+        logger.error(MessageFormat.format(SONAR_SERVER_CAN_NOT_BE_REACHED + " and data is not cached", serverUrl));
+        throw e;
       }
 
       logger.error(MessageFormat.format(SONAR_SERVER_CAN_NOT_BE_REACHED, serverUrl));
@@ -151,20 +182,12 @@ class ServerConnection {
       e.getCause() instanceof java.net.SocketTimeoutException;
   }
 
-  private String fallbackToCache(String fullUrl, HttpRequest.HttpRequestException originalException) {
-    logger.info(MessageFormat.format(SONAR_SERVER_CAN_NOT_BE_REACHED + ", trying cache", serverUrl));
-
+  private String getFromCache(String fullUrl) {
     try {
-      String cached = wsCache.getString(fullUrl);
-      if (cached != null) {
-        return cached;
-      }
-      logger.error(MessageFormat.format(SONAR_SERVER_CAN_NOT_BE_REACHED + " and data is not cached", serverUrl));
-      throw originalException;
+      return wsCache.getString(fullUrl);
     } catch (IOException e) {
       throw new IllegalStateException("Failed to access cache", e);
     }
-
   }
 
   private HttpRequest newHttpRequest(URL url) {
index aac6b25b88ca0f68f8bbc4671a7d99be2eb92f61..8a83a3eb54872d0f810939ca1166de1e23fa7654 100644 (file)
@@ -43,7 +43,7 @@ public class SimulatedLauncher implements IsolatedLauncher {
   }
 
   @Override
-  public void start(Properties properties, LogOutput logOutput, boolean forceSync) {
+  public void start(Properties properties, LogOutput logOutput, boolean preferCache) {
     globalProperties = properties;
   }
 
index e9d4535a14c883eb8337d046e98a06e98fe6e185..dd80b0755b7cfbf90d1671e0f86ccd86bf5a8bce 100644 (file)
@@ -38,6 +38,8 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.Properties;
 
+import static org.mockito.Matchers.anyBoolean;
+
 import static org.fest.assertions.Assertions.assertThat;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.argThat;
@@ -68,7 +70,7 @@ public class EmbeddedRunnerTest {
     batchLauncher = mock(IsolatedLauncherFactory.class);
     launcher = mock(IsolatedLauncher.class);
     when(launcher.getVersion()).thenReturn("5.2");
-    when(batchLauncher.createLauncher(any(Properties.class), any(ClassloadRules.class))).thenReturn(launcher);
+    when(batchLauncher.createLauncher(any(Properties.class), any(ClassloadRules.class), anyBoolean())).thenReturn(launcher);
     runner = new EmbeddedRunner(batchLauncher, mock(Logger.class), mock(LogOutput.class));
   }
 
@@ -130,7 +132,7 @@ public class EmbeddedRunnerTest {
       public boolean matches(Object o) {
         return "foo".equals(((Properties) o).getProperty("sonar.projectKey"));
       }
-    }), any(ClassloadRules.class));
+    }), any(ClassloadRules.class), anyBoolean());
 
     // it should have added a few properties to analysisProperties, and have merged global props
     final String[] mustHaveKeys = {"sonar.working.directory", "sonar.sourceEncoding", "sonar.projectBaseDir",
@@ -179,7 +181,7 @@ public class EmbeddedRunnerTest {
       public boolean matches(Object o) {
         return "foo".equals(((Properties) o).getProperty("sonar.projectKey"));
       }
-    }), any(ClassloadRules.class));
+    }), any(ClassloadRules.class), anyBoolean());
 
     // it should have added a few properties to analysisProperties
     final String[] mustHaveKeys = {"sonar.working.directory", "sonar.sourceEncoding", "sonar.projectBaseDir"};
@@ -247,7 +249,7 @@ public class EmbeddedRunnerTest {
       public boolean matches(Object o) {
         return "foo".equals(((Properties) o).getProperty("sonar.projectKey"));
       }
-    }), any(ClassloadRules.class));
+    }), any(ClassloadRules.class), anyBoolean());
 
     verify(launcher).execute(argThat(new ArgumentMatcher<Properties>() {
       @Override
index fa71aceee35fb0ea1d0908481e25df272beaf7e9..2e419945631d1d523f1dcafaaaf3ab603562be1b 100644 (file)
@@ -62,7 +62,7 @@ public class IsolatedLauncherFactoryTest {
     public static IssueListener listener = null;
 
     @Override
-    public void start(Properties properties, LogOutput logger, boolean forceSync) {
+    public void start(Properties properties, LogOutput logger, boolean preferCache) {
     }
 
     @Override
index 762473c6289eecd9f78b2f2ce3de58e2e841c4c7..5b73883de2a28131d009381f7e29fc59f6aaec42 100644 (file)
@@ -53,7 +53,7 @@ public class JarsTest {
     File batchJar = temp.newFile("sonar-runner-batch.jar");
     when(jarExtractor.extractToTemp("sonar-runner-batch")).thenReturn(batchJar);
     // index of the files to download
-    when(connection.downloadStringCache("/batch_bootstrap/index")).thenReturn(
+    when(connection.loadString("/batch_bootstrap/index")).thenReturn(
       "cpd.jar|CA124VADFSDS\n" +
         "squid.jar|34535FSFSDF\n");
 
@@ -61,7 +61,7 @@ public class JarsTest {
     List<File> files = jars35.download();
 
     assertThat(files).isNotNull();
-    verify(connection, times(1)).downloadStringCache("/batch_bootstrap/index");
+    verify(connection, times(1)).loadString("/batch_bootstrap/index");
     verifyNoMoreInteractions(connection);
     verify(fileCache, times(1)).get(eq("cpd.jar"), eq("CA124VADFSDS"), any(FileCache.Downloader.class));
     verify(fileCache, times(1)).get(eq("squid.jar"), eq("34535FSFSDF"), any(FileCache.Downloader.class));
@@ -82,7 +82,7 @@ public class JarsTest {
     File batchJar = temp.newFile("sonar-runner-batch.jar");
     when(jarExtractor.extractToTemp("sonar-runner-batch")).thenReturn(batchJar);
     // index of the files to download
-    when(connection.downloadStringCache("/batch_bootstrap/index")).thenThrow(new IllegalStateException());
+    when(connection.loadString("/batch_bootstrap/index")).thenThrow(new IllegalStateException());
 
     Jars jars35 = new Jars(fileCache, connection, jarExtractor, mock(Logger.class));
     try {
index 46d8ab75f95d0012bdf161226c7524ca1c829a2d..021836b6adcfb7356a07476449d714f842d4530c 100644 (file)
@@ -69,8 +69,8 @@ public class ServerConnectionTest {
   public void continue_if_cache_put_fails() throws Exception {
     cache = mock(PersistentCache.class);
     doThrow(IOException.class).when(cache).put(anyString(), any(byte[].class));
-    ServerConnection connection = createSimpleServerConnection(httpServer.url(), null, true);
-    String response = connection.downloadStringCache("/batch/index.txt");
+    ServerConnection connection = createSimpleServerConnection(httpServer.url(), null, true, false);
+    String response = connection.loadString("/batch/index.txt");
 
     assertThat(response).isEqualTo("abcde");
     verify(logger).warn(startsWith("Failed to cache WS call:"));
@@ -79,10 +79,54 @@ public class ServerConnectionTest {
   @Test
   public void should_download_to_string() throws Exception {
     ServerConnection connection = createSimpleServerConnection(httpServer.url(), null);
-    String response = connection.downloadStringCache("/batch/index.txt");
+    String response = connection.loadString("/batch/index.txt");
 
     assertThat(response).isEqualTo("abcde");
   }
+  
+  @Test
+  public void test_prefer_cache() throws IOException {
+    File cacheDir = cache.getDirectory().toFile();
+
+    ServerConnection connection = createSimpleServerConnection(httpServer.url() + "/", null, true, true);
+
+    //not cached
+    assertThat(cacheDir.list().length).isEqualTo(0);
+    String str = connection.loadString("/batch/index.txt");
+
+    //cached
+    assertThat(str).isEqualTo("abcde");
+    assertThat(cacheDir.list().length).isEqualTo(1);
+
+    httpServer.setMockResponseData("request2");
+    //got response in cached
+    str = connection.loadString("/batch/index.txt");
+    assertThat(str).isEqualTo("abcde");
+  }
+  
+  @Test
+  public void test_dont_prefer_cache() throws IOException {
+    File cacheDir = cache.getDirectory().toFile();
+
+    ServerConnection connection = createSimpleServerConnection(httpServer.url() + "/", null, true, false);
+
+    //not cached
+    assertThat(cacheDir.list().length).isEqualTo(0);
+    String str = connection.loadString("/batch/index.txt");
+
+    //cached
+    assertThat(str).isEqualTo("abcde");
+    assertThat(cacheDir.list().length).isEqualTo(1);
+
+    httpServer.setMockResponseData("request2");
+    //got response in cached
+    str = connection.loadString("/batch/index.txt");
+    assertThat(str).isEqualTo("request2");
+    
+    httpServer.after();
+    str = connection.loadString("/batch/index.txt");
+    assertThat(str).isEqualTo("request2");
+  }
 
   @Test
   public void should_download_to_file() throws Exception {
@@ -94,12 +138,13 @@ public class ServerConnectionTest {
   }
 
   @Test
-  public void should_throw_original_exception_fallback() throws IOException {
+  public void should_throw_connection_exception_fallback_to_cache() throws IOException {
     cache = mock(PersistentCache.class);
-    ServerConnection connection = createSimpleServerConnection("http://localhost", NetworkUtil.getNextAvailablePort(), true);
+    ServerConnection connection = createSimpleServerConnection("http://localhost", NetworkUtil.getNextAvailablePort(),
+      true, false);
 
     try {
-      connection.downloadStringCache("/batch/index.txt");
+      connection.loadString("/batch/index.txt");
       fail();
     } catch (HttpRequest.HttpRequestException e) {
       verify(cache).getString(anyString());
@@ -111,32 +156,32 @@ public class ServerConnectionTest {
   public void should_cache_jar_list() throws Exception {
     File cacheDir = cache.getDirectory().toFile();
 
-    ServerConnection connection = createSimpleServerConnection(httpServer.url() + "/", null, true);
+    ServerConnection connection = createSimpleServerConnection(httpServer.url() + "/", null, true, false);
 
     assertThat(cacheDir.list().length).isEqualTo(0);
-    String str = connection.downloadStringCache("/batch/index.txt");
+    String str = connection.loadString("/batch/index.txt");
 
     assertThat(str).isEqualTo("abcde");
     assertThat(cacheDir.list().length).isEqualTo(1);
 
     httpServer.after();
-    str = connection.downloadStringCache("/batch/index.txt");
+    str = connection.loadString("/batch/index.txt");
     assertThat(str).isEqualTo("abcde");
   }
 
   @Test
-  public void should_throw_connection_exception_() throws IOException {
+  public void should_throw_connection_exception() throws IOException {
     File cacheDir = cache.getDirectory().toFile();
     ServerConnection connection = createSimpleServerConnection(httpServer.url() + "/", null);
 
     assertThat(cacheDir.list().length).isEqualTo(0);
-    String str = connection.downloadStringCache("/batch/index.txt");
+    String str = connection.loadString("/batch/index.txt");
     assertThat(str).isEqualTo("abcde");
 
     httpServer.after();
 
     try {
-      connection.downloadStringCache("/batch/index.txt");
+      connection.loadString("/batch/index.txt");
       fail("exception expected");
     } catch (HttpRequest.HttpRequestException e) {
       // expected
@@ -154,13 +199,13 @@ public class ServerConnectionTest {
     ServerConnection connection = createSimpleServerConnection(httpServer.url() + "/", null);
 
     assertThat(cacheDir.list().length).isEqualTo(0);
-    String str = connection.downloadStringCache("/batch/index.txt");
+    String str = connection.loadString("/batch/index.txt");
 
     assertThat(str).isEqualTo("abcde");
     assertThat(cacheDir.list().length).isEqualTo(0);
 
     httpServer.setMockResponseData("request2");
-    str = connection.downloadStringCache("/batch/index.txt");
+    str = connection.loadString("/batch/index.txt");
     assertThat(str).isEqualTo("request2");
   }
 
@@ -192,7 +237,7 @@ public class ServerConnectionTest {
     ServerConnection connection = createSimpleServerConnection("http://localhost", NetworkUtil.getNextAvailablePort());
 
     try {
-      connection.downloadStringCache("/batch/index.txt");
+      connection.loadString("/batch/index.txt");
       fail();
     } catch (Exception e) {
       // success
@@ -200,10 +245,10 @@ public class ServerConnectionTest {
   }
 
   private ServerConnection createSimpleServerConnection(String url, Integer port) {
-    return createSimpleServerConnection(url, port, false);
+    return createSimpleServerConnection(url, port, false, false);
   }
 
-  private ServerConnection createSimpleServerConnection(String url, Integer port, boolean issuesMode) {
+  private ServerConnection createSimpleServerConnection(String url, Integer port, boolean issuesMode, boolean preferCache) {
     httpServer.setMockResponseData("abcde");
     String fullUrl = port == null ? url : url + ":" + port;
     Properties props = new Properties();
@@ -211,6 +256,6 @@ public class ServerConnectionTest {
     if (issuesMode) {
       props.setProperty("sonar.analysis.mode", "issues");
     }
-    return ServerConnection.create(props, cache, logger);
+    return ServerConnection.create(props, cache, logger, preferCache);
   }
 }
index 7b2fffcbe09e13d4e493a1436141922cc6d5c6f4..180710cf6d1d240b3fe7c90a44c74b43657f047c 100644 (file)
@@ -24,7 +24,7 @@ import java.util.Properties;
 
 public interface IsolatedLauncher {
 
-  void start(Properties properties, LogOutput logOutput, boolean forceSync);
+  void start(Properties properties, LogOutput logOutput, boolean preferCache);
 
   void stop();
 
index 0cc79b73c2e6a789c93c715501c0ffda72901af4..b7a49f3938279a3a08ab89c64ca427e2f3afead8 100644 (file)
@@ -40,9 +40,9 @@ public class BatchIsolatedLauncher implements IsolatedLauncher {
   private Batch batch = null;
 
   @Override
-  public void start(Properties globalProperties, org.sonar.runner.batch.LogOutput logOutput, boolean forceSync) {
+  public void start(Properties globalProperties, org.sonar.runner.batch.LogOutput logOutput, boolean preferCache) {
     batch = createBatch(globalProperties, logOutput, null);
-    batch.start(forceSync);
+    batch.start(preferCache);
   }
 
   @Override