From 51476711e73e003b9279f179939afad52e9af906 Mon Sep 17 00:00:00 2001 From: bobbymander Date: Thu, 8 Mar 2018 07:15:14 -0500 Subject: [PATCH] JUnit additions for BRMS,POLICY-SDK-APP Issue-ID: POLICY-598 Change-Id: Ic3d9ca2a5f6c29f772bd747612d6c7caeb15eb7f Signed-off-by: bobbymander --- .../onap/policy/brmsInterface/BRMSHandlerTest.java | 93 ++++++++++++++++++ .../PolicyExportAndImportControllerTest.java | 108 +++++++++++++++++++++ .../PolicyNotificationControllerTest.java | 74 ++++++++++++++ POLICY-SDK-APP/src/test/resources/PolicyExport.xls | Bin 0 -> 33792 bytes 4 files changed, 275 insertions(+) create mode 100644 BRMSGateway/src/test/java/org/onap/policy/brmsInterface/BRMSHandlerTest.java create mode 100644 POLICY-SDK-APP/src/test/java/org/onap/policy/controller/PolicyExportAndImportControllerTest.java create mode 100644 POLICY-SDK-APP/src/test/java/org/onap/policy/controller/PolicyNotificationControllerTest.java create mode 100644 POLICY-SDK-APP/src/test/resources/PolicyExport.xls diff --git a/BRMSGateway/src/test/java/org/onap/policy/brmsInterface/BRMSHandlerTest.java b/BRMSGateway/src/test/java/org/onap/policy/brmsInterface/BRMSHandlerTest.java new file mode 100644 index 000000000..8e15cdf28 --- /dev/null +++ b/BRMSGateway/src/test/java/org/onap/policy/brmsInterface/BRMSHandlerTest.java @@ -0,0 +1,93 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP Policy Engine + * ================================================================================ + * Copyright (C) 2018 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.brmsInterface; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.EntityTransaction; +import javax.persistence.Persistence; +import javax.persistence.Query; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.onap.policy.api.NotificationType; +import org.onap.policy.std.StdPDPNotification; +import org.onap.policy.utils.BackUpMonitor; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +@RunWith(PowerMockRunner.class) +public class BRMSHandlerTest { + @PrepareForTest({Persistence.class, BackUpMonitor.class}) + @Test + public void negativeTestNotifications() throws Exception { + // Mock emf, persistence, and query + EntityManagerFactory emf = Mockito.mock(EntityManagerFactory.class); + EntityManager em = Mockito.mock(EntityManager.class); + Mockito.when(emf.createEntityManager()).thenReturn(em); + PowerMockito.mockStatic(Persistence.class); + PowerMockito.when(Persistence.createEntityManagerFactory(any(), any())).thenReturn(emf); + EntityTransaction et = Mockito.mock(EntityTransaction.class); + Mockito.when(em.getTransaction()).thenReturn(et); + Query query = Mockito.mock(Query.class); + Mockito.when(em.createQuery(Mockito.anyString())).thenReturn(query); + + // Mock backup monitor + PowerMockito.mockStatic(BackUpMonitor.class); + BackUpMonitor monitor = Mockito.mock(BackUpMonitor.class); + PowerMockito.when(BackUpMonitor.getInstance(any(), any(), any(), any())).thenReturn(monitor); + + // Test constructor + StdPDPNotification notification = new StdPDPNotification(); + String propFile = "config.properties"; + BRMSHandler handler = new BRMSHandler(propFile); + BRMSPush brmsPush = new BRMSPush(propFile, handler); + handler.setBRMSPush(brmsPush); + assertNotNull(handler); + assertNotNull(brmsPush); + assertNull(handler.getPolicyEngine()); + + try { + // Test update + notification.setNotificationType(NotificationType.UPDATE); + handler.runOnNotification(notification); + handler.notificationReceived(notification); + + // Test remove + notification.setNotificationType(NotificationType.REMOVE); + handler.runOnNotification(notification); + handler.notificationReceived(notification); + + // Test both + notification.setNotificationType(NotificationType.BOTH); + handler.runOnNotification(notification); + handler.notificationReceived(notification); + } + catch (Exception ex) { + fail("Not expecting an exception: " + ex); + } + } +} diff --git a/POLICY-SDK-APP/src/test/java/org/onap/policy/controller/PolicyExportAndImportControllerTest.java b/POLICY-SDK-APP/src/test/java/org/onap/policy/controller/PolicyExportAndImportControllerTest.java new file mode 100644 index 000000000..358108fa1 --- /dev/null +++ b/POLICY-SDK-APP/src/test/java/org/onap/policy/controller/PolicyExportAndImportControllerTest.java @@ -0,0 +1,108 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP Policy Engine + * ================================================================================ + * Copyright (C) 2018 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.controller; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.mockito.Mockito.when; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import java.io.File; +import java.io.IOException; +import java.util.Collections; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.json.JSONObject; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.onap.policy.daoImp.CommonClassDaoImpl; +import org.onap.policy.rest.dao.CommonClassDao; +import org.onap.policy.rest.jpa.ConfigurationDataEntity; +import org.onap.policy.rest.jpa.UserInfo; +import org.onap.portalsdk.core.domain.User; +import org.onap.portalsdk.core.web.support.UserUtils; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import com.mockrunner.mock.web.MockHttpServletRequest; +import com.mockrunner.mock.web.MockHttpServletResponse; + +@RunWith(PowerMockRunner.class) +public class PolicyExportAndImportControllerTest { + @Test + public void testSetAndGet(){ + PolicyExportAndImportController controller = new PolicyExportAndImportController(); + PolicyController policyController = new PolicyController(); + controller.setPolicyController(policyController); + assertEquals(controller.getPolicyController(), policyController); + CommonClassDao commonClassDao = new CommonClassDaoImpl(); + PolicyExportAndImportController.setCommonClassDao(commonClassDao); + assertEquals(PolicyExportAndImportController.getCommonClassDao(), commonClassDao); + } + + @Test + public void testExport() throws IOException { + PolicyExportAndImportController controller = new PolicyExportAndImportController(); + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setBodyContent("{\n\"exportData\": {}\n}\n"); + MockHttpServletResponse response = new MockHttpServletResponse(); + + // Test negative case + controller.exportPolicy(request, response); + assertEquals(response.getStatusCode(), HttpServletResponse.SC_OK); + } + + @PrepareForTest({UserUtils.class}) + @Test + public void testImport() throws IOException { + // Mock user utilities + PowerMockito.mockStatic(UserUtils.class); + User user = new User(); + when(UserUtils.getUserSession(any())).thenReturn(user); + + // Mock dao + UserInfo info = new UserInfo(); + ConfigurationDataEntity configEntity = new ConfigurationDataEntity(); + CommonClassDao commonClassDao = Mockito.mock(CommonClassDaoImpl.class); + when(commonClassDao.getEntityItem(eq(UserInfo.class), any(), any())).thenReturn(info); + when(commonClassDao.getEntityItem(eq(ConfigurationDataEntity.class), any(), any())).thenReturn(configEntity); + when(commonClassDao.getDataById(any(), any(), any())).thenReturn(Collections.emptyList()); + + // Test import + ClassLoader classLoader = getClass().getClassLoader(); + PolicyController policyController = new PolicyController(); + PolicyController.setCommonClassDao(commonClassDao); + PolicyExportAndImportController controller = new PolicyExportAndImportController(); + PolicyExportAndImportController.setCommonClassDao(commonClassDao); + controller.setPolicyController(policyController); + HttpServletRequest request = new MockHttpServletRequest(); + + // Test negative case + String file = new File(classLoader.getResource("Config_BRMS_Raw_TestBRMSRawPolicy.1.xml").getFile()).getAbsolutePath(); + JSONObject json = controller.importRepositoryFile(file, request); + assertNull(json); + + // Another negative case + file = new File(classLoader.getResource("PolicyExport.xls").getFile()).getAbsolutePath(); + json = controller.importRepositoryFile(file, request); + assertNull(json); + } +} diff --git a/POLICY-SDK-APP/src/test/java/org/onap/policy/controller/PolicyNotificationControllerTest.java b/POLICY-SDK-APP/src/test/java/org/onap/policy/controller/PolicyNotificationControllerTest.java new file mode 100644 index 000000000..49249cad3 --- /dev/null +++ b/POLICY-SDK-APP/src/test/java/org/onap/policy/controller/PolicyNotificationControllerTest.java @@ -0,0 +1,74 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP Policy Engine + * ================================================================================ + * Copyright (C) 2018 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.controller; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.when; +import java.io.IOException; +import java.util.Collections; +import javax.servlet.http.HttpServletResponse; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.onap.policy.rest.dao.CommonClassDao; +import org.onap.portalsdk.core.domain.User; +import org.onap.portalsdk.core.web.support.UserUtils; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.springframework.web.servlet.ModelAndView; +import com.mockrunner.mock.web.MockHttpServletRequest; +import com.mockrunner.mock.web.MockHttpServletResponse; + +@RunWith(PowerMockRunner.class) +public class PolicyNotificationControllerTest { + @PrepareForTest({UserUtils.class}) + @Test + public void testWatch() throws IOException{ + // Mock user utilities + PowerMockito.mockStatic(UserUtils.class); + User user = new User(); + user.setOrgUserId("testID"); + when(UserUtils.getUserSession(any())).thenReturn(user); + + // Mock database + CommonClassDao dao = Mockito.mock(CommonClassDao.class); + Mockito.when(dao.getDataByQuery(any(), any())).thenReturn(Collections.emptyList()); + + // Test watch + PolicyNotificationController controller = new PolicyNotificationController(); + controller.commonClassDao = dao; + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setBodyContent("{\n\"watchData\": {\"name\": \"testVal\",\"path\": \"testPath\"\n}}\n"); + MockHttpServletResponse response = new MockHttpServletResponse(); + ModelAndView model = controller.watchPolicy(request, response); + assertNull(model); + assertEquals(response.getStatusCode(), HttpServletResponse.SC_OK); + + // Negative test watch + request.setBodyContent("{\n\"watchData\": {\"name\": \"testVal\",\"nopath\": \"testPath\"\n}}\n"); + response = new MockHttpServletResponse(); + model = controller.watchPolicy(request, response); + assertNull(model); + assertEquals(response.getStatusCode(), HttpServletResponse.SC_OK); + } +} diff --git a/POLICY-SDK-APP/src/test/resources/PolicyExport.xls b/POLICY-SDK-APP/src/test/resources/PolicyExport.xls new file mode 100644 index 0000000000000000000000000000000000000000..113432090cf24674ba32b26ee91e522cf20fe617 GIT binary patch literal 33792 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