summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/dbcleaner/ProjectCleaner.java22
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/dbcleaner/ProjectCleanerTest.java18
-rw-r--r--tests/projects/analysis/resilience/resilience-purge/sonar-project.properties5
-rw-r--r--tests/projects/analysis/resilience/resilience-purge/src/main/xoo/sample/Sample.xoo16
-rw-r--r--tests/projects/analysis/resilience/resilience-purge/src/main/xoo/sample/Sample.xoo.measures9
-rw-r--r--tests/src/test/java/org/sonarqube/tests/analysis/AnalysisEsResilienceTest.java106
6 files changed, 123 insertions, 53 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/dbcleaner/ProjectCleaner.java b/server/sonar-server/src/main/java/org/sonar/server/computation/dbcleaner/ProjectCleaner.java
index d2969f7c840..1def57fd52b 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/dbcleaner/ProjectCleaner.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/dbcleaner/ProjectCleaner.java
@@ -60,8 +60,8 @@ public class ProjectCleaner {
PurgeConfiguration configuration = newDefaultPurgeConfiguration(projectConfig, idUuidPair, disabledComponentUuids);
- cleanHistoricalData(session, configuration.rootProjectIdUuid().getUuid(), projectConfig);
- doPurge(session, configuration);
+ periodCleaner.clean(session, configuration.rootProjectIdUuid().getUuid(), projectConfig);
+ purgeDao.purge(session, configuration, purgeListener, profiler);
session.commit();
logProfiling(start, projectConfig);
@@ -76,22 +76,4 @@ public class ProjectCleaner {
LOG.info("\n -------- End of profiling for purge --------\n");
}
}
-
- private void cleanHistoricalData(DbSession session, String rootUuid, Configuration config) {
- try {
- periodCleaner.clean(session, rootUuid, config);
- } catch (Exception e) {
- // purge errors must no fail the batch
- LOG.error("Fail to clean historical data [uuid=" + rootUuid + "]", e);
- }
- }
-
- private void doPurge(DbSession session, PurgeConfiguration configuration) {
- try {
- purgeDao.purge(session, configuration, purgeListener, profiler);
- } catch (Exception e) {
- // purge errors must no fail the report analysis
- LOG.error("Fail to purge data [id=" + configuration.rootProjectIdUuid().getId() + "]", e);
- }
- }
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/dbcleaner/ProjectCleanerTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/dbcleaner/ProjectCleanerTest.java
index 611a8d14c53..fc9c4ab88fb 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/computation/dbcleaner/ProjectCleanerTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/dbcleaner/ProjectCleanerTest.java
@@ -86,22 +86,4 @@ public class ProjectCleanerTest {
verify(periodCleaner).clean(any(DbSession.class), anyString(), any(Configuration.class));
verify(dao).purge(any(DbSession.class), any(PurgeConfiguration.class), any(PurgeListener.class), any(PurgeProfiler.class));
}
-
- @Test
- public void if_dao_purge_fails_it_should_not_interrupt_program_execution() {
- doThrow(RuntimeException.class).when(dao).purge(any(DbSession.class), any(PurgeConfiguration.class), any(PurgeListener.class), any(PurgeProfiler.class));
-
- underTest.purge(mock(DbSession.class), mock(IdUuidPair.class), settings.asConfig(), emptyList());
-
- verify(dao).purge(any(DbSession.class), any(PurgeConfiguration.class), any(PurgeListener.class), any(PurgeProfiler.class));
- }
-
- @Test
- public void if_profiler_cleaning_fails_it_should_not_interrupt_program_execution() {
- doThrow(RuntimeException.class).when(periodCleaner).clean(any(DbSession.class), anyString(), any(Configuration.class));
-
- underTest.purge(mock(DbSession.class), mock(IdUuidPair.class), settings.asConfig(), emptyList());
-
- verify(periodCleaner).clean(any(DbSession.class), anyString(), any(Configuration.class));
- }
}
diff --git a/tests/projects/analysis/resilience/resilience-purge/sonar-project.properties b/tests/projects/analysis/resilience/resilience-purge/sonar-project.properties
new file mode 100644
index 00000000000..9e4aa0e3584
--- /dev/null
+++ b/tests/projects/analysis/resilience/resilience-purge/sonar-project.properties
@@ -0,0 +1,5 @@
+sonar.projectKey=sample
+sonar.projectName=Sample
+sonar.projectVersion=1.0-SNAPSHOT
+sonar.sources=src/main/xoo
+sonar.language=xoo
diff --git a/tests/projects/analysis/resilience/resilience-purge/src/main/xoo/sample/Sample.xoo b/tests/projects/analysis/resilience/resilience-purge/src/main/xoo/sample/Sample.xoo
new file mode 100644
index 00000000000..41871e123a3
--- /dev/null
+++ b/tests/projects/analysis/resilience/resilience-purge/src/main/xoo/sample/Sample.xoo
@@ -0,0 +1,16 @@
+package sample;
+
+public class Sample {
+
+ public Sample(int i) {
+ int j = i++;
+ }
+
+ private String myMethod() {
+ if (foo == bar) {
+ return "hello";
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+}
diff --git a/tests/projects/analysis/resilience/resilience-purge/src/main/xoo/sample/Sample.xoo.measures b/tests/projects/analysis/resilience/resilience-purge/src/main/xoo/sample/Sample.xoo.measures
new file mode 100644
index 00000000000..06c9b6c2f38
--- /dev/null
+++ b/tests/projects/analysis/resilience/resilience-purge/src/main/xoo/sample/Sample.xoo.measures
@@ -0,0 +1,9 @@
+ncloc:13
+#Used by dashboard/widgets tests
+complexity:3
+complexity_in_classes:3
+cognitive_complexity:4
+classes:1
+comment_lines:3
+public_api:5
+public_undocumented_api:2
diff --git a/tests/src/test/java/org/sonarqube/tests/analysis/AnalysisEsResilienceTest.java b/tests/src/test/java/org/sonarqube/tests/analysis/AnalysisEsResilienceTest.java
index b522d311f74..7476b9842c4 100644
--- a/tests/src/test/java/org/sonarqube/tests/analysis/AnalysisEsResilienceTest.java
+++ b/tests/src/test/java/org/sonarqube/tests/analysis/AnalysisEsResilienceTest.java
@@ -30,12 +30,14 @@ import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
+import javax.annotation.Nullable;
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.Common;
import org.sonarqube.ws.Issues;
import org.sonarqube.ws.Organizations.Organization;
import org.sonarqube.ws.QualityProfiles.CreateWsResponse.QualityProfile;
@@ -94,32 +96,32 @@ public class AnalysisEsResilienceTest {
.activateRule(profile, "xoo:OneIssuePerFile")
.assignQProfileToProject(profile, project);
- executeAnalysis(projectKey, organization, orgAdministrator, "analysis/resilience/resilience-sample-v1");
+ executeAnalysis(projectKey, organization, orgAdministrator, "analysis/resilience/resilience-sample-v1", null);
assertThat(searchFile(fileKey, organization)).isNotEmpty();
assertThat(searchFile(file2Key, organization)).isEmpty();
assertThat(searchFile(file3Key, organization)).isEmpty();
- List<Issues.Issue> issues = searchIssues(projectKey);
- assertThat(issues)
+ Issues.SearchWsResponse issues = searchIssues(projectKey);
+ assertThat(issues.getIssuesList())
.extracting(Issues.Issue::getComponent)
.containsExactlyInAnyOrder(fileKey);
byteman.activateScript("resilience/making_ce_indexation_failing.btm");
- executeAnalysis(projectKey, organization, orgAdministrator, "analysis/resilience/resilience-sample-v2");
+ executeAnalysis(projectKey, organization, orgAdministrator, "analysis/resilience/resilience-sample-v2", null);
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)
+ assertThat(issues.getIssuesList())
.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");
+ executeAnalysis(projectKey, organization, orgAdministrator, "analysis/resilience/resilience-sample-v3", null);
assertThat(searchFile(fileKey, organization)).isNotEmpty();
assertThat(searchFile(file2Key, organization)).isEmpty();
assertThat(searchFile(file3Key, organization)).isNotEmpty();
issues = searchIssues(projectKey);
- assertThat(issues)
+ assertThat(issues.getIssuesList())
.extracting(Issues.Issue::getComponent, Issues.Issue::getStatus)
.containsExactlyInAnyOrder(
tuple(fileKey, "OPEN"),
@@ -128,6 +130,76 @@ public class AnalysisEsResilienceTest {
}
@Test
+ public void purge_mechanism_must_be_resilient_at_next_analysis() 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";
+
+ QualityProfile profile = tester.qProfiles().createXooProfile(organization);
+ tester.qProfiles()
+ .activateRule(profile, "xoo:OneIssuePerFile")
+ .assignQProfileToProject(profile, project);
+
+ executeAnalysis(projectKey, organization, orgAdministrator, "analysis/resilience/resilience-purge", "2000-01-01");
+ assertThat(searchFile(fileKey, organization)).isNotEmpty();
+ Issues.SearchWsResponse issues = searchIssues(projectKey);
+ assertThat(issues.getIssuesList())
+ .extracting(Issues.Issue::getComponent)
+ .containsExactlyInAnyOrder(fileKey);
+
+ tester.qProfiles()
+ .deactivateRule(profile, "xoo:OneIssuePerFile");
+
+ // We are expecting the purge to fail during this analysis
+ tester.elasticsearch().lockWrites("issues");
+ String taskUuid = executeAnalysis(projectKey, organization, orgAdministrator, "analysis/resilience/resilience-purge", "2000-01-02");
+
+ // The task has failed
+ WsCe.Task task = tester.wsClient().ce().task(taskUuid).getTask();
+ assertThat(task.getStatus()).isEqualTo(WsCe.TaskStatus.FAILED);
+
+ // The issue must be present with status CLOSED in database
+ assertThat(searchFile(fileKey, organization)).isNotEmpty();
+ issues = searchIssues(projectKey);
+ assertThat(issues.getIssuesList())
+ .extracting(Issues.Issue::getComponent, Issues.Issue::getStatus)
+ .containsExactlyInAnyOrder(
+ tuple(fileKey, "CLOSED"));
+
+ // Now we have an inconstency : ES is seeing the issue as opened
+ assertThat(issues.getFacets().getFacets(0).getValuesList())
+ .extracting(Common.FacetValue::getVal, Common.FacetValue::getCount)
+ .containsExactlyInAnyOrder(
+ tuple("OPEN", 1L),
+ tuple("CONFIRMED", 0L),
+ tuple("REOPENED", 0L),
+ tuple("RESOLVED", 0L),
+ tuple("CLOSED", 0L)
+ );
+
+ tester.elasticsearch().unlockWrites("issues");
+
+ // Second analysis must fix the issue,
+ // The purge will delete the "old" issue
+ executeAnalysis(projectKey, organization, orgAdministrator, "analysis/resilience/resilience-purge", null);
+ assertThat(searchFile(fileKey, organization)).isNotEmpty();
+ issues = searchIssues(projectKey);
+ assertThat(issues.getIssuesList())
+ .isEmpty();
+ assertThat(issues.getFacets().getFacets(0).getValuesList())
+ .extracting(Common.FacetValue::getVal, Common.FacetValue::getCount)
+ .containsExactlyInAnyOrder(
+ tuple("OPEN", 0L),
+ tuple("CONFIRMED", 0L),
+ tuple("REOPENED", 0L),
+ tuple("RESOLVED", 0L),
+ tuple("CLOSED", 0L)
+ );
+ }
+
+ @Test
public void compute_engine_task_must_be_red_when_es_is_not_available() throws Exception {
Organization organization = tester.organizations().generate();
User orgAdministrator = tester.users().generateAdministrator(organization);
@@ -142,17 +214,17 @@ public class AnalysisEsResilienceTest {
tester.elasticsearch().lockWrites("issues");
- String analysisKey = executeAnalysis(projectKey, organization, orgAdministrator, "analysis/resilience/resilience-sample-v1");
+ String analysisKey = executeAnalysis(projectKey, organization, orgAdministrator, "analysis/resilience/resilience-sample-v1", null);
WsCe.TaskResponse task = tester.wsClient().ce().task(analysisKey);
assertThat(task.getTask().getStatus()).isEqualTo(FAILED);
}
- private List<Issues.Issue> searchIssues(String projectKey) {
+ private Issues.SearchWsResponse searchIssues(String projectKey) {
SearchWsRequest request = new SearchWsRequest()
- .setProjectKeys(Collections.singletonList(projectKey));
- Issues.SearchWsResponse results = tester.wsClient().issues().search(request);
- return results.getIssuesList();
+ .setProjectKeys(Collections.singletonList(projectKey))
+ .setFacets(Collections.singletonList("statuses"));
+ return tester.wsClient().issues().search(request);
}
private List<String> searchFile(String key, Organization organization) {
@@ -169,12 +241,16 @@ public class AnalysisEsResilienceTest {
return x.collect(Collectors.toList());
}
- private String executeAnalysis(String projectKey, Organization organization, User orgAdministrator, String projectPath) {
- BuildResult buildResult = orchestrator.executeBuild(SonarScanner.create(projectDir(projectPath),
+ private String executeAnalysis(String projectKey, Organization organization, User orgAdministrator, String projectPath, @Nullable String date) {
+ SonarScanner sonarScanner = SonarScanner.create(projectDir(projectPath),
"sonar.organization", organization.getKey(),
"sonar.projectKey", projectKey,
"sonar.login", orgAdministrator.getLogin(),
- "sonar.password", orgAdministrator.getLogin()));
+ "sonar.password", orgAdministrator.getLogin());
+ if (date != null) {
+ sonarScanner.setProperty("sonar.projectDate", date);
+ }
+ BuildResult buildResult = orchestrator.executeBuild(sonarScanner);
return ItUtils.extractCeTaskId(buildResult);
}
}