OpenSearch/src/test/java/org/elasticsearch/mget/SimpleMgetTests.java
javanna 5d987ad5e2 Internal: changed every single index operation to not replace the index within the original request
An anti-pattern that we have in our code, noticeable for java API users, is that we modify incoming requests by replacing the index or alias with the concrete index. This way not only the request has changed, but all following communications that use that request will lose the information on whether the original request was performed against an alias or an index.

Refactored the following base classes: `TransportShardReplicationOperationAction`, `TransportShardSingleOperationAction`, `TransportSingleCustomOperationAction`, `TransportInstanceSingleOperationAction` and all subclasses by introduced an InternalRequest object that contains the original request plus additional info (e.g. the concrete index). This internal request doesn't get sent over the transport but rebuilt on each node on demand (not different to what currently happens anyway, as concrete index gets set on each node). When the request becomes a shard level request, instead of using the only int shardId we serialize the ShardId that contains both concrete index name (which might then differ ffrom the original one within the request) and shard id.

Using this pattern we can move get, multi_get, explain, analyze, term_vector, multi_term_vector, index, delete, update, bulk to not replace the index name with the concrete one within the request. The index name within the original request will stay the same.

Made it also clearer within the different transport actions when the index needs to be resolved and when that's not needed (e.g. shard level request), by exposing `resolveIndex` method. Moved check block methods to parent classes as their content was always the same on every subclass.

Improved existing tests by randomly introducing the use of an alias, and verifying that the responses always contain the concrete index name and not the original one, as that's the expected behaviour.

Added backwards compatibility tests to make sure that the change is applied in a backwards compatible manner.

Closes #7223
2014-08-12 13:25:23 +02:00

176 lines
8.3 KiB
Java

/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.mget;
import org.elasticsearch.action.admin.indices.alias.Alias;
import org.elasticsearch.action.get.MultiGetItemResponse;
import org.elasticsearch.action.get.MultiGetRequest;
import org.elasticsearch.action.get.MultiGetRequestBuilder;
import org.elasticsearch.action.get.MultiGetResponse;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.search.fetch.source.FetchSourceContext;
import org.elasticsearch.test.ElasticsearchIntegrationTest;
import org.junit.Test;
import java.io.IOException;
import java.util.Map;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
import static org.hamcrest.Matchers.*;
public class SimpleMgetTests extends ElasticsearchIntegrationTest {
@Test
public void testThatMgetShouldWorkWithOneIndexMissing() throws IOException {
createIndex("test");
ensureYellow();
client().prepareIndex("test", "test", "1").setSource(jsonBuilder().startObject().field("foo", "bar").endObject()).setRefresh(true).execute().actionGet();
MultiGetResponse mgetResponse = client().prepareMultiGet()
.add(new MultiGetRequest.Item("test", "test", "1"))
.add(new MultiGetRequest.Item("nonExistingIndex", "test", "1"))
.execute().actionGet();
assertThat(mgetResponse.getResponses().length, is(2));
assertThat(mgetResponse.getResponses()[0].getIndex(), is("test"));
assertThat(mgetResponse.getResponses()[0].isFailed(), is(false));
assertThat(mgetResponse.getResponses()[1].getIndex(), is("nonExistingIndex"));
assertThat(mgetResponse.getResponses()[1].isFailed(), is(true));
assertThat(mgetResponse.getResponses()[1].getFailure().getMessage(), is("[nonExistingIndex] missing"));
mgetResponse = client().prepareMultiGet()
.add(new MultiGetRequest.Item("nonExistingIndex", "test", "1"))
.execute().actionGet();
assertThat(mgetResponse.getResponses().length, is(1));
assertThat(mgetResponse.getResponses()[0].getIndex(), is("nonExistingIndex"));
assertThat(mgetResponse.getResponses()[0].isFailed(), is(true));
assertThat(mgetResponse.getResponses()[0].getFailure().getMessage(), is("[nonExistingIndex] missing"));
}
@Test
public void testThatParentPerDocumentIsSupported() throws Exception {
assertAcked(prepareCreate("test").addAlias(new Alias("alias"))
.addMapping("test", jsonBuilder()
.startObject()
.startObject("test")
.startObject("_parent")
.field("type", "foo")
.endObject()
.endObject()
.endObject()));
ensureYellow();
client().prepareIndex("test", "test", "1").setParent("4").setRefresh(true)
.setSource(jsonBuilder().startObject().field("foo", "bar").endObject())
.execute().actionGet();
MultiGetResponse mgetResponse = client().prepareMultiGet()
.add(new MultiGetRequest.Item(indexOrAlias(), "test", "1").parent("4"))
.add(new MultiGetRequest.Item(indexOrAlias(), "test", "1"))
.execute().actionGet();
assertThat(mgetResponse.getResponses().length, is(2));
assertThat(mgetResponse.getResponses()[0].isFailed(), is(false));
assertThat(mgetResponse.getResponses()[0].getResponse().isExists(), is(true));
assertThat(mgetResponse.getResponses()[1].isFailed(), is(true));
assertThat(mgetResponse.getResponses()[1].getResponse(), nullValue());
assertThat(mgetResponse.getResponses()[1].getFailure().getMessage(), equalTo("routing is required for [test]/[test]/[1]"));
}
@SuppressWarnings("unchecked")
@Test
public void testThatSourceFilteringIsSupported() throws Exception {
assertAcked(prepareCreate("test").addAlias(new Alias("alias")));
ensureYellow();
BytesReference sourceBytesRef = jsonBuilder().startObject()
.field("field", "1", "2")
.startObject("included").field("field", "should be seen").field("hidden_field", "should not be seen").endObject()
.field("excluded", "should not be seen")
.endObject().bytes();
for (int i = 0; i < 100; i++) {
client().prepareIndex("test", "type", Integer.toString(i)).setSource(sourceBytesRef).get();
}
MultiGetRequestBuilder request = client().prepareMultiGet();
for (int i = 0; i < 100; i++) {
if (i % 2 == 0) {
request.add(new MultiGetRequest.Item(indexOrAlias(), "type", Integer.toString(i)).fetchSourceContext(new FetchSourceContext("included", "*.hidden_field")));
} else {
request.add(new MultiGetRequest.Item(indexOrAlias(), "type", Integer.toString(i)).fetchSourceContext(new FetchSourceContext(false)));
}
}
MultiGetResponse response = request.get();
assertThat(response.getResponses().length, equalTo(100));
for (int i = 0; i < 100; i++) {
MultiGetItemResponse responseItem = response.getResponses()[i];
assertThat(responseItem.getIndex(), equalTo("test"));
if (i % 2 == 0) {
Map<String, Object> source = responseItem.getResponse().getSourceAsMap();
assertThat(source.size(), equalTo(1));
assertThat(source, hasKey("included"));
assertThat(((Map<String, Object>) source.get("included")).size(), equalTo(1));
assertThat(((Map<String, Object>) source.get("included")), hasKey("field"));
} else {
assertThat(responseItem.getResponse().getSourceAsBytes(), nullValue());
}
}
}
@Test
public void testThatRoutingPerDocumentIsSupported() throws Exception {
assertAcked(prepareCreate("test").addAlias(new Alias("alias"))
.setSettings(ImmutableSettings.builder()
.put(indexSettings())
.put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, between(2, DEFAULT_MAX_NUM_SHARDS))));
ensureYellow();
client().prepareIndex("test", "test", "1").setRefresh(true).setRouting("2")
.setSource(jsonBuilder().startObject().field("foo", "bar").endObject())
.execute().actionGet();
MultiGetResponse mgetResponse = client().prepareMultiGet()
.add(new MultiGetRequest.Item(indexOrAlias(), "test", "1").routing("2"))
.add(new MultiGetRequest.Item(indexOrAlias(), "test", "1"))
.execute().actionGet();
assertThat(mgetResponse.getResponses().length, is(2));
assertThat(mgetResponse.getResponses()[0].isFailed(), is(false));
assertThat(mgetResponse.getResponses()[0].getResponse().isExists(), is(true));
assertThat(mgetResponse.getResponses()[0].getResponse().getIndex(), is("test"));
assertThat(mgetResponse.getResponses()[1].isFailed(), is(false));
assertThat(mgetResponse.getResponses()[1].getResponse().isExists(), is(false));
assertThat(mgetResponse.getResponses()[1].getResponse().getIndex(), is("test"));
}
private static String indexOrAlias() {
return randomBoolean() ? "test" : "alias";
}
}