Tests: Remove @ClusterScope tests, create REST tests (elastic/x-pack-elasticsearch#2131)

Replacing integration tests with rest tests and unit tests, thus removing integration tests that require start of a new cluster. Removing unused testing methods

Original commit: elastic/x-pack-elasticsearch@265966d80c
This commit is contained in:
Alexander Reelsen 2017-08-01 14:15:36 +02:00 committed by GitHub
parent 547b0ebc1b
commit 4bf5d9536a
11 changed files with 279 additions and 468 deletions

View File

@ -1,89 +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.xpack.watcher;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import org.elasticsearch.client.http.HttpStatus;
import org.elasticsearch.action.admin.cluster.node.info.NodeInfo;
import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse;
import org.elasticsearch.action.support.AutoCreateIndex;
import org.elasticsearch.client.ResponseException;
import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.transport.Netty4Plugin;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.threadpool.ThreadPoolInfo;
import org.elasticsearch.xpack.XPackPlugin;
import org.elasticsearch.xpack.XPackSettings;
import org.elasticsearch.xpack.ml.MachineLearning;
import org.elasticsearch.xpack.watcher.execution.InternalWatchExecutor;
import static org.elasticsearch.test.ESIntegTestCase.Scope.SUITE;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
@ClusterScope(scope = SUITE, numClientNodes = 0, transportClientRatio = 0, maxNumDataNodes = 3)
public class WatcherPluginDisableTests extends ESIntegTestCase {
@Override
protected Settings nodeSettings(int nodeOrdinal) {
return Settings.builder()
.put(super.nodeSettings(nodeOrdinal))
.put(XPackSettings.WATCHER_ENABLED.getKey(), false)
// prevent auto index creation, as watcher is disabled this should work
.put(AutoCreateIndex.AUTO_CREATE_INDEX_SETTING.getKey(), false)
// disable security because of query cache check and authentication/authorization
.put(XPackSettings.SECURITY_ENABLED.getKey(), false)
.put(XPackSettings.MONITORING_ENABLED.getKey(), false)
.put(NetworkModule.HTTP_ENABLED.getKey(), true)
// Disable native ML autodetect_process as the c++ controller won't be available
.put(MachineLearning.AUTODETECT_PROCESS.getKey(), false)
.build();
}
@Override
protected Collection<Class<? extends Plugin>> nodePlugins() {
return Arrays.asList(XPackPlugin.class, Netty4Plugin.class);
}
@Override
protected Collection<Class<? extends Plugin>> transportClientPlugins() {
return Collections.<Class<? extends Plugin>>singleton(XPackPlugin.class);
}
@Override
protected Settings transportClientSettings() {
return Settings.builder()
.put(super.transportClientSettings())
.build();
}
public void testRestEndpoints() throws Exception {
try {
getRestClient().performRequest("GET", "/_xpack/watcher/watch/my-watch");
fail("request should have failed");
} catch(ResponseException e) {
assertThat(e.getResponse().getStatusLine().getStatusCode(), is(HttpStatus.SC_BAD_REQUEST));
}
}
public void testThreadPools() throws Exception {
NodesInfoResponse nodesInfo = client().admin().cluster().prepareNodesInfo().setThreadPool(true).get();
for (NodeInfo nodeInfo : nodesInfo.getNodes()) {
ThreadPoolInfo threadPoolInfo = nodeInfo.getThreadPool();
for (ThreadPool.Info info : threadPoolInfo) {
assertThat(info.getName(), not(is(InternalWatchExecutor.THREAD_POOL_NAME)));
}
}
}
}

View File

@ -6,9 +6,20 @@
package org.elasticsearch.xpack.watcher;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import org.elasticsearch.index.IndexModule;
import org.elasticsearch.index.IndexSettings;
import org.elasticsearch.index.analysis.AnalysisRegistry;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.IndexSettingsModule;
import org.elasticsearch.threadpool.ExecutorBuilder;
import org.elasticsearch.xpack.watcher.watch.Watch;
import java.util.List;
import static java.util.Collections.emptyMap;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.hasSize;
public class WatcherPluginTests extends ESTestCase {
@ -39,4 +50,28 @@ public class WatcherPluginTests extends ESTestCase {
assertThat(exception.getMessage(), containsString("[.watches, .triggered_watches, .watcher-history-*]"));
}
public void testWatcherDisabledTests() {
Settings settings = Settings.builder()
.put("xpack.watcher.enabled", false)
.put("path.home", createTempDir())
.build();
Watcher watcher = new Watcher(settings);
List<ExecutorBuilder<?>> executorBuilders = watcher.getExecutorBuilders(settings);
assertThat(executorBuilders, hasSize(0));
assertThat(watcher.nodeModules(), hasSize(1));
assertThat(watcher.getActions(), hasSize(0));
assertThat(watcher.getRestHandlers(settings, null, null, null, null, null, null), hasSize(0));
// ensure index module is not called, even if watches index is tried
IndexSettings indexSettings = IndexSettingsModule.newIndexSettings(Watch.INDEX, settings);
AnalysisRegistry registry = new AnalysisRegistry(new Environment(settings), emptyMap(), emptyMap(), emptyMap(), emptyMap(),
emptyMap(), emptyMap(), emptyMap(), emptyMap());
IndexModule indexModule = new IndexModule(indexSettings, registry);
// this will trip an assertion if the watcher indexing operation listener is null (which it is) but we try to add it
watcher.onIndexModule(indexModule);
// also no component creation if not enabled
assertThat(watcher.createComponents(null, null, null, null, null, null, null, null, null, null, null), hasSize(0));
}
}

View File

@ -8,6 +8,7 @@ package org.elasticsearch.xpack.watcher.support;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.watcher.execution.WatchExecutionContext;
import org.elasticsearch.xpack.watcher.execution.Wid;
import org.elasticsearch.xpack.watcher.support.xcontent.ObjectPath;
import org.elasticsearch.xpack.watcher.test.WatcherTestUtils;
import org.elasticsearch.xpack.watcher.trigger.TriggerEvent;
import org.elasticsearch.xpack.watcher.trigger.schedule.ScheduleTriggerEvent;
@ -17,7 +18,6 @@ import org.joda.time.DateTime;
import java.util.Map;
import static java.util.Collections.singletonMap;
import static org.elasticsearch.xpack.watcher.test.WatcherTestUtils.assertValue;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
@ -43,11 +43,12 @@ public class VariablesTests extends ESTestCase {
Map<String, Object> model = Variables.createCtxModel(ctx, payload);
assertThat(model, notNullValue());
assertThat(model.size(), is(1));
assertValue(model, "ctx", instanceOf(Map.class));
assertValue(model, "ctx.id", is(wid.value()));
assertValue(model, "ctx.execution_time", is(executionTime));
assertValue(model, "ctx.trigger", is(event.data()));
assertValue(model, "ctx.payload", is(payload.data()));
assertValue(model, "ctx.metadata", is(metatdata));
assertThat(ObjectPath.eval("ctx", model), instanceOf(Map.class));
assertThat(ObjectPath.eval("ctx.id", model), is(wid.value()));
assertThat(ObjectPath.eval("ctx.execution_time", model), is(executionTime));
assertThat(ObjectPath.eval("ctx.trigger", model), is(event.data()));
assertThat(ObjectPath.eval("ctx.payload", model), is(payload.data()));
assertThat(ObjectPath.eval("ctx.metadata", model), is(metatdata));
}
}

View File

@ -50,7 +50,6 @@ import org.elasticsearch.xpack.TimeWarpedXPackPlugin;
import org.elasticsearch.xpack.XPackClient;
import org.elasticsearch.xpack.XPackPlugin;
import org.elasticsearch.xpack.XPackSettings;
import org.elasticsearch.xpack.common.http.HttpClient;
import org.elasticsearch.xpack.ml.MachineLearning;
import org.elasticsearch.xpack.notification.email.Authentication;
import org.elasticsearch.xpack.notification.email.Email;
@ -441,24 +440,12 @@ public abstract class AbstractWatcherIntegrationTestCase extends ESIntegTestCase
return randomBoolean() ? new XPackClient(client).watcher() : new WatcherClient(client);
}
protected HttpClient watcherHttpClient() {
return internalCluster().getInstance(HttpClient.class);
}
protected EmailService noopEmailService() {
return new NoopEmailService();
}
protected IndexNameExpressionResolver indexNameExpressionResolver() {
return internalCluster().getInstance(IndexNameExpressionResolver.class);
}
protected void assertValue(XContentSource source, String path, Matcher<?> matcher) {
WatcherTestUtils.assertValue(source, path, matcher);
}
protected void assertValue(Map<String, Object> map, String path, Matcher<?> matcher) {
WatcherTestUtils.assertValue(map, path, matcher);
assertThat(source.getValue(path), (Matcher<Object>) matcher);
}
protected void assertWatchWithMinimumPerformedActionsCount(final String watchName,

View File

@ -6,23 +6,15 @@
package org.elasticsearch.xpack.watcher.test;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.script.ScriptContext;
import org.elasticsearch.script.ScriptModule;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.xpack.common.http.HttpClient;
import org.elasticsearch.xpack.common.http.HttpMethod;
import org.elasticsearch.xpack.common.http.HttpRequestTemplate;
@ -34,7 +26,6 @@ import org.elasticsearch.xpack.notification.email.EmailService;
import org.elasticsearch.xpack.notification.email.EmailTemplate;
import org.elasticsearch.xpack.notification.email.HtmlSanitizer;
import org.elasticsearch.xpack.notification.email.Profile;
import org.elasticsearch.xpack.watcher.Watcher;
import org.elasticsearch.xpack.watcher.actions.ActionStatus;
import org.elasticsearch.xpack.watcher.actions.ActionWrapper;
import org.elasticsearch.xpack.watcher.actions.email.EmailAction;
@ -48,7 +39,6 @@ import org.elasticsearch.xpack.watcher.input.simple.ExecutableSimpleInput;
import org.elasticsearch.xpack.watcher.input.simple.SimpleInput;
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateRequest;
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateService;
import org.elasticsearch.xpack.watcher.support.xcontent.ObjectPath;
import org.elasticsearch.xpack.watcher.support.xcontent.XContentSource;
import org.elasticsearch.xpack.watcher.transform.search.ExecutableSearchTransform;
import org.elasticsearch.xpack.watcher.transform.search.SearchTransform;
@ -58,7 +48,6 @@ import org.elasticsearch.xpack.watcher.trigger.schedule.ScheduleTrigger;
import org.elasticsearch.xpack.watcher.watch.Payload;
import org.elasticsearch.xpack.watcher.watch.Watch;
import org.elasticsearch.xpack.watcher.watch.WatchStatus;
import org.hamcrest.Matcher;
import org.joda.time.DateTime;
import javax.mail.internet.AddressException;
@ -69,13 +58,11 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.apache.lucene.util.LuceneTestCase.createTempDir;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
import static org.elasticsearch.search.builder.SearchSourceBuilder.searchSource;
import static org.elasticsearch.test.ESTestCase.randomFrom;
import static org.joda.time.DateTimeZone.UTC;
import static org.junit.Assert.assertThat;
public final class WatcherTestUtils {
@ -87,14 +74,6 @@ public final class WatcherTestUtils {
return new XContentSource(bytes, xContent.type());
}
public static void assertValue(Map<String, Object> map, String path, Matcher<?> matcher) {
assertThat(ObjectPath.eval(path, map), (Matcher<Object>) matcher);
}
public static void assertValue(XContentSource source, String path, Matcher<?> matcher) {
assertThat(source.getValue(path), (Matcher<Object>) matcher);
}
public static WatcherSearchTemplateRequest templateRequest(SearchSourceBuilder sourceBuilder, String... indices) {
return templateRequest(sourceBuilder, SearchType.DEFAULT, indices);
}
@ -111,19 +90,6 @@ public final class WatcherTestUtils {
}
}
public static SearchRequest matchAllRequest(IndicesOptions indicesOptions) {
SearchRequest request = new SearchRequest(Strings.EMPTY_ARRAY)
.source(SearchSourceBuilder.searchSource().query(matchAllQuery()));
if (indicesOptions != null) {
request.indicesOptions(indicesOptions);
}
return request;
}
public static Payload simplePayload(String key, Object value) {
return new Payload.Simple(key, value);
}
public static WatchExecutionContextMockBuilder mockExecutionContextBuilder(String watchId) {
return new WatchExecutionContextMockBuilder(watchId)
.wid(new Wid(watchId, DateTime.now(UTC)));
@ -153,14 +119,6 @@ public final class WatcherTestUtils {
.buildMock();
}
public static Watch createTestWatch(String watchName, HttpClient httpClient, EmailService emailService,
WatcherSearchTemplateService searchTemplateService, Logger logger) throws AddressException {
Client client = ESIntegTestCase.client();
return createTestWatch(watchName, client, httpClient, emailService, searchTemplateService, logger);
}
public static Watch createTestWatch(String watchName, Client client, HttpClient httpClient, EmailService emailService,
WatcherSearchTemplateService searchTemplateService, Logger logger) throws AddressException {
List<ActionWrapper> actions = new ArrayList<>();
@ -201,16 +159,6 @@ public final class WatcherTestUtils {
new WatchStatus(now, statuses));
}
public static ScriptService createScriptService(ThreadPool tp) throws Exception {
Settings settings = Settings.builder()
.put("path.home", createTempDir())
.build();
Map<String, ScriptContext> contexts = new HashMap<>(ScriptModule.CORE_CONTEXTS);
contexts.put(Watcher.SCRIPT_EXECUTABLE_CONTEXT.name, Watcher.SCRIPT_EXECUTABLE_CONTEXT);
contexts.put(Watcher.SCRIPT_TEMPLATE_CONTEXT.name, Watcher.SCRIPT_TEMPLATE_CONTEXT);
return new ScriptService(settings, Collections.emptyMap(), Collections.emptyMap());
}
public static SearchType getRandomSupportedSearchType() {
return randomFrom(SearchType.QUERY_THEN_FETCH, SearchType.DFS_QUERY_THEN_FETCH);
}

View File

@ -16,6 +16,7 @@ import org.elasticsearch.xpack.watcher.support.xcontent.XContentSource;
import org.elasticsearch.xpack.watcher.test.AbstractWatcherIntegrationTestCase;
import org.elasticsearch.xpack.watcher.transport.actions.execute.ExecuteWatchResponse;
import org.elasticsearch.xpack.watcher.transport.actions.put.PutWatchResponse;
import org.hamcrest.Matcher;
import java.util.HashMap;
import java.util.List;
@ -235,4 +236,8 @@ public class ExecutionVarsIntegrationTests extends AbstractWatcherIntegrationTes
}
}
}
private static void assertValue(Map<String, Object> map, String path, Matcher<?> matcher) {
assertThat(ObjectPath.eval(path, map), (Matcher<Object>) matcher);
}
}

View File

@ -5,179 +5,36 @@
*/
package org.elasticsearch.xpack.watcher.test.integration;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.client.Client;
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.support.XContentMapValues;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.plugins.ScriptPlugin;
import org.elasticsearch.script.MockMustacheScriptEngine;
import org.elasticsearch.script.MockScriptEngine;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptContext;
import org.elasticsearch.script.ScriptEngine;
import org.elasticsearch.script.ScriptModule;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.ScriptType;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.common.text.TextTemplate;
import org.elasticsearch.xpack.watcher.Watcher;
import org.elasticsearch.xpack.watcher.condition.AlwaysCondition;
import org.elasticsearch.xpack.watcher.execution.TriggeredExecutionContext;
import org.elasticsearch.xpack.watcher.execution.WatchExecutionContext;
import org.elasticsearch.xpack.watcher.input.simple.ExecutableSimpleInput;
import org.elasticsearch.xpack.watcher.input.simple.SimpleInput;
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateRequest;
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateService;
import org.elasticsearch.xpack.watcher.transform.Transform;
import org.elasticsearch.xpack.watcher.transform.TransformBuilders;
import org.elasticsearch.xpack.watcher.transform.search.ExecutableSearchTransform;
import org.elasticsearch.xpack.watcher.transform.search.SearchTransform;
import org.elasticsearch.xpack.watcher.transform.search.SearchTransformFactory;
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.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
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.search.builder.SearchSourceBuilder.searchSource;
import static org.elasticsearch.test.ESIntegTestCase.Scope.SUITE;
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.templateRequest;
import static org.hamcrest.Matchers.arrayContainingInAnyOrder;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasKey;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.joda.time.DateTimeZone.UTC;
import static org.mockito.Mockito.mock;
@ClusterScope(scope = SUITE, numClientNodes = 0, transportClientRatio = 0, supportsDedicatedMasters = false,
numDataNodes = 1)
public class SearchTransformTests extends ESIntegTestCase {
@Override
protected Collection<Class<? extends Plugin>> nodePlugins() {
Collection<Class<? extends Plugin>> plugins = new ArrayList<>();
plugins.addAll(super.nodePlugins());
plugins.add(CustomScriptContextPlugin.class);
plugins.add(MockMustacheScriptEngine.TestPlugin.class);
return plugins;
}
@Override
public Settings indexSettings() {
return Settings.builder()
.put(super.indexSettings())
// 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.
.put("index.number_of_shards", randomIntBetween(2, 5))
.build();
}
public void testExecute() throws Exception {
index("idx", "type", "1");
ensureGreen("idx");
refresh();
WatcherSearchTemplateRequest request = templateRequest(new SearchSourceBuilder().query(QueryBuilders.matchAllQuery()), "idx");
SearchTransform searchTransform = TransformBuilders.searchTransform(request).build();
ExecutableSearchTransform transform = new ExecutableSearchTransform(searchTransform, logger, client(),
watcherSearchTemplateService(), TimeValue.timeValueMinutes(1));
WatchExecutionContext ctx = mockExecutionContext("_name", Payload.EMPTY);
Transform.Result result = transform.execute(ctx, Payload.EMPTY);
assertThat(result, notNullValue());
assertThat(result.type(), is(SearchTransform.TYPE));
assertThat(result.status(), is(Transform.Result.Status.SUCCESS));
SearchResponse response = client().prepareSearch("idx").get();
Payload expectedPayload = new Payload.XContent(response);
// we need to remove the "took" and "num_reduce_phases" fields from the response
// as they are the only fields most likely different between the two... we don't
// really care about these fields, 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");
resultData.remove("num_reduce_phases");
Map<String, Object> expectedData = expectedPayload.data();
expectedData.remove("took");
expectedData.remove("num_reduce_phases");
assertThat(resultData, equalTo(expectedData));
}
@SuppressWarnings("unchecked")
public void testExecuteFailure() throws Exception {
index("idx", "type", "1");
ensureGreen("idx");
refresh();
// create a bad request
WatcherSearchTemplateRequest request = templateRequest(new SearchSourceBuilder().query(
QueryBuilders.wrapperQuery(jsonBuilder().startObject()
.startObject("_unknown_query_").endObject().endObject().bytes())), "idx");
SearchTransform searchTransform = TransformBuilders.searchTransform(request).build();
ExecutableSearchTransform transform = new ExecutableSearchTransform(searchTransform, logger, client(),
watcherSearchTemplateService(), TimeValue.timeValueMinutes(1));
WatchExecutionContext ctx = mockExecutionContext("_name", Payload.EMPTY);
SearchTransform.Result result = transform.execute(ctx, Payload.EMPTY);
assertThat(result, notNullValue());
assertThat(result.type(), is(SearchTransform.TYPE));
assertThat(result.status(), is(Transform.Result.Status.FAILURE));
assertThat(result.reason(), notNullValue());
assertThat(result.reason(), containsString("no [query] registered for [_unknown_query_]"));
// extract the base64 encoded query from the template script, path is: query -> wrapper -> query
try (XContentBuilder builder = jsonBuilder()) {
result.executedRequest().toXContent(builder, ToXContent.EMPTY_PARAMS);
Map<String, Object> map = createParser(builder).map();
assertThat(map, hasKey("body"));
assertThat(map.get("body"), instanceOf(Map.class));
map = (Map<String, Object>) map.get("body");
assertThat(map, hasKey("query"));
assertThat(map.get("query"), instanceOf(Map.class));
map = (Map<String, Object>) map.get("query");
assertThat(map, hasKey("wrapper"));
assertThat(map.get("wrapper"), instanceOf(Map.class));
map = (Map<String, Object>) map.get("wrapper");
assertThat(map, hasKey("query"));
assertThat(map.get("query"), instanceOf(String.class));
String queryAsBase64 = (String) map.get("query");
String decodedQuery = new String(Base64.getDecoder().decode(queryAsBase64), StandardCharsets.UTF_8);
assertThat(decodedQuery, containsString("_unknown_query_"));
}
}
public class SearchTransformTests extends ESTestCase {
public void testParser() throws Exception {
String[] indices = rarely() ? null : randomBoolean() ? new String[] { "idx" } : new String[] { "idx1", "idx2" };
@ -213,7 +70,12 @@ public class SearchTransformTests extends ESIntegTestCase {
XContentParser parser = createParser(builder);
parser.nextToken();
SearchTransformFactory transformFactory = new SearchTransformFactory(Settings.EMPTY, client(), xContentRegistry(), scriptService());
final MockScriptEngine engine = new MockScriptEngine("mock", Collections.emptyMap());
Map<String, ScriptEngine> engines = Collections.singletonMap(engine.getType(), engine);
ScriptService scriptService = new ScriptService(Settings.EMPTY, engines, ScriptModule.CORE_CONTEXTS);
Client client = mock(Client.class);
SearchTransformFactory transformFactory = new SearchTransformFactory(Settings.EMPTY, client, xContentRegistry(), scriptService);
ExecutableSearchTransform executable = transformFactory.parseExecutable("_id", parser);
assertThat(executable, notNullValue());
@ -232,73 +94,4 @@ public class SearchTransformTests extends ESIntegTestCase {
assertThat(executable.transform().getRequest().getSearchSource().utf8ToString(), equalTo("{\"query\":{\"match_all\":{}}}"));
assertThat(executable.transform().getTimeout(), equalTo(readTimeout));
}
public void testDifferentSearchType() throws Exception {
WatchExecutionContext ctx = createContext();
SearchSourceBuilder searchSourceBuilder = searchSource().query(boolQuery()
.must(matchQuery("event_type", "a")));
final SearchType searchType = getRandomSupportedSearchType();
WatcherSearchTemplateRequest request = templateRequest(searchSourceBuilder, searchType, "test-search-index");
SearchTransform.Result result = executeSearchTransform(request, ctx);
assertThat(XContentMapValues.extractValue("hits.total", result.payload().data()), equalTo(0));
assertThat(result.executedRequest(), notNullValue());
assertThat(result.status(), is(Transform.Result.Status.SUCCESS));
assertThat(result.executedRequest().getSearchType(), is(searchType));
assertThat(result.executedRequest().getIndices(), arrayContainingInAnyOrder(request.getIndices()));
assertThat(result.executedRequest().getIndicesOptions(), equalTo(request.getIndicesOptions()));
}
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),
AlwaysCondition.INSTANCE,
null,
null,
new ArrayList<>(),
null,
new WatchStatus( new DateTime(40000, UTC), emptyMap())),
new DateTime(60000, UTC),
new ScheduleTriggerEvent("test-watch", new DateTime(60000, UTC), new DateTime(60000, UTC)),
timeValueSeconds(5));
}
private SearchTransform.Result executeSearchTransform(WatcherSearchTemplateRequest request, WatchExecutionContext ctx)
throws IOException {
createIndex("test-search-index");
ensureGreen("test-search-index");
SearchTransform searchTransform = TransformBuilders.searchTransform(request).build();
ExecutableSearchTransform executableSearchTransform = new ExecutableSearchTransform(searchTransform, logger,
client(), watcherSearchTemplateService(), TimeValue.timeValueMinutes(1));
return executableSearchTransform.execute(ctx, Payload.Simple.EMPTY);
}
private WatcherSearchTemplateService watcherSearchTemplateService() {
String master = internalCluster().getMasterName();
return new WatcherSearchTemplateService(internalCluster().clusterService(master).getSettings(),
internalCluster().getInstance(ScriptService.class, master),
xContentRegistry()
);
}
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 List<ScriptContext> getContexts() {
return Collections.singletonList(Watcher.SCRIPT_TEMPLATE_CONTEXT);
}
}
}

View File

@ -10,21 +10,20 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.script.ExecutableScript;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptContext;
import org.elasticsearch.script.ScriptException;
import org.elasticsearch.script.ScriptModule;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.ScriptType;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.threadpool.TestThreadPool;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.xpack.watcher.Watcher;
import org.elasticsearch.xpack.watcher.execution.WatchExecutionContext;
import org.elasticsearch.xpack.watcher.support.Variables;
import org.elasticsearch.xpack.watcher.transform.Transform;
import org.elasticsearch.xpack.watcher.watch.Payload;
import org.junit.After;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import static java.util.Collections.emptyMap;
@ -32,9 +31,7 @@ import static java.util.Collections.singleton;
import static java.util.Collections.singletonMap;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.xpack.watcher.support.Exceptions.illegalArgument;
import static org.elasticsearch.xpack.watcher.test.WatcherTestUtils.createScriptService;
import static org.elasticsearch.xpack.watcher.test.WatcherTestUtils.mockExecutionContext;
import static org.elasticsearch.xpack.watcher.test.WatcherTestUtils.simplePayload;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasEntry;
@ -47,13 +44,6 @@ import static org.mockito.Mockito.when;
public class ScriptTransformTests extends ESTestCase {
private final ThreadPool tp = new TestThreadPool(ThreadPool.Names.SAME);
@After
public void cleanup() {
tp.shutdownNow();
}
public void testExecuteMapValue() throws Exception {
ScriptService service = mock(ScriptService.class);
ScriptType type = randomFrom(ScriptType.values());
@ -65,7 +55,7 @@ public class ScriptTransformTests extends ESTestCase {
WatchExecutionContext ctx = mockExecutionContext("_name", Payload.EMPTY);
Payload payload = simplePayload("key", "value");
Payload payload = new Payload.Simple("key", "value");
Map<String, Object> model = Variables.createCtxModel(ctx, payload);
@ -93,7 +83,7 @@ public class ScriptTransformTests extends ESTestCase {
WatchExecutionContext ctx = mockExecutionContext("_name", Payload.EMPTY);
Payload payload = simplePayload("key", "value");
Payload payload = new Payload.Simple("key", "value");
Map<String, Object> model = Variables.createCtxModel(ctx, payload);
@ -119,7 +109,7 @@ public class ScriptTransformTests extends ESTestCase {
WatchExecutionContext ctx = mockExecutionContext("_name", Payload.EMPTY);
Payload payload = simplePayload("key", "value");
Payload payload = new Payload.Simple("key", "value");
Map<String, Object> model = Variables.createCtxModel(ctx, payload);
@ -185,7 +175,7 @@ public class ScriptTransformTests extends ESTestCase {
}
public void testScriptConditionParserBadLang() throws Exception {
ScriptTransformFactory transformFactory = new ScriptTransformFactory(Settings.builder().build(), createScriptService(tp));
ScriptTransformFactory transformFactory = new ScriptTransformFactory(Settings.builder().build(), createScriptService());
String script = "return true";
XContentBuilder builder = jsonBuilder().startObject()
.field(scriptTypeField(ScriptType.INLINE), script)
@ -209,4 +199,14 @@ public class ScriptTransformTests extends ESTestCase {
throw illegalArgument("unsupported script type [{}]", type);
}
}
public static ScriptService createScriptService() throws Exception {
Settings settings = Settings.builder()
.put("path.home", createTempDir())
.build();
Map<String, ScriptContext> contexts = new HashMap<>(ScriptModule.CORE_CONTEXTS);
contexts.put(Watcher.SCRIPT_EXECUTABLE_CONTEXT.name, Watcher.SCRIPT_EXECUTABLE_CONTEXT);
contexts.put(Watcher.SCRIPT_TEMPLATE_CONTEXT.name, Watcher.SCRIPT_TEMPLATE_CONTEXT);
return new ScriptService(settings, Collections.emptyMap(), Collections.emptyMap());
}
}

View File

@ -1,69 +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.xpack.watcher.transport.action.stats;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
import org.elasticsearch.xpack.watcher.WatcherState;
import org.elasticsearch.xpack.watcher.condition.CompareCondition;
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateRequest;
import org.elasticsearch.xpack.watcher.test.AbstractWatcherIntegrationTestCase;
import org.elasticsearch.xpack.watcher.transport.actions.delete.DeleteWatchResponse;
import org.elasticsearch.xpack.watcher.transport.actions.stats.WatcherStatsResponse;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.search.builder.SearchSourceBuilder.searchSource;
import static org.elasticsearch.test.ESIntegTestCase.Scope.TEST;
import static org.elasticsearch.xpack.watcher.client.WatchSourceBuilders.watchBuilder;
import static org.elasticsearch.xpack.watcher.input.InputBuilders.searchInput;
import static org.elasticsearch.xpack.watcher.test.WatcherTestUtils.templateRequest;
import static org.elasticsearch.xpack.watcher.trigger.TriggerBuilders.schedule;
import static org.elasticsearch.xpack.watcher.trigger.schedule.Schedules.cron;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.is;
@ClusterScope(scope = TEST, numClientNodes = 0, transportClientRatio = 0)
public class WatcherStatsTests extends AbstractWatcherIntegrationTestCase {
@Override
protected boolean timeWarped() {
return true;
}
public void testStartedStats() throws Exception {
WatcherStatsResponse response = watcherClient().prepareWatcherStats().get();
assertThat(response.getWatchesCount(), is(0L));
response.getNodes().forEach(nodeResponse -> {
assertThat(nodeResponse.getThreadPoolQueueSize(), is(0L));
assertThat(nodeResponse.getThreadPoolMaxSize(), is(timeWarped() ? 1L : 0L));
});
boolean isWatcherStarted = response.getNodes().stream().allMatch(node -> node.getWatcherState() == WatcherState.STARTED);
assertThat("expected watcher to be started on all nodes", isWatcherStarted, is(true));
}
public void testWatchCountStats() throws Exception {
WatcherSearchTemplateRequest request = templateRequest(searchSource().query(termQuery("field", "value")), "idx");
watcherClient().preparePutWatch("_name")
.setSource(watchBuilder()
.trigger(schedule(cron("* * * * * ? *")))
.input(searchInput(request))
.condition(new CompareCondition("ctx.payload.hits.total", CompareCondition.Op.EQ, 1L))
)
.get();
timeWarp().trigger("_name", 30, TimeValue.timeValueSeconds(1));
WatcherStatsResponse response = watcherClient().prepareWatcherStats().get();
assertThat(response.getWatchesCount(), is(1L));
response.getNodes().forEach(nodeResponse -> assertThat(nodeResponse.getThreadPoolMaxSize(), greaterThan(0L)));
DeleteWatchResponse deleteWatchResponse = watcherClient().prepareDeleteWatch("_name").get();
assertThat(deleteWatchResponse.isFound(), is(true));
}
}

View File

@ -0,0 +1,195 @@
---
setup:
- do:
cluster.health:
wait_for_status: yellow
---
"Test execute watch api with configured search transform":
- do:
index:
index: my_test_index
type: doc
id: my_id
refresh: true
body: >
{
"key": "value"
}
- do:
xpack.watcher.execute_watch:
body: >
{
"watch" : {
"trigger": {
"schedule" : { "cron" : "0 0 0 1 * ? 2099" }
},
"input": {
"simple": {
"foo": "bar"
}
},
"condition": {
"always": {}
},
"transform" : {
"search" : {
"request" : {
"indices" : [ "my_test_index" ],
"body" : {
"query": {
"match_all" : {}
}
}
}
}
},
"actions": {
"indexme" : {
"index" : {
"index" : "my-index",
"doc_type" : "my-type",
"doc_id": "my-id"
}
}
}
}
}
- match: { watch_record.trigger_event.type: "manual" }
- match: { watch_record.state: "executed" }
- match: { watch_record.result.transform.status: "success" }
- do:
get:
index: my_test_index
type: doc
id: my_id
- match: { _source.key: "value" }
---
"Test execute watch api with configured search transform using DFS_QUERY_THEN_FETCH":
- do:
indices.create:
index: my_test_index
body:
settings:
number_of_shards: "2"
number_of_replicas: "0"
- do:
index:
index: my_test_index
type: doc
id: my_id
refresh: true
body: >
{
"key": "value"
}
- do:
xpack.watcher.execute_watch:
body: >
{
"watch" : {
"trigger": {
"schedule" : { "cron" : "0 0 0 1 * ? 2099" }
},
"input": {
"simple": {
"foo": "bar"
}
},
"condition": {
"always": {}
},
"transform" : {
"search" : {
"request" : {
"search_type" : "dfs_query_then_fetch",
"indices" : [ "my_test_index" ],
"body" : {
"query": {
"match_all" : {}
}
}
}
}
},
"actions": {
"indexme" : {
"index" : {
"index" : "my-index",
"doc_type" : "my-type",
"doc_id": "my-id"
}
}
}
}
}
- match: { watch_record.trigger_event.type: "manual" }
- match: { watch_record.state: "executed" }
- match: { watch_record.result.transform.status: "success" }
- do:
get:
index: my_test_index
type: doc
id: my_id
- match: { _source.key: "value" }
---
"Test execute watch api with misconfigured search transform on failure":
- do:
indices.create:
index: my_test_index
- do:
xpack.watcher.execute_watch:
body: >
{
"watch" : {
"trigger": {
"schedule" : { "cron" : "0 0 0 1 * ? 2099" }
},
"input": {
"simple": {
"foo": "bar"
}
},
"condition": {
"always": {}
},
"transform" : {
"search" : {
"request" : {
"indices" : [ "my_test_index" ],
"body" : {
"query": {
"does_not_exist" : {}
}
}
}
}
},
"actions": {
"indexme" : {
"index" : {
"index" : "my-index",
"doc_type" : "my-type",
"doc_id": "my-id"
}
}
}
}
}
- match: { watch_record.trigger_event.type: "manual" }
- match: { watch_record.state: "executed" }
- match: { watch_record.result.transform.status: "failure" }
- match: { watch_record.result.transform.reason: "ParsingException[no [query] registered for [does_not_exist]]" }

View File

@ -13,6 +13,11 @@ watcher_manager:
- names: '.watch*'
privileges:
- all
# this index gets created by one of the watcher yaml tests
# and is needed for a search transform, so we have to create it as part of the test
- names: 'my_test_index'
privileges:
- all
run_as:
- powerless_user
- watcher_manager