9f252c5e8f601dc7701250307109b3306460f080
[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 com.google.common.collect.ImmutableMap;
24 import org.jetbrains.annotations.NotNull;
25 import org.onap.vid.exceptions.GenericUncheckedException;
26 import org.onap.vid.job.Job;
27 import org.onap.vid.job.JobAdapter;
28 import org.onap.vid.job.NextCommand;
29 import org.onap.vid.job.impl.JobSharedData;
30 import org.onap.vid.model.Action;
31 import org.onap.vid.model.serviceInstantiation.BaseResource;
32 import org.onap.vid.mso.RestMsoImplementation;
33 import org.springframework.http.HttpMethod;
34 import org.testng.annotations.DataProvider;
35 import org.testng.annotations.Test;
36
37 import javax.ws.rs.ProcessingException;
38 import java.util.Collections;
39 import java.util.Optional;
40 import java.util.stream.Stream;
41
42 import static org.mockito.ArgumentMatchers.any;
43 import static org.mockito.Mockito.*;
44 import static org.onap.vid.job.command.ResourceCommandKt.ACTION_PHASE;
45 import static org.onap.vid.job.command.ResourceCommandKt.INTERNAL_STATE;
46 import static org.onap.vid.utils.Logging.getMethodCallerName;
47 import static org.testng.Assert.assertNull;
48 import static org.testng.Assert.assertTrue;
49 import static org.testng.AssertJUnit.assertEquals;
50 import static org.testng.AssertJUnit.assertFalse;
51
52 public class ResourceCommandTest {
53
54     public static class MockCommand extends ResourceCommand {
55
56         public MockCommand(InternalState mockState, Action mockPhase, Job.JobStatus mockedJobStatus) {
57             super(mock(RestMsoImplementation.class, RETURNS_MOCKS), mock(InProgressStatusService.class), mock(MsoResultHandlerService.class, RETURNS_MOCKS), mock(WatchChildrenJobsBL.class));
58
59             this.mockedJobStatus = mockedJobStatus;
60             this.mockState = mockState;
61             this.mockPhase = mockPhase;
62             if (mockState==InternalState.INITIAL) {
63                 init(mock(JobSharedData.class), Collections.emptyMap());
64             }
65             else {
66                 init(mock(JobSharedData.class), ImmutableMap.of(INTERNAL_STATE, mockState.name(), ACTION_PHASE, mockPhase.name()));
67             }
68             when(this.getWatchChildrenJobsBL().cumulateJobStatus(any(), any())).thenReturn(mockedJobStatus);
69         }
70
71         private final Job.JobStatus mockedJobStatus;
72         private final InternalState mockState;
73         private final Action mockPhase;
74
75
76         @NotNull
77         @Override
78         public Job.JobStatus createChildren() {
79             if (mockState == InternalState.CREATING_CHILDREN || (mockState == InternalState.INITIAL && mockPhase== Action.Delete))
80                 return mockedJobStatus;
81             throw (new RuntimeException("Not expected to call "+getMethodCallerName()));
82         }
83
84         protected Job.JobStatus mockedStatusOrThrow(InternalState expectedState) {
85             if (mockState == expectedState)
86                 return mockedJobStatus;
87             throw (new RuntimeException("Not expected to call "+getMethodCallerName()));
88         }
89
90         protected MsoRestCallPlan mockedPlanOrThrow(InternalState expectedState) {
91             if (mockState == expectedState)
92                 return new MsoRestCallPlan(HttpMethod.POST, "path", Optional.empty(), Optional.empty(), "nothing");
93             throw (new RuntimeException("Not expected to call "+getMethodCallerName()));
94         }
95
96         @NotNull
97         @Override
98         public MsoRestCallPlan planCreateMyselfRestCall(@NotNull CommandParentData commandParentData, @NotNull JobAdapter.AsyncJobRequest request, @NotNull String userId) {
99             return mockedPlanOrThrow(InternalState.CREATE_MYSELF);
100         }
101
102         @NotNull
103         @Override
104         public MsoRestCallPlan planDeleteMyselfRestCall(@NotNull CommandParentData commandParentData, @NotNull JobAdapter.AsyncJobRequest request, @NotNull String userId) {
105             return mockedPlanOrThrow(InternalState.DELETE_MYSELF);
106         }
107     }
108
109     public static class MockCommandTestingStateMachine extends MockCommand {
110
111         private final JobSharedData sharedData;
112
113         public MockCommandTestingStateMachine(InternalState mockState, Action mockPhase, Job.JobStatus mockedJobStatus, boolean mockedNeedToDeleteMySelf) {
114             this(mockState, mockPhase, mockedJobStatus, mockedNeedToDeleteMySelf, false);
115         }
116
117         public MockCommandTestingStateMachine(InternalState mockState, Action mockPhase, Job.JobStatus mockedJobStatus, boolean mockedNeedToDeleteMySelf, boolean isService) {
118             super(mockState, mockPhase, mockedJobStatus);
119             this.mockedNeedToDeleteMySelf = mockedNeedToDeleteMySelf;
120             this.isService = isService;
121             this.sharedData = mock(JobSharedData.class, RETURNS_MOCKS);
122         }
123
124         protected final boolean mockedNeedToDeleteMySelf;
125         private final boolean isService;
126
127         @NotNull
128         @Override
129         public Job.JobStatus inProgress() {
130             return mockedStatusOrThrow(InternalState.IN_PROGRESS);
131         }
132
133         @NotNull
134         @Override
135         public Job.JobStatus watchChildren() {
136             return mockedStatusOrThrow(InternalState.WATCHING);
137         }
138
139         @Override
140         public boolean isNeedToDeleteMyself() {
141             return mockedNeedToDeleteMySelf;
142         }
143
144         @Override
145         protected boolean isServiceCommand() {
146             return isService;
147         }
148
149         @Override
150         public JobSharedData getSharedData() {
151             return sharedData;
152         }
153     }
154
155     @DataProvider
156     public static Object[][] nextStateDeletePhaseProvider() {
157         return new Object[][]{
158                 {InternalState.CREATING_CHILDREN, Job.JobStatus.COMPLETED, InternalState.WATCHING},
159                 {InternalState.WATCHING, Job.JobStatus.COMPLETED, InternalState.DELETE_MYSELF},
160                 {InternalState.WATCHING, Job.JobStatus.IN_PROGRESS, InternalState.WATCHING},
161                 {InternalState.WATCHING, Job.JobStatus.RESOURCE_IN_PROGRESS, InternalState.WATCHING},
162                 {InternalState.DELETE_MYSELF, Job.JobStatus.COMPLETED, InternalState.IN_PROGRESS},
163                 {InternalState.IN_PROGRESS, Job.JobStatus.COMPLETED, InternalState.TERMINAL},
164                 {InternalState.IN_PROGRESS, Job.JobStatus.IN_PROGRESS, InternalState.IN_PROGRESS},
165                 {InternalState.IN_PROGRESS, Job.JobStatus.RESOURCE_IN_PROGRESS, InternalState.IN_PROGRESS},
166         };
167     }
168
169     @Test(dataProvider = "nextStateDeletePhaseProvider")
170     public void whenCalcNextStateDeletePhase_expectedStateIsReturned(
171             InternalState internalState, Job.JobStatus jobStatus, InternalState expectedState) {
172
173         //there is no meaning to the constructor inputs here
174         MockCommandTestingStateMachine underTest = new MockCommandTestingStateMachine(InternalState.TERMINAL, Action.Delete, Job.JobStatus.FAILED, true);
175         assertEquals(expectedState, underTest.calcNextStateDeletePhase(jobStatus, internalState));
176     }
177
178     @Test
179     public void whenNoNeedToDeleteMyself_internalStateMovesFromWatchingToTerminal() {
180         MockCommandTestingStateMachine underTest = new MockCommandTestingStateMachine(InternalState.WATCHING, Action.Delete, Job.JobStatus.COMPLETED, false);
181         assertEquals(InternalState.TERMINAL, underTest.calcNextStateDeletePhase(Job.JobStatus.COMPLETED, InternalState.WATCHING));
182     }
183
184     @DataProvider
185     public static Object[][] testShallStopJobDataProvider() {
186         return new Object[][]{
187                 {Job.JobStatus.IN_PROGRESS, Action.None, false, false},
188                 {Job.JobStatus.COMPLETED_WITH_NO_ACTION, Action.None, false, false},
189                 {Job.JobStatus.COMPLETED, Action.None, false, false},
190                 {Job.JobStatus.FAILED, Action.None, false, true},
191                 {Job.JobStatus.COMPLETED_WITH_ERRORS, Action.None, false, true},
192                 {Job.JobStatus.COMPLETED_WITH_ERRORS, Action.None, true, false},
193                 {Job.JobStatus.FAILED, Action.None, true, false},
194                 {Job.JobStatus.FAILED, Action.Delete, true, true},
195                 {Job.JobStatus.FAILED, Action.Create, true, true},
196         };
197     }
198
199
200     @Test(dataProvider = "testShallStopJobDataProvider")
201     public void testShallStopJob(Job.JobStatus jobStatus, Action action, boolean isService, boolean expectedResult) {
202         //in this test, there is no meaning to constructor parameters besides isService
203         MockCommandTestingStateMachine underTest = new MockCommandTestingStateMachine(InternalState.WATCHING, Action.Delete, Job.JobStatus.COMPLETED, false, isService);
204
205         BaseResource mockedRequest = mock(BaseResource.class);
206         when(underTest.getSharedData().getRequest()).thenReturn(mockedRequest);
207         when(mockedRequest.getAction()).thenReturn(action);
208
209         assertEquals(expectedResult, underTest.shallStopJob(jobStatus));
210     }
211
212     @DataProvider
213     public static Object[][] testCallDataProvider() {
214         return new Object[][]{
215                 {"initial state with successful creating children" ,InternalState.INITIAL, Job.JobStatus.COMPLETED, InternalState.WATCHING, Job.JobStatus.RESOURCE_IN_PROGRESS},
216                 {"initial state with failed creating children", InternalState.INITIAL, Job.JobStatus.FAILED, null, Job.JobStatus.FAILED},
217                 {"watching state with children still in progress" ,InternalState.WATCHING, Job.JobStatus.RESOURCE_IN_PROGRESS, InternalState.WATCHING, Job.JobStatus.RESOURCE_IN_PROGRESS},
218                 {"watching state with children that completed with errors" ,InternalState.WATCHING, Job.JobStatus.COMPLETED_WITH_ERRORS, null, Job.JobStatus.COMPLETED_WITH_ERRORS},
219                 {"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},
220                 {"watching state with children that has completed" ,InternalState.WATCHING, Job.JobStatus.COMPLETED, InternalState.DELETE_MYSELF, Job.JobStatus.RESOURCE_IN_PROGRESS},
221                 {"mso call state that failed" ,InternalState.DELETE_MYSELF, Job.JobStatus.FAILED, null, Job.JobStatus.FAILED},
222                 //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},
223                 {"mso call state that success" ,InternalState.DELETE_MYSELF, Job.JobStatus.COMPLETED, InternalState.IN_PROGRESS, Job.JobStatus.RESOURCE_IN_PROGRESS},
224                 {"in progress return in progress" ,InternalState.IN_PROGRESS, Job.JobStatus.IN_PROGRESS, InternalState.IN_PROGRESS, Job.JobStatus.RESOURCE_IN_PROGRESS},
225                 {"in progress return in pause" ,InternalState.IN_PROGRESS, Job.JobStatus.PAUSE, InternalState.IN_PROGRESS, Job.JobStatus.RESOURCE_IN_PROGRESS},
226                 {"in progress return in pause" ,InternalState.IN_PROGRESS, Job.JobStatus.STOPPED, null, Job.JobStatus.STOPPED},
227                 {"in progress return in pause" ,InternalState.IN_PROGRESS, Job.JobStatus.FAILED, null, Job.JobStatus.FAILED},
228                 {"in progress return in pause" ,InternalState.IN_PROGRESS, Job.JobStatus.COMPLETED, null, Job.JobStatus.COMPLETED},
229
230         };
231     }
232
233     @Test(dataProvider = "testCallDataProvider")
234     public void whenCallCommandWithDeletePhase_nextJobStatusAndInternalStateAreAsExpected(
235             String description, InternalState internalState, Job.JobStatus currentStateResult,
236             InternalState expectedNextState, Job.JobStatus expectedNextStatus) {
237
238         MockCommandTestingStateMachine underTest = new MockCommandTestingStateMachine(internalState, Action.Delete, currentStateResult, true);
239         NextCommand nextCommand = underTest.call();
240         assertEquals(expectedNextStatus, nextCommand.getStatus());
241
242         //expectedNextState == null means nextCommand has no real command
243         if (expectedNextState!=null) {
244             assertEquals(expectedNextState, (nextCommand.getCommand().getData().get(INTERNAL_STATE)));
245             assertFalse(nextCommand.getStatus().isFinal());
246         }
247         else {
248             assertNull(nextCommand.getCommand());
249             assertTrue(nextCommand.getStatus().isFinal());
250         }
251     }
252
253     @Test(expectedExceptions = IllegalStateException.class)
254     public void whenCommandInUnMappedState_exceptionIsThrown() {
255         MockCommandTestingStateMachine underTest = new MockCommandTestingStateMachine(InternalState.TERMINAL, Action.Delete, Job.JobStatus.COMPLETED, true);
256         underTest.call();
257     }
258
259     @DataProvider
260     public static Object[][] InProgressDataProvider() {
261         return Stream.of(Job.JobStatus.values())
262                 .map(status -> new Object[] { status })
263                 .toArray(Object[][]::new);
264     }
265
266     @Test(dataProvider = "InProgressDataProvider")
267     public void whenGetResultFromMso_InProgressReturnThem(Job.JobStatus mockedJobStatus) {
268         Job.JobStatus expectedJobStatus = (mockedJobStatus== Job.JobStatus.PAUSE) ? Job.JobStatus.IN_PROGRESS : mockedJobStatus;
269         MockCommand underTest = new MockCommand(InternalState.IN_PROGRESS, Action.Delete, mockedJobStatus);
270         when(underTest.getInProgressStatusService().call(any(), any(), any())).thenReturn(mockedJobStatus);
271         assertEquals(expectedJobStatus, underTest.inProgress());
272     }
273
274     @DataProvider
275     public static Object[][] InProgressExceptionsDataProvider() {
276         return new Object[][]{
277                 {new ProcessingException(""), Job.JobStatus.IN_PROGRESS},
278                 {new InProgressStatusService.BadResponseFromMso(null), Job.JobStatus.IN_PROGRESS},
279                 {new GenericUncheckedException(""),Job.JobStatus.STOPPED }
280         };
281     }
282
283     @Test(dataProvider = "InProgressExceptionsDataProvider")
284     public void whenInProgressStatusServiceThrowException_InProgressReturnStatus(Exception exception, Job.JobStatus expectedJobStatus) {
285         MockCommand underTest = new MockCommand(InternalState.IN_PROGRESS, Action.Delete, expectedJobStatus);
286         when(underTest.getInProgressStatusService().call(any(), any(), any())).thenThrow(exception);
287         assertEquals(expectedJobStatus, underTest.inProgress());
288     }
289
290     @DataProvider
291     public static Object[][] testIsNeedToDeleteMySelfDataProvider() {
292         return Stream.of(Action.values())
293                 .map(status -> new Object[] { status })
294                 .toArray(Object[][]::new);
295     }
296
297     @Test(dataProvider = "testIsNeedToDeleteMySelfDataProvider")
298     public void testIsNeedToDeleteMySelf(Action action) {
299         boolean expectedResult = (action== Action.Delete);
300         MockCommand underTest = new MockCommand(InternalState.DELETE_MYSELF, Action.Delete, Job.JobStatus.IN_PROGRESS);
301         BaseResource mockedBaseResource = mock(BaseResource.class);
302         when(underTest.getSharedData().getRequest()).thenReturn(mockedBaseResource);
303         when(mockedBaseResource.getAction()).thenReturn(action);
304         assertEquals(expectedResult, underTest.isNeedToDeleteMyself());
305     }
306
307     @DataProvider
308     public static Object[][] testWatchingDataProvider() {
309         return new Object[][]{
310                 {"all children final, no failed child ", Job.JobStatus.COMPLETED, Job.JobStatus.COMPLETED},
311                 {"all children final, there is failed child ", Job.JobStatus.COMPLETED_WITH_ERRORS, Job.JobStatus.COMPLETED_WITH_ERRORS},
312                 {"not all children final", Job.JobStatus.IN_PROGRESS, Job.JobStatus.IN_PROGRESS},
313         };
314     }
315
316     @Test(dataProvider = "testWatchingDataProvider")
317     public void testWatching(String desc, Job.JobStatus childrenJobsStatus, Job.JobStatus expectedJobStatus) {
318         MockCommand underTest = new MockCommand(InternalState.WATCHING, Action.Delete, Job.JobStatus.IN_PROGRESS);
319         when(underTest.getWatchChildrenJobsBL().retrieveChildrenJobsStatus(any())).thenReturn(childrenJobsStatus);
320         assertEquals(expectedJobStatus, underTest.watchChildren());
321     }
322
323 }