Skip to content

Commit

Permalink
Fix ITs
Browse files Browse the repository at this point in the history
  • Loading branch information
antonioaversa committed Jan 24, 2025
1 parent 2924132 commit 5f8e061
Show file tree
Hide file tree
Showing 6 changed files with 466 additions and 97 deletions.
325 changes: 325 additions & 0 deletions gradle/verification-metadata.xml

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ public void ktlint() {
}

private List<Issue> getExternalIssues(String componentKey) {
return newWsClient().issues().search(new SearchRequest().setComponentKeys(Collections.singletonList(componentKey)))
return newWsClient().issues().search(new SearchRequest().setProjects(Collections.singletonList(componentKey)))
.getIssuesList().stream()
.filter(issue -> issue.getRule().startsWith("external_"))
.collect(Collectors.toList());
Expand Down
226 changes: 134 additions & 92 deletions its/plugin/src/test/java/org/sonarsource/slang/SonarLintTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,30 @@
package org.sonarsource.slang;

import com.sonar.orchestrator.junit5.OrchestratorExtension;
import com.sonar.orchestrator.junit5.OrchestratorExtensionBuilder;
import com.sonar.orchestrator.locator.Locators;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.annotation.Nullable;
import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.sonarsource.sonarlint.core.StandaloneSonarLintEngineImpl;
import org.sonar.api.batch.fs.InputFile;
import org.sonarsource.sonarlint.core.analysis.AnalysisEngine;
import org.sonarsource.sonarlint.core.analysis.api.ActiveRule;
import org.sonarsource.sonarlint.core.analysis.api.ClientInputFile;
import org.sonarsource.sonarlint.core.client.api.common.analysis.Issue;
import org.sonarsource.sonarlint.core.client.api.standalone.StandaloneAnalysisConfiguration;
import org.sonarsource.sonarlint.core.client.api.standalone.StandaloneGlobalConfiguration;
import org.sonarsource.sonarlint.core.client.api.standalone.StandaloneSonarLintEngine;
import org.sonarsource.sonarlint.core.commons.IssueSeverity;
import org.sonarsource.sonarlint.core.commons.Language;
import org.sonarsource.sonarlint.core.analysis.api.ClientModuleFileSystem;
import org.sonarsource.sonarlint.core.analysis.api.ClientModuleInfo;
import org.sonarsource.sonarlint.core.analysis.api.Issue;
import org.sonarsource.sonarlint.core.analysis.api.AnalysisConfiguration;
import org.sonarsource.sonarlint.core.analysis.api.AnalysisEngineConfiguration;
import org.sonarsource.sonarlint.core.analysis.command.AnalyzeCommand;
import org.sonarsource.sonarlint.core.analysis.command.RegisterModuleCommand;
import org.sonarsource.sonarlint.core.commons.ImpactSeverity;
import org.sonarsource.sonarlint.core.commons.SoftwareQuality;
import org.sonarsource.sonarlint.core.commons.api.SonarLanguage;

import java.io.File;
import java.io.IOException;
Expand All @@ -41,128 +51,160 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import org.sonarsource.sonarlint.core.commons.log.LogOutput;
import org.sonarsource.sonarlint.core.commons.log.SonarLintLogger;
import org.sonarsource.sonarlint.core.commons.progress.ProgressMonitor;
import org.sonarsource.sonarlint.core.plugin.commons.PluginsLoader;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;

public class SonarLintTest {

@TempDir
public static File temp;
public static Path temp;

private static StandaloneSonarLintEngine sonarlintEngine;

private static File baseDir;
private static AnalysisEngine analysisEngine;
private final ProgressMonitor progressMonitor = new ProgressMonitor(null);

@BeforeAll
public static void prepare() throws Exception {
// Orchestrator is used only to retrieve plugin artifacts from filesystem or maven
OrchestratorExtensionBuilder orchestratorBuilder = OrchestratorExtension.builderEnv();
public static void prepare() {
SonarLintLogger.setTarget(new NoOpLogOutput());
var pluginJarLocations = getPluginJarLocations();
var pluginConfiguration = new PluginsLoader.Configuration(pluginJarLocations, Set.of(SonarLanguage.KOTLIN), false, Optional.empty());
// Closing pluginLoader here in prepare would make analysisEngine see 0 plugins during analysis
var pluginLoader = new PluginsLoader().load(pluginConfiguration, Set.of());
var analysisEngineConfiguration = AnalysisEngineConfiguration.builder()
.setWorkDir(temp)
.build();
var loadedPlugins = pluginLoader.getLoadedPlugins();
analysisEngine = new AnalysisEngine(analysisEngineConfiguration, loadedPlugins, new NoOpLogOutput());
}

private static @NotNull Set<Path> getPluginJarLocations() {
var orchestratorBuilder = OrchestratorExtension.builderEnv();
TestsHelper.addLanguagePlugins(orchestratorBuilder);
OrchestratorExtension orchestrator = orchestratorBuilder
var orchestrator = orchestratorBuilder
.useDefaultAdminCredentialsForBuilds(true)
.setSonarVersion(System.getProperty(TestsHelper.SQ_VERSION_PROPERTY, TestsHelper.DEFAULT_SQ_VERSION))
.build();

Locators locators = orchestrator.getConfiguration().locators();
StandaloneGlobalConfiguration.Builder sonarLintConfigBuilder = StandaloneGlobalConfiguration.builder();
orchestrator.getDistribution().getPluginLocations().stream()
var locators = orchestrator.getConfiguration().locators();
return orchestrator.getDistribution().getPluginLocations().stream()
.filter(location -> !location.toString().contains("sonar-reset-data-plugin"))
.map(plugin -> locators.locate(plugin).toPath()).forEach(sonarLintConfigBuilder::addPlugin);

sonarLintConfigBuilder
.addEnabledLanguage(Language.KOTLIN)
.setSonarLintUserHome(temp.toPath())
.setLogOutput((formattedMessage, level) -> {
/* Don't pollute logs */
});
StandaloneGlobalConfiguration configuration = sonarLintConfigBuilder.build();
sonarlintEngine = new StandaloneSonarLintEngineImpl(configuration);
baseDir = temp;
.map(plugin -> locators.locate(plugin).toPath())
.collect(Collectors.toSet());
}

@AfterAll
public static void stop() {
sonarlintEngine.stop();
SonarLintLogger.setTarget(null);
analysisEngine.stop();
}

@Test
void test_kotlin() throws Exception {
ClientInputFile inputFile = prepareInputFile("foo.kt",
var inputFile = prepareInputFile("foo.kt",
"fun foo_bar() {\n" +
" if (true) { \n" +
" val password = \"blabla\"\n" +
" } \n" +
"}\n" +
"\n" +
"fun foo_bar_nosonar() {} // NOSONAR \n",
false, "kotlin");

List<Issue> issues = new ArrayList<>();
StandaloneAnalysisConfiguration standaloneAnalysisConfiguration = StandaloneAnalysisConfiguration.builder()
.setBaseDir(baseDir.toPath())
.addInputFile(inputFile)
.build();
sonarlintEngine.analyze(standaloneAnalysisConfiguration, issues::add, null, null);

assertThat(issues).extracting(Issue::getRuleKey, Issue::getStartLine, issue -> issue.getInputFile().getPath(), Issue::getSeverity).containsOnly(
tuple("kotlin:S100", 1, inputFile.getPath(), IssueSeverity.MINOR),
tuple("kotlin:S1481", 3, inputFile.getPath(), IssueSeverity.MINOR),
tuple("kotlin:S1145", 2, inputFile.getPath(), IssueSeverity.MAJOR));
}

private ClientInputFile prepareInputFile(String relativePath, String content, final boolean isTest, String language) throws IOException {
File file = new File(baseDir, relativePath);
Files.writeString(file.toPath(), content, StandardCharsets.UTF_8);
return createInputFile(file.toPath(), isTest, language);
}

private ClientInputFile createInputFile(final Path path, final boolean isTest, String language) {
return new ClientInputFile() {

@Override
public URI uri() {
return path.toUri();
}

@Override
public String getPath() {
return path.toString();
}
"fun foo_bar_nosonar() {} // NOSONAR \n");

var clientFileSystem = new ClientModuleFileSystem() {
@Override
public boolean isTest() {
return isTest;
public Stream<ClientInputFile> files(@NotNull String s, InputFile.@NotNull Type type) {
return Stream.of(inputFile);
}

@Override
public Charset getCharset() {
return StandardCharsets.UTF_8;
}


@Override
public <G> G getClientObject() {
return null;
public Stream<ClientInputFile> files() {
return Stream.of(inputFile);
}
};
var registerModuleCommand = new RegisterModuleCommand(new ClientModuleInfo("testModule", clientFileSystem));
analysisEngine.post(registerModuleCommand, progressMonitor).get();

@Override
public String contents() throws IOException {
return new String(Files.readAllBytes(path), StandardCharsets.UTF_8);
}
var kotlinLanguageKey = SonarLanguage.KOTLIN.name();
var analysisConfiguration = AnalysisConfiguration.builder()
.setBaseDir(temp)
.addInputFile(inputFile)
.addActiveRules(
new ActiveRule("kotlin:S100", kotlinLanguageKey),
new ActiveRule("kotlin:S1481", kotlinLanguageKey),
new ActiveRule("kotlin:S1145", kotlinLanguageKey))
.build();
var issues = new ArrayList<Issue>();
var analyzeCommand = new AnalyzeCommand("testModule", analysisConfiguration, issues::add, new NoOpLogOutput());
analysisEngine.post(analyzeCommand, progressMonitor).get();

assertThat(issues).extracting(Issue::getRuleKey, Issue::getStartLine, issue -> issue.getInputFile().uri()).containsOnly(
tuple("kotlin:S100", 1, inputFile.uri()),
tuple("kotlin:S1481", 3, inputFile.uri()),
tuple("kotlin:S1145", 2, inputFile.uri()));
}

@Override
public String relativePath() {
return path.toString();
}
private ClientInputFile prepareInputFile(String relativePath, String content) throws IOException {
var file = new File(temp.toFile(), relativePath);
Files.writeString(file.toPath(), content, StandardCharsets.UTF_8);
return new PathBasedClientInputFile(file.toPath());
}

@Override
public InputStream inputStream() throws IOException {
return Files.newInputStream(path);
}
private static class PathBasedClientInputFile implements ClientInputFile {
private final Path path;

public PathBasedClientInputFile(Path path) {
this.path = path;
}

@Override
public URI uri() {
return path.toUri();
}

@Override
public String getPath() {
return path.toString();
}

@Override
public boolean isTest() {
return false;
}

@Override
public Charset getCharset() {
return StandardCharsets.UTF_8;
}


@Override
public <G> G getClientObject() {
return null;
}

@Override
public String contents() throws IOException {
return Files.readString(path);
}

@Override
public String relativePath() {
return path.toString();
}

@Override
public InputStream inputStream() throws IOException {
return Files.newInputStream(path);
}
}

};
private static class NoOpLogOutput implements LogOutput {
@Override
public void log(String formattedMessage, @NotNull Level level, @Nullable String stacktrace) {
/* Don't pollute logs */
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public class TestsHelper {
.setSonarVersion(System.getProperty(SQ_VERSION_PROPERTY, DEFAULT_SQ_VERSION))
.restoreProfileAtStartup(FileLocation.of("src/test/resources/suppress-warnings-kotlin.xml"))
.restoreProfileAtStartup(FileLocation.of("src/test/resources/norule.xml"))
.setServerProperty("sonar.telemetry.enable", "false")
.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ public static void setUp() {
OrchestratorExtensionBuilder builder = OrchestratorExtension.builderEnv()
.useDefaultAdminCredentialsForBuilds(true)
.setSonarVersion(System.getProperty(SQ_VERSION_PROPERTY, DEFAULT_SQ_VERSION))
.addPlugin(MavenLocation.of("org.sonarsource.sonar-lits-plugin", "sonar-lits-plugin", "0.11.0.2659"));
.addPlugin(MavenLocation.of("org.sonarsource.sonar-lits-plugin", "sonar-lits-plugin", "0.11.0.2659"))
.setServerProperty("sonar.telemetry.enable", "false");

addLanguagePlugins(builder);

Expand Down
6 changes: 3 additions & 3 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ dependencyResolutionManagement {

val kotlinVersion: String by extra
val analyzerCommonsVersionStr = "2.16.0.3141"
val sonarPluginApi = "10.11.0.2468" // TODO: to be checked
val sonarPluginApi = "11.1.0.2693"
val slf4jApi = "1.7.30"

create("libs") {
Expand Down Expand Up @@ -74,8 +74,8 @@ dependencyResolutionManagement {
val junit = version("junit", "5.10.1")
val mockito = version("mockito", "5.7.0")
val mockk = version("mockk", "1.13.3")
val orchestrator = version("orchestrator", "5.0.0.2065")
val sonarlint = version("sonarlint", "9.5.0.76302")
val orchestrator = version("orchestrator", "5.1.0.2254")
val sonarlint = version("sonarlint", "10.13.0.79996")
val sonarqube = version("sonarqube", "25.1.0.102122")

library("assertj-core", "org.assertj", "assertj-core").versionRef(assertj)
Expand Down

0 comments on commit 5f8e061

Please sign in to comment.