import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.api.io.TempDir;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
import org.slf4j.event.Level;
import org.sonar.api.testfixtures.log.LogTesterJUnit5;
import org.sonar.scanner.bootstrap.ScannerMain;
import static com.github.tomakehurst.wiremock.client.WireMock.post;
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.jupiter.api.Assertions.assertThrows;
import static testutils.TestUtils.protobufBody;
class BootstrapMediumIT {
@Test
void should_fail_if_invalid_json_input() {
var in = new ByteArrayInputStream("}".getBytes());
- var e = assertThrows(IllegalArgumentException.class, () -> ScannerMain.run(in));
- assertThat(e).hasMessage("Failed to parse JSON input");
- assertThat(logTester.logs()).contains("Starting SonarScanner Engine...");
+ var exitCode = ScannerMain.run(in);
+
+ assertThat(exitCode).isEqualTo(1);
+ assertThat(logTester.getLogs(Level.ERROR)).hasSize(1);
+ assertThat(logTester.getLogs(Level.ERROR).get(0).getFormattedMsg()).isEqualTo("Error during SonarScanner Engine execution");
+ assertThat(logTester.getLogs(Level.ERROR).get(0).getThrowable()).isInstanceOf(IllegalArgumentException.class).hasMessage("Failed to parse JSON input");
}
@Test
void should_warn_if_null_property_key() {
- try {
- ScannerMain.run(new ByteArrayInputStream("{\"scannerProperties\": [{\"value\": \"aValueWithoutKey\"}]}".getBytes()));
- } catch (Exception ignored) {
- }
- assertThat(logTester.logs()).contains("Ignoring property with null key: 'aValueWithoutKey'");
+ ScannerMain.run(new ByteArrayInputStream("""
+ {"scannerProperties": [{"value": "aValueWithoutKey"}]}""".getBytes()));
+
+ assertThat(logTester.logs(Level.WARN)).contains("Ignoring property with null key: 'aValueWithoutKey'");
}
@Test
void should_warn_if_duplicate_property_keys() {
- try {
- ScannerMain.run(new ByteArrayInputStream("{\"scannerProperties\": [{\"key\": \"aKey\"}, {\"key\": \"aKey\"}]}".getBytes()));
- } catch (Exception ignored) {
- }
- assertThat(logTester.logs()).contains("Duplicated properties with key: 'aKey'");
+ ScannerMain.run(new ByteArrayInputStream("""
+ {"scannerProperties": [{"key": "aKey"}, {"key": "aKey"}]}""".getBytes()));
+
+ assertThat(logTester.logs(Level.WARN)).contains("Duplicated properties with key: 'aKey'");
}
@Test
void should_warn_if_null_property() {
- try {
- ScannerMain.run(new ByteArrayInputStream("{\"scannerProperties\": [{\"key\": \"aKey\", \"value\": \"aValue\"},]}".getBytes()));
- } catch (Exception ignored) {
- }
- assertThat(logTester.logs()).contains("Ignoring null property");
+ ScannerMain.run(new ByteArrayInputStream("""
+ {"scannerProperties": [{"key": "aKey", "value": "aValue"},]}""".getBytes()));
+
+ assertThat(logTester.logs(Level.WARN)).contains("Ignoring null property");
}
/**
*/
@Test
void should_complete_successfully(@TempDir Path baseDir) {
-
- ScannerMain.run(new ByteArrayInputStream(("{\"scannerProperties\": ["
+ var exitCode = ScannerMain.run(new ByteArrayInputStream(("{\"scannerProperties\": ["
+ "{\"key\": \"sonar.host.url\", \"value\": \"" + sonarqube.baseUrl() + "\"},"
+ "{\"key\": \"sonar.projectKey\", \"value\": \"" + PROJECT_KEY + "\"},"
+ "{\"key\": \"sonar.projectBaseDir\", \"value\": \"" + baseDir + "\"}"
+ "]}").getBytes()));
+ assertThat(exitCode).isZero();
assertThat(logTester.logs()).contains("SonarScanner Engine completed successfully");
}
+ @Test
+ void should_unwrap_message_exception_without_stacktrace(@TempDir Path baseDir) {
+ var exitCode = ScannerMain.run(new ByteArrayInputStream(("{\"scannerProperties\": ["
+ + "{\"key\": \"sonar.host.url\", \"value\": \"" + sonarqube.baseUrl() + "\"},"
+ + "{\"key\": \"sonar.projectBaseDir\", \"value\": \"" + baseDir + "\"}"
+ + "]}").getBytes()));
+
+ assertThat(exitCode).isEqualTo(1);
+ assertThat(logTester.getLogs(Level.ERROR)).hasSize(1);
+ assertThat(logTester.getLogs(Level.ERROR).get(0).getFormattedMsg()).isEqualTo("You must define the following mandatory properties for 'Unknown': sonar.projectKey");
+ assertThat(logTester.getLogs(Level.ERROR).get(0).getThrowable()).isNull();
+ }
+
+ @Test
+ void should_show_message_exception_stacktrace_in_debug(@TempDir Path baseDir) {
+ var exitCode = ScannerMain.run(new ByteArrayInputStream(("{\"scannerProperties\": ["
+ + "{\"key\": \"sonar.host.url\", \"value\": \"" + sonarqube.baseUrl() + "\"},"
+ + "{\"key\": \"sonar.projectBaseDir\", \"value\": \"" + baseDir + "\"},"
+ + "{\"key\": \"sonar.verbose\", \"value\": \"true\"}"
+ + "]}").getBytes()));
+
+ assertThat(exitCode).isEqualTo(1);
+ assertThat(logTester.getLogs(Level.ERROR)).hasSize(1);
+ assertThat(logTester.getLogs(Level.ERROR).get(0).getFormattedMsg()).isEqualTo("You must define the following mandatory properties for 'Unknown': sonar.projectKey");
+ assertThat(logTester.getLogs(Level.ERROR).get(0).getThrowable()).isNotNull();
+ }
+
@Test
void should_enable_verbose(@TempDir Path baseDir) {
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import javax.annotation.CheckForNull;
import org.jetbrains.annotations.NotNull;
import org.slf4j.LoggerFactory;
+import org.sonar.api.utils.MessageException;
import org.sonar.batch.bootstrapper.EnvironmentInformation;
import org.sonar.batch.bootstrapper.LoggingConfiguration;
private static final String SCANNER_APP_VERSION_KEY = "sonar.scanner.appVersion";
public static void main(String... args) {
- try {
- run(System.in);
- } catch (Exception e) {
- LOG.error("Error during SonarScanner Engine execution", e);
- System.exit(1);
- }
+ System.exit(run(System.in));
}
- public static void run(InputStream in) {
- LOG.info("Starting SonarScanner Engine...");
+ public static int run(InputStream in) {
+ try {
+ LOG.info("Starting SonarScanner Engine...");
+
+ var properties = parseInputProperties(in);
+
+ EnvironmentConfig.processEnvVariables(properties);
- var properties = parseInputProperties(in);
+ configureLogLevel(properties);
- EnvironmentConfig.processEnvVariables(properties);
+ runScannerEngine(properties);
- configureLogLevel(properties);
+ LOG.info("SonarScanner Engine completed successfully");
+ return 0;
+ } catch (Exception e) {
+ handleException(e);
+ return 1;
+ }
+ }
+
+ private static void handleException(Exception e) {
+ var messageException = unwrapMessageException(e);
+ if (messageException.isPresent()) {
+ // Don't show the stacktrace for a message exception to not pollute the logs
+ if (LoggerFactory.getLogger(ScannerMain.class).isDebugEnabled()) {
+ LOG.error(messageException.get(), e);
+ } else {
+ LOG.error(messageException.get());
+ }
+ } else {
+ LOG.error("Error during SonarScanner Engine execution", e);
+ }
+ }
- runScannerEngine(properties);
+ private static Optional<String> unwrapMessageException(Exception t) {
+ Throwable y = t;
+ do {
+ if (y instanceof MessageException messageException) {
+ return Optional.of(messageException.getMessage());
+ }
+ y = y.getCause();
+ } while (y != null);
- LOG.info("SonarScanner Engine completed successfully");
+ return Optional.empty();
}
private static @NotNull Map<String, String> parseInputProperties(InputStream in) {