]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-9760 Throw an exception when indexation is failing
authorEric Hartmann <hartmann.eric@gmail.com>
Tue, 5 Sep 2017 08:46:34 +0000 (10:46 +0200)
committerEric Hartmann <hartmann.eric@gmail.Com>
Thu, 14 Sep 2017 16:18:20 +0000 (18:18 +0200)
server/sonar-server/src/main/java/org/sonar/server/es/BulkIndexer.java
server/sonar-server/src/main/java/org/sonar/server/es/IndexingListener.java
server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndexer.java
server/sonar-server/src/main/java/org/sonar/server/measure/index/ProjectMeasuresIndexer.java
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/index/ActiveRuleIndexer.java
server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleIndexer.java
server/sonar-server/src/main/java/org/sonar/server/user/index/UserIndexer.java
server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueIndexerTest.java
server/sonar-server/src/test/java/org/sonar/server/test/index/TestIndexerTest.java
tests/src/test/java/org/sonarqube/tests/analysis/AnalysisEsResilienceTest.java

index cf931dff4963b4b1726e464934d23a4a7b429873..7d2eb4dcefa9882066be19e8c7f89c3b883c06a7 100644 (file)
@@ -76,7 +76,7 @@ public class BulkIndexer {
   private final SizeHandler sizeHandler;
 
   public BulkIndexer(EsClient client, IndexType indexType, Size size) {
-    this(client, indexType, size, IndexingListener.NOOP);
+    this(client, indexType, size, IndexingListener.FAIL_ON_ERROR);
   }
 
   public BulkIndexer(EsClient client, IndexType indexType, Size size, IndexingListener indexingListener) {
index ce74bd9cddef0fcb4cf0c2ff8624d2fbdc794589..d4748a5652afc24617ae04b9b1cc1a40acd0e4c3 100644 (file)
@@ -27,7 +27,7 @@ public interface IndexingListener {
 
   void onFinish(IndexingResult result);
 
-  IndexingListener NOOP = new IndexingListener() {
+  IndexingListener FAIL_ON_ERROR = new IndexingListener() {
     @Override
     public void onSuccess(List<DocId> docIds) {
       // nothing to do
@@ -35,7 +35,9 @@ public interface IndexingListener {
 
     @Override
     public void onFinish(IndexingResult result) {
-      // nothing to do
+      if (result.getFailures() > 0) {
+        throw new IllegalStateException("Indexation failures");
+      }
     }
   };
 }
index 63c08c3fb59971f346b80464aacfe88c5cae0233..ec00ef43960dc8e7d4dc2a151cae1e48195e8380 100644 (file)
@@ -52,7 +52,6 @@ import org.sonar.server.permission.index.NeedAuthorizationIndexer;
 import static java.util.Collections.emptyList;
 import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
 import static org.elasticsearch.index.query.QueryBuilders.termQuery;
-import static org.sonar.server.es.DefaultIndexSettings.REFRESH_NONE;
 import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_PROJECT_UUID;
 import static org.sonar.server.issue.index.IssueIndexDefinition.INDEX_TYPE_ISSUE;
 
@@ -93,14 +92,14 @@ public class IssueIndexer implements ProjectIndexer, NeedAuthorizationIndexer {
   @Override
   public void indexOnStartup(Set<IndexType> uninitializedIndexTypes) {
     try (IssueIterator issues = issueIteratorFactory.createForAll()) {
-      doIndex(issues, Size.LARGE, IndexingListener.NOOP);
+      doIndex(issues, Size.LARGE, IndexingListener.FAIL_ON_ERROR);
     }
   }
 
   @Override
   public void indexOnAnalysis(String branchUuid) {
     try (IssueIterator issues = issueIteratorFactory.createForProject(branchUuid)) {
-      doIndex(issues, Size.REGULAR, IndexingListener.NOOP);
+      doIndex(issues, Size.REGULAR, IndexingListener.FAIL_ON_ERROR);
     }
   }
 
@@ -227,7 +226,7 @@ public class IssueIndexer implements ProjectIndexer, NeedAuthorizationIndexer {
       return;
     }
 
-    BulkIndexer bulkIndexer = createBulkIndexer(Size.REGULAR, IndexingListener.NOOP);
+    BulkIndexer bulkIndexer = createBulkIndexer(Size.REGULAR, IndexingListener.FAIL_ON_ERROR);
     bulkIndexer.start();
     issueKeys.forEach(issueKey -> bulkIndexer.addDeletion(INDEX_TYPE_ISSUE, issueKey, projectUuid));
     bulkIndexer.stop();
@@ -235,7 +234,7 @@ public class IssueIndexer implements ProjectIndexer, NeedAuthorizationIndexer {
 
   @VisibleForTesting
   protected void index(Iterator<IssueDoc> issues) {
-    doIndex(issues, Size.LARGE, IndexingListener.NOOP);
+    doIndex(issues, Size.LARGE, IndexingListener.FAIL_ON_ERROR);
   }
 
   private void doIndex(Iterator<IssueDoc> issues, Size size, IndexingListener listener) {
index daae14186da7975fe4f9ce92596891bd0438a77a..f255de2b608bb5b6323d04c96d47fdf7ac33129f 100644 (file)
@@ -138,7 +138,7 @@ public class ProjectMeasuresIndexer implements ProjectIndexer, NeedAuthorization
     try (DbSession dbSession = dbClient.openSession(false);
       ProjectMeasuresIndexerIterator rowIt = ProjectMeasuresIndexerIterator.create(dbSession, projectUuid)) {
 
-      BulkIndexer bulkIndexer = createBulkIndexer(size, IndexingListener.NOOP);
+      BulkIndexer bulkIndexer = createBulkIndexer(size, IndexingListener.FAIL_ON_ERROR);
       bulkIndexer.start();
       while (rowIt.hasNext()) {
         ProjectMeasures doc = rowIt.next();
index 0061346194e21b0d581a7cd728481b96514af9d8..b4d25dbc803806b050706b622217548916478fd4 100644 (file)
@@ -73,7 +73,7 @@ public class ActiveRuleIndexer implements ResilientIndexer {
   @Override
   public void indexOnStartup(Set<IndexType> uninitializedIndexTypes) {
     try (DbSession dbSession = dbClient.openSession(false)) {
-      BulkIndexer bulkIndexer = createBulkIndexer(Size.LARGE, IndexingListener.NOOP);
+      BulkIndexer bulkIndexer = createBulkIndexer(Size.LARGE, IndexingListener.FAIL_ON_ERROR);
       bulkIndexer.start();
       dbClient.activeRuleDao().scrollAllForIndexing(dbSession, ar -> bulkIndexer.add(newIndexRequest(ar)));
       bulkIndexer.stop();
@@ -182,7 +182,7 @@ public class ActiveRuleIndexer implements ResilientIndexer {
         profileResult = BulkIndexer.delete(esClient, INDEX_TYPE_ACTIVE_RULE, search);
 
       } else {
-        BulkIndexer bulkIndexer = createBulkIndexer(Size.REGULAR, IndexingListener.NOOP);
+        BulkIndexer bulkIndexer = createBulkIndexer(Size.REGULAR, IndexingListener.FAIL_ON_ERROR);
         bulkIndexer.start();
         dbClient.activeRuleDao().scrollByRuleProfileForIndexing(dbSession, ruleProfileUUid, i -> bulkIndexer.add(newIndexRequest(i)));
         profileResult = bulkIndexer.stop();
index c6ceb47cb8decfff51e08010e6bb2c3c66835884..80828c4ac06c331003bc918dba5ad3ac479c8abd 100644 (file)
@@ -69,7 +69,7 @@ public class RuleIndexer implements ResilientIndexer {
   @Override
   public void indexOnStartup(Set<IndexType> uninitializedIndexTypes) {
     try (DbSession dbSession = dbClient.openSession(false)) {
-      BulkIndexer bulk = createBulkIndexer(Size.LARGE, IndexingListener.NOOP);
+      BulkIndexer bulk = createBulkIndexer(Size.LARGE, IndexingListener.FAIL_ON_ERROR);
       bulk.start();
 
       // index all definitions and system extensions
index 50d43af95afd6c7b9b27bff09b94c3f16ef50dc1..f9d5b10c886c73955545f4e6c31af2188f2e1b76 100644 (file)
@@ -67,7 +67,7 @@ public class UserIndexer implements ResilientIndexer {
       ListMultimap<String, String> organizationUuidsByLogin = ArrayListMultimap.create();
       dbClient.organizationMemberDao().selectAllForUserIndexing(dbSession, organizationUuidsByLogin::put);
 
-      BulkIndexer bulkIndexer = newBulkIndexer(Size.LARGE, IndexingListener.NOOP);
+      BulkIndexer bulkIndexer = newBulkIndexer(Size.LARGE, IndexingListener.FAIL_ON_ERROR);
       bulkIndexer.start();
       dbClient.userDao().scrollAll(dbSession,
         // only index requests, no deletion requests.
index 4379bbb348008b3b65ad94241dad50f505c2832f..0822c2731d56b835b26990109bca7eff7e8904ee 100644 (file)
@@ -141,10 +141,14 @@ public class IssueIndexerTest {
     es.lockWrites(INDEX_TYPE_ISSUE);
     db.issues().insertIssue(organization);
 
-    underTest.indexOnStartup(emptySet());
-
-    assertThatIndexHasSize(0);
-    assertThatEsQueueTableHasSize(0);
+    try {
+      // FIXME : test also message
+      expectedException.expect(IllegalStateException.class);
+      underTest.indexOnStartup(emptySet());
+    } finally {
+      assertThatIndexHasSize(0);
+      assertThatEsQueueTableHasSize(0);
+    }
   }
 
   @Test
@@ -187,10 +191,14 @@ public class IssueIndexerTest {
     es.lockWrites(INDEX_TYPE_ISSUE);
     IssueDto issue = db.issues().insertIssue(organization);
 
-    underTest.indexOnAnalysis(issue.getProjectUuid());
-
-    assertThatIndexHasSize(0);
-    assertThatEsQueueTableHasSize(0);
+    try {
+      // FIXME : test also message
+      expectedException.expect(IllegalStateException.class);
+      underTest.indexOnAnalysis(issue.getProjectUuid());
+    } finally {
+      assertThatIndexHasSize(0);
+      assertThatEsQueueTableHasSize(0);
+    }
   }
 
   @Test
@@ -416,10 +424,14 @@ public class IssueIndexerTest {
     addIssueToIndex("P1", "Issue1");
     es.lockWrites(INDEX_TYPE_ISSUE);
 
-    underTest.deleteByKeys("P1", asList("Issue1"));
-
-    assertThatIndexHasOnly("Issue1");
-    assertThatEsQueueTableHasSize(0);
+    try {
+      // FIXME : test also message
+      expectedException.expect(IllegalStateException.class);
+      underTest.deleteByKeys("P1", asList("Issue1"));
+    } finally {
+      assertThatIndexHasOnly("Issue1");
+      assertThatEsQueueTableHasSize(0);
+    }
   }
 
   @Test
index 60e297dbcaec7980584d11f56924464f1695c9aa..cc1773a3f4a5b05fb320ba4df0065e57834bdcbe 100644 (file)
@@ -20,8 +20,6 @@
 package org.sonar.server.test.index;
 
 import java.io.IOException;
-import java.sql.SQLException;
-import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import org.apache.commons.io.IOUtils;
@@ -32,15 +30,10 @@ import org.junit.Test;
 import org.sonar.api.config.internal.MapSettings;
 import org.sonar.api.utils.System2;
 import org.sonar.db.DbTester;
-import org.sonar.db.es.EsQueueDto;
 import org.sonar.server.es.EsTester;
-import org.sonar.server.es.IndexingResult;
-import org.sonar.server.es.ProjectIndexer;
 import org.sonar.server.test.db.TestTesting;
 
 import static java.lang.String.format;
-import static java.util.Arrays.asList;
-import static java.util.Collections.emptyList;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.spy;
@@ -100,73 +93,6 @@ public class TestIndexerTest {
     assertThat(countDocuments()).isZero();
   }
 
-  /**
-   * Indexing recovery is handled by Compute Engine, without using
-   * the table es_queue
-   */
-  @Test
-  public void indexOnAnalysis_does_not_fail_on_errors_and_does_not_enable_recovery_mode() throws IOException, SQLException {
-    db.prepareDbUnit(getClass(), "db.xml");
-
-    es.lockWrites(INDEX_TYPE_TEST);
-    TestTesting.updateDataColumn(db.getSession(), "FILE_UUID", TestTesting.newRandomTests(3));
-
-    underTest.indexOnAnalysis("PROJECT_UUID");
-    es.unlockWrites(INDEX_TYPE_TEST);
-
-    assertThat(countDocuments()).isEqualTo(0);
-    assertThat(db.countRowsOfTable("es_queue")).isEqualTo(0);
-  }
-
-  @Test
-  public void prepareForRecovery_must_be_empty_unless_cause_is_PROJECT_DELETION() {
-    db.prepareDbUnit(getClass(), "db.xml");
-    assertThat(underTest.prepareForRecovery(db.getSession(), asList("PROJECT_UUID"), ProjectIndexer.Cause.PROJECT_CREATION))
-      .isEmpty();
-    assertThat(underTest.prepareForRecovery(db.getSession(), asList("PROJECT_UUID"), ProjectIndexer.Cause.PROJECT_KEY_UPDATE))
-      .isEmpty();
-    assertThat(underTest.prepareForRecovery(db.getSession(), asList("PROJECT_UUID"), ProjectIndexer.Cause.PROJECT_TAGS_UPDATE))
-      .isEmpty();
-    assertThat(underTest.prepareForRecovery(db.getSession(), asList("PROJECT_UUID"), ProjectIndexer.Cause.PERMISSION_CHANGE))
-      .isEmpty();
-
-    // Only deletion is resilient with recovery
-    assertThat(underTest.prepareForRecovery(db.getSession(), asList("PROJECT_UUID"), ProjectIndexer.Cause.PROJECT_DELETION))
-      .isNotEmpty();
-  }
-
-  @Test
-  public void errors_during_project_deletion_are_recovered() throws IOException, SQLException, InterruptedException {
-    // Create a project with 3 tests
-    db.prepareDbUnit(getClass(), "db.xml");
-    TestTesting.updateDataColumn(db.getSession(), "FILE_UUID", TestTesting.newRandomTests(3));
-    underTest.indexOnAnalysis("PROJECT_UUID"); //index(db.getSession(), items);
-    assertThat(countDocuments()).isEqualTo(3);
-
-    // Now delete the files
-    es.lockWrites(INDEX_TYPE_TEST);
-    Collection<EsQueueDto> items = underTest.prepareForRecovery(db.getSession(), asList("PROJECT_UUID"), ProjectIndexer.Cause.PROJECT_DELETION);
-    db.commit();
-
-    underTest.deleteByFile("FILE_UUID");
-    es.unlockWrites(INDEX_TYPE_TEST);
-    // Still 3 tests
-    assertThat(countDocuments()).isEqualTo(3);
-
-    // Recover must delete the 3 tests
-    IndexingResult result = recover();
-    assertThat(result.getTotal()).isEqualTo(3);
-
-    assertThat(countDocuments()).isEqualTo(0);
-  }
-
-  @Test
-  public void indexing_with_empty_esqueue_dto_does_nothing() {
-    assertThat(underTest.index(db.getSession(), emptyList()))
-      .extracting(IndexingResult::getTotal, IndexingResult::getFailures, IndexingResult::getSuccess)
-      .containsExactly(0L, 0L, 0L);
-  }
-
   @Test
   public void delete_file_by_uuid() throws Exception {
     indexTest("P1", "F1", "T1", "U111");
@@ -202,9 +128,4 @@ public class TestIndexerTest {
   private long countDocuments() {
     return es.countDocuments(INDEX_TYPE_TEST);
   }
-
-  private IndexingResult recover() {
-    Collection<EsQueueDto> items = db.getDbClient().esQueueDao().selectForRecovery(db.getSession(), System.currentTimeMillis() + 10_000L, 10);
-    return underTest.index(db.getSession(), items);
-  }
 }
index 6d6adeb2030b43198ae0f3f669b29edbda12fba6..b522d311f74c7b51a75409aa8e995cfdd9365817 100644 (file)
@@ -22,6 +22,9 @@ package org.sonarqube.tests.analysis;
 import com.sonar.orchestrator.Orchestrator;
 import com.sonar.orchestrator.build.BuildResult;
 import com.sonar.orchestrator.build.SonarScanner;
+import com.sonar.orchestrator.util.NetworkUtils;
+import java.net.InetAddress;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
@@ -36,6 +39,7 @@ 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.WsCe;
 import org.sonarqube.ws.WsProjects;
 import org.sonarqube.ws.WsUsers.CreateWsResponse.User;
 import org.sonarqube.ws.client.component.SuggestionsWsRequest;
@@ -45,6 +49,7 @@ 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 org.sonarqube.ws.WsCe.TaskStatus.FAILED;
 import static util.ItUtils.projectDir;
 
 public class AnalysisEsResilienceTest {
@@ -52,12 +57,14 @@ public class AnalysisEsResilienceTest {
   @ClassRule
   public static final Orchestrator orchestrator;
   private static final Byteman byteman;
+  private static final int esHttpPort = NetworkUtils.getNextAvailablePort(InetAddress.getLoopbackAddress());
 
   static {
     byteman = new Byteman(Orchestrator.builderEnv(), CE);
     orchestrator = byteman
       .getOrchestratorBuilder()
       .addPlugin(ItUtils.xooPlugin())
+      .setServerProperty("sonar.search.httpPort", "" + esHttpPort)
       .build();
   }
 
@@ -67,6 +74,9 @@ public class AnalysisEsResilienceTest {
   @After
   public void after() throws Exception {
     byteman.deactivateAllRules();
+    for (String index : Arrays.asList("issues", "rules", "users", "components", "views", "tests", "projectmeasures")) {
+      tester.elasticsearch().unlockWrites(index);
+    }
   }
 
   @Test
@@ -117,6 +127,27 @@ public class AnalysisEsResilienceTest {
         tuple(file3Key, "OPEN"));
   }
 
+  @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);
+    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);
+
+    tester.elasticsearch().lockWrites("issues");
+
+    String analysisKey = executeAnalysis(projectKey, organization, orgAdministrator, "analysis/resilience/resilience-sample-v1");
+    WsCe.TaskResponse task = tester.wsClient().ce().task(analysisKey);
+
+    assertThat(task.getTask().getStatus()).isEqualTo(FAILED);
+  }
+
   private List<Issues.Issue> searchIssues(String projectKey) {
     SearchWsRequest request = new SearchWsRequest()
       .setProjectKeys(Collections.singletonList(projectKey));
@@ -146,5 +177,4 @@ public class AnalysisEsResilienceTest {
       "sonar.password", orgAdministrator.getLogin()));
     return ItUtils.extractCeTaskId(buildResult);
   }
-
 }