package org.ovirt.engine.ui.uicommonweb.action;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.junit.MockitoJUnitRunner;
import org.ovirt.engine.core.common.action.VdcActionType;
import org.ovirt.engine.ui.frontend.Frontend;
import org.ovirt.engine.ui.uicommonweb.action.UiAction.ActionFlowState;
import org.ovirt.engine.ui.uicommonweb.junit.UiCommonSetup;
@RunWith(MockitoJUnitRunner.class)
public abstract class AsyncUiActionTest<C> extends UiActionBaseTest {
protected VdcActionType ACTION_TYPE = VdcActionType.Unknown;
@Rule
public UiCommonSetup setup = new UiCommonSetup();
@Captor
protected ArgumentCaptor<C> callbackCaptor;
protected Frontend frontend;
@Before
@Override
public void setUp() {
super.setUp();
frontend = setup.getMocks().frontend();
}
@Test
public void runSingleActionWithSuccessTest() {
UiAction action = runSingleActionCommon(true);
assertFinishedWithNoErrors(Collections.singletonList(action));
}
@Test
public void runSingleActionWithFailureTest() {
UiAction action = runSingleActionCommon(false);
assertFinishedWithErrors(Collections.singletonList(action), 1);
}
private UiAction runSingleActionCommon(boolean succeed) {
UiAction action = createAction();
action.runAction();
verifyRunActionAndExecuteCallbacksRandomly(succeed, action.getActionFlowState(), 1);
return action;
}
@Test
public void runParallelActionFlowAllSucceedTest() {
List<UiAction> actions = runParallelActionFlowCommon(true);
assertFinishedWithNoErrors(actions);
}
@Test
public void runParallelActionFlowWithFailureTest() {
List<UiAction> actions = runParallelActionFlowCommon(false);
assertFinishedWithErrors(actions, actions.size());
}
private List<UiAction> runParallelActionFlowCommon(boolean success) {
List<UiAction> actions = runActionFlow(ActionType.parallel);
verifyRunActionAndExecuteCallbacksRandomly(success, actions.get(0).getActionFlowState(), actions.size());
return actions;
}
@Test
public void runNextActionFlowAllSucceedTest() {
List<UiAction> actions = runNextActionFlowCommon(true);
assertFinishedWithNoErrors(actions);
}
@Test
public void runNextActionFlowWithLastActionFailureTest() {
List<UiAction> actions = runNextActionFlowCommon(false);
assertFinishedWithErrors(actions, 1);
}
private List<UiAction> runNextActionFlowCommon(boolean lastSuccess) {
List<UiAction> actions = runActionFlow(ActionType.next);
ActionFlowState flowState = actions.get(0).getActionFlowState();
verifyRunActionAndExecuteCallbacksRandomly(true, flowState, 1);
verifyRunActionAndExecuteCallbacksRandomly(lastSuccess, flowState, 2, 1);
return actions;
}
@Test
public void runMixedActionFlowAllSucceed() {
// action1.and(action2).next(action3).and(action4)
List<UiAction> actions = runActionFlow(ActionType.parallel, ActionType.next, ActionType.parallel);
ActionFlowState flowState = actions.get(0).getActionFlowState();
verifyRunActionAndExecuteCallbacksRandomly(true, flowState, 2);
verifyRunActionAndExecuteCallbacksRandomly(true, flowState, 4, 2);
assertFinishedWithNoErrors(actions);
}
@Test
public void runMixedActionFlowWithFailureOnIndependentAction() {
// action1.and(action2).next(action3).and(action4)
// action1 has an error- all the flow will be executed
List<UiAction> actions = runActionFlow(ActionType.parallel, ActionType.next, ActionType.parallel);
ActionFlowState flowState = actions.get(0).getActionFlowState();
List<C> callbacks = verifyRunAction(2);
// execute action1 callback
executeCallbacks(false, flowState, callbacks.subList(1, 2));
// execute action2 callback
executeCallbacks(true, flowState, callbacks.subList(0, 1));
// verify action3 and action4 were also executed
callbacks = verifyRunAction(4);
// executed the callbacks of action3 and action4
executeCallbacks(true, flowState, callbacks.subList(callbacks.size() - 2, callbacks.size()));
assertFinishedWithErrors(actions, 1);
}
@Test
public void actionWithParallelAndNextActions() {
UiAction action = createAction();
UiAction parallelAction = createAction();
UiAction nextAction = createAction();
action.and(parallelAction);
action.then(nextAction);
action.runAction();
verifyRunActionAndExecuteCallbacksRandomly(true, action.getActionFlowState(), 2);
verifyRunActionAndExecuteCallbacksRandomly(true, action.getActionFlowState(), 3, 1);
assertFinishedWithNoErrors(new ArrayList<UiAction>(Arrays.asList(action, parallelAction, nextAction)));
}
/**
* Executes the callbacks passed as a parameter.
*
* @param success
* the success value that should be set on the return value of the callbacks
* @param flowState
* he flow state of the actions which are under test (is used to verify that the flow is not marked as
* done before all the excepted actions and callbacks were executed)
* @param callbacks
* the number of <code>Frontend.runAction(..)</code> executions excepted up to this point
*/
protected abstract void executeCallbacks(boolean success,
ActionFlowState flowState,
List<C> callbacks);
/**
* Composition of <code>verifyRunAction(..)</code> and <code>executeCallbacks(..)</code> which executes all the
* callbacks that were returned by <code>verifyRunAction(..)</code>.
*
* @param success
* the success value that should be set on the return value of the callbacks
* @param flowState
* the flow state of the actions which are under test (is used to verify that the flow is not marked as
* done before all the excepted actions and callbacks were executed)
* @param exepectedNumOfRunActionExecutions
* the number of <code>Frontend.runAction(..)</code> executions excepted up to this point
* @param numOfCallbacksFromTheEndToExecute
* the number of callbacks that should be executed starting at the end of the callbacks list (it is
* useful since <code>verifyRunAction(..)</code> returns the callbacks of <b>all</b> the
* <code>Frontend.runAction(..)</code>s that were executed so far. In case the callbacks of the first
* runActions were already executed, just the callbacks of the newly executed runActions should be
* executed).
*/
protected abstract void verifyRunActionAndExecuteCallbacksRandomly(boolean success,
ActionFlowState flowState,
int exepectedNumOfRunActionExecutions, int numOfCallbacksFromTheEndToExecute);
protected void verifyRunActionAndExecuteCallbacksRandomly(boolean success,
ActionFlowState flowState,
int exepectedNumOfRunActionExecutions) {
verifyRunActionAndExecuteCallbacksRandomly(success,
flowState,
exepectedNumOfRunActionExecutions,
exepectedNumOfRunActionExecutions);
}
/**
* Verifies that <code>Frontend.runAction(..)</code> was executed <code>exepectedNumOfRunActionExecutions</code>
* times.
*
* @return the callbacks of all the <code>Frontend.runAction(..)</code> that were executed.
*/
protected abstract List<C> verifyRunAction(int exepectedNumOfRunActionExecutions);
}