Fix container startup
[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         assertEquals(false, jobManager.isPreparingForShutDown());
122     }
123
124     /**
125      * Spawning jobs after preparing for shutdown results in error
126      */
127     @Test
128     public void testNoMoreJobsAreAllowedAfterPrepareForShutdown() throws Exception {
129         jobManager.prepareForShutdown();
130         //when
131         try {
132             jobManager.spawnJob(JOB_ID, httpResponse);
133             fail();
134         } catch (Exception e) {
135             verify(logger).error("The service is preparing to shut down");
136         }
137         assertEquals(true, jobManager.isPreparingForShutDown());
138     }
139
140     /**
141      * Verify if the jobId has valid format
142      */
143     @Test
144     public void testJobIdValidation() throws Exception {
145         try {
146             //when
147             jobManager.getJob(VNFM_ID, "bad");
148             //verify
149             fail();
150         } catch (IllegalArgumentException e) {
151             assertEquals("The jobId should be in the <vnfId>_<UUID> format, but was bad", e.getMessage());
152         }
153         try {
154             //when
155             jobManager.getJob(VNFM_ID, "vnfId_");
156             //verify
157             fail();
158         } catch (IllegalArgumentException e) {
159             assertEquals("The UUID in the jobId (vnfId_) can not be empty", e.getMessage());
160         }
161         try {
162             //when
163             jobManager.getJob(VNFM_ID, "_UUID");
164             //verify
165             fail();
166         } catch (IllegalArgumentException e) {
167             assertEquals("The vnfId in the jobId (_UUID) can not be empty", e.getMessage());
168         }
169     }
170
171     /**
172      * If the VNF exists but no operation execution is present with given internalJobId, than the state of the
173      * job is ongoing if the internal job is ongoing
174      */
175     @Test
176     public void testExistingVnfWithNotYetStartedOperation() throws Exception {
177         String jobId = jobManager.spawnJob(VNF_ID, httpResponse);
178         VnfInfo vnf = new VnfInfo();
179         vnf.setId(VNF_ID);
180         vnfs.add(vnf);
181         VnfInfo detailedVnf = new VnfInfo();
182         detailedVnf.setId(VNF_ID);
183         when(vnfApi.vnfsVnfInstanceIdGet(VNF_ID, NOKIA_LCM_API_VERSION)).thenReturn(buildObservable(detailedVnf));
184         JobDetailInfo job = jobManager.getJob(VNFM_ID, jobId);
185         //verify
186         assertResult(jobId, job, STARTED, "50", "Operation started");
187         assertTrue(jobManager.hasOngoingJobs());
188     }
189
190     /**
191      * If the VNF exists but no operation execution is present with given internalJobId, than the state of the
192      * job is failed if the internal job is finished (the operation on CBAM was not able to start)
193      */
194     @Test
195     public void testExistingVnfWithNotUnableToStartOperation() throws Exception {
196         String jobId = jobManager.spawnJob(VNF_ID, httpResponse);
197         VnfInfo vnf = new VnfInfo();
198         vnf.setId(VNF_ID);
199         vnfs.add(vnf);
200         VnfInfo detailedVnf = new VnfInfo();
201         detailedVnf.setId(VNF_ID);
202         when(vnfApi.vnfsVnfInstanceIdGet(VNF_ID, NOKIA_LCM_API_VERSION)).thenReturn(buildObservable(detailedVnf));
203         jobManager.jobFinished(jobId);
204         JobDetailInfo job = jobManager.getJob(VNFM_ID, jobId);
205         //verify
206         assertResult(jobId, job, ERROR, "100", "Operation failed due to The requested operation was not able to start on CBAM");
207         assertFalse(jobManager.hasOngoingJobs());
208     }
209
210     /**
211      * If the VNF exists but and the operation execution is present with given internalJobId, than the state of the
212      * job is ongoing if the operation is ongoing
213      */
214     @Test
215     public void testExistingVnfWithStartedOperation() throws Exception {
216         String jobId = jobManager.spawnJob(VNF_ID, httpResponse);
217         VnfInfo vnf = new VnfInfo();
218         vnf.setId(VNF_ID);
219         vnfs.add(vnf);
220         VnfInfo detailedVnf = new VnfInfo();
221         detailedVnf.setId(VNF_ID);
222         when(vnfApi.vnfsVnfInstanceIdGet(VNF_ID, NOKIA_LCM_API_VERSION)).thenReturn(buildObservable(detailedVnf));
223         OperationExecution operation = new OperationExecution();
224         operation.setId(UUID.randomUUID().toString());
225         operation.setStartTime(OffsetDateTime.now());
226         operation.setStatus(OperationStatus.STARTED);
227         detailedVnf.setOperationExecutions(new ArrayList<>());
228         detailedVnf.getOperationExecutions().add(operation);
229         JsonElement operationParams = new JsonParser().parse("{ \"additionalParams\" : { \"jobId\" : \"" + jobId + "\"}}");
230         when(operationExecutionApi.operationExecutionsOperationExecutionIdOperationParamsGet(operation.getId(), NOKIA_LCM_API_VERSION)).thenReturn(buildObservable(operationParams));
231         JobDetailInfo job = jobManager.getJob(VNFM_ID, jobId);
232         //verify
233         assertResult(jobId, job, STARTED, "50", "Operation started");
234         assertTrue(jobManager.hasOngoingJobs());
235     }
236
237     /**
238      * If the VNF does not exists till the time the job queries the status of the operation
239      */
240     @Test
241     public void testTerminatedVnf() throws Exception {
242         //ddd
243         String jobId = jobManager.spawnJob(VNF_ID, httpResponse);
244         VnfInfo vnf = new VnfInfo();
245         vnf.setId(VNF_ID);
246         vnfs.add(vnf);
247         VnfInfo detailedVnf = new VnfInfo();
248         detailedVnf.setId(VNF_ID);
249         List<Integer> vnfQueryCallCounter = new ArrayList<>();
250         when(vnfApi.vnfsVnfInstanceIdGet(VNF_ID, NOKIA_LCM_API_VERSION)).thenAnswer(new Answer<Observable<VnfInfo>>() {
251             @Override
252             public Observable<VnfInfo> answer(InvocationOnMock invocation) throws Throwable {
253                 vnfs.clear();
254                 return buildObservable(detailedVnf);
255             }
256         });
257
258         jobManager.jobFinished(jobId);
259
260         OperationExecution operation = new OperationExecution();
261         operation.setId(UUID.randomUUID().toString());
262         operation.setStartTime(OffsetDateTime.now());
263         operation.setStatus(OperationStatus.FINISHED);
264         operation.setOperationType(OperationType.TERMINATE);
265         detailedVnf.setOperationExecutions(new ArrayList<>());
266         detailedVnf.getOperationExecutions().add(operation);
267
268         JsonElement operationParams = new JsonParser().parse("{ \"additionalParams\" : { \"jobId\" : \"" + jobId + "\"}}");
269         when(operationExecutionApi.operationExecutionsOperationExecutionIdOperationParamsGet(operation.getId(), NOKIA_LCM_API_VERSION)).thenReturn(buildObservable(operationParams));
270         //when
271         JobDetailInfo job = jobManager.getJob(VNFM_ID, jobId);
272         //verify
273         assertResult(jobId, job, FINISHED, "100", "Operation finished");
274     }
275
276     /**
277      * If the VNF exists but and the operation execution is present with given internalJobId, than the state of the
278      * job is error if the operation is failed
279      */
280     @Test
281     public void testExistingVnfWithFailedOperation() throws Exception {
282         String jobId = jobManager.spawnJob(VNF_ID, httpResponse);
283         VnfInfo vnf = new VnfInfo();
284         vnf.setId(VNF_ID);
285         vnfs.add(vnf);
286         VnfInfo detailedVnf = new VnfInfo();
287         detailedVnf.setId(VNF_ID);
288         List<Integer> vnfCounter = new ArrayList<>();
289         when(vnfApi.vnfsVnfInstanceIdGet(VNF_ID, NOKIA_LCM_API_VERSION)).thenReturn(buildObservable(detailedVnf));
290         OperationExecution operation = new OperationExecution();
291         operation.setId(UUID.randomUUID().toString());
292         operation.setStartTime(OffsetDateTime.now());
293         operation.setStatus(OperationStatus.FAILED);
294         ProblemDetails errorDetails = new ProblemDetails();
295         errorDetails.setTitle("Title");
296         errorDetails.setDetail("detail");
297         operation.setError(errorDetails);
298         detailedVnf.setOperationExecutions(new ArrayList<>());
299         detailedVnf.getOperationExecutions().add(operation);
300         JsonElement operationParams = new JsonParser().parse("{ \"additionalParams\" : { \"jobId\" : \"" + jobId + "\"}}");
301         when(operationExecutionApi.operationExecutionsOperationExecutionIdOperationParamsGet(operation.getId(), NOKIA_LCM_API_VERSION)).thenReturn(buildObservable(operationParams));
302         //when
303         JobDetailInfo job = jobManager.getJob(VNFM_ID, jobId);
304         //verify
305         assertResult(jobId, job, ERROR, "100", "Operation failed due to Title: detail");
306         assertTrue(jobManager.hasOngoingJobs());
307     }
308
309     private void assertResult(String jobId, JobDetailInfo job, JobStatus status, String progress, String descriptor) {
310         assertEquals(jobId, job.getJobId());
311         assertEquals(status, job.getResponseDescriptor().getStatus());
312         assertEquals(progress, job.getResponseDescriptor().getProgress());
313         assertNull(job.getResponseDescriptor().getErrorCode());
314         boolean finalState = JobStatus.ERROR.equals(status) || JobStatus.FINISHED.equals(status);
315         if (finalState) {
316             assertEquals(2, job.getResponseDescriptor().getResponseHistoryList().size());
317             JobResponseInfo startEvent = job.getResponseDescriptor().getResponseHistoryList().get(0);
318             JobResponseInfo endEvent = job.getResponseDescriptor().getResponseHistoryList().get(1);
319             assertNull(startEvent.getErrorCode());
320             assertEquals("50", startEvent.getProgress());
321             assertEquals(JobStatus.STARTED.name(), startEvent.getStatus());
322             assertEquals("1", startEvent.getResponseId());
323             assertEquals("Operation started", startEvent.getStatusDescription());
324
325             assertNull(endEvent.getErrorCode());
326             assertEquals("100", endEvent.getProgress());
327             assertEquals(job.getResponseDescriptor().getStatus().name(), endEvent.getStatus());
328             assertEquals("2", endEvent.getResponseId());
329             assertEquals(descriptor, endEvent.getStatusDescription());
330         } else {
331             assertEquals(1, job.getResponseDescriptor().getResponseHistoryList().size());
332             assertNull(job.getResponseDescriptor().getResponseHistoryList().get(0).getErrorCode());
333             assertEquals(progress, job.getResponseDescriptor().getResponseHistoryList().get(0).getProgress());
334             assertEquals(job.getResponseDescriptor().getStatus().name(), job.getResponseDescriptor().getResponseHistoryList().get(0).getStatus());
335             assertEquals("1", job.getResponseDescriptor().getResponseHistoryList().get(0).getResponseId());
336             assertEquals(descriptor, job.getResponseDescriptor().getResponseHistoryList().get(0).getStatusDescription());
337         }
338         assertEquals(Integer.toString(job.getResponseDescriptor().getResponseHistoryList().size()), job.getResponseDescriptor().getResponseId());
339         assertEquals(descriptor, job.getResponseDescriptor().getStatusDescription());
340     }
341
342     /**
343      * If the VNF exists but and the operation execution is present with given internalJobId, than the state of the
344      * job is finished if the operation is finished, but is not a termination
345      */
346     @Test
347     public void testExistingVnfWithFinishedOperation() throws Exception {
348         String jobId = jobManager.spawnJob(VNF_ID, httpResponse);
349         VnfInfo vnf = new VnfInfo();
350         vnf.setId(VNF_ID);
351         vnfs.add(vnf);
352         VnfInfo detailedVnf = new VnfInfo();
353         detailedVnf.setId(VNF_ID);
354         when(vnfApi.vnfsVnfInstanceIdGet(VNF_ID, NOKIA_LCM_API_VERSION)).thenReturn(buildObservable(detailedVnf));
355         OperationExecution operation = new OperationExecution();
356         operation.setId(UUID.randomUUID().toString());
357         operation.setStartTime(OffsetDateTime.now());
358         operation.setStatus(OperationStatus.FINISHED);
359         operation.setOperationType(OperationType.SCALE);
360         detailedVnf.setOperationExecutions(new ArrayList<>());
361         detailedVnf.getOperationExecutions().add(operation);
362         JsonElement operationParams = new JsonParser().parse("{ \"additionalParams\" : { \"jobId\" : \"" + jobId + "\"}}");
363         when(operationExecutionApi.operationExecutionsOperationExecutionIdOperationParamsGet(operation.getId(), NOKIA_LCM_API_VERSION)).thenReturn(buildObservable(operationParams));
364         JobDetailInfo job = jobManager.getJob(VNFM_ID, jobId);
365         //verify
366         assertResult(jobId, job, JobStatus.FINISHED, "100", "Operation finished");
367         assertTrue(jobManager.hasOngoingJobs());
368     }
369
370     /**
371      * If the VNF exists but and the operation execution is present with given internalJobId, than the state of the
372      * job is ongoing if the termination operation is finished. In ONAP terminology the termination includes
373      * delete, so the ONAP operation is ongoing since the VNF is not yet deleted
374      */
375     @Test
376     public void testExistingVnfWithFinishedTerminationOperation() throws Exception {
377         String jobId = jobManager.spawnJob(VNF_ID, httpResponse);
378         VnfInfo vnf = new VnfInfo();
379         vnf.setId(VNF_ID);
380         vnfs.add(vnf);
381         VnfInfo detailedVnf = new VnfInfo();
382         detailedVnf.setId(VNF_ID);
383         when(vnfApi.vnfsVnfInstanceIdGet(VNF_ID, NOKIA_LCM_API_VERSION)).thenReturn(buildObservable(detailedVnf));
384         OperationExecution operation = new OperationExecution();
385         operation.setId(UUID.randomUUID().toString());
386         operation.setStartTime(OffsetDateTime.now());
387         operation.setStatus(OperationStatus.FINISHED);
388         operation.setOperationType(OperationType.TERMINATE);
389         detailedVnf.setOperationExecutions(new ArrayList<>());
390         detailedVnf.getOperationExecutions().add(operation);
391         JsonElement operationParams = new JsonParser().parse("{ \"additionalParams\" : { \"jobId\" : \"" + jobId + "\"}}");
392         when(operationExecutionApi.operationExecutionsOperationExecutionIdOperationParamsGet(operation.getId(), NOKIA_LCM_API_VERSION)).thenReturn(buildObservable(operationParams));
393         JobDetailInfo job = jobManager.getJob(VNFM_ID, jobId);
394         //verify
395         assertResult(jobId, job, STARTED, "50", "Operation started");
396         //when
397         jobManager.jobFinished(jobId);
398         job = jobManager.getJob(VNFM_ID, jobId);
399         //verify
400         assertResult(jobId, job, ERROR, "100", "Operation failed due to unable to delete VNF");
401         assertFalse(jobManager.hasOngoingJobs());
402
403     }
404
405     /**
406      * Failuire to retrieve operation parameters (CBAM REST API fail) is logged and propagated
407      */
408     @Test
409     public void failuresDuringOperationExecutionRetrievalIsLoggedAndPropagated() throws Exception {
410         String jobId = jobManager.spawnJob(VNF_ID, httpResponse);
411         VnfInfo vnf = new VnfInfo();
412         vnf.setId(VNF_ID);
413         vnfs.add(vnf);
414         VnfInfo detailedVnf = new VnfInfo();
415         detailedVnf.setId(VNF_ID);
416         when(vnfApi.vnfsVnfInstanceIdGet(VNF_ID, NOKIA_LCM_API_VERSION)).thenReturn(buildObservable(detailedVnf));
417         OperationExecution operation = new OperationExecution();
418         operation.setId(UUID.randomUUID().toString());
419         detailedVnf.setOperationExecutions(new ArrayList<>());
420         detailedVnf.getOperationExecutions().add(operation);
421         RuntimeException expectedException = new RuntimeException();
422         when(operationExecutionApi.operationExecutionsOperationExecutionIdOperationParamsGet(operation.getId(), NOKIA_LCM_API_VERSION)).thenThrow(expectedException);
423         //verify
424         try {
425             JobDetailInfo job = jobManager.getJob(VNFM_ID, jobId);
426             fail();
427         } catch (RuntimeException e) {
428             assertEquals(expectedException, e.getCause());
429             verify(logger).error("Unable to retrieve operation parameters of operation with " + operation.getId() + " identifier", expectedException);
430         }
431         assertTrue(jobManager.hasOngoingJobs());
432     }
433
434     /**
435      * Failure to retrieve VNF (CBAM REST API fail) is logged and propagated
436      */
437     @Test
438     public void failuresDuringVnfRetrievalIsLoggedAndPropagated() throws Exception {
439         String jobId = jobManager.spawnJob(VNF_ID, httpResponse);
440         VnfInfo vnf = new VnfInfo();
441         vnf.setId(VNF_ID);
442         vnfs.add(vnf);
443         RuntimeException expectedException = new RuntimeException();
444         when(vnfApi.vnfsVnfInstanceIdGet(VNF_ID, NOKIA_LCM_API_VERSION)).thenThrow(expectedException);
445         //verify
446         try {
447             JobDetailInfo job = jobManager.getJob(VNFM_ID, jobId);
448             fail();
449         } catch (RuntimeException e) {
450             assertEquals(expectedException, e.getCause());
451             verify(logger).error("Unable to retrieve VNF with myVnfId identifier", expectedException);
452         }
453         assertTrue(jobManager.hasOngoingJobs());
454     }
455
456     /**
457      * When searching for the ONAP job by iterating the operation executions. The newest jobs
458      * are inspected first (performance optimalization)
459      */
460     @Test
461     public void testNewestOperationAreInspectedFirst() throws Exception {
462         String jobId = jobManager.spawnJob(VNF_ID, httpResponse);
463         VnfInfo vnf = new VnfInfo();
464         vnf.setId(VNF_ID);
465         vnfs.add(vnf);
466         VnfInfo detailedVnf = new VnfInfo();
467         detailedVnf.setId(VNF_ID);
468         when(vnfApi.vnfsVnfInstanceIdGet(VNF_ID, NOKIA_LCM_API_VERSION)).thenReturn(buildObservable(detailedVnf));
469         OperationExecution olderOperation = new OperationExecution();
470         olderOperation.setId(UUID.randomUUID().toString());
471         olderOperation.setStartTime(OffsetDateTime.now());
472         olderOperation.setStatus(OperationStatus.FINISHED);
473         olderOperation.setOperationType(OperationType.TERMINATE);
474         OperationExecution newerOperation = new OperationExecution();
475         newerOperation.setId(UUID.randomUUID().toString());
476         newerOperation.setStartTime(OffsetDateTime.now().plusDays(1));
477         newerOperation.setStatus(OperationStatus.FINISHED);
478         newerOperation.setOperationType(OperationType.TERMINATE);
479         detailedVnf.setOperationExecutions(new ArrayList<>());
480         detailedVnf.getOperationExecutions().add(olderOperation);
481         detailedVnf.getOperationExecutions().add(newerOperation);
482         JsonElement operationParams = new JsonParser().parse("{ \"additionalParams\" : { \"jobId\" : \"" + jobId + "\"}}");
483         List<String> queriedOperaionsInOrder = new ArrayList<>();
484         when(operationExecutionApi.operationExecutionsOperationExecutionIdOperationParamsGet(Mockito.anyString(), Mockito.eq(NOKIA_LCM_API_VERSION)))
485                 .then(new Answer<Observable<Object>>() {
486                     @Override
487                     public Observable<Object> answer(InvocationOnMock invocationOnMock) throws Throwable {
488                         queriedOperaionsInOrder.add(invocationOnMock.getArguments()[0].toString());
489                         if (invocationOnMock.getArguments()[0].equals(olderOperation.getId())) {
490                             return buildObservable(new JsonParser().parse("{ \"additionalParams\" : { \"jobId\" : \"" + jobId + "\"}}"));
491                         } else {
492                             return buildObservable(new JsonParser().parse("{ \"additionalParams\" : { \"jobId\" : \"" + "nonMatching" + "\"}}"));
493                         }
494                     }
495                 });
496         JobDetailInfo job = jobManager.getJob(VNFM_ID, jobId);
497         //verify
498         assertEquals(Lists.newArrayList(newerOperation.getId(), olderOperation.getId()), queriedOperaionsInOrder);
499         assertTrue(jobManager.hasOngoingJobs());
500     }
501
502     /**
503      * the modify attribute job is skipped, since it is not explicitly triggered by any external job
504      */
505     @Test
506     public void testModifyAttributesOperationExecutionIsSkipped() throws Exception {
507         String jobId = jobManager.spawnJob(VNF_ID, httpResponse);
508         VnfInfo vnf = new VnfInfo();
509         vnf.setId(VNF_ID);
510         vnfs.add(vnf);
511         VnfInfo detailedVnf = new VnfInfo();
512         detailedVnf.setId(VNF_ID);
513         when(vnfApi.vnfsVnfInstanceIdGet(VNF_ID, NOKIA_LCM_API_VERSION)).thenReturn(buildObservable(detailedVnf));
514         OperationExecution olderOperation = new OperationExecution();
515         olderOperation.setId(UUID.randomUUID().toString());
516         olderOperation.setStartTime(OffsetDateTime.now());
517         olderOperation.setStatus(OperationStatus.FINISHED);
518         olderOperation.setOperationType(OperationType.TERMINATE);
519         OperationExecution newerOperation = new OperationExecution();
520         newerOperation.setId(UUID.randomUUID().toString());
521         newerOperation.setStartTime(OffsetDateTime.now().plusDays(1));
522         newerOperation.setStatus(OperationStatus.FINISHED);
523         newerOperation.setOperationType(OperationType.MODIFY_INFO);
524         detailedVnf.setOperationExecutions(new ArrayList<>());
525         detailedVnf.getOperationExecutions().add(olderOperation);
526         detailedVnf.getOperationExecutions().add(newerOperation);
527         JsonElement operationParams = new JsonParser().parse("{ \"additionalParams\" : { \"jobId\" : \"" + jobId + "\"}}");
528         List<String> queriedOperaionsInOrder = new ArrayList<>();
529         when(operationExecutionApi.operationExecutionsOperationExecutionIdOperationParamsGet(Mockito.anyString(), Mockito.eq(NOKIA_LCM_API_VERSION)))
530                 .then(new Answer<Observable<Object>>() {
531                     @Override
532                     public Observable<Object> answer(InvocationOnMock invocationOnMock) throws Throwable {
533                         queriedOperaionsInOrder.add(invocationOnMock.getArguments()[0].toString());
534                         if (invocationOnMock.getArguments()[0].equals(olderOperation.getId())) {
535                             return buildObservable(new JsonParser().parse("{ \"additionalParams\" : { \"jobId\" : \"" + jobId + "\"}}"));
536                         } else {
537                             throw new RuntimeException(); //this should be never reached
538                         }
539                     }
540                 });
541         JobDetailInfo job = jobManager.getJob(VNFM_ID, jobId);
542         //verify
543         assertEquals(Lists.newArrayList(olderOperation.getId()), queriedOperaionsInOrder);
544         assertTrue(jobManager.hasOngoingJobs());
545     }
546
547     /**
548      * if the registration process has not finished it is prevented to spawn jobs
549      */
550     @Test
551     public void noJobCanBeStartedIfRegistrationNotFinished() throws Exception {
552         //given
553         when(selfRegistrationManager.isReady()).thenReturn(false);
554         //when
555         try {
556             jobManager.spawnJob(VNF_ID, httpResponse);
557             fail();
558         } catch (RuntimeException e) {
559             assertEquals("The service is not yet ready", e.getMessage());
560         }
561     }
562
563     /**
564      * Ongoing job are out waited during the the preparation for shutdown
565      */
566     @Test
567     //need to wait for an asynchronous execution to finish
568     //this is the most optimal way to do it
569     @SuppressWarnings("squid:S2925")
570     public void onGoingJobsAreOutwaitedDuringShutdown() throws Exception {
571         String firstJobId = jobManager.spawnJob(VNF_ID, httpResponse);
572         ExecutorService executorService = Executors.newCachedThreadPool();
573         ArgumentCaptor<Integer> sleeps = ArgumentCaptor.forClass(Integer.class);
574         doNothing().when(systemFunctions).sleep(sleeps.capture());
575         //when prepare job manager for shutdown
576         Future<?> shutDown = executorService.submit(() -> jobManager.prepareForShutdown());
577         while (sleeps.getAllValues().size() == 0) {
578             try {
579                 Thread.sleep(1);
580             } catch (InterruptedException e) {
581             }
582         }
583         assertFalse(shutDown.isDone());
584         jobManager.jobFinished(firstJobId);
585         //verify
586         shutDown.get();
587         verify(systemFunctions, times(sleeps.getAllValues().size())).sleep(500L);
588     }
589 }