Fix for Penetration test _ Session and cookie management
[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(null),
290                     convertToMap(networks),
291                     convertToMap(vnfGroups),
292                     null,
293                     null, false, 1, false,false,null, null, null, null, null, null, null, null);
294         }
295
296         public static ServiceInstantiation createServiceWith2InstancesInEachLevel(Action action) {
297             return createService(
298                     ImmutableList.of(
299                             createVnf(ImmutableList.of(createVfModule(action), createVfModule(action)), action),
300                             createVnf(ImmutableList.of(createVfModule(action), createVfModule(action)), action)),
301                     ImmutableList.of(
302                             createNetwork(action),
303                             createNetwork(action)),
304                     ImmutableList.of(
305                             createGroup(ImmutableList.of(createMember(action), createMember(action)), action),
306                             createGroup(ImmutableList.of(createMember(action), createMember(action)), action))
307                     );
308         }
309
310         static InstanceGroup createGroup(List<InstanceGroupMember> groupMembers, Action action) {
311             return new InstanceGroup(mock(ModelInfo.class), null, action.name(), false, null, convertToMap(groupMembers), null, null, null,
312                 null, null);
313         }
314
315         static InstanceGroupMember createMember(Action action) {
316             return new InstanceGroupMember(null, action.toString(), null, null, null, null, null);
317         }
318
319         static Vnf createVnf(List<VfModule> vfModules, Action action) {
320             Map<String, Map<String, VfModule>> vfModulesMap = new HashMap<>();
321             vfModulesMap.put("abc",convertToMap(vfModules));
322
323             return new Vnf(mock(ModelInfo.class), null, null, action.toString(), null, null, null, null, null, null, false, null, vfModulesMap, null, null, null,
324                 null, null);
325         }
326
327         static Vnf createVnf(Action action) {
328             return new Vnf(mock(ModelInfo.class), null, null, action.toString(), null, null, null, null, null, null, false, null,null, null, null, null,
329                 null, null);
330         }
331
332         static VfModule createVfModule(Action action) {
333             return new VfModule(mock(ModelInfo.class), null, null, action.toString(), null, null, null, null, null,
334                 false, false, null, null, null, null, null, null, null, null, null);
335         }
336
337         static Network createNetwork(Action action) {
338             return new Network(mock(ModelInfo.class), null, null, action.toString(), null, null, null, null, null, null, false, null, null, null, null,
339                 null, null);
340         }
341     }
342
343     @DataProvider
344     public static Object[][] testIsDescendantHasActionDataProvider() {
345         return new Object[][]{
346                 {"empty service", Create, false, createService(emptyList(), emptyList(), emptyList())},
347                 {"instance group with None", Create, false, createService(emptyList(), emptyList(), ImmutableList.of(createGroup(emptyList(), None)))},
348                 {"instance group with Create", Create, true, createService(emptyList(), emptyList(), ImmutableList.of(createGroup(emptyList(), Create)))},
349                 {"instance group None + member Delete", Delete, true, createService(emptyList(), emptyList(), ImmutableList.of(createGroup(ImmutableList.of(createMember(Delete)), None)))},
350                 {"instance group None + member Create", Delete, false, createService(emptyList(), emptyList(), ImmutableList.of(createGroup(ImmutableList.of(createMember(Create)), None)))},
351                 {"instance group None + member Create + member Delete", Delete, true,
352                         createService(emptyList(), emptyList(), ImmutableList.of(createGroup(ImmutableList.of(createMember(Create), createMember(Delete)), None)))},
353                 {"vnf Create", Delete, false, createService(ImmutableList.of(createVnf(emptyList(), Create)), emptyList(),emptyList())},
354                 {"vnf Create", Create, true, createService(ImmutableList.of(createVnf(emptyList(), Create)), emptyList(),emptyList())},
355                 {"vnf Create null VfModules internal map", Create, false, createService(ImmutableList.of(createVnf(null, Delete)), emptyList(),emptyList())},
356                 {"vnf Delete with null VfModules", Create, false, createService(ImmutableList.of(createVnf(Delete)), emptyList(),emptyList())},
357                 {"vnf None + VfModule Create", Create, true, createService(ImmutableList.of(createVnf(ImmutableList.of(createVfModule(Create)), None)), emptyList(),emptyList())},
358                 {"vnf None + VfModule None", Create, false, createService(ImmutableList.of(createVnf(ImmutableList.of(createVfModule(None)), None)), emptyList(),emptyList())},
359                 {"network Create", Create, true, createService(emptyList(), ImmutableList.of(createNetwork(Create)), emptyList())},
360                 {"network Delete", Create, false, createService(emptyList(), ImmutableList.of(createNetwork(Delete)), emptyList())},
361         };
362     }
363
364     @Test(dataProvider = "testIsDescendantHasActionDataProvider")
365     public void testIsDescendantHasAction(String desc, Action action, boolean expectedResult, BaseResource request) {
366         //in this test, there is no meaning to constructor parameters
367         MockCommand underTest = new MockCommand(InternalState.WATCHING, Delete, COMPLETED);
368         assertEquals(expectedResult, underTest.isDescendantHasAction(request, action));
369     }
370
371     @DataProvider
372     public static Object[][] testCallDataProvider() {
373         return new Object[][]{
374                 {"initial state with successful creating children" ,InternalState.INITIAL, COMPLETED, InternalState.WATCHING, RESOURCE_IN_PROGRESS},
375                 {"initial state with failed creating children", InternalState.INITIAL, FAILED, null, FAILED},
376                 {"watching state with children still in progress" ,InternalState.WATCHING, RESOURCE_IN_PROGRESS, InternalState.WATCHING, RESOURCE_IN_PROGRESS},
377                 {"watching state with children that completed with errors" ,InternalState.WATCHING, COMPLETED_WITH_ERRORS, null, COMPLETED_WITH_ERRORS},
378                 {"watching state with children that completed with no action" ,InternalState.WATCHING, COMPLETED_WITH_NO_ACTION, InternalState.DELETE_MYSELF, RESOURCE_IN_PROGRESS},
379                 {"watching state with children that has completed" ,InternalState.WATCHING, COMPLETED, InternalState.DELETE_MYSELF, RESOURCE_IN_PROGRESS},
380                 {"mso call state that failed" ,InternalState.DELETE_MYSELF, FAILED, null, FAILED},
381                 //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},
382                 {"mso call state that success" ,InternalState.DELETE_MYSELF, COMPLETED, InternalState.IN_PROGRESS, RESOURCE_IN_PROGRESS},
383                 {"in progress return in progress" ,InternalState.IN_PROGRESS, IN_PROGRESS, InternalState.IN_PROGRESS, RESOURCE_IN_PROGRESS},
384                 {"in progress return in pause" ,InternalState.IN_PROGRESS, PAUSE, InternalState.IN_PROGRESS, RESOURCE_IN_PROGRESS},
385                 {"in progress return in pause" ,InternalState.IN_PROGRESS, STOPPED, null, STOPPED},
386                 {"in progress return in pause" ,InternalState.IN_PROGRESS, FAILED, null, FAILED},
387                 {"in progress return in pause" ,InternalState.IN_PROGRESS, COMPLETED, null, COMPLETED},
388
389         };
390     }
391
392     @Test(dataProvider = "testCallDataProvider")
393     public void whenCallCommandWithDeletePhase_nextJobStatusAndInternalStateAreAsExpected(
394             String description, InternalState internalState, Job.JobStatus currentStateResult,
395             InternalState expectedNextState, Job.JobStatus expectedNextStatus) {
396
397         MockCommandTestingStateMachine underTest = new MockCommandTestingStateMachine(internalState, Delete, currentStateResult, true);
398         NextCommand nextCommand = underTest.call();
399         assertEquals(expectedNextStatus, nextCommand.getStatus());
400
401         //expectedNextState == null means nextCommand has no real command
402         if (expectedNextState!=null) {
403             assertEquals(expectedNextState, (nextCommand.getCommand().getData().get(INTERNAL_STATE)));
404             assertFalse(nextCommand.getStatus().isFinal());
405         }
406         else {
407             assertNull(nextCommand.getCommand());
408             assertTrue(nextCommand.getStatus().isFinal());
409         }
410     }
411
412     @DataProvider
413     public static Object[][] InProgressDataProvider() {
414         return Stream.of(Job.JobStatus.values())
415                 .map(status -> new Object[] { status })
416                 .toArray(Object[][]::new);
417     }
418
419     @Test(dataProvider = "InProgressDataProvider")
420     public void whenGetResultFromMso_InProgressReturnThem(Job.JobStatus mockedJobStatus) {
421         Job.JobStatus expectedJobStatus = (mockedJobStatus== PAUSE) ? IN_PROGRESS : mockedJobStatus;
422         MockCommand underTest = new MockCommand(InternalState.IN_PROGRESS, Delete, mockedJobStatus);
423         when(underTest.getInProgressStatusService().call(any(), any(), any())).thenReturn(mockedJobStatus);
424
425         // we need to mock the request for pause after completion only when the status is completed
426         if(mockedJobStatus == COMPLETED){
427             BaseResource mockedBaseResource = mock(BaseResource.class);
428             when(underTest.getSharedData().getRequest()).thenReturn(mockedBaseResource);
429         }
430         assertEquals(expectedJobStatus, underTest.inProgress());
431     }
432
433     @DataProvider
434     public static Object[][] InProgressExceptionsDataProvider() {
435         return new Object[][]{
436                 {new ProcessingException(""), IN_PROGRESS},
437                 {new InProgressStatusService.BadResponseFromMso(null), IN_PROGRESS},
438                 {new GenericUncheckedException(""), STOPPED }
439         };
440     }
441
442     @Test(dataProvider = "InProgressExceptionsDataProvider")
443     public void whenInProgressStatusServiceThrowException_InProgressReturnStatus(Exception exception, Job.JobStatus expectedJobStatus) {
444         MockCommand underTest = new MockCommand(InternalState.IN_PROGRESS, Delete, expectedJobStatus);
445         when(underTest.getInProgressStatusService().call(any(), any(), any())).thenThrow(exception);
446         assertEquals(expectedJobStatus, underTest.inProgress());
447     }
448
449     @DataProvider
450     public static Object[][] testIsNeedToDeleteMySelfDataProvider() {
451         return Stream.of(values())
452                 .map(status -> new Object[] { status })
453                 .toArray(Object[][]::new);
454     }
455
456     @Test(dataProvider = "testIsNeedToDeleteMySelfDataProvider")
457     public void testIsNeedToDeleteMySelf(Action action) {
458         boolean expectedResult = (action== Delete);
459         MockCommand underTest = new MockCommand(InternalState.DELETE_MYSELF, Delete, IN_PROGRESS);
460         BaseResource mockedBaseResource = mock(BaseResource.class);
461         when(underTest.getSharedData().getRequest()).thenReturn(mockedBaseResource);
462         when(mockedBaseResource.getAction()).thenReturn(action);
463         assertEquals(expectedResult, underTest.isNeedToDeleteMyself());
464     }
465
466     @DataProvider
467     public static Object[][] testWatchingDataProvider() {
468         return new Object[][]{
469                 {"all children final, no failed child ", COMPLETED, COMPLETED},
470                 {"all children final, there is failed child ", COMPLETED_WITH_ERRORS, COMPLETED_WITH_ERRORS},
471                 {"not all children final", IN_PROGRESS, IN_PROGRESS},
472         };
473     }
474
475     @Test(dataProvider = "testWatchingDataProvider")
476     public void testWatching(String desc, Job.JobStatus childrenJobsStatus, Job.JobStatus expectedJobStatus) {
477         MockCommand underTest = new MockCommand(InternalState.WATCHING, Delete, IN_PROGRESS);
478         when(underTest.getWatchChildrenJobsBL().retrieveChildrenJobsStatus(any())).thenReturn(childrenJobsStatus);
479         assertEquals(expectedJobStatus, underTest.watchChildren());
480     }
481
482     @DataProvider
483     public static Object[][] testCalcInitialStateDataProvider() {
484         return new Object[][]{
485                 {Delete, true, Delete, InternalState.CREATING_CHILDREN},
486                 {Delete, false, Delete, InternalState.DELETE_MYSELF},
487                 {Delete, false, Create, InternalState.TERMINAL},
488                 {Delete, true, Create, InternalState.CREATING_CHILDREN},
489                 {Create, true, Create, InternalState.CREATE_MYSELF},
490                 {Create, false, Create, InternalState.CREATE_MYSELF},
491                 {Create, false, Delete, InternalState.TERMINAL},
492                 {Create, true, Delete, InternalState.CREATING_CHILDREN},
493                 {Create, true, Resume, InternalState.RESUME_MYSELF},
494                 {Delete, false, Resume, InternalState.TERMINAL},
495         };
496     }
497
498     @Test(dataProvider = "testCalcInitialStateDataProvider")
499     public void testCalcInitialState(Action phase, boolean isDescendantHasAction, Action action, InternalState expectedState) {
500         ResourceCommand underTest = mock(ResourceCommand.class);
501         when(underTest.calcInitialState(any(), any())).thenCallRealMethod();
502         when(underTest.isDescendantHasAction(eq(phase))).thenReturn(isDescendantHasAction);
503         when(underTest.getActionType()).thenReturn(action);
504         when(underTest.isNeedToDeleteMyself()).thenCallRealMethod();
505         when(underTest.isNeedToCreateMyself()).thenCallRealMethod();
506         when(underTest.isNeedToResumeMySelf()).thenCallRealMethod();
507
508         Map<String, String> commandData = ImmutableMap.of(INTERNAL_STATE, InternalState.INITIAL.name());
509         assertEquals(expectedState, underTest.calcInitialState(commandData, phase));
510     }
511
512
513     //throw exception when call to create children
514     //create children is just example, it could be any other method that called by ResourceCommand.invokeCommand
515     public static class MockCommandThrowExceptionOnCreateChildren extends MockCommandTestingStateMachine {
516
517         private final RuntimeException exceptionToThrow;
518
519         public MockCommandThrowExceptionOnCreateChildren(RuntimeException exceptionToThrow) {
520             super(InternalState.CREATING_CHILDREN, Delete, COMPLETED, true);
521             this.exceptionToThrow = exceptionToThrow;
522             doAnswer(returnsFirstArg()).when(this.getWatchChildrenJobsBL()).cumulateJobStatus(any(), any());
523         }
524
525         @NotNull
526         @Override
527         public Job.JobStatus createChildren() {
528             throw exceptionToThrow;
529         }
530     }
531
532     @DataProvider
533     public static Object[][] exceptionAndStateProvider() {
534         return new Object[][]{
535                 {new TryAgainException(new Exception()), RESOURCE_IN_PROGRESS},
536                 {new AbortingException(new Exception()), FAILED},
537         };
538     }
539
540     @Test(dataProvider = "exceptionAndStateProvider")
541     public void whenKnownExceptionThrownInCommandInvocation_thenStateIsAsExpected(RuntimeException exception, Job.JobStatus expectedNextStatus) {
542         MockCommandTestingStateMachine underTest = new MockCommandThrowExceptionOnCreateChildren(exception);
543         NextCommand nextCommand = underTest.call();
544         assertEquals(expectedNextStatus, nextCommand.getStatus());
545     }
546
547     @DataProvider
548     public static Object[][] resourcePosition() {
549         return new Object[][]{
550             {1, 2, 3, ImmutableList.of(1,2,3)},
551             {null, 1, 100, ImmutableList.of(101,1,100)},
552             {null, null, null, ImmutableList.of(1,2,3)},
553             {1,2,2, ImmutableList.of(1,2,2)}
554         };
555     }
556
557     @Test(dataProvider = "resourcePosition")
558     public void sortChildren_sortAccordingToPosition(Integer firstPosition, Integer secondPosition, Integer thirdPosition, List<Integer> expectedPositions){
559         BaseResource mockedRequest1 = mock(BaseResource.class);
560         when(mockedRequest1.getPosition()).thenReturn(firstPosition);
561         BaseResource mockedRequest2 = mock(BaseResource.class);
562         when(mockedRequest2.getPosition()).thenReturn(secondPosition);
563         BaseResource mockedRequest3 = mock(BaseResource.class);
564         when(mockedRequest3.getPosition()).thenReturn(thirdPosition);
565
566         MockCommand underTest = new MockCommand(InternalState.CREATING_CHILDREN, Create, IN_PROGRESS);
567         List<Pair<BaseResource, Integer>> sortedList = underTest.setPositionWhereIsMissing(ImmutableList.of(mockedRequest1, mockedRequest2, mockedRequest3));
568
569         assertEquals(sortedList.get(0).getSecond(),expectedPositions.get(0));
570         assertEquals(sortedList.get(1).getSecond(),expectedPositions.get(1));
571         assertEquals(sortedList.get(2).getSecond(),expectedPositions.get(2));
572     }
573 }