aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-batch
diff options
context:
space:
mode:
authorDuarte Meneses <duarte.meneses@sonarsource.com>2015-06-18 15:23:54 +0200
committerDuarte Meneses <duarte.meneses@sonarsource.com>2015-06-24 14:34:21 +0200
commita3f2f42774fc6f83b8bb743743a092ffc7b9bb50 (patch)
tree035aa4f53d80412c126f2de5f0df0647e4e70283 /sonar-batch
parent62bded91ea52f42a71ad7d7624d5447b1a101420 (diff)
downloadsonarqube-a3f2f42774fc6f83b8bb743743a092ffc7b9bb50.tar.gz
sonarqube-a3f2f42774fc6f83b8bb743743a092ffc7b9bb50.zip
SONAR-6649 Move initialization of persistit cache to global context
Diffstat (limited to 'sonar-batch')
-rw-r--r--sonar-batch/pom.xml2
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/bootstrap/GlobalContainer.java13
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/bootstrap/LifecycleProviderAdapter.java85
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/bootstrap/PersistentCacheProvider.java21
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectTempFolderProvider.java25
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/bootstrap/TempFolderProvider.java62
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/bootstrapper/LogCallbackAppender.java8
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/index/Caches.java16
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java9
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java6
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/bootstrap/LifecycleProviderAdapterTest.java79
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/bootstrap/PersistentCacheProviderTest.java12
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/bootstrap/ProjectTempFolderProviderTest.java8
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/bootstrap/TempFolderProviderTest.java57
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/bootstrapper/LogCallbackAppenderTest.java66
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/bootstrapper/PrintStreamTest.java102
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/index/CachesTest.java2
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/mediumtest/log/LogListenerTest.java187
18 files changed, 587 insertions, 173 deletions
diff --git a/sonar-batch/pom.xml b/sonar-batch/pom.xml
index c1b2b197c32..db21e928a97 100644
--- a/sonar-batch/pom.xml
+++ b/sonar-batch/pom.xml
@@ -25,7 +25,7 @@
<scope>provided</scope>
</dependency>
<dependency>
- <groupId>org.codehaus.sonar</groupId>
+ <groupId>org.sonarsource</groupId>
<artifactId>sonar-persistit</artifactId>
</dependency>
<dependency>
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/GlobalContainer.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/GlobalContainer.java
index 08d9cbb9a7c..94d6effc42d 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/GlobalContainer.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/GlobalContainer.java
@@ -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
index 00000000000..009aadad61d
--- /dev/null
+++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/LifecycleProviderAdapter.java
@@ -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;
+
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/PersistentCacheProvider.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/PersistentCacheProvider.java
index 9ca57407d6c..6821333b27f 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/PersistentCacheProvider.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/PersistentCacheProvider.java
@@ -20,27 +20,23 @@
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);
+ }
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectTempFolderProvider.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectTempFolderProvider.java
index e83013371ad..bcaf8ec8666 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectTempFolderProvider.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectTempFolderProvider.java
@@ -19,34 +19,33 @@
*/
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;
}
-
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/TempFolderProvider.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/TempFolderProvider.java
index 971a4a2b1f5..b1ee968f344 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/TempFolderProvider.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/TempFolderProvider.java
@@ -19,20 +19,28 @@
*/
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;
+ }
+ }
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrapper/LogCallbackAppender.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrapper/LogCallbackAppender.java
index 6c216410d13..73730de7df5 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/bootstrapper/LogCallbackAppender.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrapper/LogCallbackAppender.java
@@ -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:
diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/Caches.java b/sonar-batch/src/main/java/org/sonar/batch/index/Caches.java
index 209ec7792aa..4f0bf342693 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/index/Caches.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/index/Caches.java
@@ -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 {
diff --git a/sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java b/sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java
index 8e38c2031fe..ab769822948 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java
@@ -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();
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java b/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
index 623fd0fa90e..1c3e864170d 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
@@ -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
index 00000000000..5c3bb85a109
--- /dev/null
+++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/LifecycleProviderAdapterTest.java
@@ -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;
+ }
+ }
+}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/PersistentCacheProviderTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/PersistentCacheProviderTest.java
index 5b6db572df5..24bdf6047d5 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/PersistentCacheProviderTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/PersistentCacheProviderTest.java
@@ -19,24 +19,20 @@
*/
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();
}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ProjectTempFolderProviderTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ProjectTempFolderProviderTest.java
index e79f0516159..2b7a0435240 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ProjectTempFolderProviderTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ProjectTempFolderProviderTest.java
@@ -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();
diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/TempFolderProviderTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/TempFolderProviderTest.java
index ce64074d9a6..8c1e23b7b56 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/TempFolderProviderTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/TempFolderProviderTest.java
@@ -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
index 00000000000..ea1fd3a470e
--- /dev/null
+++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrapper/LogCallbackAppenderTest.java
@@ -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
index da833eae508..00000000000
--- a/sonar-batch/src/test/java/org/sonar/batch/bootstrapper/PrintStreamTest.java
+++ /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());
- }
-}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/index/CachesTest.java b/sonar-batch/src/test/java/org/sonar/batch/index/CachesTest.java
index 801d0f3d5ed..411435aebec 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/index/CachesTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/index/CachesTest.java
@@ -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
index 00000000000..c50f9e20adf
--- /dev/null
+++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/log/LogListenerTest.java
@@ -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;
+ }
+ }
+}