test: removed messy xpack mustache test module
The tests have been moved back to xpack, turned into a rest test or removed. For example testing specific inline, file or stored mustache template functionality is already covered in the `lang-mustache` module. The smoke-test-watcher-with-mustache should tests watcher mustach specific things like the if the watcher variables are available. Original commit: elastic/x-pack-elasticsearch@e434bcd3fa
This commit is contained in:
parent
59cb8f2271
commit
62353ff8bc
|
@ -1,11 +0,0 @@
|
||||||
|
|
||||||
/*
|
|
||||||
* Messy tests that depend on mustache directly. Fix these!
|
|
||||||
*/
|
|
||||||
|
|
||||||
apply plugin: 'elasticsearch.messy-test'
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
testCompile project(path: ':x-plugins:elasticsearch:x-pack', configuration: 'testArtifacts')
|
|
||||||
testCompile project(path: ':modules:lang-mustache', configuration: 'runtime')
|
|
||||||
}
|
|
|
@ -1,393 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
||||||
* or more contributor license agreements. Licensed under the Elastic License;
|
|
||||||
* you may not use this file except in compliance with the Elastic License.
|
|
||||||
*/
|
|
||||||
package org.elasticsearch.messy.tests;
|
|
||||||
|
|
||||||
import org.elasticsearch.action.admin.cluster.storedscripts.PutStoredScriptRequest;
|
|
||||||
import org.elasticsearch.action.search.SearchRequest;
|
|
||||||
import org.elasticsearch.action.search.SearchType;
|
|
||||||
import org.elasticsearch.common.bytes.BytesArray;
|
|
||||||
import org.elasticsearch.common.io.Streams;
|
|
||||||
import org.elasticsearch.common.settings.Settings;
|
|
||||||
import org.elasticsearch.common.unit.TimeValue;
|
|
||||||
import org.elasticsearch.common.xcontent.ToXContent;
|
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
|
||||||
import org.elasticsearch.common.xcontent.json.JsonXContent;
|
|
||||||
import org.elasticsearch.common.xcontent.support.XContentMapValues;
|
|
||||||
import org.elasticsearch.indices.query.IndicesQueriesRegistry;
|
|
||||||
import org.elasticsearch.plugins.Plugin;
|
|
||||||
import org.elasticsearch.plugins.ScriptPlugin;
|
|
||||||
import org.elasticsearch.script.ScriptContext;
|
|
||||||
import org.elasticsearch.script.ScriptService;
|
|
||||||
import org.elasticsearch.script.mustache.MustachePlugin;
|
|
||||||
import org.elasticsearch.search.aggregations.AggregatorParsers;
|
|
||||||
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
|
||||||
import org.elasticsearch.search.suggest.Suggesters;
|
|
||||||
import org.elasticsearch.test.ESIntegTestCase;
|
|
||||||
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
|
|
||||||
import org.elasticsearch.xpack.common.text.TextTemplate;
|
|
||||||
import org.elasticsearch.xpack.watcher.actions.ActionWrapper;
|
|
||||||
import org.elasticsearch.xpack.watcher.actions.ExecutableActions;
|
|
||||||
import org.elasticsearch.xpack.watcher.condition.always.ExecutableAlwaysCondition;
|
|
||||||
import org.elasticsearch.xpack.watcher.execution.TriggeredExecutionContext;
|
|
||||||
import org.elasticsearch.xpack.watcher.execution.WatchExecutionContext;
|
|
||||||
import org.elasticsearch.xpack.watcher.input.Input;
|
|
||||||
import org.elasticsearch.xpack.watcher.input.search.ExecutableSearchInput;
|
|
||||||
import org.elasticsearch.xpack.watcher.input.search.SearchInput;
|
|
||||||
import org.elasticsearch.xpack.watcher.input.search.SearchInputFactory;
|
|
||||||
import org.elasticsearch.xpack.watcher.input.simple.ExecutableSimpleInput;
|
|
||||||
import org.elasticsearch.xpack.watcher.input.simple.SimpleInput;
|
|
||||||
import org.elasticsearch.xpack.watcher.support.WatcherScript;
|
|
||||||
import org.elasticsearch.xpack.watcher.support.init.proxy.WatcherClientProxy;
|
|
||||||
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateRequest;
|
|
||||||
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateService;
|
|
||||||
import org.elasticsearch.xpack.watcher.support.xcontent.XContentSource;
|
|
||||||
import org.elasticsearch.xpack.watcher.trigger.schedule.IntervalSchedule;
|
|
||||||
import org.elasticsearch.xpack.watcher.trigger.schedule.ScheduleTrigger;
|
|
||||||
import org.elasticsearch.xpack.watcher.trigger.schedule.ScheduleTriggerEvent;
|
|
||||||
import org.elasticsearch.xpack.watcher.watch.Payload;
|
|
||||||
import org.elasticsearch.xpack.watcher.watch.Watch;
|
|
||||||
import org.elasticsearch.xpack.watcher.watch.WatchStatus;
|
|
||||||
import org.joda.time.DateTime;
|
|
||||||
import org.joda.time.chrono.ISOChronology;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import static java.util.Collections.emptyMap;
|
|
||||||
import static org.elasticsearch.common.unit.TimeValue.timeValueSeconds;
|
|
||||||
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
|
||||||
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
|
|
||||||
import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
|
|
||||||
import static org.elasticsearch.index.query.QueryBuilders.rangeQuery;
|
|
||||||
import static org.elasticsearch.search.builder.SearchSourceBuilder.searchSource;
|
|
||||||
import static org.elasticsearch.test.ESIntegTestCase.Scope.SUITE;
|
|
||||||
import static org.elasticsearch.xpack.watcher.test.WatcherTestUtils.getRandomSupportedSearchType;
|
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
|
||||||
import static org.hamcrest.Matchers.is;
|
|
||||||
import static org.joda.time.DateTimeZone.UTC;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
@ClusterScope(scope = SUITE, numClientNodes = 0, transportClientRatio = 0, randomDynamicTemplates = false, supportsDedicatedMasters = false,
|
|
||||||
numDataNodes = 1)
|
|
||||||
public class SearchInputIT extends ESIntegTestCase {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Collection<Class<? extends Plugin>> nodePlugins() {
|
|
||||||
Collection<Class<? extends Plugin>> types = new ArrayList<>();
|
|
||||||
types.addAll(super.nodePlugins());
|
|
||||||
types.add(MustachePlugin.class);
|
|
||||||
types.add(CustomScriptContextPlugin.class);
|
|
||||||
return types;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final String TEMPLATE_QUERY = "{\"query\":{\"bool\":{\"must\":{\"match\":{\"event_type\":{\"query\":\"a\"," +
|
|
||||||
"\"type\":\"boolean\"}}},\"filter\":{\"range\":{\"_timestamp\":" +
|
|
||||||
"{\"from\":\"{{ctx.trigger.scheduled_time}}||-{{seconds_param}}\",\"to\":\"{{ctx.trigger.scheduled_time}}\"," +
|
|
||||||
"\"include_lower\":true,\"include_upper\":true}}}}}}";
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Settings nodeSettings(int nodeOrdinal) {
|
|
||||||
final Path tempDir = createTempDir();
|
|
||||||
final Path configPath = tempDir.resolve("config");
|
|
||||||
final Path scriptPath = configPath.resolve("scripts");
|
|
||||||
try {
|
|
||||||
Files.createDirectories(scriptPath);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException("failed to create config dir");
|
|
||||||
|
|
||||||
}
|
|
||||||
try (InputStream stream = SearchInputIT.class.getResourceAsStream("/org/elasticsearch/xpack/watcher/input/search/config/scripts" +
|
|
||||||
"/test_disk_template.mustache");
|
|
||||||
OutputStream out = Files.newOutputStream(scriptPath.resolve("test_disk_template.mustache"))) {
|
|
||||||
Streams.copy(stream, out);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException("failed to copy mustache template");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//Set path so ScriptService will pick up the test scripts
|
|
||||||
return Settings.builder().put(super.nodeSettings(nodeOrdinal))
|
|
||||||
.put("path.conf", configPath).build();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Settings transportClientSettings() {
|
|
||||||
return Settings.builder()
|
|
||||||
.put(super.transportClientSettings())
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testExecute() throws Exception {
|
|
||||||
SearchSourceBuilder searchSourceBuilder = searchSource().query(
|
|
||||||
boolQuery().must(matchQuery("event_type", "a")).must(rangeQuery("_timestamp")
|
|
||||||
.from("{{ctx.trigger.scheduled_time}}||-30s").to("{{ctx.trigger.triggered_time}}")));
|
|
||||||
SearchRequest searchRequest = client()
|
|
||||||
.prepareSearch()
|
|
||||||
.setSearchType(ExecutableSearchInput.DEFAULT_SEARCH_TYPE)
|
|
||||||
.request()
|
|
||||||
.source(searchSourceBuilder);
|
|
||||||
|
|
||||||
WatcherSearchTemplateRequest request = new WatcherSearchTemplateRequest(searchRequest);
|
|
||||||
ExecutableSearchInput searchInput = new ExecutableSearchInput(new SearchInput(request, null, null, null), logger,
|
|
||||||
WatcherClientProxy.of(client()), watcherSearchTemplateService(), null);
|
|
||||||
WatchExecutionContext ctx = new TriggeredExecutionContext(
|
|
||||||
new Watch("test-watch",
|
|
||||||
new ScheduleTrigger(new IntervalSchedule(new IntervalSchedule.Interval(1, IntervalSchedule.Interval.Unit.MINUTES))),
|
|
||||||
new ExecutableSimpleInput(new SimpleInput(new Payload.Simple()), logger),
|
|
||||||
new ExecutableAlwaysCondition(logger),
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
new ExecutableActions(new ArrayList<ActionWrapper>()),
|
|
||||||
null,
|
|
||||||
new WatchStatus(new DateTime(0, UTC), emptyMap())),
|
|
||||||
new DateTime(0, UTC),
|
|
||||||
new ScheduleTriggerEvent("test-watch", new DateTime(0, UTC), new DateTime(0, UTC)),
|
|
||||||
timeValueSeconds(5));
|
|
||||||
SearchInput.Result result = searchInput.execute(ctx, new Payload.Simple());
|
|
||||||
|
|
||||||
assertThat(XContentMapValues.extractValue("hits.total", result.payload().data()), equalTo(0));
|
|
||||||
assertNotNull(result.executedRequest());
|
|
||||||
assertThat(result.status(), is(Input.Result.Status.SUCCESS));
|
|
||||||
assertEquals(result.executedRequest().searchType(), request.getRequest().searchType());
|
|
||||||
assertArrayEquals(result.executedRequest().indices(), request.getRequest().indices());
|
|
||||||
assertEquals(result.executedRequest().indicesOptions(), request.getRequest().indicesOptions());
|
|
||||||
|
|
||||||
XContentSource source = toXContentSource(result);
|
|
||||||
assertThat(source.getValue("query.bool.must.1.range._timestamp.from"), equalTo("1970-01-01T00:00:00.000Z||-30s"));
|
|
||||||
assertThat(source.getValue("query.bool.must.1.range._timestamp.to"), equalTo("1970-01-01T00:00:00.000Z"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testSearchInlineTemplate() throws Exception {
|
|
||||||
WatchExecutionContext ctx = createContext();
|
|
||||||
|
|
||||||
Map<String, Object> triggerParams = new HashMap<String, Object>();
|
|
||||||
triggerParams.put("triggered_time", new DateTime(1970, 01, 01, 00, 01, 00, 000, ISOChronology.getInstanceUTC()));
|
|
||||||
triggerParams.put("scheduled_time", new DateTime(1970, 01, 01, 00, 01, 00, 000, ISOChronology.getInstanceUTC()));
|
|
||||||
Map<String, Object> ctxParams = new HashMap<String, Object>();
|
|
||||||
ctxParams.put("id", ctx.id().value());
|
|
||||||
ctxParams.put("metadata", null);
|
|
||||||
ctxParams.put("vars", new HashMap<String, Object>());
|
|
||||||
ctxParams.put("watch_id", "test-watch");
|
|
||||||
ctxParams.put("trigger", triggerParams);
|
|
||||||
ctxParams.put("payload", new Payload.Simple().data());
|
|
||||||
ctxParams.put("execution_time", new DateTime(1970, 01, 01, 00, 01, 00, 000, ISOChronology.getInstanceUTC()));
|
|
||||||
Map<String, Object> expectedParams = new HashMap<String, Object>();
|
|
||||||
expectedParams.put("seconds_param", "30s");
|
|
||||||
expectedParams.put("ctx", ctxParams);
|
|
||||||
Map<String, Object> params = new HashMap<>();
|
|
||||||
params.put("seconds_param", "30s");
|
|
||||||
|
|
||||||
WatcherScript template = WatcherScript.inline(TEMPLATE_QUERY).lang("mustache").params(params).build();
|
|
||||||
|
|
||||||
SearchRequest request = client().prepareSearch()
|
|
||||||
.setSearchType(ExecutableSearchInput.DEFAULT_SEARCH_TYPE)
|
|
||||||
.setIndices("test-search-index").request();
|
|
||||||
|
|
||||||
SearchInput.Result executedResult = executeSearchInput(request, template, ctx);
|
|
||||||
|
|
||||||
assertNotNull(executedResult.executedRequest());
|
|
||||||
assertThat(executedResult.status(), is(Input.Result.Status.SUCCESS));
|
|
||||||
if (getNumShards("test-search-index").numPrimaries > 1) {
|
|
||||||
assertEquals(executedResult.executedRequest().searchType(), request.searchType());
|
|
||||||
}
|
|
||||||
assertArrayEquals(executedResult.executedRequest().indices(), request.indices());
|
|
||||||
assertEquals(executedResult.executedRequest().indicesOptions(), request.indicesOptions());
|
|
||||||
|
|
||||||
XContentSource source = toXContentSource(executedResult);
|
|
||||||
assertThat(source.getValue("query.bool.filter.0.range._timestamp.from"), equalTo("1970-01-01T00:01:00.000Z||-30s"));
|
|
||||||
assertThat(source.getValue("query.bool.filter.0.range._timestamp.to"), equalTo("1970-01-01T00:01:00.000Z"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testSearchIndexedTemplate() throws Exception {
|
|
||||||
WatchExecutionContext ctx = createContext();
|
|
||||||
|
|
||||||
PutStoredScriptRequest indexedScriptRequest = client().admin().cluster().preparePutStoredScript()
|
|
||||||
.setId("test-template")
|
|
||||||
.setScriptLang("mustache")
|
|
||||||
.setSource(new BytesArray(TEMPLATE_QUERY))
|
|
||||||
.request();
|
|
||||||
assertThat(client().admin().cluster().putStoredScript(indexedScriptRequest).actionGet().isAcknowledged(), is(true));
|
|
||||||
|
|
||||||
Map<String, Object> params = new HashMap<>();
|
|
||||||
params.put("seconds_param", "30s");
|
|
||||||
|
|
||||||
WatcherScript template = WatcherScript.indexed("test-template").lang("mustache").params(params).build();
|
|
||||||
|
|
||||||
jsonBuilder().value(TextTemplate.indexed("test-template").params(params).build()).bytes();
|
|
||||||
SearchRequest request = client().prepareSearch().setSearchType(ExecutableSearchInput.DEFAULT_SEARCH_TYPE)
|
|
||||||
.setIndices("test-search-index").request();
|
|
||||||
|
|
||||||
SearchInput.Result executedResult = executeSearchInput(request, template, ctx);
|
|
||||||
|
|
||||||
assertNotNull(executedResult.executedRequest());
|
|
||||||
assertThat(executedResult.status(), is(Input.Result.Status.SUCCESS));
|
|
||||||
if (getNumShards("test-search-index").numPrimaries > 1) {
|
|
||||||
assertEquals(executedResult.executedRequest().searchType(), request.searchType());
|
|
||||||
}
|
|
||||||
assertArrayEquals(executedResult.executedRequest().indices(), request.indices());
|
|
||||||
assertEquals(executedResult.executedRequest().indicesOptions(), request.indicesOptions());
|
|
||||||
|
|
||||||
XContentSource source = toXContentSource(executedResult);
|
|
||||||
assertThat(source.getValue("query.bool.filter.0.range._timestamp.from"), equalTo("1970-01-01T00:01:00.000Z||-30s"));
|
|
||||||
assertThat(source.getValue("query.bool.filter.0.range._timestamp.to"), equalTo("1970-01-01T00:01:00.000Z"));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testSearchOnDiskTemplate() throws Exception {
|
|
||||||
WatchExecutionContext ctx = createContext();
|
|
||||||
|
|
||||||
Map<String, Object> params = new HashMap<>();
|
|
||||||
params.put("seconds_param", "30s");
|
|
||||||
|
|
||||||
WatcherScript template = WatcherScript.file("test_disk_template").lang("mustache").params(params).build();
|
|
||||||
SearchRequest request = client().prepareSearch().setSearchType(ExecutableSearchInput.DEFAULT_SEARCH_TYPE)
|
|
||||||
.setIndices("test-search-index").request();
|
|
||||||
|
|
||||||
SearchInput.Result executedResult = executeSearchInput(request, template, ctx);
|
|
||||||
|
|
||||||
assertNotNull(executedResult.executedRequest());
|
|
||||||
assertThat(executedResult.status(), is(Input.Result.Status.SUCCESS));
|
|
||||||
assertArrayEquals(executedResult.executedRequest().indices(), request.indices());
|
|
||||||
assertEquals(executedResult.executedRequest().indicesOptions(), request.indicesOptions());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testDifferentSearchType() throws Exception {
|
|
||||||
SearchSourceBuilder searchSourceBuilder = searchSource().query(
|
|
||||||
boolQuery().must(matchQuery("event_type", "a")).must(rangeQuery("_timestamp")
|
|
||||||
.from("{{ctx.trigger.scheduled_time}}||-30s").to("{{ctx.trigger.triggered_time}}"))
|
|
||||||
);
|
|
||||||
SearchType searchType = getRandomSupportedSearchType();
|
|
||||||
|
|
||||||
SearchRequest searchRequest = client()
|
|
||||||
.prepareSearch()
|
|
||||||
.setSearchType(searchType)
|
|
||||||
.request()
|
|
||||||
.source(searchSourceBuilder);
|
|
||||||
|
|
||||||
WatcherSearchTemplateRequest request = new WatcherSearchTemplateRequest(searchRequest);
|
|
||||||
|
|
||||||
ExecutableSearchInput searchInput = new ExecutableSearchInput(new SearchInput(request, null, null, null), logger,
|
|
||||||
WatcherClientProxy.of(client()), watcherSearchTemplateService(), null);
|
|
||||||
WatchExecutionContext ctx = new TriggeredExecutionContext(
|
|
||||||
new Watch("test-watch",
|
|
||||||
new ScheduleTrigger(new IntervalSchedule(new IntervalSchedule.Interval(1, IntervalSchedule.Interval.Unit.MINUTES))),
|
|
||||||
new ExecutableSimpleInput(new SimpleInput(new Payload.Simple()), logger),
|
|
||||||
new ExecutableAlwaysCondition(logger),
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
new ExecutableActions(new ArrayList<ActionWrapper>()),
|
|
||||||
null,
|
|
||||||
new WatchStatus(new DateTime(0, UTC), emptyMap())),
|
|
||||||
new DateTime(0, UTC),
|
|
||||||
new ScheduleTriggerEvent("test-watch", new DateTime(0, UTC), new DateTime(0, UTC)),
|
|
||||||
timeValueSeconds(5));
|
|
||||||
SearchInput.Result result = searchInput.execute(ctx, new Payload.Simple());
|
|
||||||
|
|
||||||
assertThat(XContentMapValues.extractValue("hits.total", result.payload().data()), equalTo(0));
|
|
||||||
assertNotNull(result.executedRequest());
|
|
||||||
assertThat(result.status(), is(Input.Result.Status.SUCCESS));
|
|
||||||
assertEquals(result.executedRequest().searchType(), searchType);
|
|
||||||
assertArrayEquals(result.executedRequest().indices(), searchRequest.indices());
|
|
||||||
assertEquals(result.executedRequest().indicesOptions(), searchRequest.indicesOptions());
|
|
||||||
|
|
||||||
XContentSource source = toXContentSource(result);
|
|
||||||
assertThat(source.getValue("query.bool.must.1.range._timestamp.from"), equalTo("1970-01-01T00:00:00.000Z||-30s"));
|
|
||||||
assertThat(source.getValue("query.bool.must.1.range._timestamp.to"), equalTo("1970-01-01T00:00:00.000Z"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testParserValid() throws Exception {
|
|
||||||
SearchRequest searchRequest = client().prepareSearch()
|
|
||||||
.setSearchType(ExecutableSearchInput.DEFAULT_SEARCH_TYPE)
|
|
||||||
.request()
|
|
||||||
.source(searchSource()
|
|
||||||
.query(boolQuery().must(matchQuery("event_type", "a")).must(rangeQuery("_timestamp")
|
|
||||||
.from("{{ctx.trigger.scheduled_time}}||-30s").to("{{ctx.trigger.triggered_time}}"))));
|
|
||||||
|
|
||||||
TimeValue timeout = randomBoolean() ? TimeValue.timeValueSeconds(randomInt(10)) : null;
|
|
||||||
XContentBuilder builder = jsonBuilder().value(
|
|
||||||
new SearchInput(new WatcherSearchTemplateRequest(searchRequest), null, timeout, null));
|
|
||||||
XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes());
|
|
||||||
parser.nextToken();
|
|
||||||
|
|
||||||
IndicesQueriesRegistry indicesQueryRegistry = internalCluster().getInstance(IndicesQueriesRegistry.class);
|
|
||||||
SearchInputFactory factory = new SearchInputFactory(Settings.EMPTY, WatcherClientProxy.of(client()), indicesQueryRegistry,
|
|
||||||
null, null, scriptService());
|
|
||||||
|
|
||||||
SearchInput searchInput = factory.parseInput("_id", parser);
|
|
||||||
assertEquals(SearchInput.TYPE, searchInput.type());
|
|
||||||
assertThat(searchInput.getTimeout(), equalTo(timeout));
|
|
||||||
}
|
|
||||||
|
|
||||||
private WatchExecutionContext createContext() {
|
|
||||||
return new TriggeredExecutionContext(
|
|
||||||
new Watch("test-watch",
|
|
||||||
new ScheduleTrigger(new IntervalSchedule(new IntervalSchedule.Interval(1, IntervalSchedule.Interval.Unit.MINUTES))),
|
|
||||||
new ExecutableSimpleInput(new SimpleInput(new Payload.Simple()), logger),
|
|
||||||
new ExecutableAlwaysCondition(logger),
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
new ExecutableActions(new ArrayList<ActionWrapper>()),
|
|
||||||
null,
|
|
||||||
new WatchStatus(new DateTime(50000, UTC), emptyMap())),
|
|
||||||
new DateTime(60000, UTC),
|
|
||||||
new ScheduleTriggerEvent("test-watch", new DateTime(60000, UTC), new DateTime(60000, UTC)),
|
|
||||||
timeValueSeconds(5));
|
|
||||||
}
|
|
||||||
|
|
||||||
private SearchInput.Result executeSearchInput(SearchRequest request, WatcherScript template,
|
|
||||||
WatchExecutionContext ctx) throws IOException {
|
|
||||||
createIndex("test-search-index");
|
|
||||||
ensureGreen("test-search-index");
|
|
||||||
SearchInput.Builder siBuilder = SearchInput.builder(new WatcherSearchTemplateRequest(request, template));
|
|
||||||
|
|
||||||
SearchInput si = siBuilder.build();
|
|
||||||
|
|
||||||
ExecutableSearchInput searchInput = new ExecutableSearchInput(si, logger, WatcherClientProxy.of(client()),
|
|
||||||
watcherSearchTemplateService(), null);
|
|
||||||
return searchInput.execute(ctx, new Payload.Simple());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected WatcherSearchTemplateService watcherSearchTemplateService() {
|
|
||||||
String master = internalCluster().getMasterName();
|
|
||||||
return new WatcherSearchTemplateService(internalCluster().clusterService(master).getSettings(),
|
|
||||||
internalCluster().getInstance(ScriptService.class, master),
|
|
||||||
internalCluster().getInstance(IndicesQueriesRegistry.class, master),
|
|
||||||
internalCluster().getInstance(AggregatorParsers.class, master),
|
|
||||||
internalCluster().getInstance(Suggesters.class, master)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected ScriptService scriptService() {
|
|
||||||
return internalCluster().getInstance(ScriptService.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
private XContentSource toXContentSource(SearchInput.Result result) throws IOException {
|
|
||||||
try (XContentBuilder builder = jsonBuilder()) {
|
|
||||||
result.executedRequest().source().toXContent(builder, ToXContent.EMPTY_PARAMS);
|
|
||||||
return new XContentSource(builder);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Custom plugin that registers XPack script context.
|
|
||||||
*/
|
|
||||||
public static class CustomScriptContextPlugin extends Plugin implements ScriptPlugin {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ScriptContext.Plugin getCustomScriptContexts() {
|
|
||||||
return WatcherScript.CTX_PLUGIN;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
||||||
* or more contributor license agreements. Licensed under the Elastic License;
|
|
||||||
* you may not use this file except in compliance with the Elastic License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This package contains tests that use mustache to test what looks
|
|
||||||
* to be unrelated functionality, or functionality that should be
|
|
||||||
* tested with a mock instead. Instead of doing an epic battle
|
|
||||||
* with these tests, they are temporarily moved here to the mustache
|
|
||||||
* module's tests, but that is likely not where they belong. Please
|
|
||||||
* help by cleaning them up and we can remove this package!
|
|
||||||
*
|
|
||||||
* <ul>
|
|
||||||
* <li>If the test is testing templating integration with another core subsystem,
|
|
||||||
* fix it to use a mock instead, so it can be in the core tests again</li>
|
|
||||||
* <li>If the test is just being lazy, and does not really need templating to test
|
|
||||||
* something, clean it up!</li>
|
|
||||||
* </ul>
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.elasticsearch.messy.tests;
|
|
|
@ -1,26 +0,0 @@
|
||||||
{
|
|
||||||
"query": {
|
|
||||||
"bool": {
|
|
||||||
"must" : [
|
|
||||||
{
|
|
||||||
"match": {
|
|
||||||
"event_type": {
|
|
||||||
"query": "a",
|
|
||||||
"type": "boolean"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"range": {
|
|
||||||
"_timestamp": {
|
|
||||||
"from": "{{ctx.trigger.scheduled_time}}||-{{seconds_param}}",
|
|
||||||
"to": "{{ctx.trigger.scheduled_time}}",
|
|
||||||
"include_lower": true,
|
|
||||||
"include_upper": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
{
|
|
||||||
"query": {
|
|
||||||
"bool": {
|
|
||||||
"must" : [
|
|
||||||
{
|
|
||||||
"match": {
|
|
||||||
"event_type": {
|
|
||||||
"query": "a",
|
|
||||||
"type": "boolean"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"range": {
|
|
||||||
"_timestamp": {
|
|
||||||
"from": "{{ctx.trigger.scheduled_time}}||-{{seconds_param}}",
|
|
||||||
"to": "{{ctx.trigger.scheduled_time}}",
|
|
||||||
"include_lower": true,
|
|
||||||
"include_upper": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,157 @@
|
||||||
|
---
|
||||||
|
setup:
|
||||||
|
- do:
|
||||||
|
cluster.health:
|
||||||
|
wait_for_status: yellow
|
||||||
|
- do: {xpack.watcher.stats:{}}
|
||||||
|
- do:
|
||||||
|
index:
|
||||||
|
index: idx
|
||||||
|
type: type
|
||||||
|
id: 1
|
||||||
|
body: >
|
||||||
|
{
|
||||||
|
"date" : "2015-01-01T00:00:00",
|
||||||
|
"value" : "val_1"
|
||||||
|
}
|
||||||
|
- do:
|
||||||
|
index:
|
||||||
|
index: idx
|
||||||
|
type: type
|
||||||
|
id: 2
|
||||||
|
body: >
|
||||||
|
{
|
||||||
|
"date" : "2015-01-02T00:00:00",
|
||||||
|
"value" : "val_2"
|
||||||
|
}
|
||||||
|
- do:
|
||||||
|
index:
|
||||||
|
index: idx
|
||||||
|
type: type
|
||||||
|
id: 3
|
||||||
|
body: >
|
||||||
|
{
|
||||||
|
"date" : "2015-01-03T00:00:00",
|
||||||
|
"value" : "val_3"
|
||||||
|
}
|
||||||
|
- do:
|
||||||
|
index:
|
||||||
|
index: idx
|
||||||
|
type: type
|
||||||
|
id: 4
|
||||||
|
body: >
|
||||||
|
{
|
||||||
|
"date" : "2015-01-04T00:00:00",
|
||||||
|
"value" : "val_4"
|
||||||
|
}
|
||||||
|
- do:
|
||||||
|
indices.refresh:
|
||||||
|
index: idx
|
||||||
|
|
||||||
|
---
|
||||||
|
"Test input mustache integration":
|
||||||
|
- do:
|
||||||
|
xpack.watcher.execute_watch:
|
||||||
|
body: >
|
||||||
|
{
|
||||||
|
"trigger_data" : {
|
||||||
|
"scheduled_time" : "2015-01-04T00:00:00"
|
||||||
|
},
|
||||||
|
"watch" : {
|
||||||
|
"trigger" : { "schedule" : { "interval" : "10s" } },
|
||||||
|
"actions" : {
|
||||||
|
"dummy" : {
|
||||||
|
"logging" : {
|
||||||
|
"text" : "executed!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"input" : {
|
||||||
|
"search" : {
|
||||||
|
"request" : {
|
||||||
|
"indices" : "idx",
|
||||||
|
"body" : {
|
||||||
|
"query" : {
|
||||||
|
"bool" : {
|
||||||
|
"filter" : [
|
||||||
|
{
|
||||||
|
"range" : {
|
||||||
|
"date" : {
|
||||||
|
"lte" : "{{ctx.trigger.scheduled_time}}",
|
||||||
|
"gte" : "{{ctx.trigger.scheduled_time}}||-3d"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- match: { "watch_record.result.input.type": "search" }
|
||||||
|
- match: { "watch_record.result.input.status": "success" }
|
||||||
|
- match: { "watch_record.result.input.payload.hits.total": 4 }
|
||||||
|
# makes sure that the mustache template snippets have been resolved correctly:
|
||||||
|
- match: { "watch_record.result.input.search.request.body.query.bool.filter.0.range.date.from": "2015-01-04T00:00:00.000Z||-3d" }
|
||||||
|
- match: { "watch_record.result.input.search.request.body.query.bool.filter.0.range.date.to": "2015-01-04T00:00:00.000Z" }
|
||||||
|
|
||||||
|
---
|
||||||
|
"Test transform mustache integration":
|
||||||
|
- do:
|
||||||
|
xpack.watcher.execute_watch:
|
||||||
|
body: >
|
||||||
|
{
|
||||||
|
"trigger_data" : {
|
||||||
|
"scheduled_time" : "2015-01-04T00:00:00"
|
||||||
|
},
|
||||||
|
"watch" : {
|
||||||
|
"trigger" : { "schedule" : { "interval" : "10s" } },
|
||||||
|
"input" : { "simple" : { "value" : "val_3" } },
|
||||||
|
"actions" : {
|
||||||
|
"dummy" : {
|
||||||
|
"logging" : {
|
||||||
|
"text" : "executed!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"transform" : {
|
||||||
|
"search" : {
|
||||||
|
"request" : {
|
||||||
|
"indices" : "idx",
|
||||||
|
"body" : {
|
||||||
|
"query" : {
|
||||||
|
"bool" : {
|
||||||
|
"filter" : [
|
||||||
|
{
|
||||||
|
"range" : {
|
||||||
|
"date" : {
|
||||||
|
"lte" : "{{ctx.trigger.scheduled_time}}",
|
||||||
|
"gte" : "{{ctx.trigger.scheduled_time}}||-1d"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"term" : {
|
||||||
|
"value" : "{{ctx.payload.value}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- match: { "watch_record.result.transform.type": "search" }
|
||||||
|
- match: { "watch_record.result.transform.status": "success" }
|
||||||
|
- match: { "watch_record.result.transform.payload.hits.total": 1 }
|
||||||
|
- match: { "watch_record.result.transform.payload.hits.hits.0._id": "3" }
|
||||||
|
# makes sure that the mustache template snippets have been resolved correctly:
|
||||||
|
- match: { "watch_record.result.transform.search.request.body.query.bool.filter.0.range.date.from": "2015-01-04T00:00:00.000Z||-1d" }
|
||||||
|
- match: { "watch_record.result.transform.search.request.body.query.bool.filter.0.range.date.to": "2015-01-04T00:00:00.000Z" }
|
||||||
|
- match: { "watch_record.result.transform.search.request.body.query.bool.filter.1.term.value.value": "val_3" }
|
|
@ -3,42 +3,25 @@
|
||||||
* or more contributor license agreements. Licensed under the Elastic License;
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
* you may not use this file except in compliance with the Elastic License.
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
*/
|
*/
|
||||||
package org.elasticsearch.messy.tests;
|
package org.elasticsearch.integration;
|
||||||
|
|
||||||
import org.elasticsearch.ElasticsearchSecurityException;
|
import org.elasticsearch.ElasticsearchSecurityException;
|
||||||
import org.elasticsearch.Version;
|
|
||||||
import org.elasticsearch.action.search.SearchResponse;
|
import org.elasticsearch.action.search.SearchResponse;
|
||||||
import org.elasticsearch.index.query.QueryBuilders;
|
import org.elasticsearch.index.query.QueryBuilders;
|
||||||
import org.elasticsearch.indices.TermsLookup;
|
import org.elasticsearch.indices.TermsLookup;
|
||||||
import org.elasticsearch.plugins.Plugin;
|
|
||||||
import org.elasticsearch.script.ScriptService;
|
|
||||||
import org.elasticsearch.script.mustache.MustachePlugin;
|
|
||||||
import org.elasticsearch.script.mustache.TemplateQueryBuilder;
|
|
||||||
import org.elasticsearch.test.SecurityIntegTestCase;
|
import org.elasticsearch.test.SecurityIntegTestCase;
|
||||||
import org.elasticsearch.test.SecuritySettingsSource;
|
import org.elasticsearch.test.SecuritySettingsSource;
|
||||||
import org.elasticsearch.xpack.security.authc.support.SecuredString;
|
import org.elasticsearch.xpack.security.authc.support.SecuredString;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.BeforeClass;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
import static java.util.Collections.singletonMap;
|
import static java.util.Collections.singletonMap;
|
||||||
import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
|
import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
|
||||||
import static org.hamcrest.Matchers.containsString;
|
import static org.hamcrest.Matchers.containsString;
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
|
|
||||||
@SecurityIntegTestCase.AwaitsFix(bugUrl = "clean up test to not use mustache templates, otherwise needs many resources here")
|
public class SecurityCachePermissionTests extends SecurityIntegTestCase {
|
||||||
public class SecurityCachePermissionIT extends SecurityIntegTestCase {
|
|
||||||
static final String READ_ONE_IDX_USER = "read_user";
|
|
||||||
|
|
||||||
@Override
|
private final String READ_ONE_IDX_USER = "read_user";
|
||||||
protected Collection<Class<? extends Plugin>> nodePlugins() {
|
|
||||||
Collection<Class<? extends Plugin>> types = new ArrayList<>();
|
|
||||||
types.addAll(super.nodePlugins());
|
|
||||||
types.add(MustachePlugin.class);
|
|
||||||
return types;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String configUsers() {
|
public String configUsers() {
|
||||||
|
@ -61,11 +44,6 @@ public class SecurityCachePermissionIT extends SecurityIntegTestCase {
|
||||||
+ "read_one_idx:" + READ_ONE_IDX_USER + "\n";
|
+ "read_one_idx:" + READ_ONE_IDX_USER + "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
@BeforeClass
|
|
||||||
public static void checkVersion() {
|
|
||||||
assumeTrue("These tests are only valid with elasticsearch 1.6.0+", Version.CURRENT.id >= 1060099);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void loadData() {
|
public void loadData() {
|
||||||
index("data", "a", "1", "{ \"name\": \"John\", \"token\": \"token1\" }");
|
index("data", "a", "1", "{ \"name\": \"John\", \"token\": \"token1\" }");
|
||||||
|
@ -93,33 +71,4 @@ public class SecurityCachePermissionIT extends SecurityIntegTestCase {
|
||||||
assertThat(e.toString(), containsString("unauthorized"));
|
assertThat(e.toString(), containsString("unauthorized"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testThatScriptServiceDoesntLeakData() {
|
|
||||||
String source = "{\n" +
|
|
||||||
"\"template\": {\n" +
|
|
||||||
" \"query\": {\n" +
|
|
||||||
" \"exists\": {\n" +
|
|
||||||
" \"field\": \"{{name}}\"\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
"}";
|
|
||||||
|
|
||||||
//Template template = new Template(source, INLINE, MustacheScriptEngineService.NAME, null, singletonMap("name", "token"));
|
|
||||||
SearchResponse response = client().prepareSearch("data").setTypes("a")
|
|
||||||
.setQuery(new TemplateQueryBuilder(source, ScriptService.ScriptType.INLINE, singletonMap("name", "token")))
|
|
||||||
.execute().actionGet();
|
|
||||||
assertThat(response.isTimedOut(), is(false));
|
|
||||||
assertThat(response.getHits().hits().length, is(1));
|
|
||||||
|
|
||||||
// Repeat with unauthorized user!!!!
|
|
||||||
ElasticsearchSecurityException e = expectThrows(ElasticsearchSecurityException.class, () -> client()
|
|
||||||
.filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(READ_ONE_IDX_USER,
|
|
||||||
new SecuredString("changeme".toCharArray()))))
|
|
||||||
.prepareSearch("data").setTypes("a")
|
|
||||||
.setQuery(new TemplateQueryBuilder(source, ScriptService.ScriptType.INLINE, singletonMap("name", "token")))
|
|
||||||
.execute().actionGet());
|
|
||||||
assertThat(e.toString(), containsString("ElasticsearchSecurityException[action"));
|
|
||||||
assertThat(e.toString(), containsString("unauthorized"));
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -0,0 +1,199 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
package org.elasticsearch.xpack.watcher.test.integration;
|
||||||
|
|
||||||
|
import org.elasticsearch.action.search.SearchRequest;
|
||||||
|
import org.elasticsearch.action.search.SearchType;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.common.unit.TimeValue;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
|
import org.elasticsearch.common.xcontent.json.JsonXContent;
|
||||||
|
import org.elasticsearch.common.xcontent.support.XContentMapValues;
|
||||||
|
import org.elasticsearch.indices.query.IndicesQueriesRegistry;
|
||||||
|
import org.elasticsearch.plugins.Plugin;
|
||||||
|
import org.elasticsearch.plugins.ScriptPlugin;
|
||||||
|
import org.elasticsearch.script.MockMustacheScriptEngine;
|
||||||
|
import org.elasticsearch.script.ScriptContext;
|
||||||
|
import org.elasticsearch.script.ScriptService;
|
||||||
|
import org.elasticsearch.search.aggregations.AggregatorParsers;
|
||||||
|
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
||||||
|
import org.elasticsearch.search.suggest.Suggesters;
|
||||||
|
import org.elasticsearch.test.ESIntegTestCase;
|
||||||
|
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
|
||||||
|
import org.elasticsearch.xpack.watcher.actions.ExecutableActions;
|
||||||
|
import org.elasticsearch.xpack.watcher.condition.always.ExecutableAlwaysCondition;
|
||||||
|
import org.elasticsearch.xpack.watcher.execution.TriggeredExecutionContext;
|
||||||
|
import org.elasticsearch.xpack.watcher.execution.WatchExecutionContext;
|
||||||
|
import org.elasticsearch.xpack.watcher.input.Input;
|
||||||
|
import org.elasticsearch.xpack.watcher.input.search.ExecutableSearchInput;
|
||||||
|
import org.elasticsearch.xpack.watcher.input.search.SearchInput;
|
||||||
|
import org.elasticsearch.xpack.watcher.input.search.SearchInputFactory;
|
||||||
|
import org.elasticsearch.xpack.watcher.input.simple.ExecutableSimpleInput;
|
||||||
|
import org.elasticsearch.xpack.watcher.input.simple.SimpleInput;
|
||||||
|
import org.elasticsearch.xpack.watcher.support.WatcherScript;
|
||||||
|
import org.elasticsearch.xpack.watcher.support.init.proxy.WatcherClientProxy;
|
||||||
|
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateRequest;
|
||||||
|
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateService;
|
||||||
|
import org.elasticsearch.xpack.watcher.trigger.schedule.IntervalSchedule;
|
||||||
|
import org.elasticsearch.xpack.watcher.trigger.schedule.ScheduleTrigger;
|
||||||
|
import org.elasticsearch.xpack.watcher.trigger.schedule.ScheduleTriggerEvent;
|
||||||
|
import org.elasticsearch.xpack.watcher.watch.Payload;
|
||||||
|
import org.elasticsearch.xpack.watcher.watch.Watch;
|
||||||
|
import org.elasticsearch.xpack.watcher.watch.WatchStatus;
|
||||||
|
import org.joda.time.DateTime;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import static java.util.Collections.emptyMap;
|
||||||
|
import static org.elasticsearch.common.unit.TimeValue.timeValueSeconds;
|
||||||
|
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
||||||
|
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
|
||||||
|
import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
|
||||||
|
import static org.elasticsearch.index.query.QueryBuilders.rangeQuery;
|
||||||
|
import static org.elasticsearch.search.builder.SearchSourceBuilder.searchSource;
|
||||||
|
import static org.elasticsearch.test.ESIntegTestCase.Scope.SUITE;
|
||||||
|
import static org.elasticsearch.xpack.watcher.test.WatcherTestUtils.getRandomSupportedSearchType;
|
||||||
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
import static org.hamcrest.Matchers.is;
|
||||||
|
import static org.joda.time.DateTimeZone.UTC;
|
||||||
|
|
||||||
|
@ClusterScope(scope = SUITE, numClientNodes = 0, transportClientRatio = 0, randomDynamicTemplates = false, supportsDedicatedMasters = false,
|
||||||
|
numDataNodes = 1)
|
||||||
|
public class SearchInputTests extends ESIntegTestCase {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Collection<Class<? extends Plugin>> nodePlugins() {
|
||||||
|
Collection<Class<? extends Plugin>> types = new ArrayList<>();
|
||||||
|
types.addAll(super.nodePlugins());
|
||||||
|
types.add(MockMustacheScriptEngine.TestPlugin.class);
|
||||||
|
types.add(CustomScriptContextPlugin.class);
|
||||||
|
return types;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testExecute() throws Exception {
|
||||||
|
SearchSourceBuilder searchSourceBuilder = searchSource().query(
|
||||||
|
boolQuery().must(matchQuery("event_type", "a")));
|
||||||
|
SearchRequest searchRequest = client()
|
||||||
|
.prepareSearch()
|
||||||
|
.setSearchType(ExecutableSearchInput.DEFAULT_SEARCH_TYPE)
|
||||||
|
.request()
|
||||||
|
.source(searchSourceBuilder);
|
||||||
|
|
||||||
|
WatcherSearchTemplateRequest request = new WatcherSearchTemplateRequest(searchRequest);
|
||||||
|
ExecutableSearchInput searchInput = new ExecutableSearchInput(new SearchInput(request, null, null, null), logger,
|
||||||
|
WatcherClientProxy.of(client()), watcherSearchTemplateService(), null);
|
||||||
|
WatchExecutionContext ctx = new TriggeredExecutionContext(
|
||||||
|
new Watch("test-watch",
|
||||||
|
new ScheduleTrigger(new IntervalSchedule(new IntervalSchedule.Interval(1, IntervalSchedule.Interval.Unit.MINUTES))),
|
||||||
|
new ExecutableSimpleInput(new SimpleInput(new Payload.Simple()), logger),
|
||||||
|
new ExecutableAlwaysCondition(logger),
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
new ExecutableActions(new ArrayList<>()),
|
||||||
|
null,
|
||||||
|
new WatchStatus(new DateTime(0, UTC), emptyMap())),
|
||||||
|
new DateTime(0, UTC),
|
||||||
|
new ScheduleTriggerEvent("test-watch", new DateTime(0, UTC), new DateTime(0, UTC)),
|
||||||
|
timeValueSeconds(5));
|
||||||
|
SearchInput.Result result = searchInput.execute(ctx, new Payload.Simple());
|
||||||
|
|
||||||
|
assertThat(XContentMapValues.extractValue("hits.total", result.payload().data()), equalTo(0));
|
||||||
|
assertNotNull(result.executedRequest());
|
||||||
|
assertThat(result.status(), is(Input.Result.Status.SUCCESS));
|
||||||
|
assertEquals(result.executedRequest().searchType(), request.getRequest().searchType());
|
||||||
|
assertArrayEquals(result.executedRequest().indices(), request.getRequest().indices());
|
||||||
|
assertEquals(result.executedRequest().indicesOptions(), request.getRequest().indicesOptions());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testDifferentSearchType() throws Exception {
|
||||||
|
SearchSourceBuilder searchSourceBuilder = searchSource().query(
|
||||||
|
boolQuery().must(matchQuery("event_type", "a"))
|
||||||
|
);
|
||||||
|
SearchType searchType = getRandomSupportedSearchType();
|
||||||
|
|
||||||
|
SearchRequest searchRequest = client()
|
||||||
|
.prepareSearch()
|
||||||
|
.setSearchType(searchType)
|
||||||
|
.request()
|
||||||
|
.source(searchSourceBuilder);
|
||||||
|
|
||||||
|
WatcherSearchTemplateRequest request = new WatcherSearchTemplateRequest(searchRequest);
|
||||||
|
|
||||||
|
ExecutableSearchInput searchInput = new ExecutableSearchInput(new SearchInput(request, null, null, null), logger,
|
||||||
|
WatcherClientProxy.of(client()), watcherSearchTemplateService(), null);
|
||||||
|
WatchExecutionContext ctx = new TriggeredExecutionContext(
|
||||||
|
new Watch("test-watch",
|
||||||
|
new ScheduleTrigger(new IntervalSchedule(new IntervalSchedule.Interval(1, IntervalSchedule.Interval.Unit.MINUTES))),
|
||||||
|
new ExecutableSimpleInput(new SimpleInput(new Payload.Simple()), logger),
|
||||||
|
new ExecutableAlwaysCondition(logger),
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
new ExecutableActions(new ArrayList<>()),
|
||||||
|
null,
|
||||||
|
new WatchStatus(new DateTime(0, UTC), emptyMap())),
|
||||||
|
new DateTime(0, UTC),
|
||||||
|
new ScheduleTriggerEvent("test-watch", new DateTime(0, UTC), new DateTime(0, UTC)),
|
||||||
|
timeValueSeconds(5));
|
||||||
|
SearchInput.Result result = searchInput.execute(ctx, new Payload.Simple());
|
||||||
|
|
||||||
|
assertThat(XContentMapValues.extractValue("hits.total", result.payload().data()), equalTo(0));
|
||||||
|
assertNotNull(result.executedRequest());
|
||||||
|
assertThat(result.status(), is(Input.Result.Status.SUCCESS));
|
||||||
|
assertEquals(result.executedRequest().searchType(), searchType);
|
||||||
|
assertArrayEquals(result.executedRequest().indices(), searchRequest.indices());
|
||||||
|
assertEquals(result.executedRequest().indicesOptions(), searchRequest.indicesOptions());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testParserValid() throws Exception {
|
||||||
|
SearchRequest searchRequest = client().prepareSearch()
|
||||||
|
.setSearchType(ExecutableSearchInput.DEFAULT_SEARCH_TYPE)
|
||||||
|
.request()
|
||||||
|
.source(searchSource()
|
||||||
|
.query(boolQuery().must(matchQuery("event_type", "a")).must(rangeQuery("_timestamp")
|
||||||
|
.from("{{ctx.trigger.scheduled_time}}||-30s").to("{{ctx.trigger.triggered_time}}"))));
|
||||||
|
|
||||||
|
TimeValue timeout = randomBoolean() ? TimeValue.timeValueSeconds(randomInt(10)) : null;
|
||||||
|
XContentBuilder builder = jsonBuilder().value(
|
||||||
|
new SearchInput(new WatcherSearchTemplateRequest(searchRequest), null, timeout, null));
|
||||||
|
XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes());
|
||||||
|
parser.nextToken();
|
||||||
|
|
||||||
|
IndicesQueriesRegistry indicesQueryRegistry = internalCluster().getInstance(IndicesQueriesRegistry.class);
|
||||||
|
SearchInputFactory factory = new SearchInputFactory(Settings.EMPTY, WatcherClientProxy.of(client()), indicesQueryRegistry,
|
||||||
|
null, null, scriptService());
|
||||||
|
|
||||||
|
SearchInput searchInput = factory.parseInput("_id", parser);
|
||||||
|
assertEquals(SearchInput.TYPE, searchInput.type());
|
||||||
|
assertThat(searchInput.getTimeout(), equalTo(timeout));
|
||||||
|
}
|
||||||
|
|
||||||
|
private WatcherSearchTemplateService watcherSearchTemplateService() {
|
||||||
|
String master = internalCluster().getMasterName();
|
||||||
|
return new WatcherSearchTemplateService(internalCluster().clusterService(master).getSettings(),
|
||||||
|
internalCluster().getInstance(ScriptService.class, master),
|
||||||
|
internalCluster().getInstance(IndicesQueriesRegistry.class, master),
|
||||||
|
internalCluster().getInstance(AggregatorParsers.class, master),
|
||||||
|
internalCluster().getInstance(Suggesters.class, master)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ScriptService scriptService() {
|
||||||
|
return internalCluster().getInstance(ScriptService.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom plugin that registers XPack script context.
|
||||||
|
*/
|
||||||
|
public static class CustomScriptContextPlugin extends Plugin implements ScriptPlugin {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ScriptContext.Plugin getCustomScriptContexts() {
|
||||||
|
return WatcherScript.CTX_PLUGIN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,15 +3,12 @@
|
||||||
* or more contributor license agreements. Licensed under the Elastic License;
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
* you may not use this file except in compliance with the Elastic License.
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
*/
|
*/
|
||||||
package org.elasticsearch.messy.tests;
|
package org.elasticsearch.xpack.watcher.test.integration;
|
||||||
|
|
||||||
import org.elasticsearch.action.admin.cluster.storedscripts.PutStoredScriptRequest;
|
|
||||||
import org.elasticsearch.action.search.SearchRequest;
|
import org.elasticsearch.action.search.SearchRequest;
|
||||||
import org.elasticsearch.action.search.SearchResponse;
|
import org.elasticsearch.action.search.SearchResponse;
|
||||||
import org.elasticsearch.action.search.SearchType;
|
import org.elasticsearch.action.search.SearchType;
|
||||||
import org.elasticsearch.client.Requests;
|
import org.elasticsearch.client.Requests;
|
||||||
import org.elasticsearch.common.bytes.BytesArray;
|
|
||||||
import org.elasticsearch.common.io.Streams;
|
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.common.unit.TimeValue;
|
import org.elasticsearch.common.unit.TimeValue;
|
||||||
import org.elasticsearch.common.xcontent.ToXContent;
|
import org.elasticsearch.common.xcontent.ToXContent;
|
||||||
|
@ -24,9 +21,9 @@ import org.elasticsearch.index.query.QueryBuilders;
|
||||||
import org.elasticsearch.indices.query.IndicesQueriesRegistry;
|
import org.elasticsearch.indices.query.IndicesQueriesRegistry;
|
||||||
import org.elasticsearch.plugins.Plugin;
|
import org.elasticsearch.plugins.Plugin;
|
||||||
import org.elasticsearch.plugins.ScriptPlugin;
|
import org.elasticsearch.plugins.ScriptPlugin;
|
||||||
|
import org.elasticsearch.script.MockMustacheScriptEngine;
|
||||||
import org.elasticsearch.script.ScriptContext;
|
import org.elasticsearch.script.ScriptContext;
|
||||||
import org.elasticsearch.script.ScriptService;
|
import org.elasticsearch.script.ScriptService;
|
||||||
import org.elasticsearch.script.mustache.MustachePlugin;
|
|
||||||
import org.elasticsearch.search.aggregations.AggregatorParsers;
|
import org.elasticsearch.search.aggregations.AggregatorParsers;
|
||||||
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
||||||
import org.elasticsearch.search.suggest.Suggesters;
|
import org.elasticsearch.search.suggest.Suggesters;
|
||||||
|
@ -43,7 +40,6 @@ import org.elasticsearch.xpack.watcher.support.WatcherScript;
|
||||||
import org.elasticsearch.xpack.watcher.support.init.proxy.WatcherClientProxy;
|
import org.elasticsearch.xpack.watcher.support.init.proxy.WatcherClientProxy;
|
||||||
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateRequest;
|
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateRequest;
|
||||||
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateService;
|
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateService;
|
||||||
import org.elasticsearch.xpack.watcher.support.xcontent.XContentSource;
|
|
||||||
import org.elasticsearch.xpack.watcher.transform.Transform;
|
import org.elasticsearch.xpack.watcher.transform.Transform;
|
||||||
import org.elasticsearch.xpack.watcher.transform.TransformBuilders;
|
import org.elasticsearch.xpack.watcher.transform.TransformBuilders;
|
||||||
import org.elasticsearch.xpack.watcher.transform.search.ExecutableSearchTransform;
|
import org.elasticsearch.xpack.watcher.transform.search.ExecutableSearchTransform;
|
||||||
|
@ -56,35 +52,24 @@ import org.elasticsearch.xpack.watcher.watch.Payload;
|
||||||
import org.elasticsearch.xpack.watcher.watch.Watch;
|
import org.elasticsearch.xpack.watcher.watch.Watch;
|
||||||
import org.elasticsearch.xpack.watcher.watch.WatchStatus;
|
import org.elasticsearch.xpack.watcher.watch.WatchStatus;
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
import org.joda.time.chrono.ISOChronology;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static java.util.Collections.emptyMap;
|
import static java.util.Collections.emptyMap;
|
||||||
import static org.elasticsearch.common.unit.TimeValue.timeValueSeconds;
|
import static org.elasticsearch.common.unit.TimeValue.timeValueSeconds;
|
||||||
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
||||||
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
|
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
|
||||||
import static org.elasticsearch.index.query.QueryBuilders.constantScoreQuery;
|
|
||||||
import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
|
import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
|
||||||
import static org.elasticsearch.index.query.QueryBuilders.rangeQuery;
|
|
||||||
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
|
|
||||||
import static org.elasticsearch.search.builder.SearchSourceBuilder.searchSource;
|
import static org.elasticsearch.search.builder.SearchSourceBuilder.searchSource;
|
||||||
import static org.elasticsearch.test.ESIntegTestCase.Scope.SUITE;
|
import static org.elasticsearch.test.ESIntegTestCase.Scope.SUITE;
|
||||||
import static org.elasticsearch.xpack.watcher.support.WatcherDateTimeUtils.parseDate;
|
|
||||||
import static org.elasticsearch.xpack.watcher.test.WatcherTestUtils.EMPTY_PAYLOAD;
|
import static org.elasticsearch.xpack.watcher.test.WatcherTestUtils.EMPTY_PAYLOAD;
|
||||||
import static org.elasticsearch.xpack.watcher.test.WatcherTestUtils.getRandomSupportedSearchType;
|
import static org.elasticsearch.xpack.watcher.test.WatcherTestUtils.getRandomSupportedSearchType;
|
||||||
import static org.elasticsearch.xpack.watcher.test.WatcherTestUtils.mockExecutionContext;
|
import static org.elasticsearch.xpack.watcher.test.WatcherTestUtils.mockExecutionContext;
|
||||||
import static org.elasticsearch.xpack.watcher.test.WatcherTestUtils.simplePayload;
|
|
||||||
import static org.hamcrest.Matchers.arrayContainingInAnyOrder;
|
import static org.hamcrest.Matchers.arrayContainingInAnyOrder;
|
||||||
import static org.hamcrest.Matchers.containsString;
|
import static org.hamcrest.Matchers.containsString;
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
@ -94,63 +79,26 @@ import static org.hamcrest.Matchers.is;
|
||||||
import static org.hamcrest.Matchers.notNullValue;
|
import static org.hamcrest.Matchers.notNullValue;
|
||||||
import static org.joda.time.DateTimeZone.UTC;
|
import static org.joda.time.DateTimeZone.UTC;
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@ClusterScope(scope = SUITE, numClientNodes = 0, transportClientRatio = 0, randomDynamicTemplates = false, supportsDedicatedMasters = false,
|
@ClusterScope(scope = SUITE, numClientNodes = 0, transportClientRatio = 0, randomDynamicTemplates = false, supportsDedicatedMasters = false,
|
||||||
numDataNodes = 1)
|
numDataNodes = 1)
|
||||||
public class SearchTransformIT extends ESIntegTestCase {
|
public class SearchTransformTests extends ESIntegTestCase {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Collection<Class<? extends Plugin>> nodePlugins() {
|
protected Collection<Class<? extends Plugin>> nodePlugins() {
|
||||||
Collection<Class<? extends Plugin>> types = new ArrayList<>();
|
Collection<Class<? extends Plugin>> plugins = new ArrayList<>();
|
||||||
types.addAll(super.nodePlugins());
|
plugins.addAll(super.nodePlugins());
|
||||||
types.add(MustachePlugin.class);
|
plugins.add(CustomScriptContextPlugin.class);
|
||||||
types.add(CustomScriptContextPlugin.class);
|
plugins.add(MockMustacheScriptEngine.TestPlugin.class);
|
||||||
return types;
|
return plugins;
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Settings nodeSettings(int nodeOrdinal) {
|
|
||||||
final Path tempDir = createTempDir();
|
|
||||||
final Path configPath = tempDir.resolve("config");
|
|
||||||
final Path scriptPath = configPath.resolve("scripts");
|
|
||||||
try {
|
|
||||||
Files.createDirectories(scriptPath);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException("failed to create config dir");
|
|
||||||
|
|
||||||
}
|
|
||||||
String path = "/org/elasticsearch/xpack/watcher/transform/search/config/scripts/test_disk_template.mustache";
|
|
||||||
try (InputStream stream = SearchTransformIT.class.getResourceAsStream(path);
|
|
||||||
OutputStream out = Files.newOutputStream(scriptPath.resolve("test_disk_template.mustache"))) {
|
|
||||||
Streams.copy(stream, out);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException("failed to copy mustache template");
|
|
||||||
}
|
|
||||||
//Set path so ScriptService will pick up the test scripts
|
|
||||||
return Settings.builder()
|
|
||||||
.put(super.nodeSettings(nodeOrdinal))
|
|
||||||
// we're not extending from the base watcher test case, so we should prevent the watcher plugin from being loaded
|
|
||||||
.put("path.conf", configPath).build();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Settings transportClientSettings() {
|
|
||||||
return Settings.builder()
|
|
||||||
.put(super.transportClientSettings())
|
|
||||||
.build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Settings indexSettings() {
|
public Settings indexSettings() {
|
||||||
return Settings.builder()
|
return Settings.builder()
|
||||||
.put(super.indexSettings())
|
.put(super.indexSettings())
|
||||||
|
|
||||||
// we have to test this on an index that has at least 2 shards. Otherwise when searching indices with
|
// we have to test this on an index that has at least 2 shards. Otherwise when searching indices with
|
||||||
// a single shard the QUERY_THEN_FETCH search type will change to QUERY_AND_FETCH during execution.
|
// a single shard the QUERY_THEN_FETCH search type will change to QUERY_AND_FETCH during execution.
|
||||||
.put("index.number_of_shards", randomIntBetween(2, 5))
|
.put("index.number_of_shards", randomIntBetween(2, 5))
|
||||||
|
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,71 +180,6 @@ public class SearchTransformIT extends ESIntegTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testExecuteMustacheTemplate() throws Exception {
|
|
||||||
|
|
||||||
// The rational behind this test:
|
|
||||||
//
|
|
||||||
// - we index 4 documents each one associated with a unique value and each is associated with a day
|
|
||||||
// - we build a search transform such that with a filter that
|
|
||||||
// - the date must be after [scheduled_time] variable
|
|
||||||
// - the date must be before [execution_time] variable
|
|
||||||
// - the value must match [payload.value] variable
|
|
||||||
// - the variable are set as such:
|
|
||||||
// - scheduled_time = youngest document's date
|
|
||||||
// - fired_time = oldest document's date
|
|
||||||
// - payload.value = val_3
|
|
||||||
// - when executed, the variables will be replaced with the scheduled_time, fired_time and the payload.value.
|
|
||||||
// - we set all these variables accordingly (the search transform is responsible to populate them)
|
|
||||||
// - when replaced correctly, the search should return document 3.
|
|
||||||
//
|
|
||||||
// we then do a search for document 3, and compare the response to the payload returned by the transform
|
|
||||||
|
|
||||||
index("idx", "type", "1", doc("2015-01-01T00:00:00", "val_1"));
|
|
||||||
index("idx", "type", "2", doc("2015-01-02T00:00:00", "val_2"));
|
|
||||||
index("idx", "type", "3", doc("2015-01-03T00:00:00", "val_3"));
|
|
||||||
index("idx", "type", "4", doc("2015-01-04T00:00:00", "val_4"));
|
|
||||||
|
|
||||||
ensureGreen("idx");
|
|
||||||
refresh();
|
|
||||||
|
|
||||||
SearchRequest request = Requests.searchRequest("idx").source(searchSource().query(boolQuery()
|
|
||||||
.must(constantScoreQuery(rangeQuery("date").gt("{{ctx.trigger.scheduled_time}}")))
|
|
||||||
.must(constantScoreQuery(rangeQuery("date").lt("{{ctx.execution_time}}")))
|
|
||||||
.must(termQuery("value", "{{ctx.payload.value}}"))));
|
|
||||||
|
|
||||||
SearchTransform searchTransform = TransformBuilders.searchTransform(request).build();
|
|
||||||
ExecutableSearchTransform transform = new ExecutableSearchTransform(searchTransform, logger, WatcherClientProxy.of(client()),
|
|
||||||
watcherSearchTemplateService(), null);
|
|
||||||
|
|
||||||
ScheduleTriggerEvent event = new ScheduleTriggerEvent("_name", parseDate("2015-01-04T00:00:00", UTC),
|
|
||||||
parseDate("2015-01-01T00:00:00", UTC));
|
|
||||||
WatchExecutionContext ctx = mockExecutionContext("_name", parseDate("2015-01-04T00:00:00", UTC), event, EMPTY_PAYLOAD);
|
|
||||||
|
|
||||||
Payload payload = simplePayload("value", "val_3");
|
|
||||||
|
|
||||||
Transform.Result result = transform.execute(ctx, payload);
|
|
||||||
assertThat(result, notNullValue());
|
|
||||||
assertThat(result.type(), is(SearchTransform.TYPE));
|
|
||||||
|
|
||||||
SearchResponse response = client().prepareSearch("idx").setSearchType(ExecutableSearchTransform.DEFAULT_SEARCH_TYPE).setQuery(
|
|
||||||
boolQuery()
|
|
||||||
.must(constantScoreQuery(rangeQuery("date").gt(parseDate("2015-01-01T00:00:00", UTC))))
|
|
||||||
.must(constantScoreQuery(rangeQuery("date").lt(parseDate("2015-01-04T00:00:00", UTC))))
|
|
||||||
.must(termQuery("value", "val_3"))
|
|
||||||
).get();
|
|
||||||
Payload expectedPayload = new Payload.XContent(response);
|
|
||||||
|
|
||||||
// we need to remove the "took" field from teh response as this is the only field
|
|
||||||
// that most likely be different between the two... we don't really care about this
|
|
||||||
// field, we just want to make sure that the important parts of the response are the same
|
|
||||||
Map<String, Object> resultData = result.payload().data();
|
|
||||||
resultData.remove("took");
|
|
||||||
Map<String, Object> expectedData = expectedPayload.data();
|
|
||||||
expectedData.remove("took");
|
|
||||||
|
|
||||||
assertThat(resultData, equalTo(expectedData));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testParser() throws Exception {
|
public void testParser() throws Exception {
|
||||||
String[] indices = rarely() ? null : randomBoolean() ? new String[] { "idx" } : new String[] { "idx1", "idx2" };
|
String[] indices = rarely() ? null : randomBoolean() ? new String[] { "idx" } : new String[] { "idx1", "idx2" };
|
||||||
SearchType searchType = getRandomSupportedSearchType();
|
SearchType searchType = getRandomSupportedSearchType();
|
||||||
|
@ -354,116 +237,11 @@ public class SearchTransformIT extends ESIntegTestCase {
|
||||||
assertThat(executable.transform().getTimeout(), equalTo(readTimeout));
|
assertThat(executable.transform().getTimeout(), equalTo(readTimeout));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testSearchInlineTemplate() throws Exception {
|
|
||||||
WatchExecutionContext ctx = createContext();
|
|
||||||
|
|
||||||
final String templateQuery = "{\"query\":{\"bool\":{\"must\":[{\"match\":{\"event_type\":{\"query\":\"a\"," +
|
|
||||||
"\"type\":\"boolean\"}}},{\"range\":{\"_timestamp\":" +
|
|
||||||
"{\"from\":\"{{ctx.trigger.scheduled_time}}||-{{seconds_param}}\",\"to\":\"{{ctx.trigger.scheduled_time}}\"," +
|
|
||||||
"\"include_lower\":true,\"include_upper\":true}}}]}}}";
|
|
||||||
|
|
||||||
Map<String, Object> triggerParams = new HashMap<String, Object>();
|
|
||||||
triggerParams.put("triggered_time", new DateTime(1970, 01, 01, 00, 01, 00, 000, ISOChronology.getInstanceUTC()));
|
|
||||||
triggerParams.put("scheduled_time", new DateTime(1970, 01, 01, 00, 01, 00, 000, ISOChronology.getInstanceUTC()));
|
|
||||||
Map<String, Object> ctxParams = new HashMap<String, Object>();
|
|
||||||
ctxParams.put("id", ctx.id().value());
|
|
||||||
ctxParams.put("metadata", null);
|
|
||||||
ctxParams.put("vars", new HashMap<String, Object>());
|
|
||||||
ctxParams.put("watch_id", "test-watch");
|
|
||||||
ctxParams.put("payload", new HashMap<String, Object>());
|
|
||||||
ctxParams.put("trigger", triggerParams);
|
|
||||||
ctxParams.put("execution_time", new DateTime(1970, 01, 01, 00, 01, 00, 000, ISOChronology.getInstanceUTC()));
|
|
||||||
Map<String, Object> expectedParams = new HashMap<String, Object>();
|
|
||||||
expectedParams.put("seconds_param", "30s");
|
|
||||||
expectedParams.put("ctx", ctxParams);
|
|
||||||
|
|
||||||
Map<String, Object> params = new HashMap<>();
|
|
||||||
params.put("seconds_param", "30s");
|
|
||||||
|
|
||||||
WatcherScript template = WatcherScript.inline(templateQuery).lang("mustache").params(params).build();
|
|
||||||
SearchRequest request = client().prepareSearch().setSearchType(ExecutableSearchTransform.DEFAULT_SEARCH_TYPE)
|
|
||||||
.setIndices("test-search-index").request();
|
|
||||||
|
|
||||||
SearchTransform.Result executedResult = executeSearchTransform(request, template, ctx);
|
|
||||||
|
|
||||||
assertThat(executedResult.status(), is(Transform.Result.Status.SUCCESS));
|
|
||||||
assertEquals(executedResult.executedRequest().searchType(), request.searchType());
|
|
||||||
assertArrayEquals(executedResult.executedRequest().indices(), request.indices());
|
|
||||||
assertEquals(executedResult.executedRequest().indicesOptions(), request.indicesOptions());
|
|
||||||
|
|
||||||
XContentSource source = toXContentSource(executedResult);
|
|
||||||
assertThat(source.getValue("query.bool.must.1.range._timestamp.from"), equalTo("1970-01-01T00:01:00.000Z||-30s"));
|
|
||||||
assertThat(source.getValue("query.bool.must.1.range._timestamp.to"), equalTo("1970-01-01T00:01:00.000Z"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testSearchIndexedTemplate() throws Exception {
|
|
||||||
WatchExecutionContext ctx = createContext();
|
|
||||||
|
|
||||||
final String templateQuery = "{\"query\":{\"bool\":{\"must\":[{\"match\":{\"event_type\":{\"query\":\"a\"," +
|
|
||||||
"\"type\":\"boolean\"}}},{\"range\":{\"_timestamp\":" +
|
|
||||||
"{\"from\":\"{{ctx.trigger.scheduled_time}}||-{{seconds_param}}\",\"to\":\"{{ctx.trigger.scheduled_time}}\"," +
|
|
||||||
"\"include_lower\":true,\"include_upper\":true}}}]}}}";
|
|
||||||
|
|
||||||
PutStoredScriptRequest indexedScriptRequest = client().admin().cluster().preparePutStoredScript()
|
|
||||||
.setId("test-script")
|
|
||||||
.setScriptLang("mustache")
|
|
||||||
.setSource(new BytesArray(templateQuery))
|
|
||||||
.request();
|
|
||||||
assertThat(client().admin().cluster().putStoredScript(indexedScriptRequest).actionGet().isAcknowledged(), is(true));
|
|
||||||
|
|
||||||
Map<String, Object> params = new HashMap<>();
|
|
||||||
params.put("seconds_param", "30s");
|
|
||||||
|
|
||||||
WatcherScript template = WatcherScript.indexed("test-script").lang("mustache").params(params).build();
|
|
||||||
|
|
||||||
SearchRequest request = client()
|
|
||||||
.prepareSearch()
|
|
||||||
.setSearchType(ExecutableSearchTransform.DEFAULT_SEARCH_TYPE)
|
|
||||||
.setIndices("test-search-index")
|
|
||||||
.request();
|
|
||||||
|
|
||||||
SearchTransform.Result result = executeSearchTransform(request, template, ctx);
|
|
||||||
|
|
||||||
assertNotNull(result.executedRequest());
|
|
||||||
assertThat(result.status(), is(Transform.Result.Status.SUCCESS));
|
|
||||||
assertArrayEquals(result.executedRequest().indices(), request.indices());
|
|
||||||
assertEquals(result.executedRequest().indicesOptions(), request.indicesOptions());
|
|
||||||
|
|
||||||
XContentSource source = toXContentSource(result);
|
|
||||||
assertThat(source.getValue("query.bool.must.1.range._timestamp.from"), equalTo("1970-01-01T00:01:00.000Z||-30s"));
|
|
||||||
assertThat(source.getValue("query.bool.must.1.range._timestamp.to"), equalTo("1970-01-01T00:01:00.000Z"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testSearchOnDiskTemplate() throws Exception {
|
|
||||||
WatchExecutionContext ctx = createContext();
|
|
||||||
|
|
||||||
Map<String, Object> params = new HashMap<>();
|
|
||||||
params.put("seconds_param", "30s");
|
|
||||||
|
|
||||||
WatcherScript template = WatcherScript.file("test_disk_template").lang("mustache").params(params).build();
|
|
||||||
SearchRequest request = client().prepareSearch().setSearchType(ExecutableSearchTransform.DEFAULT_SEARCH_TYPE)
|
|
||||||
.setIndices("test-search-index").request();
|
|
||||||
|
|
||||||
SearchTransform.Result result = executeSearchTransform(request, template, ctx);
|
|
||||||
|
|
||||||
assertNotNull(result.executedRequest());
|
|
||||||
assertThat(result.status(), is(Transform.Result.Status.SUCCESS));
|
|
||||||
assertArrayEquals(result.executedRequest().indices(), request.indices());
|
|
||||||
assertEquals(result.executedRequest().indicesOptions(), request.indicesOptions());
|
|
||||||
|
|
||||||
XContentSource source = toXContentSource(result);
|
|
||||||
assertThat(source.getValue("query.bool.must.1.range._timestamp.from"), equalTo("1970-01-01T00:01:00.000Z||-30s"));
|
|
||||||
assertThat(source.getValue("query.bool.must.1.range._timestamp.to"), equalTo("1970-01-01T00:01:00.000Z"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testDifferentSearchType() throws Exception {
|
public void testDifferentSearchType() throws Exception {
|
||||||
WatchExecutionContext ctx = createContext();
|
WatchExecutionContext ctx = createContext();
|
||||||
|
|
||||||
SearchSourceBuilder searchSourceBuilder = searchSource().query(boolQuery()
|
SearchSourceBuilder searchSourceBuilder = searchSource().query(boolQuery()
|
||||||
.must(matchQuery("event_type", "a"))
|
.must(matchQuery("event_type", "a")));
|
||||||
.must(rangeQuery("_timestamp")
|
|
||||||
.from("{{ctx.trigger.scheduled_time}}||-30s")
|
|
||||||
.to("{{ctx.trigger.triggered_time}}")));
|
|
||||||
|
|
||||||
final SearchType searchType = getRandomSupportedSearchType();
|
final SearchType searchType = getRandomSupportedSearchType();
|
||||||
SearchRequest request = client()
|
SearchRequest request = client()
|
||||||
|
@ -480,10 +258,6 @@ public class SearchTransformIT extends ESIntegTestCase {
|
||||||
assertThat(result.executedRequest().searchType(), is(searchType));
|
assertThat(result.executedRequest().searchType(), is(searchType));
|
||||||
assertThat(result.executedRequest().indices(), arrayContainingInAnyOrder(request.indices()));
|
assertThat(result.executedRequest().indices(), arrayContainingInAnyOrder(request.indices()));
|
||||||
assertThat(result.executedRequest().indicesOptions(), equalTo(request.indicesOptions()));
|
assertThat(result.executedRequest().indicesOptions(), equalTo(request.indicesOptions()));
|
||||||
|
|
||||||
XContentSource source = toXContentSource(result);
|
|
||||||
assertThat(source.getValue("query.bool.must.1.range._timestamp.from"), equalTo("1970-01-01T00:01:00.000Z||-30s"));
|
|
||||||
assertThat(source.getValue("query.bool.must.1.range._timestamp.to"), equalTo("1970-01-01T00:01:00.000Z"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private WatchExecutionContext createContext() {
|
private WatchExecutionContext createContext() {
|
||||||
|
@ -515,7 +289,7 @@ public class SearchTransformIT extends ESIntegTestCase {
|
||||||
return executableSearchTransform.execute(ctx, Payload.Simple.EMPTY);
|
return executableSearchTransform.execute(ctx, Payload.Simple.EMPTY);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected WatcherSearchTemplateService watcherSearchTemplateService() {
|
private WatcherSearchTemplateService watcherSearchTemplateService() {
|
||||||
String master = internalCluster().getMasterName();
|
String master = internalCluster().getMasterName();
|
||||||
return new WatcherSearchTemplateService(internalCluster().clusterService(master).getSettings(),
|
return new WatcherSearchTemplateService(internalCluster().clusterService(master).getSettings(),
|
||||||
internalCluster().getInstance(ScriptService.class, master),
|
internalCluster().getInstance(ScriptService.class, master),
|
||||||
|
@ -525,24 +299,10 @@ public class SearchTransformIT extends ESIntegTestCase {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ScriptService scriptService() {
|
private ScriptService scriptService() {
|
||||||
return internalCluster().getInstance(ScriptService.class);
|
return internalCluster().getInstance(ScriptService.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Map<String, Object> doc(String date, String value) {
|
|
||||||
Map<String, Object> doc = new HashMap<>();
|
|
||||||
doc.put("date", parseDate(date, UTC));
|
|
||||||
doc.put("value", value);
|
|
||||||
return doc;
|
|
||||||
}
|
|
||||||
|
|
||||||
private XContentSource toXContentSource(SearchTransform.Result result) throws IOException {
|
|
||||||
try (XContentBuilder builder = jsonBuilder()) {
|
|
||||||
result.executedRequest().source().toXContent(builder, ToXContent.EMPTY_PARAMS);
|
|
||||||
return new XContentSource(builder);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom plugin that registers XPack script context.
|
* Custom plugin that registers XPack script context.
|
||||||
*/
|
*/
|
Loading…
Reference in New Issue