/* * 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.action.update; import org.elasticsearch.Version; import org.elasticsearch.action.DocWriteResponse; import org.elasticsearch.action.delete.DeleteRequest; import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.action.support.replication.ReplicationRequest; import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.io.stream.Streamable; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentHelper; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.json.JsonXContent; import org.elasticsearch.env.Environment; import org.elasticsearch.index.VersionType; import org.elasticsearch.index.get.GetField; import org.elasticsearch.index.get.GetResult; import org.elasticsearch.index.shard.ShardId; import org.elasticsearch.script.MockScriptEngine; import org.elasticsearch.script.Script; import org.elasticsearch.script.ScriptContextRegistry; import org.elasticsearch.script.ScriptEngineRegistry; import org.elasticsearch.script.ScriptService; import org.elasticsearch.script.ScriptSettings; import org.elasticsearch.script.ScriptType; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.RandomObjects; import org.elasticsearch.watcher.ResourceWatcherService; import org.junit.Before; import java.io.IOException; import java.nio.file.Path; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.function.Function; import static java.util.Collections.emptyList; 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; public class UpdateRequestTests extends ESTestCase { private UpdateHelper updateHelper; @Before public void setUp() throws Exception { super.setUp(); final Path genericConfigFolder = createTempDir(); final Settings baseSettings = Settings.builder() .put(Environment.PATH_HOME_SETTING.getKey(), createTempDir().toString()) .put(Environment.PATH_CONF_SETTING.getKey(), genericConfigFolder) .build(); final Environment environment = new Environment(baseSettings); final Map<String, Function<Map<String, Object>, Object>> scripts = new HashMap<>(); scripts.put( "ctx._source.update_timestamp = ctx._now", vars -> { @SuppressWarnings("unchecked") final Map<String, Object> ctx = (Map<String, Object>) vars.get("ctx"); @SuppressWarnings("unchecked") final Map<String, Object> source = (Map<String, Object>) ctx.get("_source"); source.put("update_timestamp", ctx.get("_now")); return null; }); scripts.put( "ctx._source.body = \"foo\"", vars -> { @SuppressWarnings("unchecked") final Map<String, Object> ctx = (Map<String, Object>) vars.get("ctx"); @SuppressWarnings("unchecked") final Map<String, Object> source = (Map<String, Object>) ctx.get("_source"); source.put("body", "foo"); return null; }); scripts.put( "ctx._timestamp = ctx._now", vars -> { @SuppressWarnings("unchecked") final Map<String, Object> ctx = (Map<String, Object>) vars.get("ctx"); ctx.put("_timestamp", ctx.get("_now")); return null; }); scripts.put( "ctx.op = delete", vars -> { @SuppressWarnings("unchecked") final Map<String, Object> ctx = (Map<String, Object>) vars.get("ctx"); ctx.put("op", "delete"); return null; }); scripts.put( "ctx.op = bad", vars -> { @SuppressWarnings("unchecked") final Map<String, Object> ctx = (Map<String, Object>) vars.get("ctx"); ctx.put("op", "bad"); return null; }); scripts.put( "ctx.op = none", vars -> { @SuppressWarnings("unchecked") final Map<String, Object> ctx = (Map<String, Object>) vars.get("ctx"); ctx.put("op", "none"); return null; }); scripts.put("return", vars -> null); final ScriptContextRegistry scriptContextRegistry = new ScriptContextRegistry(emptyList()); final MockScriptEngine engine = new MockScriptEngine("mock", scripts); final ScriptEngineRegistry scriptEngineRegistry = new ScriptEngineRegistry(singletonList(engine)); final ScriptSettings scriptSettings = new ScriptSettings(scriptEngineRegistry, scriptContextRegistry); final ResourceWatcherService watcherService = new ResourceWatcherService(baseSettings, null); ScriptService scriptService = new ScriptService( baseSettings, environment, watcherService, scriptEngineRegistry, scriptContextRegistry, scriptSettings); final Settings settings = settings(Version.CURRENT).build(); updateHelper = new UpdateHelper(settings, scriptService); } public void testFromXContent() throws Exception { UpdateRequest request = new UpdateRequest("test", "type", "1"); // simple script request.fromXContent(createParser(XContentFactory.jsonBuilder() .startObject() .field("script", "script1") .endObject())); Script script = request.script(); assertThat(script, notNullValue()); assertThat(script.getIdOrCode(), equalTo("script1")); assertThat(script.getType(), equalTo(ScriptType.INLINE)); assertThat(script.getLang(), equalTo(Script.DEFAULT_SCRIPT_LANG)); Map<String, Object> params = script.getParams(); assertThat(params, equalTo(emptyMap())); // simple verbose script request.fromXContent(createParser(XContentFactory.jsonBuilder().startObject() .startObject("script").field("inline", "script1").endObject() .endObject())); script = request.script(); assertThat(script, notNullValue()); assertThat(script.getIdOrCode(), equalTo("script1")); assertThat(script.getType(), equalTo(ScriptType.INLINE)); assertThat(script.getLang(), equalTo(Script.DEFAULT_SCRIPT_LANG)); params = script.getParams(); assertThat(params, equalTo(emptyMap())); // script with params request = new UpdateRequest("test", "type", "1"); request.fromXContent(createParser(XContentFactory.jsonBuilder().startObject() .startObject("script") .field("inline", "script1") .startObject("params") .field("param1", "value1") .endObject() .endObject().endObject())); script = request.script(); assertThat(script, notNullValue()); assertThat(script.getIdOrCode(), equalTo("script1")); assertThat(script.getType(), equalTo(ScriptType.INLINE)); assertThat(script.getLang(), equalTo(Script.DEFAULT_SCRIPT_LANG)); params = script.getParams(); assertThat(params, notNullValue()); assertThat(params.size(), equalTo(1)); assertThat(params.get("param1").toString(), equalTo("value1")); request = new UpdateRequest("test", "type", "1"); request.fromXContent(createParser(XContentFactory.jsonBuilder() .startObject() .startObject("script") .startObject("params") .field("param1", "value1") .endObject() .field("inline", "script1") .endObject() .endObject())); script = request.script(); assertThat(script, notNullValue()); assertThat(script.getIdOrCode(), equalTo("script1")); assertThat(script.getType(), equalTo(ScriptType.INLINE)); assertThat(script.getLang(), equalTo(Script.DEFAULT_SCRIPT_LANG)); params = script.getParams(); assertThat(params, notNullValue()); assertThat(params.size(), equalTo(1)); assertThat(params.get("param1").toString(), equalTo("value1")); // script with params and upsert request = new UpdateRequest("test", "type", "1"); request.fromXContent(createParser(XContentFactory.jsonBuilder().startObject() .startObject("script") .startObject("params") .field("param1", "value1") .endObject() .field("inline", "script1") .endObject() .startObject("upsert") .field("field1", "value1") .startObject("compound") .field("field2", "value2") .endObject() .endObject().endObject())); script = request.script(); assertThat(script, notNullValue()); assertThat(script.getIdOrCode(), equalTo("script1")); assertThat(script.getType(), equalTo(ScriptType.INLINE)); assertThat(script.getLang(), equalTo(Script.DEFAULT_SCRIPT_LANG)); params = script.getParams(); assertThat(params, notNullValue()); assertThat(params.size(), equalTo(1)); assertThat(params.get("param1").toString(), equalTo("value1")); Map<String, Object> upsertDoc = XContentHelper.convertToMap(request.upsertRequest().source(), true, request.upsertRequest().getContentType()).v2(); assertThat(upsertDoc.get("field1").toString(), equalTo("value1")); assertThat(((Map) upsertDoc.get("compound")).get("field2").toString(), equalTo("value2")); request = new UpdateRequest("test", "type", "1"); request.fromXContent(createParser(XContentFactory.jsonBuilder().startObject() .startObject("upsert") .field("field1", "value1") .startObject("compound") .field("field2", "value2") .endObject() .endObject() .startObject("script") .startObject("params") .field("param1", "value1") .endObject() .field("inline", "script1") .endObject().endObject())); script = request.script(); assertThat(script, notNullValue()); assertThat(script.getIdOrCode(), equalTo("script1")); assertThat(script.getType(), equalTo(ScriptType.INLINE)); assertThat(script.getLang(), equalTo(Script.DEFAULT_SCRIPT_LANG)); params = script.getParams(); assertThat(params, notNullValue()); assertThat(params.size(), equalTo(1)); assertThat(params.get("param1").toString(), equalTo("value1")); upsertDoc = XContentHelper.convertToMap(request.upsertRequest().source(), true, request.upsertRequest().getContentType()).v2(); assertThat(upsertDoc.get("field1").toString(), equalTo("value1")); assertThat(((Map) upsertDoc.get("compound")).get("field2").toString(), equalTo("value2")); // script with doc request = new UpdateRequest("test", "type", "1"); request.fromXContent(createParser(XContentFactory.jsonBuilder() .startObject() .startObject("doc") .field("field1", "value1") .startObject("compound") .field("field2", "value2") .endObject() .endObject() .endObject())); Map<String, Object> doc = request.doc().sourceAsMap(); assertThat(doc.get("field1").toString(), equalTo("value1")); assertThat(((Map) doc.get("compound")).get("field2").toString(), equalTo("value2")); } // Related to issue 15338 public void testFieldsParsing() throws Exception { UpdateRequest request = new UpdateRequest("test", "type1", "1").fromXContent( createParser(JsonXContent.jsonXContent, new BytesArray("{\"doc\": {\"field1\": \"value1\"}, \"fields\": \"_source\"}"))); assertThat(request.doc().sourceAsMap().get("field1").toString(), equalTo("value1")); assertThat(request.fields(), arrayContaining("_source")); request = new UpdateRequest("test", "type2", "2").fromXContent(createParser(JsonXContent.jsonXContent, new BytesArray("{\"doc\": {\"field2\": \"value2\"}, \"fields\": [\"field1\", \"field2\"]}"))); assertThat(request.doc().sourceAsMap().get("field2").toString(), equalTo("value2")); assertThat(request.fields(), arrayContaining("field1", "field2")); } public void testFetchSourceParsing() throws Exception { UpdateRequest request = new UpdateRequest("test", "type1", "1"); request.fromXContent(createParser(XContentFactory.jsonBuilder() .startObject() .field("_source", true) .endObject())); assertThat(request.fetchSource(), notNullValue()); assertThat(request.fetchSource().includes().length, equalTo(0)); assertThat(request.fetchSource().excludes().length, equalTo(0)); assertThat(request.fetchSource().fetchSource(), equalTo(true)); request.fromXContent(createParser(XContentFactory.jsonBuilder() .startObject() .field("_source", false) .endObject())); assertThat(request.fetchSource(), notNullValue()); assertThat(request.fetchSource().includes().length, equalTo(0)); assertThat(request.fetchSource().excludes().length, equalTo(0)); assertThat(request.fetchSource().fetchSource(), equalTo(false)); request.fromXContent(createParser(XContentFactory.jsonBuilder() .startObject() .field("_source", "path.inner.*") .endObject())); assertThat(request.fetchSource(), notNullValue()); assertThat(request.fetchSource().fetchSource(), equalTo(true)); assertThat(request.fetchSource().includes().length, equalTo(1)); assertThat(request.fetchSource().excludes().length, equalTo(0)); assertThat(request.fetchSource().includes()[0], equalTo("path.inner.*")); request.fromXContent(createParser(XContentFactory.jsonBuilder() .startObject() .startObject("_source") .field("includes", "path.inner.*") .field("excludes", "another.inner.*") .endObject() .endObject())); assertThat(request.fetchSource(), notNullValue()); assertThat(request.fetchSource().fetchSource(), equalTo(true)); assertThat(request.fetchSource().includes().length, equalTo(1)); assertThat(request.fetchSource().excludes().length, equalTo(1)); assertThat(request.fetchSource().includes()[0], equalTo("path.inner.*")); assertThat(request.fetchSource().excludes()[0], equalTo("another.inner.*")); } public void testNowInScript() throws IOException { // We just upsert one document with now() using a script IndexRequest indexRequest = new IndexRequest("test", "type1", "2") .source(jsonBuilder().startObject().field("foo", "bar").endObject()); { UpdateRequest updateRequest = new UpdateRequest("test", "type1", "2") .upsert(indexRequest) .script(mockInlineScript("ctx._source.update_timestamp = ctx._now")) .scriptedUpsert(true); long nowInMillis = randomNonNegativeLong(); // We simulate that the document is not existing yet GetResult getResult = new GetResult("test", "type1", "2", 0, false, null, null); UpdateHelper.Result result = updateHelper.prepare(new ShardId("test", "_na_", 0), updateRequest, getResult, () -> nowInMillis); Streamable action = result.action(); assertThat(action, instanceOf(IndexRequest.class)); IndexRequest indexAction = (IndexRequest) action; assertEquals(nowInMillis, indexAction.sourceAsMap().get("update_timestamp")); } { UpdateRequest updateRequest = new UpdateRequest("test", "type1", "2") .upsert(indexRequest) .script(mockInlineScript("ctx._timestamp = ctx._now")) .scriptedUpsert(true); // We simulate that the document is not existing yet GetResult getResult = new GetResult("test", "type1", "2", 0, true, new BytesArray("{}"), null); UpdateHelper.Result result = updateHelper.prepare(new ShardId("test", "_na_", 0), updateRequest, getResult, () -> 42L); Streamable action = result.action(); assertThat(action, instanceOf(IndexRequest.class)); } } public void testIndexTimeout() { final GetResult getResult = new GetResult("test", "type", "1", 0, true, new BytesArray("{\"f\":\"v\"}"), null); final UpdateRequest updateRequest = new UpdateRequest("test", "type", "1") .script(mockInlineScript("return")) .timeout(randomTimeValue()); runTimeoutTest(getResult, updateRequest); } public void testDeleteTimeout() { final GetResult getResult = new GetResult("test", "type", "1", 0, true, new BytesArray("{\"f\":\"v\"}"), null); final UpdateRequest updateRequest = new UpdateRequest("test", "type", "1") .script(mockInlineScript("ctx.op = delete")) .timeout(randomTimeValue()); runTimeoutTest(getResult, updateRequest); } public void testUpsertTimeout() throws IOException { final boolean exists = randomBoolean(); final BytesReference source = exists ? new BytesArray("{\"f\":\"v\"}") : null; final GetResult getResult = new GetResult("test", "type", "1", 0, exists, source, null); final XContentBuilder sourceBuilder = jsonBuilder(); sourceBuilder.startObject(); { sourceBuilder.field("f", "v"); } sourceBuilder.endObject(); final IndexRequest upsert = new IndexRequest("test", "type", "1").source(sourceBuilder); final UpdateRequest updateRequest = new UpdateRequest("test", "type", "1") .upsert(upsert) .script(mockInlineScript("return")) .timeout(randomTimeValue()); runTimeoutTest(getResult, updateRequest); } private void runTimeoutTest(final GetResult getResult, final UpdateRequest updateRequest) { final UpdateHelper.Result result = updateHelper.prepare( new ShardId("test", "", 0), updateRequest, getResult, ESTestCase::randomNonNegativeLong); final Streamable action = result.action(); assertThat(action, instanceOf(ReplicationRequest.class)); final ReplicationRequest request = (ReplicationRequest) action; assertThat(request.timeout(), equalTo(updateRequest.timeout())); } public void testToAndFromXContent() throws IOException { UpdateRequest updateRequest = new UpdateRequest(); updateRequest.detectNoop(randomBoolean()); if (randomBoolean()) { XContentType xContentType = randomFrom(XContentType.values()); BytesReference source = RandomObjects.randomSource(random(), xContentType); updateRequest.doc(new IndexRequest().source(source, xContentType)); updateRequest.docAsUpsert(randomBoolean()); } else { ScriptType scriptType = randomFrom(ScriptType.values()); String scriptLang = (scriptType != ScriptType.STORED) ? randomAlphaOfLength(10) : null; String scriptIdOrCode = randomAlphaOfLength(10); int nbScriptParams = randomIntBetween(0, 5); Map<String, Object> scriptParams = new HashMap<>(nbScriptParams); for (int i = 0; i < nbScriptParams; i++) { scriptParams.put(randomAlphaOfLength(5), randomAlphaOfLength(5)); } updateRequest.script(new Script(scriptType, scriptLang, scriptIdOrCode, scriptParams)); updateRequest.scriptedUpsert(randomBoolean()); } if (randomBoolean()) { XContentType xContentType = randomFrom(XContentType.values()); BytesReference source = RandomObjects.randomSource(random(), xContentType); updateRequest.upsert(new IndexRequest().source(source, xContentType)); } if (randomBoolean()) { String[] fields = new String[randomIntBetween(0, 5)]; for (int i = 0; i < fields.length; i++) { fields[i] = randomAlphaOfLength(5); } updateRequest.fields(fields); } if (randomBoolean()) { if (randomBoolean()) { updateRequest.fetchSource(randomBoolean()); } else { String[] includes = new String[randomIntBetween(0, 5)]; for (int i = 0; i < includes.length; i++) { includes[i] = randomAlphaOfLength(5); } String[] excludes = new String[randomIntBetween(0, 5)]; for (int i = 0; i < excludes.length; i++) { excludes[i] = randomAlphaOfLength(5); } if (randomBoolean()) { updateRequest.fetchSource(includes, excludes); } } } XContentType xContentType = randomFrom(XContentType.values()); boolean humanReadable = randomBoolean(); BytesReference originalBytes = toShuffledXContent(updateRequest, xContentType, ToXContent.EMPTY_PARAMS, humanReadable); if (randomBoolean()) { try (XContentParser parser = createParser(xContentType.xContent(), originalBytes)) { originalBytes = shuffleXContent(parser, randomBoolean()).bytes(); } } UpdateRequest parsedUpdateRequest = new UpdateRequest(); try (XContentParser parser = createParser(xContentType.xContent(), originalBytes)) { parsedUpdateRequest.fromXContent(parser); assertNull(parser.nextToken()); } assertEquals(updateRequest.detectNoop(), parsedUpdateRequest.detectNoop()); assertEquals(updateRequest.docAsUpsert(), parsedUpdateRequest.docAsUpsert()); assertEquals(updateRequest.docAsUpsert(), parsedUpdateRequest.docAsUpsert()); assertEquals(updateRequest.script(), parsedUpdateRequest.script()); assertEquals(updateRequest.scriptedUpsert(), parsedUpdateRequest.scriptedUpsert()); assertArrayEquals(updateRequest.fields(), parsedUpdateRequest.fields()); assertEquals(updateRequest.fetchSource(), parsedUpdateRequest.fetchSource()); 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")); } public void testParentAndRoutingExtraction() throws Exception { GetResult getResult = new GetResult("test", "type", "1", 0, false, null, null); IndexRequest indexRequest = new IndexRequest("test", "type", "1"); // There is no routing and parent because the document doesn't exist assertNull(UpdateHelper.calculateRouting(getResult, null)); assertNull(UpdateHelper.calculateParent(getResult, null)); // There is no routing and parent the indexing request assertNull(UpdateHelper.calculateRouting(getResult, indexRequest)); assertNull(UpdateHelper.calculateParent(getResult, indexRequest)); // Doc exists but has no source or fields getResult = new GetResult("test", "type", "1", 0, true, null, null); // There is no routing and parent on either request assertNull(UpdateHelper.calculateRouting(getResult, indexRequest)); assertNull(UpdateHelper.calculateParent(getResult, indexRequest)); Map<String, GetField> fields = new HashMap<>(); fields.put("_parent", new GetField("_parent", Collections.singletonList("parent1"))); fields.put("_routing", new GetField("_routing", Collections.singletonList("routing1"))); // Doc exists and has the parent and routing fields getResult = new GetResult("test", "type", "1", 0, true, null, fields); // Use the get result parent and routing assertThat(UpdateHelper.calculateRouting(getResult, indexRequest), equalTo("routing1")); assertThat(UpdateHelper.calculateParent(getResult, indexRequest), equalTo("parent1")); // Index request has overriding parent and routing values indexRequest = new IndexRequest("test", "type", "1").parent("parent2").routing("routing2"); // Use the request's parent and routing assertThat(UpdateHelper.calculateRouting(getResult, indexRequest), equalTo("routing2")); assertThat(UpdateHelper.calculateParent(getResult, indexRequest), equalTo("parent2")); } @SuppressWarnings("deprecated") // VersionType.FORCE is deprecated public void testCalculateUpdateVersion() throws Exception { long randomVersion = randomIntBetween(0, 100); GetResult getResult = new GetResult("test", "type", "1", randomVersion, true, new BytesArray("{}"), null); UpdateRequest request = new UpdateRequest("test", "type1", "1"); long version = UpdateHelper.calculateUpdateVersion(request, getResult); // Use the get result's version assertThat(version, equalTo(randomVersion)); request = new UpdateRequest("test", "type1", "1").versionType(VersionType.FORCE).version(1337); version = UpdateHelper.calculateUpdateVersion(request, getResult); // Use the forced update request version assertThat(version, equalTo(1337L)); } public void testNoopDetection() throws Exception { ShardId shardId = new ShardId("test", "", 0); GetResult getResult = new GetResult("test", "type", "1", 0, true, new BytesArray("{\"body\": \"foo\"}"), null); UpdateRequest request = new UpdateRequest("test", "type1", "1").fromXContent( createParser(JsonXContent.jsonXContent, new BytesArray("{\"doc\": {\"body\": \"foo\"}}"))); UpdateHelper.Result result = updateHelper.prepareUpdateIndexRequest(shardId, request, getResult, true); assertThat(result.action(), instanceOf(UpdateResponse.class)); assertThat(result.getResponseResult(), equalTo(DocWriteResponse.Result.NOOP)); // Try again, with detectNoop turned off result = updateHelper.prepareUpdateIndexRequest(shardId, request, getResult, false); assertThat(result.action(), instanceOf(IndexRequest.class)); assertThat(result.getResponseResult(), equalTo(DocWriteResponse.Result.UPDATED)); assertThat(result.updatedSourceAsMap().get("body").toString(), equalTo("foo")); // Change the request to be a different doc request = new UpdateRequest("test", "type1", "1").fromXContent( createParser(JsonXContent.jsonXContent, new BytesArray("{\"doc\": {\"body\": \"bar\"}}"))); result = updateHelper.prepareUpdateIndexRequest(shardId, request, getResult, true); assertThat(result.action(), instanceOf(IndexRequest.class)); assertThat(result.getResponseResult(), equalTo(DocWriteResponse.Result.UPDATED)); assertThat(result.updatedSourceAsMap().get("body").toString(), equalTo("bar")); } public void testUpdateScript() throws Exception { ShardId shardId = new ShardId("test", "", 0); GetResult getResult = new GetResult("test", "type", "1", 0, true, new BytesArray("{\"body\": \"bar\"}"), null); UpdateRequest request = new UpdateRequest("test", "type1", "1") .script(mockInlineScript("ctx._source.body = \"foo\"")); UpdateHelper.Result result = updateHelper.prepareUpdateScriptRequest(shardId, request, getResult, ESTestCase::randomNonNegativeLong); assertThat(result.action(), instanceOf(IndexRequest.class)); assertThat(result.getResponseResult(), equalTo(DocWriteResponse.Result.UPDATED)); assertThat(result.updatedSourceAsMap().get("body").toString(), equalTo("foo")); // Now where the script changes the op to "delete" request = new UpdateRequest("test", "type1", "1").script(mockInlineScript("ctx.op = delete")); result = updateHelper.prepareUpdateScriptRequest(shardId, request, getResult, ESTestCase::randomNonNegativeLong); assertThat(result.action(), instanceOf(DeleteRequest.class)); assertThat(result.getResponseResult(), equalTo(DocWriteResponse.Result.DELETED)); // We treat everything else as a No-op boolean goodNoop = randomBoolean(); if (goodNoop) { request = new UpdateRequest("test", "type1", "1").script(mockInlineScript("ctx.op = none")); } else { request = new UpdateRequest("test", "type1", "1").script(mockInlineScript("ctx.op = bad")); } result = updateHelper.prepareUpdateScriptRequest(shardId, request, getResult, ESTestCase::randomNonNegativeLong); assertThat(result.action(), instanceOf(UpdateResponse.class)); assertThat(result.getResponseResult(), equalTo(DocWriteResponse.Result.NOOP)); } }