From b71b3673e91930aac3fff828d628279b5dee7616 Mon Sep 17 00:00:00 2001 From: Simon Brandhof Date: Fri, 26 Oct 2012 15:36:32 +0200 Subject: [PATCH] SONAR-3895 execute bootstrap extensions (liek ProjectBuilder) before initializing db --- .../sonar/plugins/jacoco/JaCoCoSensor.java | 1 + .../plugins/jacoco/JaCoCoSensorTest.java | 1 + sonar-batch/pom.xml | 7 +- .../org/sonar/batch/RemoteServerMetadata.java | 88 ----------- .../java/org/sonar/batch/ServerMetadata.java | 73 --------- .../batch/bootstrap/ArtifactDownloader.java | 105 ------------- .../bootstrap/BatchPluginRepository.java | 10 +- .../batch/bootstrap/BootstrapModule.java | 13 +- .../bootstrap/DatabaseBatchCompatibility.java | 10 +- .../batch/bootstrap/JdbcDriverHolder.java | 30 ++-- .../batch/bootstrap/PluginDownloader.java | 84 +++++++++++ .../batch/bootstrap/ProjectExclusions.java | 1 - .../sonar/batch/bootstrap/ServerClient.java | 142 ++++++++++++++++++ .../bootstrapper/EnvironmentInformation.java | 4 + .../org/sonar/batch/local/LocalDatabase.java | 61 +++----- .../sonar/batch/phases/UpdateStatusJob.java | 7 +- .../sonar/batch/RemoteServerMetadataTest.java | 62 -------- .../bootstrap/ArtifactDownloaderTest.java | 66 -------- .../batch/bootstrap/BatchDatabaseTest.java | 42 ++++++ .../bootstrap/BatchPluginRepositoryTest.java | 22 +-- .../DatabaseBatchCompatibilityTest.java | 25 ++- .../batch/bootstrap/JdbcDriverHolderTest.java | 33 ++-- .../bootstrap/ProjectExclusionsTest.java | 15 ++ .../ServerClientTest.java} | 51 ++++--- .../batch/bootstrap/TempDirectoriesTest.java | 28 ++-- .../EnvironmentInformationTest.java | 41 +++++ .../batch/phases/UpdateStatusJobTest.java | 4 +- .../sonar/api/batch/CoverageExtension.java | 10 +- .../api/utils/command/CommandException.java | 4 +- 29 files changed, 482 insertions(+), 558 deletions(-) delete mode 100644 sonar-batch/src/main/java/org/sonar/batch/RemoteServerMetadata.java delete mode 100644 sonar-batch/src/main/java/org/sonar/batch/ServerMetadata.java delete mode 100644 sonar-batch/src/main/java/org/sonar/batch/bootstrap/ArtifactDownloader.java create mode 100644 sonar-batch/src/main/java/org/sonar/batch/bootstrap/PluginDownloader.java create mode 100644 sonar-batch/src/main/java/org/sonar/batch/bootstrap/ServerClient.java delete mode 100644 sonar-batch/src/test/java/org/sonar/batch/RemoteServerMetadataTest.java delete mode 100644 sonar-batch/src/test/java/org/sonar/batch/bootstrap/ArtifactDownloaderTest.java create mode 100644 sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchDatabaseTest.java rename sonar-batch/src/test/java/org/sonar/batch/{ServerMetadataTest.java => bootstrap/ServerClientTest.java} (50%) create mode 100644 sonar-batch/src/test/java/org/sonar/batch/bootstrapper/EnvironmentInformationTest.java diff --git a/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/JaCoCoSensor.java b/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/JaCoCoSensor.java index 085585dfb0b..8c7a4853563 100644 --- a/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/JaCoCoSensor.java +++ b/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/JaCoCoSensor.java @@ -46,6 +46,7 @@ public class JaCoCoSensor implements Sensor, CoverageExtension { public boolean shouldExecuteOnProject(Project project) { return Java.KEY.equals(project.getLanguageKey()) + && configuration.isEnabled() && project.getAnalysisType().isDynamic(true); } diff --git a/plugins/sonar-jacoco-plugin/src/test/java/org/sonar/plugins/jacoco/JaCoCoSensorTest.java b/plugins/sonar-jacoco-plugin/src/test/java/org/sonar/plugins/jacoco/JaCoCoSensorTest.java index 2701a4a9c42..6501a60dbaf 100644 --- a/plugins/sonar-jacoco-plugin/src/test/java/org/sonar/plugins/jacoco/JaCoCoSensorTest.java +++ b/plugins/sonar-jacoco-plugin/src/test/java/org/sonar/plugins/jacoco/JaCoCoSensorTest.java @@ -71,6 +71,7 @@ public class JaCoCoSensorTest { @Before public void setUp() { configuration = mock(JacocoConfiguration.class); + when(configuration.isEnabled()).thenReturn(true); sensor = new JaCoCoSensor(configuration); } diff --git a/sonar-batch/pom.xml b/sonar-batch/pom.xml index 7255d9719b2..ec6c38fa8aa 100644 --- a/sonar-batch/pom.xml +++ b/sonar-batch/pom.xml @@ -1,5 +1,6 @@ - + 4.0.0 org.codehaus.sonar @@ -33,6 +34,10 @@ org.codehaus.sonar sonar-squid + + org.codehaus.sonar + sonar-ws-client + org.slf4j slf4j-api diff --git a/sonar-batch/src/main/java/org/sonar/batch/RemoteServerMetadata.java b/sonar-batch/src/main/java/org/sonar/batch/RemoteServerMetadata.java deleted file mode 100644 index 3a830404076..00000000000 --- a/sonar-batch/src/main/java/org/sonar/batch/RemoteServerMetadata.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Sonar, open source software quality management tool. - * Copyright (C) 2008-2012 SonarSource - * mailto:contact AT sonarsource DOT com - * - * Sonar 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. - * - * Sonar 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 Sonar; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 - */ -package org.sonar.batch; - -import org.apache.commons.lang.StringUtils; -import org.codehaus.plexus.util.IOUtil; -import org.sonar.api.BatchComponent; -import org.sonar.api.platform.Server; - -import java.io.IOException; -import java.io.InputStream; -import java.net.HttpURLConnection; -import java.net.URL; - -public class RemoteServerMetadata implements BatchComponent { - - public static final int CONNECT_TIMEOUT_MILLISECONDS = 30000; - public static final int READ_TIMEOUT_MILLISECONDS = 60000; - - private String serverUrl; - - public RemoteServerMetadata(Server server) { - serverUrl = server.getURL(); - if (serverUrl.endsWith("/")) { - serverUrl = StringUtils.chop(serverUrl); - } - } - - public String getServerId() throws IOException { - String remoteServerInfo = remoteContent("/api/server"); - // don't use JSON utilities to extract ID from such a small string - return extractId(remoteServerInfo); - } - - protected String extractId(String remoteServerInfo) { - String partialId = StringUtils.substringAfter(remoteServerInfo, "\"id\":\""); - return StringUtils.substringBefore(partialId, "\""); - } - - protected String getUrlFor(String path) { - return serverUrl + path; - } - - protected String remoteContent(String path) throws IOException { - String fullUrl = getUrlFor(path); - HttpURLConnection conn = getConnection(fullUrl, "GET"); - InputStream input = (InputStream) conn.getContent(); - try { - int statusCode = conn.getResponseCode(); - if (statusCode != HttpURLConnection.HTTP_OK) { - throw new IOException("Status returned by url : '" + fullUrl + "' is invalid : " + statusCode); - } - return IOUtil.toString(input); - - } finally { - IOUtil.close(input); - conn.disconnect(); - } - } - - static HttpURLConnection getConnection(String url, String method) throws IOException { - URL page = new URL(url); - HttpURLConnection conn = (HttpURLConnection) page.openConnection(); - conn.setConnectTimeout(CONNECT_TIMEOUT_MILLISECONDS); - conn.setReadTimeout(READ_TIMEOUT_MILLISECONDS); - conn.setRequestMethod(method); - conn.connect(); - return conn; - } - -} diff --git a/sonar-batch/src/main/java/org/sonar/batch/ServerMetadata.java b/sonar-batch/src/main/java/org/sonar/batch/ServerMetadata.java deleted file mode 100644 index 853c308b467..00000000000 --- a/sonar-batch/src/main/java/org/sonar/batch/ServerMetadata.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Sonar, open source software quality management tool. - * Copyright (C) 2008-2012 SonarSource - * mailto:contact AT sonarsource DOT com - * - * Sonar 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. - * - * Sonar 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 Sonar; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 - */ -package org.sonar.batch; - -import org.apache.commons.lang.StringUtils; -import org.slf4j.LoggerFactory; -import org.sonar.api.CoreProperties; -import org.sonar.api.config.Settings; -import org.sonar.api.platform.Server; - -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Date; - -public class ServerMetadata extends Server { - - private Settings settings; - - public ServerMetadata(Settings settings) { - this.settings = settings; - } - - @Override - public String getId() { - return settings.getString(CoreProperties.SERVER_ID); - } - - @Override - public String getVersion() { - return settings.getString(CoreProperties.SERVER_VERSION); - } - - @Override - public Date getStartedAt() { - String dateString = settings.getString(CoreProperties.SERVER_STARTTIME); - if (dateString != null) { - try { - return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").parse(dateString); - - } catch (ParseException e) { - LoggerFactory.getLogger(getClass()).error("The property " + CoreProperties.SERVER_STARTTIME + " is badly formatted.", e); - } - } - return null; - } - - @Override - public String getURL() { - return StringUtils.removeEnd(StringUtils.defaultIfBlank(settings.getString("sonar.host.url"), "http://localhost:9000"), "/"); - } - - @Override - public String getPermanentServerId() { - return settings.getString(CoreProperties.PERMANENT_SERVER_ID); - } -} diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ArtifactDownloader.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ArtifactDownloader.java deleted file mode 100644 index 158dac6bbca..00000000000 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ArtifactDownloader.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Sonar, open source software quality management tool. - * Copyright (C) 2008-2012 SonarSource - * mailto:contact AT sonarsource DOT com - * - * Sonar 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. - * - * Sonar 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 Sonar; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 - */ -package org.sonar.batch.bootstrap; - -import com.google.common.collect.Lists; -import org.apache.commons.io.FileUtils; -import org.apache.commons.lang.CharUtils; -import org.apache.commons.lang.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.sonar.api.BatchComponent; -import org.sonar.api.utils.HttpDownloader; -import org.sonar.api.utils.SonarException; -import org.sonar.batch.ServerMetadata; -import org.sonar.core.plugins.RemotePlugin; - -import java.io.File; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.List; - -public class ArtifactDownloader implements BatchComponent { - - private static final Logger LOG = LoggerFactory.getLogger(ArtifactDownloader.class); - - private HttpDownloader httpDownloader; - private TempDirectories workingDirectories; - private String baseUrl; - - public ArtifactDownloader(HttpDownloader httpDownloader, TempDirectories workingDirectories, ServerMetadata server) { - this.httpDownloader = httpDownloader; - this.workingDirectories = workingDirectories; - this.baseUrl = server.getURL(); - } - - public File downloadJdbcDriver() { - String url = baseUrl + "/deploy/jdbc-driver.jar"; - try { - File jdbcDriver = new File(workingDirectories.getRoot(), "jdbc-driver.jar"); - LOG.debug("Downloading JDBC driver to " + jdbcDriver); - httpDownloader.download(new URI(url), jdbcDriver); - return jdbcDriver; - - } catch (URISyntaxException e) { - throw new SonarException("Fail to download the JDBC driver from : " + url, e); - } - } - - public List downloadPlugin(RemotePlugin remote) { - try { - File targetDir = workingDirectories.getDir("plugins/" + remote.getKey()); - FileUtils.forceMkdir(targetDir); - LOG.debug("Downloading plugin " + remote.getKey() + " into " + targetDir); - - List files = Lists.newArrayList(); - for (String filename : remote.getFilenames()) { - String url = baseUrl + "/deploy/plugins/" + remote.getKey() + "/" + filename; - File toFile = new File(targetDir, filename); - httpDownloader.download(new URI(url), toFile); - files.add(toFile); - } - - - return files; - - } catch (Exception e) { - throw new SonarException("Fail to download plugin: " + remote.getKey(), e); - } - } - - public List downloadPluginIndex() { - String url = baseUrl + "/deploy/plugins/index.txt"; - try { - LOG.debug("Downloading index of plugins"); - String indexContent = httpDownloader.downloadPlainText(new URI(url), "UTF-8"); - String[] rows = StringUtils.split(indexContent, CharUtils.LF); - List remoteLocations = Lists.newArrayList(); - for (String row : rows) { - remoteLocations.add(RemotePlugin.unmarshal(row)); - } - return remoteLocations; - - } catch (Exception e) { - throw new SonarException("Fail to download plugins index: " + url, e); - } - } - -} diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchPluginRepository.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchPluginRepository.java index 4572355f661..812cebf8d1e 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchPluginRepository.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchPluginRepository.java @@ -50,15 +50,15 @@ public class BatchPluginRepository implements PluginRepository { private static final String CORE_PLUGIN = "core"; private static final String ENGLISH_PACK_PLUGIN = "l10nen"; - private ArtifactDownloader artifactDownloader; + private PluginDownloader pluginDownloader; private Map pluginsByKey; private Map metadataByKey; private Set whiteList = null; private Set blackList = null; private PluginClassloaders classLoaders; - public BatchPluginRepository(ArtifactDownloader artifactDownloader, Settings settings) { - this.artifactDownloader = artifactDownloader; + public BatchPluginRepository(PluginDownloader pluginDownloader, Settings settings) { + this.pluginDownloader = pluginDownloader; if (settings.hasKey(CoreProperties.BATCH_INCLUDE_PLUGINS)) { whiteList = Sets.newTreeSet(Arrays.asList(settings.getStringArray(CoreProperties.BATCH_INCLUDE_PLUGINS))); LOG.info("Include plugins: " + Joiner.on(", ").join(whiteList)); @@ -70,7 +70,7 @@ public class BatchPluginRepository implements PluginRepository { } public void start() { - doStart(artifactDownloader.downloadPluginIndex()); + doStart(pluginDownloader.downloadPluginIndex()); } void doStart(List remotePlugins) { @@ -78,7 +78,7 @@ public class BatchPluginRepository implements PluginRepository { metadataByKey = Maps.newHashMap(); for (RemotePlugin remote : remotePlugins) { if (isAccepted(remote.getKey())) { - List pluginFiles = artifactDownloader.downloadPlugin(remote); + List pluginFiles = pluginDownloader.downloadPlugin(remote); List extensionFiles = pluginFiles.subList(1, pluginFiles.size()); PluginMetadata metadata = extractor.installInSameLocation(pluginFiles.get(0), remote.isCore(), extensionFiles); if (StringUtils.isBlank(metadata.getBasePlugin()) || isAccepted(metadata.getBasePlugin())) { diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapModule.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapModule.java index d7dedb1c1e1..0c7e9bd997d 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapModule.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapModule.java @@ -26,8 +26,6 @@ import org.sonar.api.utils.HttpDownloader; import org.sonar.api.utils.UriReader; import org.sonar.batch.FakeMavenPluginExecutor; import org.sonar.batch.MavenPluginExecutor; -import org.sonar.batch.RemoteServerMetadata; -import org.sonar.batch.ServerMetadata; import org.sonar.batch.config.BatchDatabaseSettingsLoader; import org.sonar.batch.config.BootstrapSettings; import org.sonar.batch.local.LocalDatabase; @@ -63,13 +61,12 @@ public class BootstrapModule extends Module { container.addSingleton(ExtensionInstaller.class); container.addSingleton(DryRun.class); container.addSingleton(Logback.class); - container.addSingleton(ServerMetadata.class);// registered here because used by BootstrapClassLoader - container.addSingleton(TempDirectories.class);// registered here because used by BootstrapClassLoader - container.addSingleton(HttpDownloader.class);// registered here because used by BootstrapClassLoader - container.addSingleton(UriReader.class);// registered here because used by BootstrapClassLoader - container.addSingleton(ArtifactDownloader.class);// registered here because used by BootstrapClassLoader + container.addSingleton(ServerClient.class); + container.addSingleton(TempDirectories.class); + container.addSingleton(HttpDownloader.class); + container.addSingleton(UriReader.class); + container.addSingleton(PluginDownloader.class); container.addSingleton(EmailSettings.class); - container.addSingleton(RemoteServerMetadata.class); container.addSingleton(I18nManager.class); container.addSingleton(RuleI18nManager.class); for (Object component : boostrapperComponents) { diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/DatabaseBatchCompatibility.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/DatabaseBatchCompatibility.java index 5b7ec00d86f..45aaf4180c1 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/DatabaseBatchCompatibility.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/DatabaseBatchCompatibility.java @@ -22,9 +22,7 @@ package org.sonar.batch.bootstrap; import org.sonar.api.BatchComponent; import org.sonar.api.config.Settings; import org.sonar.api.database.DatabaseProperties; -import org.sonar.api.platform.Server; import org.sonar.api.utils.SonarException; -import org.sonar.batch.RemoteServerMetadata; import org.sonar.core.persistence.BadDatabaseVersion; import org.sonar.core.persistence.DatabaseVersion; @@ -36,15 +34,13 @@ import java.io.IOException; public class DatabaseBatchCompatibility implements BatchComponent { private DatabaseVersion version; - private Server server; private Settings settings; - private RemoteServerMetadata remoteServer; + private ServerClient server; - public DatabaseBatchCompatibility(DatabaseVersion version, Server server, RemoteServerMetadata remoteServer, Settings settings) { + public DatabaseBatchCompatibility(DatabaseVersion version, ServerClient server, Settings settings) { this.version = version; this.server = server; this.settings = settings; - this.remoteServer = remoteServer; } public void start() { @@ -55,7 +51,7 @@ public class DatabaseBatchCompatibility implements BatchComponent { private void checkCorrectServerId() { String remoteServerId; try { - remoteServerId = remoteServer.getServerId(); + remoteServerId = server.getServerId(); } catch (IOException e) { throw new SonarException("Impossible to get the ID of the remote server: " + server.getURL(), e); } diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/JdbcDriverHolder.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/JdbcDriverHolder.java index 8de5ca9147d..dd6b47ab311 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/JdbcDriverHolder.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/JdbcDriverHolder.java @@ -19,6 +19,7 @@ */ package org.sonar.batch.bootstrap; +import com.google.common.annotations.VisibleForTesting; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sonar.api.utils.SonarException; @@ -37,13 +38,27 @@ import java.util.List; public class JdbcDriverHolder { private static final Logger LOG = LoggerFactory.getLogger(JdbcDriverHolder.class); + + private TempDirectories tempDirectories; + private ServerClient serverClient; + + // initialized in start() private JdbcDriverClassLoader classLoader; - public JdbcDriverHolder(ArtifactDownloader extensionDownloader) { - this(extensionDownloader.downloadJdbcDriver()); + public JdbcDriverHolder(TempDirectories tempDirectories, ServerClient serverClient) { + this.tempDirectories = tempDirectories; + this.serverClient = serverClient; + } + + public void start() { + File jdbcDriver = new File(tempDirectories.getRoot(), "jdbc-driver.jar"); + serverClient.download("/deploy/jdbc-driver.jar", jdbcDriver); + classLoader = initClassloader(jdbcDriver); } - JdbcDriverHolder(File jdbcDriver) { + @VisibleForTesting + static JdbcDriverClassLoader initClassloader(File jdbcDriver) { + JdbcDriverClassLoader classLoader; try { ClassLoader parentClassLoader = JdbcDriverHolder.class.getClassLoader(); classLoader = new JdbcDriverClassLoader(jdbcDriver.toURI().toURL(), parentClassLoader); @@ -51,15 +66,10 @@ public class JdbcDriverHolder { } catch (MalformedURLException e) { throw new SonarException("Fail to get URL of : " + jdbcDriver.getAbsolutePath(), e); } - } - public URLClassLoader getClassLoader() { - return classLoader; - } - - public void start() { // set as the current context classloader for hibernate, else it does not find the JDBC driver. Thread.currentThread().setContextClassLoader(classLoader); + return classLoader; } /** @@ -88,7 +98,7 @@ public class JdbcDriverHolder { classLoader = null; } - private static class JdbcDriverClassLoader extends URLClassLoader { + static class JdbcDriverClassLoader extends URLClassLoader { public JdbcDriverClassLoader(URL jdbcDriver, ClassLoader parent) { super(new URL[]{jdbcDriver}, parent); diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/PluginDownloader.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/PluginDownloader.java new file mode 100644 index 00000000000..606f2f63413 --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/PluginDownloader.java @@ -0,0 +1,84 @@ +/* +* Sonar, open source software quality management tool. +* Copyright (C) 2008-2012 SonarSource +* mailto:contact AT sonarsource DOT com +* +* Sonar 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. +* +* Sonar 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 Sonar; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 +*/ +package org.sonar.batch.bootstrap; + +import com.google.common.collect.Lists; +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang.CharUtils; +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.sonar.api.BatchComponent; +import org.sonar.api.utils.SonarException; +import org.sonar.core.plugins.RemotePlugin; + +import java.io.File; +import java.util.List; + +public class PluginDownloader implements BatchComponent { + + private static final Logger LOG = LoggerFactory.getLogger(PluginDownloader.class); + + private TempDirectories workingDirectories; + private ServerClient server; + + public PluginDownloader(TempDirectories workingDirectories, ServerClient server) { + this.workingDirectories = workingDirectories; + this.server = server; + } + + public List downloadPlugin(RemotePlugin remote) { + try { + File targetDir = workingDirectories.getDir("plugins/" + remote.getKey()); + FileUtils.forceMkdir(targetDir); + LOG.debug("Downloading plugin " + remote.getKey() + " into " + targetDir); + + List files = Lists.newArrayList(); + for (String filename : remote.getFilenames()) { + String url = "/deploy/plugins/" + remote.getKey() + "/" + filename; + File toFile = new File(targetDir, filename); + server.download(url, toFile); + files.add(toFile); + } + return files; + + } catch (Exception e) { + throw new SonarException("Fail to download plugin: " + remote.getKey(), e); + } + } + + public List downloadPluginIndex() { + String url = "/deploy/plugins/index.txt"; + try { + LOG.debug("Downloading index of plugins"); + String indexContent = server.request(url); + String[] rows = StringUtils.split(indexContent, CharUtils.LF); + List remoteLocations = Lists.newArrayList(); + for (String row : rows) { + remoteLocations.add(RemotePlugin.unmarshal(row)); + } + return remoteLocations; + + } catch (Exception e) { + throw new SonarException("Fail to download plugins index: " + url, e); + } + } + +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectExclusions.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectExclusions.java index 148fb355824..f13a84f71be 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectExclusions.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectExclusions.java @@ -77,7 +77,6 @@ public class ProjectExclusions implements BatchComponent { project.remove(); } - // TODO see http://jira.codehaus.org/browse/SONAR-2324 static String key(ProjectDefinition project) { String key = project.getKey(); if (key.contains(":")) { diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ServerClient.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ServerClient.java new file mode 100644 index 00000000000..2634faec1ef --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ServerClient.java @@ -0,0 +1,142 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch.bootstrap; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Preconditions; +import com.google.common.base.Strings; +import com.google.common.io.Files; +import com.google.common.io.InputSupplier; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.StringUtils; +import org.slf4j.LoggerFactory; +import org.sonar.api.BatchComponent; +import org.sonar.api.CoreProperties; +import org.sonar.api.config.Settings; +import org.sonar.api.platform.Server; +import org.sonar.api.utils.HttpDownloader; +import org.sonar.api.utils.SonarException; +import org.sonar.batch.bootstrapper.EnvironmentInformation; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * @since 3.4 + */ +public class ServerClient extends Server implements BatchComponent { + private Settings settings; + private EnvironmentInformation env; + + public ServerClient(Settings settings, EnvironmentInformation env) { + this.settings = settings; + this.env = env; + } + + @Override + public String getId() { + return settings.getString(CoreProperties.SERVER_ID); + } + + @Override + public String getVersion() { + return settings.getString(CoreProperties.SERVER_VERSION); + } + + @Override + public Date getStartedAt() { + String dateString = settings.getString(CoreProperties.SERVER_STARTTIME); + if (dateString != null) { + try { + return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").parse(dateString); + + } catch (ParseException e) { + LoggerFactory.getLogger(getClass()).error("The property " + CoreProperties.SERVER_STARTTIME + " is badly formatted.", e); + } + } + return null; + } + + @Override + public String getURL() { + return StringUtils.removeEnd(StringUtils.defaultIfBlank(settings.getString("sonar.host.url"), "http://localhost:9000"), "/"); + } + + @Override + public String getPermanentServerId() { + return settings.getString(CoreProperties.PERMANENT_SERVER_ID); + } + + public String getServerId() throws IOException { + String remoteServerInfo = request("/api/server"); + // don't use JSON utilities to extract ID from such a small string + return extractServerId(remoteServerInfo); + } + + @VisibleForTesting + String extractServerId(String remoteServerInfo) { + String partialId = StringUtils.substringAfter(remoteServerInfo, "\"id\":\""); + return StringUtils.substringBefore(partialId, "\""); + } + + public void download(String pathStartingWithSlash, File toFile) { + try { + InputSupplier inputSupplier = doRequest(pathStartingWithSlash); + Files.copy(inputSupplier, toFile); + } catch (Exception e) { + throw new SonarException(String.format("Unable to download '%s' to: %s", pathStartingWithSlash, toFile), e); + } + } + + public String request(String pathStartingWithSlash) { + InputSupplier inputSupplier = doRequest(pathStartingWithSlash); + try { + return IOUtils.toString(inputSupplier.getInput(), "UTF-8"); + } catch (IOException e) { + throw new SonarException(String.format("Unable to request: %s", pathStartingWithSlash), e); + } + } + + private InputSupplier doRequest(String pathStartingWithSlash) { + Preconditions.checkArgument(pathStartingWithSlash.startsWith("/"), "Path must start with slash /"); + + URI uri = URI.create(getURL() + pathStartingWithSlash); + String login = settings.getString(CoreProperties.LOGIN); + + try { + HttpDownloader.BaseHttpDownloader downloader = new HttpDownloader.BaseHttpDownloader(settings, env.toString()); + InputSupplier inputSupplier; + if (Strings.isNullOrEmpty(login)) { + inputSupplier = downloader.newInputSupplier(uri); + } else { + inputSupplier = downloader.newInputSupplier(uri, login, settings.getString(CoreProperties.PASSWORD)); + } + return inputSupplier; + } catch (Exception e) { + throw new SonarException(String.format("Unable to request: %s", uri), e); + } + } + +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrapper/EnvironmentInformation.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrapper/EnvironmentInformation.java index 2845f1776ef..fc46b57d8b6 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrapper/EnvironmentInformation.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrapper/EnvironmentInformation.java @@ -51,4 +51,8 @@ public class EnvironmentInformation implements BatchComponent { return version; } + @Override + public String toString() { + return String.format("%s/%s", key, version); + } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/local/LocalDatabase.java b/sonar-batch/src/main/java/org/sonar/batch/local/LocalDatabase.java index be9b447ab89..42b466ffe8b 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/local/LocalDatabase.java +++ b/sonar-batch/src/main/java/org/sonar/batch/local/LocalDatabase.java @@ -19,23 +19,15 @@ */ package org.sonar.batch.local; -import com.google.common.base.Strings; -import com.google.common.io.Files; -import com.google.common.io.InputSupplier; import org.sonar.api.BatchComponent; -import org.sonar.api.CoreProperties; +import org.sonar.api.batch.bootstrap.ProjectReactor; import org.sonar.api.config.Settings; import org.sonar.api.database.DatabaseProperties; -import org.sonar.api.platform.Server; -import org.sonar.api.utils.HttpDownloader; -import org.sonar.api.utils.SonarException; import org.sonar.batch.bootstrap.DryRun; +import org.sonar.batch.bootstrap.ServerClient; import org.sonar.batch.bootstrap.TempDirectories; import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.net.URI; /** * @since 3.4 @@ -48,61 +40,42 @@ public class LocalDatabase implements BatchComponent { private static final String USER = "sonar"; private static final String PASSWORD = "sonar"; - private final DryRun localMode; + private final DryRun dryRun; private final Settings settings; - private final Server server; + private final ServerClient server; + private ProjectReactor reactor; private final TempDirectories tempDirectories; - public LocalDatabase(DryRun localMode, Settings settings, Server server, TempDirectories tempDirectories) { - this.localMode = localMode; + public LocalDatabase(DryRun dryRun, Settings settings, ServerClient server, TempDirectories tempDirectories, ProjectReactor reactor) { + this.dryRun = dryRun; this.settings = settings; this.server = server; + this.reactor = reactor; this.tempDirectories = tempDirectories; } public void start() { - if (!localMode.isEnabled()) { + if (!dryRun.isEnabled()) { return; } File file = tempDirectories.getFile("local", "db.h2.db"); String h2DatabasePath = file.getAbsolutePath().replaceAll(".h2.db", ""); - downloadDatabase(file); + downloadDatabase(reactor.getRoot().getKey(), file); replaceSettings(h2DatabasePath); } - private void downloadDatabase(File toFile) { - String login = settings.getString(CoreProperties.LOGIN); - String password = settings.getString(CoreProperties.PASSWORD); - String resourceKey = settings.getString("sonar.resource"); - if (null == resourceKey) { - throw new SonarException("No resource key was provided using sonar.resource property"); - } - - URI uri = URI.create(server.getURL() + API_SYNCHRO + "?resource=" + resourceKey); - - HttpDownloader.BaseHttpDownloader downloader = new HttpDownloader.BaseHttpDownloader(settings, null); - InputSupplier inputSupplier; - if (Strings.isNullOrEmpty(login)) { - inputSupplier = downloader.newInputSupplier(uri); - } else { - inputSupplier = downloader.newInputSupplier(uri, login, password); - } - - try { - Files.copy(inputSupplier, toFile); - } catch (IOException e) { - throw new SonarException("Unable to save local database to file: " + toFile, e); - } + private void downloadDatabase(String projectKey, File toFile) { + server.download(API_SYNCHRO + "?resource=" + projectKey, toFile); } private void replaceSettings(String h2DatabasePath) { settings - .setProperty(DatabaseProperties.PROP_DIALECT, DIALECT) - .setProperty(DatabaseProperties.PROP_DRIVER, DRIVER) - .setProperty(DatabaseProperties.PROP_USER, USER) - .setProperty(DatabaseProperties.PROP_PASSWORD, PASSWORD) - .setProperty(DatabaseProperties.PROP_URL, URL + h2DatabasePath); + .setProperty(DatabaseProperties.PROP_DIALECT, DIALECT) + .setProperty(DatabaseProperties.PROP_DRIVER, DRIVER) + .setProperty(DatabaseProperties.PROP_USER, USER) + .setProperty(DatabaseProperties.PROP_PASSWORD, PASSWORD) + .setProperty(DatabaseProperties.PROP_URL, URL + h2DatabasePath); } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/phases/UpdateStatusJob.java b/sonar-batch/src/main/java/org/sonar/batch/phases/UpdateStatusJob.java index 66eb3383f5b..0862c928ab3 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/phases/UpdateStatusJob.java +++ b/sonar-batch/src/main/java/org/sonar/batch/phases/UpdateStatusJob.java @@ -24,22 +24,23 @@ import org.sonar.api.BatchComponent; import org.sonar.api.database.DatabaseSession; import org.sonar.api.database.model.Snapshot; import org.sonar.api.resources.Scopes; -import org.sonar.batch.ServerMetadata; +import org.sonar.batch.bootstrap.ServerClient; import org.sonar.batch.index.ResourcePersister; import org.sonar.core.NotDryRun; import javax.persistence.Query; + import java.util.List; @NotDryRun public class UpdateStatusJob implements BatchComponent { private DatabaseSession session; - private ServerMetadata server; + private ServerClient server; private Snapshot snapshot; // TODO remove this component private ResourcePersister resourcePersister; - public UpdateStatusJob(ServerMetadata server, DatabaseSession session, ResourcePersister resourcePersister, Snapshot snapshot) { + public UpdateStatusJob(ServerClient server, DatabaseSession session, ResourcePersister resourcePersister, Snapshot snapshot) { this.session = session; this.server = server; this.resourcePersister = resourcePersister; diff --git a/sonar-batch/src/test/java/org/sonar/batch/RemoteServerMetadataTest.java b/sonar-batch/src/test/java/org/sonar/batch/RemoteServerMetadataTest.java deleted file mode 100644 index 5a99dbf5ce1..00000000000 --- a/sonar-batch/src/test/java/org/sonar/batch/RemoteServerMetadataTest.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Sonar, open source software quality management tool. - * Copyright (C) 2008-2012 SonarSource - * mailto:contact AT sonarsource DOT com - * - * Sonar 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. - * - * Sonar 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 Sonar; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 - */ -package org.sonar.batch; - -import org.junit.Before; -import org.junit.Test; -import org.sonar.api.platform.Server; - -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class RemoteServerMetadataTest { - - private RemoteServerMetadata remoteServerMetadata; - - @Before - public void init() throws Exception { - Server server = mock(Server.class); - when(server.getURL()).thenReturn("http://localhost:8080"); - - remoteServerMetadata = new RemoteServerMetadata(server); - } - - @Test - public void shouldExtractId() throws Exception { - assertThat(remoteServerMetadata.extractId("{\"id\":\"123456\",\"version\":\"3.1\",\"status\":\"UP\"}"), is("123456")); - } - - @Test - public void shouldGiveUrlForPath() throws Exception { - assertThat(remoteServerMetadata.getUrlFor("/api/server"), is("http://localhost:8080/api/server")); - } - - @Test - public void handleLastSlash() throws Exception { - Server server = mock(Server.class); - when(server.getURL()).thenReturn("http://localhost:8080/"); - - remoteServerMetadata = new RemoteServerMetadata(server); - assertThat(remoteServerMetadata.getUrlFor("/api/server"), is("http://localhost:8080/api/server")); - } - -} diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ArtifactDownloaderTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ArtifactDownloaderTest.java deleted file mode 100644 index b3a3b5b07df..00000000000 --- a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ArtifactDownloaderTest.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Sonar, open source software quality management tool. - * Copyright (C) 2008-2012 SonarSource - * mailto:contact AT sonarsource DOT com - * - * Sonar 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. - * - * Sonar 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 Sonar; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 - */ -package org.sonar.batch.bootstrap; - -import org.junit.Test; -import org.sonar.api.utils.HttpDownloader; -import org.sonar.batch.ServerMetadata; - -import java.io.File; -import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; - -import static org.junit.Assert.assertNotNull; -import static org.mockito.Mockito.*; - -public class ArtifactDownloaderTest { - - @Test - public void shouldDownloadJdbcDriver() throws IOException, URISyntaxException { - ServerMetadata server = mock(ServerMetadata.class); - when(server.getURL()).thenReturn("http://sonar:8000"); - - HttpDownloader httpDownloader = mock(HttpDownloader.class); - TempDirectories workingDirectories = new TempDirectories(); - - ArtifactDownloader downloader = new ArtifactDownloader(httpDownloader, workingDirectories, server); - File jdbcDriver = downloader.downloadJdbcDriver(); - - assertNotNull(jdbcDriver); - verify(httpDownloader).download(new URI("http://sonar:8000/deploy/jdbc-driver.jar"), jdbcDriver); - } - -// @Test -// public void shouldDownloadExtension() throws IOException, URISyntaxException { -// ServerMetadata server = mock(ServerMetadata.class); -// when(server.getURL()).thenReturn("http://sonar:8000"); -// -// HttpDownloader httpDownloader = mock(HttpDownloader.class); -// TempDirectories workingDirectories = new TempDirectories(); -// -// ArtifactDownloader downloader = new ArtifactDownloader(httpDownloader, workingDirectories, server); -// JpaPluginFile extension = new JpaPluginFile(new JpaPlugin("findbugs"), "bcel.jar"); -// File bcel = downloader.downloadExtension(extension); -// -// assertNotNull(bcel); -// verify(httpDownloader).download(new URI("http://sonar:8000/deploy/plugins/findbugs/bcel.jar"), bcel); -// } -} diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchDatabaseTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchDatabaseTest.java new file mode 100644 index 00000000000..0be5a53f54c --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchDatabaseTest.java @@ -0,0 +1,42 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch.bootstrap; + +import org.junit.Test; +import org.sonar.api.config.Settings; + +import java.util.Properties; + +import static org.fest.assertions.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +public class BatchDatabaseTest { + @Test + public void should_init_at_least_two_connections() { + BatchDatabase db = new BatchDatabase(new Settings(), mock(JdbcDriverHolder.class)); + Properties props = new Properties(); + + db.doCompleteProperties(props); + + assertThat(Integer.parseInt(props.getProperty("sonar.jdbc.initialSize"))).isGreaterThanOrEqualTo(2); + assertThat(Integer.parseInt(props.getProperty("sonar.jdbc.maxActive"))).isGreaterThanOrEqualTo(2); + } + +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchPluginRepositoryTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchPluginRepositoryTest.java index be647dc89a9..080e48c767c 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchPluginRepositoryTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchPluginRepositoryTest.java @@ -55,7 +55,7 @@ public class BatchPluginRepositoryTest { public void shouldLoadPlugin() throws IOException { RemotePlugin checkstyle = new RemotePlugin("checkstyle", true); - ArtifactDownloader downloader = mock(ArtifactDownloader.class); + PluginDownloader downloader = mock(PluginDownloader.class); when(downloader.downloadPlugin(checkstyle)).thenReturn(copyFiles("sonar-checkstyle-plugin-2.8.jar")); repository = new BatchPluginRepository(downloader, new Settings()); @@ -74,7 +74,7 @@ public class BatchPluginRepositoryTest { RemotePlugin checkstyle = new RemotePlugin("checkstyle", true); RemotePlugin checkstyleExt = new RemotePlugin("checkstyleextensions", false); - ArtifactDownloader downloader = mock(ArtifactDownloader.class); + PluginDownloader downloader = mock(PluginDownloader.class); when(downloader.downloadPlugin(checkstyle)).thenReturn(copyFiles("sonar-checkstyle-plugin-2.8.jar")); when(downloader.downloadPlugin(checkstyleExt)).thenReturn(copyFiles("sonar-checkstyle-extensions-plugin-0.1-SNAPSHOT.jar")); @@ -95,7 +95,7 @@ public class BatchPluginRepositoryTest { RemotePlugin checkstyle = new RemotePlugin("checkstyle", true) .addFilename("checkstyle-ext.xml"); - ArtifactDownloader downloader = mock(ArtifactDownloader.class); + PluginDownloader downloader = mock(PluginDownloader.class); when(downloader.downloadPlugin(checkstyle)).thenReturn(copyFiles("sonar-checkstyle-plugin-2.8.jar", "checkstyle-ext.xml")); repository = new BatchPluginRepository(downloader, new Settings()); @@ -115,7 +115,7 @@ public class BatchPluginRepositoryTest { RemotePlugin checkstyle = new RemotePlugin("checkstyle", true); RemotePlugin checkstyleExt = new RemotePlugin("checkstyleextensions", false); - ArtifactDownloader downloader = mock(ArtifactDownloader.class); + PluginDownloader downloader = mock(PluginDownloader.class); when(downloader.downloadPlugin(checkstyle)).thenReturn(copyFiles("sonar-checkstyle-plugin-2.8.jar")); when(downloader.downloadPlugin(checkstyleExt)).thenReturn(copyFiles("sonar-checkstyle-extensions-plugin-0.1-SNAPSHOT.jar")); @@ -143,7 +143,7 @@ public class BatchPluginRepositoryTest { @Test public void shouldAlwaysAcceptIfNoWhiteListAndBlackList() { - repository = new BatchPluginRepository(mock(ArtifactDownloader.class), new Settings()); + repository = new BatchPluginRepository(mock(PluginDownloader.class), new Settings()); assertThat(repository.isAccepted("pmd"), Matchers.is(true)); } @@ -152,7 +152,7 @@ public class BatchPluginRepositoryTest { Settings settings = new Settings(); settings.setProperty(CoreProperties.BATCH_INCLUDE_PLUGINS, "checkstyle,pmd,findbugs"); settings.setProperty(CoreProperties.BATCH_EXCLUDE_PLUGINS, "cobertura,pmd"); - repository = new BatchPluginRepository(mock(ArtifactDownloader.class), settings); + repository = new BatchPluginRepository(mock(PluginDownloader.class), settings); assertThat(repository.isAccepted("pmd"), Matchers.is(true)); } @@ -161,7 +161,7 @@ public class BatchPluginRepositoryTest { public void corePluginShouldAlwaysBeInWhiteList() { Settings settings = new Settings(); settings.setProperty(CoreProperties.BATCH_INCLUDE_PLUGINS, "checkstyle,pmd,findbugs"); - repository = new BatchPluginRepository(mock(ArtifactDownloader.class), settings); + repository = new BatchPluginRepository(mock(PluginDownloader.class), settings); assertThat(repository.isAccepted("core"), Matchers.is(true)); } @@ -169,7 +169,7 @@ public class BatchPluginRepositoryTest { public void corePluginShouldNeverBeInBlackList() { Settings settings = new Settings(); settings.setProperty(CoreProperties.BATCH_EXCLUDE_PLUGINS, "core,findbugs"); - repository = new BatchPluginRepository(mock(ArtifactDownloader.class), settings); + repository = new BatchPluginRepository(mock(PluginDownloader.class), settings); assertThat(repository.isAccepted("core"), Matchers.is(true)); } @@ -178,7 +178,7 @@ public class BatchPluginRepositoryTest { public void englishPackPluginShouldNeverBeInBlackList() { Settings settings = new Settings(); settings.setProperty(CoreProperties.BATCH_EXCLUDE_PLUGINS, "l10nen,findbugs"); - repository = new BatchPluginRepository(mock(ArtifactDownloader.class), settings); + repository = new BatchPluginRepository(mock(PluginDownloader.class), settings); assertThat(repository.isAccepted("l10nen"), Matchers.is(true)); } @@ -186,7 +186,7 @@ public class BatchPluginRepositoryTest { public void shouldCheckWhitelist() { Settings settings = new Settings(); settings.setProperty(CoreProperties.BATCH_INCLUDE_PLUGINS, "checkstyle,pmd,findbugs"); - repository = new BatchPluginRepository(mock(ArtifactDownloader.class), settings); + repository = new BatchPluginRepository(mock(PluginDownloader.class), settings); assertThat(repository.isAccepted("checkstyle"), Matchers.is(true)); assertThat(repository.isAccepted("pmd"), Matchers.is(true)); @@ -197,7 +197,7 @@ public class BatchPluginRepositoryTest { public void shouldCheckBlackListIfNoWhiteList() { Settings settings = new Settings(); settings.setProperty(CoreProperties.BATCH_EXCLUDE_PLUGINS, "checkstyle,pmd,findbugs"); - repository = new BatchPluginRepository(mock(ArtifactDownloader.class), settings); + repository = new BatchPluginRepository(mock(PluginDownloader.class), settings); assertThat(repository.isAccepted("checkstyle"), Matchers.is(false)); assertThat(repository.isAccepted("pmd"), Matchers.is(false)); diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/DatabaseBatchCompatibilityTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/DatabaseBatchCompatibilityTest.java index eb2c719a8ee..6e9e1e4cade 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/DatabaseBatchCompatibilityTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/DatabaseBatchCompatibilityTest.java @@ -25,9 +25,7 @@ import org.junit.Test; import org.junit.rules.ExpectedException; import org.sonar.api.config.Settings; import org.sonar.api.database.DatabaseProperties; -import org.sonar.api.platform.Server; import org.sonar.api.utils.SonarException; -import org.sonar.batch.RemoteServerMetadata; import org.sonar.core.persistence.BadDatabaseVersion; import org.sonar.core.persistence.DatabaseVersion; @@ -42,24 +40,21 @@ public class DatabaseBatchCompatibilityTest { public ExpectedException thrown = ExpectedException.none(); private DatabaseVersion databaseVersion; - private Server server; + private ServerClient server; private Settings settings; - private RemoteServerMetadata remoteServerMetadata; @Before public void init() throws Exception { databaseVersion = mock(DatabaseVersion.class); when(databaseVersion.getSonarCoreId()).thenReturn("123456"); - server = mock(Server.class); + server = mock(ServerClient.class); when(server.getURL()).thenReturn("http://localhost:9000"); + when(server.getServerId()).thenReturn("123456"); settings = new Settings(); settings.setProperty(DatabaseProperties.PROP_URL, "jdbc:postgresql://localhost/foo"); settings.setProperty(DatabaseProperties.PROP_USER, "bar"); - - remoteServerMetadata = mock(RemoteServerMetadata.class); - when(remoteServerMetadata.getServerId()).thenReturn("123456"); } @Test @@ -69,7 +64,7 @@ public class DatabaseBatchCompatibilityTest { thrown.expect(BadDatabaseVersion.class); thrown.expectMessage("Database relates to a more recent version of Sonar. Please check your settings (JDBC settings, version of Maven plugin)"); - new DatabaseBatchCompatibility(databaseVersion, server, remoteServerMetadata, settings).start(); + new DatabaseBatchCompatibility(databaseVersion, server, settings).start(); } @Test @@ -79,7 +74,7 @@ public class DatabaseBatchCompatibilityTest { thrown.expect(BadDatabaseVersion.class); thrown.expectMessage("Database must be upgraded."); - new DatabaseBatchCompatibility(databaseVersion, server, remoteServerMetadata, settings).start(); + new DatabaseBatchCompatibility(databaseVersion, server, settings).start(); } @Test @@ -92,7 +87,7 @@ public class DatabaseBatchCompatibilityTest { thrown.expectMessage("- Batch side: jdbc:postgresql://localhost/foo (bar / *****)"); thrown.expectMessage("- Server side: check the configuration at http://localhost:9000/system"); - new DatabaseBatchCompatibility(version, server, remoteServerMetadata, settings).start(); + new DatabaseBatchCompatibility(version, server, settings).start(); } @Test @@ -105,23 +100,23 @@ public class DatabaseBatchCompatibilityTest { thrown.expect(BadDatabaseVersion.class); thrown.expectMessage("- Batch side: jdbc:postgresql://localhost/foo (sonar / *****)"); - new DatabaseBatchCompatibility(version, server, remoteServerMetadata, settings).start(); + new DatabaseBatchCompatibility(version, server, settings).start(); } @Test public void shouldFailIfCantGetServerId() throws Exception { - when(remoteServerMetadata.getServerId()).thenThrow(new IOException()); + when(server.getServerId()).thenThrow(new IOException()); thrown.expect(SonarException.class); thrown.expectMessage("Impossible to get the ID of the remote server: http://localhost:9000"); - new DatabaseBatchCompatibility(mock(DatabaseVersion.class), server, remoteServerMetadata, settings).start(); + new DatabaseBatchCompatibility(mock(DatabaseVersion.class), server, settings).start(); } @Test public void shouldDoNothingIfUpToDate() { when(databaseVersion.getStatus()).thenReturn(DatabaseVersion.Status.UP_TO_DATE); - new DatabaseBatchCompatibility(databaseVersion, server, remoteServerMetadata, settings).start(); + new DatabaseBatchCompatibility(databaseVersion, server, settings).start(); // no error } } diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/JdbcDriverHolderTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/JdbcDriverHolderTest.java index 0edd1e03882..a573dbcc3c9 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/JdbcDriverHolderTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/JdbcDriverHolderTest.java @@ -19,29 +19,40 @@ */ package org.sonar.batch.bootstrap; -import static junit.framework.Assert.assertNotNull; -import static junit.framework.Assert.assertNull; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; import java.io.File; import java.net.URISyntaxException; import java.net.URL; -import org.junit.Test; +import static org.fest.assertions.Assertions.assertThat; public class JdbcDriverHolderTest { + private ClassLoader initialThreadClassloader; + + @Before + public void before() { + initialThreadClassloader = Thread.currentThread().getContextClassLoader(); + } + + @After + public void after() { + Thread.currentThread().setContextClassLoader(initialThreadClassloader); + } + @Test - public void testClassLoader() throws URISyntaxException { + public void should_extend_classloader_with_jdbc_driver() throws URISyntaxException { /* foo.jar has just one file /foo/foo.txt */ - assertNull(getClass().getClassLoader().getResource("foo/foo.txt")); + assertThat(getClass().getClassLoader().getResource("foo/foo.txt")).isNull(); URL url = getClass().getResource("/org/sonar/batch/bootstrap/JdbcDriverHolderTest/foo.jar"); - JdbcDriverHolder classloader = new JdbcDriverHolder(new File(url.toURI())); - assertNotNull(classloader.getClassLoader()); - assertNotNull(classloader.getClassLoader().getResource("foo/foo.txt")); - - classloader.stop(); - assertNull(classloader.getClassLoader()); + JdbcDriverHolder.JdbcDriverClassLoader classloader = JdbcDriverHolder.initClassloader(new File(url.toURI())); + assertThat(classloader).isNotNull(); + assertThat(classloader.getResource("foo/foo.txt")).isNotNull(); + assertThat(Thread.currentThread().getContextClassLoader()).isSameAs(classloader); } } diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ProjectExclusionsTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ProjectExclusionsTest.java index 8270a05b211..3698c1f2b4e 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ProjectExclusionsTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ProjectExclusionsTest.java @@ -105,6 +105,21 @@ public class ProjectExclusionsTest { ProjectReactor reactor = newReactor("root", "sub1", "sub2"); ProjectExclusions exclusions = new ProjectExclusions(settings, reactor); exclusions.start(); + } + + @Test + public void shouldIgnoreMavenGroupId() { + ProjectReactor reactor = newReactor("org.apache.struts:struts", "org.apache.struts:struts-core", "org.apache.struts:struts-taglib"); + + Settings settings = new Settings(); + settings.setProperty("sonar.skippedModules", "struts-taglib"); + + ProjectExclusions exclusions = new ProjectExclusions(settings, reactor); + exclusions.start(); + + assertThat(reactor.getProject("org.apache.struts:struts")).isNotNull(); + assertThat(reactor.getProject("org.apache.struts:struts-core")).isNotNull(); + assertThat(reactor.getProject("org.apache.struts:struts-taglib")).isNull(); } } diff --git a/sonar-batch/src/test/java/org/sonar/batch/ServerMetadataTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ServerClientTest.java similarity index 50% rename from sonar-batch/src/test/java/org/sonar/batch/ServerMetadataTest.java rename to sonar-batch/src/test/java/org/sonar/batch/bootstrap/ServerClientTest.java index b0d593f78a2..e907cc2fe0d 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/ServerMetadataTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ServerClientTest.java @@ -17,43 +17,48 @@ * License along with Sonar; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 */ -package org.sonar.batch; +package org.sonar.batch.bootstrap; import org.junit.Test; import org.sonar.api.CoreProperties; import org.sonar.api.config.Settings; +import org.sonar.batch.bootstrapper.EnvironmentInformation; -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; +import static org.fest.assertions.Assertions.assertThat; +import static org.mockito.Mockito.mock; -public class ServerMetadataTest { +public class ServerClientTest { @Test - public void testLoadProperties() { - Settings settings = new Settings(); - settings.setProperty(CoreProperties.SERVER_ID, "123"); - settings.setProperty(CoreProperties.SERVER_VERSION, "2.2"); - settings.setProperty(CoreProperties.SERVER_STARTTIME, "2010-05-18T17:59:00+0000"); - settings.setProperty("sonar.host.url", "http://foo.com"); + public void shouldExtractId() throws Exception { + ServerClient server = new ServerClient(new Settings(), mock(EnvironmentInformation.class)); + assertThat(server.extractServerId("{\"id\":\"123456\",\"version\":\"3.1\",\"status\":\"UP\"}")).isEqualTo("123456"); + } - ServerMetadata server = new ServerMetadata(settings); + @Test + public void shouldRemoveUrlEndingSlash() throws Exception { + Settings settings = new Settings(); + settings.setProperty("sonar.host.url", "http://localhost:8080/sonar/"); + ServerClient server = new ServerClient(settings, new EnvironmentInformation("Junit", "4")); - assertThat(server.getId(), is("123")); - assertThat(server.getVersion(), is("2.2")); - assertThat(server.getStartedAt().getDate(), is(18)); - assertThat(server.getURL(), is("http://foo.com")); + assertThat(server.getURL()).isEqualTo("http://localhost:8080/sonar"); } - /** - * http://jira.codehaus.org/browse/SONAR-1685 - * The maven plugin fails if the property sonar.host.url ends with a slash - */ @Test - public void urlMustNotEndWithSlash() { + public void shouldLoadServerProperties() { Settings settings = new Settings(); - settings.setProperty("sonar.host.url", "http://localhost:80/"); + settings.setProperty(CoreProperties.SERVER_ID, "123"); + settings.setProperty(CoreProperties.SERVER_VERSION, "2.2"); + settings.setProperty(CoreProperties.SERVER_STARTTIME, "2010-05-18T17:59:00+0000"); + settings.setProperty(CoreProperties.PERMANENT_SERVER_ID, "abcde"); + settings.setProperty("sonar.host.url", "http://foo.com"); + + ServerClient server = new ServerClient(settings, mock(EnvironmentInformation.class)); - ServerMetadata server = new ServerMetadata(settings); - assertThat(server.getURL(), is("http://localhost:80")); + assertThat(server.getId()).isEqualTo("123"); + assertThat(server.getVersion()).isEqualTo("2.2"); + assertThat(server.getStartedAt().getDate()).isEqualTo(18); + assertThat(server.getURL()).isEqualTo("http://foo.com"); + assertThat(server.getPermanentServerId()).isEqualTo("abcde"); } } diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/TempDirectoriesTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/TempDirectoriesTest.java index c07ca958198..ce5e7929ea7 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/TempDirectoriesTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/TempDirectoriesTest.java @@ -26,9 +26,7 @@ import org.junit.Test; import java.io.File; import java.io.IOException; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertThat; +import static org.fest.assertions.Assertions.assertThat; public class TempDirectoriesTest { @@ -48,36 +46,36 @@ public class TempDirectoriesTest { @Test public void shouldCreateRoot() { - assertNotNull(tempDirectories.getRoot()); - assertThat(tempDirectories.getRoot().exists(), is(true)); - assertThat(tempDirectories.getRoot().isDirectory(), is(true)); + assertThat(tempDirectories.getRoot()).isNotNull(); + assertThat(tempDirectories.getRoot()).exists(); + assertThat(tempDirectories.getRoot()).isDirectory(); } @Test public void shouldCreateDirectory() { File findbugsDir = tempDirectories.getDir("findbugs"); - assertNotNull(findbugsDir); - assertThat(findbugsDir.exists(), is(true)); - assertThat(findbugsDir.getParentFile(), is(tempDirectories.getRoot())); - assertThat(findbugsDir.getName(), is("findbugs")); + assertThat(findbugsDir).isNotNull(); + assertThat(findbugsDir).exists(); + assertThat(findbugsDir.getParentFile()).isEqualTo(tempDirectories.getRoot()); + assertThat(findbugsDir.getName()).isEqualTo("findbugs"); } @Test public void shouldStopAndDeleteDirectory() { File root = tempDirectories.getRoot(); File findbugsDir = tempDirectories.getDir("findbugs"); - assertThat(findbugsDir.exists(), is(true)); + assertThat(findbugsDir).exists(); tempDirectories.stop(); - assertThat(root.exists(), is(false)); - assertThat(findbugsDir.exists(), is(false)); + assertThat(root).doesNotExist(); + assertThat(findbugsDir).doesNotExist(); } @Test public void shouldCreateDirectoryWhenGettingFile() { File file = tempDirectories.getFile("findbugs", "bcel.jar"); - assertNotNull(file); - assertThat(file.getParentFile().getName(), is("findbugs")); + assertThat(file).isNotNull(); + assertThat(file.getParentFile().getName()).isEqualTo("findbugs"); } } diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrapper/EnvironmentInformationTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrapper/EnvironmentInformationTest.java new file mode 100644 index 00000000000..f96ad864857 --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrapper/EnvironmentInformationTest.java @@ -0,0 +1,41 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch.bootstrapper; + +import org.junit.Test; + +import static org.fest.assertions.Assertions.assertThat; + +public class EnvironmentInformationTest { + @Test + public void test_bean() { + EnvironmentInformation env = new EnvironmentInformation("Maven Plugin", "2.0"); + + assertThat(env.getKey()).isEqualTo("Maven Plugin"); + assertThat(env.getVersion()).isEqualTo("2.0"); + } + + @Test + public void test_toString() { + EnvironmentInformation env = new EnvironmentInformation("Maven Plugin", "2.0"); + + assertThat(env.toString()).isEqualTo("Maven Plugin/2.0"); + } +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/phases/UpdateStatusJobTest.java b/sonar-batch/src/test/java/org/sonar/batch/phases/UpdateStatusJobTest.java index 8c318a265d5..0018727b445 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/phases/UpdateStatusJobTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/phases/UpdateStatusJobTest.java @@ -22,7 +22,7 @@ package org.sonar.batch.phases; import org.junit.Test; import org.sonar.api.database.DatabaseSession; import org.sonar.api.database.model.Snapshot; -import org.sonar.batch.ServerMetadata; +import org.sonar.batch.bootstrap.ServerClient; import org.sonar.batch.index.DefaultResourcePersister; import org.sonar.jpa.test.AbstractDbUnitTestCase; @@ -51,7 +51,7 @@ public class UpdateStatusJobTest extends AbstractDbUnitTestCase { setupData("sharedFixture", fixture); DatabaseSession session = getSession(); - UpdateStatusJob sensor = new UpdateStatusJob(mock(ServerMetadata.class), session, new DefaultResourcePersister(session), loadSnapshot(snapshotId)); + UpdateStatusJob sensor = new UpdateStatusJob(mock(ServerClient.class), session, new DefaultResourcePersister(session), loadSnapshot(snapshotId)); sensor.execute(); checkTables(fixture, "snapshots"); diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/CoverageExtension.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/CoverageExtension.java index 09ef5abac6c..c6144d917b3 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/CoverageExtension.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/CoverageExtension.java @@ -22,14 +22,10 @@ package org.sonar.api.batch; import org.sonar.api.BatchExtension; /** - * Marker for extension. Extension which implements this interface would be active, when: - *
    - *
  • corresponding coverage engine activated (see {@link AbstractCoverageExtension#PARAM_PLUGIN}) and language is Java
  • - *
  • type of analysis is dynamic or reuse reports
  • - *
- * + * Marker for the extensions that execute coverage tools. It's useful for the plugins that + * need to be executed after coverage analysis, for example import of test results by the Surefire plugin + * * @since 2.6 - * @TODO Ability to configure coverage engine per language - http://jira.codehaus.org/browse/SONAR-1803 */ public interface CoverageExtension extends BatchExtension { diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/utils/command/CommandException.java b/sonar-plugin-api/src/main/java/org/sonar/api/utils/command/CommandException.java index b507d5dd0e7..42c32b18a0a 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/utils/command/CommandException.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/utils/command/CommandException.java @@ -19,11 +19,13 @@ */ package org.sonar.api.utils.command; +import javax.annotation.Nullable; + public final class CommandException extends RuntimeException { private transient Command command = null; - public CommandException(Command command, String message, Throwable throwable) { + public CommandException(Command command, String message, @Nullable Throwable throwable) { super(message + " [command: " + command + "]", throwable); this.command = command; } -- 2.39.5