org.sonar.server.issue.index.IssueIndexerTest.java Source code

Java tutorial

Introduction

Here is the source code for org.sonar.server.issue.index.IssueIndexerTest.java

Source

/*
 * 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.sonar.server.issue.index;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.NoSuchElementException;
import org.apache.commons.lang.StringUtils;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.config.MapSettings;
import org.sonar.api.utils.System2;
import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ComponentTesting;
import org.sonar.db.issue.IssueDto;
import org.sonar.db.issue.IssueTesting;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.rule.RuleDto;
import org.sonar.server.es.EsTester;
import org.sonar.server.es.ProjectIndexer;

import static java.util.Arrays.asList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.sonar.server.issue.IssueDocTesting.newDoc;

public class IssueIndexerTest {

    private static final String A_PROJECT_UUID = "P1";

    private System2 system2 = System2.INSTANCE;

    @Rule
    public EsTester esTester = new EsTester(new IssueIndexDefinition(new MapSettings()));
    @Rule
    public DbTester dbTester = DbTester.create(system2);
    @Rule
    public ExpectedException expectedException = ExpectedException.none();

    private IssueIndexer underTest = new IssueIndexer(esTester.client(),
            new IssueIteratorFactory(dbTester.getDbClient()));

    @Test
    public void index_on_startup() {
        IssueIndexer indexer = spy(underTest);
        doNothing().when(indexer).indexOnStartup(null);
        indexer.indexOnStartup(null);
        verify(indexer).indexOnStartup(null);
    }

    @Test
    public void index_nothing() {
        underTest.index(Collections.emptyIterator());

        assertThat(esTester.countDocuments(IssueIndexDefinition.INDEX_TYPE_ISSUE)).isEqualTo(0L);
    }

    @Test
    public void indexOnStartup_loads_and_indexes_all_issues() {
        OrganizationDto org = dbTester.organizations().insert();
        ComponentDto project = dbTester.components().insertPrivateProject(org);
        ComponentDto dir = dbTester.components()
                .insertComponent(ComponentTesting.newDirectory(project, "src/main/java/foo"));
        ComponentDto file = dbTester.components().insertComponent(ComponentTesting.newFileDto(project, dir, "F1"));
        RuleDto rule = dbTester.rules().insertRule();
        IssueDto issue = dbTester.issues().insertIssue(IssueTesting.newDto(rule, file, project));

        underTest.indexOnStartup(null);

        List<IssueDoc> docs = esTester.getDocuments(IssueIndexDefinition.INDEX_TYPE_ISSUE, IssueDoc.class);
        assertThat(docs).hasSize(1);
        verifyDoc(docs.get(0), org, project, file, rule, issue);
    }

    @Test
    public void index_loads_and_indexes_issues_with_specified_keys() {
        OrganizationDto org = dbTester.organizations().insert();
        ComponentDto project = dbTester.components().insertPrivateProject(org);
        ComponentDto dir = dbTester.components()
                .insertComponent(ComponentTesting.newDirectory(project, "src/main/java/foo"));
        ComponentDto file = dbTester.components().insertComponent(ComponentTesting.newFileDto(project, dir, "F1"));
        RuleDto rule = dbTester.rules().insertRule();
        IssueDto issue1 = dbTester.issues().insertIssue(IssueTesting.newDto(rule, file, project));
        IssueDto issue2 = dbTester.issues().insertIssue(IssueTesting.newDto(rule, file, project));

        underTest.index(asList(issue1.getKey()));

        List<IssueDoc> docs = esTester.getDocuments(IssueIndexDefinition.INDEX_TYPE_ISSUE, IssueDoc.class);
        assertThat(docs).hasSize(1);
        verifyDoc(docs.get(0), org, project, file, rule, issue1);
    }

    @Test
    public void index_throws_NoSuchElementException_if_the_specified_key_does_not_exist() {
        try {
            underTest.index(asList("does_not_exist"));
            fail();
        } catch (NoSuchElementException e) {
            assertThat(esTester.countDocuments(IssueIndexDefinition.INDEX_TYPE_ISSUE)).isEqualTo(0);
        }
    }

    @Test
    public void indexProject_loads_and_indexes_issues_with_specified_project_uuid() {
        OrganizationDto org = dbTester.organizations().insert();
        ComponentDto project1 = dbTester.components().insertPrivateProject(org);
        ComponentDto file1 = dbTester.components().insertComponent(ComponentTesting.newFileDto(project1));
        ComponentDto project2 = dbTester.components().insertPrivateProject(org);
        ComponentDto file2 = dbTester.components().insertComponent(ComponentTesting.newFileDto(project2));
        RuleDto rule = dbTester.rules().insertRule();
        IssueDto issue1 = dbTester.issues().insertIssue(IssueTesting.newDto(rule, file1, project1));
        IssueDto issue2 = dbTester.issues().insertIssue(IssueTesting.newDto(rule, file2, project2));

        underTest.indexProject(project1.projectUuid(), ProjectIndexer.Cause.NEW_ANALYSIS);

        List<IssueDoc> docs = esTester.getDocuments(IssueIndexDefinition.INDEX_TYPE_ISSUE, IssueDoc.class);
        assertThat(docs).hasSize(1);
        verifyDoc(docs.get(0), org, project1, file1, rule, issue1);
    }

    @Test
    public void indexProject_does_nothing_when_project_is_being_created() {
        verifyThatProjectIsNotIndexed(ProjectIndexer.Cause.PROJECT_CREATION);
    }

    @Test
    public void indexProject_does_nothing_when_project_is_being_renamed() {
        verifyThatProjectIsNotIndexed(ProjectIndexer.Cause.PROJECT_KEY_UPDATE);
    }

    private void verifyThatProjectIsNotIndexed(ProjectIndexer.Cause cause) {
        OrganizationDto org = dbTester.organizations().insert();
        ComponentDto project = dbTester.components().insertPrivateProject(org);
        ComponentDto file = dbTester.components().insertComponent(ComponentTesting.newFileDto(project));
        RuleDto rule = dbTester.rules().insertRule();
        IssueDto issue = dbTester.issues().insertIssue(IssueTesting.newDto(rule, file, project));

        underTest.indexProject(project.projectUuid(), cause);

        assertThat(esTester.countDocuments(IssueIndexDefinition.INDEX_TYPE_ISSUE)).isEqualTo(0);
    }

    private static void verifyDoc(IssueDoc doc, OrganizationDto org, ComponentDto project, ComponentDto file,
            RuleDto rule, IssueDto issue) {
        assertThat(doc.key()).isEqualTo(issue.getKey());
        assertThat(doc.projectUuid()).isEqualTo(project.uuid());
        assertThat(doc.componentUuid()).isEqualTo(file.uuid());
        assertThat(doc.moduleUuid()).isEqualTo(project.uuid());
        assertThat(doc.modulePath()).isEqualTo(file.moduleUuidPath());
        assertThat(doc.directoryPath()).isEqualTo(StringUtils.substringBeforeLast(file.path(), "/"));
        assertThat(doc.severity()).isEqualTo(issue.getSeverity());
        assertThat(doc.ruleKey()).isEqualTo(rule.getKey());
        assertThat(doc.organizationUuid()).isEqualTo(org.getUuid());
        // functional date
        assertThat(doc.updateDate().getTime()).isEqualTo(issue.getIssueUpdateTime());
        // technical date
        assertThat(doc.getTechnicalUpdateDate().getTime()).isEqualTo(issue.getUpdatedAt());
    }

    @Test
    public void deleteProject_deletes_issues_of_a_specific_project() {
        dbTester.prepareDbUnit(getClass(), "index.xml");

        underTest.indexOnStartup(null);

        assertThat(esTester.countDocuments("issues", "issue")).isEqualTo(1);

        underTest.deleteProject("THE_PROJECT");

        assertThat(esTester.countDocuments("issues", "issue")).isZero();
    }

    @Test
    public void deleteByKeys_deletes_docs_by_keys() throws Exception {
        addIssue("P1", "Issue1");
        addIssue("P1", "Issue2");
        addIssue("P1", "Issue3");
        addIssue("P2", "Issue4");

        verifyIssueKeys("Issue1", "Issue2", "Issue3", "Issue4");

        underTest.deleteByKeys("P1", asList("Issue1", "Issue2"));

        verifyIssueKeys("Issue3", "Issue4");
    }

    @Test
    public void deleteByKeys_deletes_more_than_one_thousand_issues_by_keys() throws Exception {
        int numberOfIssues = 1010;
        List<String> keys = new ArrayList<>(numberOfIssues);
        IssueDoc[] issueDocs = new IssueDoc[numberOfIssues];
        for (int i = 0; i < numberOfIssues; i++) {
            String key = "Issue" + i;
            issueDocs[i] = newDoc().setKey(key).setProjectUuid(A_PROJECT_UUID);
            keys.add(key);
        }
        esTester.putDocuments(IssueIndexDefinition.INDEX_TYPE_ISSUE, issueDocs);

        assertThat(esTester.countDocuments("issues", "issue")).isEqualTo(numberOfIssues);
        underTest.deleteByKeys(A_PROJECT_UUID, keys);
        assertThat(esTester.countDocuments("issues", "issue")).isZero();
    }

    @Test
    public void nothing_to_do_when_delete_issues_on_empty_list() throws Exception {
        addIssue("P1", "Issue1");
        addIssue("P1", "Issue2");
        addIssue("P1", "Issue3");

        verifyIssueKeys("Issue1", "Issue2", "Issue3");

        underTest.deleteByKeys("P1", Collections.emptyList());

        verifyIssueKeys("Issue1", "Issue2", "Issue3");
    }

    /**
     * This is a technical constraint, to ensure, that the indexers can be called in any order, during startup.
     */
    @Test
    public void index_issue_without_parent_should_work() {
        IssueDoc issueDoc = new IssueDoc();
        issueDoc.setKey("key");
        issueDoc.setTechnicalUpdateDate(new Date());
        issueDoc.setProjectUuid("non-exitsing-parent");
        new IssueIndexer(esTester.client(), new IssueIteratorFactory(dbTester.getDbClient()))
                .index(asList(issueDoc).iterator());

        assertThat(esTester.countDocuments(IssueIndexDefinition.INDEX_TYPE_ISSUE)).isEqualTo(1L);
    }

    private void addIssue(String projectUuid, String issueKey) throws Exception {
        esTester.putDocuments(IssueIndexDefinition.INDEX_TYPE_ISSUE,
                newDoc().setKey(issueKey).setProjectUuid(projectUuid));
    }

    private void verifyIssueKeys(String... expectedKeys) {
        List<IssueDoc> issues = esTester.getDocuments(IssueIndexDefinition.INDEX_TYPE_ISSUE, IssueDoc.class);
        assertThat(issues).extracting(IssueDoc::key).containsOnly(expectedKeys);
    }
}