WhileHandler implements OutputOperationHandler<While<Object, Object>, Object> { @Override public Object doOperation(final While operation, final Context context, final Store store) throws OperationException { validateMaxRepeats(operation); Object input = operation.getInput(); for (int repeatCount = 0; repeatCount < operation.getMaxRepeats(); repeatCount++) { final While operationClone = operation.shallowClone(); if (!isSatisfied(input, operationClone, context, store)) { break; } input = doDelegateOperation(input, operationClone.getOperation(), context, store); } return input; }  @Override Object doOperation(final While operation,
                              final Context context,
                              final Store store); void validateMaxRepeats(final While operation); Object doDelegateOperation(final Object input, final Operation delegate, final Context context, final Store store); boolean isSatisfied(final Object input,
                               final While operation,
                               final Context context,
                               final Store store); int getMaxRepeats(); void setMaxRepeats(final int maxRepeats);  }
@Test public void shouldRepeatDelegateOperationUntilMaxRepeatsReached() throws OperationException { final List<EntitySeed> input = Collections.singletonList(mock(EntitySeed.class)); final int maxRepeats = 3; final GetAdjacentIds delegate = mock(GetAdjacentIds.class); final GetAdjacentIds delegateClone1 = mock(GetAdjacentIds.class); final GetAdjacentIds delegateClone2 = mock(GetAdjacentIds.class); final GetAdjacentIds delegateClone3 = mock(GetAdjacentIds.class); final Context context = mock(Context.class); final Store store = mock(Store.class); given(delegate.shallowClone()).willReturn(delegateClone1, delegateClone2, delegateClone3); final CloseableIterable result1 = mock(CloseableIterable.class); final CloseableIterable result2 = mock(CloseableIterable.class); final CloseableIterable result3 = mock(CloseableIterable.class); given(store.execute(delegateClone1, context)).willReturn(result1); given(store.execute(delegateClone2, context)).willReturn(result2); given(store.execute(delegateClone3, context)).willReturn(result3); final While operation = new While.Builder<>() .input(input) .maxRepeats(maxRepeats) .operation(delegate) .build(); final WhileHandler handler = new WhileHandler(); final Object result = handler.doOperation(operation, context, store); verify(delegateClone1, times(1)).getInput(); verify(delegateClone2, times(1)).getInput(); verify(delegateClone3, times(1)).getInput(); verify(store).execute((Output) delegateClone1, context); verify(store).execute((Output) delegateClone2, context); verify(store).execute((Output) delegateClone3, context); assertSame(result3, result); }
@Test public void shouldRepeatWhileConditionIsTrue() throws OperationException { final List<EntitySeed> input = Collections.singletonList(mock(EntitySeed.class)); final boolean condition = true; final int maxRepeats = 3; final GetElements delegate = mock(GetElements.class); final GetElements delegateClone1 = mock(GetElements.class); final GetElements delegateClone2 = mock(GetElements.class); final GetElements delegateClone3 = mock(GetElements.class); final Context context = mock(Context.class); final Store store = mock(Store.class); given(delegate.shallowClone()).willReturn(delegateClone1, delegateClone2, delegateClone3); final CloseableIterable result1 = mock(CloseableIterable.class); final CloseableIterable result2 = mock(CloseableIterable.class); final CloseableIterable result3 = mock(CloseableIterable.class); given(store.execute(delegateClone1, context)).willReturn(result1); given(store.execute(delegateClone2, context)).willReturn(result2); given(store.execute(delegateClone3, context)).willReturn(result3); final While operation = new While.Builder<>() .input(input) .condition(condition) .maxRepeats(maxRepeats) .operation(delegate) .build(); final WhileHandler handler = new WhileHandler(); final Object result = handler.doOperation(operation, context, store); verify(delegateClone1, times(1)).getInput(); verify(delegateClone2, times(1)).getInput(); verify(delegateClone3, times(1)).getInput(); verify(store).execute((Output) delegateClone1, context); verify(store).execute((Output) delegateClone2, context); verify(store).execute((Output) delegateClone3, context); assertSame(result3, result); }
@Test public void shouldNotRepeatWhileConditionIsFalse() throws OperationException { final EntitySeed input = mock(EntitySeed.class); final int maxRepeats = 3; final boolean condition = false; final Operation delegate = mock(GetElements.class); final Context context = mock(Context.class); final Store store = mock(Store.class); final While operation = new While.Builder<>() .input(input) .maxRepeats(maxRepeats) .condition(condition) .operation(delegate) .build(); final WhileHandler handler = new WhileHandler(); handler.doOperation(operation, context, store); verify(store, never()).execute((Output) delegate, context); }
@Test public void shouldThrowExceptionWhenMaxConfiguredNumberOfRepeatsExceeded() throws OperationException { final EntitySeed input = mock(EntitySeed.class); final int maxRepeats = 2500; final Operation delegate = mock(GetElements.class); final Context context = mock(Context.class); final Store store = mock(Store.class); final While operation = new While.Builder<>() .input(input) .maxRepeats(maxRepeats) .operation(delegate) .build(); final WhileHandler handler = new WhileHandler(); try { handler.doOperation(operation, context, store); fail("Exception expected"); } catch (final OperationException e) { assertTrue(e.getMessage().contains("Max repeats of the While operation is too large: " + maxRepeats + " > " + While.MAX_REPEATS)); } }
@Test public void shouldThrowExceptionWhenPredicateCannotAcceptInputType() throws OperationException { final Predicate predicate = new IsFalse(); final Object input = new EntitySeed(); final Conditional conditional = new Conditional(predicate); final Context context = mock(Context.class); final Store store = mock(Store.class); final While operation = new While.Builder<>() .input(input) .conditional(conditional) .operation(new GetElements()) .build(); final WhileHandler handler = new WhileHandler(); try { handler.doOperation(operation, context, store); fail("Exception expected"); } catch (final OperationException e) { assertTrue(e.getMessage().contains("The predicate '" + predicate.getClass().getSimpleName() + "' cannot accept an input of type '" + input.getClass().getSimpleName() + "'")); } }
@Test public void shouldUpdateTransformInputAndTestAgainstPredicate() throws OperationException { final Edge input = new Edge.Builder() .group("testEdge") .source("src") .dest("dest") .directed(true) .property("count", 3) .build(); final Map<Element, Object> transform = mock(Map.class); final Map<Element, Object> transformClone = mock(Map.class); given(transform.shallowClone()).willReturn(transformClone); final Predicate predicate = new IsMoreThan(2); final Conditional conditional = new Conditional(predicate, transform); final Context context = mock(Context.class); final Store store = mock(Store.class); final GetElements getElements = mock(GetElements.class); final While operation = new While.Builder<>() .input(input) .maxRepeats(1) .conditional(conditional) .operation(getElements) .build(); final WhileHandler handler = new WhileHandler(); handler.doOperation(operation, context, store); verify(transformClone).setInput(input); verify(store).execute(transformClone, context); }
@Test public void shouldFailPredicateTestAndNotExecuteDelegateOperation() throws OperationException { final Edge input = new Edge.Builder() .group("testEdge") .source("src") .dest("dest") .directed(true) .property("count", 3) .build(); final Map<Element, Object> transform = new Map.Builder<Element>() .first(new ExtractProperty("count")) .build(); final Predicate predicate = new IsMoreThan(5); final Conditional conditional = new Conditional(predicate, transform); final Context context = mock(Context.class); final Store store = mock(Store.class); final GetElements getElements = mock(GetElements.class); final While operation = new While.Builder<>() .input(input) .maxRepeats(1) .conditional(conditional) .operation(getElements) .build(); final WhileHandler handler = new WhileHandler(); handler.doOperation(operation, context, store); verify(store, never()).execute((Output) getElements, context); }
@Test public void shouldExecuteNonOutputOperation() throws OperationException { final AddElements addElements = new AddElements.Builder() .input(new Edge.Builder().build()) .build(); final Context context = mock(Context.class); final Store store = mock(Store.class); final While operation = new While.Builder<>() .operation(addElements) .condition(true) .maxRepeats(3) .build(); final WhileHandler handler = new WhileHandler(); handler.doOperation(operation, context, store); verify(store, times(3)).execute(addElements, context); }