From 0bd6c7f0236beb6c250c42b0cac546fcbad02670 Mon Sep 17 00:00:00 2001 From: Martijn van Groningen Date: Thu, 19 Dec 2013 18:59:41 +0100 Subject: [PATCH] Made single shards APIs fail if routing is configured to be required in the mapping. This change make single shard requests fail when no routing is specified and routing has been configured to be required in the mapping. Thi Closes #4506 --- rest-api-spec/test/create/50_parent.yaml | 2 +- rest-api-spec/test/exists/30_parent.yaml | 1 + rest-api-spec/test/get/30_parent.yaml | 2 +- rest-api-spec/test/get_source/30_parent.yaml | 2 +- rest-api-spec/test/index/50_parent.yaml | 2 +- rest-api-spec/test/update/50_parent.yaml | 2 +- .../action/RoutingMissingException.java | 6 + .../explain/TransportExplainAction.java | 6 + .../action/get/TransportGetAction.java | 6 + .../action/get/TransportMultiGetAction.java | 4 + .../action/termvector/TermVectorRequest.java | 14 +- .../TransportMultiTermVectorsAction.java | 5 + .../TransportSingleShardTermVectorAction.java | 6 + .../action/update/TransportUpdateAction.java | 6 + .../cluster/metadata/MetaData.java | 16 ++ .../elasticsearch/mget/SimpleMgetTests.java | 5 +- .../routing/AliasRoutingTests.java | 14 +- .../routing/SimpleRoutingTests.java | 169 +++++++++++++++++- 18 files changed, 248 insertions(+), 20 deletions(-) diff --git a/rest-api-spec/test/create/50_parent.yaml b/rest-api-spec/test/create/50_parent.yaml index 3600acdbbefda..e5db34e474fc8 100644 --- a/rest-api-spec/test/create/50_parent.yaml +++ b/rest-api-spec/test/create/50_parent.yaml @@ -41,7 +41,7 @@ - match: { fields._routing: "5"} - do: - catch: missing + catch: param get: index: test_1 type: test diff --git a/rest-api-spec/test/exists/30_parent.yaml b/rest-api-spec/test/exists/30_parent.yaml index 0cb1fd68d1a3a..ee7b9d6f8a6ea 100644 --- a/rest-api-spec/test/exists/30_parent.yaml +++ b/rest-api-spec/test/exists/30_parent.yaml @@ -33,6 +33,7 @@ - is_true: '' - do: + catch: param exists: index: test_1 type: test diff --git a/rest-api-spec/test/get/30_parent.yaml b/rest-api-spec/test/get/30_parent.yaml index 9d14b1b607c65..a3ad6a7e23def 100644 --- a/rest-api-spec/test/get/30_parent.yaml +++ b/rest-api-spec/test/get/30_parent.yaml @@ -33,7 +33,7 @@ - match: { fields._routing: 中文} - do: - catch: missing + catch: param get: index: test_1 type: test diff --git a/rest-api-spec/test/get_source/30_parent.yaml b/rest-api-spec/test/get_source/30_parent.yaml index e9799eb6c0527..fbd6666f1d6b5 100644 --- a/rest-api-spec/test/get_source/30_parent.yaml +++ b/rest-api-spec/test/get_source/30_parent.yaml @@ -32,7 +32,7 @@ - match: { '': {foo: bar}} - do: - catch: missing + catch: param get_source: index: test_1 type: test diff --git a/rest-api-spec/test/index/50_parent.yaml b/rest-api-spec/test/index/50_parent.yaml index 9f7edbf75cf2d..c4ec15b4c4b8e 100644 --- a/rest-api-spec/test/index/50_parent.yaml +++ b/rest-api-spec/test/index/50_parent.yaml @@ -41,7 +41,7 @@ - match: { fields._routing: "5"} - do: - catch: missing + catch: param get: index: test_1 type: test diff --git a/rest-api-spec/test/update/50_parent.yaml b/rest-api-spec/test/update/50_parent.yaml index 94cbceb5e132d..f12f98b9bfc1d 100644 --- a/rest-api-spec/test/update/50_parent.yaml +++ b/rest-api-spec/test/update/50_parent.yaml @@ -44,7 +44,7 @@ - match: { fields._routing: "5"} - do: - catch: missing + catch: param update: index: test_1 type: test diff --git a/src/main/java/org/elasticsearch/action/RoutingMissingException.java b/src/main/java/org/elasticsearch/action/RoutingMissingException.java index 117a226da8f85..c01576e4e55fa 100644 --- a/src/main/java/org/elasticsearch/action/RoutingMissingException.java +++ b/src/main/java/org/elasticsearch/action/RoutingMissingException.java @@ -20,6 +20,7 @@ package org.elasticsearch.action; import org.elasticsearch.ElasticSearchException; +import org.elasticsearch.rest.RestStatus; /** * @@ -50,4 +51,9 @@ public String type() { public String id() { return id; } + + @Override + public RestStatus status() { + return RestStatus.BAD_REQUEST; + } } diff --git a/src/main/java/org/elasticsearch/action/explain/TransportExplainAction.java b/src/main/java/org/elasticsearch/action/explain/TransportExplainAction.java index 7042e5ebbc617..8df15bf159429 100644 --- a/src/main/java/org/elasticsearch/action/explain/TransportExplainAction.java +++ b/src/main/java/org/elasticsearch/action/explain/TransportExplainAction.java @@ -23,6 +23,7 @@ import org.apache.lucene.search.Explanation; import org.elasticsearch.ElasticSearchException; import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.RoutingMissingException; import org.elasticsearch.action.support.single.shard.TransportShardSingleOperationAction; import org.elasticsearch.cache.recycler.CacheRecycler; import org.elasticsearch.cluster.ClusterService; @@ -91,6 +92,11 @@ protected void resolveRequest(ClusterState state, ExplainRequest request) { String concreteIndex = state.metaData().concreteIndex(request.index()); request.filteringAlias(state.metaData().filteringAliases(concreteIndex, request.index())); request.index(state.metaData().concreteIndex(request.index())); + + // Fail fast on the node that received the request. + if (request.routing() == null && state.getMetaData().routingRequired(request.index(), request.type())) { + throw new RoutingMissingException(request.index(), request.type(), request.id()); + } } protected ExplainResponse shardOperation(ExplainRequest request, int shardId) throws ElasticSearchException { diff --git a/src/main/java/org/elasticsearch/action/get/TransportGetAction.java b/src/main/java/org/elasticsearch/action/get/TransportGetAction.java index 2c9ee88d5c1bd..221c844d7196e 100644 --- a/src/main/java/org/elasticsearch/action/get/TransportGetAction.java +++ b/src/main/java/org/elasticsearch/action/get/TransportGetAction.java @@ -20,6 +20,7 @@ package org.elasticsearch.action.get; import org.elasticsearch.ElasticSearchException; +import org.elasticsearch.action.RoutingMissingException; import org.elasticsearch.action.support.single.shard.TransportShardSingleOperationAction; import org.elasticsearch.cluster.ClusterService; import org.elasticsearch.cluster.ClusterState; @@ -89,6 +90,11 @@ protected void resolveRequest(ClusterState state, GetRequest request) { // update the routing (request#index here is possibly an alias) request.routing(state.metaData().resolveIndexRouting(request.routing(), request.index())); request.index(state.metaData().concreteIndex(request.index())); + + // Fail fast on the node that received the request. + if (request.routing() == null && state.getMetaData().routingRequired(request.index(), request.type())) { + throw new RoutingMissingException(request.index(), request.type(), request.id()); + } } @Override diff --git a/src/main/java/org/elasticsearch/action/get/TransportMultiGetAction.java b/src/main/java/org/elasticsearch/action/get/TransportMultiGetAction.java index 8819208bfb454..cc9b5b3834433 100644 --- a/src/main/java/org/elasticsearch/action/get/TransportMultiGetAction.java +++ b/src/main/java/org/elasticsearch/action/get/TransportMultiGetAction.java @@ -68,6 +68,10 @@ protected void doExecute(final MultiGetRequest request, final ActionListener getFlags() { return flagsEnum; } + /** + * Sets the type of document to get the term vector for. + */ + public TermVectorRequest type(String type) { + this.type = type; + return this; + } + /** * Returns the type of document to get the term vector for. */ @@ -106,8 +114,9 @@ public String id() { /** * Sets the id of document the term vector is requested for. */ - public void id(String id) { + public TermVectorRequest id(String id) { this.id = id; + return this; } /** @@ -117,8 +126,9 @@ public String routing() { return routing; } - public void routing(String routing) { + public TermVectorRequest routing(String routing) { this.routing = routing; + return this; } /** diff --git a/src/main/java/org/elasticsearch/action/termvector/TransportMultiTermVectorsAction.java b/src/main/java/org/elasticsearch/action/termvector/TransportMultiTermVectorsAction.java index 4574004ab92f8..3ee828bc76523 100644 --- a/src/main/java/org/elasticsearch/action/termvector/TransportMultiTermVectorsAction.java +++ b/src/main/java/org/elasticsearch/action/termvector/TransportMultiTermVectorsAction.java @@ -71,6 +71,11 @@ protected void doExecute(final MultiTermVectorsRequest request, final ActionList termVectorRequest.type(), termVectorRequest.id(), "[" + termVectorRequest.index() + "] missing"))); continue; } + if (termVectorRequest.routing() == null && clusterState.getMetaData().routingRequired(termVectorRequest.index(), termVectorRequest.type())) { + responses.set(i, new MultiTermVectorsItemResponse(null, new MultiTermVectorsResponse.Failure(termVectorRequest.index(), + termVectorRequest.type(), termVectorRequest.id(), "routing is required, but hasn't been specified"))); + continue; + } termVectorRequest.index(clusterState.metaData().concreteIndex(termVectorRequest.index())); ShardId shardId = clusterService .operationRouting() diff --git a/src/main/java/org/elasticsearch/action/termvector/TransportSingleShardTermVectorAction.java b/src/main/java/org/elasticsearch/action/termvector/TransportSingleShardTermVectorAction.java index ebe414945b97a..8f4caab8348fd 100644 --- a/src/main/java/org/elasticsearch/action/termvector/TransportSingleShardTermVectorAction.java +++ b/src/main/java/org/elasticsearch/action/termvector/TransportSingleShardTermVectorAction.java @@ -20,6 +20,7 @@ package org.elasticsearch.action.termvector; import org.elasticsearch.ElasticSearchException; +import org.elasticsearch.action.RoutingMissingException; import org.elasticsearch.action.support.single.shard.TransportShardSingleOperationAction; import org.elasticsearch.cluster.ClusterService; import org.elasticsearch.cluster.ClusterState; @@ -80,6 +81,11 @@ protected void resolveRequest(ClusterState state, TermVectorRequest request) { // update the routing (request#index here is possibly an alias) request.routing(state.metaData().resolveIndexRouting(request.routing(), request.index())); request.index(state.metaData().concreteIndex(request.index())); + + // Fail fast on the node that received the request. + if (request.routing() == null && state.getMetaData().routingRequired(request.index(), request.type())) { + throw new RoutingMissingException(request.index(), request.type(), request.id()); + } } @Override diff --git a/src/main/java/org/elasticsearch/action/update/TransportUpdateAction.java b/src/main/java/org/elasticsearch/action/update/TransportUpdateAction.java index 754621750b6f5..d650dbfeb8488 100644 --- a/src/main/java/org/elasticsearch/action/update/TransportUpdateAction.java +++ b/src/main/java/org/elasticsearch/action/update/TransportUpdateAction.java @@ -24,6 +24,7 @@ import org.elasticsearch.ElasticSearchIllegalStateException; import org.elasticsearch.ExceptionsHelper; import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.RoutingMissingException; import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.create.CreateIndexResponse; import org.elasticsearch.action.admin.indices.create.TransportCreateIndexAction; @@ -121,6 +122,11 @@ protected boolean resolveRequest(ClusterState state, UpdateRequest request, Acti String aliasOrIndex = request.index(); request.routing((metaData.resolveIndexRouting(request.routing(), aliasOrIndex))); request.index(metaData.concreteIndex(request.index())); + + // Fail fast on the node that received the request, rather than failing when translating on the index or delete request. + if (request.routing() == null && state.getMetaData().routingRequired(request.index(), request.type())) { + throw new RoutingMissingException(request.index(), request.type(), request.id()); + } return true; } diff --git a/src/main/java/org/elasticsearch/cluster/metadata/MetaData.java b/src/main/java/org/elasticsearch/cluster/metadata/MetaData.java index c67007d911dbc..7c6ff48dec4c7 100644 --- a/src/main/java/org/elasticsearch/cluster/metadata/MetaData.java +++ b/src/main/java/org/elasticsearch/cluster/metadata/MetaData.java @@ -931,6 +931,22 @@ public boolean isPatternMatchingAllIndices(String[] indicesOrAliases, String[] c return false; } + /** + * @param concreteIndex The concrete index to check if routing is required + * @param type The type to check if routing is required + * @return Whether routing is required according to the mapping for the specified index and type + */ + public boolean routingRequired(String concreteIndex, String type) { + IndexMetaData indexMetaData = indices.get(concreteIndex); + if (indexMetaData != null) { + MappingMetaData mappingMetaData = indexMetaData.getMappings().get(type); + if (mappingMetaData != null) { + return mappingMetaData.routing().required(); + } + } + return false; + } + @Override public UnmodifiableIterator iterator() { return indices.valuesIt(); diff --git a/src/test/java/org/elasticsearch/mget/SimpleMgetTests.java b/src/test/java/org/elasticsearch/mget/SimpleMgetTests.java index b1c1e1fe2975e..5bc5f242aa3f3 100644 --- a/src/test/java/org/elasticsearch/mget/SimpleMgetTests.java +++ b/src/test/java/org/elasticsearch/mget/SimpleMgetTests.java @@ -93,8 +93,9 @@ public void testThatParentPerDocumentIsSupported() throws Exception { assertThat(mgetResponse.getResponses()[0].isFailed(), is(false)); assertThat(mgetResponse.getResponses()[0].getResponse().isExists(), is(true)); - assertThat(mgetResponse.getResponses()[1].isFailed(), is(false)); - assertThat(mgetResponse.getResponses()[1].getResponse().isExists(), is(false)); + assertThat(mgetResponse.getResponses()[1].isFailed(), is(true)); + assertThat(mgetResponse.getResponses()[1].getResponse(), nullValue()); + assertThat(mgetResponse.getResponses()[1].getFailure().getMessage(), equalTo("routing is required, but hasn't been specified")); } @SuppressWarnings("unchecked") diff --git a/src/test/java/org/elasticsearch/routing/AliasRoutingTests.java b/src/test/java/org/elasticsearch/routing/AliasRoutingTests.java index f1da8dfe9b075..c1c9d0e536ca2 100644 --- a/src/test/java/org/elasticsearch/routing/AliasRoutingTests.java +++ b/src/test/java/org/elasticsearch/routing/AliasRoutingTests.java @@ -355,7 +355,12 @@ public void testRequiredRoutingMappingWithAlias() throws Exception { logger.info("--> deleting with no routing, should broadcast the delete since _routing is required"); client().prepareDelete("test", "type1", "1").setRefresh(true).execute().actionGet(); for (int i = 0; i < 5; i++) { - assertThat(client().prepareGet("test", "type1", "1").execute().actionGet().isExists(), equalTo(false)); + try { + client().prepareGet("test", "type1", "1").get(); + assert false; + } catch (RoutingMissingException e) { + assertThat(e.getMessage(), equalTo("routing is required for [test]/[type1]/[1]")); + } assertThat(client().prepareGet("test", "type1", "1").setRouting("0").execute().actionGet().isExists(), equalTo(false)); } @@ -367,7 +372,12 @@ public void testRequiredRoutingMappingWithAlias() throws Exception { client().prepareBulk().add(Requests.deleteRequest("test").type("type1").id("1")).execute().actionGet(); client().admin().indices().prepareRefresh().execute().actionGet(); for (int i = 0; i < 5; i++) { - assertThat(client().prepareGet("test", "type1", "1").execute().actionGet().isExists(), equalTo(false)); + try { + assertThat(client().prepareGet("test", "type1", "1").execute().actionGet().isExists(), equalTo(false)); + assert false; + } catch (RoutingMissingException e) { + assertThat(e.getMessage(), equalTo("routing is required for [test]/[type1]/[1]")); + } assertThat(client().prepareGet("test", "type1", "1").setRouting("0").execute().actionGet().isExists(), equalTo(false)); } } diff --git a/src/test/java/org/elasticsearch/routing/SimpleRoutingTests.java b/src/test/java/org/elasticsearch/routing/SimpleRoutingTests.java index 441e1a98e53f1..06728c4008c64 100644 --- a/src/test/java/org/elasticsearch/routing/SimpleRoutingTests.java +++ b/src/test/java/org/elasticsearch/routing/SimpleRoutingTests.java @@ -21,17 +21,26 @@ import org.elasticsearch.ElasticSearchException; import org.elasticsearch.action.RoutingMissingException; +import org.elasticsearch.action.explain.ExplainResponse; +import org.elasticsearch.action.get.MultiGetRequest; +import org.elasticsearch.action.get.MultiGetResponse; +import org.elasticsearch.action.termvector.MultiTermVectorsResponse; +import org.elasticsearch.action.termvector.TermVectorRequest; +import org.elasticsearch.action.termvector.TermVectorResponse; +import org.elasticsearch.action.update.UpdateResponse; import org.elasticsearch.client.Requests; import org.elasticsearch.common.Priority; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.index.mapper.MapperParsingException; import org.elasticsearch.index.query.QueryBuilders; +import org.elasticsearch.rest.RestStatus; import org.elasticsearch.test.ElasticsearchIntegrationTest; import org.junit.Test; import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.nullValue; /** * @@ -173,7 +182,7 @@ public void testRequiredRoutingMapping() throws Exception { logger.info("--> indexing with id [1], and routing [0]"); client().prepareIndex("test", "type1", "1").setRouting("0").setSource("field", "value1").setRefresh(true).execute().actionGet(); - logger.info("--> verifying get with no routing, should not find anything"); + logger.info("--> verifying get with no routing, should fail"); logger.info("--> indexing with id [1], with no routing, should fail"); try { @@ -191,7 +200,13 @@ public void testRequiredRoutingMapping() throws Exception { logger.info("--> deleting with no routing, should broadcast the delete since _routing is required"); client().prepareDelete("test", "type1", "1").setRefresh(true).execute().actionGet(); for (int i = 0; i < 5; i++) { - assertThat(client().prepareGet("test", "type1", "1").execute().actionGet().isExists(), equalTo(false)); + try { + client().prepareGet("test", "type1", "1").execute().actionGet().isExists(); + assert false; + } catch (RoutingMissingException e) { + assertThat(e.status(), equalTo(RestStatus.BAD_REQUEST)); + assertThat(e.getMessage(), equalTo("routing is required for [test]/[type1]/[1]")); + } assertThat(client().prepareGet("test", "type1", "1").setRouting("0").execute().actionGet().isExists(), equalTo(false)); } @@ -203,7 +218,13 @@ public void testRequiredRoutingMapping() throws Exception { client().prepareBulk().add(Requests.deleteRequest("test").type("type1").id("1")).execute().actionGet(); client().admin().indices().prepareRefresh().execute().actionGet(); for (int i = 0; i < 5; i++) { - assertThat(client().prepareGet("test", "type1", "1").execute().actionGet().isExists(), equalTo(false)); + try { + client().prepareGet("test", "type1", "1").execute().actionGet().isExists(); + assert false; + } catch (RoutingMissingException e) { + assertThat(e.status(), equalTo(RestStatus.BAD_REQUEST)); + assertThat(e.getMessage(), equalTo("routing is required for [test]/[type1]/[1]")); + } assertThat(client().prepareGet("test", "type1", "1").setRouting("0").execute().actionGet().isExists(), equalTo(false)); } } @@ -229,9 +250,15 @@ public void testRequiredRoutingWithPathMapping() throws Exception { } - logger.info("--> verifying get with no routing, should not find anything"); + logger.info("--> verifying get with no routing, should fail"); for (int i = 0; i < 5; i++) { - assertThat(client().prepareGet("test", "type1", "1").execute().actionGet().isExists(), equalTo(false)); + try { + client().prepareGet("test", "type1", "1").execute().actionGet().isExists(); + assert false; + } catch (RoutingMissingException e) { + assertThat(e.status(), equalTo(RestStatus.BAD_REQUEST)); + assertThat(e.getMessage(), equalTo("routing is required for [test]/[type1]/[1]")); + } } logger.info("--> verifying get with routing, should find"); for (int i = 0; i < 5; i++) { @@ -253,9 +280,15 @@ public void testRequiredRoutingWithPathMappingBulk() throws Exception { client().prepareIndex("test", "type1", "1").setSource("field", "value1", "routing_field", "0")).execute().actionGet(); client().admin().indices().prepareRefresh().execute().actionGet(); - logger.info("--> verifying get with no routing, should not find anything"); + logger.info("--> verifying get with no routing, should fail"); for (int i = 0; i < 5; i++) { - assertThat(client().prepareGet("test", "type1", "1").execute().actionGet().isExists(), equalTo(false)); + try { + client().prepareGet("test", "type1", "1").execute().actionGet().isExists(); + assert false; + } catch (RoutingMissingException e) { + assertThat(e.status(), equalTo(RestStatus.BAD_REQUEST)); + assertThat(e.getMessage(), equalTo("routing is required for [test]/[type1]/[1]")); + } } logger.info("--> verifying get with routing, should find"); for (int i = 0; i < 5; i++) { @@ -277,13 +310,131 @@ public void testRequiredRoutingWithPathNumericType() throws Exception { client().prepareIndex("test", "type1", "1").setSource("field", "value1", "routing_field", 0).execute().actionGet(); client().admin().indices().prepareRefresh().execute().actionGet(); - logger.info("--> verifying get with no routing, should not find anything"); + logger.info("--> verifying get with no routing, should fail"); for (int i = 0; i < 5; i++) { - assertThat(client().prepareGet("test", "type1", "1").execute().actionGet().isExists(), equalTo(false)); + try { + client().prepareGet("test", "type1", "1").execute().actionGet().isExists(); + assert false; + } catch (RoutingMissingException e) { + assertThat(e.status(), equalTo(RestStatus.BAD_REQUEST)); + assertThat(e.getMessage(), equalTo("routing is required for [test]/[type1]/[1]")); + } } logger.info("--> verifying get with routing, should find"); for (int i = 0; i < 5; i++) { assertThat(client().prepareGet("test", "type1", "1").setRouting("0").execute().actionGet().isExists(), equalTo(true)); } } + + @Test + public void testRequiredRoutingMapping_variousAPIs() throws Exception { + client().admin().indices().prepareCreate("test") + .addMapping("type1", XContentFactory.jsonBuilder().startObject().startObject("type1").startObject("_routing").field("required", true).endObject().endObject().endObject()) + .execute().actionGet(); + client().admin().cluster().prepareHealth().setWaitForEvents(Priority.LANGUID).setWaitForGreenStatus().execute().actionGet(); + + logger.info("--> indexing with id [1], and routing [0]"); + client().prepareIndex("test", "type1", "1").setRouting("0").setSource("field", "value1").get(); + logger.info("--> indexing with id [2], and routing [0]"); + client().prepareIndex("test", "type1", "2").setRouting("0").setSource("field", "value2").setRefresh(true).get(); + + logger.info("--> verifying get with id [1] with routing [0], should succeed"); + assertThat(client().prepareGet("test", "type1", "1").setRouting("0").execute().actionGet().isExists(), equalTo(true)); + + logger.info("--> verifying get with id [1], with no routing, should fail"); + try { + client().prepareGet("test", "type1", "1").get(); + assert false; + } catch (RoutingMissingException e) { + assertThat(e.getMessage(), equalTo("routing is required for [test]/[type1]/[1]")); + } + + logger.info("--> verifying explain with id [2], with routing [0], should succeed"); + ExplainResponse explainResponse = client().prepareExplain("test", "type1", "2") + .setQuery(QueryBuilders.matchAllQuery()) + .setRouting("0").get(); + assertThat(explainResponse.isExists(), equalTo(true)); + assertThat(explainResponse.isMatch(), equalTo(true)); + + logger.info("--> verifying explain with id [2], with no routing, should fail"); + try { + client().prepareExplain("test", "type1", "2") + .setQuery(QueryBuilders.matchAllQuery()).get(); + assert false; + } catch (RoutingMissingException e) { + assertThat(e.getMessage(), equalTo("routing is required for [test]/[type1]/[2]")); + } + + logger.info("--> verifying term vector with id [1], with routing [0], should succeed"); + TermVectorResponse termVectorResponse = client().prepareTermVector("test", "type1", "1").setRouting("0").get(); + assertThat(termVectorResponse.isExists(), equalTo(true)); + assertThat(termVectorResponse.getId(), equalTo("1")); + + try { + client().prepareTermVector("test", "type1", "1").get(); + assert false; + } catch (RoutingMissingException e) { + assertThat(e.getMessage(), equalTo("routing is required for [test]/[type1]/[1]")); + } + + UpdateResponse updateResponse = client().prepareUpdate("test", "type1", "1").setRouting("0") + .setDoc("field1", "value1").get(); + assertThat(updateResponse.getId(), equalTo("1")); + assertThat(updateResponse.getVersion(), equalTo(2l)); + + try { + client().prepareUpdate("test", "type1", "1").setDoc("field1", "value1").get(); + assert false; + } catch (RoutingMissingException e) { + assertThat(e.getMessage(), equalTo("routing is required for [test]/[type1]/[1]")); + } + + logger.info("--> verifying mget with ids [1,2], with routing [0], should succeed"); + MultiGetResponse multiGetResponse = client().prepareMultiGet() + .add(new MultiGetRequest.Item("test", "type1", "1").routing("0")) + .add(new MultiGetRequest.Item("test", "type1", "2").routing("0")).get(); + assertThat(multiGetResponse.getResponses().length, equalTo(2)); + assertThat(multiGetResponse.getResponses()[0].isFailed(), equalTo(false)); + assertThat(multiGetResponse.getResponses()[0].getResponse().getId(), equalTo("1")); + assertThat(multiGetResponse.getResponses()[1].isFailed(), equalTo(false)); + assertThat(multiGetResponse.getResponses()[1].getResponse().getId(), equalTo("2")); + + logger.info("--> verifying mget with ids [1,2], with no routing, should fail"); + multiGetResponse = client().prepareMultiGet() + .add(new MultiGetRequest.Item("test", "type1", "1")) + .add(new MultiGetRequest.Item("test", "type1", "2")).get(); + assertThat(multiGetResponse.getResponses().length, equalTo(2)); + assertThat(multiGetResponse.getResponses()[0].isFailed(), equalTo(true)); + assertThat(multiGetResponse.getResponses()[0].getFailure().getId(), equalTo("1")); + assertThat(multiGetResponse.getResponses()[0].getFailure().getMessage(), equalTo("routing is required, but hasn't been specified")); + assertThat(multiGetResponse.getResponses()[1].isFailed(), equalTo(true)); + assertThat(multiGetResponse.getResponses()[1].getFailure().getId(), equalTo("2")); + assertThat(multiGetResponse.getResponses()[1].getFailure().getMessage(), equalTo("routing is required, but hasn't been specified")); + + MultiTermVectorsResponse multiTermVectorsResponse = client().prepareMultiTermVectors() + .add(new TermVectorRequest("test", "type1", "1").routing("0")) + .add(new TermVectorRequest("test", "type1", "2").routing("0")).get(); + assertThat(multiTermVectorsResponse.getResponses().length, equalTo(2)); + assertThat(multiTermVectorsResponse.getResponses()[0].getId(), equalTo("1")); + assertThat(multiTermVectorsResponse.getResponses()[0].isFailed(), equalTo(false)); + assertThat(multiTermVectorsResponse.getResponses()[0].getResponse().getId(), equalTo("1")); + assertThat(multiTermVectorsResponse.getResponses()[0].getResponse().isExists(), equalTo(true)); + assertThat(multiTermVectorsResponse.getResponses()[1].getId(), equalTo("2")); + assertThat(multiTermVectorsResponse.getResponses()[1].isFailed(), equalTo(false)); + assertThat(multiTermVectorsResponse.getResponses()[1].getResponse().getId(), equalTo("2")); + assertThat(multiTermVectorsResponse.getResponses()[1].getResponse().isExists(), equalTo(true)); + + multiTermVectorsResponse = client().prepareMultiTermVectors() + .add(new TermVectorRequest("test", "type1", "1")) + .add(new TermVectorRequest("test", "type1", "2")).get(); + assertThat(multiTermVectorsResponse.getResponses().length, equalTo(2)); + assertThat(multiTermVectorsResponse.getResponses()[0].getId(), equalTo("1")); + assertThat(multiTermVectorsResponse.getResponses()[0].isFailed(), equalTo(true)); + assertThat(multiTermVectorsResponse.getResponses()[0].getFailure().getMessage(), equalTo("routing is required, but hasn't been specified")); + assertThat(multiTermVectorsResponse.getResponses()[0].getResponse(), nullValue()); + assertThat(multiTermVectorsResponse.getResponses()[1].getId(), equalTo("2")); + assertThat(multiTermVectorsResponse.getResponses()[1].isFailed(), equalTo(true)); + assertThat(multiTermVectorsResponse.getResponses()[1].getResponse(),nullValue()); + assertThat(multiTermVectorsResponse.getResponses()[1].getFailure().getMessage(), equalTo("routing is required, but hasn't been specified")); + } }