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