From abde4bd08f8bf901dba878fc99c8f22c8ca1b071 Mon Sep 17 00:00:00 2001 From: Duarte Meneses Date: Tue, 1 Sep 2015 13:56:05 +0200 Subject: [PATCH] Improve unit tests --- .../sonar/runner/impl/ServerConnection.java | 3 - .../runner/impl/ServerConnectionTest.java | 96 ++++++++------ .../runner/impl/SimulatedLauncherTest.java | 120 ++++++++++++++++++ .../main/java/org/sonar/runner/cli/Cli.java | 34 ++--- .../main/java/org/sonar/runner/cli/Conf.java | 12 +- .../main/java/org/sonar/runner/cli/Logs.java | 28 ++-- .../main/java/org/sonar/runner/cli/Main.java | 45 ++++--- .../org/sonar/runner/cli/RunnerFactory.java | 42 +++--- .../main/java/org/sonar/runner/cli/Stats.java | 8 +- .../java/org/sonar/runner/cli/SystemInfo.java | 10 +- .../java/org/sonar/runner/cli/CliTest.java | 3 +- .../java/org/sonar/runner/cli/ConfTest.java | 3 +- .../java/org/sonar/runner/cli/MainTest.java | 38 +++++- .../sonar/runner/cli/RunnerFactoryTest.java | 51 +++++++- .../java/org/sonar/runner/cli/StatsTest.java | 3 +- .../org/sonar/runner/cli/SystemInfoTest.java | 21 ++- 16 files changed, 377 insertions(+), 140 deletions(-) create mode 100644 sonar-runner-api/src/test/java/org/sonar/runner/impl/SimulatedLauncherTest.java diff --git a/sonar-runner-api/src/main/java/org/sonar/runner/impl/ServerConnection.java b/sonar-runner-api/src/main/java/org/sonar/runner/impl/ServerConnection.java index 88a92d9..7156ebc 100644 --- a/sonar-runner-api/src/main/java/org/sonar/runner/impl/ServerConnection.java +++ b/sonar-runner-api/src/main/java/org/sonar/runner/impl/ServerConnection.java @@ -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; } diff --git a/sonar-runner-api/src/test/java/org/sonar/runner/impl/ServerConnectionTest.java b/sonar-runner-api/src/test/java/org/sonar/runner/impl/ServerConnectionTest.java index 4698576..8723c97 100644 --- a/sonar-runner-api/src/test/java/org/sonar/runner/impl/ServerConnectionTest.java +++ b/sonar-runner-api/src/test/java/org/sonar/runner/impl/ServerConnectionTest.java @@ -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); + } } diff --git a/sonar-runner-api/src/test/java/org/sonar/runner/impl/SimulatedLauncherTest.java b/sonar-runner-api/src/test/java/org/sonar/runner/impl/SimulatedLauncherTest.java new file mode 100644 index 0000000..5f34023 --- /dev/null +++ b/sonar-runner-api/src/test/java/org/sonar/runner/impl/SimulatedLauncherTest.java @@ -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 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 e : global.entrySet()) { + assertThat(content).contains(e.getKey() + "=" + e.getValue()); + } + } else { + assertThat(new File(filename + ".global")).doesNotExist(); + } + } + +} diff --git a/sonar-runner-cli/src/main/java/org/sonar/runner/cli/Cli.java b/sonar-runner-cli/src/main/java/org/sonar/runner/cli/Cli.java index f1a038b..8a34607 100644 --- a/sonar-runner-cli/src/main/java/org/sonar/runner/cli/Cli.java +++ b/sonar-runner-cli/src/main/java/org/sonar/runner/cli/Cli.java @@ -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 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 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); } } diff --git a/sonar-runner-cli/src/main/java/org/sonar/runner/cli/Conf.java b/sonar-runner-cli/src/main/java/org/sonar/runner/cli/Conf.java index 68627f7..ac7248f 100644 --- a/sonar-runner-cli/src/main/java/org/sonar/runner/cli/Conf.java +++ b/sonar-runner-cli/src/main/java/org/sonar/runner/cli/Conf.java @@ -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(); } diff --git a/sonar-runner-cli/src/main/java/org/sonar/runner/cli/Logs.java b/sonar-runner-cli/src/main/java/org/sonar/runner/cli/Logs.java index d69f3fd..6577a81 100644 --- a/sonar-runner-cli/src/main/java/org/sonar/runner/cli/Logs.java +++ b/sonar-runner-cli/src/main/java/org/sonar/runner/cli/Logs.java @@ -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); diff --git a/sonar-runner-cli/src/main/java/org/sonar/runner/cli/Main.java b/sonar-runner-cli/src/main/java/org/sonar/runner/cli/Main.java index 88b4510..0229cc9 100644 --- a/sonar-runner-cli/src/main/java/org/sonar/runner/cli/Main.java +++ b/sonar-runner-cli/src/main/java/org/sonar/runner/cli/Main.java @@ -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."); } } diff --git a/sonar-runner-cli/src/main/java/org/sonar/runner/cli/RunnerFactory.java b/sonar-runner-cli/src/main/java/org/sonar/runner/cli/RunnerFactory.java index 3abe645..69406ba 100644 --- a/sonar-runner-cli/src/main/java/org/sonar/runner/cli/RunnerFactory.java +++ b/sonar-runner-cli/src/main/java/org/sonar/runner/cli/RunnerFactory.java @@ -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); + } } - } diff --git a/sonar-runner-cli/src/main/java/org/sonar/runner/cli/Stats.java b/sonar-runner-cli/src/main/java/org/sonar/runner/cli/Stats.java index 5173137..82fbdb5 100644 --- a/sonar-runner-cli/src/main/java/org/sonar/runner/cli/Stats.java +++ b/sonar-runner-cli/src/main/java/org/sonar/runner/cli/Stats.java @@ -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; } diff --git a/sonar-runner-cli/src/main/java/org/sonar/runner/cli/SystemInfo.java b/sonar-runner-cli/src/main/java/org/sonar/runner/cli/SystemInfo.java index 43b27ab..5d98720 100644 --- a/sonar-runner-cli/src/main/java/org/sonar/runner/cli/SystemInfo.java +++ b/sonar-runner-cli/src/main/java/org/sonar/runner/cli/SystemInfo.java @@ -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); } } diff --git a/sonar-runner-cli/src/test/java/org/sonar/runner/cli/CliTest.java b/sonar-runner-cli/src/test/java/org/sonar/runner/cli/CliTest.java index a0332c2..d343561 100644 --- a/sonar-runner-cli/src/test/java/org/sonar/runner/cli/CliTest.java +++ b/sonar-runner-cli/src/test/java/org/sonar/runner/cli/CliTest.java @@ -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() { diff --git a/sonar-runner-cli/src/test/java/org/sonar/runner/cli/ConfTest.java b/sonar-runner-cli/src/test/java/org/sonar/runner/cli/ConfTest.java index 9452463..4c9d775 100644 --- a/sonar-runner-cli/src/test/java/org/sonar/runner/cli/ConfTest.java +++ b/sonar-runner-cli/src/test/java/org/sonar/runner/cli/ConfTest.java @@ -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() { diff --git a/sonar-runner-cli/src/test/java/org/sonar/runner/cli/MainTest.java b/sonar-runner-cli/src/test/java/org/sonar/runner/cli/MainTest.java index 857ed8c..a0dec5c 100644 --- a/sonar-runner-cli/src/test/java/org/sonar/runner/cli/MainTest.java +++ b/sonar-runner-cli/src/test/java/org/sonar/runner/cli/MainTest.java @@ -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(); diff --git a/sonar-runner-cli/src/test/java/org/sonar/runner/cli/RunnerFactoryTest.java b/sonar-runner-cli/src/test/java/org/sonar/runner/cli/RunnerFactoryTest.java index 7ca2688..169ea30 100644 --- a/sonar-runner-cli/src/test/java/org/sonar/runner/cli/RunnerFactoryTest.java +++ b/sonar-runner-cli/src/test/java/org/sonar/runner/cli/RunnerFactoryTest.java @@ -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); + } + } diff --git a/sonar-runner-cli/src/test/java/org/sonar/runner/cli/StatsTest.java b/sonar-runner-cli/src/test/java/org/sonar/runner/cli/StatsTest.java index ff8fa0b..1037483 100644 --- a/sonar-runner-cli/src/test/java/org/sonar/runner/cli/StatsTest.java +++ b/sonar-runner-cli/src/test/java/org/sonar/runner/cli/StatsTest.java @@ -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()); diff --git a/sonar-runner-cli/src/test/java/org/sonar/runner/cli/SystemInfoTest.java b/sonar-runner-cli/src/test/java/org/sonar/runner/cli/SystemInfoTest.java index cfedfe7..e777003 100644 --- a/sonar-runner-cli/src/test/java/org/sonar/runner/cli/SystemInfoTest.java +++ b/sonar-runner-cli/src/test/java/org/sonar/runner/cli/SystemInfoTest.java @@ -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); } } -- 2.39.5