Added validation for upserd request (#24282)
The version on an update request is a syntactic sugar for get of a specific version, doc merge and a version index. This changes it to reject requests with both upsert and a version. If the upsert index request is versioned, we also reject the op.
This commit is contained in:
parent
a72db191f2
commit
a5bd2012b6
|
@ -98,6 +98,12 @@ public class UpdateRequest extends InstanceShardOperationRequest<UpdateRequest>
|
|||
@Override
|
||||
public ActionRequestValidationException validate() {
|
||||
ActionRequestValidationException validationException = super.validate();
|
||||
if (version != Versions.MATCH_ANY && upsertRequest != null) {
|
||||
validationException = addValidationError("can't provide both upsert request and a version", validationException);
|
||||
}
|
||||
if(upsertRequest != null && upsertRequest.version() != Versions.MATCH_ANY) {
|
||||
validationException = addValidationError("can't provide version in upsert request", validationException);
|
||||
}
|
||||
if (type == null) {
|
||||
validationException = addValidationError("type is missing", validationException);
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ import org.elasticsearch.test.ESTestCase;
|
|||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -255,4 +256,39 @@ public class BulkRequestTests extends ESTestCase {
|
|||
assertEquals(1, request.sourceAsMap().size());
|
||||
assertEquals("value", request.sourceAsMap().get("field"));
|
||||
}
|
||||
|
||||
public void testToValidateUpsertRequestAndVersionInBulkRequest() throws IOException {
|
||||
XContentType xContentType = XContentType.SMILE;
|
||||
BytesReference data;
|
||||
try (BytesStreamOutput out = new BytesStreamOutput()) {
|
||||
try (XContentBuilder builder = XContentFactory.contentBuilder(xContentType, out)) {
|
||||
builder.startObject();
|
||||
builder.startObject("update");
|
||||
builder.field("_index", "index");
|
||||
builder.field("_type", "type");
|
||||
builder.field("_id", "id");
|
||||
builder.field("_version", 1L);
|
||||
builder.endObject();
|
||||
builder.endObject();
|
||||
}
|
||||
out.write(xContentType.xContent().streamSeparator());
|
||||
try(XContentBuilder builder = XContentFactory.contentBuilder(xContentType, out)) {
|
||||
builder.startObject();
|
||||
builder.field("doc", "{}");
|
||||
Map<String,Object> values = new HashMap<>();
|
||||
values.put("_version", 2L);
|
||||
values.put("_index", "index");
|
||||
values.put("_type", "type");
|
||||
builder.field("upsert", values);
|
||||
builder.endObject();
|
||||
}
|
||||
out.write(xContentType.xContent().streamSeparator());
|
||||
data = out.bytes();
|
||||
}
|
||||
BulkRequest bulkRequest = new BulkRequest();
|
||||
bulkRequest.add(data, null, null, xContentType);
|
||||
assertThat(bulkRequest.validate().validationErrors(), contains("can't provide both upsert request and a version",
|
||||
"can't provide version in upsert request"));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -59,9 +59,11 @@ import static java.util.Collections.emptyMap;
|
|||
import static java.util.Collections.singletonList;
|
||||
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
||||
import static org.elasticsearch.common.xcontent.XContentHelper.toXContent;
|
||||
import static org.elasticsearch.common.xcontent.XContentHelper.update;
|
||||
import static org.elasticsearch.script.MockScriptEngine.mockInlineScript;
|
||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertToXContentEquivalent;
|
||||
import static org.hamcrest.Matchers.arrayContaining;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
|
@ -485,4 +487,19 @@ public class UpdateRequestTests extends ESTestCase {
|
|||
BytesReference finalBytes = toXContent(parsedUpdateRequest, xContentType, humanReadable);
|
||||
assertToXContentEquivalent(originalBytes, finalBytes, xContentType);
|
||||
}
|
||||
|
||||
public void testToValidateUpsertRequestAndVersion() {
|
||||
UpdateRequest updateRequest = new UpdateRequest("index", "type", "id");
|
||||
updateRequest.version(1L);
|
||||
updateRequest.doc("{}", XContentType.JSON);
|
||||
updateRequest.upsert(new IndexRequest("index","type", "id"));
|
||||
assertThat(updateRequest.validate().validationErrors(), contains("can't provide both upsert request and a version"));
|
||||
}
|
||||
|
||||
public void testToValidateUpsertRequestWithVersion() {
|
||||
UpdateRequest updateRequest = new UpdateRequest("index", "type", "id");
|
||||
updateRequest.doc("{}", XContentType.JSON);
|
||||
updateRequest.upsert(new IndexRequest("index", "type", "1").version(1L));
|
||||
assertThat(updateRequest.validate().validationErrors(), contains("can't provide version in upsert request"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -491,61 +491,7 @@ public class UpdateIT extends ESIntegTestCase {
|
|||
assertThat(updateResponse.getGetResult().sourceAsMap().get("bar").toString(), equalTo("baz"));
|
||||
assertThat(updateResponse.getGetResult().sourceAsMap().get("extra").toString(), equalTo("foo"));
|
||||
}
|
||||
|
||||
public void testVersionedUpdate() throws Exception {
|
||||
assertAcked(prepareCreate("test").addAlias(new Alias("alias")));
|
||||
ensureGreen();
|
||||
|
||||
index("test", "type", "1", "text", "value"); // version is now 1
|
||||
|
||||
assertThrows(client().prepareUpdate(indexOrAlias(), "type", "1")
|
||||
.setScript(new Script(ScriptType.INLINE, "put_values", "", Collections.singletonMap("text", "v2"))).setVersion(2)
|
||||
.execute(),
|
||||
VersionConflictEngineException.class);
|
||||
|
||||
client().prepareUpdate(indexOrAlias(), "type", "1")
|
||||
.setScript(new Script(ScriptType.INLINE, "put_values", "", Collections.singletonMap("text", "v2"))).setVersion(1).get();
|
||||
assertThat(client().prepareGet("test", "type", "1").get().getVersion(), equalTo(2L));
|
||||
|
||||
// and again with a higher version..
|
||||
client().prepareUpdate(indexOrAlias(), "type", "1")
|
||||
.setScript(new Script(ScriptType.INLINE, "put_values", "", Collections.singletonMap("text", "v3"))).setVersion(2).get();
|
||||
|
||||
assertThat(client().prepareGet("test", "type", "1").get().getVersion(), equalTo(3L));
|
||||
|
||||
// after delete
|
||||
client().prepareDelete("test", "type", "1").get();
|
||||
assertThrows(client().prepareUpdate("test", "type", "1")
|
||||
.setScript(new Script(ScriptType.INLINE, "put_values", "", Collections.singletonMap("text", "v2"))).setVersion(3)
|
||||
.execute(),
|
||||
DocumentMissingException.class);
|
||||
|
||||
// external versioning
|
||||
client().prepareIndex("test", "type", "2").setSource("text", "value").setVersion(10).setVersionType(VersionType.EXTERNAL).get();
|
||||
|
||||
assertThrows(client().prepareUpdate(indexOrAlias(), "type", "2")
|
||||
.setScript(new Script(ScriptType.INLINE, "put_values", "", Collections.singletonMap("text", "v2"))).setVersion(2)
|
||||
.setVersionType(VersionType.EXTERNAL).execute(),
|
||||
ActionRequestValidationException.class);
|
||||
|
||||
GetResponse get = get("test", "type", "2");
|
||||
assertThat(get.getVersion(), equalTo(10L));
|
||||
assertThat((String) get.getSource().get("text"), equalTo("value"));
|
||||
|
||||
// upserts - the combination with versions is a bit weird. Test are here to ensure we do not change our behavior unintentionally
|
||||
|
||||
// With internal versions, tt means "if object is there with version X, update it or explode. If it is not there, index.
|
||||
client().prepareUpdate(indexOrAlias(), "type", "3")
|
||||
.setScript(new Script(ScriptType.INLINE, "put_values", "", Collections.singletonMap("text", "v2")))
|
||||
.setVersion(10).setUpsert("{ \"text\": \"v0\" }", XContentType.JSON).get();
|
||||
get = get("test", "type", "3");
|
||||
assertThat(get.getVersion(), equalTo(1L));
|
||||
assertThat((String) get.getSource().get("text"), equalTo("v0"));
|
||||
|
||||
// retry on conflict is rejected:
|
||||
assertThrows(client().prepareUpdate(indexOrAlias(), "type", "1").setVersion(10).setRetryOnConflict(5), ActionRequestValidationException.class);
|
||||
}
|
||||
|
||||
|
||||
public void testIndexAutoCreation() throws Exception {
|
||||
UpdateResponse updateResponse = client().prepareUpdate("test", "type1", "1")
|
||||
.setUpsert(XContentFactory.jsonBuilder().startObject().field("bar", "baz").endObject())
|
||||
|
|
Loading…
Reference in New Issue