Fix container startup 21/41721/2
authorDenes Nemeth <denes.nemeth@nokia.com>
Mon, 9 Apr 2018 13:04:03 +0000 (15:04 +0200)
committerDenes Nemeth <denes.nemeth@nokia.com>
Mon, 9 Apr 2018 16:09:33 +0000 (18:09 +0200)
Change-Id: I5e7f9fb4bc83b113b5d27c5cd26e19cdc42e2c57
Issue-ID: VFC-728
Signed-off-by: Denes Nemeth <denes.nemeth@nokia.com>
nokiav2/driver/src/main/java/org/onap/vfc/nfvo/driver/vnfm/svnfm/nokia/NokiaSvnfmApplication.java
nokiav2/driver/src/main/java/org/onap/vfc/nfvo/driver/vnfm/svnfm/nokia/onap/core/SelfRegistrationManager.java
nokiav2/driver/src/main/java/org/onap/vfc/nfvo/driver/vnfm/svnfm/nokia/util/SystemFunctions.java
nokiav2/driver/src/main/java/org/onap/vfc/nfvo/driver/vnfm/svnfm/nokia/vnfm/JobManager.java
nokiav2/driver/src/main/resources/self.swagger.json
nokiav2/driver/src/test/java/org/onap/vfc/nfvo/driver/vnfm/svnfm/nokia/TestNokiaSvnfmApplication.java
nokiav2/driver/src/test/java/org/onap/vfc/nfvo/driver/vnfm/svnfm/nokia/util/TestSystemFunctions.java
nokiav2/driver/src/test/java/org/onap/vfc/nfvo/driver/vnfm/svnfm/nokia/vnfm/TestJobManager.java
nokiav2/generatedapis/src/main/resources/so.vnfm.json

index 6296d4b..ceb0335 100644 (file)
 
 package org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia;
 
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
 import org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.onap.core.SelfRegistrationManager;
+import org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.util.SystemFunctions;
 import org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.vnfm.JobManager;
 import org.slf4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -28,6 +33,9 @@ import org.springframework.context.annotation.Profile;
 import org.springframework.context.event.ContextClosedEvent;
 import org.springframework.stereotype.Component;
 
+import static java.util.concurrent.Executors.newCachedThreadPool;
+
+import static org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.util.SystemFunctions.systemFunctions;
 import static org.slf4j.LoggerFactory.getLogger;
 
 /**
@@ -43,7 +51,7 @@ public class NokiaSvnfmApplication {
      * @param args arguments for the application (not used)
      */
     public static void main(String[] args) {
-        SpringApplication.run(NokiaSvnfmApplication.class, args);
+        systemFunctions().newSpringApplication(NokiaSvnfmApplication.class).run(args);
     }
 
     /**
@@ -55,19 +63,45 @@ public class NokiaSvnfmApplication {
     @Component
     @Profile("!test")
     public static class SelfRegistrationTrigger implements ApplicationListener<ApplicationReadyEvent> {
+        private final SelfRegistrationManager selfRegistrationManager;
+        private final JobManager jobManager;
+        /**
+         * Runs the registration process
+         */
+        private ExecutorService executorService = newCachedThreadPool();
+
         @Autowired
-        private SelfRegistrationManager selfRegistrationManager;
+        SelfRegistrationTrigger(SelfRegistrationManager selfRegistrationManager, JobManager jobManager){
+            this.jobManager = jobManager;
+            this.selfRegistrationManager = selfRegistrationManager;
+        }
 
         @Override
         public void onApplicationEvent(ApplicationReadyEvent contextRefreshedEvent) {
-            logger.info("Self registration started");
-            try {
-                selfRegistrationManager.register();
-                logger.info("Self registration finished");
-            } catch (RuntimeException e) {
-                logger.error("Self registration failed", e);
-                throw e;
-            }
+            Callable<Boolean> singleRegistration = () -> {
+                logger.info("Self registration started");
+                try {
+                    selfRegistrationManager.register();
+                    logger.info("Self registration finished");
+                } catch (RuntimeException e) {
+                    logger.error("Self registration failed", e);
+                    throw e;
+                }
+                return true;
+            };
+            executorService.submit(() -> {
+                while(!jobManager.isPreparingForShutDown()){
+                    try{
+                        executorService.submit(singleRegistration).get();
+                        //registration successful
+                        return;
+                    }
+                    catch (Exception e){
+                        logger.warn("Unable to execute self registration process", e);
+                    }
+                    systemFunctions().sleep(5000);
+                }
+            });
         }
     }
 
@@ -79,10 +113,14 @@ public class NokiaSvnfmApplication {
     @Component
     @Profile("!test")
     public static class SelfDeRegistrationTrigger implements ApplicationListener<ContextClosedEvent> {
+        private final SelfRegistrationManager selfRegistrationManager;
+        private final JobManager jobManager;
+
         @Autowired
-        private SelfRegistrationManager selfRegistrationManager;
-        @Autowired
-        private JobManager jobManager;
+        SelfDeRegistrationTrigger(SelfRegistrationManager selfRegistrationManager, JobManager jobManager){
+            this.jobManager = jobManager;
+            this.selfRegistrationManager = selfRegistrationManager;
+        }
 
         @Override
         public void onApplicationEvent(ContextClosedEvent contextClosedEvent) {
index 172dd33..1dc3220 100644 (file)
@@ -42,14 +42,11 @@ import static org.slf4j.LoggerFactory.getLogger;
 public class SelfRegistrationManager {
     public static final String DRIVER_VERSION = "v1";
     public static final String SERVICE_NAME = "NokiaSVNFM";
-    // 1 means internal 0 means core :)
-    public static final String INTERNAL_SERVICE = "1";
     public static final String SWAGGER_API_DEFINITION = "self.swagger.json";
     private static Logger logger = getLogger(SelfRegistrationManager.class);
     private final DriverProperties driverProperties;
     private final MsbApiProvider msbApiProvider;
     private final CbamRestApiProvider cbamRestApiProvider;
-
     @Value("${driverMsbExternalIp}")
     private String driverMsbExternalIp;
     @Value("${driverVnfmExternalIp}")
index 22d4c20..87a4d56 100644 (file)
@@ -20,6 +20,7 @@ import java.io.InputStream;
 import java.io.PrintStream;
 import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.http.impl.client.HttpClients;
+import org.springframework.boot.SpringApplication;
 
 /**
  * Wrapper class for static method calls to core or core libraries.
@@ -160,4 +161,12 @@ public class SystemFunctions {
     public CloseableHttpClient getHttpClient() {
         return HttpClients.createDefault();
     }
+
+    /**
+     * @param clazz the main source of the Spring application
+     * @return a new Spring application
+     */
+    public SpringApplication newSpringApplication(Class clazz){
+        return new SpringApplication(clazz);
+    }
 }
\ No newline at end of file
index 277be9c..e97f634 100644 (file)
@@ -97,6 +97,13 @@ public class JobManager {
         return jobId.getAsString();
     }
 
+    /**
+     * @return is the component preparing for shutdown
+     */
+    public boolean isPreparingForShutDown(){
+        return preparingForShutDown;
+    }
+
     /**
      * Throws an exception in case the service is not ready to serve requests due to
      * not being able to register to MSB or to subscribe to CBAM LCNs
index 6404150..37da1b3 100644 (file)
       },
       "delete": {
         "tags": [
-          "SO VNFM driver"
+          "SO VNFM Adaptor"
         ],
         "summary": "Deletes VNF",
         "description": "Deletes the VNF. If the VNF was instantiated VNF termination must be called before VNF deletion",
     "/so/{vnfmId}/vnfs/{vnfId}/heal": {
       "post": {
         "tags": [
-          "SO VNFM driver"
+          "SO VNFM Adaptor"
         ],
         "summary": "VNF heal",
         "description": "VNF heal",
     "/so/{vnfmId}/vnfs/{vnfId}/terminate": {
       "post": {
         "tags": [
-          "SO VNFM driver"
+          "SO VNFM Adaptor"
         ],
         "summary": "VNF terminate",
         "description": "VNF terminate",
     "/so/{vnfmId}/jobs/{jobId}": {
       "get": {
         "tags": [
-          "SO VNFM driver"
+          "SO VNFM Adaptor"
         ],
         "summary": "Query job status",
         "description": "Query the job status",
index 444660b..c6586c2 100644 (file)
  */
 package org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia;
 
+import java.util.HashSet;
+import java.util.Set;
 import junit.framework.TestCase;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.*;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
 import org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.onap.core.SelfRegistrationManager;
+import org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.util.SystemFunctions;
+import org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.util.TestUtil;
 import org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.vnfm.JobManager;
+import org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.vnfm.TestBase;
 import org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.vnfm.Useless;
 import org.slf4j.Logger;
+import org.springframework.boot.SpringApplication;
 import org.springframework.boot.context.event.ApplicationReadyEvent;
 import org.springframework.context.event.ContextClosedEvent;
 import org.springframework.test.util.ReflectionTestUtils;
 
 import static junit.framework.TestCase.assertEquals;
 import static junit.framework.TestCase.assertTrue;
-import static org.mockito.Mockito.verify;
+import static junit.framework.TestCase.fail;
+import static org.mockito.Mockito.*;
+import static org.springframework.test.util.ReflectionTestUtils.setField;
 
 
-public class TestNokiaSvnfmApplication {
-    @Mock
-    private SelfRegistrationManager selfRegistrationManager;
+public class TestNokiaSvnfmApplication extends TestBase {
     @Mock
     private JobManager jobManager;
-    @Mock
-    private Logger logger;
-    @InjectMocks
+
     private NokiaSvnfmApplication.SelfRegistrationTrigger selfRegistrationTriggerer;
-    @InjectMocks
     private NokiaSvnfmApplication.SelfDeRegistrationTrigger selfUnregistrationTriggerer;
 
 
     @Before
     public void initMocks() throws Exception {
-        MockitoAnnotations.initMocks(this);
-        ReflectionTestUtils.setField(NokiaSvnfmApplication.class, "logger", logger);
+        selfRegistrationTriggerer = new NokiaSvnfmApplication.SelfRegistrationTrigger(selfRegistrationManager, jobManager);
+        selfUnregistrationTriggerer = new NokiaSvnfmApplication.SelfDeRegistrationTrigger(selfRegistrationManager, jobManager);
+        setField(NokiaSvnfmApplication.class, "logger", logger);
     }
 
     /**
@@ -66,15 +72,27 @@ public class TestNokiaSvnfmApplication {
      * Assert that the self registration process is started after the servlet is up and is able to answer REST requests.
      */
     @Test
+    @SuppressWarnings("squid:S2925") //the execution is asynchronous no other way to wait
     public void testRegistrationIsCalledAfterComponentIsUp() throws Exception {
         //given
         ApplicationReadyEvent event = Mockito.mock(ApplicationReadyEvent.class);
         //when
         selfRegistrationTriggerer.onApplicationEvent(event);
         //verify
-        verify(selfRegistrationManager).register();
-        verify(logger).info("Self registration started");
-        verify(logger).info("Self registration finished");
+        boolean success = false;
+        while(!success)
+        {
+            try {
+                verify(selfRegistrationManager).register();
+                verify(logger).info("Self registration started");
+                verify(logger).info("Self registration finished");
+                success = true;
+            }
+            catch (Error e){
+
+            }
+            Thread.sleep(10);
+        }
         // this forces the event to be fired after the servlet is up (prevents refactor)
         assertTrue(ApplicationReadyEvent.class.isAssignableFrom(event.getClass()));
     }
@@ -98,24 +116,56 @@ public class TestNokiaSvnfmApplication {
         assertTrue(ContextClosedEvent.class.isAssignableFrom(event.getClass()));
     }
 
+    /**
+     * Assert that the self registration process is started after the servlet is up and is able to answer REST requests.
+     */
+    @Test
+    public void testPreparingForShutdownDoesNotStartRegistration() throws Exception {
+        //given
+        ApplicationReadyEvent event = Mockito.mock(ApplicationReadyEvent.class);
+        when(jobManager.isPreparingForShutDown()).thenReturn(true);
+        //when
+        selfRegistrationTriggerer.onApplicationEvent(event);
+        //verify
+        verify(selfRegistrationManager, never()).register();
+    }
+
     /**
      * Failures in registration is logged and propagated
      */
     @Test
-    public void failedRegistration() {
+    @SuppressWarnings("squid:S2925") //the execution is asynchronous no other way to wait
+    public void failedFirstRegistration() {
         //given
-        RuntimeException expectedException = new RuntimeException();
-        Mockito.doThrow(expectedException).when(selfRegistrationManager).register();
+        Set<RuntimeException> expectedException = new HashSet<>();
+        doAnswer(new Answer() {
+            @Override
+            public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
+                if(expectedException.size() == 0){
+                    RuntimeException e = new RuntimeException();
+                    expectedException.add(e);
+                    throw e;
+                }
+                return null;
+            }
+        }).when(selfRegistrationManager).register();
         ApplicationReadyEvent event = Mockito.mock(ApplicationReadyEvent.class);
         //when
-        try {
-            selfRegistrationTriggerer.onApplicationEvent(event);
-            //verify
-            TestCase.fail();
-        } catch (RuntimeException e) {
-            assertEquals(e, expectedException);
+        selfRegistrationTriggerer.onApplicationEvent(event);
+        //verify
+        //wait for the registration to succeed
+        boolean success = false;
+        while(!success){
+            try{
+                verify(logger).info("Self registration finished");
+                success = true;
+                Thread.sleep(10);
+            }
+            catch (Exception e2){}
+            catch (Error e){}
         }
-        verify(logger).error("Self registration failed", expectedException);
+        verify(logger, times(2)).info("Self registration started");
+        verify(logger).error("Self registration failed", expectedException.iterator().next());
     }
 
     /**
@@ -131,7 +181,7 @@ public class TestNokiaSvnfmApplication {
         try {
             selfUnregistrationTriggerer.onApplicationEvent(event);
             //verify
-            TestCase.fail();
+            fail();
         } catch (RuntimeException e) {
             assertEquals(e, expectedException);
         }
@@ -149,16 +199,17 @@ public class TestNokiaSvnfmApplication {
     }
 
     /**
-     * static entry point calling an other static entry point can not be tested
-     * only using powermock
+     * test spring application bootstrapping
      */
     @Test
-    @Useless
     public void useless() throws Exception {
-        try {
-            NokiaSvnfmApplication.main(null);
-        } catch (Exception e) {
-
-        }
+        String[] args = new String [0];
+        SpringApplication springApplicaiton = Mockito.mock(SpringApplication.class);
+        SystemFunctions systemFunctions = SystemFunctions.systemFunctions();
+        when(this.systemFunctions.newSpringApplication(NokiaSvnfmApplication.class)).thenReturn(springApplicaiton);
+        //when
+        NokiaSvnfmApplication.main(args);
+        //verify
+        verify(springApplicaiton).run(args);
     }
 }
index 0b31fef..c627bfc 100644 (file)
@@ -20,7 +20,9 @@ import java.util.Base64;
 import java.util.HashSet;
 import java.util.Set;
 import org.junit.Test;
+import org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.NokiaSvnfmApplication;
 import org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.vnfm.Useless;
+import org.springframework.boot.SpringApplication;
 
 import static org.junit.Assert.*;
 
@@ -115,4 +117,14 @@ public class TestSystemFunctions {
     public void testHttp() {
         assertNotNull(SystemFunctions.systemFunctions().getHttpClient());
     }
+
+    /**
+     * Test spring application wrapping
+      */
+    @Test
+    public void testSpring(){
+        SpringApplication springApplication = SystemFunctions.systemFunctions().newSpringApplication(NokiaSvnfmApplication.class);
+
+        assertEquals(1, springApplication.getAllSources().size());
+    }
 }
index b34bc1d..432fff6 100644 (file)
@@ -118,6 +118,7 @@ public class TestJobManager extends TestBase {
         JobDetailInfo job = jobManager.getJob(VNFM_ID, jobId);
         //verify
         assertResult(jobId, job, JobStatus.FINISHED, "100", "Operation finished");
+        assertEquals(false, jobManager.isPreparingForShutDown());
     }
 
     /**
@@ -133,6 +134,7 @@ public class TestJobManager extends TestBase {
         } catch (Exception e) {
             verify(logger).error("The service is preparing to shut down");
         }
+        assertEquals(true, jobManager.isPreparingForShutDown());
     }
 
     /**
index 78b8dff..75b76a3 100644 (file)
       },
       "delete": {
         "tags": [
-          "SO VNFM driver"
+          "SO VNFM Adaptor"
         ],
         "summary": "Deletes VNF",
         "description": "Deletes the VNF. If the VNF was instantiated VNF termination must be called before VNF deletion",
     "/so/{vnfmId}/vnfs/{vnfId}/heal": {
       "post": {
         "tags": [
-          "SO VNFM driver"
+          "SO VNFM Adaptor"
         ],
         "summary": "VNF heal",
         "description": "VNF heal",
     "/so/{vnfmId}/vnfs/{vnfId}/terminate": {
       "post": {
         "tags": [
-          "SO VNFM driver"
+          "SO VNFM Adaptor"
         ],
         "summary": "VNF terminate",
         "description": "VNF terminate",
     "/so/{vnfmId}/jobs/{jobId}": {
       "get": {
         "tags": [
-          "SO VNFM driver"
+          "SO VNFM Adaptor"
         ],
         "summary": "Query job status",
         "description": "Query the job status",