|  | @@ -19,9 +19,6 @@
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  package org.elasticsearch.ingest.common;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -import org.elasticsearch.common.settings.Settings;
 | 
	
		
			
				|  |  | -import org.elasticsearch.common.util.concurrent.EsExecutors;
 | 
	
		
			
				|  |  | -import org.elasticsearch.common.util.concurrent.ThreadContext;
 | 
	
		
			
				|  |  |  import org.elasticsearch.ingest.CompoundProcessor;
 | 
	
		
			
				|  |  |  import org.elasticsearch.ingest.IngestDocument;
 | 
	
		
			
				|  |  |  import org.elasticsearch.ingest.Processor;
 | 
	
	
		
			
				|  | @@ -29,7 +26,6 @@ import org.elasticsearch.ingest.TestProcessor;
 | 
	
		
			
				|  |  |  import org.elasticsearch.ingest.TestTemplateService;
 | 
	
		
			
				|  |  |  import org.elasticsearch.script.TemplateScript;
 | 
	
		
			
				|  |  |  import org.elasticsearch.test.ESTestCase;
 | 
	
		
			
				|  |  | -import org.junit.Before;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  import java.util.ArrayList;
 | 
	
		
			
				|  |  |  import java.util.Arrays;
 | 
	
	
		
			
				|  | @@ -38,74 +34,15 @@ import java.util.HashMap;
 | 
	
		
			
				|  |  |  import java.util.List;
 | 
	
		
			
				|  |  |  import java.util.Locale;
 | 
	
		
			
				|  |  |  import java.util.Map;
 | 
	
		
			
				|  |  | -import java.util.concurrent.ExecutorService;
 | 
	
		
			
				|  |  | -import java.util.concurrent.ThreadPoolExecutor;
 | 
	
		
			
				|  |  | -import java.util.concurrent.TimeUnit;
 | 
	
		
			
				|  |  |  import java.util.function.BiConsumer;
 | 
	
		
			
				|  |  | -import java.util.function.Consumer;
 | 
	
		
			
				|  |  | +import java.util.stream.Collectors;
 | 
	
		
			
				|  |  |  import java.util.stream.IntStream;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  import static org.elasticsearch.ingest.IngestDocumentMatcher.assertIngestDocument;
 | 
	
		
			
				|  |  |  import static org.hamcrest.Matchers.equalTo;
 | 
	
		
			
				|  |  | -import static org.mockito.Matchers.any;
 | 
	
		
			
				|  |  | -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;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  public class ForEachProcessorTests extends ESTestCase {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    @SuppressWarnings("unchecked")
 | 
	
		
			
				|  |  | -    private Consumer<Runnable> genericExecutor = (Consumer<Runnable>) mock(Consumer.class);
 | 
	
		
			
				|  |  | -    private final ExecutorService direct = EsExecutors.newDirectExecutorService();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    @Before
 | 
	
		
			
				|  |  | -    public void setup() {
 | 
	
		
			
				|  |  | -        //execute runnable on same thread for simplicity. some tests will override this and actually run async
 | 
	
		
			
				|  |  | -        doAnswer(invocationOnMock -> {
 | 
	
		
			
				|  |  | -            direct.execute((Runnable) invocationOnMock.getArguments()[0]);
 | 
	
		
			
				|  |  | -            return null;
 | 
	
		
			
				|  |  | -        }).when(genericExecutor).accept(any(Runnable.class));
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    public void testExecute() throws Exception {
 | 
	
		
			
				|  |  | -        ThreadPoolExecutor asyncExecutor =
 | 
	
		
			
				|  |  | -            EsExecutors.newScaling(getClass().getName() + "/" + getTestName(), between(1, 2), between(3, 4), 10, TimeUnit.SECONDS,
 | 
	
		
			
				|  |  | -                EsExecutors.daemonThreadFactory("test"), new ThreadContext(Settings.EMPTY));
 | 
	
		
			
				|  |  | -        doAnswer(invocationOnMock -> {
 | 
	
		
			
				|  |  | -            asyncExecutor.execute((Runnable) invocationOnMock.getArguments()[0]);
 | 
	
		
			
				|  |  | -            return null;
 | 
	
		
			
				|  |  | -        }).when(genericExecutor).accept(any(Runnable.class));
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        List<String> values = new ArrayList<>();
 | 
	
		
			
				|  |  | -        values.add("foo");
 | 
	
		
			
				|  |  | -        values.add("bar");
 | 
	
		
			
				|  |  | -        values.add("baz");
 | 
	
		
			
				|  |  | -        IntStream.range(0, ForEachProcessor.MAX_RECURSE_PER_THREAD).forEach(value -> values.add("a"));
 | 
	
		
			
				|  |  | -        IngestDocument ingestDocument = new IngestDocument(
 | 
	
		
			
				|  |  | -            "_index", "_id", null, null, null, Collections.singletonMap("values", values)
 | 
	
		
			
				|  |  | -        );
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        ForEachProcessor processor = new ForEachProcessor(
 | 
	
		
			
				|  |  | -            "_tag", "values", new UppercaseProcessor("_tag", "_ingest._value", false, "_ingest._value"),
 | 
	
		
			
				|  |  | -            false, genericExecutor
 | 
	
		
			
				|  |  | -        );
 | 
	
		
			
				|  |  | -        processor.execute(ingestDocument, (result, e) -> {});
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        assertBusy(() -> assertEquals(values.size() / ForEachProcessor.MAX_RECURSE_PER_THREAD, asyncExecutor.getCompletedTaskCount()));
 | 
	
		
			
				|  |  | -        asyncExecutor.shutdown();
 | 
	
		
			
				|  |  | -        asyncExecutor.awaitTermination(5, TimeUnit.SECONDS);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        @SuppressWarnings("unchecked")
 | 
	
		
			
				|  |  | -        List<String> result = ingestDocument.getFieldValue("values", List.class);
 | 
	
		
			
				|  |  | -        assertThat(result.get(0), equalTo("FOO"));
 | 
	
		
			
				|  |  | -        assertThat(result.get(1), equalTo("BAR"));
 | 
	
		
			
				|  |  | -        assertThat(result.get(2), equalTo("BAZ"));
 | 
	
		
			
				|  |  | -        IntStream.range(3, ForEachProcessor.MAX_RECURSE_PER_THREAD + 3).forEach(i -> assertThat(result.get(i), equalTo("A")));
 | 
	
		
			
				|  |  | -        verify(genericExecutor, times(values.size() / ForEachProcessor.MAX_RECURSE_PER_THREAD)).accept(any(Runnable.class));
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |      public void testExecuteWithAsyncProcessor() throws Exception {
 | 
	
		
			
				|  |  |          List<String> values = new ArrayList<>();
 | 
	
		
			
				|  |  |          values.add("foo");
 | 
	
	
		
			
				|  | @@ -116,7 +53,7 @@ public class ForEachProcessorTests extends ESTestCase {
 | 
	
		
			
				|  |  |          );
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          ForEachProcessor processor = new ForEachProcessor("_tag", "values", new AsyncUpperCaseProcessor("_ingest._value"),
 | 
	
		
			
				|  |  | -            false, genericExecutor);
 | 
	
		
			
				|  |  | +            false);
 | 
	
		
			
				|  |  |          processor.execute(ingestDocument, (result, e) -> {
 | 
	
		
			
				|  |  |          });
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -128,8 +65,6 @@ public class ForEachProcessorTests extends ESTestCase {
 | 
	
		
			
				|  |  |              assertThat(result.get(1), equalTo("BAR"));
 | 
	
		
			
				|  |  |              assertThat(result.get(2), equalTo("BAZ"));
 | 
	
		
			
				|  |  |          });
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        verifyZeroInteractions(genericExecutor);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      public void testExecuteWithFailure() throws Exception {
 | 
	
	
		
			
				|  | @@ -142,7 +77,7 @@ public class ForEachProcessorTests extends ESTestCase {
 | 
	
		
			
				|  |  |                  throw new RuntimeException("failure");
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          });
 | 
	
		
			
				|  |  | -        ForEachProcessor processor = new ForEachProcessor("_tag", "values", testProcessor, false, genericExecutor);
 | 
	
		
			
				|  |  | +        ForEachProcessor processor = new ForEachProcessor("_tag", "values", testProcessor, false);
 | 
	
		
			
				|  |  |          Exception[] exceptions = new Exception[1];
 | 
	
		
			
				|  |  |          processor.execute(ingestDocument, (result, e) -> {exceptions[0] = e;});
 | 
	
		
			
				|  |  |          assertThat(exceptions[0].getMessage(), equalTo("failure"));
 | 
	
	
		
			
				|  | @@ -160,7 +95,7 @@ public class ForEachProcessorTests extends ESTestCase {
 | 
	
		
			
				|  |  |          Processor onFailureProcessor = new TestProcessor(ingestDocument1 -> {});
 | 
	
		
			
				|  |  |          processor = new ForEachProcessor(
 | 
	
		
			
				|  |  |              "_tag", "values", new CompoundProcessor(false, Arrays.asList(testProcessor), Arrays.asList(onFailureProcessor)),
 | 
	
		
			
				|  |  | -            false, genericExecutor
 | 
	
		
			
				|  |  | +            false
 | 
	
		
			
				|  |  |          );
 | 
	
		
			
				|  |  |          processor.execute(ingestDocument, (result, e) -> {});
 | 
	
		
			
				|  |  |          assertThat(testProcessor.getInvokedCounter(), equalTo(3));
 | 
	
	
		
			
				|  | @@ -179,7 +114,7 @@ public class ForEachProcessorTests extends ESTestCase {
 | 
	
		
			
				|  |  |              id.setFieldValue("_ingest._value.index", id.getSourceAndMetadata().get("_index"));
 | 
	
		
			
				|  |  |              id.setFieldValue("_ingest._value.id", id.getSourceAndMetadata().get("_id"));
 | 
	
		
			
				|  |  |          });
 | 
	
		
			
				|  |  | -        ForEachProcessor processor = new ForEachProcessor("_tag", "values", innerProcessor, false, genericExecutor);
 | 
	
		
			
				|  |  | +        ForEachProcessor processor = new ForEachProcessor("_tag", "values", innerProcessor, false);
 | 
	
		
			
				|  |  |          processor.execute(ingestDocument, (result, e) -> {});
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          assertThat(innerProcessor.getInvokedCounter(), equalTo(2));
 | 
	
	
		
			
				|  | @@ -205,7 +140,7 @@ public class ForEachProcessorTests extends ESTestCase {
 | 
	
		
			
				|  |  |          ForEachProcessor processor = new ForEachProcessor(
 | 
	
		
			
				|  |  |              "_tag", "values", new SetProcessor("_tag",
 | 
	
		
			
				|  |  |              new TestTemplateService.MockTemplateScript.Factory("_ingest._value.new_field"),
 | 
	
		
			
				|  |  | -            (model) -> model.get("other")), false, genericExecutor);
 | 
	
		
			
				|  |  | +            (model) -> model.get("other")), false);
 | 
	
		
			
				|  |  |          processor.execute(ingestDocument, (result, e) -> {});
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          assertThat(ingestDocument.getFieldValue("values.0.new_field", String.class), equalTo("value"));
 | 
	
	
		
			
				|  | @@ -215,17 +150,10 @@ public class ForEachProcessorTests extends ESTestCase {
 | 
	
		
			
				|  |  |          assertThat(ingestDocument.getFieldValue("values.4.new_field", String.class), equalTo("value"));
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    public void testRandom() throws Exception {
 | 
	
		
			
				|  |  | -        ThreadPoolExecutor asyncExecutor =
 | 
	
		
			
				|  |  | -            EsExecutors.newScaling(getClass().getName() + "/" + getTestName(), between(1, 2), between(3, 4), 10, TimeUnit.SECONDS,
 | 
	
		
			
				|  |  | -                EsExecutors.daemonThreadFactory("test"), new ThreadContext(Settings.EMPTY));
 | 
	
		
			
				|  |  | -        doAnswer(invocationOnMock -> {
 | 
	
		
			
				|  |  | -            asyncExecutor.execute((Runnable) invocationOnMock.getArguments()[0]);
 | 
	
		
			
				|  |  | -            return null;
 | 
	
		
			
				|  |  | -        }).when(genericExecutor).accept(any(Runnable.class));
 | 
	
		
			
				|  |  | +    public void testRandom() {
 | 
	
		
			
				|  |  |          Processor innerProcessor = new Processor() {
 | 
	
		
			
				|  |  |                  @Override
 | 
	
		
			
				|  |  | -                public IngestDocument execute(IngestDocument ingestDocument) throws Exception {
 | 
	
		
			
				|  |  | +                public IngestDocument execute(IngestDocument ingestDocument) {
 | 
	
		
			
				|  |  |                      String existingValue = ingestDocument.getFieldValue("_ingest._value", String.class);
 | 
	
		
			
				|  |  |                      ingestDocument.setFieldValue("_ingest._value", existingValue + ".");
 | 
	
		
			
				|  |  |                      return ingestDocument;
 | 
	
	
		
			
				|  | @@ -242,28 +170,19 @@ public class ForEachProcessorTests extends ESTestCase {
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |          };
 | 
	
		
			
				|  |  |          int numValues = randomIntBetween(1, 10000);
 | 
	
		
			
				|  |  | -        List<String> values = new ArrayList<>(numValues);
 | 
	
		
			
				|  |  | -        for (int i = 0; i < numValues; i++) {
 | 
	
		
			
				|  |  | -            values.add("");
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | +        List<String> values = IntStream.range(0, numValues).mapToObj(i->"").collect(Collectors.toList());
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |          IngestDocument ingestDocument = new IngestDocument(
 | 
	
		
			
				|  |  |              "_index", "_id", null, null, null, Collections.singletonMap("values", values)
 | 
	
		
			
				|  |  |          );
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        ForEachProcessor processor = new ForEachProcessor("_tag", "values", innerProcessor, false, genericExecutor);
 | 
	
		
			
				|  |  | +        ForEachProcessor processor = new ForEachProcessor("_tag", "values", innerProcessor, false);
 | 
	
		
			
				|  |  |          processor.execute(ingestDocument, (result, e) -> {});
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        assertBusy(() -> assertEquals(values.size() / ForEachProcessor.MAX_RECURSE_PER_THREAD, asyncExecutor.getCompletedTaskCount()));
 | 
	
		
			
				|  |  | -        asyncExecutor.shutdown();
 | 
	
		
			
				|  |  | -        asyncExecutor.awaitTermination(5, TimeUnit.SECONDS);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |          @SuppressWarnings("unchecked")
 | 
	
		
			
				|  |  |          List<String> result = ingestDocument.getFieldValue("values", List.class);
 | 
	
		
			
				|  |  |          assertThat(result.size(), equalTo(numValues));
 | 
	
		
			
				|  |  | -        for (String r : result) {
 | 
	
		
			
				|  |  | -            assertThat(r, equalTo("."));
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        verify(genericExecutor, times(values.size() / ForEachProcessor.MAX_RECURSE_PER_THREAD)).accept(any(Runnable.class));
 | 
	
		
			
				|  |  | +        result.forEach(r -> assertThat(r, equalTo(".")));
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      public void testModifyFieldsOutsideArray() throws Exception {
 | 
	
	
		
			
				|  | @@ -281,7 +200,7 @@ public class ForEachProcessorTests extends ESTestCase {
 | 
	
		
			
				|  |  |                  "_tag", "values", new CompoundProcessor(false,
 | 
	
		
			
				|  |  |                  Collections.singletonList(new UppercaseProcessor("_tag_upper", "_ingest._value", false, "_ingest._value")),
 | 
	
		
			
				|  |  |                  Collections.singletonList(new AppendProcessor("_tag", template, (model) -> (Collections.singletonList("added"))))
 | 
	
		
			
				|  |  | -        ), false, genericExecutor);
 | 
	
		
			
				|  |  | +        ), false);
 | 
	
		
			
				|  |  |          processor.execute(ingestDocument, (result, e) -> {});
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          List<?> result = ingestDocument.getFieldValue("values", List.class);
 | 
	
	
		
			
				|  | @@ -307,7 +226,7 @@ public class ForEachProcessorTests extends ESTestCase {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          TestProcessor processor = new TestProcessor(doc -> doc.setFieldValue("_ingest._value",
 | 
	
		
			
				|  |  |                  doc.getFieldValue("_source._value", String.class)));
 | 
	
		
			
				|  |  | -        ForEachProcessor forEachProcessor = new ForEachProcessor("_tag", "values", processor, false, genericExecutor);
 | 
	
		
			
				|  |  | +        ForEachProcessor forEachProcessor = new ForEachProcessor("_tag", "values", processor, false);
 | 
	
		
			
				|  |  |          forEachProcessor.execute(ingestDocument, (result, e) -> {});
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          List<?> result = ingestDocument.getFieldValue("values", List.class);
 | 
	
	
		
			
				|  | @@ -340,8 +259,8 @@ public class ForEachProcessorTests extends ESTestCase {
 | 
	
		
			
				|  |  |                  doc -> doc.setFieldValue("_ingest._value", doc.getFieldValue("_ingest._value", String.class).toUpperCase(Locale.ENGLISH))
 | 
	
		
			
				|  |  |          );
 | 
	
		
			
				|  |  |          ForEachProcessor processor = new ForEachProcessor(
 | 
	
		
			
				|  |  | -                "_tag", "values1", new ForEachProcessor("_tag", "_ingest._value.values2", testProcessor, false, genericExecutor),
 | 
	
		
			
				|  |  | -            false, genericExecutor);
 | 
	
		
			
				|  |  | +                "_tag", "values1", new ForEachProcessor("_tag", "_ingest._value.values2", testProcessor, false),
 | 
	
		
			
				|  |  | +            false);
 | 
	
		
			
				|  |  |          processor.execute(ingestDocument, (result, e) -> {});
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          List<?> result = ingestDocument.getFieldValue("values1.0.values2", List.class);
 | 
	
	
		
			
				|  | @@ -359,7 +278,7 @@ public class ForEachProcessorTests extends ESTestCase {
 | 
	
		
			
				|  |  |          );
 | 
	
		
			
				|  |  |          IngestDocument ingestDocument = new IngestDocument(originalIngestDocument);
 | 
	
		
			
				|  |  |          TestProcessor testProcessor = new TestProcessor(doc -> {});
 | 
	
		
			
				|  |  | -        ForEachProcessor processor = new ForEachProcessor("_tag", "_ingest._value", testProcessor, true, genericExecutor);
 | 
	
		
			
				|  |  | +        ForEachProcessor processor = new ForEachProcessor("_tag", "_ingest._value", testProcessor, true);
 | 
	
		
			
				|  |  |          processor.execute(ingestDocument, (result, e) -> {});
 | 
	
		
			
				|  |  |          assertIngestDocument(originalIngestDocument, ingestDocument);
 | 
	
		
			
				|  |  |          assertThat(testProcessor.getInvokedCounter(), equalTo(0));
 |