Skip to content

Commit 49b1106

Browse files
committed
Tests: Add unit test for InternalScriptedMetric
Relates to #22278
1 parent b8e2d12 commit 49b1106

File tree

3 files changed

+139
-8
lines changed

3 files changed

+139
-8
lines changed

core/src/main/java/org/elasticsearch/search/aggregations/metrics/scripted/InternalScriptedMetric.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import java.util.HashMap;
3636
import java.util.List;
3737
import java.util.Map;
38+
import java.util.Objects;
3839

3940
public class InternalScriptedMetric extends InternalAggregation implements ScriptedMetric {
4041
private final Script reduceScript;
@@ -126,4 +127,16 @@ public XContentBuilder doXContentBody(XContentBuilder builder, Params params) th
126127
return builder.field("value", aggregation());
127128
}
128129

130+
@Override
131+
protected boolean doEquals(Object obj) {
132+
InternalScriptedMetric other = (InternalScriptedMetric) obj;
133+
return Objects.equals(reduceScript, other.reduceScript) &&
134+
Objects.equals(aggregation, other.aggregation);
135+
}
136+
137+
@Override
138+
protected int doHashCode() {
139+
return Objects.hash(reduceScript, aggregation);
140+
}
141+
129142
}

core/src/test/java/org/elasticsearch/search/aggregations/InternalAggregationTestCase.java

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
2323
import org.elasticsearch.common.settings.Settings;
24+
import org.elasticsearch.script.ScriptService;
2425
import org.elasticsearch.search.SearchModule;
2526
import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator;
2627
import org.elasticsearch.test.AbstractWireSerializingTestCase;
@@ -36,9 +37,7 @@ public abstract class InternalAggregationTestCase<T extends InternalAggregation>
3637
private final NamedWriteableRegistry namedWriteableRegistry = new NamedWriteableRegistry(
3738
new SearchModule(Settings.EMPTY, false, emptyList()).getNamedWriteables());
3839

39-
protected abstract T createTestInstance(String name,
40-
List<PipelineAggregator> pipelineAggregators,
41-
Map<String, Object> metaData);
40+
protected abstract T createTestInstance(String name, List<PipelineAggregator> pipelineAggregators, Map<String, Object> metaData);
4241

4342
/** Return an instance on an unmapped field. */
4443
protected T createUnmappedInstance(String name,
@@ -57,21 +56,30 @@ public final void testReduceRandom() {
5756
inputs.add(t);
5857
toReduce.add(t);
5958
}
60-
if (randomBoolean()) {
61-
// we leave at least one in the list
62-
List<InternalAggregation> internalAggregations = randomSubsetOf(randomIntBetween(1, toReduceSize), toReduce);
63-
InternalAggregation.ReduceContext context = new InternalAggregation.ReduceContext(null, null, false);
59+
ScriptService mockScriptService = mockScriptService();
60+
if (randomBoolean() && toReduce.size() > 1) {
61+
// we leave at least the first element in the list
62+
List<InternalAggregation> internalAggregations = randomSubsetOf(randomIntBetween(1, toReduceSize - 1),
63+
toReduce.subList(1, toReduceSize));
64+
InternalAggregation.ReduceContext context = new InternalAggregation.ReduceContext(null, mockScriptService, false);
6465
@SuppressWarnings("unchecked")
6566
T reduced = (T) inputs.get(0).reduce(internalAggregations, context);
6667
toReduce.removeAll(internalAggregations);
6768
toReduce.add(reduced);
6869
}
69-
InternalAggregation.ReduceContext context = new InternalAggregation.ReduceContext(null, null, true);
70+
InternalAggregation.ReduceContext context = new InternalAggregation.ReduceContext(null, mockScriptService, true);
7071
@SuppressWarnings("unchecked")
7172
T reduced = (T) inputs.get(0).reduce(toReduce, context);
7273
assertReduced(reduced, inputs);
7374
}
7475

76+
/**
77+
* overwrite in tests that need it
78+
*/
79+
protected ScriptService mockScriptService() {
80+
return null;
81+
}
82+
7583
protected abstract void assertReduced(T reduced, List<T> inputs);
7684

7785
@Override
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.elasticsearch.search.aggregations.metrics.scripted;
21+
22+
import org.elasticsearch.ElasticsearchException;
23+
import org.elasticsearch.common.io.stream.Writeable.Reader;
24+
import org.elasticsearch.common.settings.Settings;
25+
import org.elasticsearch.env.Environment;
26+
import org.elasticsearch.script.MockScriptEngine;
27+
import org.elasticsearch.script.Script;
28+
import org.elasticsearch.script.ScriptContextRegistry;
29+
import org.elasticsearch.script.ScriptEngineRegistry;
30+
import org.elasticsearch.script.ScriptService;
31+
import org.elasticsearch.script.ScriptSettings;
32+
import org.elasticsearch.script.ScriptType;
33+
import org.elasticsearch.search.aggregations.InternalAggregationTestCase;
34+
import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator;
35+
36+
import java.io.IOException;
37+
import java.util.Collections;
38+
import java.util.HashMap;
39+
import java.util.List;
40+
import java.util.Map;
41+
42+
public class InternalScriptedMetricTests extends InternalAggregationTestCase<InternalScriptedMetric> {
43+
44+
private static final String REDUCE_SCRIPT_NAME = "reduceScript";
45+
// randomized only once so that any random test instance has the same value
46+
private boolean hasReduceScript = randomBoolean();
47+
48+
@Override
49+
protected InternalScriptedMetric createTestInstance(String name, List<PipelineAggregator> pipelineAggregators,
50+
Map<String, Object> metaData) {
51+
Map<String, Object> params = new HashMap<>();
52+
if (randomBoolean()) {
53+
params.put(randomAsciiOfLength(5), randomAsciiOfLength(5));
54+
}
55+
Script reduceScript = null;
56+
if (hasReduceScript) {
57+
reduceScript = new Script(ScriptType.INLINE, MockScriptEngine.NAME, REDUCE_SCRIPT_NAME, params);
58+
}
59+
return new InternalScriptedMetric(name, randomAsciiOfLength(5), reduceScript, pipelineAggregators, metaData);
60+
}
61+
62+
/**
63+
* Mock of the script service. The script that is run looks at the
64+
* "_aggs" parameter visible when executing the script and simply returns the count.
65+
* This should be equal to the number of input InternalScriptedMetrics that are reduced
66+
* in total.
67+
*/
68+
@Override
69+
protected ScriptService mockScriptService() {
70+
Settings settings = Settings.builder()
71+
.put(Environment.PATH_HOME_SETTING.getKey(), createTempDir())
72+
// no file watching, so we don't need a ResourceWatcherService
73+
.put(ScriptService.SCRIPT_AUTO_RELOAD_ENABLED_SETTING.getKey(), "false")
74+
.build();
75+
// mock script always retuns the size of the input aggs list as result
76+
@SuppressWarnings("unchecked")
77+
MockScriptEngine scriptEngine = new MockScriptEngine(MockScriptEngine.NAME,
78+
Collections.singletonMap(REDUCE_SCRIPT_NAME, script -> {
79+
return ((List<Object>) script.get("_aggs")).size();
80+
}));
81+
ScriptEngineRegistry scriptEngineRegistry = new ScriptEngineRegistry(Collections.singletonList(scriptEngine));
82+
ScriptContextRegistry scriptContextRegistry = new ScriptContextRegistry(Collections.emptyList());
83+
ScriptSettings scriptSettings = new ScriptSettings(scriptEngineRegistry, scriptContextRegistry);
84+
try {
85+
return new ScriptService(settings, new Environment(settings), null, scriptEngineRegistry, scriptContextRegistry,
86+
scriptSettings);
87+
} catch (IOException e) {
88+
throw new ElasticsearchException(e);
89+
}
90+
}
91+
92+
@Override
93+
protected void assertReduced(InternalScriptedMetric reduced, List<InternalScriptedMetric> inputs) {
94+
InternalScriptedMetric firstAgg = inputs.get(0);
95+
assertEquals(firstAgg.getName(), reduced.getName());
96+
assertEquals(firstAgg.pipelineAggregators(), reduced.pipelineAggregators());
97+
assertEquals(firstAgg.getMetaData(), reduced.getMetaData());
98+
if (hasReduceScript) {
99+
assertEquals(inputs.size(), reduced.aggregation());
100+
} else {
101+
assertEquals(inputs.size(), ((List<Object>) reduced.aggregation()).size());
102+
}
103+
}
104+
105+
@Override
106+
protected Reader<InternalScriptedMetric> instanceReader() {
107+
return InternalScriptedMetric::new;
108+
}
109+
110+
}

0 commit comments

Comments
 (0)