summaryrefslogtreecommitdiffstats
path: root/nokiav2/driver/src/test/java/org/onap/vfc/nfvo/driver/vnfm/svnfm/nokia/vnfm/TestJobManager.java
blob: 1ba58abed30b0878a432f10c32db751d908c784f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
7
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.onap.ccsdk.parent</groupId>
        <artifactId>odlparent-lite</artifactId>
        <version>2.3.0</version>
        <relativePath/>
    </parent>

    <groupId>org.onap.sdnc.northbound</groupId>
    <artifactId>optical-service-installer</artifactId>
    <version>2.3.0-SNAPSHOT</version>
    <packaging>pom</packaging>

    <name>sdnc-northbound :: optical-service :: ${project.artifactId}</name>

    <properties>
        <application.name>sdnc-optical-service</application.name>
        <features.boot>${application.name}</features.boot>
        <features.repositories>mvn:org.onap.sdnc.northbound/${features.boot}/${project.version}/xml/features
        </features.repositories>
        <include.transitive.dependencies>false</include.transitive.dependencies>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.onap.sdnc.northbound</groupId>
            <artifactId>${application.name}</artifactId>
            <version>${project.version}</version>
            <type>xml</type>
            <classifier>features</classifier>
            <exclusions>
                <exclusion>
                    <groupId>*</groupId>
                    <artifactId>*</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.onap.sdnc.northbound</groupId>
            <artifactId>optical-service-model</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.onap.sdnc.northbound</groupId>
            <artifactId>optical-service-provider</artifactId>
            <version>${project.version}</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>2.6</version>
                <executions>
                    <execution>
                        <id>maven-repo-zip</id>
                        <goals>
                            <goal>single</goal>
                        </goals>
                        <phase>package</phase>
                        <configuration>
                            <attach>true</attach>
                            <finalName>stage/${application.name}-${project.version}</finalName>
                            <descriptors>
                                <descriptor>src/assembl
/*
 * Copyright 2016-2017, Nokia Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.vnfm;

import com.google.common.collect.Lists;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.nokia.cbam.lcm.v32.ApiException;
import com.nokia.cbam.lcm.v32.model.*;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.onap.vnfmdriver.model.JobDetailInfo;
import org.onap.vnfmdriver.model.JobResponseInfo;
import org.onap.vnfmdriver.model.JobStatus;
import org.springframework.test.util.ReflectionTestUtils;
import org.threeten.bp.OffsetDateTime;

import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import static junit.framework.TestCase.*;
import static org.mockito.Mockito.*;
import static org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.vnfm.CbamRestApiProvider.NOKIA_LCM_API_VERSION;
import static org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.vnfm.ILifecycleChangeNotificationManager.SEPARATOR;
import static org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.vnfm.JobManager.extractOnapJobId;
import static org.onap.vnfmdriver.model.JobStatus.*;

public class TestJobManager extends TestBase {

    @Mock
    private HttpServletResponse httpResponse;

    @InjectMocks
    private JobManager jobManager;
    private List<VnfInfo> vnfs = new ArrayList<>();

    @Before
    public void initMocks() throws Exception {
        ReflectionTestUtils.setField(JobManager.class, "logger", logger);
        when(vnfApi.vnfsGet(NOKIA_LCM_API_VERSION)).thenReturn(vnfs);
        when(selfRegistrationManager.isReady()).thenReturn(true);
    }

    /**
     * Only the _ can be used as separator
     * . / % & handled specially in URLs
     * - used in CBAM for separation
     */
    @Test
    public void testSeparator() {
        assertEquals("_", SEPARATOR);
    }

    /**
     * The operation result must contain the ONAP job identifier under the jobId field
     */
    @Test
    public void testJobIdExtractionFromOperationResult() {
        assertEquals("1234", extractOnapJobId(new JsonParser().parse("{ \"additionalParams\" : { \"jobId\" : \"1234\"}}")));
        try {
            extractOnapJobId(new JsonParser().parse("{ }"));
            fail();
        } catch (NoSuchElementException e) {
            assertEquals("The operation result {} does not contain the mandatory additionalParams structure", e.getMessage());
        }
        try {
            extractOnapJobId(new JsonParser().parse("{ \"additionalParams\" : { } }"));
            fail();
        } catch (NoSuchElementException e) {
            assertEquals("The operation result {\"additionalParams\":{}} does not contain the mandatory jobId in the additionalParams structure", e.getMessage());
        }
    }

    /**
     * If the VNF does not exists but the job manager still runs the VNF manipulation process the job is reported to be running
     */
    @Test
    public void testJobForNonExistingVnfReportedRunningIfJobIsOngoing() throws Exception {
        String jobId = jobManager.spawnJob(VNF_ID, httpResponse);
        //when
        JobDetailInfo job = jobManager.getJob(VNFM_ID, jobId);
        //verify
        assertResult(jobId, job, STARTED, "50", "Operation started");
    }

    /**
     * If the VNF does not exists and the internal job is not running the job is reported to be finished
     */
    @Test
    public void testJobForExistingVnfReportedRunningIfJobIsFinished() throws Exception {
        String jobId = jobManager.spawnJob(VNF_ID, httpResponse);
        jobManager.jobFinished(jobId);
        //when
        JobDetailInfo job = jobManager.getJob(VNFM_ID, jobId);
        //verify
        assertResult(jobId, job, JobStatus.FINISHED, "100", "Operation finished");
    }

    /**
     * Spawning jobs after preparing for shutdown results in error
     */
    @Test
    public void testNoMoreJobsAreAllowedAfterPrepareForShutdown() throws Exception {
        jobManager.prepareForShutdown();
        //when
        try {
            jobManager.spawnJob(JOB_ID, httpResponse);
            fail();
        } catch (Exception e) {
            verify(logger).error("The service is preparing to shut down");
        }
    }

    /**
     * Verify if the jobId has valid format
     */
    @Test
    public void testJobIdValidation() throws Exception {
        try {
            //when
            jobManager.getJob(VNFM_ID, "bad");
            //verify
            fail();
        } catch (IllegalArgumentException e) {
            assertEquals("The jobId should be in the <vnfId>_<UUID> format, but was bad", e.getMessage());
        }
        try {
            //when
            jobManager.getJob(VNFM_ID, "vnfId_");
            //verify
            fail();
        } catch (IllegalArgumentException e) {
            assertEquals("The UUID in the jobId (vnfId_) can not be empty", e.getMessage());
        }
        try {
            //when
            jobManager.getJob(VNFM_ID, "_UUID");
            //verify
            fail();
        } catch (IllegalArgumentException e) {
            assertEquals("The vnfId in the jobId (_UUID) can not be empty", e.getMessage());
        }
    }

    /**
     * If the VNF exists but no operation execution is present with given internalJobId, than the state of the
     * job is ongoing if the internal job is ongoing
     */
    @Test
    public void testExistingVnfWithNotYetStartedOperation() throws Exception {
        String jobId = jobManager.spawnJob(VNF_ID, httpResponse);
        VnfInfo vnf = new VnfInfo();
        vnf.setId(VNF_ID);
        vnfs.add(vnf);
        VnfInfo detailedVnf = new VnfInfo();
        detailedVnf.setId(VNF_ID);
        when(vnfApi.vnfsVnfInstanceIdGet(VNF_ID, NOKIA_LCM_API_VERSION)).thenReturn(detailedVnf);
        JobDetailInfo job = jobManager.getJob(VNFM_ID, jobId);
        //verify
        assertResult(jobId, job, STARTED, "50", "Operation started");
        assertTrue(jobManager.hasOngoingJobs());
    }

    /**
     * If the VNF exists but no operation execution is present with given internalJobId, than the state of the
     * job is failed if the internal job is finished (the operation on CBAM was not able to start)
     */
    @Test
    public void testExistingVnfWithNotUnableToStartOperation() throws Exception {
        String jobId = jobManager.spawnJob(VNF_ID, httpResponse);
        VnfInfo vnf = new VnfInfo();
        vnf.setId(VNF_ID);
        vnfs.add(vnf);
        VnfInfo detailedVnf = new VnfInfo();
        detailedVnf.setId(VNF_ID);
        when(vnfApi.vnfsVnfInstanceIdGet(VNF_ID, NOKIA_LCM_API_VERSION)).thenReturn(detailedVnf);
        jobManager.jobFinished(jobId);
        JobDetailInfo job = jobManager.getJob(VNFM_ID, jobId);
        //verify
        assertResult(jobId, job, ERROR, "100", "Operation failed due to The requested operation was not able to start on CBAM");
        assertFalse(jobManager.hasOngoingJobs());
    }

    /**
     * If the VNF exists but and the operation execution is present with given internalJobId, than the state of the
     * job is ongoing if the operation is ongoing
     */
    @Test
    public void testExistingVnfWithStartedOperation() throws Exception {
        String jobId = jobManager.spawnJob(VNF_ID, httpResponse);
        VnfInfo vnf = new VnfInfo();
        vnf.setId(VNF_ID);
        vnfs.add(vnf);
        VnfInfo detailedVnf = new VnfInfo();
        detailedVnf.setId(VNF_ID);
        when(vnfApi.vnfsVnfInstanceIdGet(VNF_ID, NOKIA_LCM_API_VERSION)).thenReturn(detailedVnf);
        OperationExecution operation = new OperationExecution();
        operation.setId(UUID.randomUUID().toString());
        operation.setStartTime(OffsetDateTime.now());
        operation.setStatus(OperationStatus.STARTED);
        detailedVnf.setOperationExecutions(new ArrayList<>());
        detailedVnf.getOperationExecutions().add(operation);
        JsonElement operationParams = new JsonParser().parse("{ \"additionalParams\" : { \"jobId\" : \"" + jobId + "\"}}");
        when(operationExecutionApi.operationExecutionsOperationExecutionIdOperationParamsGet(operation.getId(), NOKIA_LCM_API_VERSION)).thenReturn(operationParams);
        JobDetailInfo job = jobManager.getJob(VNFM_ID, jobId);
        //verify
        assertResult(jobId, job, STARTED, "50", "Operation started");
        assertTrue(jobManager.hasOngoingJobs());
    }

    /**
     * If the VNF does not exists till the time the job queries the status of the operation
     */
    @Test
    public void testTerminatedVnf() throws Exception {
        //ddd
        String jobId = jobManager.spawnJob(VNF_ID, httpResponse);
        VnfInfo vnf = new VnfInfo();
        vnf.setId(VNF_ID);
        vnfs.add(vnf);
        VnfInfo detailedVnf = new VnfInfo();
        detailedVnf.setId(VNF_ID);
        List<Integer> vnfQueryCallCounter = new ArrayList<>();
        when(vnfApi.vnfsVnfInstanceIdGet(VNF_ID, NOKIA_LCM_API_VERSION)).thenAnswer(new Answer<VnfInfo>() {
            @Override
            public VnfInfo answer(InvocationOnMock invocation) throws Throwable {
                vnfs.clear();
                return detailedVnf;
            }
        });

        jobManager.jobFinished(jobId);

        OperationExecution operation = new OperationExecution();
        operation.setId(UUID.randomUUID().toString());
        operation.setStartTime(OffsetDateTime.now());
        operation.setStatus(OperationStatus.FINISHED);
        operation.setOperationType(OperationType.TERMINATE);
        detailedVnf.setOperationExecutions(new ArrayList<>());
        detailedVnf.getOperationExecutions().add(operation);

        JsonElement operationParams = new JsonParser().parse("{ \"additionalParams\" : { \"jobId\" : \"" + jobId + "\"}}");
        when(operationExecutionApi.operationExecutionsOperationExecutionIdOperationParamsGet(operation.getId(), NOKIA_LCM_API_VERSION)).thenReturn(operationParams);
        //when
        JobDetailInfo job = jobManager.getJob(VNFM_ID, jobId);
        //verify
        assertResult(jobId, job, FINISHED, "100", "Operation finished");
    }

    /**
     * If the VNF exists but and the operation execution is present with given internalJobId, than the state of the
     * job is error if the operation is failed
     */
    @Test
    public void testExistingVnfWithFailedOperation() throws Exception {
        String jobId = jobManager.spawnJob(VNF_ID, httpResponse);
        VnfInfo vnf = new VnfInfo();
        vnf.setId(VNF_ID);
        vnfs.add(vnf);
        VnfInfo detailedVnf = new VnfInfo();
        detailedVnf.setId(VNF_ID);
        List<Integer> vnfCounter = new ArrayList<>();
        when(vnfApi.vnfsVnfInstanceIdGet(VNF_ID, NOKIA_LCM_API_VERSION)).thenReturn(detailedVnf);
        OperationExecution operation = new OperationExecution();
        operation.setId(UUID.randomUUID().toString());
        operation.setStartTime(OffsetDateTime.now());
        operation.setStatus(OperationStatus.FAILED);
        ProblemDetails errorDetails = new ProblemDetails();
        errorDetails.setTitle("Title");
        errorDetails.setDetail("detail");
        operation.setError(errorDetails);
        detailedVnf.setOperationExecutions(new ArrayList<>());
        detailedVnf.getOperationExecutions().add(operation);
        JsonElement operationParams = new JsonParser().parse("{ \"additionalParams\" : { \"jobId\" : \"" + jobId + "\"}}");
        when(operationExecutionApi.operationExecutionsOperationExecutionIdOperationParamsGet(operation.getId(), NOKIA_LCM_API_VERSION)).thenReturn(operationParams);
        //when
        JobDetailInfo job = jobManager.getJob(VNFM_ID, jobId);
        //verify
        assertResult(jobId, job, ERROR, "100", "Operation failed due to Title: detail");
        assertTrue(jobManager.hasOngoingJobs());
    }

    private void assertResult(String jobId, JobDetailInfo job, JobStatus status, String progress, String descriptor) {
        assertEquals(jobId, job.getJobId());
        assertEquals(status, job.getResponseDescriptor().getStatus());
        assertEquals(progress, job.getResponseDescriptor().getProgress());
        assertNull(job.getResponseDescriptor().getErrorCode());
        boolean finalState = JobStatus.ERROR.equals(status) || JobStatus.FINISHED.equals(status);
        if (finalState) {
            assertEquals(2, job.getResponseDescriptor().getResponseHistoryList().size());
            JobResponseInfo startEvent = job.getResponseDescriptor().getResponseHistoryList().get(0);
            JobResponseInfo endEvent = job.getResponseDescriptor().getResponseHistoryList().get(1);
            assertNull(startEvent.getErrorCode());
            assertEquals("50", startEvent.getProgress());
            assertEquals(JobStatus.STARTED.name(), startEvent.getStatus());
            assertEquals("1", startEvent.getResponseId());
            assertEquals("Operation started", startEvent.getStatusDescription());

            assertNull(endEvent.getErrorCode());
            assertEquals("100", endEvent.getProgress());
            assertEquals(job.getResponseDescriptor().getStatus().name(), endEvent.getStatus());
            assertEquals("2", endEvent.getResponseId());
            assertEquals(descriptor, endEvent.getStatusDescription());
        } else {
            assertEquals(1, job.getResponseDescriptor().getResponseHistoryList().size());
            assertNull(job.getResponseDescriptor().getResponseHistoryList().get(0).getErrorCode());
            assertEquals(progress, job.getResponseDescriptor().getResponseHistoryList().get(0).getProgress());
            assertEquals(job.getResponseDescriptor().getStatus().name(), job.getResponseDescriptor().getResponseHistoryList().get(0).getStatus());
            assertEquals("1", job.getResponseDescriptor().getResponseHistoryList().get(0).getResponseId());
            assertEquals(descriptor, job.getResponseDescriptor().getResponseHistoryList().get(0).getStatusDescription());
        }
        assertEquals(Integer.toString(job.getResponseDescriptor().getResponseHistoryList().size()), job.getResponseDescriptor().getResponseId());
        assertEquals(descriptor, job.getResponseDescriptor().getStatusDescription());
    }

    /**
     * If the VNF exists but and the operation execution is present with given internalJobId, than the state of the
     * job is finished if the operation is finished, but is not a termination
     */
    @Test
    public void testExistingVnfWithFinishedOperation() throws Exception {
        String jobId = jobManager.spawnJob(VNF_ID, httpResponse);
        VnfInfo vnf = new VnfInfo();
        vnf.setId(VNF_ID);
        vnfs.add(vnf);
        VnfInfo detailedVnf = new VnfInfo();
        detailedVnf.setId(VNF_ID);
        when(vnfApi.vnfsVnfInstanceIdGet(VNF_ID, NOKIA_LCM_API_VERSION)).thenReturn(detailedVnf);
        OperationExecution operation = new OperationExecution();
        operation.setId(UUID.randomUUID().toString());
        operation.setStartTime(OffsetDateTime.now());
        operation.setStatus(OperationStatus.FINISHED);
        operation.setOperationType(OperationType.SCALE);
        detailedVnf.setOperationExecutions(new ArrayList<>());
        detailedVnf.getOperationExecutions().add(operation);
        JsonElement operationParams = new JsonParser().parse("{ \"additionalParams\" : { \"jobId\" : \"" + jobId + "\"}}");
        when(operationExecutionApi.operationExecutionsOperationExecutionIdOperationParamsGet(operation.getId(), NOKIA_LCM_API_VERSION)).thenReturn(operationParams);
        JobDetailInfo job = jobManager.getJob(VNFM_ID, jobId);
        //verify
        assertResult(jobId, job, JobStatus.FINISHED, "100", "Operation finished");
        assertTrue(jobManager.hasOngoingJobs());
    }

    /**
     * If the VNF exists but and the operation execution is present with given internalJobId, than the state of the
     * job is ongoing if the termination operation is finished. In ONAP terminology the termination includes
     * delete, so the ONAP operation is ongoing since the VNF is not yet deleted
     */
    @Test
    public void testExistingVnfWithFinishedTerminationOperation() throws Exception {
        String jobId = jobManager.spawnJob(VNF_ID, httpResponse);
        VnfInfo vnf = new VnfInfo();
        vnf.setId(VNF_ID);
        vnfs.add(vnf);
        VnfInfo detailedVnf = new VnfInfo();
        detailedVnf.setId(VNF_ID);
        when(vnfApi.vnfsVnfInstanceIdGet(VNF_ID, NOKIA_LCM_API_VERSION)).thenReturn(detailedVnf);
        OperationExecution operation = new OperationExecution();
        operation.setId(UUID.randomUUID().toString());
        operation.setStartTime(OffsetDateTime.now());
        operation.setStatus(OperationStatus.FINISHED);
        operation.setOperationType(OperationType.TERMINATE);
        detailedVnf.setOperationExecutions(new ArrayList<>());
        detailedVnf.getOperationExecutions().add(operation);
        JsonElement operationParams = new JsonParser().parse("{ \"additionalParams\" : { \"jobId\" : \"" + jobId + "\"}}");
        when(operationExecutionApi.operationExecutionsOperationExecutionIdOperationParamsGet(operation.getId(), NOKIA_LCM_API_VERSION)).thenReturn(operationParams);
        JobDetailInfo job = jobManager.getJob(VNFM_ID, jobId);
        //verify
        assertResult(jobId, job, STARTED, "50", "Operation started");
        //when
        jobManager.jobFinished(jobId);
        job = jobManager.getJob(VNFM_ID, jobId);
        //verify
        assertResult(jobId, job, ERROR, "100", "Operation failed due to unable to delete VNF");
        assertFalse(jobManager.hasOngoingJobs());

    }

    /**
     * Failuire to retrieve operation parameters (CBAM REST API fail) is logged and propagated
     */
    @Test
    public void failuresDuringOperationExecutionRetrievalIsLoggedAndPropagated() throws Exception {
        String jobId = jobManager.spawnJob(VNF_ID, httpResponse);
        VnfInfo vnf = new VnfInfo();
        vnf.setId(VNF_ID);
        vnfs.add(vnf);
        VnfInfo detailedVnf = new VnfInfo();
        detailedVnf.setId(VNF_ID);
        when(vnfApi.vnfsVnfInstanceIdGet(VNF_ID, NOKIA_LCM_API_VERSION)).thenReturn(detailedVnf);
        OperationExecution operation = new OperationExecution();
        operation.setId(UUID.randomUUID().toString());
        detailedVnf.setOperationExecutions(new ArrayList<>());
        detailedVnf.getOperationExecutions().add(operation);
        ApiException expectedException = new ApiException();
        when(operationExecutionApi.operationExecutionsOperationExecutionIdOperationParamsGet(operation.getId(), NOKIA_LCM_API_VERSION)).thenThrow(expectedException);
        //verify
        try {
            JobDetailInfo job = jobManager.getJob(VNFM_ID, jobId);
            fail();
        } catch (RuntimeException e) {
            assertEquals(expectedException, e.getCause());
            verify(logger).error("Unable to retrieve operation parameters", expectedException);
        }
        assertTrue(jobManager.hasOngoingJobs());
    }

    /**
     * Failure to retrieve VNF (CBAM REST API fail) is logged and propagated
     */
    @Test
    public void failuresDuringVnfRetrievalIsLoggedAndPropagated() throws Exception {
        String jobId = jobManager.spawnJob(VNF_ID, httpResponse);
        VnfInfo vnf = new VnfInfo();
        vnf.setId(VNF_ID);
        vnfs.add(vnf);
        ApiException expectedException = new ApiException();
        when(vnfApi.vnfsVnfInstanceIdGet(VNF_ID, NOKIA_LCM_API_VERSION)).thenThrow(expectedException);
        //verify
        try {
            JobDetailInfo job = jobManager.getJob(VNFM_ID, jobId);
            fail();
        } catch (RuntimeException e) {
            assertEquals(expectedException, e.getCause());
            verify(logger).error("Unable to retrieve VNF", expectedException);
        }
        assertTrue(jobManager.hasOngoingJobs());
    }

    /**
     * When searching for the ONAP job by iterating the operation executions. The newest jobs
     * are inspected first (performance optimalization)
     */
    @Test
    public void testNewestOperationAreInspectedFirst() throws Exception {
        String jobId = jobManager.spawnJob(VNF_ID, httpResponse);
        VnfInfo vnf = new VnfInfo();
        vnf.setId(VNF_ID);
        vnfs.add(vnf);
        VnfInfo detailedVnf = new VnfInfo();
        detailedVnf.setId(VNF_ID);
        when(vnfApi.vnfsVnfInstanceIdGet(VNF_ID, NOKIA_LCM_API_VERSION)).thenReturn(detailedVnf);
        OperationExecution olderOperation = new OperationExecution();
        olderOperation.setId(UUID.randomUUID().toString());
        olderOperation.setStartTime(OffsetDateTime.now());
        olderOperation.setStatus(OperationStatus.FINISHED);
        olderOperation.setOperationType(OperationType.TERMINATE);
        OperationExecution newerOperation = new OperationExecution();
        newerOperation.setId(UUID.randomUUID().toString());
        newerOperation.setStartTime(OffsetDateTime.now().plusDays(1));
        newerOperation.setStatus(OperationStatus.FINISHED);
        newerOperation.setOperationType(OperationType.TERMINATE);
        detailedVnf.setOperationExecutions(new ArrayList<>());
        detailedVnf.getOperationExecutions().add(olderOperation);
        detailedVnf.getOperationExecutions().add(newerOperation);
        JsonElement operationParams = new JsonParser().parse("{ \"additionalParams\" : { \"jobId\" : \"" + jobId + "\"}}");
        List<String> queriedOperaionsInOrder = new ArrayList<>();
        when(operationExecutionApi.operationExecutionsOperationExecutionIdOperationParamsGet(Mockito.anyString(), Mockito.eq(NOKIA_LCM_API_VERSION)))
                .then(new Answer<Object>() {
                    @Override
                    public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
                        queriedOperaionsInOrder.add(invocationOnMock.getArguments()[0].toString());
                        if (invocationOnMock.getArguments()[0].equals(olderOperation.getId())) {
                            return new JsonParser().parse("{ \"additionalParams\" : { \"jobId\" : \"" + jobId + "\"}}");
                        } else {
                            return new JsonParser().parse("{ \"additionalParams\" : { \"jobId\" : \"" + "nonMatching" + "\"}}");
                        }
                    }
                });
        JobDetailInfo job = jobManager.getJob(VNFM_ID, jobId);
        //verify
        assertEquals(Lists.newArrayList(newerOperation.getId(), olderOperation.getId()), queriedOperaionsInOrder);
        assertTrue(jobManager.hasOngoingJobs());
    }

    /**
     * if the registration process has not finished it is prevented to spawn jobs
     */
    @Test
    public void noJobCanBeStartedIfRegistrationNotFinished() throws Exception {
        //given
        when(selfRegistrationManager.isReady()).thenReturn(false);
        //when
        try {
            jobManager.spawnJob(VNF_ID, httpResponse);
            fail();
        } catch (RuntimeException e) {
            assertEquals("The service is not yet ready", e.getMessage());
        }
    }

    /**
     * Ongoing job are out waited during the the preparation for shutdown
     */
    @Test
    public void onGoingJobsAreOutwaitedDuringShutdown() throws Exception {
        String firstJobId = jobManager.spawnJob(VNF_ID, httpResponse);
        ExecutorService executorService = Executors.newCachedThreadPool();
        ArgumentCaptor<Integer> sleeps = ArgumentCaptor.forClass(Integer.class);
        doNothing().when(systemFunctions).sleep(sleeps.capture());
        Future<?> shutDown = executorService.submit(new Runnable() {
            @Override
            public void run() {
                jobManager.prepareForShutdown();
            }
        });
        while (sleeps.getAllValues().size() == 0) {
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
            }
        }
        assertFalse(shutDown.isDone());
        jobManager.jobFinished(firstJobId);
        //verify
        shutDown.get();
        verify(systemFunctions, times(sleeps.getAllValues().size())).sleep(500L);
    }
}