From 1162f4b61e6893c0f44d1f9d5d8abc81a94bed48 Mon Sep 17 00:00:00 2001 From: Jim Hahn Date: Mon, 11 Mar 2019 11:37:53 -0400 Subject: Add ServiceManager class Added ServiceManager class to start a list of services, in order, and stop them in reverse order. Also addressed minor checkstyle issue in TopicSinkClient. Enabled logging from tests. Updated some comments. Updated license date. Added state checks and support for multi-threading. Change-Id: Ie7f053d9884766fe199895691a57eb5a51b1d155 Issue-ID: POLICY-1542 Signed-off-by: Jim Hahn --- .../common/utils/resources/ResourceUtilsTest.java | 16 +- .../services/ServiceManagerExceptionTest.java | 63 ++++++ .../common/utils/services/ServiceManagerTest.java | 249 +++++++++++++++++++++ 3 files changed, 320 insertions(+), 8 deletions(-) create mode 100644 utils/src/test/java/org/onap/policy/common/utils/services/ServiceManagerExceptionTest.java create mode 100644 utils/src/test/java/org/onap/policy/common/utils/services/ServiceManagerTest.java (limited to 'utils/src/test/java/org') diff --git a/utils/src/test/java/org/onap/policy/common/utils/resources/ResourceUtilsTest.java b/utils/src/test/java/org/onap/policy/common/utils/resources/ResourceUtilsTest.java index d1aa59d5..eb918d35 100644 --- a/utils/src/test/java/org/onap/policy/common/utils/resources/ResourceUtilsTest.java +++ b/utils/src/test/java/org/onap/policy/common/utils/resources/ResourceUtilsTest.java @@ -5,15 +5,15 @@ * 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. - * + * * SPDX-License-Identifier: Apache-2.0 * ============LICENSE_END========================================================= */ @@ -158,10 +158,10 @@ public class ResourceUtilsTest { theUrl = ResourceUtils.getLocalFile("file:///"); assertNotNull(theUrl); - + theUrl = ResourceUtils.getLocalFile("file:///testdir/testfile.xml"); assertNull(theUrl); - + theUrl = ResourceUtils.getLocalFile(null); assertNull(theUrl); } @@ -185,7 +185,7 @@ public class ResourceUtilsTest { theStream = ResourceUtils.getResourceAsStream(jarFileResource); assertNotNull(theStream); - + theStream = ResourceUtils.getResourceAsStream(pathDirResource); assertNotNull(theStream); @@ -250,7 +250,7 @@ public class ResourceUtilsTest { assertNull(theString); theString = ResourceUtils.getResourceAsString(""); - assertEquals("org\ntestdir\n", theString); + assertEquals("logback-test.xml\norg\ntestdir\n", theString); } @Test @@ -295,7 +295,7 @@ public class ResourceUtilsTest { assertEquals("/something/else", ResourceUtils.getFilePath4Resource("/something/else")); assertTrue(ResourceUtils.getFilePath4Resource("xml/example.xml").endsWith("xml/example.xml")); } - + /** * Cleandown resource utils test. */ diff --git a/utils/src/test/java/org/onap/policy/common/utils/services/ServiceManagerExceptionTest.java b/utils/src/test/java/org/onap/policy/common/utils/services/ServiceManagerExceptionTest.java new file mode 100644 index 00000000..5fe321e8 --- /dev/null +++ b/utils/src/test/java/org/onap/policy/common/utils/services/ServiceManagerExceptionTest.java @@ -0,0 +1,63 @@ +/* + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.common.utils.services; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; + +import org.junit.Test; + +public class ServiceManagerExceptionTest { + private ServiceManagerException sme; + + @Test + public void testServiceManagerException() { + sme = new ServiceManagerException(); + assertNull(sme.getMessage()); + assertNull(sme.getCause()); + } + + @Test + public void testServiceManagerExceptionString() { + sme = new ServiceManagerException("hello"); + assertEquals("hello", sme.getMessage()); + assertNull(sme.getCause()); + } + + @Test + public void testServiceManagerExceptionThrowable() { + Throwable thrown = new Throwable("expected exception"); + sme = new ServiceManagerException(thrown); + assertNotNull(sme.getMessage()); + assertSame(thrown, sme.getCause()); + } + + @Test + public void testServiceManagerExceptionStringThrowable() { + Throwable thrown = new Throwable("another expected exception"); + sme = new ServiceManagerException("world", thrown); + assertEquals("world", sme.getMessage()); + assertSame(thrown, sme.getCause()); + } + +} diff --git a/utils/src/test/java/org/onap/policy/common/utils/services/ServiceManagerTest.java b/utils/src/test/java/org/onap/policy/common/utils/services/ServiceManagerTest.java new file mode 100644 index 00000000..49c0599b --- /dev/null +++ b/utils/src/test/java/org/onap/policy/common/utils/services/ServiceManagerTest.java @@ -0,0 +1,249 @@ +/* + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.common.utils.services; + +import static org.assertj.core.api.Assertions.assertThatIllegalStateException; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.Arrays; +import java.util.LinkedList; +import org.junit.Before; +import org.junit.Test; +import org.onap.policy.common.capabilities.Startable; +import org.onap.policy.common.utils.services.ServiceManager.RunnableWithEx; + +public class ServiceManagerTest { + private static final String ALREADY_RUNNING = "services are already running"; + private static final String EXPECTED_EXCEPTION = "expected exception"; + + private ServiceManager svcmgr; + + /** + * Initializes {@link #svcmgr}. + */ + @Before + public void setUp() { + svcmgr = new ServiceManager(); + } + + @Test + public void testAddAction() throws Exception { + RunnableWithEx start1 = mock(RunnableWithEx.class); + RunnableWithEx stop1 = mock(RunnableWithEx.class); + svcmgr.addAction("first action", start1, stop1); + + RunnableWithEx start2 = mock(RunnableWithEx.class); + RunnableWithEx stop2 = mock(RunnableWithEx.class); + svcmgr.addAction("second action", start2, stop2); + + svcmgr.start(); + verify(start1).run(); + verify(start2).run(); + verify(stop1, never()).run(); + verify(stop2, never()).run(); + + // cannot add while running + assertThatIllegalStateException().isThrownBy(() -> svcmgr.addAction("fail action", start1, stop1)) + .withMessage(ALREADY_RUNNING + "; cannot add fail action"); + + svcmgr.stop(); + verify(start1).run(); + verify(start2).run(); + verify(stop1).run(); + verify(stop2).run(); + } + + @Test + public void testAddStartable() throws Exception { + Startable start1 = mock(Startable.class); + svcmgr.addService("first startable", start1); + + Startable start2 = mock(Startable.class); + svcmgr.addService("second startable", start2); + + svcmgr.start(); + verify(start1).start(); + verify(start1, never()).stop(); + verify(start2).start(); + verify(start2, never()).stop(); + + // cannot add while running + assertThatIllegalStateException().isThrownBy(() -> svcmgr.addService("fail startable", start1)) + .withMessage(ALREADY_RUNNING + "; cannot add fail startable"); + + svcmgr.stop(); + verify(start1).start(); + verify(start1).stop(); + verify(start2).start(); + verify(start2).stop(); + } + + @Test + public void testStart() throws Exception { + Startable start1 = mock(Startable.class); + svcmgr.addService("test start", start1); + + svcmgr.start(); + verify(start1).start(); + verify(start1, never()).stop(); + + // cannot re-start + assertThatIllegalStateException().isThrownBy(() -> svcmgr.start()) + .withMessage(ALREADY_RUNNING); + + // verify that it didn't try to start the service again + verify(start1).start(); + } + + @Test + public void testStart_Ex() { + Startable start1 = mock(Startable.class); + svcmgr.addService("test start ex", start1); + + Startable start2 = mock(Startable.class); + svcmgr.addService("second test start ex", start2); + + // this one will throw an exception + Startable start3 = mock(Startable.class); + RuntimeException exception = new RuntimeException(EXPECTED_EXCEPTION); + when(start3.start()).thenThrow(exception); + svcmgr.addService("third test start ex", start3); + + Startable start4 = mock(Startable.class); + svcmgr.addService("fourth test start ex", start4); + + Startable start5 = mock(Startable.class); + svcmgr.addService("fifth test start ex", start5); + + assertThatThrownBy(() -> svcmgr.start()).isInstanceOf(ServiceManagerException.class).hasCause(exception); + + verify(start1).start(); + verify(start2).start(); + verify(start3).start(); + verify(start4, never()).start(); + verify(start5, never()).start(); + + verify(start1).stop(); + verify(start2).stop(); + verify(start3, never()).stop(); + verify(start4, never()).stop(); + verify(start5, never()).stop(); + } + + @Test + public void testStart_RewindEx() { + Startable start1 = mock(Startable.class); + svcmgr.addService("test start rewind", start1); + + // this one will throw an exception during rewind + Startable start2 = mock(Startable.class); + RuntimeException exception2 = new RuntimeException(EXPECTED_EXCEPTION); + when(start2.stop()).thenThrow(exception2); + svcmgr.addService("second test start rewind", start2); + + // this one will throw an exception + Startable start3 = mock(Startable.class); + RuntimeException exception = new RuntimeException(EXPECTED_EXCEPTION); + when(start3.start()).thenThrow(exception); + svcmgr.addService("third test start rewind", start3); + + Startable start4 = mock(Startable.class); + svcmgr.addService("fourth test start rewind", start4); + + Startable start5 = mock(Startable.class); + svcmgr.addService("fifth test start rewind", start5); + + assertThatThrownBy(() -> svcmgr.start()).isInstanceOf(ServiceManagerException.class).hasCause(exception); + } + + @Test + public void testStop() throws Exception { + Startable start1 = mock(Startable.class); + svcmgr.addService("first stop", start1); + + // cannot stop until started + assertThatIllegalStateException().isThrownBy(() -> svcmgr.stop()) + .withMessage("services are not running"); + + // verify that it didn't try to stop the service + verify(start1, never()).stop(); + + // start it + svcmgr.start(); + + svcmgr.stop(); + verify(start1).stop(); + } + + @Test + public void testStop_Ex() throws Exception { + RunnableWithEx start1 = mock(RunnableWithEx.class); + RunnableWithEx stop1 = mock(RunnableWithEx.class); + svcmgr.addAction("first stop ex", start1, stop1); + + Startable start2 = mock(Startable.class); + svcmgr.addService("second stop ex", start2); + + svcmgr.start(); + verify(start1).run(); + verify(stop1, never()).run(); + verify(start2).start(); + verify(start2, never()).stop(); + + svcmgr.stop(); + verify(start1).run(); + verify(stop1).run(); + verify(start2).start(); + verify(start2).stop(); + } + + @Test + public void testRewind() throws Exception { + RunnableWithEx starter = mock(RunnableWithEx.class); + LinkedList lst = new LinkedList<>(); + + svcmgr.addAction("first rewind", starter, () -> lst.add("rewind1")); + svcmgr.addAction("second rewind", starter, () -> lst.add("rewind2")); + + // this one will throw an exception during rewind + RuntimeException exception = new RuntimeException(EXPECTED_EXCEPTION); + svcmgr.addAction("third rewind", starter, () -> { + lst.add("rewind3"); + throw exception; + }); + + svcmgr.addAction("fourth rewind", starter, () -> lst.add("rewind4")); + svcmgr.addAction("fifth rewind", starter, () -> lst.add("rewind5")); + + svcmgr.start(); + + assertThatThrownBy(() -> svcmgr.stop()).isInstanceOf(ServiceManagerException.class).hasCause(exception); + + // all of them should have been stopped, in reverse order + assertEquals(Arrays.asList("rewind5", "rewind4", "rewind3", "rewind2", "rewind1").toString(), lst.toString()); + } + +} -- cgit 1.2.3-korg