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