Set JobStatus as COMPLETED_AND_PAUSED when needed so we can present it on instantiati...
[vid.git] / vid-app-common / src / test / java / org / onap / vid / job / command / ResourceCommandTest.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * VID
4  * ================================================================================
5  * Copyright (C) 2017 - 2019 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.vid.job.command;
22
23 import static java.util.Collections.emptyList;
24 import static org.mockito.AdditionalAnswers.returnsFirstArg;
25 import static org.mockito.ArgumentMatchers.any;
26 import static org.mockito.Mockito.RETURNS_MOCKS;
27 import static org.mockito.Mockito.doAnswer;
28 import static org.mockito.Mockito.eq;
29 import static org.mockito.Mockito.mock;
30 import static org.mockito.Mockito.when;
31 import static org.onap.vid.job.Job.JobStatus.COMPLETED;
32 import static org.onap.vid.job.Job.JobStatus.COMPLETED_WITH_ERRORS;
33 import static org.onap.vid.job.Job.JobStatus.COMPLETED_WITH_NO_ACTION;
34 import static org.onap.vid.job.Job.JobStatus.FAILED;
35 import static org.onap.vid.job.Job.JobStatus.IN_PROGRESS;
36 import static org.onap.vid.job.Job.JobStatus.PAUSE;
37 import static org.onap.vid.job.Job.JobStatus.RESOURCE_IN_PROGRESS;
38 import static org.onap.vid.job.Job.JobStatus.STOPPED;
39 import static org.onap.vid.job.command.ResourceCommandKt.ACTION_PHASE;
40 import static org.onap.vid.job.command.ResourceCommandKt.INTERNAL_STATE;
41 import static org.onap.vid.job.command.ResourceCommandTest.FakeResourceCreator.createGroup;
42 import static org.onap.vid.job.command.ResourceCommandTest.FakeResourceCreator.createMember;
43 import static org.onap.vid.job.command.ResourceCommandTest.FakeResourceCreator.createNetwork;
44 import static org.onap.vid.job.command.ResourceCommandTest.FakeResourceCreator.createService;
45 import static org.onap.vid.job.command.ResourceCommandTest.FakeResourceCreator.createVfModule;
46 import static org.onap.vid.job.command.ResourceCommandTest.FakeResourceCreator.createVnf;
47 import static org.onap.vid.model.Action.Create;
48 import static org.onap.vid.model.Action.Delete;
49 import static org.onap.vid.model.Action.None;
50 import static org.onap.vid.model.Action.Resume;
51 import static org.onap.vid.model.Action.values;
52 import static org.onap.vid.utils.Logging.getMethodCallerName;
53 import static org.testng.Assert.assertNull;
54 import static org.testng.Assert.assertTrue;
55 import static org.testng.AssertJUnit.assertEquals;
56 import static org.testng.AssertJUnit.assertFalse;
57
58 import com.google.common.collect.ImmutableList;
59 import com.google.common.collect.ImmutableMap;
60 import java.util.Collections;
61 import java.util.HashMap;
62 import java.util.List;
63 import java.util.Map;
64 import java.util.Optional;
65 import java.util.UUID;
66 import java.util.stream.Collectors;
67 import java.util.stream.Stream;
68 import javax.ws.rs.ProcessingException;
69 import kotlin.Pair;
70 import org.jetbrains.annotations.NotNull;
71 import org.onap.vid.exceptions.AbortingException;
72 import org.onap.vid.exceptions.GenericUncheckedException;
73 import org.onap.vid.exceptions.TryAgainException;
74 import org.onap.vid.job.Job;
75 import org.onap.vid.job.JobAdapter;
76 import org.onap.vid.job.JobsBrokerService;
77 import org.onap.vid.job.NextCommand;
78 import org.onap.vid.job.impl.JobSharedData;
79 import org.onap.vid.model.Action;
80 import org.onap.vid.model.serviceInstantiation.BaseResource;
81 import org.onap.vid.model.serviceInstantiation.InstanceGroup;
82 import org.onap.vid.model.serviceInstantiation.InstanceGroupMember;
83 import org.onap.vid.model.serviceInstantiation.Network;
84 import org.onap.vid.model.serviceInstantiation.ServiceInstantiation;
85 import org.onap.vid.model.serviceInstantiation.VfModule;
86 import org.onap.vid.model.serviceInstantiation.Vnf;
87 import org.onap.vid.mso.RestMsoImplementation;
88 import org.onap.vid.mso.model.ModelInfo;
89 import org.springframework.http.HttpMethod;
90 import org.testng.annotations.DataProvider;
91 import org.testng.annotations.Test;
92 import org.togglz.core.manager.FeatureManager;
93
94 public class ResourceCommandTest {
95
96     public static class MockCommand extends ResourceCommand {
97
98         public MockCommand(InternalState mockState, Action mockPhase, Job.JobStatus mockedJobStatus) {
99             this(mockState, mockPhase, mockedJobStatus, false);
100         }
101
102         public MockCommand(InternalState mockState, Action mockPhase, Job.JobStatus mockedJobStatus, boolean lateInit) {
103             super(
104                     mock(RestMsoImplementation.class, RETURNS_MOCKS),
105                     mock(InProgressStatusService.class),
106                     mock(MsoResultHandlerService.class, RETURNS_MOCKS),
107                     mock(WatchChildrenJobsBL.class),
108                     mock(JobsBrokerService.class, RETURNS_MOCKS),
109                     mock(JobAdapter.class, RETURNS_MOCKS),
110                     mock(FeatureManager.class));
111             this.mockedJobStatus = mockedJobStatus;
112             this.mockState = mockState;
113             this.mockPhase = mockPhase;
114             if (!lateInit) {
115                 init();
116             }
117             when(this.getWatchChildrenJobsBL().cumulateJobStatus(any(), any())).thenReturn(mockedJobStatus);
118         }
119
120         protected void init() {
121             if (mockState == InternalState.INITIAL) {
122                 init(mock(JobSharedData.class), Collections.emptyMap());
123             } else {
124                 init(mock(JobSharedData.class), ImmutableMap.of(INTERNAL_STATE, mockState.name(), ACTION_PHASE, mockPhase.name()));
125             }
126         }
127
128         private final Job.JobStatus mockedJobStatus;
129         private final InternalState mockState;
130         private final Action mockPhase;
131
132
133         @NotNull
134         @Override
135         public Job.JobStatus createChildren() {
136             if (mockState == InternalState.CREATING_CHILDREN || (mockState == InternalState.INITIAL && mockPhase== Delete))
137                 return mockedJobStatus;
138             throw (new RuntimeException("Not expected to call "+getMethodCallerName()));
139         }
140
141         protected Job.JobStatus mockedStatusOrThrow(InternalState expectedState) {
142             if (mockState == expectedState)
143                 return mockedJobStatus;
144             throw (new RuntimeException("Not expected to call "+getMethodCallerName()));
145         }
146
147         protected MsoRestCallPlan mockedPlanOrThrow(InternalState expectedState) {
148             if (mockState == expectedState)
149                 return new MsoRestCallPlan(HttpMethod.POST, "path", Optional.empty(), Optional.empty(), "nothing");
150             throw (new RuntimeException("Not expected to call "+getMethodCallerName()));
151         }
152
153         @NotNull
154         @Override
155         public MsoRestCallPlan planCreateMyselfRestCall(@NotNull CommandParentData commandParentData, @NotNull JobAdapter.AsyncJobRequest request, @NotNull String userId, String testApi) {
156             return mockedPlanOrThrow(InternalState.CREATE_MYSELF);
157         }
158
159         @NotNull
160         @Override
161         public MsoRestCallPlan planDeleteMyselfRestCall(@NotNull CommandParentData commandParentData, @NotNull JobAdapter.AsyncJobRequest request, @NotNull String userId) {
162             return mockedPlanOrThrow(InternalState.DELETE_MYSELF);
163         }
164     }
165
166     public static class MockCommandTestingStateMachine extends MockCommand {
167
168         private final JobSharedData sharedData;
169         private final boolean isDescendantHasAction;
170
171         public MockCommandTestingStateMachine(InternalState mockState, Action mockPhase, Job.JobStatus mockedJobStatus, boolean mockedNeedToDeleteMySelf) {
172             this(mockState, mockPhase, mockedJobStatus, mockedNeedToDeleteMySelf, false, true);
173         }
174
175         public MockCommandTestingStateMachine(InternalState mockState, Action mockPhase, Job.JobStatus mockedJobStatus, boolean mockedNeedToDeleteMySelf, boolean isService, boolean isDescendantHasAction) {
176             super(mockState, mockPhase, mockedJobStatus, true);
177             this.mockedNeedToDeleteMySelf = mockedNeedToDeleteMySelf;
178             this.isService = isService;
179             this.sharedData = mock(JobSharedData.class, RETURNS_MOCKS);
180             this.isDescendantHasAction = isDescendantHasAction;
181             init();
182         }
183
184         protected final boolean mockedNeedToDeleteMySelf;
185         private final boolean isService;
186
187         @NotNull
188         @Override
189         public Job.JobStatus inProgress() {
190             return mockedStatusOrThrow(InternalState.IN_PROGRESS);
191         }
192
193         @NotNull
194         @Override
195         public Job.JobStatus watchChildren() {
196             return mockedStatusOrThrow(InternalState.WATCHING);
197         }
198
199         @Override
200         public boolean isNeedToDeleteMyself() {
201             return mockedNeedToDeleteMySelf;
202         }
203
204         @Override
205         protected boolean isServiceCommand() {
206             return isService;
207         }
208
209         @Override
210         public JobSharedData getSharedData() {
211             return sharedData;
212         }
213
214         @Override
215         protected boolean isDescendantHasAction(@NotNull Action phase) {
216             return isDescendantHasAction;
217         }
218     }
219
220     @DataProvider
221     public static Object[][] nextStateDeletePhaseProvider() {
222         return new Object[][]{
223                 {InternalState.CREATING_CHILDREN, COMPLETED, InternalState.WATCHING},
224                 {InternalState.WATCHING, COMPLETED, InternalState.DELETE_MYSELF},
225                 {InternalState.WATCHING, IN_PROGRESS, InternalState.WATCHING},
226                 {InternalState.WATCHING, RESOURCE_IN_PROGRESS, InternalState.WATCHING},
227                 {InternalState.DELETE_MYSELF, COMPLETED, InternalState.IN_PROGRESS},
228                 {InternalState.IN_PROGRESS, COMPLETED, InternalState.TERMINAL},
229                 {InternalState.IN_PROGRESS, IN_PROGRESS, InternalState.IN_PROGRESS},
230                 {InternalState.IN_PROGRESS, RESOURCE_IN_PROGRESS, InternalState.IN_PROGRESS},
231         };
232     }
233
234     @Test(dataProvider = "nextStateDeletePhaseProvider")
235     public void whenCalcNextStateDeletePhase_expectedStateIsReturned(
236             InternalState internalState, Job.JobStatus jobStatus, InternalState expectedState) {
237
238         //there is no meaning to the constructor inputs here
239         MockCommandTestingStateMachine underTest = new MockCommandTestingStateMachine(InternalState.TERMINAL, Delete, FAILED, true);
240         assertEquals(expectedState, underTest.calcNextStateDeletePhase(jobStatus, internalState));
241     }
242
243     @Test
244     public void whenNoNeedToDeleteMyself_internalStateMovesFromWatchingToTerminal() {
245         MockCommandTestingStateMachine underTest = new MockCommandTestingStateMachine(InternalState.WATCHING, Delete, COMPLETED, false);
246         assertEquals(InternalState.TERMINAL, underTest.calcNextStateDeletePhase(COMPLETED, InternalState.WATCHING));
247     }
248
249     @DataProvider
250     public static Object[][] testShallStopJobDataProvider() {
251         return new Object[][]{
252                 {IN_PROGRESS, None, false, false},
253                 {COMPLETED_WITH_NO_ACTION, None, false, false},
254                 {COMPLETED, None, false, false},
255                 {FAILED, None, false, true},
256                 {COMPLETED_WITH_ERRORS, None, false, true},
257                 {COMPLETED_WITH_ERRORS, None, true, false},
258                 {FAILED, None, true, false},
259                 {FAILED, Delete, true, true},
260                 {FAILED, Create, true, true},
261         };
262     }
263
264
265     @Test(dataProvider = "testShallStopJobDataProvider")
266     public void testShallStopJob(Job.JobStatus jobStatus, Action action, boolean isService, boolean expectedResult) {
267         //in this test, there is no meaning to constructor parameters besides isService
268         MockCommandTestingStateMachine underTest = new MockCommandTestingStateMachine(InternalState.WATCHING, Delete, COMPLETED, false, isService, true);
269
270         BaseResource mockedRequest = mock(BaseResource.class);
271         when(underTest.getSharedData().getRequest()).thenReturn(mockedRequest);
272         when(mockedRequest.getAction()).thenReturn(action);
273
274         assertEquals(expectedResult, underTest.shallStopJob(jobStatus));
275     }
276
277     public static class FakeResourceCreator {
278
279         public static<T> Map<String, T> convertToMap(List<T> list) {
280             if (list==null) {
281                 return null;
282             }
283             return list.stream().collect(Collectors.toMap(x-> UUID.randomUUID().toString(), x->x));
284         }
285
286         static ServiceInstantiation createService(List<Vnf> vnfs, List<Network> networks, List<InstanceGroup> vnfGroups) {
287             return new ServiceInstantiation(mock(ModelInfo.class), null, null, null, null, null, null, null, null, null, null, null, null, null, null,
288                     convertToMap(vnfs),
289                     convertToMap(networks),
290                     convertToMap(vnfGroups),
291                     null,
292                     null, false, 1, false,false,null, null, null, null, null, null, null, null);
293         }
294
295         public static ServiceInstantiation createServiceWith2InstancesInEachLevel(Action action) {
296             return createService(
297                     ImmutableList.of(
298                             createVnf(ImmutableList.of(createVfModule(action), createVfModule(action)), action),
299                             createVnf(ImmutableList.of(createVfModule(action), createVfModule(action)), action)),
300                     ImmutableList.of(
301                             createNetwork(action),
302                             createNetwork(action)),
303                     ImmutableList.of(
304                             createGroup(ImmutableList.of(createMember(action), createMember(action)), action),
305                             createGroup(ImmutableList.of(createMember(action), createMember(action)), action))
306                     );
307         }
308
309         static InstanceGroup createGroup(List<InstanceGroupMember> groupMembers, Action action) {
310             return new InstanceGroup(mock(ModelInfo.class), null, action.name(), false, null, convertToMap(groupMembers), null, null, null,
311                 null, null);
312         }
313
314         static InstanceGroupMember createMember(Action action) {
315             return new InstanceGroupMember(null, action.toString(), null, null, null, null, null);
316         }
317
318         static Vnf createVnf(List<VfModule> vfModules, Action action) {
319             Map<String, Map<String, VfModule>> vfModulesMap = new HashMap<>();
320             vfModulesMap.put("abc",convertToMap(vfModules));
321
322             return new Vnf(mock(ModelInfo.class), null, null, action.toString(), null, null, null, null, null, null, false, null, vfModulesMap, null, null, null,
323                 null, null);
324         }
325
326         static Vnf createVnf(Action action) {
327             return new Vnf(mock(ModelInfo.class), null, null, action.toString(), null, null, null, null, null, null, false, null,null, null, null, null,
328                 null, null);
329         }
330
331         static VfModule createVfModule(Action action) {
332             return new VfModule(mock(ModelInfo.class), null, null, action.toString(), null, null, null, null, null,
333                 false, false, null, null, null, null, null, null, null, null, null);
334         }
335
336         static Network createNetwork(Action action) {
337             return new Network(mock(ModelInfo.class), null, null, action.toString(), null, null, null, null, null, null, false, null, null, null, null,
338                 null, null);
339         }
340     }
341
342     @DataProvider
343     public static Object[][] testIsDescendantHasActionDataProvider() {
344         return new Object[][]{
345                 {"empty service", Create, false, createService(emptyList(), emptyList(), emptyList())},
346                 {"instance group with None", Create, false, createService(emptyList(), emptyList(), ImmutableList.of(createGroup(emptyList(), None)))},
347                 {"instance group with Create", Create, true, createService(emptyList(), emptyList(), ImmutableList.of(createGroup(emptyList(), Create)))},
348                 {"instance group None + member Delete", Delete, true, createService(emptyList(), emptyList(), ImmutableList.of(createGroup(ImmutableList.of(createMember(Delete)), None)))},
349                 {"instance group None + member Create", Delete, false, createService(emptyList(), emptyList(), ImmutableList.of(createGroup(ImmutableList.of(createMember(Create)), None)))},
350                 {"instance group None + member Create + member Delete", Delete, true,
351                         createService(emptyList(), emptyList(), ImmutableList.of(createGroup(ImmutableList.of(createMember(Create), createMember(Delete)), None)))},
352                 {"vnf Create", Delete, false, createService(ImmutableList.of(createVnf(emptyList(), Create)), emptyList(),emptyList())},
353                 {"vnf Create", Create, true, createService(ImmutableList.of(createVnf(emptyList(), Create)), emptyList(),emptyList())},
354                 {"vnf Create null VfModules internal map", Create, false, createService(ImmutableList.of(createVnf(null, Delete)), emptyList(),emptyList())},
355                 {"vnf Delete with null VfModules", Create, false, createService(ImmutableList.of(createVnf(Delete)), emptyList(),emptyList())},
356                 {"vnf None + VfModule Create", Create, true, createService(ImmutableList.of(createVnf(ImmutableList.of(createVfModule(Create)), None)), emptyList(),emptyList())},
357                 {"vnf None + VfModule None", Create, false, createService(ImmutableList.of(createVnf(ImmutableList.of(createVfModule(None)), None)), emptyList(),emptyList())},
358                 {"network Create", Create, true, createService(emptyList(), ImmutableList.of(createNetwork(Create)), emptyList())},
359                 {"network Delete", Create, false, createService(emptyList(), ImmutableList.of(createNetwork(Delete)), emptyList())},
360         };
361     }
362
363     @Test(dataProvider = "testIsDescendantHasActionDataProvider")
364     public void testIsDescendantHasAction(String desc, Action action, boolean expectedResult, BaseResource request) {
365         //in this test, there is no meaning to constructor parameters
366         MockCommand underTest = new MockCommand(InternalState.WATCHING, Delete, COMPLETED);
367         assertEquals(expectedResult, underTest.isDescendantHasAction(request, action));
368     }
369
370     @DataProvider
371     public static Object[][] testCallDataProvider() {
372         return new Object[][]{
373                 {"initial state with successful creating children" ,InternalState.INITIAL, COMPLETED, InternalState.WATCHING, RESOURCE_IN_PROGRESS},
374                 {"initial state with failed creating children", InternalState.INITIAL, FAILED, null, FAILED},
375                 {"watching state with children still in progress" ,InternalState.WATCHING, RESOURCE_IN_PROGRESS, InternalState.WATCHING, RESOURCE_IN_PROGRESS},
376                 {"watching state with children that completed with errors" ,InternalState.WATCHING, COMPLETED_WITH_ERRORS, null, COMPLETED_WITH_ERRORS},
377                 {"watching state with children that completed with no action" ,InternalState.WATCHING, COMPLETED_WITH_NO_ACTION, InternalState.DELETE_MYSELF, RESOURCE_IN_PROGRESS},
378                 {"watching state with children that has completed" ,InternalState.WATCHING, COMPLETED, InternalState.DELETE_MYSELF, RESOURCE_IN_PROGRESS},
379                 {"mso call state that failed" ,InternalState.DELETE_MYSELF, FAILED, null, FAILED},
380                 //TODO handle AAI get unique name state {"mso call state that still in progress" ,InternalState.DELETE_MYSELF, Job.JobStatus.FAILED, null, Job.JobStatus.FAILED, false},
381                 {"mso call state that success" ,InternalState.DELETE_MYSELF, COMPLETED, InternalState.IN_PROGRESS, RESOURCE_IN_PROGRESS},
382                 {"in progress return in progress" ,InternalState.IN_PROGRESS, IN_PROGRESS, InternalState.IN_PROGRESS, RESOURCE_IN_PROGRESS},
383                 {"in progress return in pause" ,InternalState.IN_PROGRESS, PAUSE, InternalState.IN_PROGRESS, RESOURCE_IN_PROGRESS},
384                 {"in progress return in pause" ,InternalState.IN_PROGRESS, STOPPED, null, STOPPED},
385                 {"in progress return in pause" ,InternalState.IN_PROGRESS, FAILED, null, FAILED},
386                 {"in progress return in pause" ,InternalState.IN_PROGRESS, COMPLETED, null, COMPLETED},
387
388         };
389     }
390
391     @Test(dataProvider = "testCallDataProvider")
392     public void whenCallCommandWithDeletePhase_nextJobStatusAndInternalStateAreAsExpected(
393             String description, InternalState internalState, Job.JobStatus currentStateResult,
394             InternalState expectedNextState, Job.JobStatus expectedNextStatus) {
395
396         MockCommandTestingStateMachine underTest = new MockCommandTestingStateMachine(internalState, Delete, currentStateResult, true);
397         NextCommand nextCommand = underTest.call();
398         assertEquals(expectedNextStatus, nextCommand.getStatus());
399
400         //expectedNextState == null means nextCommand has no real command
401         if (expectedNextState!=null) {
402             assertEquals(expectedNextState, (nextCommand.getCommand().getData().get(INTERNAL_STATE)));
403             assertFalse(nextCommand.getStatus().isFinal());
404         }
405         else {
406             assertNull(nextCommand.getCommand());
407             assertTrue(nextCommand.getStatus().isFinal());
408         }
409     }
410
411     @DataProvider
412     public static Object[][] InProgressDataProvider() {
413         return Stream.of(Job.JobStatus.values())
414                 .map(status -> new Object[] { status })
415                 .toArray(Object[][]::new);
416     }
417
418     @Test(dataProvider = "InProgressDataProvider")
419     public void whenGetResultFromMso_InProgressReturnThem(Job.JobStatus mockedJobStatus) {
420         Job.JobStatus expectedJobStatus = (mockedJobStatus== PAUSE) ? IN_PROGRESS : mockedJobStatus;
421         MockCommand underTest = new MockCommand(InternalState.IN_PROGRESS, Delete, mockedJobStatus);
422         when(underTest.getInProgressStatusService().call(any(), any(), any())).thenReturn(mockedJobStatus);
423
424         // we need to mock the request for pause after completion only when the status is completed
425         if(mockedJobStatus == COMPLETED){
426             BaseResource mockedBaseResource = mock(BaseResource.class);
427             when(underTest.getSharedData().getRequest()).thenReturn(mockedBaseResource);
428         }
429         assertEquals(expectedJobStatus, underTest.inProgress());
430     }
431
432     @DataProvider
433     public static Object[][] InProgressExceptionsDataProvider() {
434         return new Object[][]{
435                 {new ProcessingException(""), IN_PROGRESS},
436                 {new InProgressStatusService.BadResponseFromMso(null), IN_PROGRESS},
437                 {new GenericUncheckedException(""), STOPPED }
438         };
439     }
440
441     @Test(dataProvider = "InProgressExceptionsDataProvider")
442     public void whenInProgressStatusServiceThrowException_InProgressReturnStatus(Exception exception, Job.JobStatus expectedJobStatus) {
443         MockCommand underTest = new MockCommand(InternalState.IN_PROGRESS, Delete, expectedJobStatus);
444         when(underTest.getInProgressStatusService().call(any(), any(), any())).thenThrow(exception);
445         assertEquals(expectedJobStatus, underTest.inProgress());
446     }
447
448     @DataProvider
449     public static Object[][] testIsNeedToDeleteMySelfDataProvider() {
450         return Stream.of(values())
451                 .map(status -> new Object[] { status })
452                 .toArray(Object[][]::new);
453     }
454
455     @Test(dataProvider = "testIsNeedToDeleteMySelfDataProvider")
456     public void testIsNeedToDeleteMySelf(Action action) {
457         boolean expectedResult = (action== Delete);
458         MockCommand underTest = new MockCommand(InternalState.DELETE_MYSELF, Delete, IN_PROGRESS);
459         BaseResource mockedBaseResource = mock(BaseResource.class);
460         when(underTest.getSharedData().getRequest()).thenReturn(mockedBaseResource);
461         when(mockedBaseResource.getAction()).thenReturn(action);
462         assertEquals(expectedResult, underTest.isNeedToDeleteMyself());
463     }
464
465     @DataProvider
466     public static Object[][] testWatchingDataProvider() {
467         return new Object[][]{
468                 {"all children final, no failed child ", COMPLETED, COMPLETED},
469                 {"all children final, there is failed child ", COMPLETED_WITH_ERRORS, COMPLETED_WITH_ERRORS},
470                 {"not all children final", IN_PROGRESS, IN_PROGRESS},
471         };
472     }
473
474     @Test(dataProvider = "testWatchingDataProvider")
475     public void testWatching(String desc, Job.JobStatus childrenJobsStatus, Job.JobStatus expectedJobStatus) {
476         MockCommand underTest = new MockCommand(InternalState.WATCHING, Delete, IN_PROGRESS);
477         when(underTest.getWatchChildrenJobsBL().retrieveChildrenJobsStatus(any())).thenReturn(childrenJobsStatus);
478         assertEquals(expectedJobStatus, underTest.watchChildren());
479     }
480
481     @DataProvider
482     public static Object[][] testCalcInitialStateDataProvider() {
483         return new Object[][]{
484                 {Delete, true, Delete, InternalState.CREATING_CHILDREN},
485                 {Delete, false, Delete, InternalState.DELETE_MYSELF},
486                 {Delete, false, Create, InternalState.TERMINAL},
487                 {Delete, true, Create, InternalState.CREATING_CHILDREN},
488                 {Create, true, Create, InternalState.CREATE_MYSELF},
489                 {Create, false, Create, InternalState.CREATE_MYSELF},
490                 {Create, false, Delete, InternalState.TERMINAL},
491                 {Create, true, Delete, InternalState.CREATING_CHILDREN},
492                 {Create, true, Resume, InternalState.RESUME_MYSELF},
493                 {Delete, false, Resume, InternalState.TERMINAL},
494         };
495     }
496
497     @Test(dataProvider = "testCalcInitialStateDataProvider")
498     public void testCalcInitialState(Action phase, boolean isDescendantHasAction, Action action, InternalState expectedState) {
499         ResourceCommand underTest = mock(ResourceCommand.class);
500         when(underTest.calcInitialState(any(), any())).thenCallRealMethod();
501         when(underTest.isDescendantHasAction(eq(phase))).thenReturn(isDescendantHasAction);
502         when(underTest.getActionType()).thenReturn(action);
503         when(underTest.isNeedToDeleteMyself()).thenCallRealMethod();
504         when(underTest.isNeedToCreateMyself()).thenCallRealMethod();
505         when(underTest.isNeedToResumeMySelf()).thenCallRealMethod();
506
507         Map<String, String> commandData = ImmutableMap.of(INTERNAL_STATE, InternalState.INITIAL.name());
508         assertEquals(expectedState, underTest.calcInitialState(commandData, phase));
509     }
510
511
512     //throw exception when call to create children
513     //create children is just example, it could be any other method that called by ResourceCommand.invokeCommand
514     public static class MockCommandThrowExceptionOnCreateChildren extends MockCommandTestingStateMachine {
515
516         private final RuntimeException exceptionToThrow;
517
518         public MockCommandThrowExceptionOnCreateChildren(RuntimeException exceptionToThrow) {
519             super(InternalState.CREATING_CHILDREN, Delete, COMPLETED, true);
520             this.exceptionToThrow = exceptionToThrow;
521             doAnswer(returnsFirstArg()).when(this.getWatchChildrenJobsBL()).cumulateJobStatus(any(), any());
522         }
523
524         @NotNull
525         @Override
526         public Job.JobStatus createChildren() {
527             throw exceptionToThrow;
528         }
529     }
530
531     @DataProvider
532     public static Object[][] exceptionAndStateProvider() {
533         return new Object[][]{
534                 {new TryAgainException(new Exception()), RESOURCE_IN_PROGRESS},
535                 {new AbortingException(new Exception()), FAILED},
536         };
537     }
538
539     @Test(dataProvider = "exceptionAndStateProvider")
540     public void whenKnownExceptionThrownInCommandInvocation_thenStateIsAsExpected(RuntimeException exception, Job.JobStatus expectedNextStatus) {
541         MockCommandTestingStateMachine underTest = new MockCommandThrowExceptionOnCreateChildren(exception);
542         NextCommand nextCommand = underTest.call();
543         assertEquals(expectedNextStatus, nextCommand.getStatus());
544     }
545
546     @DataProvider
547     public static Object[][] resourcePosition() {
548         return new Object[][]{
549             {1, 2, 3, ImmutableList.of(1,2,3)},
550             {null, 1, 100, ImmutableList.of(101,1,100)},
551             {null, null, null, ImmutableList.of(1,2,3)},
552             {1,2,2, ImmutableList.of(1,2,2)}
553         };
554     }
555
556     @Test(dataProvider = "resourcePosition")
557     public void sortChildren_sortAccordingToPosition(Integer firstPosition, Integer secondPosition, Integer thirdPosition, List<Integer> expectedPositions){
558         BaseResource mockedRequest1 = mock(BaseResource.class);
559         when(mockedRequest1.getPosition()).thenReturn(firstPosition);
560         BaseResource mockedRequest2 = mock(BaseResource.class);
561         when(mockedRequest2.getPosition()).thenReturn(secondPosition);
562         BaseResource mockedRequest3 = mock(BaseResource.class);
563         when(mockedRequest3.getPosition()).thenReturn(thirdPosition);
564
565         MockCommand underTest = new MockCommand(InternalState.CREATING_CHILDREN, Create, IN_PROGRESS);
566         List<Pair<BaseResource, Integer>> sortedList = underTest.setPositionWhereIsMissing(ImmutableList.of(mockedRequest1, mockedRequest2, mockedRequest3));
567
568         assertEquals(sortedList.get(0).getSecond(),expectedPositions.get(0));
569         assertEquals(sortedList.get(1).getSecond(),expectedPositions.get(1));
570         assertEquals(sortedList.get(2).getSecond(),expectedPositions.get(2));
571     }
572 }