OpenSearch/server/src/test/java/org/opensearch/script/ScriptContextInfoTests.java
Rabi Panda d1e070c92b [Rename] Fix import issues in tests. (#414)
This commit fixes the import issues in already refactored test packages.

Signed-off-by: Rabi Panda <adnapibar@gmail.com>
2021-03-21 20:56:34 -05:00

365 lines
16 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.opensearch.script;
import org.opensearch.common.bytes.BytesArray;
import org.opensearch.common.collect.Tuple;
import org.opensearch.common.xcontent.DeprecationHandler;
import org.opensearch.common.xcontent.NamedXContentRegistry;
import org.opensearch.common.xcontent.XContentBuilder;
import org.opensearch.common.xcontent.XContentFactory;
import org.opensearch.common.xcontent.XContentParser;
import org.opensearch.common.xcontent.XContentType;
import org.opensearch.script.ScriptContextInfo.ScriptMethodInfo;
import org.opensearch.script.ScriptContextInfo.ScriptMethodInfo.ParameterInfo;
import org.opensearch.test.OpenSearchTestCase;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class ScriptContextInfoTests extends OpenSearchTestCase {
public interface MinimalContext {
void execute();
}
public void testMinimalContext() {
String name = "minimal_context";
ScriptContextInfo info = new ScriptContextInfo(name, MinimalContext.class);
assertEquals(name, info.name);
assertEquals("execute", info.execute.name);
assertEquals("void", info.execute.returnType);
assertEquals(0, info.execute.parameters.size());
assertEquals(0, info.getters.size());
}
public static class PrimitiveContext {
public int execute(boolean foo, long bar, short baz, float qux) {return 0;}
public static final String[] PARAMETERS = {"foo", "bar", "baz", "qux"};
public byte getByte() {return 0x00;}
public char getChar() {return 'a';}
}
public void testPrimitiveContext() {
String name = "primitive_context";
ScriptContextInfo info = new ScriptContextInfo(name, PrimitiveContext.class);
assertEquals(name, info.name);
assertEquals("execute", info.execute.name);
assertEquals("int", info.execute.returnType);
assertEquals(4, info.execute.parameters.size());
List<Tuple<String, String>> eparams = new ArrayList<>();
eparams.add(new Tuple<>("boolean", "foo"));
eparams.add(new Tuple<>("long", "bar"));
eparams.add(new Tuple<>("short", "baz"));
eparams.add(new Tuple<>("float", "qux"));
for (int i=0; i < info.execute.parameters.size(); i++) {
assertEquals(eparams.get(i).v1(), info.execute.parameters.get(i).type);
assertEquals(eparams.get(i).v2(), info.execute.parameters.get(i).name);
}
assertEquals(2, info.getters.size());
HashMap<String,String> getters = new HashMap<String,String>() {{
put("getByte", "byte");
put("getChar", "char");
}};
for (ScriptContextInfo.ScriptMethodInfo getter: info.getters) {
assertEquals(0, getter.parameters.size());
String returnType = getters.remove(getter.name);
assertNotNull(returnType);
assertEquals(returnType, getter.returnType);
}
assertEquals(0, getters.size());
}
public static class CustomType0 {}
public static class CustomType1 {}
public static class CustomType2 {}
public static class CustomTypeContext {
public CustomType0 execute(CustomType1 custom1, CustomType2 custom2) {return new CustomType0();}
public static final String[] PARAMETERS = {"custom1", "custom2"};
public CustomType1 getCustom1() {return new CustomType1();}
public CustomType2 getCustom2() {return new CustomType2();}
}
public void testCustomTypeContext() {
String ct = "org.opensearch.script.ScriptContextInfoTests$CustomType";
String ct0 = ct + 0;
String ct1 = ct + 1;
String ct2 = ct + 2;
String name = "custom_type_context";
ScriptContextInfo info = new ScriptContextInfo(name, CustomTypeContext.class);
assertEquals(name, info.name);
assertEquals("execute", info.execute.name);
assertEquals(ct0, info.execute.returnType);
assertEquals(2, info.execute.parameters.size());
List<Tuple<String, String>> eparams = new ArrayList<>();
eparams.add(new Tuple<>(ct1, "custom1"));
eparams.add(new Tuple<>(ct2, "custom2"));
for (int i=0; i < info.execute.parameters.size(); i++) {
assertEquals(eparams.get(i).v1(), info.execute.parameters.get(i).type);
assertEquals(eparams.get(i).v2(), info.execute.parameters.get(i).name);
}
assertEquals(2, info.getters.size());
HashMap<String,String> getters = new HashMap<String,String>(){{
put("getCustom1",ct1);
put("getCustom2",ct2);
}};
for (ScriptContextInfo.ScriptMethodInfo getter: info.getters) {
assertEquals(0, getter.parameters.size());
String returnType = getters.remove(getter.name);
assertNotNull(returnType);
assertEquals(returnType, getter.returnType);
}
assertEquals(0, getters.size());
HashMap<String,String> methods = new HashMap<String,String>(){{
put("getCustom1",ct1);
put("getCustom2",ct2);
put("execute",ct0);
}};
for (ScriptContextInfo.ScriptMethodInfo method: info.methods()) {
String returnType = methods.remove(method.name);
assertNotNull(returnType);
assertEquals(returnType, method.returnType);
}
assertEquals(0, methods.size());
}
public static class TwoExecute {
public void execute(int foo) {}
public boolean execute(boolean foo) {return foo;}
public static final String[] PARAMETERS = {"foo"};
}
public void testTwoExecute() {
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () ->
new ScriptContextInfo("two_execute", TwoExecute.class));
assertEquals("Cannot have multiple [execute] methods on class [" + TwoExecute.class.getName() + "]", e.getMessage());
}
public static class NoExecute {}
public void testNoExecute() {
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () ->
new ScriptContextInfo("no_execute", NoExecute.class));
assertEquals("Could not find required method [execute] on class [" + NoExecute.class.getName() + "]", e.getMessage());
}
public static class NoParametersField {
public void execute(int foo) {}
}
public void testNoParametersField() {
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () ->
new ScriptContextInfo("no_parameters_field", NoParametersField.class));
assertEquals("Could not find field [PARAMETERS] on instance class [" + NoParametersField.class.getName() +
"] but method [execute] has [1] parameters", e.getMessage());
}
public static class BadParametersFieldType {
public void execute(int foo) {}
public static final int[] PARAMETERS = {1};
}
public void testBadParametersFieldType() {
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () ->
new ScriptContextInfo("bad_parameters_field_type", BadParametersFieldType.class));
assertEquals("Expected a constant [String[] PARAMETERS] on instance class [" + BadParametersFieldType.class.getName() +
"] for method [execute] with [1] parameters, found [int[]]", e.getMessage());
}
public static class WrongNumberOfParameters {
public void execute(int foo) {}
public static final String[] PARAMETERS = {"foo", "bar"};
}
public void testWrongNumberOfParameters() {
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () ->
new ScriptContextInfo("wrong_number_of_parameters", WrongNumberOfParameters.class));
assertEquals("Expected argument names [2] to have the same arity [1] for method [execute] of class ["
+ WrongNumberOfParameters.class.getName() + "]", e.getMessage());
}
public interface Default {
default int getDefault() {return 1;}
boolean getNonDefault1();
}
public static class GetterConditional implements Default {
public void execute() {}
public boolean getNonDefault1() {return true;}
public float getNonDefault2() {return 0.1f;}
public static long getStatic() {return 2L;}
public char getChar(char ch) { return ch;}
}
public void testGetterConditional() {
Set<ScriptMethodInfo> getters =
new ScriptContextInfo("getter_conditional", GetterConditional.class).getters;
assertEquals(2, getters.size());
HashMap<String,String> methods = new HashMap<String,String>(){{
put("getNonDefault1","boolean");
put("getNonDefault2","float");
}};
for (ScriptContextInfo.ScriptMethodInfo method: getters) {
String returnType = methods.remove(method.name);
assertNotNull(returnType);
assertEquals(returnType, method.returnType);
}
assertEquals(0, methods.size());
}
public void testParameterInfoParser() throws IOException {
XContentBuilder builder = XContentFactory.jsonBuilder();
XContentParser parser = XContentType.JSON.xContent()
.createParser(
NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION,
new BytesArray("{\"type\":\"foo\", \"name\": \"bar\"}").streamInput());
ScriptContextInfo.ScriptMethodInfo.ParameterInfo info = ScriptContextInfo.ScriptMethodInfo.ParameterInfo.fromXContent(parser);
assertEquals(new ScriptContextInfo.ScriptMethodInfo.ParameterInfo("foo", "bar"), info);
}
public void testScriptMethodInfoParser() throws IOException {
String json = "{\"name\": \"fooFunc\", \"return_type\": \"int\", \"params\": [{\"type\": \"int\", \"name\": \"fooParam\"}, " +
"{\"type\": \"java.util.Map\", \"name\": \"barParam\"}]}";
XContentParser parser = XContentType.JSON.xContent()
.createParser(
NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION,
new BytesArray(json).streamInput());
ScriptContextInfo.ScriptMethodInfo info = ScriptContextInfo.ScriptMethodInfo.fromXContent(parser);
assertEquals(new ScriptContextInfo.ScriptMethodInfo("fooFunc", "int", new ArrayList<>(
Arrays.asList(new ScriptContextInfo.ScriptMethodInfo.ParameterInfo("int", "fooParam"),
new ScriptContextInfo.ScriptMethodInfo.ParameterInfo("java.util.Map", "barParam"))
)), info);
}
public void testScriptContextInfoParser() throws IOException {
String json = "{" +
" \"name\": \"similarity\"," +
" \"methods\": [" +
" {" +
" \"name\": \"execute\"," +
" \"return_type\": \"double\"," +
" \"params\": [" +
" {" +
" \"type\": \"double\"," +
" \"name\": \"weight\"" +
" }," +
" {" +
" \"type\": \"org.opensearch.index.similarity.ScriptedSimilarity$Query\"," +
" \"name\": \"query\"" +
" }," +
" {" +
" \"type\": \"org.opensearch.index.similarity.ScriptedSimilarity$Field\"," +
" \"name\": \"field\"" +
" }," +
" {" +
" \"type\": \"org.opensearch.index.similarity.ScriptedSimilarity$Term\"," +
" \"name\": \"term\"" +
" }," +
" {" +
" \"type\": \"org.opensearch.index.similarity.ScriptedSimilarity$Doc\"," +
" \"name\": \"doc\"" +
" }" +
" ]" +
" }," +
" {" +
" \"name\": \"getParams\"," +
" \"return_type\": \"java.util.Map\"," +
" \"params\": []" +
" }," +
" {" +
" \"name\": \"getDoc\"," +
" \"return_type\": \"java.util.Map\"," +
" \"params\": []" +
" }," +
" {" +
" \"name\": \"get_score\"," +
" \"return_type\": \"double\"," +
" \"params\": []" +
" }" +
" ]" +
"}";
XContentParser parser = XContentType.JSON.xContent()
.createParser(
NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION,
new BytesArray(json).streamInput());
ScriptContextInfo parsed = ScriptContextInfo.fromXContent(parser);
ScriptContextInfo expected = new ScriptContextInfo(
"similarity",
new ScriptMethodInfo(
"execute",
"double",
Collections.unmodifiableList(Arrays.asList(
new ParameterInfo("double", "weight"),
new ParameterInfo("org.opensearch.index.similarity.ScriptedSimilarity$Query", "query"),
new ParameterInfo("org.opensearch.index.similarity.ScriptedSimilarity$Field", "field"),
new ParameterInfo("org.opensearch.index.similarity.ScriptedSimilarity$Term", "term"),
new ParameterInfo("org.opensearch.index.similarity.ScriptedSimilarity$Doc", "doc")
)
)),
Collections.unmodifiableSet(new HashSet<>(Arrays.asList(
new ScriptMethodInfo("getParams", "java.util.Map", new ArrayList<>()),
new ScriptMethodInfo("getDoc", "java.util.Map", new ArrayList<>()),
new ScriptMethodInfo("get_score", "double", new ArrayList<>())
)))
);
assertEquals(expected, parsed);
}
public void testIgnoreOtherMethodsInListConstructor() {
ScriptContextInfo constructed = new ScriptContextInfo("otherNames", Collections.unmodifiableList(Arrays.asList(
new ScriptMethodInfo("execute", "double", Collections.emptyList()),
new ScriptMethodInfo("otherName", "bool", Collections.emptyList())
)));
ScriptContextInfo expected = new ScriptContextInfo("otherNames",
new ScriptMethodInfo("execute", "double", Collections.emptyList()),
Collections.emptySet()
);
assertEquals(expected, constructed);
}
public void testNoExecuteInListConstructor() {
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () ->
new ScriptContextInfo("noExecute", Collections.unmodifiableList(Arrays.asList(
new ScriptMethodInfo("getSomeOther", "int", Collections.emptyList()),
new ScriptMethodInfo("getSome", "bool", Collections.emptyList())
))));
assertEquals("Could not find required method [execute] in [noExecute], found [getSome, getSomeOther]", e.getMessage());
}
public void testMultipleExecuteInListConstructor() {
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () ->
new ScriptContextInfo("multiexecute", Collections.unmodifiableList(Arrays.asList(
new ScriptMethodInfo("execute", "double", Collections.emptyList()),
new ScriptMethodInfo("execute", "double", Collections.unmodifiableList(Arrays.asList(
new ParameterInfo("double", "weight")
)))))));
assertEquals("Cannot have multiple [execute] methods in [multiexecute], found [2]", e.getMessage());
}
}