package com.github.obourgain.elasticsearch.http; import static org.elasticsearch.common.xcontent.XContentType.JSON; import static org.elasticsearch.node.internal.InternalNode.HTTP_ENABLED; import java.io.IOException; import java.net.InetSocketAddress; import java.util.Collections; import java.util.HashMap; import java.util.Map; import org.assertj.core.api.Assertions; import org.assertj.core.data.MapEntry; import org.elasticsearch.action.admin.cluster.node.info.NodeInfo; import org.elasticsearch.client.Requests; import org.elasticsearch.client.transport.TransportClient; import org.elasticsearch.cluster.metadata.MappingMetaData; import org.elasticsearch.common.settings.ImmutableSettings; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.transport.InetSocketTransportAddress; import org.elasticsearch.common.transport.TransportAddress; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.test.ElasticsearchIntegrationTest; import org.hamcrest.Matchers; import org.junit.After; import org.junit.Assert; import org.junit.Before; import com.carrotsearch.randomizedtesting.annotations.ThreadLeakFilters; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.type.MapType; import com.github.obourgain.elasticsearch.http.client.HttpClient; import com.github.obourgain.elasticsearch.http.response.entity.Shards; /** * @author olivier bourgain */ @ThreadLeakFilters(defaultFilters = true, filters = {RxNettyThreadFilter.class}) @ElasticsearchIntegrationTest.ClusterScope(transportClientRatio = 1, numClientNodes = 1, numDataNodes = 1, scope = ElasticsearchIntegrationTest.Scope.SUITE) public abstract class AbstractTest extends ElasticsearchIntegrationTest { public static final String THE_INDEX = "the_index"; public static final String THE_TYPE = "the_type"; public static final String THE_ID = "the_id"; protected TransportClient transportClient; protected HttpClient httpClient; @Override protected Settings nodeSettings(int nodeOrdinal) { return ImmutableSettings.settingsBuilder() .put(super.nodeSettings(nodeOrdinal)) .put(HTTP_ENABLED, true) .build(); } @Before public void setUpClient() throws IOException, InterruptedException, NoSuchFieldException, IllegalAccessException { createIndex(THE_INDEX); ensureSearchable(THE_INDEX); transportClient = (TransportClient) cluster().client(); String url = getUrlOfOneNode(); httpClient = new HttpClient(Collections.singleton(url)); } protected String getUrlOfOneNode() { NodeInfo[] nodes = admin().cluster().nodesInfo(Requests.nodesInfoRequest()).actionGet().getNodes(); Assert.assertThat(nodes.length, Matchers.greaterThanOrEqualTo(1)); TransportAddress transportAddress = nodes[0].getHttp().getAddress().publishAddress(); Assert.assertEquals(InetSocketTransportAddress.class, transportAddress.getClass()); InetSocketTransportAddress inetSocketTransportAddress = (InetSocketTransportAddress) transportAddress; InetSocketAddress socketAddress = inetSocketTransportAddress.address(); return String.format("http://%s:%d", socketAddress.getHostName(), socketAddress.getPort()); } @After public void stopClient() { httpClient.close(); } private XContentType initialContentType = null; @Before public void save_request_content_type() { // this client only uses JSON, so set the content type used by ES on request generation, but also clean up stuff afterwards initialContentType = Requests.CONTENT_TYPE; Requests.CONTENT_TYPE = JSON; } @After public void restore_request_content_type() { Requests.CONTENT_TYPE = initialContentType; } protected void createDoc() throws IOException { createSimpleDoc(THE_INDEX, THE_TYPE, THE_ID); } protected void createSimpleDoc(String index, String type, String id) throws IOException { transportClient.index(Requests.indexRequest().index(index).type(type).id(id).refresh(true) .source(XContentFactory.jsonBuilder().startObject() .field("the_string_field", "the_string_value") .field("the_integer_field", 42) .field("the_boolean_field", true) .field("the_long_array_field", new long[]{42L, 53L}) .endObject()) ).actionGet(); } protected void createDocFromClasspathFile(String index, String type, String id, String path) throws IOException { String document = TestFilesUtils.readFromClasspath(path); createDoc(index, type, id, document); } protected void createDoc(String index, String type, String id, String document) throws IOException { transportClient.index(Requests.indexRequest().index(index).type(type).id(id).refresh(true).source(document)).actionGet(); } protected void deleteDoc(String index, String type, String id) { transportClient.delete(Requests.deleteRequest(index).type(type).id(id).refresh(true)).actionGet(); } protected void createPercolatorQuery() throws IOException { QueryBuilder qb = QueryBuilders.matchQuery("the_string_field", "the_string_value"); transportClient.prepareIndex(THE_INDEX, ".percolator", "the_query") .setSource(XContentFactory.jsonBuilder() .startObject() .field("query", qb) .endObject()) .setRefresh(true) .execute().actionGet(); } protected void compareMap(Map<String, Object> expected, Map<String, Object> actualSource) { Assertions.assertThat(actualSource).hasSameSizeAs(expected); for (Map.Entry<String, Object> actualEntry : actualSource.entrySet()) { Assertions.assertThat(expected).contains(MapEntry.entry(actualEntry.getKey(), actualEntry.getValue())); } } protected XContentBuilder source() throws IOException { return XContentFactory.jsonBuilder().startObject() .field("the_string_field", "the_string_value") .field("the_integer_field", 42) .field("the_boolean_field", true) .field("the_long_array_field", new long[]{42L, 53L}) .endObject(); } public void assertShardsSuccessfulForIT(Shards shards, String indexName) { Assertions.assertThat(shards.getTotal()).describedAs(shards.toString()).isEqualTo(getNumShards(indexName).numPrimaries); Assertions.assertThat(shards.getSuccessful()).describedAs(shards.toString()).isEqualTo(getNumShards(indexName).numPrimaries); Assertions.assertThat(shards.getFailed()).describedAs(shards.toString()).isEqualTo(0); } public void assertSettingsEquals(Settings expected, Settings actual) { for (Map.Entry<String, String> entry : expected.getAsMap().entrySet()) { Assertions.assertThat(actual.get(entry.getKey())).isEqualTo(entry.getValue()); } } public void assertMappingsEquals(Map<String, Object> expected, MappingMetaData actual) { Map<String, Object> sourceAsMap; try { sourceAsMap = actual.getSourceAsMap(); } catch (IOException e) { throw new RuntimeException(e); } for (Map.Entry<String, Object> entry : expected.entrySet()) { String key = entry.getKey(); Assertions.assertThat(sourceAsMap.containsKey(key)).isTrue(); Object actualValue = sourceAsMap.get(key); if (entry.getValue() instanceof Map) { assertMapContainsValues((Map) entry.getValue(), ((Map) sourceAsMap.get(entry.getKey()))); } else { Assertions.assertThat(actualValue).isEqualTo(entry.getValue()); } } } protected void assertMapContainsValues(Map<Object, Object> expectedValues, Map<Object, Object> actual) { for (Map.Entry entry : expectedValues.entrySet()) { Assertions.assertThat(actual.containsKey(entry.getKey())).isTrue(); Assertions.assertThat(actual.get(entry.getKey())).isEqualTo(entry.getValue()); } } protected Map<String, Object> mappingAsJsonToMap(String mappingAsJson) { ObjectMapper objectMapper = new ObjectMapper(); MapType mapType = objectMapper.getTypeFactory().constructMapType(HashMap.class, String.class, Object.class); try { return new ObjectMapper().readValue(mappingAsJson, mapType); } catch (IOException e) { throw new RuntimeException(e); } } }