/*
* 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.io.OutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.DeserializationConfig;
import org.codehaus.jackson.map.ObjectMapper;
import org.elasticsearch.action.bulk.BulkRequestBuilder;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.logging.ESLoggerFactory;
import org.elasticsearch.common.settings.SettingsException;
import org.elasticsearch.common.xcontent.XContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentGenerator;
import org.elasticsearch.river.RiverName;
import org.jboss.elasticsearch.river.remote.testtools.TestUtils;
import org.jboss.elasticsearch.tools.content.StructuredContentPreprocessor;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* Unit test for {@link DocumentWithCommentsIndexStructureBuilder}.
*
* @author Vlastimil Elias (velias at redhat dot com)
* @author Lukáš Vlček (lvlcek@redhat.com)
*/
public class DocumentWithCommentsIndexStructureBuilderTest {
private static ObjectMapper mapper;
private JsonNode toJsonNode(String source) {
JsonNode node = null;
try {
node = mapper.readValue(source, JsonNode.class);
} catch (IOException e) {
fail("Exception while parsing!: " + e);
}
return node;
}
@BeforeClass
public static void setUp() {
mapper = new ObjectMapper();
mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
@Test
public void configuration_read_ok() {
IESIntegration esIntegrationMock = mockEsIntegrationComponent();
DocumentWithCommentsIndexStructureBuilder tested = new DocumentWithCommentsIndexStructureBuilder(esIntegrationMock,
"index_name", "type_name", loadTestSettings("/index_structure_configuration_test_ok.json"), true);
Assert.assertEquals("river_name", tested.riverName);
Assert.assertEquals("index_name", tested.indexName);
Assert.assertEquals("type_name", tested.issueTypeName);
Assert.assertEquals("document_id", tested.remoteDataFieldForDocumentId);
Assert.assertEquals("updated", tested.remoteDataFieldForUpdated);
Assert.assertEquals("delFlag", tested.remoteDataFieldForDeleted);
Assert.assertEquals("true", tested.remoteDataValueForDeleted);
Assert.assertEquals("river_name", tested.indexFieldForRiverName);
Assert.assertEquals("space_key_field", tested.indexFieldForSpaceKey);
Assert.assertEquals("document_id_field", tested.indexFieldForRemoteDocumentId);
Assert.assertEquals(CommentIndexingMode.CHILD, tested.commentIndexingMode);
Assert.assertEquals("all_comments", tested.indexFieldForComments);
Assert.assertEquals("jira_issue_comment_type", tested.commentTypeName);
Assert.assertEquals(5, tested.fieldsConfig.size());
assertFieldConfiguration(tested.fieldsConfig, "created", "fields.created", null);
assertFieldConfiguration(tested.fieldsConfig, "reporter", "fields.reporter", "user2");
assertFieldConfiguration(tested.fieldsConfig, "assignee", "fields.assignee", "user2");
assertFieldConfiguration(tested.fieldsConfig, "fix_versions", "fields.fixVersions", "name2");
assertFieldConfiguration(tested.fieldsConfig, "components", "fields.components", "name2");
Assert.assertEquals(2, tested.filtersConfig.size());
Assert.assertTrue(tested.filtersConfig.containsKey("user2"));
Assert.assertTrue(tested.filtersConfig.containsKey("name2"));
Map<String, String> userFilter = tested.filtersConfig.get("user2");
Assert.assertEquals(2, userFilter.size());
Assert.assertEquals("username2", userFilter.get("name"));
Assert.assertEquals("display_name2", userFilter.get("displayName"));
Assert.assertEquals(4, tested.commentFieldsConfig.size());
assertFieldConfiguration(tested.commentFieldsConfig, "comment_body", "body", null);
assertFieldConfiguration(tested.commentFieldsConfig, "comment_author2", "author", "user2");
assertFieldConfiguration(tested.commentFieldsConfig, "comment_updater", "updateAuthor", "user2");
assertFieldConfiguration(tested.commentFieldsConfig, "comment_created", "created", null);
Mockito.verify(esIntegrationMock).createLogger(DocumentWithCommentsIndexStructureBuilder.class);
}
@Test
public void configuration_read_ok_noupdatedmandatory() {
Map<String, Object> settings = loadTestSettings("/index_structure_configuration_test_ok.json");
settings.remove(DocumentWithCommentsIndexStructureBuilder.CONFIG_REMOTEFIELD_UPDATED);
settings.remove(DocumentWithCommentsIndexStructureBuilder.CONFIG_REMOTEFIELD_DELETED);
settings.remove(DocumentWithCommentsIndexStructureBuilder.CONFIG_REMOTEFIELD_DELETEDVALUE);
DocumentWithCommentsIndexStructureBuilder tested = new DocumentWithCommentsIndexStructureBuilder(
mockEsIntegrationComponent(), "index_name", "type_name", settings, false);
Assert.assertEquals("river_name", tested.riverName);
Assert.assertEquals("index_name", tested.indexName);
Assert.assertEquals("type_name", tested.issueTypeName);
Assert.assertEquals("document_id", tested.remoteDataFieldForDocumentId);
Assert.assertEquals(null, tested.remoteDataFieldForUpdated);
Assert.assertNull(tested.remoteDataFieldForDeleted);
Assert.assertNull(tested.remoteDataValueForDeleted);
Assert.assertEquals("river_name", tested.indexFieldForRiverName);
Assert.assertEquals("space_key_field", tested.indexFieldForSpaceKey);
Assert.assertEquals("document_id_field", tested.indexFieldForRemoteDocumentId);
Assert.assertEquals(CommentIndexingMode.CHILD, tested.commentIndexingMode);
Assert.assertEquals("all_comments", tested.indexFieldForComments);
Assert.assertEquals("jira_issue_comment_type", tested.commentTypeName);
Assert.assertEquals(5, tested.fieldsConfig.size());
assertFieldConfiguration(tested.fieldsConfig, "created", "fields.created", null);
assertFieldConfiguration(tested.fieldsConfig, "reporter", "fields.reporter", "user2");
assertFieldConfiguration(tested.fieldsConfig, "assignee", "fields.assignee", "user2");
assertFieldConfiguration(tested.fieldsConfig, "fix_versions", "fields.fixVersions", "name2");
assertFieldConfiguration(tested.fieldsConfig, "components", "fields.components", "name2");
Assert.assertEquals(2, tested.filtersConfig.size());
Assert.assertTrue(tested.filtersConfig.containsKey("user2"));
Assert.assertTrue(tested.filtersConfig.containsKey("name2"));
Map<String, String> userFilter = tested.filtersConfig.get("user2");
Assert.assertEquals(2, userFilter.size());
Assert.assertEquals("username2", userFilter.get("name"));
Assert.assertEquals("display_name2", userFilter.get("displayName"));
Assert.assertEquals(4, tested.commentFieldsConfig.size());
assertFieldConfiguration(tested.commentFieldsConfig, "comment_body", "body", null);
assertFieldConfiguration(tested.commentFieldsConfig, "comment_author2", "author", "user2");
assertFieldConfiguration(tested.commentFieldsConfig, "comment_updater", "updateAuthor", "user2");
assertFieldConfiguration(tested.commentFieldsConfig, "comment_created", "created", null);
}
@SuppressWarnings("unchecked")
private Map<String, Object> loadTestSettings(String file) {
return (Map<String, Object>) Utils.loadJSONFromJarPackagedFile(file).get("index");
}
@Test
public void configuration_read_validation() {
try {
Map<String, Object> config = loadTestSettings("/index_structure_configuration_test_ok.json");
config.remove(DocumentWithCommentsIndexStructureBuilder.CONFIG_REMOTEFIELD_DOCUMENTID);
new DocumentWithCommentsIndexStructureBuilder(mockEsIntegrationComponent(), "index_name", "type_name", config,
true);
Assert.fail("SettingsException must be thrown");
} catch (SettingsException e) {
System.out.println(e.getMessage());
Assert.assertEquals("String value must be provided for 'index/remote_field_document_id' configuration!",
e.getMessage());
}
try {
Map<String, Object> config = loadTestSettings("/index_structure_configuration_test_ok.json");
config.put(DocumentWithCommentsIndexStructureBuilder.CONFIG_REMOTEFIELD_DOCUMENTID, " ");
new DocumentWithCommentsIndexStructureBuilder(mockEsIntegrationComponent(), "index_name", "type_name", config,
true);
Assert.fail("SettingsException must be thrown");
} catch (SettingsException e) {
System.out.println(e.getMessage());
Assert.assertEquals("String value must be provided for 'index/remote_field_document_id' configuration!",
e.getMessage());
}
try {
Map<String, Object> config = loadTestSettings("/index_structure_configuration_test_ok.json");
config.remove(DocumentWithCommentsIndexStructureBuilder.CONFIG_REMOTEFIELD_DELETEDVALUE);
new DocumentWithCommentsIndexStructureBuilder(mockEsIntegrationComponent(), "index_name", "type_name", config,
true);
Assert.fail("SettingsException must be thrown");
} catch (SettingsException e) {
System.out.println(e.getMessage());
Assert
.assertEquals(
"Configuration fields 'index/remote_field_deleted' and 'index/remote_field_deleted_value' must be both set or both empty",
e.getMessage());
}
// TODO other validation tests
}
@Test
public void configuration_defaultLoading() {
Map<String, Object> settings = createSettingsWithMandatoryFilled();
assertDefaultConfigurationLoaded(new DocumentWithCommentsIndexStructureBuilder(mockEsIntegrationComponent(),
"index_name", "type_name", settings, true));
}
@SuppressWarnings("rawtypes")
public static Map<String, Object> createSettingsWithMandatoryFilled() {
Map<String, Object> settings = new HashMap<String, Object>();
// fill some mandatory fields not loaded from default
settings.put(DocumentWithCommentsIndexStructureBuilder.CONFIG_FIELDS, new HashMap());
settings.put(DocumentWithCommentsIndexStructureBuilder.CONFIG_FILTERS, new HashMap());
settings.put(DocumentWithCommentsIndexStructureBuilder.CONFIG_REMOTEFIELD_DOCUMENTID, "docid");
settings.put(DocumentWithCommentsIndexStructureBuilder.CONFIG_REMOTEFIELD_UPDATED, "up");
return settings;
}
private void assertDefaultConfigurationLoaded(DocumentWithCommentsIndexStructureBuilder tested) {
Assert.assertEquals("river_name", tested.riverName);
Assert.assertEquals("index_name", tested.indexName);
Assert.assertEquals("type_name", tested.issueTypeName);
Assert.assertEquals("source", tested.indexFieldForRiverName);
Assert.assertEquals("space_key", tested.indexFieldForSpaceKey);
Assert.assertEquals("document_id", tested.indexFieldForRemoteDocumentId);
Assert.assertEquals(CommentIndexingMode.NONE, tested.commentIndexingMode);
Assert.assertEquals(0, tested.fieldsConfig.size());
Assert.assertEquals(0, tested.filtersConfig.size());
}
private void assertFieldConfiguration(Map<String, Map<String, String>> fieldsConfig, String indexFieldName,
String jiraFieldName, String filter) {
Assert.assertTrue(fieldsConfig.containsKey(indexFieldName));
Map<String, String> field = fieldsConfig.get(indexFieldName);
Assert.assertEquals(jiraFieldName, field.get(DocumentWithCommentsIndexStructureBuilder.CONFIG_FIELDS_REMOTEFIELD));
Assert.assertEquals(filter, field.get(DocumentWithCommentsIndexStructureBuilder.CONFIG_FIELDS_VALUEFILTER));
}
@Test
public void addIssueDataPreprocessor() {
DocumentWithCommentsIndexStructureBuilder tested = new DocumentWithCommentsIndexStructureBuilder(
mockEsIntegrationComponent(), null, null, createSettingsWithMandatoryFilled(), true);
// case - not NPE
tested.addDataPreprocessor(null);
// case - preprocessors adding
tested.addDataPreprocessor(mock(StructuredContentPreprocessor.class));
Assert.assertEquals(1, tested.issueDataPreprocessors.size());
tested.addDataPreprocessor(mock(StructuredContentPreprocessor.class));
tested.addDataPreprocessor(mock(StructuredContentPreprocessor.class));
tested.addDataPreprocessor(mock(StructuredContentPreprocessor.class));
Assert.assertEquals(4, tested.issueDataPreprocessors.size());
}
@Test
public void preprocessIssueData() {
DocumentWithCommentsIndexStructureBuilder tested = new DocumentWithCommentsIndexStructureBuilder(
mockEsIntegrationComponent(), null, null, createSettingsWithMandatoryFilled(), true);
Map<String, Object> issue = null;
// case - no NPE and change when no preprocessors defined and issue data are null
Assert.assertNull(tested.preprocessDocumentData("ORG", issue));
// case - no NPE and change when no preprocessors defined and issue data are notnull
{
issue = new HashMap<String, Object>();
issue.put("key", "ORG-1545");
Map<String, Object> ret = tested.preprocessDocumentData("ORG", issue);
Assert.assertEquals(issue, ret);
Assert.assertEquals(1, ret.size());
Assert.assertEquals("ORG-1545", ret.get("key"));
}
// case - all preprocessors called
{
StructuredContentPreprocessor idp1 = mock(StructuredContentPreprocessor.class);
StructuredContentPreprocessor idp2 = mock(StructuredContentPreprocessor.class);
when(idp1.preprocessData(issue)).thenAnswer(new Answer<Map<String, Object>>() {
@SuppressWarnings("unchecked")
@Override
public Map<String, Object> answer(InvocationOnMock invocation) throws Throwable {
Map<String, Object> ret = (Map<String, Object>) invocation.getArguments()[0];
ret.put("idp1", "called");
return ret;
}
});
when(idp2.preprocessData(issue)).thenAnswer(new Answer<Map<String, Object>>() {
@SuppressWarnings("unchecked")
@Override
public Map<String, Object> answer(InvocationOnMock invocation) throws Throwable {
Map<String, Object> ret = (Map<String, Object>) invocation.getArguments()[0];
ret.put("idp2", "called");
return ret;
}
});
tested.addDataPreprocessor(idp1);
tested.addDataPreprocessor(idp2);
Map<String, Object> ret = tested.preprocessDocumentData("ORG", issue);
Assert.assertEquals(issue, ret);
Assert.assertEquals(3, ret.size());
Assert.assertEquals("ORG-1545", ret.get("key"));
Assert.assertEquals("called", ret.get("idp1"));
Assert.assertEquals("called", ret.get("idp2"));
}
}
@SuppressWarnings("unchecked")
@Test
public void buildSearchForIndexedDocumentsNotUpdatedAfter() throws IOException {
Client client = Mockito.mock(Client.class);
Map<String, Object> settings = (Map<String, Object>) Utils.loadJSONFromJarPackagedFile(
"/index_structure_configuration_test_ok.json").get("index");
DocumentWithCommentsIndexStructureBuilder tested = new DocumentWithCommentsIndexStructureBuilder(
mockEsIntegrationComponent(), "search_index", "issue_type", settings, true);
tested.commentTypeName = "comment_type";
// case - comments NONE
{
tested.commentIndexingMode = CommentIndexingMode.NONE;
SearchRequestBuilder srb = new SearchRequestBuilder(client);
tested.buildSearchForIndexedDocumentsNotUpdatedAfter(srb, "ORG",
DateTimeUtils.parseISODateTime("2012-09-06T12:22:19Z"));
Assert.assertArrayEquals(new String[] { "issue_type" }, srb.request().types());
assertTrue(
"Should equals but is: \n" + srb.toString(),
toJsonNode(srb.toString()).equals(
toJsonNode(TestUtils
.readStringFromClasspathFile("/asserts/buildSearchForIndexedDocumentsNotUpdatedAfter.json"))));
}
// case - comments EMBEDDED
{
tested.commentIndexingMode = CommentIndexingMode.EMBEDDED;
SearchRequestBuilder srb = new SearchRequestBuilder(client);
tested.buildSearchForIndexedDocumentsNotUpdatedAfter(srb, "ORG",
DateTimeUtils.parseISODateTime("2012-09-06T12:22:19Z"));
Assert.assertArrayEquals(new String[] { "issue_type" }, srb.request().types());
assertTrue(
"Should equals",
toJsonNode(srb.toString()).equals(
toJsonNode(TestUtils
.readStringFromClasspathFile("/asserts/buildSearchForIndexedDocumentsNotUpdatedAfter.json"))));
}
// case - comments EMBEDDED
{
tested.commentIndexingMode = CommentIndexingMode.CHILD;
SearchRequestBuilder srb = new SearchRequestBuilder(client);
tested.buildSearchForIndexedDocumentsNotUpdatedAfter(srb, "ORG",
DateTimeUtils.parseISODateTime("2012-09-06T12:22:19Z"));
Assert.assertArrayEquals(new String[] { "issue_type", "comment_type" }, srb.request().types());
assertTrue(
"Should equals",
toJsonNode(srb.toString()).equals(
toJsonNode(TestUtils
.readStringFromClasspathFile("/asserts/buildSearchForIndexedDocumentsNotUpdatedAfter.json"))));
}
// case - comments EMBEDDED
{
tested.commentIndexingMode = CommentIndexingMode.STANDALONE;
SearchRequestBuilder srb = new SearchRequestBuilder(client);
tested.buildSearchForIndexedDocumentsNotUpdatedAfter(srb, "ORG",
DateTimeUtils.parseISODateTime("2012-09-06T12:22:19Z"));
Assert.assertArrayEquals(new String[] { "issue_type", "comment_type" }, srb.request().types());
assertTrue(
"Should equals",
toJsonNode(srb.toString()).equals(
toJsonNode(TestUtils
.readStringFromClasspathFile("/asserts/buildSearchForIndexedDocumentsNotUpdatedAfter.json"))));
}
}
@Test
public void prepareIssueIndexedDocument() throws Exception {
DocumentWithCommentsIndexStructureBuilder tested = new DocumentWithCommentsIndexStructureBuilder(
mockEsIntegrationComponent(), "search_index", "issue_type",
loadTestSettings("/index_structure_configuration_test_ok.json"), true);
// case - no comments
{
tested.commentIndexingMode = CommentIndexingMode.NONE;
String res = tested.prepareIndexedDocument("ORG", TestUtils.readDocumentJsonDataFromClasspathFile("ORG-1501"))
.string();
assertTrue(
"Should equals",
toJsonNode(res).equals(
toJsonNode(TestUtils
.readStringFromClasspathFile("/asserts/prepareIssueIndexedDocument_ORG-1501_NOCOMMENT.json"))));
}
tested.remoteDataFieldForComments = "fields.comment.comments";
// case - comments as CHILD so not in this document
{
tested.commentIndexingMode = CommentIndexingMode.CHILD;
String res = tested.prepareIndexedDocument("ORG", TestUtils.readDocumentJsonDataFromClasspathFile("ORG-1501"))
.string();
assertTrue(
"Should equals",
toJsonNode(res).equals(
toJsonNode(TestUtils
.readStringFromClasspathFile("/asserts/prepareIssueIndexedDocument_ORG-1501_NOCOMMENT.json"))));
}
// case - comments as STANDALONE so not in this document
{
tested.commentIndexingMode = CommentIndexingMode.STANDALONE;
String res = tested.prepareIndexedDocument("ORG", TestUtils.readDocumentJsonDataFromClasspathFile("ORG-1501"))
.string();
assertTrue(
"Should equals",
toJsonNode(res).equals(
toJsonNode(TestUtils
.readStringFromClasspathFile("/asserts/prepareIssueIndexedDocument_ORG-1501_NOCOMMENT.json"))));
}
// case - comments as EMBEDDED so present in this document
{
tested.commentIndexingMode = CommentIndexingMode.EMBEDDED;
String res = tested.prepareIndexedDocument("ORG", TestUtils.readDocumentJsonDataFromClasspathFile("ORG-1501"))
.string();
assertTrue(
"Should equals",
toJsonNode(res).equals(
toJsonNode(TestUtils
.readStringFromClasspathFile("/asserts/prepareIssueIndexedDocument_ORG-1501_COMMENTS.json"))));
}
// case - comments as EMBEDDED but not in source so no present in this document
{
tested.commentIndexingMode = CommentIndexingMode.EMBEDDED;
String res = tested.prepareIndexedDocument("ORG", TestUtils.readDocumentJsonDataFromClasspathFile("ORG-1523"))
.string();
System.out.println(res);
assertTrue(
"Should equals",
toJsonNode(res).equals(
toJsonNode(TestUtils
.readStringFromClasspathFile("/asserts/prepareIssueIndexedDocument_ORG-1523_NOCOMMENTS.json"))));
}
}
@Test
public void prepareCommentIndexedDocument() throws Exception {
DocumentWithCommentsIndexStructureBuilder tested = new DocumentWithCommentsIndexStructureBuilder(
mockEsIntegrationComponent(), "search_index", "issue_type",
loadTestSettings("/index_structure_configuration_test_ok.json"), true);
tested.remoteDataFieldForComments = "fields.comment.comments";
Map<String, Object> issue = TestUtils.readDocumentJsonDataFromClasspathFile("ORG-1501");
List<Map<String, Object>> comments = tested.extractComments(issue);
String res = tested.prepareCommentIndexedDocument("ORG", "ORG-1501", comments.get(0)).string();
assertTrue(
"Should equals",
toJsonNode(res)
.equals(
toJsonNode(TestUtils
.readStringFromClasspathFile("/asserts/prepareCommentIndexedDocument_ORG-1501_1.json"))));
}
@Test
public void extractDocumentId() {
DocumentWithCommentsIndexStructureBuilder tested = new DocumentWithCommentsIndexStructureBuilder(
mockEsIntegrationComponent(), "search_index", "doc_type", createSettingsWithMandatoryFilled(), true);
tested.remoteDataFieldForDocumentId = null;
Map<String, Object> document = new HashMap<String, Object>();
document.put("key", "ORG-15");
document.put("key2", new Integer(10));
Utils.putValueIntoMapOfMaps(document, "key3.value", "ORG-17");
// case - normal key extraction from String
tested.remoteDataFieldForDocumentId = "key";
Assert.assertEquals("ORG-15", tested.extractDocumentId(document));
// case - normal key extraction from Integer
tested.remoteDataFieldForDocumentId = "key2";
Assert.assertEquals("10", tested.extractDocumentId(document));
// case - dot notation
tested.remoteDataFieldForDocumentId = "key3.value";
Assert.assertEquals("ORG-17", tested.extractDocumentId(document));
// case - id not found so null is returned
tested.remoteDataFieldForDocumentId = "key_unknown";
Assert.assertEquals(null, tested.extractDocumentId(document));
// case - bad type for id
try {
tested.remoteDataFieldForDocumentId = "key3";
tested.extractDocumentId(document);
Assert.fail("SettingsException expected");
} catch (SettingsException e) {
// OK
}
}
@Test
public void extractDocumentUpdated() {
DocumentWithCommentsIndexStructureBuilder tested = new DocumentWithCommentsIndexStructureBuilder(
mockEsIntegrationComponent(), "search_index", "doc_type", createSettingsWithMandatoryFilled(), true);
tested.remoteDataFieldForUpdated = null;
Map<String, Object> document = new HashMap<String, Object>();
document.put("key", "12564");
document.put("key2", new Integer(10));
document.put("key3", new Long(11));
Utils.putValueIntoMapOfMaps(document, "key4.value", "2012-09-06T02:26:53.000-0400");
document.put("badformat", "adafsf");
// case - date extraction from String with number
tested.remoteDataFieldForUpdated = "key";
Assert.assertEquals(new Date(12564l), tested.extractDocumentUpdated(document));
// case - date extraction from Integer
tested.remoteDataFieldForUpdated = "key2";
Assert.assertEquals(new Date(10l), tested.extractDocumentUpdated(document));
// case - date extraction from Integer
tested.remoteDataFieldForUpdated = "key3";
Assert.assertEquals(new Date(11l), tested.extractDocumentUpdated(document));
// case - dot notation and extraction from ISO format
tested.remoteDataFieldForUpdated = "key4.value";
Assert.assertEquals(DateTimeUtils.parseISODateTime("2012-09-06T02:26:53.000-0400"),
tested.extractDocumentUpdated(document));
// case - value not found so null is returned
tested.remoteDataFieldForUpdated = "key_unknown";
Assert.assertEquals(null, tested.extractDocumentUpdated(document));
// case - bad format not parseable to ISO date nor number
try {
tested.remoteDataFieldForUpdated = "badformat";
tested.extractDocumentUpdated(document);
Assert.fail("SettingsException expected");
} catch (SettingsException e) {
// OK
}
// case - bad type ov value in map
try {
tested.remoteDataFieldForUpdated = "key4";
tested.extractDocumentUpdated(document);
Assert.fail("SettingsException expected");
} catch (SettingsException e) {
// OK
}
}
@Test
public void extractDocumentDeleted() {
DocumentWithCommentsIndexStructureBuilder tested = new DocumentWithCommentsIndexStructureBuilder(
mockEsIntegrationComponent(), "search_index", "doc_type", createSettingsWithMandatoryFilled(), true);
tested.remoteDataFieldForDeleted = null;
tested.remoteDataValueForDeleted = null;
Map<String, Object> document = new HashMap<String, Object>();
Assert.assertFalse(tested.extractDocumentDeleted(null));
Assert.assertFalse(tested.extractDocumentDeleted(document));
tested.remoteDataFieldForDeleted = "delflag";
tested.remoteDataValueForDeleted = "true";
Assert.assertFalse(tested.extractDocumentDeleted(null));
Assert.assertFalse(tested.extractDocumentDeleted(document));
document.put(tested.remoteDataFieldForDeleted, Boolean.TRUE);
Assert.assertTrue(tested.extractDocumentDeleted(document));
document.put(tested.remoteDataFieldForDeleted, tested.remoteDataValueForDeleted);
Assert.assertTrue(tested.extractDocumentDeleted(document));
// case sensitive evaluation of the value
document.put(tested.remoteDataFieldForDeleted, "True");
Assert.assertFalse(tested.extractDocumentDeleted(document));
// Integer value from remote data
tested.remoteDataValueForDeleted = "1";
document.put(tested.remoteDataFieldForDeleted, new Integer(0));
Assert.assertFalse(tested.extractDocumentDeleted(document));
document.put(tested.remoteDataFieldForDeleted, new Integer(1));
Assert.assertTrue(tested.extractDocumentDeleted(document));
// bad type in remote data
try {
document.put(tested.remoteDataFieldForDeleted, new ArrayList<>());
tested.extractDocumentDeleted(document);
Assert.fail("SettingsException expected");
} catch (SettingsException e) {
// OK
}
try {
document.put(tested.remoteDataFieldForDeleted, new HashMap<>());
tested.extractDocumentDeleted(document);
Assert.fail("SettingsException expected");
} catch (SettingsException e) {
// OK
}
}
@SuppressWarnings("unchecked")
@Test
public void indexDocument() throws Exception {
DocumentWithCommentsIndexStructureBuilder tested = new DocumentWithCommentsIndexStructureBuilder(
mockEsIntegrationComponent(), "search_index", "issue_type",
loadTestSettings("/index_structure_configuration_test_ok.json"), true);
tested.remoteDataFieldForComments = "fields.comment.comments";
Client client = Mockito.mock(Client.class);
// case - comments NONE
{
BulkRequestBuilder esBulk = new BulkRequestBuilder(client);
tested.commentIndexingMode = CommentIndexingMode.NONE;
Map<String, Object> document = TestUtils.readDocumentJsonDataFromClasspathFile("ORG-1501");
tested.indexDocument(esBulk, "ORG", document);
Assert.assertEquals("ORG", document.get("spaceKey"));
Assert.assertEquals(1, esBulk.request().numberOfActions());
}
// case - comments EMBEDDED
{
BulkRequestBuilder esBulk = new BulkRequestBuilder(client);
tested.commentIndexingMode = CommentIndexingMode.EMBEDDED;
tested.indexDocument(esBulk, "ORG", TestUtils.readDocumentJsonDataFromClasspathFile("ORG-1501"));
Assert.assertEquals(1, esBulk.request().numberOfActions());
}
// case - comments CHILD
{
BulkRequestBuilder esBulk = new BulkRequestBuilder(client);
tested.commentIndexingMode = CommentIndexingMode.CHILD;
tested.indexDocument(esBulk, "ORG", TestUtils.readDocumentJsonDataFromClasspathFile("ORG-1501"));
Assert.assertEquals(3, esBulk.request().numberOfActions());
}
// case - comments STANDALONE with comments in issue
{
BulkRequestBuilder esBulk = new BulkRequestBuilder(client);
tested.commentIndexingMode = CommentIndexingMode.STANDALONE;
tested.indexDocument(esBulk, "ORG", TestUtils.readDocumentJsonDataFromClasspathFile("ORG-1501"));
Assert.assertEquals(3, esBulk.request().numberOfActions());
}
// case - comments STANDALONE without comments in issue
{
BulkRequestBuilder esBulk = new BulkRequestBuilder(client);
tested.commentIndexingMode = CommentIndexingMode.STANDALONE;
tested.indexDocument(esBulk, "ORG", TestUtils.readDocumentJsonDataFromClasspathFile("ORG-15013"));
Assert.assertEquals(1, esBulk.request().numberOfActions());
}
// case - preprocessor called
{
BulkRequestBuilder esBulk = new BulkRequestBuilder(client);
tested.commentIndexingMode = CommentIndexingMode.STANDALONE;
StructuredContentPreprocessor idp1 = mock(StructuredContentPreprocessor.class);
when(idp1.preprocessData(Mockito.anyMap())).thenAnswer(new Answer<Map<String, Object>>() {
@Override
public Map<String, Object> answer(InvocationOnMock invocation) throws Throwable {
return (Map<String, Object>) invocation.getArguments()[0];
}
});
tested.addDataPreprocessor(idp1);
tested.indexDocument(esBulk, "ORG", TestUtils.readDocumentJsonDataFromClasspathFile("ORG-15013"));
Assert.assertEquals(1, esBulk.request().numberOfActions());
verify(idp1, times(1)).preprocessData(Mockito.anyMap());
}
}
@Test
public void addValueToTheIndex() throws Exception {
DocumentWithCommentsIndexStructureBuilder tested = new DocumentWithCommentsIndexStructureBuilder(
mockEsIntegrationComponent(), null, null, createSettingsWithMandatoryFilled(), true);
XContentGenerator xContentGeneratorMock = mock(XContentGenerator.class);
XContentBuilder out = XContentBuilder.builder(preparexContentMock(xContentGeneratorMock));
// case - no exception if values parameter is null
tested.addValueToTheIndex(out, "testfield", "testpath", null, (Map<String, String>) null);
verify(xContentGeneratorMock, times(0)).writeFieldName(Mockito.anyString());
// case - no exception if value is not found
reset(xContentGeneratorMock);
Map<String, Object> values = new HashMap<String, Object>();
tested.addValueToTheIndex(out, "testfield", "testpath", values, (Map<String, String>) null);
verify(xContentGeneratorMock, times(0)).writeFieldName(Mockito.anyString());
// case - get correctly value from first level of nesting, no filtering on null filter
reset(xContentGeneratorMock);
values.put("myKey", "myValue");
values.put("myKey2", "myValue2");
tested.addValueToTheIndex(out, "testfield", "myKey2", values, (Map<String, String>) null);
verify(xContentGeneratorMock, times(1)).writeFieldName(Mockito.anyString());
verify(xContentGeneratorMock).writeFieldName("testfield");
verify(xContentGeneratorMock).writeString("myValue2");
Mockito.verifyNoMoreInteractions(xContentGeneratorMock);
// case - get correctly value from deeper level of nesting, no filtering with empty filter
reset(xContentGeneratorMock);
values.put("myKey", "myValue");
values.put("myKey2", "myValue2");
Map<String, Object> parent3 = new HashMap<String, Object>();
values.put("parent3", parent3);
parent3.put("myKey3", "myValue3");
Map<String, String> filter = new HashMap<String, String>();
tested.addValueToTheIndex(out, "testfield3", "parent3.myKey3", values, filter);
verify(xContentGeneratorMock, times(1)).writeFieldName(Mockito.anyString());
verify(xContentGeneratorMock).writeFieldName("testfield3");
verify(xContentGeneratorMock).writeString("myValue3");
Mockito.verifyNoMoreInteractions(xContentGeneratorMock);
// case - no error when filter on filtering unsupported value
reset(xContentGeneratorMock);
values.clear();
values.put("myKey", "myValue");
values.put("myKey2", "myValue2");
filter.put("myKeyFilter", "myKeyFilter");
tested.addValueToTheIndex(out, "testfield", "myKey2", values, filter);
verify(xContentGeneratorMock).writeFieldName("testfield");
verify(xContentGeneratorMock).writeString("myValue2");
Mockito.verifyNoMoreInteractions(xContentGeneratorMock);
// case - get correctly value from first level of nesting, filtering on Map
reset(xContentGeneratorMock);
values.clear();
values.put("myKey", "myValue");
values.put("myKey2", "myValue2");
parent3 = new HashMap<String, Object>();
values.put("parent3", parent3);
parent3.put("myKey3", "myValue3");
parent3.put("myKey4", "myValue4");
filter.clear();
filter.put("myKey3", "myKey1");
tested.addValueToTheIndex(out, "testfield", "parent3", values, filter);
verify(xContentGeneratorMock).writeFieldName("testfield");
verify(xContentGeneratorMock).writeStartObject();
verify(xContentGeneratorMock).writeFieldName("myKey1");
verify(xContentGeneratorMock).writeString("myValue3");
verify(xContentGeneratorMock).writeEndObject();
Mockito.verifyNoMoreInteractions(xContentGeneratorMock);
// case - filtering on List of Maps
reset(xContentGeneratorMock);
values.clear();
values.put("myKey", "myValue");
values.put("myKey2", "myValue2");
List<Object> parent3list = new ArrayList<Object>();
values.put("parent3", parent3list);
Map<String, Object> obj31 = new HashMap<String, Object>();
parent3list.add(obj31);
obj31.put("myKey3", "myValue31");
obj31.put("myKey4", "myValue41");
Map<String, Object> obj32 = new HashMap<String, Object>();
parent3list.add(obj32);
obj32.put("myKey3", "myValue32");
obj32.put("myKey4", "myValue42");
filter.clear();
filter.put("myKey3", "myKey3");
tested.addValueToTheIndex(out, "testfield", "parent3", values, filter);
verify(xContentGeneratorMock).writeFieldName("testfield");
verify(xContentGeneratorMock, times(1)).writeStartArray();
verify(xContentGeneratorMock, times(2)).writeStartObject();
verify(xContentGeneratorMock, times(2)).writeFieldName("myKey3");
verify(xContentGeneratorMock).writeString("myValue31");
verify(xContentGeneratorMock).writeString("myValue32");
verify(xContentGeneratorMock, times(2)).writeEndObject();
verify(xContentGeneratorMock, times(1)).writeEndArray();
Mockito.verifyNoMoreInteractions(xContentGeneratorMock);
}
@Test
public void addValueToTheIndexField() throws Exception {
DocumentWithCommentsIndexStructureBuilder tested = new DocumentWithCommentsIndexStructureBuilder(
mockEsIntegrationComponent(), null, null, createSettingsWithMandatoryFilled(), true);
XContentGenerator xContentGeneratorMock = mock(XContentGenerator.class);
XContentBuilder out = XContentBuilder.builder(preparexContentMock(xContentGeneratorMock));
// case - string field
tested.addValueToTheIndexField(out, "test", "testvalue");
verify(xContentGeneratorMock).writeFieldName("test");
verify(xContentGeneratorMock).writeString("testvalue");
// case - integer field
reset(xContentGeneratorMock);
tested.addValueToTheIndexField(out, "testint", new Integer(10));
verify(xContentGeneratorMock).writeFieldName("testint");
verify(xContentGeneratorMock).writeNumber(10);
// case - nothing added if value is null
reset(xContentGeneratorMock);
tested.addValueToTheIndexField(out, "testnull", null);
Mockito.verifyZeroInteractions(xContentGeneratorMock);
}
/**
* Prepare {@link XContent} mock to be used for {@link XContentBuilder} test instance creation.
*
* @param xContentGeneratorMock to be returned from XContent mock
* @return XContent mock instance
* @throws IOException
*/
protected XContent preparexContentMock(XContentGenerator xContentGeneratorMock) throws IOException {
XContent xContentMock = mock(XContent.class);
when(xContentMock.createGenerator(Mockito.any(OutputStream.class))).thenReturn(xContentGeneratorMock);
return xContentMock;
}
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", "river_name");
Mockito.when(esIntegrationMock.riverName()).thenReturn(riverName);
return esIntegrationMock;
}
}