/*
* 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);
}
}
}