Skip to content

Commit

Permalink
SONARPHP-1573 Update static RSPEC files and SonarLintTest (#1315)
Browse files Browse the repository at this point in the history
  • Loading branch information
jonas-wielage-sonarsource authored Nov 13, 2024
1 parent 24bb9c2 commit 91df795
Show file tree
Hide file tree
Showing 50 changed files with 549 additions and 195 deletions.
2 changes: 1 addition & 1 deletion .cirrus/modules/qa.star
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
11 changes: 7 additions & 4 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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" }
Expand All @@ -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" }
Expand All @@ -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" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,17 @@ 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)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class PHPIntegrationTest {
static void startServer() {
Tests.provisionProject(PROJECT_KEY, PROJECT_NAME, "php", "it-profile");
SonarScanner build = createScanner()
.setProjectDir(FileLocation.of("../../sources/src/psysh/").getFile())
.setProjectDir(FileLocation.of("../sources/src/psysh/").getFile())
.setProjectKey(PROJECT_KEY)
.setProjectName(PROJECT_NAME)
.setSourceEncoding("UTF-8")
Expand Down
Original file line number Diff line number Diff line change
@@ -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: <a href="https://github.com/SonarSource/sonarlint-core/blob/master/its/tests/src/test/java/its/StandaloneTests.java">
* sonarlint-core StandaloneTests.java</a>
*/
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<Path> shouldRaiseIssue() {
return provideTestFiles();
}

private static List<Path> provideTestFiles() {
List<Path> testFiles;

try (Stream<Path> 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();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,15 @@

class Tests {

public static final String PROJECT_ROOT_DIR = "../projects/";
public static final String PROJECT_ROOT_DIR = "projects/";

private static final String RESOURCE_DIRECTORY = "/com/sonar/it/php/";

public static final String PHP_SENSOR_NAME = "PHP sensor";

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.*");
Expand All @@ -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"))
Expand Down
Loading

0 comments on commit 91df795

Please sign in to comment.