aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-batch
diff options
context:
space:
mode:
authorDuarte Meneses <duarte.meneses@sonarsource.com>2015-08-20 16:58:48 +0200
committerDuarte Meneses <duarte.meneses@sonarsource.com>2015-08-21 13:55:09 +0200
commit7370c19e9acfefb2b9ac1fb3aeea7fd73f5a5fc3 (patch)
treeb8446a920ddb827cbd967129b5a27e6c17331565 /sonar-batch
parent24cd3f3a91720995ec076ac0073665ba73f27ade (diff)
downloadsonarqube-7370c19e9acfefb2b9ac1fb3aeea7fd73f5a5fc3.tar.gz
sonarqube-7370c19e9acfefb2b9ac1fb3aeea7fd73f5a5fc3.zip
SONAR-6721 Prevent running concurrent batch processes on the same physical project
Diffstat (limited to 'sonar-batch')
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/analysis/AnalysisTempFolderProvider.java57
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/bootstrap/GlobalTempFolderProvider.java48
-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/scan/MutableProjectReactorProvider.java19
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan/ProjectLock.java101
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java5
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/analysis/AnalysisTempFolderProviderTest.java48
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/bootstrap/GlobalTempFolderProviderTest.java21
-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/mediumtest/issues/IssuesIssuesModeMediumTest.java4
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/scan/ProjectLockTest.java83
11 files changed, 316 insertions, 234 deletions
diff --git a/sonar-batch/src/main/java/org/sonar/batch/analysis/AnalysisTempFolderProvider.java b/sonar-batch/src/main/java/org/sonar/batch/analysis/AnalysisTempFolderProvider.java
index 639a932fb36..63078cdb648 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/analysis/AnalysisTempFolderProvider.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/analysis/AnalysisTempFolderProvider.java
@@ -19,49 +19,62 @@
*/
package org.sonar.batch.analysis;
-import org.sonar.batch.bootstrap.LifecycleProviderAdapter;
-
+import org.sonar.api.batch.bootstrap.ProjectReactor;
+import org.picocontainer.PicoContainer;
+import org.picocontainer.ComponentLifecycle;
+import org.picocontainer.injectors.ProviderAdapter;
import org.sonar.api.utils.TempFolder;
-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.Files;
import java.nio.file.Path;
-import java.nio.file.Paths;
-public class AnalysisTempFolderProvider extends LifecycleProviderAdapter {
+public class AnalysisTempFolderProvider extends ProviderAdapter implements ComponentLifecycle<TempFolder> {
static final String TMP_NAME = ".sonartmp";
private DefaultTempFolder projectTempFolder;
- public TempFolder provide(AnalysisProperties props) {
+ public TempFolder provide(ProjectReactor projectReactor) {
if (projectTempFolder == null) {
- String workingDirPath = StringUtils.defaultIfBlank(props.property(CoreProperties.WORKING_DIRECTORY), CoreProperties.WORKING_DIRECTORY_DEFAULT_VALUE);
- Path workingDir = Paths.get(workingDirPath).normalize();
-
- if (!workingDir.isAbsolute()) {
- Path base = getBasePath(props);
- workingDir = base.resolve(workingDir);
- }
-
- Path tempDir = workingDir.resolve(TMP_NAME);
+ Path workingDir = projectReactor.getRoot().getWorkDir().toPath();
+ Path tempDir = workingDir.normalize().resolve(TMP_NAME);
try {
+ Files.deleteIfExists(tempDir);
Files.createDirectories(tempDir);
} catch (IOException e) {
throw new IllegalStateException("Unable to create root temp directory " + tempDir, e);
}
+
projectTempFolder = new DefaultTempFolder(tempDir.toFile(), true);
- this.instance = projectTempFolder;
}
return projectTempFolder;
}
- private static Path getBasePath(AnalysisProperties props) {
- String baseDir = props.property("sonar.projectBaseDir");
- if (baseDir == null) {
- throw new IllegalStateException("sonar.projectBaseDir needs to be specified");
+ @Override
+ public void start(PicoContainer container) {
+ started = true;
+ }
+
+ private boolean started = false;
+
+ @Override
+ public void stop(PicoContainer container) {
+ if (projectTempFolder != null) {
+ projectTempFolder.stop();
}
- return Paths.get(baseDir);
+ }
+
+ @Override
+ public void dispose(PicoContainer container) {
+ }
+
+ @Override
+ public boolean componentHasLifecycle() {
+ return true;
+ }
+
+ @Override
+ public boolean isStarted() {
+ return started;
}
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/GlobalTempFolderProvider.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/GlobalTempFolderProvider.java
index e86114efb2e..9ccec68c9bd 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/GlobalTempFolderProvider.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/GlobalTempFolderProvider.java
@@ -19,6 +19,10 @@
*/
package org.sonar.batch.bootstrap;
+import org.picocontainer.ComponentLifecycle;
+
+import org.picocontainer.PicoContainer;
+import org.picocontainer.injectors.ProviderAdapter;
import org.sonar.api.utils.System2;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
@@ -36,10 +40,9 @@ import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.concurrent.TimeUnit;
-public class GlobalTempFolderProvider extends LifecycleProviderAdapter {
+public class GlobalTempFolderProvider extends ProviderAdapter implements ComponentLifecycle<TempFolder> {
private static final Logger LOG = Loggers.get(GlobalTempFolderProvider.class);
private static final long CLEAN_MAX_AGE = TimeUnit.DAYS.toMillis(21);
-
static final String TMP_NAME_PREFIX = ".sonartmp_";
private System2 system;
@@ -57,10 +60,10 @@ public class GlobalTempFolderProvider extends LifecycleProviderAdapter {
if (tempFolder == null) {
String workingPathName = StringUtils.defaultIfBlank(bootstrapProps.property(CoreProperties.GLOBAL_WORKING_DIRECTORY), CoreProperties.GLOBAL_WORKING_DIRECTORY_DEFAULT_VALUE);
- Path workingPath = Paths.get(workingPathName).normalize();
+ Path workingPath = Paths.get(workingPathName);
if (!workingPath.isAbsolute()) {
- Path home = findHome(bootstrapProps);
+ Path home = findSonarHome(bootstrapProps);
workingPath = home.resolve(workingPath).normalize();
}
@@ -71,7 +74,6 @@ public class GlobalTempFolderProvider extends LifecycleProviderAdapter {
}
Path tempDir = createTempFolder(workingPath);
tempFolder = new DefaultTempFolder(tempDir.toFile(), true);
- this.instance = tempFolder;
}
return tempFolder;
}
@@ -90,20 +92,20 @@ public class GlobalTempFolderProvider extends LifecycleProviderAdapter {
}
}
- private Path findHome(GlobalProperties props) {
+ private Path findSonarHome(GlobalProperties props) {
String home = props.property("sonar.userHome");
if (home != null) {
- return Paths.get(home);
+ return Paths.get(home).toAbsolutePath();
}
home = system.envVariable("SONAR_USER_HOME");
if (home != null) {
- return Paths.get(home);
+ return Paths.get(home).toAbsolutePath();
}
home = system.property("user.home");
- return Paths.get(home, ".sonar");
+ return Paths.get(home, ".sonar").toAbsolutePath();
}
private static void cleanTempFolders(Path path) throws IOException {
@@ -143,4 +145,32 @@ public class GlobalTempFolderProvider extends LifecycleProviderAdapter {
return creationTime < threshold;
}
}
+
+ @Override
+ public void start(PicoContainer container) {
+ started = true;
+ }
+
+ private boolean started = false;
+
+ @Override
+ public void stop(PicoContainer container) {
+ if (tempFolder != null) {
+ tempFolder.stop();
+ }
+ }
+
+ @Override
+ public void dispose(PicoContainer container) {
+ }
+
+ @Override
+ public boolean componentHasLifecycle() {
+ return true;
+ }
+
+ @Override
+ public boolean isStarted() {
+ return started;
+ }
}
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
deleted file mode 100644
index 009aadad61d..00000000000
--- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/LifecycleProviderAdapter.java
+++ /dev/null
@@ -1,85 +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.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/scan/MutableProjectReactorProvider.java b/sonar-batch/src/main/java/org/sonar/batch/scan/MutableProjectReactorProvider.java
index b9a8a1cf460..a9b29578702 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/scan/MutableProjectReactorProvider.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/scan/MutableProjectReactorProvider.java
@@ -19,15 +19,18 @@
*/
package org.sonar.batch.scan;
+import org.apache.commons.io.FileUtils;
import org.sonar.batch.analysis.AnalysisProperties;
-
import org.picocontainer.injectors.ProviderAdapter;
import org.sonar.api.batch.bootstrap.ProjectBootstrapper;
import org.sonar.api.batch.bootstrap.ProjectReactor;
-import org.sonar.api.utils.SonarException;
import javax.annotation.Nullable;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+
public class MutableProjectReactorProvider extends ProviderAdapter {
private final ProjectBootstrapper projectBootstrapper;
@@ -49,9 +52,19 @@ public class MutableProjectReactorProvider extends ProviderAdapter {
reactor = projectBootstrapper.bootstrap();
}
if (reactor == null) {
- throw new SonarException(projectBootstrapper + " has returned null as ProjectReactor");
+ throw new IllegalStateException(projectBootstrapper + " has returned null as ProjectReactor");
}
+ cleanDirectory(reactor.getRoot().getWorkDir());
}
return reactor;
}
+
+ private void cleanDirectory(File dir) {
+ try {
+ FileUtils.deleteDirectory(dir);
+ Files.createDirectories(dir.toPath());
+ } catch (IOException e) {
+ throw new IllegalStateException("Failed to recreate working directory: " + dir.getAbsolutePath(), e);
+ }
+ }
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectLock.java b/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectLock.java
new file mode 100644
index 00000000000..a373763a361
--- /dev/null
+++ b/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectLock.java
@@ -0,0 +1,101 @@
+/*
+ * 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.scan;
+
+import org.picocontainer.Startable;
+import org.sonar.api.batch.bootstrap.ProjectReactor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.channels.FileChannel;
+import java.nio.channels.FileLock;
+import java.nio.channels.OverlappingFileLockException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+public class ProjectLock implements Startable {
+ private static final Logger LOG = LoggerFactory.getLogger(ProjectLock.class);
+ static final String LOCK_FILE_NAME = ".sonar_lock";
+ private final Path lockFilePath;
+
+ private RandomAccessFile lockRandomAccessFile;
+ private FileChannel lockChannel;
+ private FileLock lockFile;
+
+ public ProjectLock(ProjectReactor projectReactor) {
+ Path directory = projectReactor.getRoot().getBaseDir().toPath();
+ this.lockFilePath = directory.resolve(LOCK_FILE_NAME).toAbsolutePath();
+ }
+
+ public void tryLock() {
+ try {
+ lockRandomAccessFile = new RandomAccessFile(lockFilePath.toFile(), "rw");
+ lockChannel = lockRandomAccessFile.getChannel();
+ lockFile = lockChannel.tryLock(0, 1024, false);
+
+ if (lockFile == null) {
+ failAlreadyInProgress();
+ }
+ } catch (OverlappingFileLockException e) {
+ failAlreadyInProgress();
+ } catch (IOException e) {
+ throw new IllegalStateException("Failed to create project lock in " + lockFilePath.toString(), e);
+ }
+ }
+
+ private static void failAlreadyInProgress() {
+ throw new IllegalStateException("Another SonarQube analysis is already in progress for this project");
+ }
+
+ public void stop() {
+ if (lockFile != null) {
+ try {
+ Files.delete(lockFilePath);
+ lockFile.release();
+ lockFile = null;
+ } catch (IOException e) {
+ LOG.error("Error releasing lock", e);
+ }
+ }
+ if (lockChannel != null) {
+ try {
+ lockChannel.close();
+ lockChannel = null;
+ } catch (IOException e) {
+ LOG.error("Error closing file channel", e);
+ }
+ }
+ if (lockRandomAccessFile != null) {
+ try {
+ lockRandomAccessFile.close();
+ lockRandomAccessFile = null;
+ } catch (IOException e) {
+ LOG.error("Error closing file", e);
+ }
+ }
+ }
+
+ @Override
+ public void start() {
+ }
+
+}
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 869a64b4c93..e31f14a104e 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
@@ -20,7 +20,6 @@
package org.sonar.batch.scan;
import org.sonar.batch.analysis.DefaultAnalysisMode;
-
import org.sonar.batch.analysis.AnalysisWSLoaderProvider;
import org.sonar.batch.analysis.AnalysisTempFolderProvider;
import org.sonar.batch.analysis.AnalysisProperties;
@@ -51,7 +50,6 @@ import org.sonar.batch.bootstrap.ExtensionMatcher;
import org.sonar.batch.bootstrap.ExtensionUtils;
import org.sonar.batch.bootstrap.MetricProvider;
import org.sonar.batch.bootstrapper.EnvironmentInformation;
-import org.sonar.batch.deprecated.components.DefaultResourceCreationLock;
import org.sonar.batch.duplication.DuplicationCache;
import org.sonar.batch.events.EventBus;
import org.sonar.batch.index.BatchComponentCache;
@@ -107,6 +105,7 @@ public class ProjectScanContainer extends ComponentContainer {
add(component);
}
addBatchComponents();
+ getComponentByType(ProjectLock.class).tryLock();
addBatchExtensions();
Settings settings = getComponentByType(Settings.class);
if (settings != null && settings.getBoolean(CoreProperties.PROFILING_LOG_PROPERTY)) {
@@ -135,6 +134,7 @@ public class ProjectScanContainer extends ComponentContainer {
new MutableProjectReactorProvider(getComponentByType(ProjectBootstrapper.class)),
new ImmutableProjectReactorProvider(),
ProjectBuildersExecutor.class,
+ ProjectLock.class,
EventBus.class,
PhasesTimeProfiler.class,
ResourceTypes.class,
@@ -143,7 +143,6 @@ public class ProjectScanContainer extends ComponentContainer {
ProjectReactorValidator.class,
new ProjectRepositoriesProvider(),
new AnalysisWSLoaderProvider(),
- DefaultResourceCreationLock.class,
CodeColorizers.class,
MetricProvider.class,
ProjectConfigurator.class,
diff --git a/sonar-batch/src/test/java/org/sonar/batch/analysis/AnalysisTempFolderProviderTest.java b/sonar-batch/src/test/java/org/sonar/batch/analysis/AnalysisTempFolderProviderTest.java
index 601f90d876c..3a81a7304d6 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/analysis/AnalysisTempFolderProviderTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/analysis/AnalysisTempFolderProviderTest.java
@@ -19,20 +19,21 @@
*/
package org.sonar.batch.analysis;
-import org.sonar.batch.analysis.AnalysisTempFolderProvider;
+import org.sonar.api.batch.bootstrap.ProjectDefinition;
-import org.sonar.batch.analysis.AnalysisProperties;
+import org.sonar.api.batch.bootstrap.ProjectReactor;
+import org.junit.Before;
+import org.sonar.batch.analysis.AnalysisTempFolderProvider;
import org.sonar.api.utils.TempFolder;
-import org.apache.commons.io.FileUtils;
-import com.google.common.collect.ImmutableMap;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
-import org.sonar.api.CoreProperties;
import java.io.File;
import java.io.IOException;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.mock;
import static org.assertj.core.api.Assertions.assertThat;
public class AnalysisTempFolderProviderTest {
@@ -40,33 +41,26 @@ public class AnalysisTempFolderProviderTest {
@Rule
public TemporaryFolder temp = new TemporaryFolder();
- private AnalysisTempFolderProvider tempFolderProvider = new AnalysisTempFolderProvider();
-
- @Test
- public void createTempFolderWithProps() throws Exception {
- File workingDir = temp.newFolder();
- File tmpDir = new File(workingDir, AnalysisTempFolderProvider.TMP_NAME);
+ private AnalysisTempFolderProvider tempFolderProvider;
+ private ProjectReactor projectReactor;
- TempFolder tempFolder = tempFolderProvider.provide(new AnalysisProperties(ImmutableMap.of(CoreProperties.WORKING_DIRECTORY, workingDir.getAbsolutePath()), ""));
- tempFolder.newDir();
- tempFolder.newFile();
- assertThat(tmpDir).exists();
- assertThat(tmpDir.list()).hasSize(2);
+ @Before
+ public void setUp() {
+ tempFolderProvider = new AnalysisTempFolderProvider();
+ projectReactor = mock(ProjectReactor.class);
+ ProjectDefinition projectDefinition = mock(ProjectDefinition.class);
+ when(projectReactor.getRoot()).thenReturn(projectDefinition);
+ when(projectDefinition.getWorkDir()).thenReturn(temp.getRoot());
}
@Test
public void createTempFolder() throws IOException {
- File workingDir = temp.newFolder();
- File defaultDir = new File(new File(workingDir, CoreProperties.WORKING_DIRECTORY_DEFAULT_VALUE), AnalysisTempFolderProvider.TMP_NAME);
+ File defaultDir = new File(temp.getRoot(), AnalysisTempFolderProvider.TMP_NAME);
- try {
- TempFolder tempFolder = tempFolderProvider.provide(new AnalysisProperties(ImmutableMap.of("sonar.projectBaseDir", workingDir.getAbsolutePath()), ""));
- tempFolder.newDir();
- tempFolder.newFile();
- assertThat(defaultDir).exists();
- assertThat(defaultDir.list()).hasSize(2);
- } finally {
- FileUtils.deleteDirectory(defaultDir);
- }
+ TempFolder tempFolder = tempFolderProvider.provide(projectReactor);
+ tempFolder.newDir();
+ tempFolder.newFile();
+ assertThat(defaultDir).exists();
+ assertThat(defaultDir.list()).hasSize(2);
}
}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/GlobalTempFolderProviderTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/GlobalTempFolderProviderTest.java
index aeb18d14d99..6620f59fb98 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/GlobalTempFolderProviderTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/GlobalTempFolderProviderTest.java
@@ -55,7 +55,7 @@ public class GlobalTempFolderProviderTest {
tempFolder.newFile();
assertThat(getCreatedTempDir(workingDir)).exists();
assertThat(getCreatedTempDir(workingDir).list()).hasSize(2);
-
+
FileUtils.deleteQuietly(workingDir);
}
@@ -73,7 +73,7 @@ public class GlobalTempFolderProviderTest {
tempFolderProvider.provide(new GlobalProperties(ImmutableMap.of(CoreProperties.GLOBAL_WORKING_DIRECTORY, workingDir.getAbsolutePath())));
// this also checks that all other temps were deleted
assertThat(getCreatedTempDir(workingDir)).exists();
-
+
FileUtils.deleteQuietly(workingDir);
}
@@ -88,7 +88,7 @@ public class GlobalTempFolderProviderTest {
tempFolder.newFile();
assertThat(getCreatedTempDir(workingDir)).exists();
assertThat(getCreatedTempDir(workingDir).list()).hasSize(2);
-
+
FileUtils.deleteQuietly(sonarHome);
}
@@ -97,7 +97,7 @@ public class GlobalTempFolderProviderTest {
System2 system = mock(System2.class);
tempFolderProvider = new GlobalTempFolderProvider(system);
File userHome = temp.newFolder();
-
+
when(system.envVariable("SONAR_USER_HOME")).thenReturn(null);
when(system.property("user.home")).thenReturn(userHome.getAbsolutePath().toString());
@@ -115,6 +115,19 @@ public class GlobalTempFolderProviderTest {
}
}
+ @Test
+ public void dotWorkingDir() throws IOException {
+ File sonarHome = temp.getRoot();
+ String globalWorkDir = ".";
+ GlobalProperties globalProperties = new GlobalProperties(ImmutableMap.of("sonar.userHome", sonarHome.getAbsolutePath(),
+ CoreProperties.GLOBAL_WORKING_DIRECTORY, globalWorkDir));
+
+ TempFolder tempFolder = tempFolderProvider.provide(globalProperties);
+ File newFile = tempFolder.newFile();
+ assertThat(newFile.getParentFile().getParentFile().getAbsolutePath()).isEqualTo(sonarHome.getAbsolutePath());
+ assertThat(newFile.getParentFile().getName()).startsWith(".sonartmp_");
+ }
+
private File getCreatedTempDir(File workingDir) {
assertThat(workingDir).isDirectory();
assertThat(workingDir.listFiles()).hasSize(1);
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
deleted file mode 100644
index 5c3bb85a109..00000000000
--- a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/LifecycleProviderAdapterTest.java
+++ /dev/null
@@ -1,79 +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.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/mediumtest/issues/IssuesIssuesModeMediumTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issues/IssuesIssuesModeMediumTest.java
index bb44b2390d3..e21eea304c4 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issues/IssuesIssuesModeMediumTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issues/IssuesIssuesModeMediumTest.java
@@ -86,8 +86,8 @@ public class IssuesIssuesModeMediumTest {
.property(CoreProperties.ANALYSIS_MODE, CoreProperties.ANALYSIS_MODE_ISSUES)
.start();
- assertThat(result2.trackedIssues()).hasSize(28);
- assertThat(issueListener.issueList).hasSize(28);
+ assertThat(result2.trackedIssues()).hasSize(14);
+ assertThat(issueListener.issueList).hasSize(14);
}
private class IssueRecorder implements IssueListener {
diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan/ProjectLockTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/ProjectLockTest.java
new file mode 100644
index 00000000000..b3eb55252e8
--- /dev/null
+++ b/sonar-batch/src/test/java/org/sonar/batch/scan/ProjectLockTest.java
@@ -0,0 +1,83 @@
+/*
+ * 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.scan;
+
+import org.junit.rules.ExpectedException;
+
+import org.sonar.api.batch.bootstrap.ProjectDefinition;
+import org.sonar.api.batch.bootstrap.ProjectReactor;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.assertj.core.api.Assertions.assertThat;
+import org.junit.Test;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.rules.TemporaryFolder;
+
+public class ProjectLockTest {
+ @Rule
+ public TemporaryFolder tempFolder = new TemporaryFolder();
+
+ @Rule
+ public ExpectedException exception = ExpectedException.none();
+ private ProjectLock lock;
+
+ @Before
+ public void setUp() {
+ ProjectReactor projectReactor = mock(ProjectReactor.class);
+ ProjectDefinition projectDefinition = mock(ProjectDefinition.class);
+ when(projectReactor.getRoot()).thenReturn(projectDefinition);
+ when(projectDefinition.getBaseDir()).thenReturn(tempFolder.getRoot());
+
+ lock = new ProjectLock(projectReactor);
+ }
+
+ @Test
+ public void tryLock() {
+ Path lockFilePath = tempFolder.getRoot().toPath().resolve(ProjectLock.LOCK_FILE_NAME);
+ lock.tryLock();
+ assertThat(Files.exists(lockFilePath)).isTrue();
+ assertThat(Files.isRegularFile(lockFilePath)).isTrue();
+
+ lock.stop();
+ assertThat(Files.exists(lockFilePath)).isFalse();
+ }
+
+ @Test
+ public void tryLockConcurrently() {
+ exception.expect(IllegalStateException.class);
+ exception.expectMessage("Another SonarQube analysis is already in progress for this project");
+ lock.tryLock();
+ lock.tryLock();
+ }
+
+ @Test
+ public void tryLockTwice() {
+ lock.tryLock();
+ lock.stop();
+ lock.tryLock();
+ lock.stop();
+ }
+
+}