@@ -295,7 +295,6 @@ public class IssuesModeTest { | |||
fail("Issue not found"); | |||
} | |||
// SONAR-4602 | |||
@Test | |||
public void concurrent_issue_mode_on_existing_project() throws Exception { | |||
restoreProfile("one-issue-per-line.xml"); | |||
@@ -312,7 +311,7 @@ public class IssuesModeTest { | |||
// Install sonar-runner in advance to avoid concurrent unzip issues | |||
FileSystem fileSystem = orchestrator.getConfiguration().fileSystem(); | |||
new SonarRunnerInstaller(fileSystem).install(Version.create(SonarRunner.DEFAULT_RUNNER_VERSION), fileSystem.workspace()); | |||
final int nThreads = 5; | |||
final int nThreads = 3; | |||
ExecutorService executorService = Executors.newFixedThreadPool(nThreads); | |||
List<Callable<BuildResult>> tasks = new ArrayList<>(); | |||
for (int i = 0; i < nThreads; i++) { | |||
@@ -325,8 +324,20 @@ public class IssuesModeTest { | |||
}); | |||
} | |||
boolean expectedError = false; | |||
for (Future<BuildResult> result : executorService.invokeAll(tasks)) { | |||
try { | |||
result.get(); | |||
} catch(ExecutionException e) { | |||
if(e.getCause() instanceof BuildFailureException) { | |||
BuildFailureException bfe = (BuildFailureException) e.getCause(); | |||
assertThat(bfe.getResult().getLogs()).contains("Another SonarQube analysis is already in progress for this project"); | |||
expectedError = true; | |||
} | |||
} | |||
} | |||
if(!expectedError) { | |||
fail("At least one of the threads should have failed"); | |||
} | |||
} | |||
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} |
@@ -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); | |||
} | |||
} | |||
} |
@@ -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() { | |||
} | |||
} |
@@ -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, |
@@ -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); | |||
} | |||
} |
@@ -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); |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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 { |
@@ -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(); | |||
} | |||
} |
@@ -483,7 +483,7 @@ public interface CoreProperties { | |||
* @since 5.2 | |||
*/ | |||
String GLOBAL_WORKING_DIRECTORY = "sonar.globalWorking.directory"; | |||
String GLOBAL_WORKING_DIRECTORY_DEFAULT_VALUE = "."; | |||
String GLOBAL_WORKING_DIRECTORY_DEFAULT_VALUE = ""; | |||
/** | |||
* @since 4.2 |