]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6649 Move initialization of persistit cache to global context
authorDuarte Meneses <duarte.meneses@sonarsource.com>
Thu, 18 Jun 2015 13:23:54 +0000 (15:23 +0200)
committerDuarte Meneses <duarte.meneses@sonarsource.com>
Wed, 24 Jun 2015 12:34:21 +0000 (14:34 +0200)
25 files changed:
pom.xml
sonar-batch/pom.xml
sonar-batch/src/main/java/org/sonar/batch/bootstrap/GlobalContainer.java
sonar-batch/src/main/java/org/sonar/batch/bootstrap/LifecycleProviderAdapter.java [new file with mode: 0644]
sonar-batch/src/main/java/org/sonar/batch/bootstrap/PersistentCacheProvider.java
sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectTempFolderProvider.java
sonar-batch/src/main/java/org/sonar/batch/bootstrap/TempFolderProvider.java
sonar-batch/src/main/java/org/sonar/batch/bootstrapper/LogCallbackAppender.java
sonar-batch/src/main/java/org/sonar/batch/index/Caches.java
sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java
sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
sonar-batch/src/test/java/org/sonar/batch/bootstrap/LifecycleProviderAdapterTest.java [new file with mode: 0644]
sonar-batch/src/test/java/org/sonar/batch/bootstrap/PersistentCacheProviderTest.java
sonar-batch/src/test/java/org/sonar/batch/bootstrap/ProjectTempFolderProviderTest.java
sonar-batch/src/test/java/org/sonar/batch/bootstrap/TempFolderProviderTest.java
sonar-batch/src/test/java/org/sonar/batch/bootstrapper/LogCallbackAppenderTest.java [new file with mode: 0644]
sonar-batch/src/test/java/org/sonar/batch/bootstrapper/PrintStreamTest.java [deleted file]
sonar-batch/src/test/java/org/sonar/batch/index/CachesTest.java
sonar-batch/src/test/java/org/sonar/batch/mediumtest/log/LogListenerTest.java [new file with mode: 0644]
sonar-home/src/main/java/org/sonar/home/cache/PersistentCache.java
sonar-home/src/main/java/org/sonar/home/cache/PersistentCacheBuilder.java
sonar-home/src/test/java/org/sonar/home/cache/PersistentCacheTest.java
sonar-plugin-api/src/main/java/org/sonar/api/utils/internal/DefaultTempFolder.java
sonar-plugin-api/src/main/java/org/sonar/api/utils/internal/JUnitTempFolder.java
sonar-plugin-api/src/main/java/org/sonar/api/utils/internal/TempFolderCleaner.java

diff --git a/pom.xml b/pom.xml
index eae7b1b6c72710ac24515c486223878d9b7985d6..f1421deae85d1e9093d73c02a3210427db1fccdf 100644 (file)
--- a/pom.xml
+++ b/pom.xml
         <version>2.3.1</version>
       </dependency>
       <dependency>
-        <groupId>org.codehaus.sonar</groupId>
+        <groupId>org.sonarsource</groupId>
         <artifactId>sonar-persistit</artifactId>
-        <version>3.3.2-SNAPSHOT</version>
+        <version>3.3.2</version>
         <exclusions>
           <exclusion>
             <groupId>commons-logging</groupId>
index c1b2b197c325dc5056db0c83b4d7e86fae910d5b..db21e928a977c85c11d3a90a8bc8749e0ce5a743 100644 (file)
@@ -25,7 +25,7 @@
       <scope>provided</scope>
     </dependency>
     <dependency>
-      <groupId>org.codehaus.sonar</groupId>
+      <groupId>org.sonarsource</groupId>
       <artifactId>sonar-persistit</artifactId>
     </dependency>
     <dependency>
index 08d9cbb9a7c398ddad2e2e524f482c902e9c560b..94d6effc42dc781de1f71df7ca7c51766defb4eb 100644 (file)
@@ -29,7 +29,6 @@ import org.sonar.api.Plugin;
 import org.sonar.api.utils.Durations;
 import org.sonar.api.utils.System2;
 import org.sonar.api.utils.UriReader;
-import org.sonar.api.utils.internal.TempFolderCleaner;
 import org.sonar.batch.components.PastSnapshotFinder;
 import org.sonar.batch.deprecated.components.PastSnapshotFinderByDate;
 import org.sonar.batch.deprecated.components.PastSnapshotFinderByDays;
@@ -67,13 +66,14 @@ import org.sonar.jpa.session.JpaDatabaseSession;
 public class GlobalContainer extends ComponentContainer {
 
   private final Map<String, String> bootstrapProperties;
+  private PersistentCacheProvider persistentCacheProvider;
 
   private GlobalContainer(Map<String, String> bootstrapProperties) {
     super();
     this.bootstrapProperties = bootstrapProperties;
   }
 
-  public static GlobalContainer create(Map<String, String> bootstrapProperties, List extensions) {
+  public static GlobalContainer create(Map<String, String> bootstrapProperties, List<?> extensions) {
     GlobalContainer container = new GlobalContainer(bootstrapProperties);
     container.add(extensions);
     return container;
@@ -92,6 +92,8 @@ public class GlobalContainer extends ComponentContainer {
   }
 
   private void addBootstrapComponents() {
+    persistentCacheProvider = new PersistentCacheProvider();
+
     add(
       // plugins
       BatchPluginRepository.class,
@@ -107,11 +109,10 @@ public class GlobalContainer extends ComponentContainer {
       Logback.class,
       DefaultServer.class,
       new TempFolderProvider(),
-      TempFolderCleaner.class,
       DefaultHttpDownloader.class,
       UriReader.class,
       new FileCacheProvider(),
-      new PersistentCacheProvider(),
+      persistentCacheProvider,
       System2.INSTANCE,
       DefaultI18n.class,
       Durations.class,
@@ -124,7 +125,7 @@ public class GlobalContainer extends ComponentContainer {
     addIfMissing(DefaultServerLineHashesLoader.class, ServerLineHashesLoader.class);
   }
 
-  public void addIfMissing(Object object, Class objectType) {
+  public void addIfMissing(Object object, Class<?> objectType) {
     if (getComponentByType(objectType) == null) {
       add(object);
     }
@@ -166,7 +167,7 @@ public class GlobalContainer extends ComponentContainer {
 
   public void executeAnalysis(Map<String, String> analysisProperties, Object... components) {
     AnalysisProperties props = new AnalysisProperties(analysisProperties, this.getComponentByType(BootstrapProperties.class).property(CoreProperties.ENCRYPTION_SECRET_KEY_PATH));
+    persistentCacheProvider.reconfigure(props);
     new ProjectScanContainer(this, props, components).execute();
   }
-
 }
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/LifecycleProviderAdapter.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/LifecycleProviderAdapter.java
new file mode 100644 (file)
index 0000000..009aada
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.batch.bootstrap;
+
+import org.picocontainer.lifecycle.ReflectionLifecycleStrategy;
+import org.picocontainer.monitors.NullComponentMonitor;
+
+import org.picocontainer.LifecycleStrategy;
+import org.picocontainer.PicoContainer;
+import org.picocontainer.ComponentLifecycle;
+import org.picocontainer.injectors.ProviderAdapter;
+import org.picocontainer.Startable;
+
+public abstract class LifecycleProviderAdapter extends ProviderAdapter implements Startable, ComponentLifecycle<Object> {
+  private LifecycleStrategy lifecycleStrategy;
+  protected Object instance;
+
+  public LifecycleProviderAdapter() {
+    this(new ReflectionLifecycleStrategy(new NullComponentMonitor()));
+  }
+
+  public LifecycleProviderAdapter(LifecycleStrategy lifecycleStrategy) {
+    this.lifecycleStrategy = lifecycleStrategy;
+  }
+
+  @Override
+  public final void start() {
+    if (instance != null) {
+      lifecycleStrategy.start(instance);
+    }
+  }
+
+  @Override
+  public final void stop() {
+    if (instance != null) {
+      lifecycleStrategy.stop(instance);
+    }
+  }
+
+  @Override
+  public void start(PicoContainer container) {
+    start();
+    started = true;
+  }
+
+  @Override
+  public void stop(PicoContainer container) {
+    stop();
+    started = false;
+  }
+
+  @Override
+  public void dispose(PicoContainer container) {
+  }
+
+  @Override
+  public boolean componentHasLifecycle() {
+    return true;
+  }
+
+  @Override
+  public boolean isStarted() {
+    return started;
+  }
+
+  private boolean started = false;
+
+}
index 9ca57407d6ce4a6da9405a10e97c1b9d8fa173cf..6821333b27f56e390f61373bee57d9735a30d63b 100644 (file)
 package org.sonar.batch.bootstrap;
 
 import org.sonar.home.log.Slf4jLog;
-
 import org.sonar.home.cache.PersistentCacheBuilder;
 import org.picocontainer.injectors.ProviderAdapter;
 
 import java.nio.file.Paths;
+import java.util.Map;
 
 import org.sonar.home.cache.PersistentCache;
 
 public class PersistentCacheProvider extends ProviderAdapter {
   private PersistentCache cache;
 
-  public PersistentCache provide(BootstrapProperties props) {
+  public PersistentCache provide(UserProperties props) {
     if (cache == null) {
       PersistentCacheBuilder builder = new PersistentCacheBuilder();
 
       builder.setLog(new Slf4jLog(PersistentCache.class));
-      String enableCache = props.property("sonar.enableHttpCache");
-
-      if (!"true".equals(enableCache)) {
-        builder.forceUpdate(true);
-      }
+      builder.forceUpdate(isForceUpdate(props.properties()));
 
       String home = props.property("sonar.userHome");
       if (home != null) {
@@ -51,4 +47,15 @@ public class PersistentCacheProvider extends ProviderAdapter {
     }
     return cache;
   }
+
+  public void reconfigure(UserProperties props) {
+    if (cache != null) {
+      cache.reconfigure(isForceUpdate(props.properties()));
+    }
+  }
+
+  private static boolean isForceUpdate(Map<String, String> props) {
+    String enableCache = props.get("sonar.enableHttpCache");
+    return !"true".equals(enableCache);
+  }
 }
index e83013371ad81e059ca0fb9ae60d3aee6daba0d7..bcaf8ec866672198d80e85654ff7c03db8819d6e 100644 (file)
  */
 package org.sonar.batch.bootstrap;
 
-import org.sonar.api.utils.ProjectTempFolder;
-
-import org.apache.commons.io.FileUtils;
+import org.sonar.api.utils.TempFolder;
 import org.apache.commons.lang.StringUtils;
-import org.picocontainer.injectors.ProviderAdapter;
 import org.sonar.api.CoreProperties;
 import org.sonar.api.utils.internal.DefaultTempFolder;
 
-import java.io.File;
 import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 
-public class ProjectTempFolderProvider extends ProviderAdapter {
+public class ProjectTempFolderProvider extends LifecycleProviderAdapter {
   static final String TMP_NAME = ".sonartmp";
-  private ProjectTempFolder projectTempFolder;
+  private DefaultTempFolder projectTempFolder;
 
-  public ProjectTempFolder provide(BootstrapProperties bootstrapProps) {
+  public TempFolder provide(BootstrapProperties bootstrapProps) {
     if (projectTempFolder == null) {
       String workingDirPath = StringUtils.defaultIfBlank(bootstrapProps.property(CoreProperties.WORKING_DIRECTORY), CoreProperties.WORKING_DIRECTORY_DEFAULT_VALUE);
-      File workingDir = new File(workingDirPath).getAbsoluteFile();
-      File tempDir = new File(workingDir, TMP_NAME);
+      Path workingDir = Paths.get(workingDirPath);
+      Path tempDir = workingDir.resolve(TMP_NAME).normalize();
       try {
-        FileUtils.forceMkdir(tempDir);
+        Files.createDirectories(tempDir);
       } catch (IOException e) {
         throw new IllegalStateException("Unable to create root temp directory " + tempDir, e);
       }
-      projectTempFolder = new DefaultTempFolder(tempDir, true);
+      projectTempFolder = new DefaultTempFolder(tempDir.toFile(), true);
+      this.instance = projectTempFolder;
     }
     return projectTempFolder;
   }
-
 }
index 971a4a2b1f59828e0a29ea7bda507710afdb2ac1..b1ee968f3449329862ddd9d2c3fe93c9b5142012 100644 (file)
  */
 package org.sonar.batch.bootstrap;
 
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+import org.apache.commons.io.FileUtils;
 import org.sonar.api.utils.TempFolder;
-import org.picocontainer.injectors.ProviderAdapter;
 import org.apache.commons.lang.StringUtils;
 import org.sonar.api.CoreProperties;
 import org.sonar.api.utils.internal.DefaultTempFolder;
 
 import java.io.IOException;
+import java.nio.file.DirectoryStream;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.concurrent.TimeUnit;
 
-public class TempFolderProvider extends ProviderAdapter {
-  static final String TMP_NAME = ".sonartmp";
-  private TempFolder tempFolder;
+public class TempFolderProvider extends LifecycleProviderAdapter {
+  private static final Logger LOG = Loggers.get(TempFolderProvider.class);
+  private static final long CLEAN_MAX_AGE = TimeUnit.DAYS.toMillis(21);
+  static final String TMP_NAME_PREFIX = ".sonartmp_";
+
+  private DefaultTempFolder tempFolder;
 
   public TempFolder provide(BootstrapProperties bootstrapProps) {
     if (tempFolder == null) {
@@ -45,13 +53,20 @@ public class TempFolderProvider extends ProviderAdapter {
         workingPath = home.resolve(workingPath).normalize();
       }
 
-      Path tempDir = workingPath.resolve(TMP_NAME);
+      try {
+        cleanTempFolders(workingPath);
+      } catch (IOException e) {
+        LOG.warn("failed to clean global working directory: " + e.getMessage());
+      }
+
+      Path tempDir = workingPath.resolve(TMP_NAME_PREFIX + System.currentTimeMillis());
       try {
         Files.createDirectories(tempDir);
       } catch (IOException e) {
         throw new IllegalStateException("Unable to create root temp directory " + tempDir, e);
       }
       tempFolder = new DefaultTempFolder(tempDir.toFile(), true);
+      this.instance = tempFolder;
     }
     return tempFolder;
   }
@@ -72,4 +87,41 @@ public class TempFolderProvider extends ProviderAdapter {
     return Paths.get(home, ".sonar");
   }
 
+  private static void cleanTempFolders(Path path) throws IOException {
+    if (Files.exists(path)) {
+      try (DirectoryStream<Path> stream = Files.newDirectoryStream(path, new CleanFilter())) {
+        for (Path p : stream) {
+          FileUtils.deleteQuietly(p.toFile());
+        }
+      }
+    }
+  }
+
+  private static class CleanFilter implements DirectoryStream.Filter<Path> {
+    @Override
+    public boolean accept(Path e) throws IOException {
+      if (!Files.isDirectory(e)) {
+        return false;
+      }
+
+      if (!e.getFileName().toString().startsWith(TMP_NAME_PREFIX)) {
+        return false;
+      }
+
+      long threshold = System.currentTimeMillis() - CLEAN_MAX_AGE;
+
+      // we could also check the timestamp in the name, instead
+      BasicFileAttributes attrs;
+
+      try {
+        attrs = Files.readAttributes(e, BasicFileAttributes.class);
+      } catch (IOException ioe) {
+        LOG.warn("couldn't read file attributes for " + e + " : " + ioe.getMessage());
+        return false;
+      }
+
+      long creationTime = attrs.creationTime().toMillis();
+      return creationTime < threshold;
+    }
+  }
 }
index 6c216410d13a0f5028d8f28cc252d916ce0ac222..73730de7df5311d477b36d9dcc41fb17b9936ea8 100644 (file)
@@ -38,11 +38,11 @@ public class LogCallbackAppender extends UnsynchronizedAppenderBase<ILoggingEven
 
   @Override
   protected void append(ILoggingEvent event) {
-    target.log(event.getFormattedMessage(), translate(event.getLevel()));
+    target.log(event.getMessage(), translate(event.getLevel()));
   }
-  
-  private LogListener.Level translate(Level level) {
-    switch(level.toInt()) {
+
+  private static LogListener.Level translate(Level level) {
+    switch (level.toInt()) {
       case Level.ERROR_INT:
         return LogListener.Level.ERROR;
       case Level.WARN_INT:
index 209ec7792aa36732e6f8bb4f650b14567b524b75..4f0bf3426932118a23b4f21e96e8fd87d588babe 100644 (file)
@@ -37,17 +37,21 @@ import org.sonar.api.batch.BatchSide;
 
 @BatchSide
 public class Caches implements Startable {
-  private final Map<String, Exchange> caches = Maps.newHashMap();
+  private final Map<String, Exchange> cacheMap = Maps.newHashMap();
   private Persistit persistit;
   private Volume volume;
 
   public Caches(CachesManager caches) {
     persistit = caches.persistit();
-    start();
+    doStart();
   }
 
   @Override
   public void start() {
+    // done in constructor
+  }
+
+  private void doStart() {
     try {
       persistit.flush();
       volume = persistit.createTemporaryVolume();
@@ -63,12 +67,12 @@ public class Caches implements Startable {
 
   public <V> Cache<V> createCache(String cacheName) {
     Preconditions.checkState(volume != null && volume.isOpened(), "Caches are not initialized");
-    Preconditions.checkState(!caches.containsKey(cacheName), "Cache is already created: " + cacheName);
+    Preconditions.checkState(!cacheMap.containsKey(cacheName), "Cache is already created: " + cacheName);
     try {
       Exchange exchange = persistit.getExchange(volume, cacheName, true);
       exchange.setMaximumValueSize(Value.MAXIMUM_SIZE);
       Cache<V> cache = new Cache<>(cacheName, exchange);
-      caches.put(cacheName, exchange);
+      cacheMap.put(cacheName, exchange);
       return cache;
     } catch (Exception e) {
       throw new IllegalStateException("Fail to create cache: " + cacheName, e);
@@ -77,11 +81,11 @@ public class Caches implements Startable {
 
   @Override
   public void stop() {
-    for (Entry<String, Exchange> e : caches.entrySet()) {
+    for (Entry<String, Exchange> e : cacheMap.entrySet()) {
       persistit.releaseExchange(e.getValue());
     }
 
-    caches.clear();
+    cacheMap.clear();
 
     if (volume != null) {
       try {
index 8e38c2031fe1768e18a64a4982c651b4d757975f..ab769822948816d03cbc4f63ac747d3890942641 100644 (file)
@@ -19,6 +19,8 @@
  */
 package org.sonar.batch.mediumtest;
 
+import org.sonar.home.log.LogListener;
+
 import com.google.common.base.Function;
 import com.google.common.io.Files;
 import org.sonar.api.CoreProperties;
@@ -78,10 +80,16 @@ public class BatchMediumTester {
     private final FakeServerIssuesLoader serverIssues = new FakeServerIssuesLoader();
     private final FakeServerLineHashesLoader serverLineHashes = new FakeServerLineHashesLoader();
     private final Map<String, String> bootstrapProperties = new HashMap<>();
+    private LogListener logListener = null; 
 
     public BatchMediumTester build() {
       return new BatchMediumTester(this);
     }
+    
+    public BatchMediumTesterBuilder setLogListener(LogListener listener) {
+      this.logListener = listener;
+      return this;
+    }
 
     public BatchMediumTesterBuilder registerPlugin(String pluginKey, File location) {
       pluginInstaller.add(pluginKey, location);
@@ -167,6 +175,7 @@ public class BatchMediumTester {
         builder.serverLineHashes,
         new DefaultDebtModel())
       .setBootstrapProperties(builder.bootstrapProperties)
+      .setLogListener(builder.logListener)
       .build();
   }
 
index 623fd0fa90ee166b406c893af4e36c4bf30e44cd..1c3e864170dfcdd52363f38a3ea1ed596017e299 100644 (file)
@@ -21,8 +21,6 @@ package org.sonar.batch.scan;
 
 import org.sonar.batch.bootstrap.ProjectTempFolderProvider;
 
-import org.sonar.api.utils.internal.TempFolderCleaner;
-import org.sonar.batch.bootstrap.TempFolderProvider;
 import com.google.common.annotations.VisibleForTesting;
 import org.sonar.api.CoreProperties;
 import org.sonar.api.batch.InstantiationStrategy;
@@ -155,9 +153,9 @@ public class ProjectScanContainer extends ComponentContainer {
       Caches.class,
       BatchComponentCache.class,
 
-      //temp
+      // temp
       new ProjectTempFolderProvider(),
-      
+
       // file system
       InputPathCache.class,
       PathResolver.class,
diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/LifecycleProviderAdapterTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/LifecycleProviderAdapterTest.java
new file mode 100644 (file)
index 0000000..5c3bb85
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.batch.bootstrap;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.Before;
+import org.picocontainer.Startable;
+import org.junit.Test;
+
+public class LifecycleProviderAdapterTest {
+  private DummyProvider provider;
+
+  @Before
+  public void setUp() {
+    provider = new DummyProvider();
+    provider.provide();
+  }
+
+  @Test
+  public void testStart() {
+    // ComponentLifecycle's start gets called on the provider
+    provider.start(null);
+    assertThat(provider.inst.started).isEqualTo(true);
+    assertThat(provider.isStarted()).isEqualTo(true);
+    assertThat(provider.inst.stopped).isEqualTo(false);
+  }
+
+  @Test
+  public void testSop() {
+    // ComponentLifecycle's stop gets called on the provider
+    provider.stop(null);
+    assertThat(provider.inst.stopped).isEqualTo(true);
+    assertThat(provider.isStarted()).isEqualTo(false);
+    assertThat(provider.inst.started).isEqualTo(false);
+  }
+
+  public class DummyProvided implements Startable {
+    boolean started = false;
+    boolean stopped = false;
+
+    @Override
+    public void start() {
+      started = true;
+    }
+
+    @Override
+    public void stop() {
+      stopped = true;
+    }
+  }
+
+  public class DummyProvider extends LifecycleProviderAdapter {
+    DummyProvided inst;
+
+    public DummyProvided provide() {
+      inst = new DummyProvided();
+      super.instance = inst;
+      return inst;
+    }
+  }
+}
index 5b6db572df54b35d7575c2539de8340939a1e3d9..24bdf6047d57b68710e6e89f04b2d014c3e15a0f 100644 (file)
  */
 package org.sonar.batch.bootstrap;
 
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.junit.Before;
-
-import static org.mockito.Mockito.when;
+import java.util.Collections;
 
+import org.junit.Before;
 import static org.assertj.core.api.Assertions.assertThat;
 import org.junit.Test;
 
 public class PersistentCacheProviderTest {
   private PersistentCacheProvider provider = null;
 
-  @Mock
   private BootstrapProperties props = null;
 
   @Before
   public void prepare() {
-    MockitoAnnotations.initMocks(this);
+    props = new BootstrapProperties(Collections.<String, String>emptyMap());
     provider = new PersistentCacheProvider();
   }
 
@@ -55,7 +51,7 @@ public class PersistentCacheProviderTest {
     // normally force update (cache disabled)
     assertThat(provider.provide(props).isForceUpdate()).isTrue();
 
-    when(props.property("sonar.enableHttpCache")).thenReturn("true");
+    props.properties().put("sonar.enableHttpCache", "true");
     provider = new PersistentCacheProvider();
     assertThat(provider.provide(props).isForceUpdate()).isFalse();
   }
index e79f05161599b85a0f2e226fcb70a61e34ee3f08..2b7a04352404a118ae6467ff40d2bcbeffb4179c 100644 (file)
@@ -19,9 +19,9 @@
  */
 package org.sonar.batch.bootstrap;
 
-import org.apache.commons.io.FileUtils;
+import org.sonar.api.utils.TempFolder;
 
-import org.sonar.api.utils.ProjectTempFolder;
+import org.apache.commons.io.FileUtils;
 import com.google.common.collect.ImmutableMap;
 import org.junit.Rule;
 import org.junit.Test;
@@ -46,7 +46,7 @@ public class ProjectTempFolderProviderTest {
     File workingDir = temp.newFolder();
     File tmpDir = new File(workingDir, ProjectTempFolderProvider.TMP_NAME);
 
-    ProjectTempFolder tempFolder = tempFolderProvider.provide(new BootstrapProperties(ImmutableMap.of(CoreProperties.WORKING_DIRECTORY, workingDir.getAbsolutePath())));
+    TempFolder tempFolder = tempFolderProvider.provide(new BootstrapProperties(ImmutableMap.of(CoreProperties.WORKING_DIRECTORY, workingDir.getAbsolutePath())));
     tempFolder.newDir();
     tempFolder.newFile();
     assertThat(tmpDir).exists();
@@ -58,7 +58,7 @@ public class ProjectTempFolderProviderTest {
     File defaultDir = new File(CoreProperties.WORKING_DIRECTORY_DEFAULT_VALUE, ProjectTempFolderProvider.TMP_NAME);
 
     try {
-      ProjectTempFolder tempFolder = tempFolderProvider.provide(new BootstrapProperties(Collections.<String, String>emptyMap()));
+      TempFolder tempFolder = tempFolderProvider.provide(new BootstrapProperties(Collections.<String, String>emptyMap()));
       tempFolder.newDir();
       tempFolder.newFile();
       assertThat(defaultDir).exists();
index ce64074d9a699d6af5a442ad5d2e35566bb37790..8c1e23b7b56866631daa4b2676c94b18523b3838 100644 (file)
@@ -25,7 +25,12 @@ import com.google.common.collect.ImmutableMap;
 import org.sonar.api.CoreProperties;
 
 import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.attribute.BasicFileAttributeView;
+import java.nio.file.attribute.FileTime;
 import java.util.Collections;
+import java.util.concurrent.TimeUnit;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import org.junit.Rule;
@@ -40,42 +45,72 @@ public class TempFolderProviderTest {
 
   @Test
   public void createTempFolderProps() throws Exception {
-    File workingDir = temp.newFolder();
+    File workingDir = temp.getRoot();
 
     TempFolder tempFolder = tempFolderProvider.provide(new BootstrapProperties(ImmutableMap.of(CoreProperties.GLOBAL_WORKING_DIRECTORY, workingDir.getAbsolutePath())));
     tempFolder.newDir();
     tempFolder.newFile();
-    assertThat(new File(workingDir, TempFolderProvider.TMP_NAME)).exists();
-    assertThat(new File(workingDir, ".sonartmp").list()).hasSize(2);
+    assertThat(getCreatedTempDir(workingDir)).exists();
+    assertThat(getCreatedTempDir(workingDir).list()).hasSize(2);
+  }
+
+  @Test
+  public void cleanUpOld() throws IOException {
+    long creationTime = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(100);
+    File workingDir = temp.getRoot();
+
+    for (int i = 0; i < 3; i++) {
+      File tmp = new File(workingDir, ".sonartmp_" + i);
+      tmp.mkdirs();
+      setFileCreationDate(tmp, creationTime);
+    }
+
+    tempFolderProvider.provide(new BootstrapProperties(ImmutableMap.of(CoreProperties.GLOBAL_WORKING_DIRECTORY, workingDir.getAbsolutePath())));
+    // this also checks that all other temps were deleted
+    assertThat(getCreatedTempDir(workingDir)).exists();
   }
 
   @Test
   public void createTempFolderSonarHome() throws Exception {
     // with sonar home, it will be in {sonar.home}/.sonartmp
-    File sonarHome = temp.newFolder();
-    File tmpDir = new File(new File(sonarHome, CoreProperties.GLOBAL_WORKING_DIRECTORY_DEFAULT_VALUE), TempFolderProvider.TMP_NAME);
+    File sonarHome = temp.getRoot();
+    File workingDir = new File(sonarHome, CoreProperties.GLOBAL_WORKING_DIRECTORY_DEFAULT_VALUE);
 
     TempFolder tempFolder = tempFolderProvider.provide(new BootstrapProperties(ImmutableMap.of("sonar.userHome", sonarHome.getAbsolutePath())));
     tempFolder.newDir();
     tempFolder.newFile();
-    assertThat(tmpDir).exists();
-    assertThat(tmpDir.list()).hasSize(2);
+    assertThat(getCreatedTempDir(workingDir)).exists();
+    assertThat(getCreatedTempDir(workingDir).list()).hasSize(2);
   }
 
   @Test
   public void createTempFolderDefault() throws Exception {
+    File userHome = temp.getRoot();
+    System.setProperty("user.home", userHome.getAbsolutePath());
+
     // if nothing is defined, it will be in {user.home}/.sonar/.sonartmp
     File defaultSonarHome = new File(System.getProperty("user.home"), ".sonar");
-    File tmpDir = new File(new File(defaultSonarHome, CoreProperties.GLOBAL_WORKING_DIRECTORY_DEFAULT_VALUE), TempFolderProvider.TMP_NAME);
+    File workingDir = new File(defaultSonarHome, CoreProperties.GLOBAL_WORKING_DIRECTORY_DEFAULT_VALUE).getAbsoluteFile();
 
     try {
       TempFolder tempFolder = tempFolderProvider.provide(new BootstrapProperties(Collections.<String, String>emptyMap()));
       tempFolder.newDir();
       tempFolder.newFile();
-      assertThat(tmpDir).exists();
-      assertThat(tmpDir.list()).hasSize(2);
+      assertThat(getCreatedTempDir(workingDir)).exists();
+      assertThat(getCreatedTempDir(workingDir).list()).hasSize(2);
     } finally {
-      FileUtils.deleteDirectory(tmpDir);
+      FileUtils.deleteDirectory(getCreatedTempDir(workingDir));
     }
   }
+
+  private File getCreatedTempDir(File workingDir) {
+    assertThat(workingDir.listFiles()).hasSize(1);
+    return workingDir.listFiles()[0];
+  }
+
+  private void setFileCreationDate(File f, long time) throws IOException {
+    BasicFileAttributeView attributes = Files.getFileAttributeView(f.toPath(), BasicFileAttributeView.class);
+    FileTime creationTime = FileTime.fromMillis(time);
+    attributes.setTimes(creationTime, creationTime, creationTime);
+  }
 }
diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrapper/LogCallbackAppenderTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrapper/LogCallbackAppenderTest.java
new file mode 100644 (file)
index 0000000..ea1fd3a
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.batch.bootstrapper;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import org.junit.Test;
+import org.sonar.home.log.LogListener;
+import org.junit.Before;
+
+public class LogCallbackAppenderTest {
+  private LogListener listener;
+  private LogCallbackAppender appender;
+  private ILoggingEvent event;
+
+  @Before
+  public void setUp() {
+    listener = mock(LogListener.class);
+    appender = new LogCallbackAppender(listener);
+    event = mock(ILoggingEvent.class);
+    when(event.getMessage()).thenReturn("test");
+    when(event.getLevel()).thenReturn(Level.INFO);
+  }
+
+  @Test
+  public void testAppendLog() {
+
+    appender.append(event);
+
+    verify(event).getMessage();
+    verify(event).getLevel();
+
+    verify(listener).log("test", LogListener.Level.INFO);
+
+    verifyNoMoreInteractions(event, listener);
+  }
+
+  @Test
+  public void testChangeTarget() {
+    listener = mock(LogListener.class);
+    appender.setTarget(listener);
+    testAppendLog();
+  }
+}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrapper/PrintStreamTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrapper/PrintStreamTest.java
deleted file mode 100644 (file)
index da833ea..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * SonarQube is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.batch.bootstrapper;
-
-import ch.qos.logback.core.encoder.EchoEncoder;
-import ch.qos.logback.classic.spi.ILoggingEvent;
-import org.mockito.Matchers;
-import ch.qos.logback.core.encoder.Encoder;
-import ch.qos.logback.core.Context;
-import org.junit.Test;
-import org.junit.Before;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.PrintStream;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-import static org.mockito.Mockito.when;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.mock;
-
-public class PrintStreamTest {
-  private static final String TEST_STR = "foo";
-
-  private ByteArrayOutputStream os;
-  private PrintStream stream;
-  private PrintStreamAppender<ILoggingEvent> appender;
-  private Context context = mock(Context.class);
-
-  private Encoder<ILoggingEvent> encoder = mock(Encoder.class);
-  private ILoggingEvent event = mock(ILoggingEvent.class);
-
-  @Before
-  public void setUp() {
-    os = new ByteArrayOutputStream();
-    stream = new PrintStream(os);
-
-    appender = new PrintStreamAppender<ILoggingEvent>(stream);
-    when(event.getMessage()).thenReturn(TEST_STR);
-    when(event.toString()).thenReturn(TEST_STR);
-  }
-
-  @Test
-  public void testNullStream() {
-    appender.setContext(mock(Context.class));
-    appender.setEncoder(encoder);
-    appender.setTarget(null);
-    appender.start();
-    appender.doAppend(event);
-
-    verifyNoMoreInteractions(encoder);
-  }
-
-  @Test
-  public void testEncoder() throws IOException {
-    appender.setContext(mock(Context.class));
-    appender.setEncoder(encoder);
-    appender.start();
-    appender.doAppend(event);
-
-    verify(encoder, times(1)).init(Matchers.notNull(OutputStream.class));
-    verify(encoder, times(1)).doEncode(event);
-
-  }
-
-  @Test
-  public void testWrite() {
-    encoder = new EchoEncoder<>();
-    encoder.setContext(context);
-    encoder.start();
-
-    appender.setContext(mock(Context.class));
-    appender.setEncoder(encoder);
-    appender.setTarget(stream);
-    appender.start();
-
-    appender.doAppend(event);
-
-    assertThat(os.toString()).isEqualTo(TEST_STR + System.lineSeparator());
-  }
-}
index 801d0f3d5ed3da2a3b621827a274e4f32bcab82a..411435aebec80152cfc4adf1e55c7029847f6b7e 100644 (file)
@@ -65,8 +65,6 @@ public class CachesTest extends AbstractCachesTest {
   public void leak_test() throws PersistitException {
     caches.stop();
 
-    System.out.println(cachesManager.tempDir());
-
     int len = 1 * 1024 * 1024;
     StringBuilder sb = new StringBuilder(len);
     for (int i = 0; i < len; i++) {
diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/log/LogListenerTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/log/LogListenerTest.java
new file mode 100644 (file)
index 0000000..c50f9e2
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.batch.mediumtest.log;
+
+import org.junit.BeforeClass;
+import org.junit.AfterClass;
+import org.sonar.home.log.LogListener;
+import org.sonar.home.log.LogListener.Level;
+import org.apache.commons.io.FileUtils;
+import org.junit.Test;
+import com.google.common.collect.ImmutableMap;
+import org.junit.After;
+import org.junit.Before;
+import org.sonar.batch.mediumtest.BatchMediumTester;
+import org.sonar.xoo.XooPlugin;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import org.junit.Rule;
+import org.junit.rules.ExpectedException;
+import org.junit.rules.TemporaryFolder;
+
+public class LogListenerTest {
+  @Rule
+  public TemporaryFolder temp = new TemporaryFolder();
+
+  @Rule
+  public ExpectedException thrown = ExpectedException.none();
+
+  private Pattern simpleTimePattern = Pattern.compile("\\d{2}:\\d{2}:\\d{2}");
+  private List<LogEvent> logOutput;
+  private ByteArrayOutputStream stdOutTarget = new ByteArrayOutputStream();
+  private ByteArrayOutputStream stdErrTarget = new ByteArrayOutputStream();
+  private static PrintStream savedStdOut;
+  private static PrintStream savedStdErr;
+
+  public BatchMediumTester tester = BatchMediumTester.builder()
+    .registerPlugin("xoo", new XooPlugin())
+    .addDefaultQProfile("xoo", "Sonar Way")
+    .setLogListener(new SimpleLogListener())
+    .build();
+
+  private File baseDir;
+
+  private ImmutableMap.Builder<String, String> builder;
+
+  @BeforeClass
+  public static void backupStdStreams() {
+    savedStdOut = System.out;
+    savedStdErr = System.err;
+  }
+
+  @AfterClass
+  public static void resumeStdStreams() {
+    if (savedStdOut != null) {
+      System.setOut(savedStdOut);
+    }
+    if (savedStdErr != null) {
+      System.setErr(savedStdErr);
+    }
+  }
+
+  @Before
+  public void prepare() throws IOException {
+    System.setOut(new PrintStream(stdOutTarget));
+    System.setErr(new PrintStream(stdErrTarget));
+    logOutput = new LinkedList<>();
+    tester.start();
+
+    baseDir = temp.newFolder();
+
+    builder = ImmutableMap.<String, String>builder()
+      .put("sonar.task", "scan")
+      .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+      .put("sonar.projectKey", "com.foo.project")
+      .put("sonar.projectName", "Foo Project")
+      .put("sonar.projectVersion", "1.0-SNAPSHOT")
+      .put("sonar.projectDescription", "Description of Foo Project");
+  }
+
+  private void assertNoStdOutput() {
+    assertThat(stdOutTarget.toByteArray()).isEmpty();
+    assertThat(stdErrTarget.toByteArray()).isEmpty();
+  }
+
+  /**
+   *   Check that log message is not formatted, i.e. has no log level and timestamp.
+   */
+  private void assertMsgClean(String msg) {
+    for (Level l : Level.values()) {
+      assertThat(msg).doesNotContain(l.toString());
+    }
+
+    Matcher matcher = simpleTimePattern.matcher(msg);
+    assertThat(matcher.find()).isFalse();
+  }
+
+  @After
+  public void stop() {
+    tester.stop();
+  }
+
+  @Test
+  public void testNoStdLog() throws IOException {
+    File srcDir = new File(baseDir, "src");
+    srcDir.mkdir();
+
+    File xooFile = new File(srcDir, "sample.xoo");
+    FileUtils.write(xooFile, "Sample xoo\ncontent");
+
+    tester.newTask()
+      .properties(builder
+        .put("sonar.sources", "src")
+        .build())
+      .start();
+
+    assertNoStdOutput();
+    assertThat(logOutput).isNotEmpty();
+    for (LogEvent e : logOutput) {
+      savedStdOut.println("[captured]" + e.level + " " + e.msg);
+    }
+  }
+
+  @Test
+  public void testNoFormattedMsgs() throws IOException {
+    File srcDir = new File(baseDir, "src");
+    srcDir.mkdir();
+
+    File xooFile = new File(srcDir, "sample.xoo");
+    FileUtils.write(xooFile, "Sample xoo\ncontent");
+
+    tester.newTask()
+      .properties(builder
+        .put("sonar.sources", "src")
+        .build())
+      .start();
+
+    assertNoStdOutput();
+
+    for (LogEvent e : logOutput) {
+      assertMsgClean(e.msg);
+      savedStdOut.println("[captured]" + e.level + " " + e.msg);
+    }
+  }
+
+  private class SimpleLogListener implements LogListener {
+    @Override
+    public void log(String msg, Level level) {
+      logOutput.add(new LogEvent(msg, level));
+    }
+  }
+
+  private static class LogEvent {
+    String msg;
+    Level level;
+
+    LogEvent(String msg, Level level) {
+      this.msg = msg;
+      this.level = level;
+    }
+  }
+}
index a5d88ffcbe9b11ab5a670122b30f0e7ebb1600c7..3ceeaa47f3d463ba6590b57e9da99a2a92f3b2f4 100644 (file)
@@ -52,15 +52,19 @@ public class PersistentCache {
   // eviction strategy is to expire entries after modification once a time duration has elapsed
   private final long defaultDurationToExpireMs;
   private final Log log;
-  private final boolean forceUpdate;
+  private boolean forceUpdate;
 
   public PersistentCache(Path baseDir, long defaultDurationToExpireMs, Log log, boolean forceUpdate) {
     this.baseDir = baseDir;
     this.defaultDurationToExpireMs = defaultDurationToExpireMs;
     this.log = log;
-    this.forceUpdate = forceUpdate;
 
+    reconfigure(forceUpdate);
     log.info("cache: " + baseDir + ", default expiration time (ms): " + defaultDurationToExpireMs);
+  }
+
+  public void reconfigure(boolean forceUpdate) {
+    this.forceUpdate = forceUpdate;
 
     if (forceUpdate) {
       log.debug("cache: forcing update");
index c8fcf06d4d0b802f0b3a66e8410498ac7657c926..c58dc53bbd6c4b7e5efccda5c97510193d038d3a 100644 (file)
@@ -30,17 +30,19 @@ import java.nio.file.Paths;
 import java.util.concurrent.TimeUnit;
 
 public class PersistentCacheBuilder {
+  private static final long DEFAULT_EXPIRE_DURATION = TimeUnit.MILLISECONDS.convert(1L, TimeUnit.DAYS);
+  private static final String DIR_NAME = "ws_cache";
+
   private boolean forceUpdate = false;
   private Path cachePath = null;
   private Log log = new StandardLog();
-  private String name = "ws_cache";
 
   public PersistentCache build() {
     if (cachePath == null) {
       setSonarHome(findHome());
     }
 
-    return new PersistentCache(cachePath, TimeUnit.MILLISECONDS.convert(1L, TimeUnit.DAYS), log, forceUpdate);
+    return new PersistentCache(cachePath, DEFAULT_EXPIRE_DURATION, log, forceUpdate);
   }
 
   public PersistentCacheBuilder setLog(Log log) {
@@ -50,7 +52,7 @@ public class PersistentCacheBuilder {
 
   public PersistentCacheBuilder setSonarHome(@Nullable Path p) {
     if (p != null) {
-      this.cachePath = p.resolve(name);
+      this.cachePath = p.resolve(DIR_NAME);
     }
     return this;
   }
index 5f1e342464236963cf43871b376fab15d3c2654c..8f8596e07050aad6a76e337ab88f76c49c1ae593 100644 (file)
  */
 package org.sonar.home.cache;
 
+import org.apache.commons.io.FileUtils;
+
 import org.sonar.home.log.Slf4jLog;
 import org.junit.Rule;
 import org.junit.rules.TemporaryFolder;
 
 import java.io.File;
-import java.nio.file.Path;
 import java.util.concurrent.Callable;
 
 import static org.mockito.Mockito.when;
@@ -95,9 +96,26 @@ public class PersistentCacheTest {
     assertCacheHit(true);
   }
 
+  @Test
+  public void testReconfigure() throws Exception {
+    cache = new PersistentCache(tmp.getRoot().toPath(), Long.MAX_VALUE, log, true);
+    assertCacheHit(false);
+    assertCacheHit(false);
+
+    File root = tmp.getRoot();
+    FileUtils.deleteDirectory(root);
+
+    // should re-create cache directory and start using the cache
+    cache.reconfigure(false);
+    assertThat(root).exists();
+
+    assertCacheHit(false);
+    assertCacheHit(true);
+  }
+
   @Test
   public void testExpiration() throws Exception {
-    //negative time to make sure it is expired on the second call
+    // negative time to make sure it is expired on the second call
     cache = new PersistentCache(tmp.getRoot().toPath(), -100, log, false);
     assertCacheHit(false);
     assertCacheHit(false);
@@ -118,7 +136,7 @@ public class PersistentCacheTest {
       return VALUE;
     }
   }
-  
+
   /**
    * WSCache should be transparent regarding exceptions: if an exception is thrown by the value loader, it should pass through
    * the cache to the original caller using the cache.
index 865821924077a10190d93cab73847e5750663116..de0ee3d7962eb9ad7fba71966252ca300399adf4 100644 (file)
@@ -19,7 +19,6 @@
  */
 package org.sonar.api.utils.internal;
 
-import org.sonar.api.utils.ProjectTempFolder;
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.lang.StringUtils;
 import org.sonar.api.utils.TempFolder;
@@ -30,21 +29,21 @@ import java.io.File;
 import java.io.IOException;
 import java.text.MessageFormat;
 
-public class DefaultTempFolder implements TempFolder, ProjectTempFolder {
+public class DefaultTempFolder implements TempFolder {
 
   /** Maximum loop count when creating temp directories. */
   private static final int TEMP_DIR_ATTEMPTS = 10000;
 
   private final File tempDir;
-  private final boolean cleanUp;
+  private final boolean deleteOnExit;
 
   public DefaultTempFolder(File tempDir) {
     this(tempDir, false);
   }
 
-  public DefaultTempFolder(File tempDir, boolean cleanUp) {
+  public DefaultTempFolder(File tempDir, boolean deleteOnExit) {
     this.tempDir = tempDir;
-    this.cleanUp = cleanUp;
+    this.deleteOnExit = deleteOnExit;
   }
 
   @Override
@@ -114,7 +113,7 @@ public class DefaultTempFolder implements TempFolder, ProjectTempFolder {
   }
 
   public void stop() {
-    if(cleanUp) {
+    if (deleteOnExit) {
       clean();
     }
   }
index e5cda14785f4336da7f8af8bc981657a15dfa94c..3a8c15bf474cb8759b91fade250cd75828af6603 100644 (file)
@@ -19,8 +19,6 @@
  */
 package org.sonar.api.utils.internal;
 
-import org.sonar.api.utils.ProjectTempFolder;
-
 import org.apache.commons.lang.StringUtils;
 import org.junit.rules.ExternalResource;
 import org.junit.rules.TemporaryFolder;
@@ -53,7 +51,7 @@ import java.io.IOException;
  *
  * @since 5.1
  */
-public class JUnitTempFolder extends ExternalResource implements TempFolder, ProjectTempFolder {
+public class JUnitTempFolder extends ExternalResource implements TempFolder {
 
   private final TemporaryFolder junit = new TemporaryFolder();
 
index 7697cf7d6debaaf84c71bcf5c79c8a2fb81787de..9d70e919bb999ac8296f6dfb8a92cc04f2df47b8 100644 (file)
  */
 package org.sonar.api.utils.internal;
 
-import org.sonar.api.batch.BatchSide;
 import org.sonar.api.server.ServerSide;
 import org.sonar.api.utils.TempFolder;
 
-@BatchSide
 @ServerSide
 public class TempFolderCleaner {