From: Julien HENRY Date: Tue, 7 May 2024 10:39:16 +0000 (+0200) Subject: Unwrap MessageException X-Git-Tag: 10.6.0.92116~117 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=792b34433b4a7f98c9ae1749378e68e426343728;p=sonarqube.git Unwrap MessageException --- diff --git a/sonar-scanner-engine/src/it/java/org/sonar/scanner/mediumtest/bootstrap/BootstrapMediumIT.java b/sonar-scanner-engine/src/it/java/org/sonar/scanner/mediumtest/bootstrap/BootstrapMediumIT.java index d7e0f7fc758..06033ba21dd 100644 --- a/sonar-scanner-engine/src/it/java/org/sonar/scanner/mediumtest/bootstrap/BootstrapMediumIT.java +++ b/sonar-scanner-engine/src/it/java/org/sonar/scanner/mediumtest/bootstrap/BootstrapMediumIT.java @@ -26,6 +26,8 @@ import org.junit.jupiter.api.BeforeEach; 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; @@ -39,7 +41,6 @@ import static com.github.tomakehurst.wiremock.client.WireMock.okJson; 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 { @@ -104,37 +105,37 @@ 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"); } /** @@ -142,16 +143,43 @@ class BootstrapMediumIT { */ @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) { diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ScannerMain.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ScannerMain.java index 044b42fd620..1dbafef4ce9 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ScannerMain.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ScannerMain.java @@ -30,9 +30,11 @@ import java.nio.charset.StandardCharsets; 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; @@ -47,26 +49,53 @@ public class ScannerMain { 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 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 parseInputProperties(InputStream in) {