Merge branch 'master' into hlclient/add-delete-method

# Conflicts:
#	client/rest-high-level/src/main/java/org/elasticsearch/client/Request.java
#	client/rest-high-level/src/test/java/org/elasticsearch/client/CrudIT.java
This commit is contained in:
David Pilato 2017-02-15 16:08:29 +01:00
commit 0bbcd94827
5 changed files with 502 additions and 65 deletions

View File

@ -20,10 +20,22 @@
package org.elasticsearch.client; package org.elasticsearch.client;
import org.apache.http.HttpEntity; import org.apache.http.HttpEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.ContentType;
import org.apache.lucene.util.BytesRef;
import org.elasticsearch.action.DocWriteRequest;
import org.elasticsearch.action.delete.DeleteRequest; import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.get.GetRequest; import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.support.ActiveShardCount;
import org.elasticsearch.action.support.WriteRequest;
import org.elasticsearch.common.Strings; import org.elasticsearch.common.Strings;
import org.elasticsearch.common.lucene.uid.Versions; import org.elasticsearch.common.lucene.uid.Versions;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.VersionType; import org.elasticsearch.index.VersionType;
import org.elasticsearch.search.fetch.subphase.FetchSourceContext; import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
@ -35,6 +47,8 @@ import java.util.StringJoiner;
final class Request { final class Request {
private static final String DELIMITER = "/";
final String method; final String method;
final String endpoint; final String endpoint;
final Map<String, String> params; final Map<String, String> params;
@ -61,53 +75,53 @@ final class Request {
} }
static Request exists(GetRequest getRequest) { static Request exists(GetRequest getRequest) {
return new Request("HEAD", getEndpoint(getRequest), getParams(getRequest), null); Request request = get(getRequest);
return new Request(HttpHead.METHOD_NAME, request.endpoint, request.params, null);
} }
static Request get(GetRequest getRequest) { static Request get(GetRequest getRequest) {
return new Request("GET", getEndpoint(getRequest), getParams(getRequest), null); String endpoint = endpoint(getRequest.index(), getRequest.type(), getRequest.id());
Params parameters = Params.builder();
parameters.withPreference(getRequest.preference());
parameters.withRouting(getRequest.routing());
parameters.withParent(getRequest.parent());
parameters.withRefresh(getRequest.refresh());
parameters.withRealtime(getRequest.realtime());
parameters.withStoredFields(getRequest.storedFields());
parameters.withVersion(getRequest.version());
parameters.withVersionType(getRequest.versionType());
parameters.withFetchSourceContext(getRequest.fetchSourceContext());
return new Request(HttpGet.METHOD_NAME, endpoint, parameters.getParams(), null);
}
static Request index(IndexRequest indexRequest) {
String method = Strings.hasLength(indexRequest.id()) ? HttpPut.METHOD_NAME : HttpPost.METHOD_NAME;
boolean isCreate = (indexRequest.opType() == DocWriteRequest.OpType.CREATE);
String endpoint = endpoint(indexRequest.index(), indexRequest.type(), indexRequest.id(), isCreate ? "_create" : null);
Params parameters = Params.builder();
parameters.withRouting(indexRequest.routing());
parameters.withParent(indexRequest.parent());
parameters.withTimeout(indexRequest.timeout());
parameters.withVersion(indexRequest.version());
parameters.withVersionType(indexRequest.versionType());
parameters.withPipeline(indexRequest.getPipeline());
parameters.withRefreshPolicy(indexRequest.getRefreshPolicy());
parameters.withWaitForActiveShards(indexRequest.waitForActiveShards());
BytesRef source = indexRequest.source().toBytesRef();
ContentType contentType = ContentType.create(indexRequest.getContentType().mediaType());
HttpEntity entity = new ByteArrayEntity(source.bytes, source.offset, source.length, contentType);
return new Request(method, endpoint, parameters.getParams(), entity);
} }
static Request delete(DeleteRequest deleteRequest) { static Request delete(DeleteRequest deleteRequest) {
return new Request("DELETE", deleteEndpoint(deleteRequest), deleteParams(deleteRequest), null); return new Request("DELETE", deleteEndpoint(deleteRequest), deleteParams(deleteRequest), null);
}
private static Map<String, String> getParams(GetRequest getRequest) {
Map<String, String> params = new HashMap<>();
putParam("preference", getRequest.preference(), params);
putParam("routing", getRequest.routing(), params);
putParam("parent", getRequest.parent(), params);
if (getRequest.refresh()) {
params.put("refresh", Boolean.TRUE.toString());
}
if (getRequest.realtime() == false) {
params.put("realtime", Boolean.FALSE.toString());
}
if (getRequest.storedFields() != null && getRequest.storedFields().length > 0) {
params.put("stored_fields", String.join(",", getRequest.storedFields()));
}
if (getRequest.version() != Versions.MATCH_ANY) {
params.put("version", Long.toString(getRequest.version()));
}
if (getRequest.versionType() != VersionType.INTERNAL) {
params.put("version_type", getRequest.versionType().name().toLowerCase(Locale.ROOT));
}
if (getRequest.fetchSourceContext() != null) {
FetchSourceContext fetchSourceContext = getRequest.fetchSourceContext();
if (fetchSourceContext.fetchSource() == false) {
params.put("_source", Boolean.FALSE.toString());
}
if (fetchSourceContext.includes() != null && fetchSourceContext.includes().length > 0) {
params.put("_source_include", String.join(",", fetchSourceContext.includes()));
}
if (fetchSourceContext.excludes() != null && fetchSourceContext.excludes().length > 0) {
params.put("_source_exclude", String.join(",", fetchSourceContext.excludes()));
}
}
return Collections.unmodifiableMap(params);
}
private static Map<String, String> deleteParams(DeleteRequest deleteRequest) {
Map<String, String> params = new HashMap<>(); Map<String, String> params = new HashMap<>();
putParam("routing", deleteRequest.routing(), params); putParam("routing", deleteRequest.routing(), params);
putParam("parent", deleteRequest.parent(), params); putParam("parent", deleteRequest.parent(), params);
@ -118,21 +132,140 @@ final class Request {
params.put("version_type", deleteRequest.versionType().name().toLowerCase(Locale.ROOT)); params.put("version_type", deleteRequest.versionType().name().toLowerCase(Locale.ROOT));
} }
return Collections.unmodifiableMap(params); return Collections.unmodifiableMap(params);
} }
private static String getEndpoint(GetRequest getRequest) { /**
StringJoiner pathJoiner = new StringJoiner("/", "/", ""); * Utility method to build request's endpoint.
return pathJoiner.add(getRequest.index()).add(getRequest.type()).add(getRequest.id()).toString(); */
static String endpoint(String... parts) {
if (parts == null || parts.length == 0) {
return DELIMITER;
StringJoiner joiner = new StringJoiner(DELIMITER, DELIMITER, "");
for (String part : parts) {
if (part != null) {
joiner.add(part);
}
}
return joiner.toString();
} }
private static String deleteEndpoint(DeleteRequest deleteRequest) { /**
StringJoiner pathJoiner = new StringJoiner("/", "/", ""); * Utility class to build request's parameters map and centralize all parameter names.
return pathJoiner.add(deleteRequest.index()).add(deleteRequest.type()).add(deleteRequest.id()).toString(); */
static class Params {
private final Map<String, String> params = new HashMap<>();
private Params() {
} }
private static void putParam(String key, String value, Map<String, String> params) { Params putParam(String key, String value) {
if (Strings.hasLength(value)) { if (Strings.hasLength(value)) {
params.put(key, value); if (params.putIfAbsent(key, value) != null) {
throw new IllegalArgumentException("Request parameter [" + key + "] is already registered");
}
}
return this;
}
Params putParam(String key, TimeValue value) {
if (value != null) {
return putParam(key, value.getStringRep());
}
return this;
}
Params withFetchSourceContext(FetchSourceContext fetchSourceContext) {
if (fetchSourceContext != null) {
if (fetchSourceContext.fetchSource() == false) {
putParam("_source", Boolean.FALSE.toString());
}
if (fetchSourceContext.includes() != null && fetchSourceContext.includes().length > 0) {
putParam("_source_include", String.join(",", fetchSourceContext.includes()));
}
if (fetchSourceContext.excludes() != null && fetchSourceContext.excludes().length > 0) {
putParam("_source_exclude", String.join(",", fetchSourceContext.excludes()));
}
}
return this;
}
Params withParent(String parent) {
return putParam("parent", parent);
}
Params withPipeline(String pipeline) {
return putParam("pipeline", pipeline);
}
Params withPreference(String preference) {
return putParam("preference", preference);
}
Params withRealtime(boolean realtime) {
if (realtime == false) {
return putParam("realtime", Boolean.FALSE.toString());
}
return this;
}
Params withRefresh(boolean refresh) {
if (refresh) {
return withRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
}
return this;
}
Params withRefreshPolicy(WriteRequest.RefreshPolicy refreshPolicy) {
if (refreshPolicy != WriteRequest.RefreshPolicy.NONE) {
putParam("refresh", refreshPolicy.getValue());
}
return this;
}
Params withRouting(String routing) {
return putParam("routing", routing);
}
Params withStoredFields(String[] storedFields) {
if (storedFields != null && storedFields.length > 0) {
return putParam("stored_fields", String.join(",", storedFields));
}
return this;
}
Params withTimeout(TimeValue timeout) {
return putParam("timeout", timeout);
}
Params withVersion(long version) {
if (version != Versions.MATCH_ANY) {
return putParam("version", Long.toString(version));
}
return this;
}
Params withVersionType(VersionType versionType) {
if (versionType != VersionType.INTERNAL) {
return putParam("version_type", versionType.name().toLowerCase(Locale.ROOT));
}
return this;
}
Params withWaitForActiveShards(ActiveShardCount activeShardCount) {
if (activeShardCount != null && activeShardCount != ActiveShardCount.DEFAULT) {
return putParam("wait_for_active_shards", activeShardCount.toString().toLowerCase(Locale.ROOT));
}
return this;
}
Map<String, String> getParams() {
return Collections.unmodifiableMap(params);
}
static Params builder() {
return new Params();
} }
} }
} }

View File

@ -30,6 +30,8 @@ import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse; import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest; import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse; import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.main.MainRequest; import org.elasticsearch.action.main.MainRequest;
import org.elasticsearch.common.CheckedFunction; import org.elasticsearch.common.CheckedFunction;
import org.elasticsearch.common.xcontent.NamedXContentRegistry; import org.elasticsearch.common.xcontent.NamedXContentRegistry;
@ -44,6 +46,9 @@ import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.function.Function; import java.util.function.Function;
import static java.util.Collections.emptySet;
import static java.util.Collections.singleton;
/** /**
* High level REST client that wraps an instance of the low level {@link RestClient} and allows to build requests and read responses. * High level REST client that wraps an instance of the low level {@link RestClient} and allows to build requests and read responses.
* The provided {@link RestClient} is externally built and closed. * The provided {@link RestClient} is externally built and closed.
@ -61,37 +66,61 @@ public class RestHighLevelClient {
*/ */
public boolean ping(Header... headers) throws IOException { public boolean ping(Header... headers) throws IOException {
return performRequest(new MainRequest(), (request) -> Request.ping(), RestHighLevelClient::convertExistsResponse, return performRequest(new MainRequest(), (request) -> Request.ping(), RestHighLevelClient::convertExistsResponse,
Collections.emptySet(), headers); emptySet(), headers);
} }
/** /**
* Retrieves a document by id using the get api * Retrieves a document by id using the Get API
*
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-get.html">Get API on elastic.co</a>
*/ */
public GetResponse get(GetRequest getRequest, Header... headers) throws IOException { public GetResponse get(GetRequest getRequest, Header... headers) throws IOException {
return performRequestAndParseEntity(getRequest, Request::get, GetResponse::fromXContent, Collections.singleton(404), headers); return performRequestAndParseEntity(getRequest, Request::get, GetResponse::fromXContent, singleton(404), headers);
} }
/** /**
* Asynchronously retrieves a document by id using the get api * Asynchronously retrieves a document by id using the Get API
*
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-get.html">Get API on elastic.co</a>
*/ */
public void getAsync(GetRequest getRequest, ActionListener<GetResponse> listener, Header... headers) { public void getAsync(GetRequest getRequest, ActionListener<GetResponse> listener, Header... headers) {
performRequestAsyncAndParseEntity(getRequest, Request::get, GetResponse::fromXContent, listener, performRequestAsyncAndParseEntity(getRequest, Request::get, GetResponse::fromXContent, listener, singleton(404), headers);
Collections.singleton(404), headers);
} }
/** /**
* Checks for the existence of a document. Returns true if it exists, false otherwise * Checks for the existence of a document. Returns true if it exists, false otherwise
*
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-get.html">Get API on elastic.co</a>
*/ */
public boolean exists(GetRequest getRequest, Header... headers) throws IOException { public boolean exists(GetRequest getRequest, Header... headers) throws IOException {
return performRequest(getRequest, Request::exists, RestHighLevelClient::convertExistsResponse, Collections.emptySet(), headers); return performRequest(getRequest, Request::exists, RestHighLevelClient::convertExistsResponse, emptySet(), headers);
} }
/** /**
* Asynchronously checks for the existence of a document. Returns true if it exists, false otherwise * Asynchronously checks for the existence of a document. Returns true if it exists, false otherwise
*
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-get.html">Get API on elastic.co</a>
*/ */
public void existsAsync(GetRequest getRequest, ActionListener<Boolean> listener, Header... headers) { public void existsAsync(GetRequest getRequest, ActionListener<Boolean> listener, Header... headers) {
performRequestAsync(getRequest, Request::exists, RestHighLevelClient::convertExistsResponse, listener, performRequestAsync(getRequest, Request::exists, RestHighLevelClient::convertExistsResponse, listener, emptySet(), headers);
Collections.emptySet(), headers); }
/**
* Index a document using the Index API
*
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-index_.html">Index API on elastic.co</a>
*/
public IndexResponse index(IndexRequest indexRequest, Header... headers) throws IOException {
return performRequestAndParseEntity(indexRequest, Request::index, IndexResponse::fromXContent, emptySet(), headers);
}
/**
* Asynchronously index a document using the Index API
*
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-index_.html">Index API on elastic.co</a>
*/
public void indexAsync(IndexRequest indexRequest, ActionListener<IndexResponse> listener, Header... headers) {
performRequestAsyncAndParseEntity(indexRequest, Request::index, IndexResponse::fromXContent, listener, emptySet(), headers);
} }
/** /**

View File

@ -22,12 +22,19 @@ package org.elasticsearch.client;
import org.apache.http.entity.ContentType; import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity; import org.apache.http.entity.StringEntity;
import org.elasticsearch.ElasticsearchException; import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.DocWriteRequest;
import org.elasticsearch.action.DocWriteResponse; import org.elasticsearch.action.DocWriteResponse;
import org.elasticsearch.action.delete.DeleteRequest; import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse; import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.ElasticsearchStatusException;
import org.elasticsearch.action.get.GetRequest; import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse; import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.common.Strings; import org.elasticsearch.common.Strings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.VersionType;
import org.elasticsearch.rest.RestStatus; import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.fetch.subphase.FetchSourceContext; import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
@ -145,6 +152,122 @@ public class CrudIT extends ESRestHighLevelClientTestCase {
} }
} }
public void testIndex() throws IOException {
final XContentType xContentType = randomFrom(XContentType.values());
{
IndexRequest indexRequest = new IndexRequest("index", "type");
indexRequest.source(XContentBuilder.builder(xContentType.xContent()).startObject().field("test", "test").endObject());
IndexResponse indexResponse = execute(indexRequest, highLevelClient()::index, highLevelClient()::indexAsync);
assertEquals(RestStatus.CREATED, indexResponse.status());
assertEquals(DocWriteResponse.Result.CREATED, indexResponse.getResult());
assertEquals("index", indexResponse.getIndex());
assertEquals("type", indexResponse.getType());
assertTrue(Strings.hasLength(indexResponse.getId()));
assertEquals(1L, indexResponse.getVersion());
assertNotNull(indexResponse.getShardId());
assertEquals(-1, indexResponse.getShardId().getId());
assertEquals("index", indexResponse.getShardId().getIndexName());
assertEquals("index", indexResponse.getShardId().getIndex().getName());
assertEquals("_na_", indexResponse.getShardId().getIndex().getUUID());
assertNotNull(indexResponse.getShardInfo());
assertEquals(0, indexResponse.getShardInfo().getFailed());
assertTrue(indexResponse.getShardInfo().getSuccessful() > 0);
assertTrue(indexResponse.getShardInfo().getTotal() > 0);
}
{
IndexRequest indexRequest = new IndexRequest("index", "type", "id");
indexRequest.source(XContentBuilder.builder(xContentType.xContent()).startObject().field("version", 1).endObject());
IndexResponse indexResponse = execute(indexRequest, highLevelClient()::index, highLevelClient()::indexAsync);
assertEquals(RestStatus.CREATED, indexResponse.status());
assertEquals("index", indexResponse.getIndex());
assertEquals("type", indexResponse.getType());
assertEquals("id", indexResponse.getId());
assertEquals(1L, indexResponse.getVersion());
indexRequest = new IndexRequest("index", "type", "id");
indexRequest.source(XContentBuilder.builder(xContentType.xContent()).startObject().field("version", 2).endObject());
indexResponse = execute(indexRequest, highLevelClient()::index, highLevelClient()::indexAsync);
assertEquals(RestStatus.OK, indexResponse.status());
assertEquals("index", indexResponse.getIndex());
assertEquals("type", indexResponse.getType());
assertEquals("id", indexResponse.getId());
assertEquals(2L, indexResponse.getVersion());
ElasticsearchStatusException exception = expectThrows(ElasticsearchStatusException.class, () -> {
IndexRequest wrongRequest = new IndexRequest("index", "type", "id");
wrongRequest.source(XContentBuilder.builder(xContentType.xContent()).startObject().field("field", "test").endObject());
wrongRequest.version(5L);
execute(wrongRequest, highLevelClient()::index, highLevelClient()::indexAsync);
});
assertEquals(RestStatus.CONFLICT, exception.status());
assertEquals("Elasticsearch exception [type=version_conflict_engine_exception, reason=[type][id]: " +
"version conflict, current version [2] is different than the one provided [5]]", exception.getMessage());
assertEquals("index", exception.getMetadata("es.index").get(0));
}
{
ElasticsearchStatusException exception = expectThrows(ElasticsearchStatusException.class, () -> {
IndexRequest indexRequest = new IndexRequest("index", "type", "missing_parent");
indexRequest.source(XContentBuilder.builder(xContentType.xContent()).startObject().field("field", "test").endObject());
indexRequest.parent("missing");
execute(indexRequest, highLevelClient()::index, highLevelClient()::indexAsync);
});
assertEquals(RestStatus.BAD_REQUEST, exception.status());
assertEquals("Elasticsearch exception [type=illegal_argument_exception, " +
"reason=Can't specify parent if no parent field has been configured]", exception.getMessage());
}
{
ElasticsearchStatusException exception = expectThrows(ElasticsearchStatusException.class, () -> {
IndexRequest indexRequest = new IndexRequest("index", "type", "missing_pipeline");
indexRequest.source(XContentBuilder.builder(xContentType.xContent()).startObject().field("field", "test").endObject());
indexRequest.setPipeline("missing");
execute(indexRequest, highLevelClient()::index, highLevelClient()::indexAsync);
});
assertEquals(RestStatus.BAD_REQUEST, exception.status());
assertEquals("Elasticsearch exception [type=illegal_argument_exception, " +
"reason=pipeline with id [missing] does not exist]", exception.getMessage());
}
{
IndexRequest indexRequest = new IndexRequest("index", "type", "external_version_type");
indexRequest.source(XContentBuilder.builder(xContentType.xContent()).startObject().field("field", "test").endObject());
indexRequest.version(12L);
indexRequest.versionType(VersionType.EXTERNAL);
IndexResponse indexResponse = execute(indexRequest, highLevelClient()::index, highLevelClient()::indexAsync);
assertEquals(RestStatus.CREATED, indexResponse.status());
assertEquals("index", indexResponse.getIndex());
assertEquals("type", indexResponse.getType());
assertEquals("external_version_type", indexResponse.getId());
assertEquals(12L, indexResponse.getVersion());
}
{
final IndexRequest indexRequest = new IndexRequest("index", "type", "with_create_op_type");
indexRequest.source(XContentBuilder.builder(xContentType.xContent()).startObject().field("field", "test").endObject());
indexRequest.opType(DocWriteRequest.OpType.CREATE);
IndexResponse indexResponse = execute(indexRequest, highLevelClient()::index, highLevelClient()::indexAsync);
assertEquals(RestStatus.CREATED, indexResponse.status());
assertEquals("index", indexResponse.getIndex());
assertEquals("type", indexResponse.getType());
assertEquals("with_create_op_type", indexResponse.getId());
ElasticsearchStatusException exception = expectThrows(ElasticsearchStatusException.class, () -> {
execute(indexRequest, highLevelClient()::index, highLevelClient()::indexAsync);
});
assertEquals(RestStatus.CONFLICT, exception.status());
assertEquals("Elasticsearch exception [type=version_conflict_engine_exception, reason=[type][with_create_op_type]: " +
"version conflict, document already exists (current version [1])]", exception.getMessage());
}
}
public void testDelete() throws IOException { public void testDelete() throws IOException {
{ {
DeleteRequest deleteRequest = new DeleteRequest("index", "type", "does_not_exist"); DeleteRequest deleteRequest = new DeleteRequest("index", "type", "does_not_exist");

View File

@ -19,12 +19,23 @@
package org.elasticsearch.client; package org.elasticsearch.client;
import org.apache.http.HttpEntity;
import org.apache.http.entity.ByteArrayEntity;
import org.elasticsearch.action.DocWriteRequest;
import org.elasticsearch.action.get.GetRequest; import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.support.WriteRequest;
import org.elasticsearch.action.support.replication.ReplicationRequest;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.lucene.uid.Versions; import org.elasticsearch.common.lucene.uid.Versions;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.VersionType; import org.elasticsearch.index.VersionType;
import org.elasticsearch.search.fetch.subphase.FetchSourceContext; import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
@ -155,4 +166,145 @@ public class RequestTests extends ESTestCase {
assertNull(request.entity); assertNull(request.entity);
assertEquals(method, request.method); assertEquals(method, request.method);
} }
public void testIndex() throws IOException {
String index = randomAsciiOfLengthBetween(3, 10);
String type = randomAsciiOfLengthBetween(3, 10);
IndexRequest indexRequest = new IndexRequest(index, type);
String id = randomBoolean() ? randomAsciiOfLengthBetween(3, 10) : null;
indexRequest.id(id);
Map<String, String> expectedParams = new HashMap<>();
String method = "POST";
if (id != null) {
method = "PUT";
if (randomBoolean()) {
indexRequest.opType(DocWriteRequest.OpType.CREATE);
}
}
// There is some logic around _create endpoint and version/version type
if (indexRequest.opType() == DocWriteRequest.OpType.CREATE) {
indexRequest.version(randomFrom(Versions.MATCH_ANY, Versions.MATCH_DELETED));
expectedParams.put("version", Long.toString(Versions.MATCH_DELETED));
} else {
if (randomBoolean()) {
long version = randomFrom(Versions.MATCH_ANY, Versions.MATCH_DELETED, Versions.NOT_FOUND, randomNonNegativeLong());
indexRequest.version(version);
if (version != Versions.MATCH_ANY) {
expectedParams.put("version", Long.toString(version));
}
}
if (randomBoolean()) {
VersionType versionType = randomFrom(VersionType.values());
indexRequest.versionType(versionType);
if (versionType != VersionType.INTERNAL) {
expectedParams.put("version_type", versionType.name().toLowerCase(Locale.ROOT));
}
}
}
if (randomBoolean()) {
String timeout = randomTimeValue();
indexRequest.timeout(timeout);
expectedParams.put("timeout", timeout);
} else {
expectedParams.put("timeout", ReplicationRequest.DEFAULT_TIMEOUT.getStringRep());
}
if (frequently()) {
if (randomBoolean()) {
String routing = randomAsciiOfLengthBetween(3, 10);
indexRequest.routing(routing);
expectedParams.put("routing", routing);
}
if (randomBoolean()) {
String parent = randomAsciiOfLengthBetween(3, 10);
indexRequest.parent(parent);
expectedParams.put("parent", parent);
}
if (randomBoolean()) {
String pipeline = randomAsciiOfLengthBetween(3, 10);
indexRequest.setPipeline(pipeline);
expectedParams.put("pipeline", pipeline);
}
if (randomBoolean()) {
WriteRequest.RefreshPolicy refreshPolicy = randomFrom(WriteRequest.RefreshPolicy.values());
indexRequest.setRefreshPolicy(refreshPolicy);
if (refreshPolicy != WriteRequest.RefreshPolicy.NONE) {
expectedParams.put("refresh", refreshPolicy.getValue());
}
}
}
XContentType xContentType = randomFrom(XContentType.values());
int nbFields = randomIntBetween(0, 10);
try (XContentBuilder builder = XContentBuilder.builder(xContentType.xContent())) {
builder.startObject();
for (int i = 0; i < nbFields; i++) {
builder.field("field_" + i, i);
}
builder.endObject();
indexRequest.source(builder);
}
Request request = Request.index(indexRequest);
if (indexRequest.opType() == DocWriteRequest.OpType.CREATE) {
assertEquals("/" + index + "/" + type + "/" + id + "/_create", request.endpoint);
} else if (id != null) {
assertEquals("/" + index + "/" + type + "/" + id, request.endpoint);
} else {
assertEquals("/" + index + "/" + type, request.endpoint);
}
assertEquals(expectedParams, request.params);
assertEquals(method, request.method);
HttpEntity entity = request.entity;
assertNotNull(entity);
assertTrue(entity instanceof ByteArrayEntity);
try (XContentParser parser = createParser(xContentType.xContent(), entity.getContent())) {
assertEquals(nbFields, parser.map().size());
}
}
public void testParams() {
final int nbParams = randomIntBetween(0, 10);
Request.Params params = Request.Params.builder();
Map<String, String> expectedParams = new HashMap<>();
for (int i = 0; i < nbParams; i++) {
String paramName = "p_" + i;
String paramValue = randomAsciiOfLength(5);
params.putParam(paramName, paramValue);
expectedParams.put(paramName, paramValue);
}
Map<String, String> requestParams = params.getParams();
assertEquals(nbParams, requestParams.size());
assertEquals(expectedParams, requestParams);
}
public void testParamsNoDuplicates() {
Request.Params params = Request.Params.builder();
params.putParam("test", "1");
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> params.putParam("test", "2"));
assertEquals("Request parameter [test] is already registered", e.getMessage());
Map<String, String> requestParams = params.getParams();
assertEquals(1L, requestParams.size());
assertEquals("1", requestParams.values().iterator().next());
}
public void testEndpoint() {
assertEquals("/", Request.endpoint());
assertEquals("/", Request.endpoint(Strings.EMPTY_ARRAY));
assertEquals("/", Request.endpoint(""));
assertEquals("/a/b", Request.endpoint("a", "b"));
assertEquals("/a/b/_create", Request.endpoint("a", "b", "_create"));
assertEquals("/a/b/c/_create", Request.endpoint("a", "b", "c", "_create"));
}
} }

View File

@ -46,7 +46,7 @@ setup:
"field collapsing": "field collapsing":
- skip: - skip:
version: " - 5.99.99" version: " - 5.2.99"
reason: this uses a new API that has been added in 5.3 reason: this uses a new API that has been added in 5.3
- do: - do:
@ -82,7 +82,7 @@ setup:
"field collapsing and from": "field collapsing and from":
- skip: - skip:
version: " - 5.99.99" version: " - 5.2.99"
reason: this uses a new API that has been added in 5.3 reason: this uses a new API that has been added in 5.3
- do: - do:
@ -107,7 +107,7 @@ setup:
"field collapsing and inner_hits": "field collapsing and inner_hits":
- skip: - skip:
version: " - 5.99.99" version: " - 5.2.99"
reason: this uses a new API that has been added in 5.3 reason: this uses a new API that has been added in 5.3
- do: - do:
@ -152,7 +152,7 @@ setup:
"field collapsing, inner_hits and maxConcurrentGroupRequests": "field collapsing, inner_hits and maxConcurrentGroupRequests":
- skip: - skip:
version: " - 5.99.99" version: " - 5.2.99"
reason: this uses a new API that has been added in 5.3 reason: this uses a new API that has been added in 5.3
- do: - do:
@ -197,7 +197,7 @@ setup:
"field collapsing and scroll": "field collapsing and scroll":
- skip: - skip:
version: " - 5.99.99" version: " - 5.2.99"
reason: this uses a new API that has been added in 5.3 reason: this uses a new API that has been added in 5.3
- do: - do:
@ -213,7 +213,7 @@ setup:
"field collapsing and search_after": "field collapsing and search_after":
- skip: - skip:
version: " - 5.99.99" version: " - 5.2.99"
reason: this uses a new API that has been added in 5.3 reason: this uses a new API that has been added in 5.3
- do: - do:
@ -230,7 +230,7 @@ setup:
"field collapsing and rescore": "field collapsing and rescore":
- skip: - skip:
version: " - 5.99.99" version: " - 5.2.99"
reason: this uses a new API that has been added in 5.3 reason: this uses a new API that has been added in 5.3
- do: - do: