From 5a5f6514c2e0fcdceff646d39cb4bc5df6329396 Mon Sep 17 00:00:00 2001 From: Jonas Wielage Date: Wed, 13 Nov 2024 16:19:04 +0100 Subject: [PATCH] Update SonarLintTest, move test folder --- .cirrus/modules/qa.star | 2 +- README.md | 2 +- gradle/libs.versions.toml | 11 +- its/plugin/{tests => }/build.gradle.kts | 14 +- .../java/com/sonar/it/php/CpdTokenTest.java | 0 .../com/sonar/it/php/CustomRulesTest.java | 0 .../it/php/FrameworkDetectionPHPTest.java | 0 .../java/com/sonar/it/php/NoSonarTest.java | 0 .../com/sonar/it/php/NonPhpProjectTest.java | 0 .../com/sonar/it/php/PHPIntegrationTest.java | 0 .../java/com/sonar/it/php/PHPTest.java | 0 .../java/com/sonar/it/php/PHPUnitTest.java | 0 .../com/sonar/it/php/PhpStanReportTest.java | 0 .../com/sonar/it/php/PsalmReportTest.java | 0 .../java/com/sonar/it/php/SonarLintTest.java | 182 ++++++++++++++ .../sonar/it/php/SuppressWarningsTest.java | 0 .../java/com/sonar/it/php/Tests.java | 8 +- .../utils/MockSonarLintRpcClientDelegate.java | 233 ++++++++++++++++++ .../sonar/it/php/utils/SonarLintUtils.java | 65 +++++ .../com/sonar/it/php/drupal_profile.xml | 0 .../resources/com/sonar/it/php/no_rules.xml | 0 .../resources/com/sonar/it/php/nosonar.xml | 0 .../sonar/it/php/profile-php-custom-rules.xml | 0 .../resources/com/sonar/it/php/profile.xml | 0 .../resources/com/sonar/it/php/sleep.xml | 0 .../java/com/sonar/it/php/SonarLintTest.java | 140 ----------- settings.gradle.kts | 2 +- 27 files changed, 503 insertions(+), 156 deletions(-) rename its/plugin/{tests => }/build.gradle.kts (73%) rename its/plugin/{tests => }/src/integrationTest/java/com/sonar/it/php/CpdTokenTest.java (100%) rename its/plugin/{tests => }/src/integrationTest/java/com/sonar/it/php/CustomRulesTest.java (100%) rename its/plugin/{tests => }/src/integrationTest/java/com/sonar/it/php/FrameworkDetectionPHPTest.java (100%) rename its/plugin/{tests => }/src/integrationTest/java/com/sonar/it/php/NoSonarTest.java (100%) rename its/plugin/{tests => }/src/integrationTest/java/com/sonar/it/php/NonPhpProjectTest.java (100%) rename its/plugin/{tests => }/src/integrationTest/java/com/sonar/it/php/PHPIntegrationTest.java (100%) rename its/plugin/{tests => }/src/integrationTest/java/com/sonar/it/php/PHPTest.java (100%) rename its/plugin/{tests => }/src/integrationTest/java/com/sonar/it/php/PHPUnitTest.java (100%) rename its/plugin/{tests => }/src/integrationTest/java/com/sonar/it/php/PhpStanReportTest.java (100%) rename its/plugin/{tests => }/src/integrationTest/java/com/sonar/it/php/PsalmReportTest.java (100%) create mode 100644 its/plugin/src/integrationTest/java/com/sonar/it/php/SonarLintTest.java rename its/plugin/{tests => }/src/integrationTest/java/com/sonar/it/php/SuppressWarningsTest.java (100%) rename its/plugin/{tests => }/src/integrationTest/java/com/sonar/it/php/Tests.java (96%) create mode 100644 its/plugin/src/integrationTest/java/com/sonar/it/php/utils/MockSonarLintRpcClientDelegate.java create mode 100644 its/plugin/src/integrationTest/java/com/sonar/it/php/utils/SonarLintUtils.java rename its/plugin/{tests => }/src/integrationTest/resources/com/sonar/it/php/drupal_profile.xml (100%) rename its/plugin/{tests => }/src/integrationTest/resources/com/sonar/it/php/no_rules.xml (100%) rename its/plugin/{tests => }/src/integrationTest/resources/com/sonar/it/php/nosonar.xml (100%) rename its/plugin/{tests => }/src/integrationTest/resources/com/sonar/it/php/profile-php-custom-rules.xml (100%) rename its/plugin/{tests => }/src/integrationTest/resources/com/sonar/it/php/profile.xml (100%) rename its/plugin/{tests => }/src/integrationTest/resources/com/sonar/it/php/sleep.xml (100%) delete mode 100644 its/plugin/tests/src/integrationTest/java/com/sonar/it/php/SonarLintTest.java diff --git a/.cirrus/modules/qa.star b/.cirrus/modules/qa.star index 7e3ba392ff..9400c6883b 100644 --- a/.cirrus/modules/qa.star +++ b/.cirrus/modules/qa.star @@ -14,7 +14,7 @@ load( "mkdir_orchestrator_home_script", ) -QA_PLUGIN_GRADLE_TASK = "its:plugin:tests:integrationTest" +QA_PLUGIN_GRADLE_TASK = "its:plugin:integrationTest" QA_RULING_GRADLE_TASK = "its:ruling:integrationTest" QA_QUBE_LATEST_RELEASE = "LATEST_RELEASE" diff --git a/README.md b/README.md index e2ae9d0aef..c8ff329e76 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ Before running any of the integration tests make sure the submodules are checked #### Plugin Test The "Plugin Test" is an additional integration test that verifies plugin features such as metric calculation, coverage, etc. To launch it: ```shell -./gradlew its:plugin:tests:integrationTest +./gradlew its:plugin:integrationTest ``` #### Ruling Test diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b9f9ace36e..4c6a6fb393 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -4,8 +4,8 @@ sonar-plugin-api = "10.13.0.2560" sonarqube = "10.7.0.96327" sonar-scanner-gradle = "5.1.0.4882" sonar-orchestrator = "5.0.0.2065" -sonarlint = "9.8.0.76914" -slf4j = "1.7.36" +sonarlint = "10.9.0.79478" +slf4j = "2.0.16" sslr = "1.24.0.633" junit = "5.11.3" assertj = "3.26.3" @@ -19,6 +19,7 @@ jsr305 = "3.0.2" maven-project = "2.2.1" junit-platform = "1.11.3" staxmate = "2.0.1" +awaitility = "4.2.2" [libraries] sonar-analyzer-commons = { module = "org.sonarsource.analyzer-commons:sonar-analyzer-commons", version.ref = "sonar-commons" } @@ -32,8 +33,9 @@ sonar-testing-harness = { module = "org.sonarsource.sonarqube:sonar-testing-harn sonar-ws = { module = "org.sonarsource.sonarqube:sonar-ws", version.ref = "sonarqube" } sonar-scanner-gradle = { module = "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin", version.ref = "sonar-scanner-gradle" } sonar-orchestrator-junit5 = { module = "org.sonarsource.orchestrator:sonar-orchestrator-junit5", version.ref = "sonar-orchestrator" } -sonarlint-core = { module = "org.sonarsource.sonarlint.core:sonarlint-core", version.ref = "sonarlint" } -sonarlint-plugin-api = { module = "org.sonarsource.sonarlint.core:sonarlint-plugin-api", version.ref = "sonarlint" } +sonar-lint-core = { module = "org.sonarsource.sonarlint.core:sonarlint-core", version.ref = "sonarlint" } +sonar-lint-rpc-java-client = { module = "org.sonarsource.sonarlint.core:sonarlint-rpc-java-client", version.ref = "sonarlint" } +sonar-lint-rpc-impl = { module = "org.sonarsource.sonarlint.core:sonarlint-rpc-impl", version.ref = "sonarlint" } slf4j-api = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" } sslr-core = { module = "org.sonarsource.sslr:sslr-core", version.ref = "sslr" } sslr-toolkit = { module = "org.sonarsource.sslr:sslr-toolkit", version.ref = "sslr" } @@ -50,6 +52,7 @@ jsr305 = { module = "com.google.code.findbugs:jsr305", version.ref = "jsr305" } maven-project = { module = "org.apache.maven:maven-project", version.ref = "maven-project" } junit-platform = { module = "org.junit.platform:junit-platform-suite", version.ref = "junit-platform" } staxmate = { module = "org.codehaus.staxmate:staxmate", version.ref = "staxmate" } +awaitility = { module = "org.awaitility:awaitility", version.ref = "awaitility"} [plugins] spotless = { id = "com.diffplug.spotless", version.ref = "spotless-gradle" } diff --git a/its/plugin/tests/build.gradle.kts b/its/plugin/build.gradle.kts similarity index 73% rename from its/plugin/tests/build.gradle.kts rename to its/plugin/build.gradle.kts index d882521cab..fdd2f6c880 100644 --- a/its/plugin/tests/build.gradle.kts +++ b/its/plugin/build.gradle.kts @@ -7,18 +7,22 @@ plugins { description = "PHP :: Integration Tests :: Plugin" dependencies { - "integrationTestImplementation"(project(":sonar-php-plugin", configuration = "shadow")) + "integrationTestCompileOnly"(project(":sonar-php-plugin", configuration = "shadow")) "integrationTestImplementation"(libs.sonar.orchestrator.junit5) - "integrationTestImplementation"(libs.junit.platform) - "integrationTestImplementation"(libs.sonar.ws) - "integrationTestImplementation"(libs.sonarlint.core) - "integrationTestImplementation"(libs.sonarlint.plugin.api) "integrationTestImplementation"(libs.sonar.plugin.api) + "integrationTestImplementation"(libs.sonar.ws) + "integrationTestImplementation"(libs.sonar.lint.core) + "integrationTestImplementation"(libs.sonar.lint.rpc.java.client) + "integrationTestImplementation"(libs.sonar.lint.rpc.impl) + "integrationTestImplementation"(libs.junit.platform) "integrationTestImplementation"(libs.junit.jupiter) "integrationTestImplementation"(libs.assertj.core) + "integrationTestImplementation"(libs.awaitility) "integrationTestCompileOnly"(libs.jsr305) } +val integrationTest by sourceSets.integrationTest + (tasks["integrationTest"] as Test).filter { setIncludePatterns("Tests") } diff --git a/its/plugin/tests/src/integrationTest/java/com/sonar/it/php/CpdTokenTest.java b/its/plugin/src/integrationTest/java/com/sonar/it/php/CpdTokenTest.java similarity index 100% rename from its/plugin/tests/src/integrationTest/java/com/sonar/it/php/CpdTokenTest.java rename to its/plugin/src/integrationTest/java/com/sonar/it/php/CpdTokenTest.java diff --git a/its/plugin/tests/src/integrationTest/java/com/sonar/it/php/CustomRulesTest.java b/its/plugin/src/integrationTest/java/com/sonar/it/php/CustomRulesTest.java similarity index 100% rename from its/plugin/tests/src/integrationTest/java/com/sonar/it/php/CustomRulesTest.java rename to its/plugin/src/integrationTest/java/com/sonar/it/php/CustomRulesTest.java diff --git a/its/plugin/tests/src/integrationTest/java/com/sonar/it/php/FrameworkDetectionPHPTest.java b/its/plugin/src/integrationTest/java/com/sonar/it/php/FrameworkDetectionPHPTest.java similarity index 100% rename from its/plugin/tests/src/integrationTest/java/com/sonar/it/php/FrameworkDetectionPHPTest.java rename to its/plugin/src/integrationTest/java/com/sonar/it/php/FrameworkDetectionPHPTest.java diff --git a/its/plugin/tests/src/integrationTest/java/com/sonar/it/php/NoSonarTest.java b/its/plugin/src/integrationTest/java/com/sonar/it/php/NoSonarTest.java similarity index 100% rename from its/plugin/tests/src/integrationTest/java/com/sonar/it/php/NoSonarTest.java rename to its/plugin/src/integrationTest/java/com/sonar/it/php/NoSonarTest.java diff --git a/its/plugin/tests/src/integrationTest/java/com/sonar/it/php/NonPhpProjectTest.java b/its/plugin/src/integrationTest/java/com/sonar/it/php/NonPhpProjectTest.java similarity index 100% rename from its/plugin/tests/src/integrationTest/java/com/sonar/it/php/NonPhpProjectTest.java rename to its/plugin/src/integrationTest/java/com/sonar/it/php/NonPhpProjectTest.java diff --git a/its/plugin/tests/src/integrationTest/java/com/sonar/it/php/PHPIntegrationTest.java b/its/plugin/src/integrationTest/java/com/sonar/it/php/PHPIntegrationTest.java similarity index 100% rename from its/plugin/tests/src/integrationTest/java/com/sonar/it/php/PHPIntegrationTest.java rename to its/plugin/src/integrationTest/java/com/sonar/it/php/PHPIntegrationTest.java diff --git a/its/plugin/tests/src/integrationTest/java/com/sonar/it/php/PHPTest.java b/its/plugin/src/integrationTest/java/com/sonar/it/php/PHPTest.java similarity index 100% rename from its/plugin/tests/src/integrationTest/java/com/sonar/it/php/PHPTest.java rename to its/plugin/src/integrationTest/java/com/sonar/it/php/PHPTest.java diff --git a/its/plugin/tests/src/integrationTest/java/com/sonar/it/php/PHPUnitTest.java b/its/plugin/src/integrationTest/java/com/sonar/it/php/PHPUnitTest.java similarity index 100% rename from its/plugin/tests/src/integrationTest/java/com/sonar/it/php/PHPUnitTest.java rename to its/plugin/src/integrationTest/java/com/sonar/it/php/PHPUnitTest.java diff --git a/its/plugin/tests/src/integrationTest/java/com/sonar/it/php/PhpStanReportTest.java b/its/plugin/src/integrationTest/java/com/sonar/it/php/PhpStanReportTest.java similarity index 100% rename from its/plugin/tests/src/integrationTest/java/com/sonar/it/php/PhpStanReportTest.java rename to its/plugin/src/integrationTest/java/com/sonar/it/php/PhpStanReportTest.java diff --git a/its/plugin/tests/src/integrationTest/java/com/sonar/it/php/PsalmReportTest.java b/its/plugin/src/integrationTest/java/com/sonar/it/php/PsalmReportTest.java similarity index 100% rename from its/plugin/tests/src/integrationTest/java/com/sonar/it/php/PsalmReportTest.java rename to its/plugin/src/integrationTest/java/com/sonar/it/php/PsalmReportTest.java diff --git a/its/plugin/src/integrationTest/java/com/sonar/it/php/SonarLintTest.java b/its/plugin/src/integrationTest/java/com/sonar/it/php/SonarLintTest.java new file mode 100644 index 0000000000..544d1d1703 --- /dev/null +++ b/its/plugin/src/integrationTest/java/com/sonar/it/php/SonarLintTest.java @@ -0,0 +1,182 @@ +/* + * SonarQube PHP Plugin + * Copyright (C) 2010-2024 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package com.sonar.it.php; + +import com.sonar.it.php.utils.MockSonarLintRpcClientDelegate; +import com.sonar.it.php.utils.SonarLintUtils; +import java.io.IOException; +import java.io.PipedInputStream; +import java.io.PipedOutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.time.Duration; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.stream.Stream; +import org.awaitility.Awaitility; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.io.TempDir; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.sonarsource.sonarlint.core.rpc.client.ClientJsonRpcLauncher; +import org.sonarsource.sonarlint.core.rpc.client.SonarLintRpcClientDelegate; +import org.sonarsource.sonarlint.core.rpc.impl.BackendJsonRpcLauncher; +import org.sonarsource.sonarlint.core.rpc.protocol.SonarLintRpcServer; +import org.sonarsource.sonarlint.core.rpc.protocol.backend.analysis.AnalyzeFilesParams; +import org.sonarsource.sonarlint.core.rpc.protocol.backend.analysis.AnalyzeFilesResponse; +import org.sonarsource.sonarlint.core.rpc.protocol.backend.file.DidUpdateFileSystemParams; +import org.sonarsource.sonarlint.core.rpc.protocol.backend.initialize.HttpConfigurationDto; +import org.sonarsource.sonarlint.core.rpc.protocol.backend.initialize.InitializeParams; +import org.sonarsource.sonarlint.core.rpc.protocol.common.ClientFileDto; +import org.sonarsource.sonarlint.core.serverconnection.FileUtils; + +import static com.sonar.it.php.utils.SonarLintUtils.ENABLED_LANGUAGES; +import static com.sonar.it.php.utils.SonarLintUtils.IT_CLIENT_INFO; +import static com.sonar.it.php.utils.SonarLintUtils.IT_TELEMETRY_ATTRIBUTES; +import static com.sonar.it.php.utils.SonarLintUtils.toMap; +import static java.util.Collections.emptyList; +import static java.util.Collections.emptyMap; +import static java.util.Collections.emptySet; +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Inspiration: + * sonarlint-core StandaloneTests.java + */ +public class SonarLintTest { + public static final Path BASE_DIR = Paths.get("projects/sonarlint"); + private static final String CONFIG_SCOPE_ID = "my-ide-project-name"; + + @TempDir + private static Path sonarUserHome; + + private static SonarLintRpcServer backend; + private static SonarLintRpcClientDelegate client; + + @BeforeAll + static void prepare() throws IOException, ExecutionException, InterruptedException { + startBackend(); + } + + @AfterEach + void reset() { + ((MockSonarLintRpcClientDelegate) client).getRaisedIssues().clear(); + } + + @AfterAll + static void cleanup() throws InterruptedException, ExecutionException, TimeoutException { + backend.shutdown().get(1_000, TimeUnit.MILLISECONDS); + FileUtils.deleteRecursively(sonarUserHome); + } + + private static SonarLintRpcClientDelegate newMockSonarLintClient() { + return new MockSonarLintRpcClientDelegate(); + } + + @ParameterizedTest + @MethodSource + void shouldRaiseIssue(Path inputFile) { + var analyzeResponse = analyzeFile(CONFIG_SCOPE_ID, inputFile); + + assertThat(analyzeResponse.getFailedAnalysisFiles()).isEmpty(); + // it could happen that the notification is not yet received while the analysis request is finished. + Awaitility.await().atMost(Duration.ofMillis(200)).untilAsserted( + () -> assertThat(((MockSonarLintRpcClientDelegate) client).getRaisedIssues(CONFIG_SCOPE_ID)).hasSize(3)); + } + + static List shouldRaiseIssue() { + return provideTestFiles(); + } + + private static List provideTestFiles() { + List testFiles; + + try (Stream pathStream = Files.list(BASE_DIR)) { + testFiles = pathStream + .map(Path::getFileName) + .map(BASE_DIR::resolve) + .toList(); + } catch (IOException e) { + throw new AssertionError("Can not load test files from " + BASE_DIR, e); + } + + if (testFiles.isEmpty()) { + throw new AssertionError("There are no test files provided"); + } + + return testFiles; + } + + private static AnalyzeFilesResponse analyzeFile(String configScopeId, Path filePath, String... properties) { + var fileUri = filePath.toUri(); + backend.getFileService().didUpdateFileSystem( + new DidUpdateFileSystemParams(List.of(), List.of( + new ClientFileDto(fileUri, filePath, configScopeId, false, null, filePath.toAbsolutePath(), null, null, true)))); + + return backend.getAnalysisService().analyzeFiles( + new AnalyzeFilesParams(configScopeId, UUID.randomUUID(), List.of(fileUri), toMap(properties), System.currentTimeMillis())) + .join(); + } + + static void startBackend() throws IOException, ExecutionException, InterruptedException { + var clientToServerOutputStream = new PipedOutputStream(); + var clientToServerInputStream = new PipedInputStream(clientToServerOutputStream); + + var serverToClientOutputStream = new PipedOutputStream(); + var serverToClientInputStream = new PipedInputStream(serverToClientOutputStream); + client = newMockSonarLintClient(); + new BackendJsonRpcLauncher(clientToServerInputStream, serverToClientOutputStream); + var clientLauncher = new ClientJsonRpcLauncher(serverToClientInputStream, clientToServerOutputStream, client); + backend = clientLauncher.getServerProxy(); + + var featureFlags = SonarLintUtils.featureFlagsForStandaloneMode(); + backend.initialize( + new InitializeParams( + IT_CLIENT_INFO, + IT_TELEMETRY_ATTRIBUTES, + HttpConfigurationDto.defaultConfig(), + null, + featureFlags, + sonarUserHome.resolve("storage"), + sonarUserHome.resolve("work"), + Set.of(Tests.PHP_PLUGIN_LOCATION.getFile().toPath()), + emptyMap(), + ENABLED_LANGUAGES, + emptySet(), + emptySet(), + emptyList(), + emptyList(), + sonarUserHome.toString(), + Map.of(), + false, + null, + false, + null)) + .get(); + } +} diff --git a/its/plugin/tests/src/integrationTest/java/com/sonar/it/php/SuppressWarningsTest.java b/its/plugin/src/integrationTest/java/com/sonar/it/php/SuppressWarningsTest.java similarity index 100% rename from its/plugin/tests/src/integrationTest/java/com/sonar/it/php/SuppressWarningsTest.java rename to its/plugin/src/integrationTest/java/com/sonar/it/php/SuppressWarningsTest.java diff --git a/its/plugin/tests/src/integrationTest/java/com/sonar/it/php/Tests.java b/its/plugin/src/integrationTest/java/com/sonar/it/php/Tests.java similarity index 96% rename from its/plugin/tests/src/integrationTest/java/com/sonar/it/php/Tests.java rename to its/plugin/src/integrationTest/java/com/sonar/it/php/Tests.java index 1e4fb210f3..741377f7e6 100644 --- a/its/plugin/tests/src/integrationTest/java/com/sonar/it/php/Tests.java +++ b/its/plugin/src/integrationTest/java/com/sonar/it/php/Tests.java @@ -59,7 +59,7 @@ class Tests { public static final String PHP_INI_SENSOR_NAME = "Analyzer for \"php.ini\" files"; - public static final FileLocation PHP_PLUGIN_LOCATION = FileLocation.byWildcardFilename(new File("../../../sonar-php-plugin/build/libs"), "sonar-php-plugin-*-all.jar"); + public static final FileLocation PHP_PLUGIN_LOCATION = FileLocation.byWildcardFilename(new File("../../sonar-php-plugin/build/libs"), "sonar-php-plugin-*-all.jar"); public static final String SCANNER_VERSION = "6.1.0.4477"; private static final Pattern DEBUG_AND_INFO_LOG_LINE_PATTERN = Pattern.compile("\\d{2}:\\d{2}:\\d{2}\\.\\d{3}\\s(INFO|DEBUG)\\s.*"); @@ -74,7 +74,7 @@ class Tests { .restoreProfileAtStartup(FileLocation.ofClasspath(RESOURCE_DIRECTORY + "drupal_profile.xml")) .restoreProfileAtStartup(FileLocation.ofClasspath(RESOURCE_DIRECTORY + "no_rules.xml")) // Custom rules plugin - .addPlugin(FileLocation.byWildcardFilename(new File("../../../php-custom-rules-plugin/build/libs"), "php-custom-rules-plugin-*-all.jar")) + .addPlugin(FileLocation.byWildcardFilename(new File("../../php-custom-rules-plugin/build/libs"), "php-custom-rules-plugin-*-all.jar")) .restoreProfileAtStartup(FileLocation.ofClasspath(RESOURCE_DIRECTORY + "profile-php-custom-rules.xml")) .restoreProfileAtStartup(FileLocation.ofClasspath(RESOURCE_DIRECTORY + "nosonar.xml")) .restoreProfileAtStartup(FileLocation.ofClasspath(RESOURCE_DIRECTORY + "sleep.xml")) @@ -125,8 +125,8 @@ static Double getMeasureAsDouble(String componentKey, String metricKey) { @CheckForNull static Components.Component getComponent(String projectKey, String componentKey) { List components = newWsClient().components().tree(new TreeRequest() - .setComponent(projectKey) - .setQ(componentKey)) + .setComponent(projectKey) + .setQ(componentKey)) .getComponentsList(); return components.size() == 1 ? components.get(0) : null; } diff --git a/its/plugin/src/integrationTest/java/com/sonar/it/php/utils/MockSonarLintRpcClientDelegate.java b/its/plugin/src/integrationTest/java/com/sonar/it/php/utils/MockSonarLintRpcClientDelegate.java new file mode 100644 index 0000000000..b09d3639e7 --- /dev/null +++ b/its/plugin/src/integrationTest/java/com/sonar/it/php/utils/MockSonarLintRpcClientDelegate.java @@ -0,0 +1,233 @@ +/* + * SonarQube PHP Plugin + * Copyright (C) 2010-2024 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package com.sonar.it.php.utils; + +import java.net.URI; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.CancellationException; +import org.sonarsource.sonarlint.core.rpc.client.ConfigScopeNotFoundException; +import org.sonarsource.sonarlint.core.rpc.client.ConnectionNotFoundException; +import org.sonarsource.sonarlint.core.rpc.client.SonarLintCancelChecker; +import org.sonarsource.sonarlint.core.rpc.client.SonarLintRpcClientDelegate; +import org.sonarsource.sonarlint.core.rpc.protocol.backend.config.binding.BindingSuggestionDto; +import org.sonarsource.sonarlint.core.rpc.protocol.backend.tracking.TaintVulnerabilityDto; +import org.sonarsource.sonarlint.core.rpc.protocol.client.analysis.RawIssueDto; +import org.sonarsource.sonarlint.core.rpc.protocol.client.binding.AssistBindingParams; +import org.sonarsource.sonarlint.core.rpc.protocol.client.binding.AssistBindingResponse; +import org.sonarsource.sonarlint.core.rpc.protocol.client.binding.NoBindingSuggestionFoundParams; +import org.sonarsource.sonarlint.core.rpc.protocol.client.connection.AssistCreatingConnectionParams; +import org.sonarsource.sonarlint.core.rpc.protocol.client.connection.AssistCreatingConnectionResponse; +import org.sonarsource.sonarlint.core.rpc.protocol.client.connection.ConnectionSuggestionDto; +import org.sonarsource.sonarlint.core.rpc.protocol.client.event.DidReceiveServerHotspotEvent; +import org.sonarsource.sonarlint.core.rpc.protocol.client.fix.FixSuggestionDto; +import org.sonarsource.sonarlint.core.rpc.protocol.client.hotspot.HotspotDetailsDto; +import org.sonarsource.sonarlint.core.rpc.protocol.client.http.GetProxyPasswordAuthenticationResponse; +import org.sonarsource.sonarlint.core.rpc.protocol.client.http.ProxyDto; +import org.sonarsource.sonarlint.core.rpc.protocol.client.http.X509CertificateDto; +import org.sonarsource.sonarlint.core.rpc.protocol.client.issue.IssueDetailsDto; +import org.sonarsource.sonarlint.core.rpc.protocol.client.log.LogParams; +import org.sonarsource.sonarlint.core.rpc.protocol.client.message.MessageType; +import org.sonarsource.sonarlint.core.rpc.protocol.client.message.ShowSoonUnsupportedMessageParams; +import org.sonarsource.sonarlint.core.rpc.protocol.client.progress.ReportProgressParams; +import org.sonarsource.sonarlint.core.rpc.protocol.client.progress.StartProgressParams; +import org.sonarsource.sonarlint.core.rpc.protocol.client.smartnotification.ShowSmartNotificationParams; +import org.sonarsource.sonarlint.core.rpc.protocol.client.telemetry.TelemetryClientLiveAttributesResponse; +import org.sonarsource.sonarlint.core.rpc.protocol.common.ClientFileDto; +import org.sonarsource.sonarlint.core.rpc.protocol.common.Either; +import org.sonarsource.sonarlint.core.rpc.protocol.common.TokenDto; +import org.sonarsource.sonarlint.core.rpc.protocol.common.UsernamePasswordDto; + +/** + * Inspiration: + * sonarlint-core MockSonarLintRpcClientDelegate.java + */ +public class MockSonarLintRpcClientDelegate implements SonarLintRpcClientDelegate { + private final Map> raisedIssues = new HashMap<>(); + + public List getRaisedIssues(String configurationScopeId) { + var issues = raisedIssues.get(configurationScopeId); + return issues != null ? issues : List.of(); + } + + public Map> getRaisedIssues() { + return raisedIssues; + } + + @Override + public void didRaiseIssue(String configurationScopeId, UUID analysisId, RawIssueDto rawIssue) { + raisedIssues.computeIfAbsent(configurationScopeId, k -> new ArrayList<>()).add(rawIssue); + } + + @Override + public void suggestBinding(Map> suggestionsByConfigScope) { + + } + + @Override + public void suggestConnection(Map> suggestionsByConfigScope) { + + } + + @Override + public void openUrlInBrowser(URL url) { + + } + + @Override + public void showMessage(MessageType type, String text) { + + } + + @Override + public void log(LogParams params) { + System.out.println(params); + } + + @Override + public void showSoonUnsupportedMessage(ShowSoonUnsupportedMessageParams params) { + + } + + @Override + public void showSmartNotification(ShowSmartNotificationParams params) { + + } + + @Override + public String getClientLiveDescription() { + return ""; + } + + @Override + public void showHotspot(String configurationScopeId, HotspotDetailsDto hotspotDetails) { + + } + + @Override + public void showIssue(String configurationScopeId, IssueDetailsDto issueDetails) { + + } + + @Override + public void showFixSuggestion(String configurationScopeId, String issueKey, FixSuggestionDto fixSuggestion) { + + } + + @Override + public AssistCreatingConnectionResponse assistCreatingConnection(AssistCreatingConnectionParams params, SonarLintCancelChecker cancelChecker) throws CancellationException { + throw new CancellationException("Unsupported in ITS"); + } + + @Override + public AssistBindingResponse assistBinding(AssistBindingParams params, SonarLintCancelChecker cancelChecker) throws CancellationException { + throw new CancellationException("Unsupported in ITS"); + } + + @Override + public void startProgress(StartProgressParams params) throws UnsupportedOperationException { + + } + + @Override + public void reportProgress(ReportProgressParams params) { + + } + + @Override + public void didSynchronizeConfigurationScopes(Set configurationScopeIds) { + + } + + @Override + public Either getCredentials(String connectionId) throws ConnectionNotFoundException { + throw new ConnectionNotFoundException(); + } + + @Override + public List selectProxies(URI uri) { + return List.of(ProxyDto.NO_PROXY); + } + + @Override + public GetProxyPasswordAuthenticationResponse getProxyPasswordAuthentication(String host, int port, String protocol, String prompt, String scheme, URL targetHost) { + return new GetProxyPasswordAuthenticationResponse("", ""); + } + + @Override + public boolean checkServerTrusted(List chain, String authType) { + return false; + } + + @Override + public void didReceiveServerHotspotEvent(DidReceiveServerHotspotEvent params) { + + } + + @Override + public String matchSonarProjectBranch(String configurationScopeId, String mainBranchName, Set allBranchesNames, SonarLintCancelChecker cancelChecker) + throws ConfigScopeNotFoundException { + return mainBranchName; + } + + public boolean matchProjectBranch(String configurationScopeId, String branchNameToMatch, SonarLintCancelChecker cancelChecker) throws ConfigScopeNotFoundException { + return true; + } + + @Override + public void didChangeMatchedSonarProjectBranch(String configScopeId, String newMatchedBranchName) { + + } + + @Override + public TelemetryClientLiveAttributesResponse getTelemetryLiveAttributes() { + System.err.println("Telemetry should be disabled in ITs"); + throw new CancellationException("Telemetry should be disabled in ITs"); + } + + @Override + public void didChangeTaintVulnerabilities(String configurationScopeId, Set closedTaintVulnerabilityIds, List addedTaintVulnerabilities, + List updatedTaintVulnerabilities) { + + } + + @Override + public List listFiles(String configScopeId) { + return List.of(); + } + + @Override + public void noBindingSuggestionFound(NoBindingSuggestionFoundParams params) { + } + + @Override + public void didChangeAnalysisReadiness(Set configurationScopeIds, boolean areReadyForAnalysis) { + + } + + public void clear() { + raisedIssues.clear(); + } +} diff --git a/its/plugin/src/integrationTest/java/com/sonar/it/php/utils/SonarLintUtils.java b/its/plugin/src/integrationTest/java/com/sonar/it/php/utils/SonarLintUtils.java new file mode 100644 index 0000000000..5df8b29170 --- /dev/null +++ b/its/plugin/src/integrationTest/java/com/sonar/it/php/utils/SonarLintUtils.java @@ -0,0 +1,65 @@ +/* + * SonarQube PHP Plugin + * Copyright (C) 2010-2024 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package com.sonar.it.php.utils; + +import com.google.common.base.Preconditions; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import org.sonarsource.sonarlint.core.rpc.protocol.backend.initialize.ClientConstantInfoDto; +import org.sonarsource.sonarlint.core.rpc.protocol.backend.initialize.FeatureFlagsDto; +import org.sonarsource.sonarlint.core.rpc.protocol.backend.initialize.TelemetryClientConstantAttributesDto; +import org.sonarsource.sonarlint.core.rpc.protocol.common.Language; + +import static java.util.Collections.emptyMap; + +public class SonarLintUtils { + public static final Set ENABLED_LANGUAGES = EnumSet.of(Language.PHP); + public static final ClientConstantInfoDto IT_CLIENT_INFO = new ClientConstantInfoDto("clientName", "integrationTests"); + public static final TelemetryClientConstantAttributesDto IT_TELEMETRY_ATTRIBUTES = new TelemetryClientConstantAttributesDto( + "SonarLint ITs", "SonarLint ITs", "1.2.3", "4.5.6", emptyMap()); + + public static FeatureFlagsDto featureFlagsForStandaloneMode() { + return new FeatureFlagsDto( + true, + true, + true, + false, + true, + true, + false, + true, + false, + false); + } + + public static Map toMap(String[] keyValues) { + Preconditions.checkArgument(keyValues.length % 2 == 0, "Must be an even number of key/values"); + Map map = new HashMap<>(); + var index = 0; + while (index < keyValues.length) { + var key = keyValues[index++]; + var value = keyValues[index++]; + map.put(key, value); + } + return map; + } +} diff --git a/its/plugin/tests/src/integrationTest/resources/com/sonar/it/php/drupal_profile.xml b/its/plugin/src/integrationTest/resources/com/sonar/it/php/drupal_profile.xml similarity index 100% rename from its/plugin/tests/src/integrationTest/resources/com/sonar/it/php/drupal_profile.xml rename to its/plugin/src/integrationTest/resources/com/sonar/it/php/drupal_profile.xml diff --git a/its/plugin/tests/src/integrationTest/resources/com/sonar/it/php/no_rules.xml b/its/plugin/src/integrationTest/resources/com/sonar/it/php/no_rules.xml similarity index 100% rename from its/plugin/tests/src/integrationTest/resources/com/sonar/it/php/no_rules.xml rename to its/plugin/src/integrationTest/resources/com/sonar/it/php/no_rules.xml diff --git a/its/plugin/tests/src/integrationTest/resources/com/sonar/it/php/nosonar.xml b/its/plugin/src/integrationTest/resources/com/sonar/it/php/nosonar.xml similarity index 100% rename from its/plugin/tests/src/integrationTest/resources/com/sonar/it/php/nosonar.xml rename to its/plugin/src/integrationTest/resources/com/sonar/it/php/nosonar.xml diff --git a/its/plugin/tests/src/integrationTest/resources/com/sonar/it/php/profile-php-custom-rules.xml b/its/plugin/src/integrationTest/resources/com/sonar/it/php/profile-php-custom-rules.xml similarity index 100% rename from its/plugin/tests/src/integrationTest/resources/com/sonar/it/php/profile-php-custom-rules.xml rename to its/plugin/src/integrationTest/resources/com/sonar/it/php/profile-php-custom-rules.xml diff --git a/its/plugin/tests/src/integrationTest/resources/com/sonar/it/php/profile.xml b/its/plugin/src/integrationTest/resources/com/sonar/it/php/profile.xml similarity index 100% rename from its/plugin/tests/src/integrationTest/resources/com/sonar/it/php/profile.xml rename to its/plugin/src/integrationTest/resources/com/sonar/it/php/profile.xml diff --git a/its/plugin/tests/src/integrationTest/resources/com/sonar/it/php/sleep.xml b/its/plugin/src/integrationTest/resources/com/sonar/it/php/sleep.xml similarity index 100% rename from its/plugin/tests/src/integrationTest/resources/com/sonar/it/php/sleep.xml rename to its/plugin/src/integrationTest/resources/com/sonar/it/php/sleep.xml diff --git a/its/plugin/tests/src/integrationTest/java/com/sonar/it/php/SonarLintTest.java b/its/plugin/tests/src/integrationTest/java/com/sonar/it/php/SonarLintTest.java deleted file mode 100644 index 256810421a..0000000000 --- a/its/plugin/tests/src/integrationTest/java/com/sonar/it/php/SonarLintTest.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * SonarQube PHP Plugin - * Copyright (C) 2010-2024 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package com.sonar.it.php; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.net.URI; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; -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.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.Language; - -import static org.assertj.core.api.Assertions.assertThat; - -class SonarLintTest { - - @TempDir - public static File tempDirectory; - - private static StandaloneSonarLintEngine sonarlintEngine; - - private static Path baseDir; - - @BeforeAll - static void prepare() { - StandaloneGlobalConfiguration sonarLintConfig = StandaloneGlobalConfiguration.builder() - .addPlugin(Tests.PHP_PLUGIN_LOCATION.getFile().toPath()) - .addEnabledLanguage(Language.PHP) - .setSonarLintUserHome(tempDirectory.toPath()) - .setLogOutput((formattedMessage, level) -> { - /* Don't pollute logs */ - }) - .build(); - sonarlintEngine = new StandaloneSonarLintEngineImpl(sonarLintConfig); - baseDir = tempDirectory.toPath(); - } - - @AfterAll - static void stop() { - sonarlintEngine.stop(); - } - - @Test - void shouldRaiseIssues() throws IOException { - Path filePath = Tests.projectDirectoryFor("sonarlint").toPath().resolve("Math.php"); - filePath = Files.copy(filePath, baseDir.resolve("Math.php")); - ClientInputFile inputFile = prepareInputFile(filePath, false); - - List issues = new ArrayList<>(); - StandaloneAnalysisConfiguration configuration = StandaloneAnalysisConfiguration.builder() - .setBaseDir(baseDir) - .addInputFile(inputFile) - .build(); - sonarlintEngine.analyze(configuration, issues::add, null, null); - - assertThat(issues).hasSize(3); - } - - private ClientInputFile prepareInputFile(Path filePath, final boolean isTest) { - return createInputFile(filePath, isTest); - } - - private ClientInputFile createInputFile(final Path path, final boolean isTest) { - return new ClientInputFile() { - - @Override - public String getPath() { - return path.toString(); - } - - @Override - public boolean isTest() { - return isTest; - } - - @Override - public Charset getCharset() { - return StandardCharsets.UTF_8; - } - - @Override - public G getClientObject() { - return null; - } - - @Override - public String contents() throws IOException { - return new String(Files.readAllBytes(path), StandardCharsets.UTF_8); - } - - @Override - public String relativePath() { - return path.toString(); - } - - @Override - public URI uri() { - return path.toUri(); - } - - @Override - public InputStream inputStream() throws IOException { - return Files.newInputStream(path); - } - - }; - } - -} diff --git a/settings.gradle.kts b/settings.gradle.kts index f19d56e52d..618efa2bb1 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -35,7 +35,7 @@ include(":sonar-php-plugin") include(":php-frontend") include(":php-checks") include(":php-custom-rules-plugin") -include(":its:plugin:tests") +include(":its:plugin") include(":its:ruling") gradle.allprojects {