@@ -61,9 +61,6 @@ class ServerConnection { | |||
} | |||
private static String removeEndSlash(String url) { | |||
if (url == null) { | |||
return null; | |||
} | |||
return url.endsWith("/") ? url.substring(0, url.length() - 1) : url; | |||
} | |||
@@ -19,6 +19,8 @@ | |||
*/ | |||
package org.sonar.runner.impl; | |||
import org.sonar.home.cache.PersistentCacheLoader; | |||
import com.github.kevinsawicki.http.HttpRequest; | |||
import java.io.File; | |||
@@ -27,6 +29,11 @@ import java.net.ConnectException; | |||
import java.net.SocketTimeoutException; | |||
import java.util.Properties; | |||
import static org.mockito.Matchers.startsWith; | |||
import static org.mockito.Mockito.verify; | |||
import static org.mockito.Mockito.doThrow; | |||
import static org.mockito.Matchers.any; | |||
import static org.mockito.Matchers.anyString; | |||
import static org.junit.Assert.*; | |||
import org.apache.commons.io.FileUtils; | |||
import org.junit.Before; | |||
@@ -48,20 +55,29 @@ public class ServerConnectionTest { | |||
@Rule | |||
public TemporaryFolder temp = new TemporaryFolder(); | |||
private PersistentCache cache = null; | |||
private PersistentCache cache; | |||
private Logger logger; | |||
@Before | |||
public void setUp() { | |||
cache = new PersistentCacheBuilder(mock(Logger.class)).setSonarHome(temp.getRoot().toPath()).build(); | |||
logger = mock(Logger.class); | |||
} | |||
@Test | |||
public void should_download_to_string() throws Exception { | |||
httpServer.setMockResponseData("abcde"); | |||
Properties props = new Properties(); | |||
props.setProperty("sonar.host.url", httpServer.url()); | |||
public void continue_if_cache_put_fails() throws Exception { | |||
cache = mock(PersistentCache.class); | |||
doThrow(IOException.class).when(cache).put(anyString(), any(byte[].class)); | |||
ServerConnection connection = createSimpleServerConnection(httpServer.url(), null, true); | |||
String response = connection.downloadStringCache("/batch/index.txt"); | |||
ServerConnection connection = ServerConnection.create(props, cache, mock(Logger.class)); | |||
assertThat(response).isEqualTo("abcde"); | |||
verify(logger).warn(startsWith("Failed to cache WS call:")); | |||
} | |||
@Test | |||
public void should_download_to_string() throws Exception { | |||
ServerConnection connection = createSimpleServerConnection(httpServer.url(), null); | |||
String response = connection.downloadStringCache("/batch/index.txt"); | |||
assertThat(response).isEqualTo("abcde"); | |||
@@ -69,27 +85,34 @@ public class ServerConnectionTest { | |||
@Test | |||
public void should_download_to_file() throws Exception { | |||
httpServer.setMockResponseData("abcde"); | |||
Properties props = new Properties(); | |||
props.setProperty("sonar.host.url", httpServer.url()); | |||
ServerConnection connection = ServerConnection.create(props, cache, mock(Logger.class)); | |||
ServerConnection connection = createSimpleServerConnection(httpServer.url(), null); | |||
File toFile = temp.newFile(); | |||
connection.download("/batch/index.txt", toFile); | |||
assertThat(FileUtils.readFileToString(toFile)).isEqualTo("abcde"); | |||
} | |||
@Test | |||
public void should_throw_original_exception_fallback() throws IOException { | |||
cache = mock(PersistentCache.class); | |||
ServerConnection connection = createSimpleServerConnection("http://localhost", NetworkUtil.getNextAvailablePort(), true); | |||
try { | |||
connection.downloadStringCache("/batch/index.txt"); | |||
fail(); | |||
} catch (HttpRequest.HttpRequestException e) { | |||
verify(cache).getString(anyString(), any(PersistentCacheLoader.class)); | |||
assertThat(e.getCause()).isInstanceOf(ConnectException.class); | |||
} | |||
} | |||
@Test | |||
public void should_cache_jar_list() throws Exception { | |||
File cacheDir = new File(temp.getRoot(), "ws_cache"); | |||
httpServer.setMockResponseData("abcde"); | |||
Properties props = new Properties(); | |||
props.setProperty("sonar.host.url", httpServer.url() + "/"); | |||
props.setProperty("sonar.analysis.mode", "issues"); | |||
ServerConnection connection = createSimpleServerConnection(httpServer.url() + "/", null, true); | |||
assertThat(cacheDir.list().length).isEqualTo(0); | |||
ServerConnection connection = ServerConnection.create(props, cache, mock(Logger.class)); | |||
String str = connection.downloadStringCache("/batch/index.txt"); | |||
assertThat(str).isEqualTo("abcde"); | |||
@@ -103,12 +126,9 @@ public class ServerConnectionTest { | |||
@Test | |||
public void should_throw_connection_exception_() throws IOException { | |||
File cacheDir = new File(temp.getRoot(), "ws_cache"); | |||
httpServer.setMockResponseData("abcde"); | |||
Properties props = new Properties(); | |||
props.setProperty("sonar.host.url", httpServer.url() + "/"); | |||
ServerConnection connection = createSimpleServerConnection(httpServer.url() + "/", null); | |||
assertThat(cacheDir.list().length).isEqualTo(0); | |||
ServerConnection connection = ServerConnection.create(props, cache, mock(Logger.class)); | |||
String str = connection.downloadStringCache("/batch/index.txt"); | |||
assertThat(str).isEqualTo("abcde"); | |||
@@ -128,14 +148,11 @@ public class ServerConnectionTest { | |||
} | |||
@Test | |||
public void should_not_cache_not_preview() throws Exception { | |||
public void should_not_cache_not_issues_mode() throws Exception { | |||
File cacheDir = new File(temp.getRoot(), "ws_cache"); | |||
httpServer.setMockResponseData("abcde"); | |||
Properties props = new Properties(); | |||
props.setProperty("sonar.host.url", httpServer.url() + "/"); | |||
ServerConnection connection = createSimpleServerConnection(httpServer.url() + "/", null); | |||
assertThat(cacheDir.list().length).isEqualTo(0); | |||
ServerConnection connection = ServerConnection.create(props, cache, mock(Logger.class)); | |||
String str = connection.downloadStringCache("/batch/index.txt"); | |||
assertThat(str).isEqualTo("abcde"); | |||
@@ -149,11 +166,7 @@ public class ServerConnectionTest { | |||
// SONARPLUGINS-3061 | |||
@Test | |||
public void should_support_trailing_slash() throws Exception { | |||
httpServer.setMockResponseData("abcde"); | |||
Properties props = new Properties(); | |||
props.setProperty("sonar.host.url", httpServer.url() + "/"); | |||
ServerConnection connection = ServerConnection.create(props, cache, mock(Logger.class)); | |||
ServerConnection connection = createSimpleServerConnection(httpServer.url() + "/", null); | |||
File toFile = temp.newFile(); | |||
connection.download("/batch/index.txt", toFile); | |||
@@ -162,10 +175,8 @@ public class ServerConnectionTest { | |||
@Test | |||
public void should_not_download_file_when_host_is_down() throws Exception { | |||
Properties props = new Properties(); | |||
props.setProperty("sonar.host.url", "http://localhost:" + NetworkUtil.getNextAvailablePort()); | |||
ServerConnection connection = createSimpleServerConnection("http://localhost", NetworkUtil.getNextAvailablePort()); | |||
ServerConnection connection = ServerConnection.create(props, cache, mock(Logger.class)); | |||
File toFile = temp.newFile(); | |||
try { | |||
connection.download("/batch/index.txt", toFile); | |||
@@ -177,10 +188,8 @@ public class ServerConnectionTest { | |||
@Test | |||
public void should_not_download_string_when_host_is_down() throws Exception { | |||
Properties props = new Properties(); | |||
props.setProperty("sonar.host.url", "http://localhost:" + NetworkUtil.getNextAvailablePort()); | |||
ServerConnection connection = createSimpleServerConnection("http://localhost", NetworkUtil.getNextAvailablePort()); | |||
ServerConnection connection = ServerConnection.create(props, cache, mock(Logger.class)); | |||
try { | |||
connection.downloadStringCache("/batch/index.txt"); | |||
fail(); | |||
@@ -188,4 +197,19 @@ public class ServerConnectionTest { | |||
// success | |||
} | |||
} | |||
private ServerConnection createSimpleServerConnection(String url, Integer port) { | |||
return createSimpleServerConnection(url, port, false); | |||
} | |||
private ServerConnection createSimpleServerConnection(String url, Integer port, boolean issuesMode) { | |||
httpServer.setMockResponseData("abcde"); | |||
String fullUrl = port == null ? url : url + ":" + port; | |||
Properties props = new Properties(); | |||
props.setProperty("sonar.host.url", fullUrl); | |||
if (issuesMode) { | |||
props.setProperty("sonar.analysis.mode", "issues"); | |||
} | |||
return ServerConnection.create(props, cache, logger); | |||
} | |||
} |
@@ -0,0 +1,120 @@ | |||
/* | |||
* SonarQube Runner - API | |||
* Copyright (C) 2011 SonarSource | |||
* sonarqube@googlegroups.com | |||
* | |||
* 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.junit.Rule; | |||
import org.junit.rules.TemporaryFolder; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
import org.sonar.home.cache.Logger; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.util.Map; | |||
import java.util.Properties; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.Mockito.mock; | |||
public class SimulatedLauncherTest { | |||
private static final String VERSION = "5.2"; | |||
private SimulatedLauncher launcher; | |||
private Logger logger; | |||
private String filename; | |||
@Rule | |||
public TemporaryFolder temp = new TemporaryFolder(); | |||
@Before | |||
public void setUp() { | |||
logger = mock(Logger.class); | |||
launcher = new SimulatedLauncher(VERSION, logger); | |||
filename = new File(temp.getRoot(), "props").getAbsolutePath(); | |||
} | |||
@Test | |||
public void testDump() throws IOException { | |||
Properties global = new Properties(); | |||
global.putAll(createProperties(true)); | |||
Properties analysis = new Properties(); | |||
analysis.putAll(createProperties(false)); | |||
launcher.start(global, null, false); | |||
launcher.execute(analysis); | |||
assertDump(global, analysis); | |||
} | |||
@Test(expected = IllegalStateException.class) | |||
public void error_if_no_dump_file() { | |||
launcher.execute(new Properties()); | |||
} | |||
@Test | |||
public void no_ops() { | |||
launcher.syncProject(null); | |||
} | |||
@Test | |||
public void testOldExecute() { | |||
Properties global = new Properties(); | |||
global.putAll(createProperties(true)); | |||
Properties analysis = new Properties(); | |||
analysis.putAll(createProperties(false)); | |||
launcher.start(global, null, false); | |||
launcher.executeOldVersion(analysis, null); | |||
} | |||
private Properties createProperties(boolean global) { | |||
Properties prop = new Properties(); | |||
prop.put("key1_" + global, "value1"); | |||
prop.put("key2_" + global, "value2"); | |||
prop.put(InternalProperties.RUNNER_DUMP_TO_FILE, filename); | |||
return prop; | |||
} | |||
@Test | |||
public void version() { | |||
assertThat(launcher.getVersion()).isEqualTo(VERSION); | |||
} | |||
private void assertDump(Properties global, Properties analysis) throws IOException { | |||
if (analysis != null) { | |||
String content = FileUtils.readFileToString(new File(filename)); | |||
for (Map.Entry<Object, Object> e : analysis.entrySet()) { | |||
assertThat(content).contains(e.getKey() + "=" + e.getValue()); | |||
} | |||
} else { | |||
assertThat(new File(filename)).doesNotExist(); | |||
} | |||
if (global != null) { | |||
String content = FileUtils.readFileToString(new File(filename + ".global")); | |||
for (Map.Entry<Object, Object> e : global.entrySet()) { | |||
assertThat(content).contains(e.getKey() + "=" + e.getValue()); | |||
} | |||
} else { | |||
assertThat(new File(filename + ".global")).doesNotExist(); | |||
} | |||
} | |||
} |
@@ -29,10 +29,12 @@ class Cli { | |||
private boolean displayStackTrace = false; | |||
private boolean interactive = false; | |||
private Properties props = new Properties(); | |||
private Exit exit; | |||
private final Exit exit; | |||
private Logs logger; | |||
public Cli(Exit exit) { | |||
public Cli(Exit exit, Logs logger) { | |||
this.exit = exit; | |||
this.logger = logger; | |||
} | |||
boolean isDebugMode() { | |||
@@ -71,14 +73,14 @@ class Cli { | |||
} else if ("-e".equals(arg) || "--errors".equals(arg)) { | |||
displayStackTrace = true; | |||
Logs.setDisplayStackTrace(true); | |||
logger.setDisplayStackTrace(true); | |||
} else if ("-X".equals(arg) || "--debug".equals(arg)) { | |||
props.setProperty("sonar.verbose", "true"); | |||
displayStackTrace = true; | |||
debugMode = true; | |||
Logs.setDebugEnabled(true); | |||
Logs.setDisplayStackTrace(true); | |||
logger.setDebugEnabled(true); | |||
logger.setDisplayStackTrace(true); | |||
} else if ("-D".equals(arg) || "--define".equals(arg)) { | |||
i++; | |||
@@ -130,21 +132,21 @@ class Cli { | |||
} | |||
private void printError(String message) { | |||
Logs.error(message); | |||
logger.error(message); | |||
printUsage(); | |||
} | |||
private void printUsage() { | |||
Logs.info(""); | |||
Logs.info("usage: sonar-runner [options]"); | |||
Logs.info(""); | |||
Logs.info("Options:"); | |||
Logs.info(" -D,--define <arg> Define property"); | |||
Logs.info(" -e,--errors Produce execution error messages"); | |||
Logs.info(" -h,--help Display help information"); | |||
Logs.info(" -v,--version Display version information"); | |||
Logs.info(" -X,--debug Produce execution debug output"); | |||
Logs.info(" -i,--interactive Run interactively"); | |||
logger.info(""); | |||
logger.info("usage: sonar-runner [options]"); | |||
logger.info(""); | |||
logger.info("Options:"); | |||
logger.info(" -D,--define <arg> Define property"); | |||
logger.info(" -e,--errors Produce execution error messages"); | |||
logger.info(" -h,--help Display help information"); | |||
logger.info(" -v,--version Display version information"); | |||
logger.info(" -X,--debug Produce execution debug output"); | |||
logger.info(" -i,--interactive Run interactively"); | |||
exit.exit(Exit.SUCCESS); | |||
} | |||
} |
@@ -39,9 +39,11 @@ class Conf { | |||
private static final String SONAR_PROJECT_PROPERTIES_FILENAME = "sonar-project.properties"; | |||
private final Cli cli; | |||
private final Logs logger; | |||
Conf(Cli cli) { | |||
Conf(Cli cli, Logs logger) { | |||
this.cli = cli; | |||
this.logger = logger; | |||
} | |||
Properties properties() throws IOException { | |||
@@ -57,10 +59,10 @@ class Conf { | |||
private Properties loadGlobalProperties() throws IOException { | |||
File settingsFile = locatePropertiesFile(cli.properties(), RUNNER_HOME, "conf/sonar-runner.properties", RUNNER_SETTINGS); | |||
if (settingsFile != null && settingsFile.isFile() && settingsFile.exists()) { | |||
Logs.info("Runner configuration file: " + settingsFile.getAbsolutePath()); | |||
logger.info("Runner configuration file: " + settingsFile.getAbsolutePath()); | |||
return toProperties(settingsFile); | |||
} | |||
Logs.info("Runner configuration file: NONE"); | |||
logger.info("Runner configuration file: NONE"); | |||
return new Properties(); | |||
} | |||
@@ -70,7 +72,7 @@ class Conf { | |||
SONAR_PROJECT_PROPERTIES_FILENAME, | |||
PROJECT_SETTINGS); | |||
if (rootSettingsFile != null && rootSettingsFile.isFile() && rootSettingsFile.exists()) { | |||
Logs.info("Project configuration file: " + rootSettingsFile.getAbsolutePath()); | |||
logger.info("Project configuration file: " + rootSettingsFile.getAbsolutePath()); | |||
Properties projectProps = new Properties(); | |||
Properties rootProps = toProperties(rootSettingsFile); | |||
projectProps.putAll(rootProps); | |||
@@ -78,7 +80,7 @@ class Conf { | |||
loadModulesProperties(rootProps, projectProps, ""); | |||
return projectProps; | |||
} | |||
Logs.info("Project configuration file: NONE"); | |||
logger.info("Project configuration file: NONE"); | |||
return new Properties(); | |||
} | |||
@@ -20,44 +20,40 @@ | |||
package org.sonar.runner.cli; | |||
public class Logs { | |||
private boolean debugEnabled = false; | |||
private boolean displayStackTrace = false; | |||
private Logs() { | |||
public void setDebugEnabled(boolean debugEnabled) { | |||
this.debugEnabled = debugEnabled; | |||
} | |||
private static boolean debugEnabled = false; | |||
private static boolean displayStackTrace = false; | |||
public static void setDebugEnabled(boolean debugEnabled) { | |||
Logs.debugEnabled = debugEnabled; | |||
} | |||
public static void setDisplayStackTrace(boolean displayStackTrace) { | |||
Logs.displayStackTrace = displayStackTrace; | |||
public void setDisplayStackTrace(boolean displayStackTrace) { | |||
this.displayStackTrace = displayStackTrace; | |||
} | |||
public static boolean isDebugEnabled() { | |||
public boolean isDebugEnabled() { | |||
return debugEnabled; | |||
} | |||
public static void debug(String message) { | |||
public void debug(String message) { | |||
if (isDebugEnabled()) { | |||
System.out.println("DEBUG: " + message); | |||
} | |||
} | |||
public static void info(String message) { | |||
public void info(String message) { | |||
System.out.println("INFO: " + message); | |||
} | |||
public static void warn(String message) { | |||
public void warn(String message) { | |||
System.out.println("WARN: " + message); | |||
} | |||
public static void error(String message) { | |||
public void error(String message) { | |||
System.err.println("ERROR: " + message); | |||
} | |||
public static void error(String message, Throwable t) { | |||
public void error(String message, Throwable t) { | |||
System.err.println("ERROR: " + message); | |||
if (t != null && displayStackTrace) { | |||
t.printStackTrace(System.err); |
@@ -46,25 +46,28 @@ public class Main { | |||
private EmbeddedRunner runner; | |||
private BufferedReader inputReader; | |||
private RunnerFactory runnerFactory; | |||
private Logs logger; | |||
Main(Shutdown shutdown, Cli cli, Conf conf, RunnerFactory runnerFactory) { | |||
Main(Shutdown shutdown, Cli cli, Conf conf, RunnerFactory runnerFactory, Logs logger) { | |||
this.shutdown = shutdown; | |||
this.cli = cli; | |||
this.conf = conf; | |||
this.runnerFactory = runnerFactory; | |||
this.logger = logger; | |||
} | |||
public static void main(String[] args) { | |||
Exit exit = new Exit(); | |||
Shutdown shutdown = new Shutdown(exit); | |||
Cli cli = new Cli(exit).parse(args); | |||
Logs logs = new Logs(); | |||
Cli cli = new Cli(exit, logs).parse(args); | |||
cli.verify(); | |||
Main main = new Main(shutdown, cli, new Conf(cli), new RunnerFactory()); | |||
Main main = new Main(shutdown, cli, new Conf(cli, logs), new RunnerFactory(logs), logs); | |||
main.execute(); | |||
} | |||
void execute() { | |||
Stats stats = new Stats().start(); | |||
Stats stats = new Stats(logger).start(); | |||
try { | |||
Properties p = conf.properties(); | |||
@@ -88,7 +91,7 @@ public class Main { | |||
private void interactiveLoop(Properties p) throws IOException { | |||
do { | |||
Stats stats = new Stats().start(); | |||
Stats stats = new Stats(logger).start(); | |||
try { | |||
runAnalysis(stats, p); | |||
} catch (Exception e) { | |||
@@ -99,13 +102,13 @@ public class Main { | |||
} | |||
private void init(Properties p) throws IOException { | |||
SystemInfo.print(); | |||
SystemInfo.print(logger); | |||
if (cli.isDisplayVersionOnly()) { | |||
shutdown.exit(Exit.SUCCESS); | |||
} | |||
if (cli.isDisplayStackTrace()) { | |||
Logs.info("Error stacktraces are turned on."); | |||
logger.info("Error stacktraces are turned on."); | |||
} | |||
runner = runnerFactory.create(p); | |||
@@ -140,43 +143,43 @@ public class Main { | |||
this.inputReader = inputReader; | |||
} | |||
private static void displayExecutionResult(Stats stats, String resultMsg) { | |||
Logs.info("------------------------------------------------------------------------"); | |||
Logs.info("EXECUTION " + resultMsg); | |||
Logs.info("------------------------------------------------------------------------"); | |||
private void displayExecutionResult(Stats stats, String resultMsg) { | |||
logger.info("------------------------------------------------------------------------"); | |||
logger.info("EXECUTION " + resultMsg); | |||
logger.info("------------------------------------------------------------------------"); | |||
stats.stop(); | |||
Logs.info("------------------------------------------------------------------------"); | |||
logger.info("------------------------------------------------------------------------"); | |||
} | |||
private void showError(String message, Throwable e, boolean showStackTrace) { | |||
if (showStackTrace) { | |||
Logs.error(message, e); | |||
logger.error(message, e); | |||
if (!cli.isDebugMode()) { | |||
Logs.error(""); | |||
logger.error(""); | |||
suggestDebugMode(); | |||
} | |||
} else { | |||
Logs.error(message); | |||
logger.error(message); | |||
if (e != null) { | |||
Logs.error(e.getMessage()); | |||
logger.error(e.getMessage()); | |||
String previousMsg = ""; | |||
for (Throwable cause = e.getCause(); cause != null | |||
&& cause.getMessage() != null | |||
&& !cause.getMessage().equals(previousMsg); cause = cause.getCause()) { | |||
Logs.error("Caused by: " + cause.getMessage()); | |||
logger.error("Caused by: " + cause.getMessage()); | |||
previousMsg = cause.getMessage(); | |||
} | |||
} | |||
Logs.error(""); | |||
Logs.error("To see the full stack trace of the errors, re-run SonarQube Runner with the -e switch."); | |||
logger.error(""); | |||
logger.error("To see the full stack trace of the errors, re-run SonarQube Runner with the -e switch."); | |||
if (!cli.isDebugMode()) { | |||
suggestDebugMode(); | |||
} | |||
} | |||
} | |||
private static void suggestDebugMode() { | |||
Logs.error("Re-run SonarQube Runner using the -X switch to enable full debug logging."); | |||
private void suggestDebugMode() { | |||
logger.error("Re-run SonarQube Runner using the -X switch to enable full debug logging."); | |||
} | |||
} |
@@ -25,26 +25,32 @@ import org.sonar.runner.api.LogOutput; | |||
class RunnerFactory { | |||
private final Logs logger; | |||
public RunnerFactory(Logs logger) { | |||
this.logger = logger; | |||
} | |||
EmbeddedRunner create(Properties props) { | |||
return EmbeddedRunner.create(new LogOutput() { | |||
return EmbeddedRunner.create(new DefaultLogOutput()).addGlobalProperties(props); | |||
} | |||
@Override | |||
public void log(String formattedMessage, Level level) { | |||
switch (level) { | |||
case TRACE: | |||
case DEBUG: | |||
Logs.debug(formattedMessage); | |||
break; | |||
case ERROR: | |||
Logs.error(formattedMessage); | |||
break; | |||
case INFO: | |||
case WARN: | |||
default: | |||
Logs.info(formattedMessage); | |||
} | |||
class DefaultLogOutput implements LogOutput { | |||
@Override | |||
public void log(String formattedMessage, Level level) { | |||
switch (level) { | |||
case TRACE: | |||
case DEBUG: | |||
logger.debug(formattedMessage); | |||
break; | |||
case ERROR: | |||
logger.error(formattedMessage); | |||
break; | |||
case INFO: | |||
case WARN: | |||
default: | |||
logger.info(formattedMessage); | |||
} | |||
}).addGlobalProperties(props); | |||
} | |||
} | |||
} |
@@ -20,9 +20,11 @@ | |||
package org.sonar.runner.cli; | |||
class Stats { | |||
private final Logs logger; | |||
private long startTime; | |||
Stats() { | |||
Stats(Logs logger) { | |||
this.logger = logger; | |||
} | |||
Stats start() { | |||
@@ -32,12 +34,12 @@ class Stats { | |||
Stats stop() { | |||
long stopTime = System.currentTimeMillis() - startTime; | |||
Logs.info("Total time: " + formatTime(stopTime)); | |||
logger.info("Total time: " + formatTime(stopTime)); | |||
System.gc(); | |||
Runtime r = Runtime.getRuntime(); | |||
long mb = 1024L * 1024; | |||
Logs.info("Final Memory: " + (r.totalMemory() - r.freeMemory()) / mb + "M/" + r.totalMemory() / mb + "M"); | |||
logger.info("Final Memory: " + (r.totalMemory() - r.freeMemory()) / mb + "M/" + r.totalMemory() / mb + "M"); | |||
return this; | |||
} |
@@ -31,13 +31,13 @@ class SystemInfo { | |||
SystemInfo.system = system; | |||
} | |||
static void print() { | |||
Logs.info("SonarQube Runner " + RunnerVersion.version()); | |||
Logs.info(java()); | |||
Logs.info(os()); | |||
static void print(Logs logger) { | |||
logger.info("SonarQube Runner " + RunnerVersion.version()); | |||
logger.info(java()); | |||
logger.info(os()); | |||
String runnerOpts = system.getenv("SONAR_RUNNER_OPTS"); | |||
if (runnerOpts != null) { | |||
Logs.info("SONAR_RUNNER_OPTS=" + runnerOpts); | |||
logger.info("SONAR_RUNNER_OPTS=" + runnerOpts); | |||
} | |||
} | |||
@@ -31,7 +31,8 @@ import static org.fest.assertions.Assertions.assertThat; | |||
public class CliTest { | |||
Exit exit = mock(Exit.class); | |||
Cli cli = new Cli(exit); | |||
Logs logs = new Logs(); | |||
Cli cli = new Cli(exit, logs); | |||
@Test | |||
public void should_parse_empty_arguments() { |
@@ -38,8 +38,9 @@ public class ConfTest { | |||
public TemporaryFolder temp = new TemporaryFolder(); | |||
Properties args = new Properties(); | |||
Logs logs = new Logs(); | |||
Cli cli = mock(Cli.class); | |||
Conf conf = new Conf(cli); | |||
Conf conf = new Conf(cli, logs); | |||
@Before | |||
public void initConf() { |
@@ -25,6 +25,7 @@ import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.nio.charset.StandardCharsets; | |||
import java.util.Properties; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
import org.mockito.InOrder; | |||
@@ -32,7 +33,6 @@ import org.mockito.Mock; | |||
import org.mockito.Mockito; | |||
import org.mockito.MockitoAnnotations; | |||
import org.sonar.runner.api.EmbeddedRunner; | |||
import static org.mockito.Matchers.any; | |||
import static org.mockito.Mockito.doThrow; | |||
import static org.mockito.Mockito.mock; | |||
@@ -54,6 +54,8 @@ public class MainTest { | |||
private RunnerFactory runnerFactory; | |||
@Mock | |||
private EmbeddedRunner runner; | |||
@Mock | |||
private Logs logs; | |||
@Before | |||
public void setUp() throws IOException { | |||
@@ -65,7 +67,7 @@ public class MainTest { | |||
@Test | |||
public void should_execute_runner() { | |||
Main main = new Main(exit, cli, conf, runnerFactory); | |||
Main main = new Main(exit, cli, conf, runnerFactory, logs); | |||
main.execute(); | |||
verify(exit).exit(Exit.SUCCESS); | |||
@@ -79,14 +81,36 @@ public class MainTest { | |||
@Test | |||
public void should_stop_on_error() { | |||
EmbeddedRunner runner = mock(EmbeddedRunner.class); | |||
doThrow(new IllegalStateException("Error")).when(runner).runAnalysis(any(Properties.class)); | |||
Exception e = new NullPointerException("NPE"); | |||
e = new IllegalStateException("Error", e); | |||
doThrow(e).when(runner).runAnalysis(any(Properties.class)); | |||
when(runnerFactory.create(any(Properties.class))).thenReturn(runner); | |||
Main main = new Main(exit, cli, conf, runnerFactory, logs); | |||
main.execute(); | |||
verify(runner).stop(); | |||
verify(exit).exit(Exit.ERROR); | |||
verify(logs).error("Caused by: NPE" ); | |||
} | |||
@Test | |||
public void show_error_stacktrace() { | |||
Exception e = new NullPointerException("NPE"); | |||
e = new IllegalStateException("Error", e); | |||
when(cli.isDisplayStackTrace()).thenReturn(true); | |||
EmbeddedRunner runner = mock(EmbeddedRunner.class); | |||
doThrow(e).when(runner).runAnalysis(any(Properties.class)); | |||
when(runnerFactory.create(any(Properties.class))).thenReturn(runner); | |||
Main main = new Main(exit, cli, conf, runnerFactory); | |||
Main main = new Main(exit, cli, conf, runnerFactory, logs); | |||
main.execute(); | |||
verify(runner).stop(); | |||
verify(exit).exit(Exit.ERROR); | |||
verify(logs).error("Error during Sonar runner execution", e); | |||
} | |||
@Test | |||
@@ -96,7 +120,7 @@ public class MainTest { | |||
when(runnerFactory.create(any(Properties.class))).thenReturn(runner); | |||
when(cli.isInteractive()).thenReturn(true); | |||
Main main = new Main(exit, cli, conf, runnerFactory); | |||
Main main = new Main(exit, cli, conf, runnerFactory, logs); | |||
BufferedReader inputReader = mock(BufferedReader.class); | |||
when(inputReader.readLine()).thenReturn(""); | |||
when(exit.shouldExit()).thenReturn(false).thenReturn(true); | |||
@@ -115,7 +139,7 @@ public class MainTest { | |||
when(cli.isDisplayVersionOnly()).thenReturn(true); | |||
when(conf.properties()).thenReturn(p); | |||
Main main = new Main(exit, cli, conf, runnerFactory); | |||
Main main = new Main(exit, cli, conf, runnerFactory, logs); | |||
main.execute(); | |||
InOrder inOrder = Mockito.inOrder(exit, runnerFactory); | |||
@@ -136,7 +160,7 @@ public class MainTest { | |||
when(cli.isDebugMode()).thenReturn(true); | |||
when(cli.isDisplayStackTrace()).thenReturn(true); | |||
Main main = new Main(exit, cli, conf, runnerFactory); | |||
Main main = new Main(exit, cli, conf, runnerFactory, logs); | |||
main.execute(); | |||
verify(runner, times(1)).start(); |
@@ -19,23 +19,70 @@ | |||
*/ | |||
package org.sonar.runner.cli; | |||
import org.sonar.runner.api.LogOutput.Level; | |||
import org.sonar.runner.api.LogOutput; | |||
import org.junit.Before; | |||
import java.util.Properties; | |||
import static org.mockito.Mockito.verifyNoMoreInteractions; | |||
import static org.mockito.Mockito.reset; | |||
import static org.mockito.Mockito.verify; | |||
import static org.mockito.Mockito.mock; | |||
import org.junit.Test; | |||
import org.sonar.runner.api.EmbeddedRunner; | |||
import static org.fest.assertions.Assertions.assertThat; | |||
public class RunnerFactoryTest { | |||
Properties props = new Properties(); | |||
Logs logs; | |||
@Before | |||
public void setUp() { | |||
logs = mock(Logs.class); | |||
} | |||
@Test | |||
public void should_create_embedded_runner() { | |||
props.setProperty("foo", "bar"); | |||
EmbeddedRunner runner = new RunnerFactory().create(props); | |||
EmbeddedRunner runner = new RunnerFactory(logs).create(props); | |||
assertThat(runner).isInstanceOf(EmbeddedRunner.class); | |||
assertThat(runner.globalProperties().get("foo")).isEqualTo("bar"); | |||
} | |||
@Test | |||
public void should_fwd_logs() { | |||
LogOutput logOutput = new RunnerFactory(logs).new DefaultLogOutput(); | |||
String msg = "test"; | |||
logOutput.log(msg, Level.DEBUG); | |||
verify(logs).debug(msg); | |||
verifyNoMoreInteractions(logs); | |||
reset(logs); | |||
logOutput.log(msg, Level.INFO); | |||
verify(logs).info(msg); | |||
verifyNoMoreInteractions(logs); | |||
reset(logs); | |||
logOutput.log(msg, Level.ERROR); | |||
verify(logs).error(msg); | |||
verifyNoMoreInteractions(logs); | |||
reset(logs); | |||
logOutput.log(msg, Level.WARN); | |||
verify(logs).info(msg); | |||
verifyNoMoreInteractions(logs); | |||
reset(logs); | |||
logOutput.log(msg, Level.TRACE); | |||
verify(logs).debug(msg); | |||
verifyNoMoreInteractions(logs); | |||
reset(logs); | |||
} | |||
} |
@@ -27,6 +27,7 @@ import org.junit.Test; | |||
import static org.fest.assertions.Assertions.assertThat; | |||
public class StatsTest { | |||
Logs logs = new Logs(); | |||
@Test | |||
public void shouldPrintStats() throws UnsupportedEncodingException { | |||
@@ -36,7 +37,7 @@ public class StatsTest { | |||
try { | |||
System.setOut(new PrintStream(baos)); | |||
new Stats().start().stop(); | |||
new Stats(logs).start().stop(); | |||
String out = baos.toString(); | |||
String[] lines = out.split(System.lineSeparator()); |
@@ -21,9 +21,11 @@ package org.sonar.runner.cli; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.when; | |||
import static org.mockito.Mockito.verify; | |||
import static org.mockito.Mockito.verifyNoMoreInteractions; | |||
import org.sonar.runner.api.RunnerVersion; | |||
import org.junit.Before; | |||
import org.sonar.runner.cli.SystemInfo.System2; | |||
import org.junit.Test; | |||
@@ -31,10 +33,13 @@ import org.sonar.runner.cli.SystemInfo; | |||
import static org.fest.assertions.Assertions.assertThat; | |||
public class SystemInfoTest { | |||
System2 mockSystem = mock(System2.class); | |||
System2 mockSystem; | |||
Logs logs; | |||
@Before | |||
public void setUp() { | |||
mockSystem = mock(System2.class); | |||
logs = mock(Logs.class); | |||
SystemInfo.setSystem(mockSystem); | |||
} | |||
@@ -74,11 +79,17 @@ public class SystemInfoTest { | |||
mockOs(); | |||
mockJava(); | |||
when(mockSystem.getenv("SONAR_RUNNER_OPTS")).thenReturn("arg"); | |||
SystemInfo.print(); | |||
SystemInfo.print(logs); | |||
verify(mockSystem).getProperty("java.version"); | |||
verify(mockSystem).getProperty("os.version"); | |||
verify(mockSystem).getenv("SONAR_RUNNER_OPTS"); | |||
verify(logs).info("SonarQube Runner " + RunnerVersion.version()); | |||
verify(logs).info("Java 1.9 oracle (64-bit)"); | |||
verify(logs).info("linux 2.5 x64"); | |||
verify(logs).info("SONAR_RUNNER_OPTS=arg"); | |||
verifyNoMoreInteractions(logs); | |||
} | |||
} |