From a087eb237d62b3280f1fc5d3540b1b57afccd4bd Mon Sep 17 00:00:00 2001 From: Steve Marion Date: Fri, 28 Feb 2025 16:38:04 +0100 Subject: SONAR-24521 Implements sonar plugin API addAnalysisData method in the scanner-engine. Add Xoo plugin sensor that utilizes the analysisData method. --- .../sensor/internal/InMemorySensorStorage.java | 25 ++++++++++- .../batch/sensor/internal/SensorContextTester.java | 11 ++++- .../sensor/internal/InMemorySensorStorageTest.java | 49 +++++++++++++++++++++- 3 files changed, 79 insertions(+), 6 deletions(-) (limited to 'sonar-plugin-api-impl/src') diff --git a/sonar-plugin-api-impl/src/main/java/org/sonar/api/batch/sensor/internal/InMemorySensorStorage.java b/sonar-plugin-api-impl/src/main/java/org/sonar/api/batch/sensor/internal/InMemorySensorStorage.java index b62b77831b4..09157ef9420 100644 --- a/sonar-plugin-api-impl/src/main/java/org/sonar/api/batch/sensor/internal/InMemorySensorStorage.java +++ b/sonar-plugin-api-impl/src/main/java/org/sonar/api/batch/sensor/internal/InMemorySensorStorage.java @@ -19,12 +19,17 @@ */ package org.sonar.api.batch.sensor.internal; +import static org.sonar.api.utils.Preconditions.checkArgument; + +import java.io.IOException; +import java.io.InputStream; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import org.apache.commons.lang3.StringUtils; import org.sonar.api.batch.sensor.code.NewSignificantCode; import org.sonar.api.batch.sensor.code.internal.DefaultSignificantCode; import org.sonar.api.batch.sensor.coverage.NewCoverage; @@ -41,8 +46,6 @@ import org.sonar.api.batch.sensor.rule.AdHocRule; import org.sonar.api.batch.sensor.symbol.NewSymbolTable; import org.sonar.api.batch.sensor.symbol.internal.DefaultSymbolTable; -import static org.sonar.api.utils.Preconditions.checkArgument; - class InMemorySensorStorage implements SensorStorage { Map> measuresByComponentAndMetric = new HashMap<>(); @@ -58,6 +61,7 @@ class InMemorySensorStorage implements SensorStorage { Map symbolsPerComponent = new HashMap<>(); Map contextProperties = new HashMap<>(); Map telemetryEntries = new HashMap<>(); + Map analysisDataEntries = new HashMap<>(); Map significantCodePerComponent = new HashMap<>(); @Override @@ -157,4 +161,21 @@ class InMemorySensorStorage implements SensorStorage { } significantCodePerComponent.put(fileKey, significantCode); } + + public void storeAnalysisData(String key, String mimeType, InputStream data) { + checkArgument(!StringUtils.isBlank(key), "Key must not be null"); + checkArgument(!StringUtils.isBlank(mimeType), "MimeType must not be null"); + checkArgument(data != null, "Data must not be null"); + if (analysisDataEntries.containsKey(key)) { + throw new UnsupportedOperationException("Trying to save analysis data twice for the same key is not supported: " + key); + } + try (data) { + byte[] bytes = data.readAllBytes(); + analysisDataEntries.put(key, new AnalysisData(key, mimeType, bytes)); + } catch (IOException e) { + throw new IllegalStateException("Failed to read data from InputStream", e); + } + } + + record AnalysisData(String key, String mimeType, byte[] data) { } } diff --git a/sonar-plugin-api-impl/src/main/java/org/sonar/api/batch/sensor/internal/SensorContextTester.java b/sonar-plugin-api-impl/src/main/java/org/sonar/api/batch/sensor/internal/SensorContextTester.java index 02c5fa5191f..b4fd5512335 100644 --- a/sonar-plugin-api-impl/src/main/java/org/sonar/api/batch/sensor/internal/SensorContextTester.java +++ b/sonar-plugin-api-impl/src/main/java/org/sonar/api/batch/sensor/internal/SensorContextTester.java @@ -19,7 +19,10 @@ */ package org.sonar.api.batch.sensor.internal; +import static java.util.Collections.unmodifiableMap; + import java.io.File; +import java.io.InputStream; import java.io.Serializable; import java.nio.charset.Charset; import java.nio.file.Path; @@ -87,8 +90,6 @@ import org.sonar.api.scanner.fs.InputProject; import org.sonar.api.utils.System2; import org.sonar.api.utils.Version; -import static java.util.Collections.unmodifiableMap; - /** * Utility class to help testing {@link Sensor}. This is not an API and method signature may evolve. *

@@ -447,6 +448,12 @@ public class SensorContextTester implements SensorContext { sensorStorage.storeTelemetry(key, value); } + @Override + public void addAnalysisData(String key, String mimeType, InputStream data) { + //No Need to check the source of the plugin in the tester + sensorStorage.storeAnalysisData(key,mimeType, data); + } + public void setCacheEnabled(boolean enabled) { this.cacheEnabled = enabled; } diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/batch/sensor/internal/InMemorySensorStorageTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/batch/sensor/internal/InMemorySensorStorageTest.java index d4ca8ee5865..85b073639b6 100644 --- a/sonar-plugin-api-impl/src/test/java/org/sonar/api/batch/sensor/internal/InMemorySensorStorageTest.java +++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/batch/sensor/internal/InMemorySensorStorageTest.java @@ -19,12 +19,16 @@ */ package org.sonar.api.batch.sensor.internal; -import org.junit.Test; - import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.data.MapEntry.entry; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import org.junit.Test; + public class InMemorySensorStorageTest { InMemorySensorStorage underTest = new InMemorySensorStorage(); @@ -50,4 +54,45 @@ public class InMemorySensorStorageTest { .isInstanceOf(IllegalArgumentException.class) .hasMessage("Value of context property must not be null"); } + + @Test + public void test_storeAnalysisData() { + // Given + String key = "analysisKey"; + String mimeType = "mimeType"; + String dataString = "analysisData"; + ByteArrayInputStream dataStream = new ByteArrayInputStream(dataString.getBytes(StandardCharsets.UTF_8)); + + // When + underTest.storeAnalysisData(key, mimeType, dataStream); + + // Then + assertThat(underTest.analysisDataEntries).containsKey(key); + assertThat(new String(underTest.analysisDataEntries.get(key).data(), StandardCharsets.UTF_8)).isEqualTo(dataString); + } + + @Test + public void storeAnalysisData_throws_UOE_if_operation_not_supported() { + underTest.storeAnalysisData("unsupportedKey", "mimeType", new ByteArrayInputStream("dummyData".getBytes(StandardCharsets.UTF_8))); + ByteArrayInputStream dataStream = new ByteArrayInputStream("newData".getBytes(StandardCharsets.UTF_8)); + + assertThatThrownBy(() -> underTest.storeAnalysisData("unsupportedKey", "mimeType", dataStream)) + .isInstanceOf(UnsupportedOperationException.class); + } + + @Test + public void storeAnalysisData_throws_IOE_on_data_handling_error() { + InputStream faultyStream = new InputStream() { + @Override + public int read() throws IOException { + throw new IOException("Simulated IO Exception"); + } + }; + + assertThatThrownBy(() -> underTest.storeAnalysisData("validKey", "mimeType", faultyStream)) + .isInstanceOf(IllegalStateException.class) + .hasMessageContaining("Failed to read data from InputStream"); + } + + } -- cgit v1.2.3