Alona Kaplan has posted comments on this change. Change subject: webadmin: fluent UiAction ......................................................................
Patch Set 25: (18 comments) https://gerrit.ovirt.org/#/c/36848/25/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/action/UiAction.java File frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/action/UiAction.java: Line 173: return name; Line 174: } Line 175: Line 176: void tryToFinalize(boolean handleErrors) { Line 177: if (actionFlowState.isAllDone() && actionFlowState.isStartedProgress()) { > I think only model.stopProgress() should depend on whether actionFlowState. Done Line 178: model.stopProgress(); Line 179: Line 180: if (handleErrors) { Line 181: handleErrors(); https://gerrit.ovirt.org/#/c/36848/25/frontend/webadmin/modules/uicommonweb/src/test/java/org/ovirt/engine/ui/uicommonweb/action/AsyncUiActionTest.java File frontend/webadmin/modules/uicommonweb/src/test/java/org/ovirt/engine/ui/uicommonweb/action/AsyncUiActionTest.java: Line 85: assertFinishedSuccessfully(actions); Line 86: } Line 87: Line 88: @Test Line 89: public void runNextActionFlowWithLastActionFailureTest() { > How about a test where the first action fails, which makes sure the second There is a specific test for this use-case in each of the sub-classes. Since the sub-classes have different behavior in this case the test couldn't be common. Line 90: List<UiAction> actions = runNextActionFlowCommon(false); Line 91: assertFinishedWithFailures(actions, 1); Line 92: } Line 93: Line 96: ActionFlowState flowState = actions.get(0).getActionFlowState(); Line 97: Line 98: verifyRunActionAndExecuteCallbacksRandomly(true, flowState, 1); Line 99: List<C> callbacks = verfifyRunAction(2); Line 100: executeCallbacks(lastSuccess, flowState, callbacks.subList(callbacks.size() - 1, callbacks.size())); > This code REALLY isn't clear - it took me a very long time to figure out th I'm not sure why did it take you so long to figure out the behavior. 'verifyRunActionAndExecuteCallbacksRandomly(..)' as its name specifies, is a composition of two methods 'verfifyRunAction(.., exepectedNumOfRunActionExecutions)'- verifies the Frontend.runAction was exucted 'exepectedNumOfRunActionExecutions' times and return the callback of all the executed actions. 'executeCallbacks(.., callbacks)'- executes the callbacks that were passed to the method. The callbacks are executed in a random order to simulate the real life behavior of getting the responses from the backed in a random order. The method is generic and therefore unaware to the content of the callbacks it executes. So I don't really understand why did you except if to do the 'future' checks. As you see, in this case 'verifyRunActionAndExecuteCallbacksRandomly(..,1)'- verifies that only ONE runAction was executed and therefore it executes only its ONE callback. Since its callback executes another runAction. Line 99- verifies that up to this point 2 runActions had run. Line 100- executes just the callback of the last action (since the callback of the firs action was already executed). If you have a better suggestion of how to write this code I will be happy to hear. Meanwhile, I've added a new overload to verifyRunActionAndExecuteCallbacksRandomly that excepts 'numOfCallbacksFromTheEndToExecute' parameter. So now line 99 and 100 are combined to one method call. Also, added java docs to verifyRunActionAndExecuteCallbacksRandomly, verfifyRunAction and executeCallbacks. Line 101: Line 102: return actions; Line 103: } Line 104: Line 109: ActionFlowState flowState = actions.get(0).getActionFlowState(); Line 110: Line 111: verifyRunActionAndExecuteCallbacksRandomly(true, flowState, 2); Line 112: List<C> callbacks = verfifyRunAction(4); Line 113: executeCallbacks(true, flowState, callbacks.subList(callbacks.size() - 2, callbacks.size())); > Same comment as above. same answer Line 114: Line 115: assertFinishedSuccessfully(actions); Line 116: } Line 117: Line 117: Line 118: @Test Line 119: public void runMixedActionFlowWithFailureOnIndependentAction() { Line 120: // action1.and(action2).next(action3).and(action4) Line 121: // action1 has an error- all the flow will be executed > As above, a more interesting case is if action1 also has a next action. Please refer to the test in line 144, that is exactly what it verifies. Line 122: Line 123: List<UiAction> actions = runActionFlow(ActionType.parallel, ActionType.next, ActionType.parallel); Line 124: ActionFlowState flowState = actions.get(0).getActionFlowState(); Line 125: Line 131: // execute action2 callback Line 132: executeCallbacks(true, flowState, callbacks.subList(0, 1)); Line 133: Line 134: // verify action3 and action4 were also executed Line 135: callbacks = verfifyRunAction(4); > Same as before - it's very hard to follow what you're validating. It is a complex case. I hope my explanation in the previous comment helped you to understand. The flow is action1.and(action2).next(action3).and(action4), action1 has an error. In mean that- phase 1- action1 and action2 will be executed. phase 2- action3 and action4 will be executed from action2's callback. line 126- verifies phase 1, 2 Frontend.runAction were executed. One of action1 and one of action2. line 129- executes action1's callback, the return value that is passed to the callback is 'succeed=false' on the return value, since action1 fails (it should affect the flow since action1 doesn't have actions that depend on it). line 132- executes action2's callback with 'succeed=true' on the return value. line 135- since action2's callback was executed in line 129, now action3 and action4 should have also been executed. So now, the total number of executed 'Frontend.runAction' should be 4. line 138- executes the callbacks action3 and action4. Line 136: Line 137: // executed the callbacks of action3 and action4 Line 138: executeCallbacks(true, flowState, callbacks.subList(callbacks.size() - 2, callbacks.size())); Line 139: Line 164: protected abstract void verifyRunActionAndExecuteCallbacksRandomly(boolean success, Line 165: ActionFlowState flowState, Line 166: int exepectedNumOfRunActionExecutions); Line 167: Line 168: protected abstract List<C> verfifyRunAction(int exepectedNumOfRunActionExecutions); > verfify? :) Done https://gerrit.ovirt.org/#/c/36848/25/frontend/webadmin/modules/uicommonweb/src/test/java/org/ovirt/engine/ui/uicommonweb/action/SyncUiActionTest.java File frontend/webadmin/modules/uicommonweb/src/test/java/org/ovirt/engine/ui/uicommonweb/action/SyncUiActionTest.java: Line 88: public void shouldExecuteTest() { Line 89: UiAction action = new SyncUiAction(model, "test") { //$NON-NLS-1$ Line 90: @Override Line 91: protected void onActionExecute() { Line 92: assertTrue(false); > Maybe call Mockito's fail() instead? Done Line 93: } Line 94: Line 95: @Override Line 96: protected boolean shouldExecute() { Line 121: SimpleAction finalAction = new SimpleAction() { Line 122: Line 123: @Override Line 124: public void execute() { Line 125: // Do nothing > Similarly to the above case, maybe call fail() to also mark this as a piece Done Line 126: } Line 127: }; Line 128: action1.onAllExecutionsFinish(finalAction); Line 129: action2.onAllExecutionsFinish(finalAction); https://gerrit.ovirt.org/#/c/36848/25/frontend/webadmin/modules/uicommonweb/src/test/java/org/ovirt/engine/ui/uicommonweb/action/UiActionBaseTest.java File frontend/webadmin/modules/uicommonweb/src/test/java/org/ovirt/engine/ui/uicommonweb/action/UiActionBaseTest.java: Line 54: int numOfProgressInteractions = shouldCallProgressActions ? 1 : 0; Line 55: verify(model, times(numOfProgressInteractions)).startProgress(any(String.class)); Line 56: verify(model, times(numOfProgressInteractions)).stopProgress(); Line 57: Line 58: UiAction previousAction = null; > The test in this block is actually quite important, and I think should be e The state consistency check is ran on each assertAllDone. assertAllDone is ran when the flow is finished. Each flow (unless there is a bug/exception) should be finished (counter=0), no matter if there were failures or all succeeded. So, in my opinion, the check here is enough. Line 59: for (UiAction action : actions) { Line 60: if (previousAction != null) { Line 61: assertSame(previousAction.getActionFlowState(), action.getActionFlowState()); Line 62: } https://gerrit.ovirt.org/#/c/36848/25/frontend/webadmin/modules/uicommonweb/src/test/java/org/ovirt/engine/ui/uicommonweb/action/UiVdcActionTest.java File frontend/webadmin/modules/uicommonweb/src/test/java/org/ovirt/engine/ui/uicommonweb/action/UiVdcActionTest.java: Line 20: @RunWith(MockitoJUnitRunner.class) Line 21: public class UiVdcActionTest extends AsyncUiActionTest<IFrontendActionAsyncCallback> { Line 22: Line 23: @Test Line 24: public void runNextActionFlowWithFirstActionFailureTest() { > There's a similar test in UiVdcMultipleActionTest - can't they be unified a As I wrote in the answer to the previous comment. UiVdcAction and UiVdcMultipleAction have different behaviour in this case. UiVdcAction- Doesn't run the next action in case of a failure. UiVdcMultipleAction- runs the next action in case of a failure in one of the multiple actions. Line 25: List<UiAction> actions = runActionFlow(ActionType.next); Line 26: ActionFlowState flowState = actions.get(0).getActionFlowState(); Line 27: Line 28: verifyRunActionAndExecuteCallbacksRandomly(false, flowState, 1); Line 32: assertFinishedWithFailures(Collections.singletonList(actions.get(0)), 1); Line 33: } Line 34: Line 35: @Test Line 36: public void runMixedActionFlowWithFailureOnDependentAction() { > Same question. same answer. Line 37: // action1.and(action2).next(action3).and(action4) Line 38: // action1 and action 2 has failure -> action3 and action4 won't be executed Line 39: Line 40: List<UiAction> actions = runActionFlow(ActionType.parallel, ActionType.next, ActionType.parallel); Line 52: action.runAction(); Line 53: Line 54: verifyRunActionAndExecuteCallbacksRandomly(false, action.getActionFlowState(), 1, true); Line 55: Line 56: assertFinishedSuccessfully(Collections.singletonList(action)); > This is weird for two reasons: 1. If the error dialog is shown it means the errors are not collected. Therefore, at the end of the flow there are no errors, as if everything finished successfully. Change the method name to assertFinishedWithNoErros, I hope now it is clearer. 2. I don't. This is a test class for UiVdcAction. I'm not testing the functionality of other classes. Line 57: } Line 58: Line 59: @Override Line 60: protected UiVdcAction createAction() { Line 60: protected UiVdcAction createAction() { Line 61: return new UiVdcAction(ACTION_TYPE, new VdcActionParametersBase(), model); Line 62: } Line 63: Line 64: private UiVdcAction createAction(boolean showErrorDialog) { > You don't actually use the argument here - either rename the method or pass Done Line 65: return new UiVdcAction(ACTION_TYPE, new VdcActionParametersBase(), model, true); Line 66: } Line 67: Line 68: private void verifyRunActionAndExecuteCallbacksRandomly(boolean success, Line 97: } Line 98: Line 99: private List<IFrontendActionAsyncCallback> verfifyRunAction(int exepectedNumOfRunActionExecutions, Line 100: boolean showErrorDialog) { Line 101: verify(frontend, times(exepectedNumOfRunActionExecutions)).runAction(eq(ACTION_TYPE), > What is the benefit of using eq() over passing ACTION_TYPE itself? Same que it is the syntax, it doesn't pass compilation without the eq. Line 102: any(VdcActionParametersBase.class), Line 103: callbackCaptor.capture(), Line 104: eq(showErrorDialog)); Line 105: List<IFrontendActionAsyncCallback> callbacks = callbackCaptor.getAllValues(); https://gerrit.ovirt.org/#/c/36848/25/frontend/webadmin/modules/uicommonweb/src/test/java/org/ovirt/engine/ui/uicommonweb/action/UiVdcMultipleActionTest.java File frontend/webadmin/modules/uicommonweb/src/test/java/org/ovirt/engine/ui/uicommonweb/action/UiVdcMultipleActionTest.java: Line 48: assertFinishedWithFailures(actions.subList(0, 2), 2); Line 49: } Line 50: Line 51: @Test Line 52: public void waitForResultTest() { > Shouldn't this (or another test) verify that a subsequent action is run des Created a common test method this test and runNextActionFlowWithFirstActionFailureTest that receives waitForResult as a parameter. Line 53: UiAction action = createAction(true, true); Line 54: action.runAction(); Line 55: Line 56: verifyRunActionAndExecuteCallbacksRandomly(false, action.getActionFlowState(), 1, true); Line 59: } Line 60: Line 61: @Test Line 62: public void dontRunNextInCaseOfErrorTest() { Line 63: UiAction action1 = createAction(false, false); > Do you actually care whether the first parameter is false or true? Shouldn' Created a common method that receives waitForResult as a parameter. Splitted the test into two. Line 64: UiAction action2 = createAction(); Line 65: action1.then(action2); Line 66: action1.runAction(); Line 67: Line 139: } Line 140: Line 141: private List<IFrontendMultipleActionAsyncCallback> verfifyRunAction(int exepectedNumOfRunActionExecutions, Line 142: boolean waitForResult) { Line 143: verify(frontend, times(exepectedNumOfRunActionExecutions)).runMultipleAction(eq(ACTION_TYPE), > Same questions as in UiVdcAction concerning the usage of eq() here and belo same answer Line 144: anyListOf(VdcActionParametersBase.class), Line 145: callbackCaptor.capture(), Line 146: eq(false), Line 147: eq(waitForResult)); -- To view, visit https://gerrit.ovirt.org/36848 To unsubscribe, visit https://gerrit.ovirt.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I262282d00bbb16a65f36a2463d3ffe8dbf6594c6 Gerrit-PatchSet: 25 Gerrit-Project: ovirt-engine Gerrit-Branch: master Gerrit-Owner: Alona Kaplan <alkap...@redhat.com> Gerrit-Reviewer: Alona Kaplan <alkap...@redhat.com> Gerrit-Reviewer: Lior Vernia <lver...@redhat.com> Gerrit-Reviewer: Yevgeny Zaspitsky <yzasp...@redhat.com> Gerrit-Reviewer: automat...@ovirt.org Gerrit-Reviewer: oVirt Jenkins CI Server Gerrit-HasComments: Yes _______________________________________________ Engine-patches mailing list Engine-patches@ovirt.org http://lists.ovirt.org/mailman/listinfo/engine-patches