diff options
author | Daniel Schwarz <bartfastiel@users.noreply.github.com> | 2017-08-14 14:34:29 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-08-14 14:34:29 +0200 |
commit | ffff02cbed3e5f94bbf0c1718425d66e19ac3901 (patch) | |
tree | 6d99fd0df0913d32b37da9c8b3a280af6ad856d1 /tests/src/test/java | |
parent | 3a98cfe82a4eaf08eade2517dd115837b0126799 (diff) | |
download | sonarqube-ffff02cbed3e5f94bbf0c1718425d66e19ac3901.tar.gz sonarqube-ffff02cbed3e5f94bbf0c1718425d66e19ac3901.zip |
SONAR-9704 verify that the compute engine is resilient
Diffstat (limited to 'tests/src/test/java')
6 files changed, 263 insertions, 10 deletions
diff --git a/tests/src/test/java/org/sonarqube/tests/Byteman.java b/tests/src/test/java/org/sonarqube/tests/Byteman.java index ccb025e34f9..59dc06f8112 100644 --- a/tests/src/test/java/org/sonarqube/tests/Byteman.java +++ b/tests/src/test/java/org/sonarqube/tests/Byteman.java @@ -21,6 +21,10 @@ import com.sonar.orchestrator.OrchestratorBuilder; import java.io.File; +import java.net.InetAddress; +import java.util.Collections; +import org.jboss.byteman.agent.submit.Submit; +import org.sonar.process.NetworkUtils; import static java.lang.String.format; @@ -30,14 +34,25 @@ import static java.lang.String.format; */ public class Byteman { - public static OrchestratorBuilder enableScript(OrchestratorBuilder builder, String filename) { + private final int port; + private final OrchestratorBuilder builder; + + public enum Process { + WEB("sonar.web.javaAdditionalOpts"), CE("sonar.ce.javaAdditionalOpts"); + + private final String argument; + + Process(String argument) { + this.argument = argument; + } + } + + public Byteman(OrchestratorBuilder builder, Process process) { + this.builder = builder; String jar = findBytemanJar(); - builder - .setServerProperty("sonar.web.javaAdditionalOpts", - format("-javaagent:%s=script:%s,boot:%s", jar, findBytemanScript(filename), jar)) - .setServerProperty("sonar.search.recovery.delayInMs", "1000") - .setServerProperty("sonar.search.recovery.minAgeInMs", "3000"); - return builder; + port = NetworkUtils.getNextAvailablePort(InetAddress.getLoopbackAddress()); + String bytemanArg = format("-javaagent:%s=boot:%s,port:%d", jar, jar, port); + builder.setServerProperty(process.argument, bytemanArg); } private static String findBytemanJar() { @@ -49,6 +64,12 @@ public class Byteman { return jar.getAbsolutePath(); } + public void activateScript(String filename) throws Exception { + String bytemanScript = findBytemanScript(filename); + Submit submit = new Submit(InetAddress.getLoopbackAddress().getHostAddress(), port); + submit.addRulesFromFiles(Collections.singletonList(bytemanScript)); + } + private static String findBytemanScript(String filename) { // see pom.xml, Maven copies and renames the artifact. File script = new File( filename); @@ -57,4 +78,19 @@ public class Byteman { } return script.getAbsolutePath(); } + + public void deactivateAllRules() throws Exception { + Submit submit = new Submit(InetAddress.getLoopbackAddress().getHostAddress(), port); + try { + submit.deleteAllRules(); + } catch (java.lang.Exception e) { + if (e.getMessage() == null || !e.getMessage().contains("No rule scripts to remove")) { + throw e; + } + } + } + + public OrchestratorBuilder getOrchestratorBuilder() { + return builder; + } } diff --git a/tests/src/test/java/org/sonarqube/tests/QProfileTester.java b/tests/src/test/java/org/sonarqube/tests/QProfileTester.java index 764b80d6955..c2d163151c6 100644 --- a/tests/src/test/java/org/sonarqube/tests/QProfileTester.java +++ b/tests/src/test/java/org/sonarqube/tests/QProfileTester.java @@ -26,8 +26,10 @@ import org.sonarqube.ws.Common; import org.sonarqube.ws.Organizations.Organization; import org.sonarqube.ws.QualityProfiles.CreateWsResponse.QualityProfile; import org.sonarqube.ws.Rules; +import org.sonarqube.ws.WsProjects.CreateWsResponse.Project; import org.sonarqube.ws.client.HttpException; import org.sonarqube.ws.client.qualityprofile.ActivateRuleWsRequest; +import org.sonarqube.ws.client.qualityprofile.AddProjectRequest; import org.sonarqube.ws.client.qualityprofile.CreateRequest; import org.sonarqube.ws.client.qualityprofile.QualityProfilesService; import org.sonarqube.ws.client.rule.SearchWsRequest; @@ -79,6 +81,14 @@ public class QProfileTester { return this; } + public QProfileTester assignQProfileToProject(QualityProfile profile, Project project) { + service().addProject(AddProjectRequest.builder() + .setProjectKey(project.getKey()) + .setProfileKey(profile.getKey()) + .build()); + return this; + } + public QProfileTester assertThatNumberOfActiveRulesEqualsTo(QualityProfile profile, int expectedActiveRules) { return assertThatNumberOfActiveRulesEqualsTo(profile.getKey(), expectedActiveRules); } diff --git a/tests/src/test/java/org/sonarqube/tests/analysis/AnalysisEsResilienceTest.java b/tests/src/test/java/org/sonarqube/tests/analysis/AnalysisEsResilienceTest.java new file mode 100644 index 00000000000..6d6adeb2030 --- /dev/null +++ b/tests/src/test/java/org/sonarqube/tests/analysis/AnalysisEsResilienceTest.java @@ -0,0 +1,150 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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 org.sonarqube.tests.analysis; + +import com.sonar.orchestrator.Orchestrator; +import com.sonar.orchestrator.build.BuildResult; +import com.sonar.orchestrator.build.SonarScanner; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.junit.After; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.sonarqube.tests.Byteman; +import org.sonarqube.tests.Tester; +import org.sonarqube.ws.Issues; +import org.sonarqube.ws.Organizations.Organization; +import org.sonarqube.ws.QualityProfiles.CreateWsResponse.QualityProfile; +import org.sonarqube.ws.WsProjects; +import org.sonarqube.ws.WsUsers.CreateWsResponse.User; +import org.sonarqube.ws.client.component.SuggestionsWsRequest; +import org.sonarqube.ws.client.issue.SearchWsRequest; +import util.ItUtils; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.tuple; +import static org.sonarqube.tests.Byteman.Process.CE; +import static util.ItUtils.projectDir; + +public class AnalysisEsResilienceTest { + + @ClassRule + public static final Orchestrator orchestrator; + private static final Byteman byteman; + + static { + byteman = new Byteman(Orchestrator.builderEnv(), CE); + orchestrator = byteman + .getOrchestratorBuilder() + .addPlugin(ItUtils.xooPlugin()) + .build(); + } + + @Rule + public Tester tester = new Tester(orchestrator); + + @After + public void after() throws Exception { + byteman.deactivateAllRules(); + } + + @Test + public void activation_and_deactivation_of_rule_is_resilient_to_indexing_errors() throws Exception { + Organization organization = tester.organizations().generate(); + User orgAdministrator = tester.users().generateAdministrator(organization); + WsProjects.CreateWsResponse.Project project = tester.projects().generate(organization); + String projectKey = project.getKey(); + String fileKey = projectKey + ":src/main/xoo/sample/Sample.xoo"; + String file2Key = projectKey + ":src/main/xoo/sample/Sample2.xoo"; + String file3Key = projectKey + ":src/main/xoo/sample/Sample3.xoo"; + + QualityProfile profile = tester.qProfiles().createXooProfile(organization); + tester.qProfiles() + .activateRule(profile, "xoo:OneIssuePerFile") + .assignQProfileToProject(profile, project); + + executeAnalysis(projectKey, organization, orgAdministrator, "analysis/resilience/resilience-sample-v1"); + assertThat(searchFile(fileKey, organization)).isNotEmpty(); + assertThat(searchFile(file2Key, organization)).isEmpty(); + assertThat(searchFile(file3Key, organization)).isEmpty(); + List<Issues.Issue> issues = searchIssues(projectKey); + assertThat(issues) + .extracting(Issues.Issue::getComponent) + .containsExactlyInAnyOrder(fileKey); + + byteman.activateScript("resilience/making_ce_indexation_failing.btm"); + executeAnalysis(projectKey, organization, orgAdministrator, "analysis/resilience/resilience-sample-v2"); + assertThat(searchFile(fileKey, organization)).isNotEmpty(); + assertThat(searchFile(file2Key, organization)).isEmpty();// inconsistency: in DB there is also file2Key + assertThat(searchFile(file3Key, organization)).isEmpty();// inconsistency: in DB there is also file3Key + issues = searchIssues(projectKey); + assertThat(issues) + .extracting(Issues.Issue::getComponent) + .containsExactlyInAnyOrder(fileKey /* inconsistency: in DB there is also file2Key and file3Key */); + byteman.deactivateAllRules(); + + executeAnalysis(projectKey, organization, orgAdministrator, "analysis/resilience/resilience-sample-v3"); + assertThat(searchFile(fileKey, organization)).isNotEmpty(); + assertThat(searchFile(file2Key, organization)).isEmpty(); + assertThat(searchFile(file3Key, organization)).isNotEmpty(); + issues = searchIssues(projectKey); + assertThat(issues) + .extracting(Issues.Issue::getComponent, Issues.Issue::getStatus) + .containsExactlyInAnyOrder( + tuple(fileKey, "OPEN"), + tuple(file2Key, "CLOSED"), + tuple(file3Key, "OPEN")); + } + + private List<Issues.Issue> searchIssues(String projectKey) { + SearchWsRequest request = new SearchWsRequest() + .setProjectKeys(Collections.singletonList(projectKey)); + Issues.SearchWsResponse results = tester.wsClient().issues().search(request); + return results.getIssuesList(); + } + + private List<String> searchFile(String key, Organization organization) { + SuggestionsWsRequest query = SuggestionsWsRequest.builder() + .setS(key) + .build(); + Map<String, Object> response = ItUtils.jsonToMap( + tester.wsClient().components().suggestions(query).content() + ); + List results = (List) response.get("results"); + Map trkResult = (Map) results.stream().filter(result -> "FIL".equals(((Map) result).get("q"))).findAny().get(); + List items = (List) trkResult.get("items"); + Stream<String> x = items.stream().map(item -> (String) ((Map) item).get("key")); + return x.collect(Collectors.toList()); + } + + private String executeAnalysis(String projectKey, Organization organization, User orgAdministrator, String projectPath) { + BuildResult buildResult = orchestrator.executeBuild(SonarScanner.create(projectDir(projectPath), + "sonar.organization", organization.getKey(), + "sonar.projectKey", projectKey, + "sonar.login", orgAdministrator.getLogin(), + "sonar.password", orgAdministrator.getLogin())); + return ItUtils.extractCeTaskId(buildResult); + } + +} diff --git a/tests/src/test/java/org/sonarqube/tests/qualityProfile/ActiveRuleEsResilienceTest.java b/tests/src/test/java/org/sonarqube/tests/qualityProfile/ActiveRuleEsResilienceTest.java index cfa5f160423..49be3215f07 100644 --- a/tests/src/test/java/org/sonarqube/tests/qualityProfile/ActiveRuleEsResilienceTest.java +++ b/tests/src/test/java/org/sonarqube/tests/qualityProfile/ActiveRuleEsResilienceTest.java @@ -21,6 +21,8 @@ package org.sonarqube.tests.qualityProfile; import com.sonar.orchestrator.Orchestrator; import java.util.concurrent.TimeUnit; +import org.junit.After; +import org.junit.Before; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; @@ -35,19 +37,35 @@ import org.sonarqube.ws.client.rule.SearchWsRequest; import util.ItUtils; import static org.assertj.core.api.Assertions.assertThat; +import static org.sonarqube.tests.Byteman.Process.WEB; public class ActiveRuleEsResilienceTest { private static final String RULE_ONE_BUG_PER_LINE = "xoo:OneBugIssuePerLine"; @ClassRule public static final Orchestrator orchestrator; + private static final Byteman byteman; static { - orchestrator = Byteman.enableScript(Orchestrator.builderEnv(), "resilience/active_rule_indexer.btm") + byteman = new Byteman(Orchestrator.builderEnv(), WEB); + orchestrator = byteman + .getOrchestratorBuilder() + .setServerProperty("sonar.search.recovery.delayInMs", "1000") + .setServerProperty("sonar.search.recovery.minAgeInMs", "3000") .addPlugin(ItUtils.xooPlugin()) .build(); } + @Before + public void before() throws Exception { + byteman.activateScript("resilience/active_rule_indexer.btm"); + } + + @After + public void after() throws Exception { + byteman.deactivateAllRules(); + } + @Rule public TestRule timeout = new DisableOnDebug(Timeout.builder() .withLookingForStuckThread(true) diff --git a/tests/src/test/java/org/sonarqube/tests/rule/RuleEsResilienceTest.java b/tests/src/test/java/org/sonarqube/tests/rule/RuleEsResilienceTest.java index a9f606fb320..c887cf652f3 100644 --- a/tests/src/test/java/org/sonarqube/tests/rule/RuleEsResilienceTest.java +++ b/tests/src/test/java/org/sonarqube/tests/rule/RuleEsResilienceTest.java @@ -21,6 +21,8 @@ package org.sonarqube.tests.rule; import com.sonar.orchestrator.Orchestrator; import java.util.concurrent.TimeUnit; +import org.junit.After; +import org.junit.Before; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; @@ -35,18 +37,34 @@ import util.ItUtils; import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; +import static org.sonarqube.tests.Byteman.Process.WEB; public class RuleEsResilienceTest { @ClassRule public static final Orchestrator orchestrator; + private static final Byteman byteman; static { - orchestrator = Byteman.enableScript(Orchestrator.builderEnv(), "resilience/rule_indexer.btm") + byteman = new Byteman(Orchestrator.builderEnv(), WEB); + orchestrator = byteman + .getOrchestratorBuilder() + .setServerProperty("sonar.search.recovery.delayInMs", "1000") + .setServerProperty("sonar.search.recovery.minAgeInMs", "3000") .addPlugin(ItUtils.xooPlugin()) .build(); } + @Before + public void before() throws Exception { + byteman.activateScript("resilience/rule_indexer.btm"); + } + + @After + public void after() throws Exception { + byteman.deactivateAllRules(); + } + @Rule public TestRule timeout = new DisableOnDebug(Timeout.builder() .withLookingForStuckThread(true) diff --git a/tests/src/test/java/org/sonarqube/tests/user/UserEsResilienceTest.java b/tests/src/test/java/org/sonarqube/tests/user/UserEsResilienceTest.java index b98661e8fe4..3f2d69fe898 100644 --- a/tests/src/test/java/org/sonarqube/tests/user/UserEsResilienceTest.java +++ b/tests/src/test/java/org/sonarqube/tests/user/UserEsResilienceTest.java @@ -21,6 +21,8 @@ package org.sonarqube.tests.user; import com.sonar.orchestrator.Orchestrator; import java.util.concurrent.TimeUnit; +import org.junit.After; +import org.junit.Before; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; @@ -32,17 +34,36 @@ import org.sonarqube.tests.Tester; import org.sonarqube.ws.WsUsers.CreateWsResponse.User; import org.sonarqube.ws.client.user.SearchRequest; import org.sonarqube.ws.client.user.UpdateRequest; +import util.ItUtils; import static org.assertj.core.api.Assertions.assertThat; +import static org.sonarqube.tests.Byteman.Process.WEB; import static util.ItUtils.expectHttpError; public class UserEsResilienceTest { @ClassRule public static final Orchestrator orchestrator; + private static final Byteman byteman; static { - orchestrator = Byteman.enableScript(Orchestrator.builderEnv(), "resilience/user_indexer.btm").build(); + byteman = new Byteman(Orchestrator.builderEnv(), WEB); + orchestrator = byteman + .getOrchestratorBuilder() + .setServerProperty("sonar.search.recovery.delayInMs", "1000") + .setServerProperty("sonar.search.recovery.minAgeInMs", "3000") + .addPlugin(ItUtils.xooPlugin()) + .build(); + } + + @Before + public void before() throws Exception { + byteman.activateScript("resilience/user_indexer.btm"); + } + + @After + public void after() throws Exception { + byteman.deactivateAllRules(); } @Rule |