/* * 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.script; import org.elasticsearch.ResourceNotFoundException; import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.test.AbstractSerializingTestCase; import java.io.IOException; import java.io.UncheckedIOException; import java.util.Collections; import static java.util.Collections.emptyMap; import static java.util.Collections.singletonMap; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.nullValue; public class StoredScriptTests extends AbstractSerializingTestCase<StoredScriptSource> { public void testBasicAddDelete() { StoredScriptSource source = new StoredScriptSource("lang", "code", emptyMap()); ScriptMetaData smd = ScriptMetaData.putStoredScript(null, "test", source); assertThat(smd.getStoredScript("test", null), equalTo(source)); assertThat(smd.getStoredScript("test", "lang"), equalTo(source)); smd = ScriptMetaData.deleteStoredScript(smd, "test", null); assertThat(smd.getStoredScript("test", null), nullValue()); assertThat(smd.getStoredScript("test", "lang"), nullValue()); } public void testDifferentMultiAddDelete() { StoredScriptSource source0 = new StoredScriptSource("lang0", "code0", emptyMap()); StoredScriptSource source1 = new StoredScriptSource("lang0", "code1", emptyMap()); StoredScriptSource source2 = new StoredScriptSource("lang1", "code2", singletonMap(Script.CONTENT_TYPE_OPTION, XContentType.JSON.mediaType())); ScriptMetaData smd = ScriptMetaData.putStoredScript(null, "test0", source0); smd = ScriptMetaData.putStoredScript(smd, "test1", source1); smd = ScriptMetaData.putStoredScript(smd, "test2", source2); assertThat(smd.getStoredScript("test0", null), equalTo(source0)); assertThat(smd.getStoredScript("test0", "lang0"), equalTo(source0)); assertThat(smd.getStoredScript("test1", null), equalTo(source1)); assertThat(smd.getStoredScript("test1", "lang0"), equalTo(source1)); assertThat(smd.getStoredScript("test2", null), equalTo(source2)); assertThat(smd.getStoredScript("test2", "lang1"), equalTo(source2)); assertThat(smd.getStoredScript("test3", null), nullValue()); assertThat(smd.getStoredScript("test0", "lang1"), nullValue()); assertThat(smd.getStoredScript("test2", "lang0"), nullValue()); smd = ScriptMetaData.deleteStoredScript(smd, "test0", null); assertThat(smd.getStoredScript("test0", null), nullValue()); assertThat(smd.getStoredScript("test0", "lang0"), nullValue()); assertThat(smd.getStoredScript("test1", null), equalTo(source1)); assertThat(smd.getStoredScript("test1", "lang0"), equalTo(source1)); assertThat(smd.getStoredScript("test2", null), equalTo(source2)); assertThat(smd.getStoredScript("test2", "lang1"), equalTo(source2)); assertThat(smd.getStoredScript("test3", null), nullValue()); assertThat(smd.getStoredScript("test0", "lang1"), nullValue()); assertThat(smd.getStoredScript("test2", "lang0"), nullValue()); smd = ScriptMetaData.deleteStoredScript(smd, "test2", "lang1"); assertThat(smd.getStoredScript("test0", null), nullValue()); assertThat(smd.getStoredScript("test0", "lang0"), nullValue()); assertThat(smd.getStoredScript("test1", null), equalTo(source1)); assertThat(smd.getStoredScript("test1", "lang0"), equalTo(source1)); assertThat(smd.getStoredScript("test2", null), nullValue()); assertThat(smd.getStoredScript("test2", "lang1"), nullValue()); assertThat(smd.getStoredScript("test3", null), nullValue()); assertThat(smd.getStoredScript("test0", "lang1"), nullValue()); assertThat(smd.getStoredScript("test2", "lang0"), nullValue()); smd = ScriptMetaData.deleteStoredScript(smd, "test1", "lang0"); assertThat(smd.getStoredScript("test0", null), nullValue()); assertThat(smd.getStoredScript("test0", "lang0"), nullValue()); assertThat(smd.getStoredScript("test1", null), nullValue()); assertThat(smd.getStoredScript("test1", "lang0"), nullValue()); assertThat(smd.getStoredScript("test2", null), nullValue()); assertThat(smd.getStoredScript("test2", "lang1"), nullValue()); assertThat(smd.getStoredScript("test3", null), nullValue()); assertThat(smd.getStoredScript("test0", "lang1"), nullValue()); assertThat(smd.getStoredScript("test2", "lang0"), nullValue()); } public void testSameMultiAddDelete() { StoredScriptSource source0 = new StoredScriptSource("lang0", "code0", emptyMap()); StoredScriptSource source1 = new StoredScriptSource("lang1", "code1", emptyMap()); StoredScriptSource source2 = new StoredScriptSource("lang2", "code1", emptyMap()); StoredScriptSource source3 = new StoredScriptSource("lang1", "code2", singletonMap(Script.CONTENT_TYPE_OPTION, XContentType.JSON.mediaType())); ScriptMetaData smd = ScriptMetaData.putStoredScript(null, "test0", source0); smd = ScriptMetaData.putStoredScript(smd, "test0", source1); assertWarnings("stored script [test0] already exists using a different lang [lang0]," + " the new namespace for stored scripts will only use (id) instead of (lang, id)"); smd = ScriptMetaData.putStoredScript(smd, "test3", source3); smd = ScriptMetaData.putStoredScript(smd, "test0", source2); assertWarnings("stored script [test0] already exists using a different lang [lang1]," + " the new namespace for stored scripts will only use (id) instead of (lang, id)"); assertThat(smd.getStoredScript("test0", null), equalTo(source2)); assertThat(smd.getStoredScript("test0", "lang0"), equalTo(source0)); assertThat(smd.getStoredScript("test0", "lang1"), equalTo(source1)); assertThat(smd.getStoredScript("test0", "lang2"), equalTo(source2)); assertThat(smd.getStoredScript("test3", null), equalTo(source3)); assertThat(smd.getStoredScript("test3", "lang1"), equalTo(source3)); smd = ScriptMetaData.deleteStoredScript(smd, "test0", "lang1"); assertThat(smd.getStoredScript("test0", null), equalTo(source2)); assertThat(smd.getStoredScript("test0", "lang0"), equalTo(source0)); assertThat(smd.getStoredScript("test0", "lang1"), nullValue()); assertThat(smd.getStoredScript("test0", "lang2"), equalTo(source2)); assertThat(smd.getStoredScript("test3", null), equalTo(source3)); assertThat(smd.getStoredScript("test3", "lang1"), equalTo(source3)); smd = ScriptMetaData.deleteStoredScript(smd, "test0", null); assertThat(smd.getStoredScript("test0", null), nullValue()); assertThat(smd.getStoredScript("test0", "lang0"), equalTo(source0)); assertThat(smd.getStoredScript("test0", "lang1"), nullValue()); assertThat(smd.getStoredScript("test0", "lang2"), nullValue()); assertThat(smd.getStoredScript("test3", null), equalTo(source3)); assertThat(smd.getStoredScript("test3", "lang1"), equalTo(source3)); smd = ScriptMetaData.deleteStoredScript(smd, "test3", "lang1"); assertThat(smd.getStoredScript("test0", null), nullValue()); assertThat(smd.getStoredScript("test0", "lang0"), equalTo(source0)); assertThat(smd.getStoredScript("test0", "lang1"), nullValue()); assertThat(smd.getStoredScript("test0", "lang2"), nullValue()); assertThat(smd.getStoredScript("test3", null), nullValue()); assertThat(smd.getStoredScript("test3", "lang1"), nullValue()); smd = ScriptMetaData.deleteStoredScript(smd, "test0", "lang0"); assertThat(smd.getStoredScript("test0", null), nullValue()); assertThat(smd.getStoredScript("test0", "lang0"), nullValue()); assertThat(smd.getStoredScript("test0", "lang1"), nullValue()); assertThat(smd.getStoredScript("test0", "lang2"), nullValue()); assertThat(smd.getStoredScript("test3", null), nullValue()); assertThat(smd.getStoredScript("test3", "lang1"), nullValue()); } public void testInvalidDelete() { ResourceNotFoundException rnfe = expectThrows(ResourceNotFoundException.class, () -> ScriptMetaData.deleteStoredScript(null, "test", "lang")); assertThat(rnfe.getMessage(), equalTo("stored script [test] using lang [lang] does not exist and cannot be deleted")); rnfe = expectThrows(ResourceNotFoundException.class, () -> ScriptMetaData.deleteStoredScript(null, "test", null)); assertThat(rnfe.getMessage(), equalTo("stored script [test] does not exist and cannot be deleted")); } public void testSourceParsing() throws Exception { // simple script value string try (XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON)) { builder.startObject().field("script", "code").endObject(); StoredScriptSource parsed = StoredScriptSource.parse("lang", builder.bytes(), XContentType.JSON); StoredScriptSource source = new StoredScriptSource("lang", "code", Collections.emptyMap()); assertThat(parsed, equalTo(source)); } // simple template value string try (XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON)) { builder.startObject().field("template", "code").endObject(); StoredScriptSource parsed = StoredScriptSource.parse("lang", builder.bytes(), XContentType.JSON); StoredScriptSource source = new StoredScriptSource("lang", "code", Collections.emptyMap()); assertThat(parsed, equalTo(source)); } // complex template with wrapper template object try (XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON)) { builder.startObject().field("template").startObject().field("query", "code").endObject().endObject(); String code; try (XContentBuilder cb = XContentFactory.contentBuilder(builder.contentType())) { code = cb.startObject().field("query", "code").endObject().string(); } StoredScriptSource parsed = StoredScriptSource.parse("lang", builder.bytes(), XContentType.JSON); StoredScriptSource source = new StoredScriptSource("lang", code, Collections.emptyMap()); assertThat(parsed, equalTo(source)); } // complex template with no wrapper object try (XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON)) { builder.startObject().field("query", "code").endObject(); String code; try (XContentBuilder cb = XContentFactory.contentBuilder(builder.contentType())) { code = cb.startObject().field("query", "code").endObject().string(); } StoredScriptSource parsed = StoredScriptSource.parse("lang", builder.bytes(), XContentType.JSON); StoredScriptSource source = new StoredScriptSource("lang", code, Collections.emptyMap()); assertThat(parsed, equalTo(source)); } // complex template using script as the field name try (XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON)) { builder.startObject().field("script").startObject().field("query", "code").endObject().endObject(); String code; try (XContentBuilder cb = XContentFactory.contentBuilder(builder.contentType())) { code = cb.startObject().field("query", "code").endObject().string(); } StoredScriptSource parsed = StoredScriptSource.parse("lang", builder.bytes(), XContentType.JSON); StoredScriptSource source = new StoredScriptSource("lang", code, Collections.emptyMap()); assertThat(parsed, equalTo(source)); } // complex script with script object try (XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON)) { builder.startObject().field("script").startObject().field("lang", "lang").field("code", "code").endObject().endObject(); StoredScriptSource parsed = StoredScriptSource.parse(null, builder.bytes(), XContentType.JSON); StoredScriptSource source = new StoredScriptSource("lang", "code", Collections.emptyMap()); assertThat(parsed, equalTo(source)); } // complex script with script object and empty options try (XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON)) { builder.startObject().field("script").startObject().field("lang", "lang").field("code", "code") .field("options").startObject().endObject().endObject().endObject(); StoredScriptSource parsed = StoredScriptSource.parse(null, builder.bytes(), XContentType.JSON); StoredScriptSource source = new StoredScriptSource("lang", "code", Collections.emptyMap()); assertThat(parsed, equalTo(source)); } // complex script with embedded template try (XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON)) { builder.startObject().field("script").startObject().field("lang", "lang").startObject("code").field("query", "code") .endObject().startObject("options").endObject().endObject().endObject().string(); String code; try (XContentBuilder cb = XContentFactory.contentBuilder(builder.contentType())) { code = cb.startObject().field("query", "code").endObject().string(); } StoredScriptSource parsed = StoredScriptSource.parse(null, builder.bytes(), XContentType.JSON); StoredScriptSource source = new StoredScriptSource("lang", code, Collections.singletonMap(Script.CONTENT_TYPE_OPTION, builder.contentType().mediaType())); assertThat(parsed, equalTo(source)); } } public void testSourceParsingErrors() throws Exception { // check for missing lang parameter when parsing a template try (XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON)) { builder.startObject().field("template", "code").endObject(); IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, () -> StoredScriptSource.parse(null, builder.bytes(), XContentType.JSON)); assertThat(iae.getMessage(), equalTo("unexpected stored script format")); } // check for missing lang parameter when parsing a script try (XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON)) { builder.startObject().field("script").startObject().field("code", "code").endObject().endObject(); IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, () -> StoredScriptSource.parse(null, builder.bytes(), XContentType.JSON)); assertThat(iae.getMessage(), equalTo("must specify lang for stored script")); } // check for missing code parameter when parsing a script try (XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON)) { builder.startObject().field("script").startObject().field("lang", "lang").endObject().endObject(); IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, () -> StoredScriptSource.parse(null, builder.bytes(), XContentType.JSON)); assertThat(iae.getMessage(), equalTo("must specify code for stored script")); } // check for illegal options parameter when parsing a script try (XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON)) { builder.startObject().field("script").startObject().field("lang", "lang").field("code", "code") .startObject("options").field("option", "option").endObject().endObject().endObject(); IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, () -> StoredScriptSource.parse(null, builder.bytes(), XContentType.JSON)); assertThat(iae.getMessage(), equalTo("illegal compiler options [{option=option}] specified")); } } @Override protected StoredScriptSource createTestInstance() { return new StoredScriptSource( randomAlphaOfLength(randomIntBetween(4, 32)), randomAlphaOfLength(randomIntBetween(4, 16383)), Collections.emptyMap()); } @Override protected Writeable.Reader<StoredScriptSource> instanceReader() { return StoredScriptSource::new; } @Override protected StoredScriptSource doParseInstance(XContentParser parser) { try { return StoredScriptSource.fromXContent(parser); } catch (IOException ioe) { throw new UncheckedIOException(ioe); } } }