Fix sonar issues
[vfc/nfvo/driver/vnfm/svnfm.git] / nokiav2 / driver / src / test / java / org / onap / vfc / nfvo / driver / vnfm / svnfm / nokia / vnfm / TestJobManager.java
1 /*
2  * Copyright 2016-2017, Nokia Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.vnfm;
17
18 import com.google.common.collect.Lists;
19 import com.google.gson.JsonElement;
20 import com.google.gson.JsonParser;
21 import com.nokia.cbam.lcm.v32.model.*;
22 import io.reactivex.Observable;
23 import java.util.ArrayList;
24 import java.util.List;
25 import java.util.NoSuchElementException;
26 import java.util.UUID;
27 import java.util.concurrent.ExecutorService;
28 import java.util.concurrent.Executors;
29 import java.util.concurrent.Future;
30 import javax.servlet.http.HttpServletResponse;
31 import org.junit.Before;
32 import org.junit.Test;
33 import org.mockito.ArgumentCaptor;
34 import org.mockito.InjectMocks;
35 import org.mockito.Mock;
36 import org.mockito.Mockito;
37 import org.mockito.invocation.InvocationOnMock;
38 import org.mockito.stubbing.Answer;
39 import org.onap.vnfmdriver.model.JobDetailInfo;
40 import org.onap.vnfmdriver.model.JobResponseInfo;
41 import org.onap.vnfmdriver.model.JobStatus;
42 import org.springframework.test.util.ReflectionTestUtils;
43 import org.threeten.bp.OffsetDateTime;
44
45 import static junit.framework.TestCase.*;
46 import static org.mockito.Mockito.*;
47 import static org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.util.CbamUtils.SEPARATOR;
48 import static org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.vnfm.CbamRestApiProvider.NOKIA_LCM_API_VERSION;
49 import static org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.vnfm.JobManager.extractOnapJobId;
50 import static org.onap.vnfmdriver.model.JobStatus.*;
51
52 public class TestJobManager extends TestBase {
53
54     @Mock
55     private HttpServletResponse httpResponse;
56
57     @InjectMocks
58     private JobManager jobManager;
59     private List<VnfInfo> vnfs = new ArrayList<>();
60
61     @Before
62     public void initMocks() throws Exception {
63         ReflectionTestUtils.setField(JobManager.class, "logger", logger);
64         when(vnfApi.vnfsGet(NOKIA_LCM_API_VERSION)).thenReturn(buildObservable(vnfs));
65         when(selfRegistrationManager.isReady()).thenReturn(true);
66     }
67
68     /**
69      * Only the _ can be used as separator
70      * . / % & handled specially in URLs
71      * - used in CBAM for separation
72      */
73     @Test
74     public void testSeparator() {
75         assertEquals("_", SEPARATOR);
76     }
77
78     /**
79      * The operation result must contain the ONAP job identifier under the jobId field
80      */
81     @Test
82     public void testJobIdExtractionFromOperationResult() {
83         assertEquals("1234", extractOnapJobId(new JsonParser().parse("{ \"additionalParams\" : { \"jobId\" : \"1234\"}}")));
84         try {
85             extractOnapJobId(new JsonParser().parse("{ }"));
86             fail();
87         } catch (NoSuchElementException e) {
88             assertEquals("The operation result {} does not contain the mandatory additionalParams structure", e.getMessage());
89         }
90         try {
91             extractOnapJobId(new JsonParser().parse("{ \"additionalParams\" : { } }"));
92             fail();
93         } catch (NoSuchElementException e) {
94             assertEquals("The operation result {\"additionalParams\":{}} does not contain the mandatory jobId in the additionalParams structure", e.getMessage());
95         }
96     }
97
98     /**
99      * If the VNF does not exists but the job manager still runs the VNF manipulation process the job is reported to be running
100      */
101     @Test
102     public void testJobForNonExistingVnfReportedRunningIfJobIsOngoing() throws Exception {
103         String jobId = jobManager.spawnJob(VNF_ID, httpResponse);
104         //when
105         JobDetailInfo job = jobManager.getJob(VNFM_ID, jobId);
106         //verify
107         assertResult(jobId, job, STARTED, "50", "Operation started");
108     }
109
110     /**
111      * If the VNF does not exists and the internal job is not running the job is reported to be finished
112      */
113     @Test
114     public void testJobForExistingVnfReportedRunningIfJobIsFinished() throws Exception {
115         String jobId = jobManager.spawnJob(VNF_ID, httpResponse);
116         jobManager.jobFinished(jobId);
117         //when
118         JobDetailInfo job = jobManager.getJob(VNFM_ID, jobId);
119         //verify
120         assertResult(jobId, job, JobStatus.FINISHED, "100", "Operation finished");
121     }
122
123     /**
124      * Spawning jobs after preparing for shutdown results in error
125      */
126     @Test
127     public void testNoMoreJobsAreAllowedAfterPrepareForShutdown() throws Exception {
128         jobManager.prepareForShutdown();
129         //when
130         try {
131             jobManager.spawnJob(JOB_ID, httpResponse);
132             fail();
133         } catch (Exception e) {
134             verify(logger).error("The service is preparing to shut down");
135         }
136     }
137
138     /**
139      * Verify if the jobId has valid format
140      */
141     @Test
142     public void testJobIdValidation() throws Exception {
143         try {
144             //when
145             jobManager.getJob(VNFM_ID, "bad");
146             //verify
147             fail();
148         } catch (IllegalArgumentException e) {
149             assertEquals("The jobId should be in the <vnfId>_<UUID> format, but was bad", e.getMessage());
150         }
151         try {
152             //when
153             jobManager.getJob(VNFM_ID, "vnfId_");
154             //verify
155             fail();
156         } catch (IllegalArgumentException e) {
157             assertEquals("The UUID in the jobId (vnfId_) can not be empty", e.getMessage());
158         }
159         try {
160             //when
161             jobManager.getJob(VNFM_ID, "_UUID");
162             //verify
163             fail();
164         } catch (IllegalArgumentException e) {
165             assertEquals("The vnfId in the jobId (_UUID) can not be empty", e.getMessage());
166         }
167     }
168
169     /**
170      * If the VNF exists but no operation execution is present with given internalJobId, than the state of the
171      * job is ongoing if the internal job is ongoing
172      */
173     @Test
174     public void testExistingVnfWithNotYetStartedOperation() throws Exception {
175         String jobId = jobManager.spawnJob(VNF_ID, httpResponse);
176         VnfInfo vnf = new VnfInfo();
177         vnf.setId(VNF_ID);
178         vnfs.add(vnf);
179         VnfInfo detailedVnf = new VnfInfo();
180         detailedVnf.setId(VNF_ID);
181         when(vnfApi.vnfsVnfInstanceIdGet(VNF_ID, NOKIA_LCM_API_VERSION)).thenReturn(buildObservable(detailedVnf));
182         JobDetailInfo job = jobManager.getJob(VNFM_ID, jobId);
183         //verify
184         assertResult(jobId, job, STARTED, "50", "Operation started");
185         assertTrue(jobManager.hasOngoingJobs());
186     }
187
188     /**
189      * If the VNF exists but no operation execution is present with given internalJobId, than the state of the
190      * job is failed if the internal job is finished (the operation on CBAM was not able to start)
191      */
192     @Test
193     public void testExistingVnfWithNotUnableToStartOperation() throws Exception {
194         String jobId = jobManager.spawnJob(VNF_ID, httpResponse);
195         VnfInfo vnf = new VnfInfo();
196         vnf.setId(VNF_ID);
197         vnfs.add(vnf);
198         VnfInfo detailedVnf = new VnfInfo();
199         detailedVnf.setId(VNF_ID);
200         when(vnfApi.vnfsVnfInstanceIdGet(VNF_ID, NOKIA_LCM_API_VERSION)).thenReturn(buildObservable(detailedVnf));
201         jobManager.jobFinished(jobId);
202         JobDetailInfo job = jobManager.getJob(VNFM_ID, jobId);
203         //verify
204         assertResult(jobId, job, ERROR, "100", "Operation failed due to The requested operation was not able to start on CBAM");
205         assertFalse(jobManager.hasOngoingJobs());
206     }
207
208     /**
209      * If the VNF exists but and the operation execution is present with given internalJobId, than the state of the
210      * job is ongoing if the operation is ongoing
211      */
212     @Test
213     public void testExistingVnfWithStartedOperation() throws Exception {
214         String jobId = jobManager.spawnJob(VNF_ID, httpResponse);
215         VnfInfo vnf = new VnfInfo();
216         vnf.setId(VNF_ID);
217         vnfs.add(vnf);
218         VnfInfo detailedVnf = new VnfInfo();
219         detailedVnf.setId(VNF_ID);
220         when(vnfApi.vnfsVnfInstanceIdGet(VNF_ID, NOKIA_LCM_API_VERSION)).thenReturn(buildObservable(detailedVnf));
221         OperationExecution operation = new OperationExecution();
222         operation.setId(UUID.randomUUID().toString());
223         operation.setStartTime(OffsetDateTime.now());
224         operation.setStatus(OperationStatus.STARTED);
225         detailedVnf.setOperationExecutions(new ArrayList<>());
226         detailedVnf.getOperationExecutions().add(operation);
227         JsonElement operationParams = new JsonParser().parse("{ \"additionalParams\" : { \"jobId\" : \"" + jobId + "\"}}");
228         when(operationExecutionApi.operationExecutionsOperationExecutionIdOperationParamsGet(operation.getId(), NOKIA_LCM_API_VERSION)).thenReturn(buildObservable(operationParams));
229         JobDetailInfo job = jobManager.getJob(VNFM_ID, jobId);
230         //verify
231         assertResult(jobId, job, STARTED, "50", "Operation started");
232         assertTrue(jobManager.hasOngoingJobs());
233     }
234
235     /**
236      * If the VNF does not exists till the time the job queries the status of the operation
237      */
238     @Test
239     public void testTerminatedVnf() throws Exception {
240         //ddd
241         String jobId = jobManager.spawnJob(VNF_ID, httpResponse);
242         VnfInfo vnf = new VnfInfo();
243         vnf.setId(VNF_ID);
244         vnfs.add(vnf);
245         VnfInfo detailedVnf = new VnfInfo();
246         detailedVnf.setId(VNF_ID);
247         List<Integer> vnfQueryCallCounter = new ArrayList<>();
248         when(vnfApi.vnfsVnfInstanceIdGet(VNF_ID, NOKIA_LCM_API_VERSION)).thenAnswer(new Answer<Observable<VnfInfo>>() {
249             @Override
250             public Observable<VnfInfo> answer(InvocationOnMock invocation) throws Throwable {
251                 vnfs.clear();
252                 return buildObservable(detailedVnf);
253             }
254         });
255
256         jobManager.jobFinished(jobId);
257
258         OperationExecution operation = new OperationExecution();
259         operation.setId(UUID.randomUUID().toString());
260         operation.setStartTime(OffsetDateTime.now());
261         operation.setStatus(OperationStatus.FINISHED);
262         operation.setOperationType(OperationType.TERMINATE);
263         detailedVnf.setOperationExecutions(new ArrayList<>());
264         detailedVnf.getOperationExecutions().add(operation);
265
266         JsonElement operationParams = new JsonParser().parse("{ \"additionalParams\" : { \"jobId\" : \"" + jobId + "\"}}");
267         when(operationExecutionApi.operationExecutionsOperationExecutionIdOperationParamsGet(operation.getId(), NOKIA_LCM_API_VERSION)).thenReturn(buildObservable(operationParams));
268         //when
269         JobDetailInfo job = jobManager.getJob(VNFM_ID, jobId);
270         //verify
271         assertResult(jobId, job, FINISHED, "100", "Operation finished");
272     }
273
274     /**
275      * If the VNF exists but and the operation execution is present with given internalJobId, than the state of the
276      * job is error if the operation is failed
277      */
278     @Test
279     public void testExistingVnfWithFailedOperation() throws Exception {
280         String jobId = jobManager.spawnJob(VNF_ID, httpResponse);
281         VnfInfo vnf = new VnfInfo();
282         vnf.setId(VNF_ID);
283         vnfs.add(vnf);
284         VnfInfo detailedVnf = new VnfInfo();
285         detailedVnf.setId(VNF_ID);
286         List<Integer> vnfCounter = new ArrayList<>();
287         when(vnfApi.vnfsVnfInstanceIdGet(VNF_ID, NOKIA_LCM_API_VERSION)).thenReturn(buildObservable(detailedVnf));
288         OperationExecution operation = new OperationExecution();
289         operation.setId(UUID.randomUUID().toString());
290         operation.setStartTime(OffsetDateTime.now());
291         operation.setStatus(OperationStatus.FAILED);
292         ProblemDetails errorDetails = new ProblemDetails();
293         errorDetails.setTitle("Title");
294         errorDetails.setDetail("detail");
295         operation.setError(errorDetails);
296         detailedVnf.setOperationExecutions(new ArrayList<>());
297         detailedVnf.getOperationExecutions().add(operation);
298         JsonElement operationParams = new JsonParser().parse("{ \"additionalParams\" : { \"jobId\" : \"" + jobId + "\"}}");
299         when(operationExecutionApi.operationExecutionsOperationExecutionIdOperationParamsGet(operation.getId(), NOKIA_LCM_API_VERSION)).thenReturn(buildObservable(operationParams));
300         //when
301         JobDetailInfo job = jobManager.getJob(VNFM_ID, jobId);
302         //verify
303         assertResult(jobId, job, ERROR, "100", "Operation failed due to Title: detail");
304         assertTrue(jobManager.hasOngoingJobs());
305     }
306
307     private void assertResult(String jobId, JobDetailInfo job, JobStatus status, String progress, String descriptor) {
308         assertEquals(jobId, job.getJobId());
309         assertEquals(status, job.getResponseDescriptor().getStatus());
310         assertEquals(progress, job.getResponseDescriptor().getProgress());
311         assertNull(job.getResponseDescriptor().getErrorCode());
312         boolean finalState = JobStatus.ERROR.equals(status) || JobStatus.FINISHED.equals(status);
313         if (finalState) {
314             assertEquals(2, job.getResponseDescriptor().getResponseHistoryList().size());
315             JobResponseInfo startEvent = job.getResponseDescriptor().getResponseHistoryList().get(0);
316             JobResponseInfo endEvent = job.getResponseDescriptor().getResponseHistoryList().get(1);
317             assertNull(startEvent.getErrorCode());
318             assertEquals("50", startEvent.getProgress());
319             assertEquals(JobStatus.STARTED.name(), startEvent.getStatus());
320             assertEquals("1", startEvent.getResponseId());
321             assertEquals("Operation started", startEvent.getStatusDescription());
322
323             assertNull(endEvent.getErrorCode());
324             assertEquals("100", endEvent.getProgress());
325             assertEquals(job.getResponseDescriptor().getStatus().name(), endEvent.getStatus());
326             assertEquals("2", endEvent.getResponseId());
327             assertEquals(descriptor, endEvent.getStatusDescription());
328         } else {
329             assertEquals(1, job.getResponseDescriptor().getResponseHistoryList().size());
330             assertNull(job.getResponseDescriptor().getResponseHistoryList().get(0).getErrorCode());
331             assertEquals(progress, job.getResponseDescriptor().getResponseHistoryList().get(0).getProgress());
332             assertEquals(job.getResponseDescriptor().getStatus().name(), job.getResponseDescriptor().getResponseHistoryList().get(0).getStatus());
333             assertEquals("1", job.getResponseDescriptor().getResponseHistoryList().get(0).getResponseId());
334             assertEquals(descriptor, job.getResponseDescriptor().getResponseHistoryList().get(0).getStatusDescription());
335         }
336         assertEquals(Integer.toString(job.getResponseDescriptor().getResponseHistoryList().size()), job.getResponseDescriptor().getResponseId());
337         assertEquals(descriptor, job.getResponseDescriptor().getStatusDescription());
338     }
339
340     /**
341      * If the VNF exists but and the operation execution is present with given internalJobId, than the state of the
342      * job is finished if the operation is finished, but is not a termination
343      */
344     @Test
345     public void testExistingVnfWithFinishedOperation() throws Exception {
346         String jobId = jobManager.spawnJob(VNF_ID, httpResponse);
347         VnfInfo vnf = new VnfInfo();
348         vnf.setId(VNF_ID);
349         vnfs.add(vnf);
350         VnfInfo detailedVnf = new VnfInfo();
351         detailedVnf.setId(VNF_ID);
352         when(vnfApi.vnfsVnfInstanceIdGet(VNF_ID, NOKIA_LCM_API_VERSION)).thenReturn(buildObservable(detailedVnf));
353         OperationExecution operation = new OperationExecution();
354         operation.setId(UUID.randomUUID().toString());
355         operation.setStartTime(OffsetDateTime.now());
356         operation.setStatus(OperationStatus.FINISHED);
357         operation.setOperationType(OperationType.SCALE);
358         detailedVnf.setOperationExecutions(new ArrayList<>());
359         detailedVnf.getOperationExecutions().add(operation);
360         JsonElement operationParams = new JsonParser().parse("{ \"additionalParams\" : { \"jobId\" : \"" + jobId + "\"}}");
361         when(operationExecutionApi.operationExecutionsOperationExecutionIdOperationParamsGet(operation.getId(), NOKIA_LCM_API_VERSION)).thenReturn(buildObservable(operationParams));
362         JobDetailInfo job = jobManager.getJob(VNFM_ID, jobId);
363         //verify
364         assertResult(jobId, job, JobStatus.FINISHED, "100", "Operation finished");
365         assertTrue(jobManager.hasOngoingJobs());
366     }
367
368     /**
369      * If the VNF exists but and the operation execution is present with given internalJobId, than the state of the
370      * job is ongoing if the termination operation is finished. In ONAP terminology the termination includes
371      * delete, so the ONAP operation is ongoing since the VNF is not yet deleted
372      */
373     @Test
374     public void testExistingVnfWithFinishedTerminationOperation() throws Exception {
375         String jobId = jobManager.spawnJob(VNF_ID, httpResponse);
376         VnfInfo vnf = new VnfInfo();
377         vnf.setId(VNF_ID);
378         vnfs.add(vnf);
379         VnfInfo detailedVnf = new VnfInfo();
380         detailedVnf.setId(VNF_ID);
381         when(vnfApi.vnfsVnfInstanceIdGet(VNF_ID, NOKIA_LCM_API_VERSION)).thenReturn(buildObservable(detailedVnf));
382         OperationExecution operation = new OperationExecution();
383         operation.setId(UUID.randomUUID().toString());
384         operation.setStartTime(OffsetDateTime.now());
385         operation.setStatus(OperationStatus.FINISHED);
386         operation.setOperationType(OperationType.TERMINATE);
387         detailedVnf.setOperationExecutions(new ArrayList<>());
388         detailedVnf.getOperationExecutions().add(operation);
389         JsonElement operationParams = new JsonParser().parse("{ \"additionalParams\" : { \"jobId\" : \"" + jobId + "\"}}");
390         when(operationExecutionApi.operationExecutionsOperationExecutionIdOperationParamsGet(operation.getId(), NOKIA_LCM_API_VERSION)).thenReturn(buildObservable(operationParams));
391         JobDetailInfo job = jobManager.getJob(VNFM_ID, jobId);
392         //verify
393         assertResult(jobId, job, STARTED, "50", "Operation started");
394         //when
395         jobManager.jobFinished(jobId);
396         job = jobManager.getJob(VNFM_ID, jobId);
397         //verify
398         assertResult(jobId, job, ERROR, "100", "Operation failed due to unable to delete VNF");
399         assertFalse(jobManager.hasOngoingJobs());
400
401     }
402
403     /**
404      * Failuire to retrieve operation parameters (CBAM REST API fail) is logged and propagated
405      */
406     @Test
407     public void failuresDuringOperationExecutionRetrievalIsLoggedAndPropagated() throws Exception {
408         String jobId = jobManager.spawnJob(VNF_ID, httpResponse);
409         VnfInfo vnf = new VnfInfo();
410         vnf.setId(VNF_ID);
411         vnfs.add(vnf);
412         VnfInfo detailedVnf = new VnfInfo();
413         detailedVnf.setId(VNF_ID);
414         when(vnfApi.vnfsVnfInstanceIdGet(VNF_ID, NOKIA_LCM_API_VERSION)).thenReturn(buildObservable(detailedVnf));
415         OperationExecution operation = new OperationExecution();
416         operation.setId(UUID.randomUUID().toString());
417         detailedVnf.setOperationExecutions(new ArrayList<>());
418         detailedVnf.getOperationExecutions().add(operation);
419         RuntimeException expectedException = new RuntimeException();
420         when(operationExecutionApi.operationExecutionsOperationExecutionIdOperationParamsGet(operation.getId(), NOKIA_LCM_API_VERSION)).thenThrow(expectedException);
421         //verify
422         try {
423             JobDetailInfo job = jobManager.getJob(VNFM_ID, jobId);
424             fail();
425         } catch (RuntimeException e) {
426             assertEquals(expectedException, e.getCause());
427             verify(logger).error("Unable to retrieve operation parameters of operation with " + operation.getId() + " identifier", expectedException);
428         }
429         assertTrue(jobManager.hasOngoingJobs());
430     }
431
432     /**
433      * Failure to retrieve VNF (CBAM REST API fail) is logged and propagated
434      */
435     @Test
436     public void failuresDuringVnfRetrievalIsLoggedAndPropagated() throws Exception {
437         String jobId = jobManager.spawnJob(VNF_ID, httpResponse);
438         VnfInfo vnf = new VnfInfo();
439         vnf.setId(VNF_ID);
440         vnfs.add(vnf);
441         RuntimeException expectedException = new RuntimeException();
442         when(vnfApi.vnfsVnfInstanceIdGet(VNF_ID, NOKIA_LCM_API_VERSION)).thenThrow(expectedException);
443         //verify
444         try {
445             JobDetailInfo job = jobManager.getJob(VNFM_ID, jobId);
446             fail();
447         } catch (RuntimeException e) {
448             assertEquals(expectedException, e.getCause());
449             verify(logger).error("Unable to retrieve VNF with myVnfId identifier", expectedException);
450         }
451         assertTrue(jobManager.hasOngoingJobs());
452     }
453
454     /**
455      * When searching for the ONAP job by iterating the operation executions. The newest jobs
456      * are inspected first (performance optimalization)
457      */
458     @Test
459     public void testNewestOperationAreInspectedFirst() throws Exception {
460         String jobId = jobManager.spawnJob(VNF_ID, httpResponse);
461         VnfInfo vnf = new VnfInfo();
462         vnf.setId(VNF_ID);
463         vnfs.add(vnf);
464         VnfInfo detailedVnf = new VnfInfo();
465         detailedVnf.setId(VNF_ID);
466         when(vnfApi.vnfsVnfInstanceIdGet(VNF_ID, NOKIA_LCM_API_VERSION)).thenReturn(buildObservable(detailedVnf));
467         OperationExecution olderOperation = new OperationExecution();
468         olderOperation.setId(UUID.randomUUID().toString());
469         olderOperation.setStartTime(OffsetDateTime.now());
470         olderOperation.setStatus(OperationStatus.FINISHED);
471         olderOperation.setOperationType(OperationType.TERMINATE);
472         OperationExecution newerOperation = new OperationExecution();
473         newerOperation.setId(UUID.randomUUID().toString());
474         newerOperation.setStartTime(OffsetDateTime.now().plusDays(1));
475         newerOperation.setStatus(OperationStatus.FINISHED);
476         newerOperation.setOperationType(OperationType.TERMINATE);
477         detailedVnf.setOperationExecutions(new ArrayList<>());
478         detailedVnf.getOperationExecutions().add(olderOperation);
479         detailedVnf.getOperationExecutions().add(newerOperation);
480         JsonElement operationParams = new JsonParser().parse("{ \"additionalParams\" : { \"jobId\" : \"" + jobId + "\"}}");
481         List<String> queriedOperaionsInOrder = new ArrayList<>();
482         when(operationExecutionApi.operationExecutionsOperationExecutionIdOperationParamsGet(Mockito.anyString(), Mockito.eq(NOKIA_LCM_API_VERSION)))
483                 .then(new Answer<Observable<Object>>() {
484                     @Override
485                     public Observable<Object> answer(InvocationOnMock invocationOnMock) throws Throwable {
486                         queriedOperaionsInOrder.add(invocationOnMock.getArguments()[0].toString());
487                         if (invocationOnMock.getArguments()[0].equals(olderOperation.getId())) {
488                             return buildObservable(new JsonParser().parse("{ \"additionalParams\" : { \"jobId\" : \"" + jobId + "\"}}"));
489                         } else {
490                             return buildObservable(new JsonParser().parse("{ \"additionalParams\" : { \"jobId\" : \"" + "nonMatching" + "\"}}"));
491                         }
492                     }
493                 });
494         JobDetailInfo job = jobManager.getJob(VNFM_ID, jobId);
495         //verify
496         assertEquals(Lists.newArrayList(newerOperation.getId(), olderOperation.getId()), queriedOperaionsInOrder);
497         assertTrue(jobManager.hasOngoingJobs());
498     }
499
500     /**
501      * the modify attribute job is skipped, since it is not explicitly triggered by any external job
502      */
503     @Test
504     public void testModifyAttributesOperationExecutionIsSkipped() throws Exception {
505         String jobId = jobManager.spawnJob(VNF_ID, httpResponse);
506         VnfInfo vnf = new VnfInfo();
507         vnf.setId(VNF_ID);
508         vnfs.add(vnf);
509         VnfInfo detailedVnf = new VnfInfo();
510         detailedVnf.setId(VNF_ID);
511         when(vnfApi.vnfsVnfInstanceIdGet(VNF_ID, NOKIA_LCM_API_VERSION)).thenReturn(buildObservable(detailedVnf));
512         OperationExecution olderOperation = new OperationExecution();
513         olderOperation.setId(UUID.randomUUID().toString());
514         olderOperation.setStartTime(OffsetDateTime.now());
515         olderOperation.setStatus(OperationStatus.FINISHED);
516         olderOperation.setOperationType(OperationType.TERMINATE);
517         OperationExecution newerOperation = new OperationExecution();
518         newerOperation.setId(UUID.randomUUID().toString());
519         newerOperation.setStartTime(OffsetDateTime.now().plusDays(1));
520         newerOperation.setStatus(OperationStatus.FINISHED);
521         newerOperation.setOperationType(OperationType.MODIFY_INFO);
522         detailedVnf.setOperationExecutions(new ArrayList<>());
523         detailedVnf.getOperationExecutions().add(olderOperation);
524         detailedVnf.getOperationExecutions().add(newerOperation);
525         JsonElement operationParams = new JsonParser().parse("{ \"additionalParams\" : { \"jobId\" : \"" + jobId + "\"}}");
526         List<String> queriedOperaionsInOrder = new ArrayList<>();
527         when(operationExecutionApi.operationExecutionsOperationExecutionIdOperationParamsGet(Mockito.anyString(), Mockito.eq(NOKIA_LCM_API_VERSION)))
528                 .then(new Answer<Observable<Object>>() {
529                     @Override
530                     public Observable<Object> answer(InvocationOnMock invocationOnMock) throws Throwable {
531                         queriedOperaionsInOrder.add(invocationOnMock.getArguments()[0].toString());
532                         if (invocationOnMock.getArguments()[0].equals(olderOperation.getId())) {
533                             return buildObservable(new JsonParser().parse("{ \"additionalParams\" : { \"jobId\" : \"" + jobId + "\"}}"));
534                         } else {
535                             throw new RuntimeException(); //this should be never reached
536                         }
537                     }
538                 });
539         JobDetailInfo job = jobManager.getJob(VNFM_ID, jobId);
540         //verify
541         assertEquals(Lists.newArrayList(olderOperation.getId()), queriedOperaionsInOrder);
542         assertTrue(jobManager.hasOngoingJobs());
543     }
544
545     /**
546      * if the registration process has not finished it is prevented to spawn jobs
547      */
548     @Test
549     public void noJobCanBeStartedIfRegistrationNotFinished() throws Exception {
550         //given
551         when(selfRegistrationManager.isReady()).thenReturn(false);
552         //when
553         try {
554             jobManager.spawnJob(VNF_ID, httpResponse);
555             fail();
556         } catch (RuntimeException e) {
557             assertEquals("The service is not yet ready", e.getMessage());
558         }
559     }
560
561     /**
562      * Ongoing job are out waited during the the preparation for shutdown
563      */
564     @Test
565     //need to wait for an asynchronous execution to finish
566     //this is the most optimal way to do it
567     @SuppressWarnings("squid:S2925")
568     public void onGoingJobsAreOutwaitedDuringShutdown() throws Exception {
569         String firstJobId = jobManager.spawnJob(VNF_ID, httpResponse);
570         ExecutorService executorService = Executors.newCachedThreadPool();
571         ArgumentCaptor<Integer> sleeps = ArgumentCaptor.forClass(Integer.class);
572         doNothing().when(systemFunctions).sleep(sleeps.capture());
573         //when prepare job manager for shutdown
574         Future<?> shutDown = executorService.submit(() -> jobManager.prepareForShutdown());
575         while (sleeps.getAllValues().size() == 0) {
576             try {
577                 Thread.sleep(1);
578             } catch (InterruptedException e) {
579             }
580         }
581         assertFalse(shutDown.isDone());
582         jobManager.jobFinished(firstJobId);
583         //verify
584         shutDown.get();
585         verify(systemFunctions, times(sleeps.getAllValues().size())).sleep(500L);
586     }
587 }