Browse Source

SONAR-19522 Fail-fast if SARIF file doesn't exist. (#8587)

tags/10.1.0.73491
Wojtek Wajerowicz 11 months ago
parent
commit
27fb5c0e4f

+ 2
- 1
sonar-core/src/main/java/org/sonar/core/sarif/SarifSerializer.java View File

*/ */
package org.sonar.core.sarif; package org.sonar.core.sarif;


import java.nio.file.NoSuchFileException;
import java.nio.file.Path; import java.nio.file.Path;


public interface SarifSerializer { public interface SarifSerializer {


String serialize(Sarif210 sarif210); String serialize(Sarif210 sarif210);


Sarif210 deserialize(Path sarifPath);
Sarif210 deserialize(Path sarifPath) throws NoSuchFileException;
} }

+ 4
- 3
sonar-core/src/main/java/org/sonar/core/sarif/SarifSerializerImpl.java View File

import com.google.gson.JsonSyntaxException; import com.google.gson.JsonSyntaxException;
import java.io.IOException; import java.io.IOException;
import java.io.Reader; import java.io.Reader;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path; import java.nio.file.Path;
import javax.inject.Inject; import javax.inject.Inject;
import org.sonar.api.ce.ComputeEngineSide; import org.sonar.api.ce.ComputeEngineSide;
} }


@Override @Override
public Sarif210 deserialize(Path reportPath) {
public Sarif210 deserialize(Path reportPath) throws NoSuchFileException {
try (Reader reader = newBufferedReader(reportPath, UTF_8)) { try (Reader reader = newBufferedReader(reportPath, UTF_8)) {
Sarif210 sarif = gson.fromJson(reader, Sarif210.class); Sarif210 sarif = gson.fromJson(reader, Sarif210.class);
SarifVersionValidator.validateSarifVersion(sarif.getVersion()); SarifVersionValidator.validateSarifVersion(sarif.getVersion());
return sarif; return sarif;
} catch (NoSuchFileException e) {
throw e;
} catch (JsonIOException | IOException e) { } catch (JsonIOException | IOException e) {
throw new IllegalStateException(format(SARIF_REPORT_ERROR, reportPath), e); throw new IllegalStateException(format(SARIF_REPORT_ERROR, reportPath), e);
} catch (JsonSyntaxException e) { } catch (JsonSyntaxException e) {
throw new IllegalStateException(format(SARIF_JSON_SYNTAX_ERROR, reportPath), e); throw new IllegalStateException(format(SARIF_JSON_SYNTAX_ERROR, reportPath), e);
} catch (IllegalStateException e) {
throw new IllegalStateException(e.getMessage(), e);
} }
} }
} }

sonar-core/src/test/java/org/sonar/core/sarif/SarifSerializerTest.java → sonar-core/src/test/java/org/sonar/core/sarif/SarifSerializerImplTest.java View File



import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.URL; import java.net.URL;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.Set; import java.util.Set;
import static org.sonar.core.sarif.SarifVersionValidator.UNSUPPORTED_VERSION_MESSAGE_TEMPLATE; import static org.sonar.core.sarif.SarifVersionValidator.UNSUPPORTED_VERSION_MESSAGE_TEMPLATE;


@RunWith(MockitoJUnitRunner.class) @RunWith(MockitoJUnitRunner.class)
public class SarifSerializerTest {
public class SarifSerializerImplTest {


private static final String SARIF_JSON = "{\"version\":\"2.1.0\",\"$schema\":\"http://json.schemastore.org/sarif-2.1.0-rtm.4\",\"runs\":[{\"results\":[]}]}"; private static final String SARIF_JSON = "{\"version\":\"2.1.0\",\"$schema\":\"http://json.schemastore.org/sarif-2.1.0-rtm.4\",\"runs\":[{\"results\":[]}]}";


} }


@Test @Test
public void deserialize() throws URISyntaxException {
public void deserialize() throws URISyntaxException, NoSuchFileException {
URL sarifResource = requireNonNull(getClass().getResource("eslint-sarif210.json")); URL sarifResource = requireNonNull(getClass().getResource("eslint-sarif210.json"));
Path sarif = Paths.get(sarifResource.toURI()); Path sarif = Paths.get(sarifResource.toURI());


Path sarif = Paths.get(file); Path sarif = Paths.get(file);


assertThatThrownBy(() -> serializer.deserialize(sarif)) assertThatThrownBy(() -> serializer.deserialize(sarif))
.isInstanceOf(IllegalStateException.class)
.hasMessage(format("Failed to read SARIF report at '%s'", file));
.isInstanceOf(NoSuchFileException.class);
} }


@Test @Test

+ 7
- 1
sonar-scanner-engine/src/main/java/org/sonar/scanner/externalissue/sarif/SarifIssuesImportSensor.java View File

*/ */
package org.sonar.scanner.externalissue.sarif; package org.sonar.scanner.externalissue.sarif;


import java.nio.file.NoSuchFileException;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import org.sonar.api.resources.Qualifiers; import org.sonar.api.resources.Qualifiers;
import org.sonar.api.scanner.ScannerSide; import org.sonar.api.scanner.ScannerSide;
import org.sonar.api.scanner.sensor.ProjectSensor; import org.sonar.api.scanner.sensor.ProjectSensor;
import org.sonar.api.utils.MessageException;
import org.sonar.core.sarif.Sarif210; import org.sonar.core.sarif.Sarif210;
import org.sonar.core.sarif.SarifSerializer; import org.sonar.core.sarif.SarifSerializer;


import static java.lang.String.format;

@ScannerSide @ScannerSide
public class SarifIssuesImportSensor implements ProjectSensor { public class SarifIssuesImportSensor implements ProjectSensor {


try { try {
SarifImportResults sarifImportResults = processReport(context, reportPath); SarifImportResults sarifImportResults = processReport(context, reportPath);
filePathToImportResults.put(reportPath, sarifImportResults); filePathToImportResults.put(reportPath, sarifImportResults);
} catch (NoSuchFileException e) {
throw MessageException.of(format("SARIF report file not found: %s", e.getFile()));
} catch (Exception exception) { } catch (Exception exception) {
LOG.warn("Failed to process SARIF report from file '{}', error: '{}'", reportPath, exception.getMessage()); LOG.warn("Failed to process SARIF report from file '{}', error: '{}'", reportPath, exception.getMessage());
} }
return Arrays.stream(config.getStringArray(SARIF_REPORT_PATHS_PROPERTY_KEY)).collect(Collectors.toSet()); return Arrays.stream(config.getStringArray(SARIF_REPORT_PATHS_PROPERTY_KEY)).collect(Collectors.toSet());
} }


private SarifImportResults processReport(SensorContext context, String reportPath) {
private SarifImportResults processReport(SensorContext context, String reportPath) throws NoSuchFileException {
LOG.debug("Importing SARIF issues from '{}'", reportPath); LOG.debug("Importing SARIF issues from '{}'", reportPath);
Path reportFilePath = context.fileSystem().resolvePath(reportPath).toPath(); Path reportFilePath = context.fileSystem().resolvePath(reportPath).toPath();
Sarif210 sarifReport = sarifSerializer.deserialize(reportFilePath); Sarif210 sarifReport = sarifSerializer.deserialize(reportFilePath);

+ 34
- 12
sonar-scanner-engine/src/test/java/org/sonar/scanner/externalissue/sarif/SarifIssuesImportSensorTest.java View File

package org.sonar.scanner.externalissue.sarif; package org.sonar.scanner.externalissue.sarif;


import com.google.common.collect.MoreCollectors; import com.google.common.collect.MoreCollectors;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Optional; import java.util.Optional;
import org.junit.Before; import org.junit.Before;
import org.sonar.api.config.internal.MapSettings; import org.sonar.api.config.internal.MapSettings;
import org.sonar.api.testfixtures.log.LogAndArguments; import org.sonar.api.testfixtures.log.LogAndArguments;
import org.sonar.api.testfixtures.log.LogTester; import org.sonar.api.testfixtures.log.LogTester;
import org.sonar.api.utils.MessageException;
import org.sonar.api.utils.log.LoggerLevel; import org.sonar.api.utils.log.LoggerLevel;
import org.sonar.core.sarif.Sarif210; import org.sonar.core.sarif.Sarif210;
import org.sonar.core.sarif.SarifSerializer; import org.sonar.core.sarif.SarifSerializer;


import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
private final SensorContextTester sensorContext = SensorContextTester.create(Path.of(".")); private final SensorContextTester sensorContext = SensorContextTester.create(Path.of("."));


@Test @Test
public void execute_whenSingleFileIsSpecified_shouldImportResults() {
public void execute_whenSingleFileIsSpecified_shouldImportResults() throws NoSuchFileException {
sensorSettings.setProperty("sonar.sarifReportPaths", FILE_1); sensorSettings.setProperty("sonar.sarifReportPaths", FILE_1);


ReportAndResults reportAndResults = mockSuccessfulReportAndResults(FILE_1); ReportAndResults reportAndResults = mockSuccessfulReportAndResults(FILE_1);
} }


@Test @Test
public void execute_whenMultipleFilesAreSpecified_shouldImportResults() {
public void execute_whenMultipleFilesAreSpecified_shouldImportResults() throws NoSuchFileException {
sensorSettings.setProperty("sonar.sarifReportPaths", SARIF_REPORT_PATHS_PARAM); sensorSettings.setProperty("sonar.sarifReportPaths", SARIF_REPORT_PATHS_PARAM);
ReportAndResults reportAndResults1 = mockSuccessfulReportAndResults(FILE_1); ReportAndResults reportAndResults1 = mockSuccessfulReportAndResults(FILE_1);
ReportAndResults reportAndResults2 = mockSuccessfulReportAndResults(FILE_2); ReportAndResults reportAndResults2 = mockSuccessfulReportAndResults(FILE_2);
} }


@Test @Test
public void execute_whenFileContainsOnlySuccessfulRuns_shouldLogCorrectMessage() {
public void execute_whenFileContainsOnlySuccessfulRuns_shouldLogCorrectMessage() throws NoSuchFileException {
sensorSettings.setProperty("sonar.sarifReportPaths", FILE_1); sensorSettings.setProperty("sonar.sarifReportPaths", FILE_1);
ReportAndResults reportAndResults = mockSuccessfulReportAndResults(FILE_1); ReportAndResults reportAndResults = mockSuccessfulReportAndResults(FILE_1);


} }


@Test @Test
public void execute_whenFileContainsOnlyFailedRuns_shouldLogCorrectMessage() {
public void execute_whenFileContainsOnlyFailedRuns_shouldLogCorrectMessage() throws NoSuchFileException {


sensorSettings.setProperty("sonar.sarifReportPaths", FILE_1); sensorSettings.setProperty("sonar.sarifReportPaths", FILE_1);
ReportAndResults reportAndResults = mockFailedReportAndResults(FILE_1); ReportAndResults reportAndResults = mockFailedReportAndResults(FILE_1);
} }


@Test @Test
public void execute_whenFileContainsFailedAndSuccessfulRuns_shouldLogCorrectMessage() {
public void execute_whenFileContainsFailedAndSuccessfulRuns_shouldLogCorrectMessage() throws NoSuchFileException {


sensorSettings.setProperty("sonar.sarifReportPaths", FILE_1); sensorSettings.setProperty("sonar.sarifReportPaths", FILE_1);


} }


@Test @Test
public void execute_whenImportFails_shouldSkipReport() {
public void execute_whenImportFails_shouldSkipReport() throws NoSuchFileException {
sensorSettings.setProperty("sonar.sarifReportPaths", SARIF_REPORT_PATHS_PARAM); sensorSettings.setProperty("sonar.sarifReportPaths", SARIF_REPORT_PATHS_PARAM);


ReportAndResults reportAndResults1 = mockFailedReportAndResults(FILE_1); ReportAndResults reportAndResults1 = mockFailedReportAndResults(FILE_1);
} }


@Test @Test
public void execute_whenDeserializationFails_shouldSkipReport() {
public void execute_whenDeserializationFails_shouldSkipReport() throws NoSuchFileException {
sensorSettings.setProperty("sonar.sarifReportPaths", SARIF_REPORT_PATHS_PARAM); sensorSettings.setProperty("sonar.sarifReportPaths", SARIF_REPORT_PATHS_PARAM);


failDeserializingReport(FILE_1); failDeserializingReport(FILE_1);
assertSummaryIsCorrectlyDisplayedForSuccessfulFile(FILE_2, reportAndResults2.getSarifImportResults()); assertSummaryIsCorrectlyDisplayedForSuccessfulFile(FILE_2, reportAndResults2.getSarifImportResults());
} }


private void failDeserializingReport(String path) {
@Test
public void execute_whenDeserializationThrowsMessageException_shouldRethrow() throws NoSuchFileException {
sensorSettings.setProperty("sonar.sarifReportPaths", FILE_1);

NoSuchFileException e = new NoSuchFileException("non-existent");
failDeserializingReportWithException(FILE_1, e);

SarifIssuesImportSensor sensor = new SarifIssuesImportSensor(sarifSerializer, sarifImporter, sensorSettings.asConfig());
assertThatThrownBy(() -> sensor.execute(sensorContext))
.isInstanceOf(MessageException.class)
.hasMessage("SARIF report file not found: non-existent");

}

private void failDeserializingReport(String path) throws NoSuchFileException {
Path reportFilePath = sensorContext.fileSystem().resolvePath(path).toPath(); Path reportFilePath = sensorContext.fileSystem().resolvePath(path).toPath();
when(sarifSerializer.deserialize(reportFilePath)).thenThrow(new NullPointerException("deserialization failed")); when(sarifSerializer.deserialize(reportFilePath)).thenThrow(new NullPointerException("deserialization failed"));
} }


private ReportAndResults mockSuccessfulReportAndResults(String path) {
private void failDeserializingReportWithException(String path, Exception exception) throws NoSuchFileException {
Path reportFilePath = sensorContext.fileSystem().resolvePath(path).toPath();
when(sarifSerializer.deserialize(reportFilePath)).thenThrow(exception);
}

private ReportAndResults mockSuccessfulReportAndResults(String path) throws NoSuchFileException {
Sarif210 report = mockSarifReport(path); Sarif210 report = mockSarifReport(path);


SarifImportResults sarifImportResults = mock(SarifImportResults.class); SarifImportResults sarifImportResults = mock(SarifImportResults.class);
return new ReportAndResults(report, sarifImportResults); return new ReportAndResults(report, sarifImportResults);
} }


private Sarif210 mockSarifReport(String path) {
private Sarif210 mockSarifReport(String path) throws NoSuchFileException {
Sarif210 report = mock(Sarif210.class); Sarif210 report = mock(Sarif210.class);
Path reportFilePath = sensorContext.fileSystem().resolvePath(path).toPath(); Path reportFilePath = sensorContext.fileSystem().resolvePath(path).toPath();
when(sarifSerializer.deserialize(reportFilePath)).thenReturn(report); when(sarifSerializer.deserialize(reportFilePath)).thenReturn(report);
return report; return report;
} }


private ReportAndResults mockFailedReportAndResults(String path) {
private ReportAndResults mockFailedReportAndResults(String path) throws NoSuchFileException {
Sarif210 report = mockSarifReport(path); Sarif210 report = mockSarifReport(path);


SarifImportResults sarifImportResults = mock(SarifImportResults.class); SarifImportResults sarifImportResults = mock(SarifImportResults.class);
return new ReportAndResults(report, sarifImportResults); return new ReportAndResults(report, sarifImportResults);
} }


private ReportAndResults mockMixedReportAndResults(String path) {
private ReportAndResults mockMixedReportAndResults(String path) throws NoSuchFileException {
Sarif210 report = mockSarifReport(path); Sarif210 report = mockSarifReport(path);


SarifImportResults sarifImportResults = mock(SarifImportResults.class); SarifImportResults sarifImportResults = mock(SarifImportResults.class);

Loading…
Cancel
Save