Skip to content

Commit 94f0c82

Browse files
javannaromseygeek
andauthored
Add MapperScriptTestCase (#71322)
When we added scripts to long and double mapped fields, we added tests for the general scripting infrastructure, and also specific tests for those two field types. This commit extracts those type-specific tests out into a new base test class that we can use when adding scripts to more field mappers. Co-authored-by: Alan Woodward <[email protected]>
1 parent b462937 commit 94f0c82

File tree

8 files changed

+389
-38
lines changed

8 files changed

+389
-38
lines changed

server/src/main/java/org/elasticsearch/index/mapper/NumberFieldMapper.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,11 @@ public Builder(String name, NumberType type, ScriptCompiler compiler, boolean ig
118118

119119
this.onScriptError.requiresParameters(this.script);
120120
this.script.precludesParameters(ignoreMalformed, coerce, nullValue);
121+
this.script.setValidator(s -> {
122+
if (s != null && indexed.get() == false && hasDocValues.get() == false) {
123+
throw new MapperParsingException("Cannot define script on field with index:false and doc_values:false");
124+
}
125+
});
121126
}
122127

123128
Builder nullValue(Number number) {

server/src/main/java/org/elasticsearch/script/AbstractLongFieldScript.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ public final int count() {
6262
return count;
6363
}
6464

65-
protected final void emit(long v) {
65+
public final void emit(long v) {
6666
checkMaxSize(count);
6767
if (values.length < count + 1) {
6868
values = ArrayUtil.grow(values, count + 1);

server/src/main/java/org/elasticsearch/script/DoubleFieldScript.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,6 @@ public interface LeafFactory {
2929
DoubleFieldScript newInstance(LeafReaderContext ctx);
3030
}
3131

32-
33-
3432
private double[] values = new double[1];
3533
private int count;
3634

@@ -74,7 +72,7 @@ public final int count() {
7472
return count;
7573
}
7674

77-
protected final void emit(double v) {
75+
public final void emit(double v) {
7876
checkMaxSize(count);
7977
if (values.length < count + 1) {
8078
values = ArrayUtil.grow(values, count + 1);

server/src/test/java/org/elasticsearch/index/mapper/DoubleFieldMapperTests.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
import java.util.Arrays;
1616
import java.util.List;
1717

18+
import static org.hamcrest.Matchers.equalTo;
19+
1820
public class DoubleFieldMapperTests extends NumberFieldMapperTests {
1921

2022
@Override
@@ -53,4 +55,34 @@ protected Number randomNumber() {
5355
*/
5456
return randomBoolean() ? randomDoubleBetween(-Double.MAX_VALUE, Double.MAX_VALUE, true) : randomFloat();
5557
}
58+
59+
public void testScriptAndPrecludedParameters() {
60+
{
61+
Exception e = expectThrows(MapperParsingException.class, () -> createDocumentMapper(fieldMapping(b -> {
62+
b.field("type", "double");
63+
b.field("script", "test");
64+
b.field("coerce", "true");
65+
})));
66+
assertThat(e.getMessage(),
67+
equalTo("Failed to parse mapping [_doc]: Field [coerce] cannot be set in conjunction with field [script]"));
68+
}
69+
{
70+
Exception e = expectThrows(MapperParsingException.class, () -> createDocumentMapper(fieldMapping(b -> {
71+
b.field("type", "double");
72+
b.field("script", "test");
73+
b.field("null_value", 7);
74+
})));
75+
assertThat(e.getMessage(),
76+
equalTo("Failed to parse mapping [_doc]: Field [null_value] cannot be set in conjunction with field [script]"));
77+
}
78+
{
79+
Exception e = expectThrows(MapperParsingException.class, () -> createDocumentMapper(fieldMapping(b -> {
80+
b.field("type", "double");
81+
b.field("script", "test");
82+
b.field("ignore_malformed", "true");
83+
})));
84+
assertThat(e.getMessage(),
85+
equalTo("Failed to parse mapping [_doc]: Field [ignore_malformed] cannot be set in conjunction with field [script]"));
86+
}
87+
}
5688
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0 and the Server Side Public License, v 1; you may not use this file except
5+
* in compliance with, at your election, the Elastic License 2.0 or the Server
6+
* Side Public License, v 1.
7+
*/
8+
9+
package org.elasticsearch.index.mapper;
10+
11+
import org.apache.lucene.index.IndexableField;
12+
import org.apache.lucene.index.LeafReaderContext;
13+
import org.elasticsearch.script.DoubleFieldScript;
14+
import org.elasticsearch.search.lookup.SearchLookup;
15+
16+
import java.io.IOException;
17+
import java.util.Map;
18+
import java.util.function.Consumer;
19+
20+
public class DoubleScriptMapperTests extends MapperScriptTestCase<DoubleFieldScript.Factory> {
21+
22+
private static DoubleFieldScript.Factory factory(Consumer<DoubleFieldScript> executor) {
23+
return new DoubleFieldScript.Factory() {
24+
@Override
25+
public DoubleFieldScript.LeafFactory newFactory(String fieldName, Map<String, Object> params, SearchLookup searchLookup) {
26+
return new DoubleFieldScript.LeafFactory() {
27+
@Override
28+
public DoubleFieldScript newInstance(LeafReaderContext ctx) {
29+
return new DoubleFieldScript(fieldName, params, searchLookup, ctx) {
30+
@Override
31+
public void execute() {
32+
executor.accept(this);
33+
}
34+
};
35+
}
36+
};
37+
}
38+
};
39+
}
40+
41+
@Override
42+
protected String type() {
43+
return "double";
44+
}
45+
46+
@Override
47+
protected DoubleFieldScript.Factory serializableScript() {
48+
return factory(s -> {});
49+
}
50+
51+
@Override
52+
protected DoubleFieldScript.Factory errorThrowingScript() {
53+
return factory(s -> {
54+
throw new UnsupportedOperationException("Oops");
55+
});
56+
}
57+
58+
@Override
59+
protected DoubleFieldScript.Factory compileScript(String name) {
60+
if ("single-valued".equals(name)) {
61+
return factory(s -> s.emit(3.14));
62+
}
63+
if ("multi-valued".equals(name)) {
64+
return factory(s -> {
65+
s.emit(3.14);
66+
s.emit(2.78);
67+
});
68+
}
69+
return super.compileScript(name);
70+
}
71+
72+
public void testMultipleValues() throws IOException {
73+
DocumentMapper mapper = createDocumentMapper(fieldMapping(b -> {
74+
b.field("type", "double");
75+
b.field("script", "multi-valued");
76+
}));
77+
ParsedDocument doc = mapper.parse(source(b -> {}));
78+
IndexableField[] fields = doc.rootDoc().getFields("field");
79+
assertEquals(4, fields.length);
80+
assertEquals("DoublePoint <field:3.14>", fields[0].toString());
81+
assertEquals("docValuesType=SORTED_NUMERIC<field:4614253070214989087>", fields[1].toString());
82+
assertEquals("DoublePoint <field:2.78>", fields[2].toString());
83+
assertEquals("docValuesType=SORTED_NUMERIC<field:4613442422282062397>", fields[3].toString());
84+
}
85+
86+
public void testDocValuesDisabled() throws IOException {
87+
DocumentMapper mapper = createDocumentMapper(fieldMapping(b -> {
88+
b.field("type", "double");
89+
b.field("script", "single-valued");
90+
b.field("doc_values", false);
91+
}));
92+
ParsedDocument doc = mapper.parse(source(b -> {}));
93+
IndexableField[] fields = doc.rootDoc().getFields("field");
94+
assertEquals(1, fields.length);
95+
assertEquals("DoublePoint <field:3.14>", fields[0].toString());
96+
}
97+
98+
public void testIndexDisabled() throws IOException {
99+
DocumentMapper mapper = createDocumentMapper(fieldMapping(b -> {
100+
b.field("type", "double");
101+
b.field("script", "single-valued");
102+
b.field("index", false);
103+
}));
104+
ParsedDocument doc = mapper.parse(source(b -> {}));
105+
IndexableField[] fields = doc.rootDoc().getFields("field");
106+
assertEquals(1, fields.length);
107+
assertEquals("docValuesType=SORTED_NUMERIC<field:4614253070214989087>", fields[0].toString());
108+
}
109+
}

server/src/test/java/org/elasticsearch/index/mapper/IndexTimeScriptTests.java

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010

1111
import org.apache.lucene.index.IndexableField;
1212
import org.apache.lucene.index.LeafReaderContext;
13-
import org.elasticsearch.common.Strings;
1413
import org.elasticsearch.script.DoubleFieldScript;
1514
import org.elasticsearch.script.LongFieldScript;
1615
import org.elasticsearch.script.Script;
@@ -71,20 +70,6 @@ public void testDoublesAccess() throws IOException {
7170
assertEquals(doc.rootDoc().getField("double_field_plus_two").numericValue(), 6.5);
7271
}
7372

74-
public void testSerialization() throws IOException {
75-
DocumentMapper mapper = createDocumentMapper(mapping(b -> {
76-
b.startObject("message").field("type", "text").endObject();
77-
b.startObject("message_length");
78-
b.field("type", "long");
79-
b.field("script", "message_length");
80-
b.endObject();
81-
}));
82-
assertEquals(
83-
"{\"_doc\":{\"properties\":{\"message\":{\"type\":\"text\"}," +
84-
"\"message_length\":{\"type\":\"long\",\"script\":{\"source\":\"message_length\",\"lang\":\"painless\"}}}}}",
85-
Strings.toString(mapper.mapping()));
86-
}
87-
8873
public void testCrossReferences() throws IOException {
8974
DocumentMapper mapper = createDocumentMapper(mapping(b -> {
9075
b.startObject("message").field("type", "text").endObject();
@@ -107,25 +92,6 @@ public void testCrossReferences() throws IOException {
10792
assertEquals(doc.rootDoc().getField("message_length_plus_four").numericValue(), 21d);
10893
}
10994

110-
public void testCannotIndexDirectlyIntoScriptMapper() throws IOException {
111-
DocumentMapper mapper = createDocumentMapper(mapping(b -> {
112-
b.startObject("message").field("type", "text").endObject();
113-
b.startObject("message_length");
114-
b.field("type", "long");
115-
b.field("script", "length");
116-
b.endObject();
117-
}));
118-
119-
Exception e = expectThrows(MapperParsingException.class, () -> mapper.parse(source(b -> {
120-
b.field("message", "foo");
121-
b.field("message_length", 3);
122-
})));
123-
assertEquals("failed to parse field [message_length] of type [long] in document with id '1'. Preview of field's value: '3'",
124-
e.getMessage());
125-
Throwable original = e.getCause();
126-
assertEquals("Cannot index data directly into a field with a [script] parameter", original.getMessage());
127-
}
128-
12995
public void testLoopDetection() throws IOException {
13096
DocumentMapper mapper = createDocumentMapper(mapping(b -> {
13197
b.startObject("field1").field("type", "long").field("script", "field2_plus_two").endObject();
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0 and the Server Side Public License, v 1; you may not use this file except
5+
* in compliance with, at your election, the Elastic License 2.0 or the Server
6+
* Side Public License, v 1.
7+
*/
8+
9+
package org.elasticsearch.index.mapper;
10+
11+
import org.apache.lucene.index.IndexableField;
12+
import org.apache.lucene.index.LeafReaderContext;
13+
import org.elasticsearch.script.LongFieldScript;
14+
import org.elasticsearch.search.lookup.SearchLookup;
15+
16+
import java.io.IOException;
17+
import java.util.Map;
18+
import java.util.function.Consumer;
19+
20+
public class LongScriptMapperTests extends MapperScriptTestCase<LongFieldScript.Factory> {
21+
22+
private static LongFieldScript.Factory factory(Consumer<LongFieldScript> executor) {
23+
return new LongFieldScript.Factory() {
24+
@Override
25+
public LongFieldScript.LeafFactory newFactory(String fieldName, Map<String, Object> params, SearchLookup searchLookup) {
26+
return new LongFieldScript.LeafFactory() {
27+
@Override
28+
public LongFieldScript newInstance(LeafReaderContext ctx) {
29+
return new LongFieldScript(fieldName, params, searchLookup, ctx) {
30+
@Override
31+
public void execute() {
32+
executor.accept(this);
33+
}
34+
};
35+
}
36+
};
37+
}
38+
};
39+
}
40+
41+
@Override
42+
protected String type() {
43+
return "long";
44+
}
45+
46+
@Override
47+
protected LongFieldScript.Factory serializableScript() {
48+
return factory(s -> {});
49+
}
50+
51+
@Override
52+
protected LongFieldScript.Factory errorThrowingScript() {
53+
return factory(s -> {
54+
throw new UnsupportedOperationException("Oops");
55+
});
56+
}
57+
58+
@Override
59+
protected LongFieldScript.Factory compileScript(String name) {
60+
if ("single-valued".equals(name)) {
61+
return factory(s -> s.emit(4));
62+
}
63+
if ("multi-valued".equals(name)) {
64+
return factory(s -> {
65+
s.emit(1);
66+
s.emit(2);
67+
});
68+
}
69+
return super.compileScript(name);
70+
}
71+
72+
public void testMultipleValues() throws IOException {
73+
DocumentMapper mapper = createDocumentMapper(fieldMapping(b -> {
74+
b.field("type", "long");
75+
b.field("script", "multi-valued");
76+
}));
77+
ParsedDocument doc = mapper.parse(source(b -> {}));
78+
IndexableField[] fields = doc.rootDoc().getFields("field");
79+
assertEquals(4, fields.length);
80+
assertEquals("LongPoint <field:1>", fields[0].toString());
81+
assertEquals("docValuesType=SORTED_NUMERIC<field:1>", fields[1].toString());
82+
assertEquals("LongPoint <field:2>", fields[2].toString());
83+
assertEquals("docValuesType=SORTED_NUMERIC<field:2>", fields[3].toString());
84+
}
85+
86+
public void testDocValuesDisabled() throws IOException {
87+
DocumentMapper mapper = createDocumentMapper(fieldMapping(b -> {
88+
b.field("type", "long");
89+
b.field("script", "single-valued");
90+
b.field("doc_values", false);
91+
}));
92+
ParsedDocument doc = mapper.parse(source(b -> {}));
93+
IndexableField[] fields = doc.rootDoc().getFields("field");
94+
assertEquals(1, fields.length);
95+
assertEquals("LongPoint <field:4>", fields[0].toString());
96+
}
97+
98+
public void testIndexDisabled() throws IOException {
99+
DocumentMapper mapper = createDocumentMapper(fieldMapping(b -> {
100+
b.field("type", "long");
101+
b.field("script", "single-valued");
102+
b.field("index", false);
103+
}));
104+
ParsedDocument doc = mapper.parse(source(b -> {}));
105+
IndexableField[] fields = doc.rootDoc().getFields("field");
106+
assertEquals(1, fields.length);
107+
assertEquals("docValuesType=SORTED_NUMERIC<field:4>", fields[0].toString());
108+
}
109+
110+
}

0 commit comments

Comments
 (0)