/* * JBoss, Home of Professional Open Source * Copyright 2012 Red Hat Inc. and/or its affiliates and other contributors * as indicated by the @authors tag. All rights reserved. */ package org.jboss.elasticsearch.river.remote; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import junit.framework.Assert; import org.elasticsearch.action.search.SearchRequestBuilder; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.client.Client; import org.elasticsearch.common.logging.ESLoggerFactory; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.index.query.FilterBuilder; import org.elasticsearch.index.query.FilterBuilders; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.river.RiverName; import org.elasticsearch.river.RiverSettings; import org.elasticsearch.search.SearchHit; import org.jboss.elasticsearch.river.remote.testtools.ESRealClientTestBase; import org.jboss.elasticsearch.river.remote.testtools.TestUtils; import org.mockito.Mockito; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; /** * Base class with helpers for unit tests of Space indexers which test search index update processes against embedded * inmemmory elastic search node. * * @author Vlastimil Elias (velias at redhat dot com) */ public class SpaceIndexer_IntegrationTestBase extends ESRealClientTestBase { protected static final String CFG_RIVER_NAME = "remote_river"; protected static final String CFG_INDEX_NAME = CFG_RIVER_NAME; protected static final String CFG_TYPE_DOCUMENT = "jira_issue"; protected static final String CFG_TYPE_COMMENT = "jira_issue_comment"; protected static final String CFG_TYPE_ACTIVITY = "jira_river_indexupdate"; protected static final String CFG_INDEX_NAME_ACTIVITY = "activity_index"; protected static final String SPACE_KEY = "ORG"; protected DocumentWithCommentsIndexStructureBuilder prepareStructureBuilder() { DocumentWithCommentsIndexStructureBuilder structureBuilder = new DocumentWithCommentsIndexStructureBuilder( mockEsIntegrationComponent(), CFG_INDEX_NAME, CFG_TYPE_DOCUMENT, DocumentWithCommentsIndexStructureBuilderTest.createSettingsWithMandatoryFilled(), true); structureBuilder.remoteDataFieldForDocumentId = "key"; structureBuilder.remoteDataFieldForUpdated = "fields.updated"; structureBuilder.remoteDataFieldForDeleted = "fields.deleted"; structureBuilder.remoteDataValueForDeleted = "true"; structureBuilder.remoteDataFieldForComments = "fields.comment.comments"; structureBuilder.remoteDataFieldForCommentId = "id"; structureBuilder.indexFieldForComments = "comments"; structureBuilder.commentTypeName = CFG_TYPE_COMMENT; structureBuilder.commentFieldsConfig = new HashMap<String, Map<String, String>>(); return structureBuilder; } protected IESIntegration mockEsIntegrationComponent() { IESIntegration esIntegrationMock = mock(IESIntegration.class); Mockito.when(esIntegrationMock.createLogger(Mockito.any(Class.class))).thenReturn( ESLoggerFactory.getLogger(SpaceIndexerCoordinator.class.getName())); RiverName riverName = new RiverName("remote", CFG_RIVER_NAME); Mockito.when(esIntegrationMock.riverName()).thenReturn(riverName); return esIntegrationMock; } /** * Assert documents with given id's exists in {@value #CFG_INDEX_NAME} search index and no any other exists here. * * @param client to be used * @param documentType type of document to check * @param documentIds list of document id's to check * */ protected void assertDocumentsInIndex(Client client, String documentType, String... documentIds) { SearchRequestBuilder srb = client.prepareSearch(CFG_INDEX_NAME).setTypes(documentType) .setQuery(QueryBuilders.matchAllQuery()); assertImplSearchResults(client, srb, documentIds); } /** * Assert child documents with given id's exists in {@value #CFG_INDEX_NAME} search index for given parent, and no any * other exists here. * * @param client to be used * @param documentType type of document to check * @param parentDocumentId id of parent to check childs for * @param childDocumentIds list of document id's to check * */ protected void assertChildDocumentsInIndex(Client client, String documentType, String parentDocumentId, String... childDocumentIds) { SearchRequestBuilder srb = client.prepareSearch(CFG_INDEX_NAME).setTypes(documentType) .setQuery(QueryBuilders.matchAllQuery()); srb.setPostFilter(FilterBuilders.termFilter("_parent", parentDocumentId)); assertImplSearchResults(client, srb, childDocumentIds); } protected void assertImplSearchResults(Client client, SearchRequestBuilder srb, String... documentIds) { client.admin().indices().prepareRefresh(CFG_INDEX_NAME).execute().actionGet(); SearchResponse resp = srb.execute().actionGet(); List<String> expected = Arrays.asList(documentIds); Assert.assertEquals("Documents number is wrong", expected.size(), resp.getHits().getTotalHits()); for (SearchHit hit : resp.getHits().getHits()) { Assert.assertTrue("Document list can't contain document with id " + hit.id(), expected.contains(hit.id())); } } /** * Assert number of documents of given type in search index. * * @param client to be used * @param indexName name of index to check documents in * @param documentType type of document to check * @param expectedNum expected number of documents * */ protected void assertNumDocumentsInIndex(Client client, String indexName, String documentType, int expectedNum) { client.admin().indices().prepareRefresh(indexName).execute().actionGet(); SearchRequestBuilder srb = client.prepareSearch(indexName).setTypes(documentType) .setQuery(QueryBuilders.matchAllQuery()); SearchResponse resp = srb.execute().actionGet(); Assert.assertEquals("Documents number is wrong", expectedNum, resp.getHits().getTotalHits()); } /** * Assert documents with given id's exists in {@value #CFG_INDEX_NAME} search index and was NOT updated after given * bound date (so was updated before). * * @param client to be used * @param documentType type of document to check * @param boundDate bound date for check * @param documentIds list of document id's to check * */ protected void assertDocumentsUpdatedBeforeDate(Client client, String documentType, Date boundDate, String... documentIds) { assertImplDocumentsUpdatedDate(client, documentType, boundDate, true, documentIds); } /** * Assert documents with given id's exists in {@value #CFG_INDEX_NAME} search index and was updated after given bound * date. * * @param client to be used * @param documentType type of document to check * @param boundDate bound date for check * @param documentIds list of document id's to check * */ protected void assertDocumentsUpdatedAfterDate(Client client, String documentType, Date boundDate, String... documentIds) { assertImplDocumentsUpdatedDate(client, documentType, boundDate, false, documentIds); } protected void assertImplDocumentsUpdatedDate(Client client, String documentType, Date boundDate, boolean beforeDate, String... documentIds) { FilterBuilder filterTime = null; if (beforeDate) { filterTime = FilterBuilders.rangeFilter("_timestamp").lt(boundDate); } else { filterTime = FilterBuilders.rangeFilter("_timestamp").gte(boundDate); } SearchRequestBuilder srb = client.prepareSearch(CFG_INDEX_NAME).setTypes(documentType) .setQuery(QueryBuilders.matchAllQuery()).setPostFilter(filterTime); assertImplSearchResults(client, srb, documentIds); } protected ChangedDocumentsResults prepareChangedDocumentsCallResults(String... issueKeys) throws IOException { return prepareChangedDocumentsCallResults(false, issueKeys); } protected ChangedDocumentsResults prepareChangedDocumentsCallResults(boolean setTotal, String... issueKeys) throws IOException { List<Map<String, Object>> list = new ArrayList<Map<String, Object>>(); if (issueKeys != null) { for (String key : issueKeys) { list.add(TestUtils.readDocumentJsonDataFromClasspathFile(key)); } } return new ChangedDocumentsResults(list, 0, setTotal ? issueKeys.length : null); } protected RemoteRiver initRiverInstanceForTest(Client client, SpaceIndexingMode spaceIndexingMode) throws Exception { Map<String, Object> settings = new HashMap<String, Object>(); Settings gs = mock(Settings.class); RiverSettings rs = new RiverSettings(gs, settings); RemoteRiver tested = new RemoteRiver(new RiverName("remote", CFG_RIVER_NAME), rs); tested.client = client; tested.spaceIndexingMode = spaceIndexingMode; IRemoteSystemClient jClientMock = mock(IRemoteSystemClient.class); tested.remoteSystemClient = jClientMock; // simulate started river tested.closed = false; return tested; } protected void initIndexStructures(Client client, CommentIndexingMode commentMode) throws Exception { indexCreate(CFG_INDEX_NAME); indexCreate(CFG_INDEX_NAME_ACTIVITY); client.admin().indices().preparePutMapping(CFG_INDEX_NAME).setType(CFG_TYPE_DOCUMENT) .setSource(TestUtils.readStringFromClasspathFile("/mappings/jira_issue.json")).execute().actionGet(); if (commentMode.isExtraDocumentIndexed()) { String commentMappingFilePath = "/mappings/jira_issue_comment.json"; if (commentMode == CommentIndexingMode.CHILD) commentMappingFilePath = "/mappings/jira_issue_comment-child.json"; client.admin().indices().preparePutMapping(CFG_INDEX_NAME).setType(CFG_TYPE_COMMENT) .setSource(TestUtils.readStringFromClasspathFile(commentMappingFilePath)).execute().actionGet(); } } /** * Adds two issues from <code>AAA</code> space into search index for tests - keys <code>AAA-1</code> and * <code>AAA-2</code> * * @param remoteRiverMock to be used * @param structureBuilder to be used * @throws Exception */ protected void initDocumentsForProjectAAA(RemoteRiver remoteRiverMock, DocumentWithCommentsIndexStructureBuilder structureBuilder) throws Exception { IRemoteSystemClient remoteClientMock = mock(IRemoteSystemClient.class); SpaceByLastUpdateTimestampIndexer tested = new SpaceByLastUpdateTimestampIndexer("AAA", true, remoteClientMock, remoteRiverMock, structureBuilder); ChangedDocumentsResults changedIssues = prepareChangedDocumentsCallResults("AAA-1", "AAA-2"); when(remoteClientMock.getChangedDocuments("AAA", 0, true, null)).thenReturn(changedIssues); when( remoteClientMock.getChangedDocuments(Mockito.eq("AAA"), Mockito.eq(0), Mockito.eq(true), (Date) Mockito.notNull())).thenReturn(new ChangedDocumentsResults(null, 0, null)); tested.run(); remoteRiverMock.refreshSearchIndex(CFG_INDEX_NAME); } }