<artifactId>fest-assert</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
import java.util.Properties;
public class BatchLauncher {
+ final String isolatedLauncherClass;
- public void execute(Properties properties, List<Object> extensions) {
- FileDownloader fileDownloader = FileDownloader.create(properties);
- ServerVersion serverVersion = new ServerVersion(fileDownloader);
- List<File> jarFiles;
- if (serverVersion.is35Compatible()) {
- jarFiles = new Jars35(fileDownloader, new JarExtractor()).download();
- } else if (serverVersion.is30Compatible()) {
- String workDir = properties.getProperty("sonar.working.directory");
- jarFiles = new Jars30(fileDownloader).download(new File(workDir), new JarExtractor());
- } else {
- throw new IllegalStateException("Sonar " + serverVersion.version()
- + " is not supported. Please upgrade Sonar to version 3.0 or more.");
- }
+ /**
+ * For unit tests
+ */
+ BatchLauncher(String isolatedLauncherClass) {
+ this.isolatedLauncherClass = isolatedLauncherClass;
+ }
+
+ public BatchLauncher() {
+ this.isolatedLauncherClass = "org.sonar.runner.batch.IsolatedLauncher";
+ }
+
+ public void execute(Properties props, List<Object> extensions) {
+ ServerConnection serverConnection = ServerConnection.create(props);
+ ServerVersion serverVersion = new ServerVersion(serverConnection);
+ JarDownloader jarDownloader = new JarDownloader(props, serverConnection, serverVersion);
+ doExecute(jarDownloader, props, extensions);
+ }
- String unmaskedPackages = properties.getProperty(InternalProperties.RUNNER_UNMASKED_PACKAGES, "");
+ /**
+ * @return the {@link IsolatedLauncher} instance for unit tests
+ */
+ Object doExecute(JarDownloader jarDownloader, Properties props, List<Object> extensions) {
+ List<File> jarFiles = jarDownloader.download();
+ String unmaskedPackages = props.getProperty(InternalProperties.RUNNER_UNMASKED_PACKAGES, "");
IsolatedClassloader classloader = new IsolatedClassloader(getClass().getClassLoader(), unmaskedPackages.split(":"));
classloader.addFiles(jarFiles);
- delegateExecution(classloader, properties, extensions);
+ return delegateExecution(classloader, props, extensions);
}
- private void delegateExecution(IsolatedClassloader classloader, Properties properties, List<Object> extensions) {
+ private Object delegateExecution(IsolatedClassloader classloader, Properties properties, List<Object> extensions) {
ClassLoader initialContextClassLoader = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(classloader);
- Class<?> launcherClass = classloader.findClass("org.sonar.runner.batch.IsolatedLauncher");
+ Class<?> launcherClass = classloader.loadClass(isolatedLauncherClass);
Method executeMethod = launcherClass.getMethod("execute", Properties.class, List.class);
Object launcher = launcherClass.newInstance();
executeMethod.invoke(launcher, properties, extensions);
+ return launcher;
} catch (InvocationTargetException e) {
// Unwrap original exception
throw new RunnerException("Unable to execute Sonar", e.getTargetException());
import java.util.Properties;
public class BatchLauncherMain {
- public static void main(String[] args) throws IOException {
+ private final BatchLauncher launcher;
+
+ BatchLauncherMain(BatchLauncher l) {
+ this.launcher = l;
+ }
+
+ void execute(String[] args) throws IOException {
if (args.length == 0) {
throw new IllegalArgumentException("Missing path to properties file");
}
Properties props = loadProperties(args[0]);
- new BatchLauncher().execute(props, Collections.emptyList());
+ launcher.execute(props, Collections.emptyList());
}
- private static Properties loadProperties(String arg) throws IOException {
+ private Properties loadProperties(String arg) throws IOException {
Properties props = new Properties();
FileInputStream input = new FileInputStream(arg);
try {
return props;
}
+ public static void main(String[] args) throws IOException {
+ new BatchLauncherMain(new BatchLauncher()).execute(args);
+ }
}
+++ /dev/null
-/*
- * Sonar Runner - Implementation
- * Copyright (C) 2011 SonarSource
- * dev@sonar.codehaus.org
- *
- * This program 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.
- *
- * This program 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 02
- */
-package org.sonar.runner.impl;
-
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.io.IOUtils;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.net.ConnectException;
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.net.UnknownHostException;
-import java.util.Properties;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-class FileDownloader {
-
-
- static final int CONNECT_TIMEOUT_MILLISECONDS = 30000;
- static final int READ_TIMEOUT_MILLISECONDS = 60000;
- private static final Pattern CHARSET_PATTERN = Pattern.compile("(?i)\\bcharset=\\s*\"?([^\\s;\"]*)");
-
- private final String serverUrl;
- private final String userAgent;
-
- private FileDownloader(String serverUrl, String app, String appVersion) {
- this.serverUrl = serverUrl;
- this.userAgent = app + "/" + appVersion;
- }
-
- static FileDownloader create(Properties properties) {
- String serverUrl = properties.getProperty("sonar.host.url");
- String app = properties.getProperty(InternalProperties.RUNNER_APP);
- String appVersion = properties.getProperty(InternalProperties.RUNNER_APP_VERSION);
- return new FileDownloader(serverUrl, app, appVersion);
- }
-
- void download(String path, File toFile) {
- InputStream input = null;
- FileOutputStream output = null;
- String fullUrl = serverUrl + path;
- try {
- if (Logs.isDebugEnabled()) {
- Logs.debug("Download " + fullUrl + " to " + toFile.getAbsolutePath());
- }
- HttpURLConnection connection = newHttpConnection(new URL(fullUrl));
- int statusCode = connection.getResponseCode();
- if (statusCode != HttpURLConnection.HTTP_OK) {
- throw new IOException("Status returned by url : '" + fullUrl + "' is invalid : " + statusCode);
- }
- output = new FileOutputStream(toFile, false);
- input = connection.getInputStream();
- IOUtils.copyLarge(input, output);
-
- } catch (Exception e) {
- if (e instanceof ConnectException || e instanceof UnknownHostException) {
- Logs.error("Sonar server '" + serverUrl + "' can not be reached");
- }
- IOUtils.closeQuietly(output);
- FileUtils.deleteQuietly(toFile);
- throw new IllegalStateException("Fail to download: " + fullUrl, e);
-
- } finally {
- IOUtils.closeQuietly(input);
- IOUtils.closeQuietly(output);
- }
- }
-
- String downloadString(String path) throws IOException {
- String fullUrl = serverUrl + path;
- HttpURLConnection conn = newHttpConnection(new URL(fullUrl));
- String charset = getCharsetFromContentType(conn.getContentType());
- if (charset == null || "".equals(charset)) {
- charset = "UTF-8";
- }
- Reader reader = null;
- try {
- int statusCode = conn.getResponseCode();
- if (statusCode != HttpURLConnection.HTTP_OK) {
- throw new IOException("Status returned by url : '" + fullUrl + "' is invalid : " + statusCode);
- }
- reader = new InputStreamReader(conn.getInputStream(), charset);
- return IOUtils.toString(reader);
- } catch (IOException e) {
- if (e instanceof ConnectException || e instanceof UnknownHostException) {
- Logs.error("Sonar server '" + serverUrl + "' can not be reached");
- }
- throw e;
-
- } finally {
- IOUtils.closeQuietly(reader);
- conn.disconnect();
- }
- }
-
- private HttpURLConnection newHttpConnection(URL url) throws IOException {
- //TODO send credentials
- HttpURLConnection connection = (HttpURLConnection) url.openConnection();
- connection.setConnectTimeout(CONNECT_TIMEOUT_MILLISECONDS);
- connection.setReadTimeout(READ_TIMEOUT_MILLISECONDS);
- connection.setInstanceFollowRedirects(true);
- connection.setRequestMethod("GET");
- connection.setRequestProperty("User-Agent", userAgent);
- return connection;
- }
-
- /**
- * Parse out a charset from a content type header.
- *
- * @param contentType e.g. "text/html; charset=EUC-JP"
- * @return "EUC-JP", or null if not found. Charset is trimmed and upper-cased.
- */
- static String getCharsetFromContentType(String contentType) {
- if (contentType == null) {
- return null;
- }
-
- Matcher m = CHARSET_PATTERN.matcher(contentType);
- if (m.find()) {
- return m.group(1).trim().toUpperCase();
- }
- return null;
- }
-}
--- /dev/null
+/*
+ * Sonar Runner - Implementation
+ * Copyright (C) 2011 SonarSource
+ * dev@sonar.codehaus.org
+ *
+ * This program 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.
+ *
+ * This program 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 02
+ */
+package org.sonar.runner.impl;
+
+import java.io.File;
+import java.util.List;
+import java.util.Properties;
+
+class JarDownloader {
+ private final ServerConnection serverConnection;
+ private final ServerVersion serverVersion;
+ private final Properties props;
+
+ JarDownloader(Properties props, ServerConnection conn, ServerVersion version) {
+ this.props = props;
+ this.serverConnection = conn;
+ this.serverVersion = version;
+ }
+
+ List<File> download() {
+ List<File> jarFiles;
+ if (serverVersion.is35Compatible()) {
+ jarFiles = download35();
+ } else if (serverVersion.is30Compatible()) {
+ jarFiles = download30();
+ } else {
+ throw new IllegalStateException("Sonar " + serverVersion.version()
+ + " is not supported. Please upgrade Sonar to version 3.0 or more.");
+ }
+ return jarFiles;
+ }
+
+ List<File> download30() {
+ String workDir = props.getProperty("sonar.working.directory");
+ return new Jars30(serverConnection).download(new File(workDir), new JarExtractor());
+ }
+
+ List<File> download35() {
+ return new Jars35(serverConnection, new JarExtractor()).download();
+ }
+}
class Jars30 {
private static final String BATCH_PATH = "/batch/";
- private final FileDownloader downloader;
+ private final ServerConnection downloader;
- Jars30(FileDownloader downloader) {
+ Jars30(ServerConnection downloader) {
this.downloader = downloader;
}
static final String BATCH_PATH = "/batch/";
private final FileCache fileCache;
- private final FileDownloader downloader;
+ private final ServerConnection downloader;
private final JarExtractor jarExtractor;
- Jars35(FileDownloader downloader, JarExtractor jarExtractor) {
+ Jars35(ServerConnection downloader, JarExtractor jarExtractor) {
this.fileCache = new FileCacheBuilder().setLog(new StandardLog()).build();
this.downloader = downloader;
this.jarExtractor = jarExtractor;
}
private static class JarDownloader implements FileCache.Downloader {
- private final FileDownloader downloader;
+ private final ServerConnection downloader;
- private JarDownloader(FileDownloader downloader) {
+ private JarDownloader(ServerConnection downloader) {
this.downloader = downloader;
}
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
*/
-
package org.sonar.runner.impl;
-/**
- * Exception thrown by the Sonar Runner when something bad happens.
- *
- * @since 1.2
- */
public class RunnerException extends RuntimeException {
- private static final long serialVersionUID = 4810407777585753030L;
-
- /**
- * See {@link RuntimeException}
- */
- public RunnerException(String message) {
- super(message);
- }
-
- /**
- * See {@link RuntimeException}
- */
- public RunnerException(Throwable cause) {
- super(cause);
- }
-
- /**
- * See {@link RuntimeException}
- */
public RunnerException(String message, Throwable cause) {
super(message, cause);
}
--- /dev/null
+/*
+ * Sonar Runner - Implementation
+ * Copyright (C) 2011 SonarSource
+ * dev@sonar.codehaus.org
+ *
+ * This program 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.
+ *
+ * This program 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 02
+ */
+package org.sonar.runner.impl;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.net.ConnectException;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.UnknownHostException;
+import java.util.Properties;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+class ServerConnection {
+
+ static final int CONNECT_TIMEOUT_MILLISECONDS = 30000;
+ static final int READ_TIMEOUT_MILLISECONDS = 60000;
+ private static final Pattern CHARSET_PATTERN = Pattern.compile("(?i)\\bcharset=\\s*\"?([^\\s;\"]*)");
+
+ private final String serverUrl;
+ private final String userAgent;
+
+ private ServerConnection(String serverUrl, String app, String appVersion) {
+ this.serverUrl = serverUrl;
+ this.userAgent = app + "/" + appVersion;
+ }
+
+ static ServerConnection create(Properties properties) {
+ String serverUrl = properties.getProperty("sonar.host.url");
+ String app = properties.getProperty(InternalProperties.RUNNER_APP);
+ String appVersion = properties.getProperty(InternalProperties.RUNNER_APP_VERSION);
+ return new ServerConnection(serverUrl, app, appVersion);
+ }
+
+ void download(String path, File toFile) {
+ InputStream input = null;
+ FileOutputStream output = null;
+ String fullUrl = serverUrl + path;
+ try {
+ if (Logs.isDebugEnabled()) {
+ Logs.debug("Download " + fullUrl + " to " + toFile.getAbsolutePath());
+ }
+ HttpURLConnection connection = newHttpConnection(new URL(fullUrl));
+ int statusCode = connection.getResponseCode();
+ if (statusCode != HttpURLConnection.HTTP_OK) {
+ throw new IOException("Status returned by url : '" + fullUrl + "' is invalid : " + statusCode);
+ }
+ output = new FileOutputStream(toFile, false);
+ input = connection.getInputStream();
+ IOUtils.copyLarge(input, output);
+
+ } catch (Exception e) {
+ if (e instanceof ConnectException || e instanceof UnknownHostException) {
+ Logs.error("Sonar server '" + serverUrl + "' can not be reached");
+ }
+ IOUtils.closeQuietly(output);
+ FileUtils.deleteQuietly(toFile);
+ throw new IllegalStateException("Fail to download: " + fullUrl, e);
+
+ } finally {
+ IOUtils.closeQuietly(input);
+ IOUtils.closeQuietly(output);
+ }
+ }
+
+ String downloadString(String path) throws IOException {
+ String fullUrl = serverUrl + path;
+ HttpURLConnection conn = newHttpConnection(new URL(fullUrl));
+ String charset = getCharsetFromContentType(conn.getContentType());
+ if (charset == null || "".equals(charset)) {
+ charset = "UTF-8";
+ }
+ Reader reader = null;
+ try {
+ int statusCode = conn.getResponseCode();
+ if (statusCode != HttpURLConnection.HTTP_OK) {
+ throw new IOException("Status returned by url : '" + fullUrl + "' is invalid : " + statusCode);
+ }
+ reader = new InputStreamReader(conn.getInputStream(), charset);
+ return IOUtils.toString(reader);
+ } catch (IOException e) {
+ if (e instanceof ConnectException || e instanceof UnknownHostException) {
+ Logs.error("Sonar server '" + serverUrl + "' can not be reached");
+ }
+ throw e;
+
+ } finally {
+ IOUtils.closeQuietly(reader);
+ conn.disconnect();
+ }
+ }
+
+ private HttpURLConnection newHttpConnection(URL url) throws IOException {
+ //TODO send credentials
+ HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+ connection.setConnectTimeout(CONNECT_TIMEOUT_MILLISECONDS);
+ connection.setReadTimeout(READ_TIMEOUT_MILLISECONDS);
+ connection.setInstanceFollowRedirects(true);
+ connection.setRequestMethod("GET");
+ connection.setRequestProperty("User-Agent", userAgent);
+ return connection;
+ }
+
+ /**
+ * Parse out a charset from a content type header.
+ *
+ * @param contentType e.g. "text/html; charset=EUC-JP"
+ * @return "EUC-JP", or null if not found. Charset is trimmed and upper-cased.
+ */
+ static String getCharsetFromContentType(String contentType) {
+ if (contentType == null) {
+ return null;
+ }
+
+ Matcher m = CHARSET_PATTERN.matcher(contentType);
+ if (m.find()) {
+ return m.group(1).trim().toUpperCase();
+ }
+ return null;
+ }
+}
private static final String[] LESS_THAN_3_0 = {"0", "1", "2"};
private static final String[] LESS_THAN_3_5 = {"0", "1", "2", "3.0", "3.1", "3.2", "3.3", "3.4"};
- private final FileDownloader fileDownloader;
+ private final ServerConnection serverConnection;
private String version;
- ServerVersion(FileDownloader fileDownloader) {
- this.fileDownloader = fileDownloader;
+ ServerVersion(ServerConnection serverConnection) {
+ this.serverConnection = serverConnection;
}
String version() {
private String downloadVersion() {
String result;
try {
- result = fileDownloader.downloadString("/api/server/version");
+ result = serverConnection.downloadString("/api/server/version");
} catch (IOException e) {
throw new IllegalStateException("Fail to request server version", e);
}
--- /dev/null
+/*
+ * Sonar Runner - Implementation
+ * Copyright (C) 2011 SonarSource
+ * dev@sonar.codehaus.org
+ *
+ * This program 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.
+ *
+ * This program 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 02
+ */
+package org.sonar.runner.impl;
+
+import org.junit.Test;
+import org.mockito.ArgumentMatcher;
+
+import java.io.File;
+import java.net.URL;
+import java.util.List;
+import java.util.Properties;
+
+import static org.fest.assertions.Fail.fail;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+public class BatchLauncherMainTest {
+
+ BatchLauncher launcher = mock(BatchLauncher.class);
+
+ @Test
+ public void should_load_properties_and_execute() throws Exception {
+ URL url = getClass().getResource("/org/sonar/runner/impl/BatchLauncherMainTest/props.properties");
+ BatchLauncherMain main = new BatchLauncherMain(launcher);
+ main.execute(new String[]{new File(url.toURI()).getAbsolutePath()});
+
+ verify(launcher).execute(argThat(new ArgumentMatcher<Properties>() {
+ @Override
+ public boolean matches(Object o) {
+ return ((Properties) o).get("sonar.login").equals("foo");
+ }
+ }), argThat(new ArgumentMatcher<List<Object>>() {
+ @Override
+ public boolean matches(Object o) {
+ return ((List) o).isEmpty();
+ }
+ }));
+ }
+
+ @Test
+ public void should_fail_if_missing_path_to_properties_file() {
+ try {
+ BatchLauncherMain main = new BatchLauncherMain(launcher);
+ main.execute(new String[0]);
+ fail();
+ } catch (Exception e) {
+ // success
+ }
+ }
+
+ @Test
+ public void should_fail_if_properties_file_does_not_exist() {
+ try {
+ BatchLauncherMain main = new BatchLauncherMain(launcher);
+ main.execute(new String[]{"unknown/file.properties"});
+ fail();
+ } catch (Exception e) {
+ // success
+ }
+
+ }
+}
--- /dev/null
+/*
+ * Sonar Runner - Implementation
+ * Copyright (C) 2011 SonarSource
+ * dev@sonar.codehaus.org
+ *
+ * This program 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.
+ *
+ * This program 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 02
+ */
+package org.sonar.runner.impl;
+
+import org.junit.Test;
+import org.sonar.runner.batch.IsolatedLauncher;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Properties;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.fest.assertions.Fail.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+public class BatchLauncherTest {
+
+ JarDownloader jarDownloader = mock(JarDownloader.class);
+
+ @Test
+ public void should_download_jars_and_execute_batch() {
+ BatchLauncher launcher = new BatchLauncher(FakeIsolatedLauncher.class.getName());
+ Properties props = new Properties();
+ props.put("foo", "bar");
+
+ // Unmask the current classloader in order to access FakeIsolatedLauncher
+ props.put(InternalProperties.RUNNER_UNMASKED_PACKAGES, "org.sonar.runner.impl");
+ List<Object> extensions = new ArrayList<Object>();
+
+ FakeIsolatedLauncher isolatedLauncher = (FakeIsolatedLauncher) launcher.doExecute(jarDownloader, props, extensions);
+ assertThat(isolatedLauncher.props.get("foo")).isEqualTo("bar");
+ assertThat(isolatedLauncher.extensions).isSameAs(extensions);
+ verify(jarDownloader).download();
+ }
+
+ @Test
+ public void should_use_isolated_classloader() {
+ BatchLauncher launcher = new BatchLauncher(FakeIsolatedLauncher.class.getName());
+ Properties props = new Properties();
+
+ // The current classloader in not available -> fail to load FakeIsolatedLauncher
+ props.put(InternalProperties.RUNNER_UNMASKED_PACKAGES, "");
+ try {
+ launcher.doExecute(jarDownloader, props, Collections.emptyList());
+ fail();
+ } catch (RunnerException e) {
+ // success
+ }
+ }
+
+ @Test
+ public void verify_isolated_classloader_name() {
+ // the class IsolatedLauncher should not be loaded in the classloader of BatchLauncher,
+ // that's why it's referenced by its name
+ assertThat(new BatchLauncher().isolatedLauncherClass).isEqualTo(IsolatedLauncher.class.getName());
+ }
+
+ @Test
+ public void test_real_execution() {
+ // verify the creation of dependent components
+ Properties props = new Properties();
+ List<Object> extensions = Collections.emptyList();
+ BatchLauncher launcher = spy(new BatchLauncher());
+ doReturn(new Object()).when(launcher).doExecute(any(JarDownloader.class), eq(props), eq(extensions));
+
+ launcher.execute(props, extensions);
+
+ verify(launcher).execute(props, extensions);
+ }
+
+ public static class FakeIsolatedLauncher {
+ public Properties props = null;
+ public List<Object> extensions = null;
+
+ public void execute(Properties props, List<Object> extensions) {
+ this.props = props;
+ this.extensions = extensions;
+ }
+ }
+}
--- /dev/null
+/*
+ * Sonar Runner - Implementation
+ * Copyright (C) 2011 SonarSource
+ * dev@sonar.codehaus.org
+ *
+ * This program 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.
+ *
+ * This program 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 02
+ */
+package org.sonar.runner.impl;
+
+import org.junit.Test;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.fest.assertions.Fail.fail;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+public class JarDownloaderTest {
+
+ ServerConnection serverConnection = mock(ServerConnection.class);
+ ServerVersion serverVersion = mock(ServerVersion.class);
+ Properties props = new Properties();
+ JarDownloader downloader = spy(new JarDownloader(props, serverConnection, serverVersion));
+
+ @Test
+ public void should_download_3_5_jar_files() {
+ when(serverVersion.is35Compatible()).thenReturn(true);
+ doReturn(new ArrayList()).when(downloader).download35();
+ List<File> jarFiles = downloader.download();
+ assertThat(jarFiles).isNotNull();
+ }
+
+ @Test
+ public void should_download_3_0_jar_files() {
+ when(serverVersion.is35Compatible()).thenReturn(false);
+ when(serverVersion.is30Compatible()).thenReturn(true);
+ doReturn(new ArrayList()).when(downloader).download30();
+ List<File> jarFiles = downloader.download();
+ assertThat(jarFiles).isNotNull();
+ }
+
+ @Test
+ public void should_fail_if_2_x() {
+ when(serverVersion.version()).thenReturn("2.10");
+ when(serverVersion.is30Compatible()).thenReturn(false);
+ when(serverVersion.is35Compatible()).thenReturn(false);
+ try {
+ downloader.download();
+ fail();
+ } catch (IllegalStateException e) {
+ assertThat(e).hasMessage("Sonar 2.10 is not supported. Please upgrade Sonar to version 3.0 or more.");
+ }
+ }
+}
import java.io.File;
import static org.fest.assertions.Assertions.assertThat;
+import static org.fest.assertions.Fail.fail;
public class JarExtractorTest {
@Test
assertThat(FileUtils.readFileToString(jarFile, "UTF-8")).isEqualTo("Fake jar for unit tests");
assertThat(jarFile.toURI().toURL().toString()).doesNotContain("jar:file");
}
+
+ @Test
+ public void should_fail_to_extract() throws Exception {
+ try {
+ new JarExtractor().extract("unknown");
+ fail();
+ } catch (IllegalStateException e) {
+ assertThat(e).hasMessage("Fail to extract unknown.jar");
+ }
+ }
}
--- /dev/null
+/*
+ * Sonar Runner - Implementation
+ * Copyright (C) 2011 SonarSource
+ * dev@sonar.codehaus.org
+ *
+ * This program 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.
+ *
+ * This program 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 02
+ */
+package org.sonar.runner.impl;
+
+import org.junit.Test;
+
+import java.net.ConnectException;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.fest.assertions.Fail.fail;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class ServerVersionTest {
+
+ ServerConnection connection = mock(ServerConnection.class);
+ ServerVersion version = new ServerVersion(connection);
+
+ @Test
+ public void should_fail_on_connection_error() throws Exception {
+ when(connection.downloadString("/api/server/version")).thenThrow(new ConnectException());
+ try {
+ version.version();
+ fail();
+ } catch (IllegalStateException e) {
+ // success
+ }
+ }
+
+ @Test
+ public void should_fail_if_bad_version() throws Exception {
+ when(connection.downloadString("/api/server/version")).thenReturn("");
+ try {
+ version.version();
+ fail();
+ } catch (IllegalStateException e) {
+ assertThat(e).hasMessage("Server version is not set");
+ }
+ }
+
+ @Test
+ public void test_2_x() throws Exception {
+ when(connection.downloadString("/api/server/version")).thenReturn("2.10");
+ assertThat(version.version()).isEqualTo("2.10");
+ assertThat(version.is30Compatible()).isFalse();
+ assertThat(version.is35Compatible()).isFalse();
+ verify(connection, times(1)).downloadString("/api/server/version");
+ }
+
+ @Test
+ public void test_3_0() throws Exception {
+ when(connection.downloadString("/api/server/version")).thenReturn("3.0");
+ assertThat(version.version()).isEqualTo("3.0");
+ assertThat(version.is30Compatible()).isTrue();
+ assertThat(version.is35Compatible()).isFalse();
+ verify(connection, times(1)).downloadString("/api/server/version");
+ }
+
+ @Test
+ public void test_3_1() throws Exception {
+ when(connection.downloadString("/api/server/version")).thenReturn("3.1");
+ assertThat(version.version()).isEqualTo("3.1");
+ assertThat(version.is30Compatible()).isTrue();
+ assertThat(version.is35Compatible()).isFalse();
+ verify(connection, times(1)).downloadString("/api/server/version");
+ }
+
+ @Test
+ public void test_3_5() throws Exception {
+ when(connection.downloadString("/api/server/version")).thenReturn("3.5");
+ assertThat(version.version()).isEqualTo("3.5");
+ assertThat(version.is30Compatible()).isTrue();
+ assertThat(version.is35Compatible()).isTrue();
+ verify(connection, times(1)).downloadString("/api/server/version");
+ }
+
+ @Test
+ public void test_3_5_1() throws Exception {
+ when(connection.downloadString("/api/server/version")).thenReturn("3.5.1");
+ assertThat(version.version()).isEqualTo("3.5.1");
+ assertThat(version.is30Compatible()).isTrue();
+ assertThat(version.is35Compatible()).isTrue();
+ verify(connection, times(1)).downloadString("/api/server/version");
+ }
+
+ @Test
+ public void test_3_6() throws Exception {
+ when(connection.downloadString("/api/server/version")).thenReturn("3.6");
+ assertThat(version.version()).isEqualTo("3.6");
+ assertThat(version.is30Compatible()).isTrue();
+ assertThat(version.is35Compatible()).isTrue();
+ verify(connection, times(1)).downloadString("/api/server/version");
+ }
+
+ @Test
+ public void test_4_0() throws Exception {
+ when(connection.downloadString("/api/server/version")).thenReturn("4.0");
+ assertThat(version.version()).isEqualTo("4.0");
+ assertThat(version.is30Compatible()).isTrue();
+ assertThat(version.is35Compatible()).isTrue();
+ verify(connection, times(1)).downloadString("/api/server/version");
+ }
+}
--- /dev/null
+sonar.login=foo
+sonar.password=bar
\ No newline at end of file