From a995e82e01a3315940051ca55133c9cb14eccc6b Mon Sep 17 00:00:00 2001 From: Denes Nemeth Date: Mon, 9 Apr 2018 15:04:03 +0200 Subject: [PATCH] Fix container startup Change-Id: I5e7f9fb4bc83b113b5d27c5cd26e19cdc42e2c57 Issue-ID: VFC-728 Signed-off-by: Denes Nemeth --- .../vnfm/svnfm/nokia/NokiaSvnfmApplication.java | 64 +++++++++--- .../nokia/onap/core/SelfRegistrationManager.java | 3 - .../vnfm/svnfm/nokia/util/SystemFunctions.java | 9 ++ .../driver/vnfm/svnfm/nokia/vnfm/JobManager.java | 7 ++ .../driver/src/main/resources/self.swagger.json | 8 +- .../svnfm/nokia/TestNokiaSvnfmApplication.java | 115 +++++++++++++++------ .../vnfm/svnfm/nokia/util/TestSystemFunctions.java | 12 +++ .../vnfm/svnfm/nokia/vnfm/TestJobManager.java | 2 + .../generatedapis/src/main/resources/so.vnfm.json | 8 +- 9 files changed, 172 insertions(+), 56 deletions(-) diff --git a/nokiav2/driver/src/main/java/org/onap/vfc/nfvo/driver/vnfm/svnfm/nokia/NokiaSvnfmApplication.java b/nokiav2/driver/src/main/java/org/onap/vfc/nfvo/driver/vnfm/svnfm/nokia/NokiaSvnfmApplication.java index 6296d4b2..ceb0335d 100644 --- a/nokiav2/driver/src/main/java/org/onap/vfc/nfvo/driver/vnfm/svnfm/nokia/NokiaSvnfmApplication.java +++ b/nokiav2/driver/src/main/java/org/onap/vfc/nfvo/driver/vnfm/svnfm/nokia/NokiaSvnfmApplication.java @@ -16,7 +16,12 @@ 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 { + 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 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 { + 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) { diff --git a/nokiav2/driver/src/main/java/org/onap/vfc/nfvo/driver/vnfm/svnfm/nokia/onap/core/SelfRegistrationManager.java b/nokiav2/driver/src/main/java/org/onap/vfc/nfvo/driver/vnfm/svnfm/nokia/onap/core/SelfRegistrationManager.java index 172dd338..1dc32209 100644 --- a/nokiav2/driver/src/main/java/org/onap/vfc/nfvo/driver/vnfm/svnfm/nokia/onap/core/SelfRegistrationManager.java +++ b/nokiav2/driver/src/main/java/org/onap/vfc/nfvo/driver/vnfm/svnfm/nokia/onap/core/SelfRegistrationManager.java @@ -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}") diff --git a/nokiav2/driver/src/main/java/org/onap/vfc/nfvo/driver/vnfm/svnfm/nokia/util/SystemFunctions.java b/nokiav2/driver/src/main/java/org/onap/vfc/nfvo/driver/vnfm/svnfm/nokia/util/SystemFunctions.java index 22d4c20d..87a4d56d 100644 --- a/nokiav2/driver/src/main/java/org/onap/vfc/nfvo/driver/vnfm/svnfm/nokia/util/SystemFunctions.java +++ b/nokiav2/driver/src/main/java/org/onap/vfc/nfvo/driver/vnfm/svnfm/nokia/util/SystemFunctions.java @@ -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 diff --git a/nokiav2/driver/src/main/java/org/onap/vfc/nfvo/driver/vnfm/svnfm/nokia/vnfm/JobManager.java b/nokiav2/driver/src/main/java/org/onap/vfc/nfvo/driver/vnfm/svnfm/nokia/vnfm/JobManager.java index 277be9c4..e97f634d 100644 --- a/nokiav2/driver/src/main/java/org/onap/vfc/nfvo/driver/vnfm/svnfm/nokia/vnfm/JobManager.java +++ b/nokiav2/driver/src/main/java/org/onap/vfc/nfvo/driver/vnfm/svnfm/nokia/vnfm/JobManager.java @@ -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 diff --git a/nokiav2/driver/src/main/resources/self.swagger.json b/nokiav2/driver/src/main/resources/self.swagger.json index 64041502..37da1b30 100644 --- a/nokiav2/driver/src/main/resources/self.swagger.json +++ b/nokiav2/driver/src/main/resources/self.swagger.json @@ -1169,7 +1169,7 @@ }, "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", @@ -1298,7 +1298,7 @@ "/so/{vnfmId}/vnfs/{vnfId}/heal": { "post": { "tags": [ - "SO VNFM driver" + "SO VNFM Adaptor" ], "summary": "VNF heal", "description": "VNF heal", @@ -1347,7 +1347,7 @@ "/so/{vnfmId}/vnfs/{vnfId}/terminate": { "post": { "tags": [ - "SO VNFM driver" + "SO VNFM Adaptor" ], "summary": "VNF terminate", "description": "VNF terminate", @@ -1396,7 +1396,7 @@ "/so/{vnfmId}/jobs/{jobId}": { "get": { "tags": [ - "SO VNFM driver" + "SO VNFM Adaptor" ], "summary": "Query job status", "description": "Query the job status", diff --git a/nokiav2/driver/src/test/java/org/onap/vfc/nfvo/driver/vnfm/svnfm/nokia/TestNokiaSvnfmApplication.java b/nokiav2/driver/src/test/java/org/onap/vfc/nfvo/driver/vnfm/svnfm/nokia/TestNokiaSvnfmApplication.java index 444660b1..c6586c28 100644 --- a/nokiav2/driver/src/test/java/org/onap/vfc/nfvo/driver/vnfm/svnfm/nokia/TestNokiaSvnfmApplication.java +++ b/nokiav2/driver/src/test/java/org/onap/vfc/nfvo/driver/vnfm/svnfm/nokia/TestNokiaSvnfmApplication.java @@ -15,40 +15,46 @@ */ 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 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); } } diff --git a/nokiav2/driver/src/test/java/org/onap/vfc/nfvo/driver/vnfm/svnfm/nokia/util/TestSystemFunctions.java b/nokiav2/driver/src/test/java/org/onap/vfc/nfvo/driver/vnfm/svnfm/nokia/util/TestSystemFunctions.java index 0b31fef5..c627bfcf 100644 --- a/nokiav2/driver/src/test/java/org/onap/vfc/nfvo/driver/vnfm/svnfm/nokia/util/TestSystemFunctions.java +++ b/nokiav2/driver/src/test/java/org/onap/vfc/nfvo/driver/vnfm/svnfm/nokia/util/TestSystemFunctions.java @@ -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()); + } } diff --git a/nokiav2/driver/src/test/java/org/onap/vfc/nfvo/driver/vnfm/svnfm/nokia/vnfm/TestJobManager.java b/nokiav2/driver/src/test/java/org/onap/vfc/nfvo/driver/vnfm/svnfm/nokia/vnfm/TestJobManager.java index b34bc1d7..432fff6d 100644 --- a/nokiav2/driver/src/test/java/org/onap/vfc/nfvo/driver/vnfm/svnfm/nokia/vnfm/TestJobManager.java +++ b/nokiav2/driver/src/test/java/org/onap/vfc/nfvo/driver/vnfm/svnfm/nokia/vnfm/TestJobManager.java @@ -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()); } /** diff --git a/nokiav2/generatedapis/src/main/resources/so.vnfm.json b/nokiav2/generatedapis/src/main/resources/so.vnfm.json index 78b8dffd..75b76a3c 100644 --- a/nokiav2/generatedapis/src/main/resources/so.vnfm.json +++ b/nokiav2/generatedapis/src/main/resources/so.vnfm.json @@ -114,7 +114,7 @@ }, "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", @@ -249,7 +249,7 @@ "/so/{vnfmId}/vnfs/{vnfId}/heal": { "post": { "tags": [ - "SO VNFM driver" + "SO VNFM Adaptor" ], "summary": "VNF heal", "description": "VNF heal", @@ -298,7 +298,7 @@ "/so/{vnfmId}/vnfs/{vnfId}/terminate": { "post": { "tags": [ - "SO VNFM driver" + "SO VNFM Adaptor" ], "summary": "VNF terminate", "description": "VNF terminate", @@ -347,7 +347,7 @@ "/so/{vnfmId}/jobs/{jobId}": { "get": { "tags": [ - "SO VNFM driver" + "SO VNFM Adaptor" ], "summary": "Query job status", "description": "Query the job status", -- 2.16.6