|
@@ -7,15 +7,23 @@ package org.elasticsearch.xpack.watcher.execution;
|
|
|
|
|
|
import org.elasticsearch.ElasticsearchException;
|
|
|
import org.elasticsearch.Version;
|
|
|
+import org.elasticsearch.action.ActionListener;
|
|
|
+import org.elasticsearch.action.DocWriteRequest;
|
|
|
+import org.elasticsearch.action.admin.indices.refresh.RefreshAction;
|
|
|
import org.elasticsearch.action.admin.indices.refresh.RefreshResponse;
|
|
|
+import org.elasticsearch.action.bulk.BulkAction;
|
|
|
+import org.elasticsearch.action.bulk.BulkItemResponse;
|
|
|
+import org.elasticsearch.action.bulk.BulkProcessor;
|
|
|
+import org.elasticsearch.action.bulk.BulkRequest;
|
|
|
+import org.elasticsearch.action.bulk.BulkResponse;
|
|
|
+import org.elasticsearch.action.index.IndexResponse;
|
|
|
+import org.elasticsearch.action.search.ClearScrollAction;
|
|
|
import org.elasticsearch.action.search.ClearScrollResponse;
|
|
|
-import org.elasticsearch.action.search.SearchRequest;
|
|
|
+import org.elasticsearch.action.search.SearchAction;
|
|
|
import org.elasticsearch.action.search.SearchResponse;
|
|
|
+import org.elasticsearch.action.search.SearchScrollAction;
|
|
|
import org.elasticsearch.action.search.SearchScrollRequest;
|
|
|
-import org.elasticsearch.action.support.PlainActionFuture;
|
|
|
-import org.elasticsearch.client.AdminClient;
|
|
|
import org.elasticsearch.client.Client;
|
|
|
-import org.elasticsearch.client.IndicesAdminClient;
|
|
|
import org.elasticsearch.cluster.ClusterName;
|
|
|
import org.elasticsearch.cluster.ClusterState;
|
|
|
import org.elasticsearch.cluster.metadata.AliasMetaData;
|
|
@@ -65,6 +73,9 @@ import org.junit.Before;
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.Collection;
|
|
|
import java.util.Collections;
|
|
|
+import java.util.LinkedHashMap;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
|
|
|
import static java.util.Collections.singleton;
|
|
|
import static org.hamcrest.Matchers.equalTo;
|
|
@@ -79,7 +90,6 @@ import static org.mockito.Mockito.doAnswer;
|
|
|
import static org.mockito.Mockito.mock;
|
|
|
import static org.mockito.Mockito.times;
|
|
|
import static org.mockito.Mockito.verify;
|
|
|
-import static org.mockito.Mockito.verifyZeroInteractions;
|
|
|
import static org.mockito.Mockito.when;
|
|
|
|
|
|
public class TriggeredWatchStoreTests extends ESTestCase {
|
|
@@ -92,15 +102,34 @@ public class TriggeredWatchStoreTests extends ESTestCase {
|
|
|
private Client client;
|
|
|
private TriggeredWatch.Parser parser;
|
|
|
private TriggeredWatchStore triggeredWatchStore;
|
|
|
+ private final Map<BulkRequest, BulkResponse> bulks = new LinkedHashMap<>();
|
|
|
+ private BulkProcessor.Listener listener = new BulkProcessor.Listener() {
|
|
|
+ @Override
|
|
|
+ public void beforeBulk(long executionId, BulkRequest request) {
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void afterBulk(long executionId, BulkRequest request, BulkResponse response) {
|
|
|
+ bulks.put(request, response);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void afterBulk(long executionId, BulkRequest request, Throwable failure) {
|
|
|
+ throw new ElasticsearchException(failure);
|
|
|
+ }
|
|
|
+ };
|
|
|
|
|
|
@Before
|
|
|
public void init() {
|
|
|
+ Settings settings = Settings.builder().put("node.name", randomAlphaOfLength(10)).build();
|
|
|
client = mock(Client.class);
|
|
|
ThreadPool threadPool = mock(ThreadPool.class);
|
|
|
when(client.threadPool()).thenReturn(threadPool);
|
|
|
+ when(client.settings()).thenReturn(settings);
|
|
|
when(threadPool.getThreadContext()).thenReturn(new ThreadContext(Settings.EMPTY));
|
|
|
parser = mock(TriggeredWatch.Parser.class);
|
|
|
- triggeredWatchStore = new TriggeredWatchStore(Settings.EMPTY, client, parser);
|
|
|
+ BulkProcessor bulkProcessor = BulkProcessor.builder(client, listener).setConcurrentRequests(0).setBulkActions(1).build();
|
|
|
+ triggeredWatchStore = new TriggeredWatchStore(settings, client, parser, bulkProcessor);
|
|
|
}
|
|
|
|
|
|
public void testFindTriggeredWatchesEmptyCollection() {
|
|
@@ -174,14 +203,11 @@ public class TriggeredWatchStoreTests extends ESTestCase {
|
|
|
csBuilder.routingTable(routingTableBuilder.build());
|
|
|
ClusterState cs = csBuilder.build();
|
|
|
|
|
|
- RefreshResponse refreshResponse = mockRefreshResponse(1, 1);
|
|
|
- AdminClient adminClient = mock(AdminClient.class);
|
|
|
- when(client.admin()).thenReturn(adminClient);
|
|
|
- IndicesAdminClient indicesAdminClient = mock(IndicesAdminClient.class);
|
|
|
- when(adminClient.indices()).thenReturn(indicesAdminClient);
|
|
|
- PlainActionFuture<RefreshResponse> future = PlainActionFuture.newFuture();
|
|
|
- when(indicesAdminClient.refresh(any())).thenReturn(future);
|
|
|
- future.onResponse(refreshResponse);
|
|
|
+ doAnswer(invocation -> {
|
|
|
+ ActionListener<RefreshResponse> listener = (ActionListener<RefreshResponse>) invocation.getArguments()[2];
|
|
|
+ listener.onResponse(mockRefreshResponse(1, 1));
|
|
|
+ return null;
|
|
|
+ }).when(client).execute(eq(RefreshAction.INSTANCE), any(), any());
|
|
|
|
|
|
SearchResponse searchResponse1 = mock(SearchResponse.class);
|
|
|
when(searchResponse1.getSuccessfulShards()).thenReturn(1);
|
|
@@ -194,9 +220,11 @@ public class TriggeredWatchStoreTests extends ESTestCase {
|
|
|
SearchHits hits = new SearchHits(new SearchHit[]{hit}, 1, 1.0f);
|
|
|
when(searchResponse1.getHits()).thenReturn(hits);
|
|
|
when(searchResponse1.getScrollId()).thenReturn("_scrollId");
|
|
|
- PlainActionFuture<SearchResponse> searchFuture = PlainActionFuture.newFuture();
|
|
|
- when(client.search(any(SearchRequest.class))).thenReturn(searchFuture);
|
|
|
- searchFuture.onResponse(searchResponse1);
|
|
|
+ doAnswer(invocation -> {
|
|
|
+ ActionListener<SearchResponse> listener = (ActionListener<SearchResponse>) invocation.getArguments()[2];
|
|
|
+ listener.onResponse(searchResponse1);
|
|
|
+ return null;
|
|
|
+ }).when(client).execute(eq(SearchAction.INSTANCE), any(), any());
|
|
|
|
|
|
// First return a scroll response with a single hit and then with no hits
|
|
|
hit = new SearchHit(0, "second_foo", new Text(TriggeredWatchStoreField.DOC_TYPE), null);
|
|
@@ -209,24 +237,27 @@ public class TriggeredWatchStoreTests extends ESTestCase {
|
|
|
SearchResponse searchResponse3 = new SearchResponse(InternalSearchResponse.empty(), "_scrollId2", 1, 1, 0, 1, null, null);
|
|
|
|
|
|
doAnswer(invocation -> {
|
|
|
- SearchScrollRequest request = (SearchScrollRequest) invocation.getArguments()[0];
|
|
|
- PlainActionFuture<SearchResponse> searchScrollFuture = PlainActionFuture.newFuture();
|
|
|
+ SearchScrollRequest request = (SearchScrollRequest) invocation.getArguments()[1];
|
|
|
+ ActionListener<SearchResponse> listener = (ActionListener<SearchResponse>) invocation.getArguments()[2];
|
|
|
if (request.scrollId().equals("_scrollId")) {
|
|
|
- searchScrollFuture.onResponse(searchResponse2);
|
|
|
+ listener.onResponse(searchResponse2);
|
|
|
} else if (request.scrollId().equals("_scrollId1")) {
|
|
|
- searchScrollFuture.onResponse(searchResponse3);
|
|
|
+ listener.onResponse(searchResponse3);
|
|
|
} else {
|
|
|
- searchScrollFuture.onFailure(new ElasticsearchException("test issue"));
|
|
|
+ listener.onFailure(new ElasticsearchException("test issue"));
|
|
|
}
|
|
|
- return searchScrollFuture;
|
|
|
- }).when(client).searchScroll(any());
|
|
|
+ return null;
|
|
|
+ }).when(client).execute(eq(SearchScrollAction.INSTANCE), any(), any());
|
|
|
|
|
|
TriggeredWatch triggeredWatch = mock(TriggeredWatch.class);
|
|
|
when(parser.parse(eq("_id"), eq(1L), any(BytesReference.class))).thenReturn(triggeredWatch);
|
|
|
|
|
|
- PlainActionFuture<ClearScrollResponse> clearScrollResponseFuture = PlainActionFuture.newFuture();
|
|
|
- when(client.clearScroll(any())).thenReturn(clearScrollResponseFuture);
|
|
|
- clearScrollResponseFuture.onResponse(new ClearScrollResponse(true, 1));
|
|
|
+ doAnswer(invocation -> {
|
|
|
+ ActionListener<ClearScrollResponse> listener = (ActionListener<ClearScrollResponse>) invocation.getArguments()[2];
|
|
|
+ listener.onResponse(new ClearScrollResponse(true, 1));
|
|
|
+ return null;
|
|
|
+
|
|
|
+ }).when(client).execute(eq(ClearScrollAction.INSTANCE), any(), any());
|
|
|
|
|
|
assertThat(TriggeredWatchStore.validate(cs), is(true));
|
|
|
DateTime now = DateTime.now(UTC);
|
|
@@ -251,10 +282,10 @@ public class TriggeredWatchStoreTests extends ESTestCase {
|
|
|
assertThat(triggeredWatches, notNullValue());
|
|
|
assertThat(triggeredWatches, hasSize(watches.size()));
|
|
|
|
|
|
- verify(client.admin().indices(), times(1)).refresh(any());
|
|
|
- verify(client, times(1)).search(any(SearchRequest.class));
|
|
|
- verify(client, times(2)).searchScroll(any());
|
|
|
- verify(client, times(1)).clearScroll(any());
|
|
|
+ verify(client, times(1)).execute(eq(RefreshAction.INSTANCE), any(), any());
|
|
|
+ verify(client, times(1)).execute(eq(SearchAction.INSTANCE), any(), any());
|
|
|
+ verify(client, times(2)).execute(eq(SearchScrollAction.INSTANCE), any(), any());
|
|
|
+ verify(client, times(1)).execute(eq(ClearScrollAction.INSTANCE), any(), any());
|
|
|
}
|
|
|
|
|
|
// the elasticsearch migration helper is doing reindex using aliases, so we have to
|
|
@@ -332,7 +363,7 @@ public class TriggeredWatchStoreTests extends ESTestCase {
|
|
|
assertThat(TriggeredWatchStore.validate(cs), is(true));
|
|
|
Watch watch = mock(Watch.class);
|
|
|
triggeredWatchStore.findTriggeredWatches(Collections.singletonList(watch), cs);
|
|
|
- verifyZeroInteractions(client);
|
|
|
+ verify(client, times(0)).execute(any(), any(), any());
|
|
|
}
|
|
|
|
|
|
public void testIndexNotFoundButInMetaData() {
|
|
@@ -344,13 +375,11 @@ public class TriggeredWatchStoreTests extends ESTestCase {
|
|
|
ClusterState cs = csBuilder.build();
|
|
|
Watch watch = mock(Watch.class);
|
|
|
|
|
|
- AdminClient adminClient = mock(AdminClient.class);
|
|
|
- when(client.admin()).thenReturn(adminClient);
|
|
|
- IndicesAdminClient indicesAdminClient = mock(IndicesAdminClient.class);
|
|
|
- when(adminClient.indices()).thenReturn(indicesAdminClient);
|
|
|
- PlainActionFuture<RefreshResponse> future = PlainActionFuture.newFuture();
|
|
|
- when(indicesAdminClient.refresh(any())).thenReturn(future);
|
|
|
- future.onFailure(new IndexNotFoundException(TriggeredWatchStoreField.INDEX_NAME));
|
|
|
+ doAnswer(invocation -> {
|
|
|
+ ActionListener<RefreshResponse> listener = (ActionListener<RefreshResponse>) invocation.getArguments()[2];
|
|
|
+ listener.onFailure(new IndexNotFoundException(TriggeredWatchStoreField.INDEX_NAME));
|
|
|
+ return null;
|
|
|
+ }).when(client).execute(eq(RefreshAction.INSTANCE), any(), any());
|
|
|
|
|
|
Collection<TriggeredWatch> triggeredWatches = triggeredWatchStore.findTriggeredWatches(Collections.singletonList(watch), cs);
|
|
|
assertThat(triggeredWatches, hasSize(0));
|
|
@@ -381,6 +410,65 @@ public class TriggeredWatchStoreTests extends ESTestCase {
|
|
|
assertThat(BytesReference.bytes(jsonBuilder).utf8ToString(), equalTo(BytesReference.bytes(jsonBuilder2).utf8ToString()));
|
|
|
}
|
|
|
|
|
|
+ public void testPutTriggeredWatches() throws Exception {
|
|
|
+ DateTime now = DateTime.now(UTC);
|
|
|
+ int numberOfTriggeredWatches = randomIntBetween(1, 100);
|
|
|
+
|
|
|
+ List<TriggeredWatch> triggeredWatches = new ArrayList<>(numberOfTriggeredWatches);
|
|
|
+ for (int i = 0; i < numberOfTriggeredWatches; i++) {
|
|
|
+ triggeredWatches.add(new TriggeredWatch(new Wid("watch_id_", now), new ScheduleTriggerEvent("watch_id", now, now)));
|
|
|
+ }
|
|
|
+
|
|
|
+ doAnswer(invocation -> {
|
|
|
+ BulkRequest bulkRequest = (BulkRequest) invocation.getArguments()[1];
|
|
|
+ ActionListener<BulkResponse> listener = (ActionListener<BulkResponse>) invocation.getArguments()[2];
|
|
|
+
|
|
|
+ int size = bulkRequest.requests().size();
|
|
|
+ BulkItemResponse[] bulkItemResponse = new BulkItemResponse[size];
|
|
|
+ for (int i = 0; i < size; i++) {
|
|
|
+ DocWriteRequest<?> writeRequest = bulkRequest.requests().get(i);
|
|
|
+ ShardId shardId = new ShardId(TriggeredWatchStoreField.INDEX_NAME, "uuid", 0);
|
|
|
+ IndexResponse indexResponse = new IndexResponse(shardId, writeRequest.type(), writeRequest.id(), 1, 1, 1, true);
|
|
|
+ bulkItemResponse[i] = new BulkItemResponse(0, writeRequest.opType(), indexResponse);
|
|
|
+ }
|
|
|
+
|
|
|
+ listener.onResponse(new BulkResponse(bulkItemResponse, 123));
|
|
|
+ return null;
|
|
|
+ }).when(client).execute(eq(BulkAction.INSTANCE), any(), any());
|
|
|
+
|
|
|
+
|
|
|
+ BulkResponse response = triggeredWatchStore.putAll(triggeredWatches);
|
|
|
+ assertThat(response.hasFailures(), is(false));
|
|
|
+ assertThat(response.getItems().length, is(numberOfTriggeredWatches));
|
|
|
+ }
|
|
|
+
|
|
|
+ public void testDeleteTriggeredWatches() throws Exception {
|
|
|
+ DateTime now = DateTime.now(UTC);
|
|
|
+
|
|
|
+ doAnswer(invocation -> {
|
|
|
+ BulkRequest bulkRequest = (BulkRequest) invocation.getArguments()[0];
|
|
|
+ ActionListener<BulkResponse> listener = (ActionListener<BulkResponse>) invocation.getArguments()[1];
|
|
|
+
|
|
|
+ int size = bulkRequest.requests().size();
|
|
|
+ BulkItemResponse[] bulkItemResponse = new BulkItemResponse[size];
|
|
|
+ for (int i = 0; i < size; i++) {
|
|
|
+ DocWriteRequest<?> writeRequest = bulkRequest.requests().get(i);
|
|
|
+ ShardId shardId = new ShardId(TriggeredWatchStoreField.INDEX_NAME, "uuid", 0);
|
|
|
+ IndexResponse indexResponse = new IndexResponse(shardId, writeRequest.type(), writeRequest.id(), 1, 1, 1, true);
|
|
|
+ bulkItemResponse[i] = new BulkItemResponse(0, writeRequest.opType(), indexResponse);
|
|
|
+ }
|
|
|
+
|
|
|
+ listener.onResponse(new BulkResponse(bulkItemResponse, 123));
|
|
|
+ return null;
|
|
|
+ }).when(client).bulk(any(), any());
|
|
|
+
|
|
|
+ triggeredWatchStore.delete(new Wid("watch_id_", now));
|
|
|
+ assertThat(bulks.keySet(), hasSize(1));
|
|
|
+ BulkResponse response = bulks.values().iterator().next();
|
|
|
+ assertThat(response.hasFailures(), is(false));
|
|
|
+ assertThat(response.getItems().length, is(1));
|
|
|
+ }
|
|
|
+
|
|
|
private RefreshResponse mockRefreshResponse(int total, int successful) {
|
|
|
RefreshResponse refreshResponse = mock(RefreshResponse.class);
|
|
|
when(refreshResponse.getTotalShards()).thenReturn(total);
|