aboutsummaryrefslogtreecommitdiffstats
path: root/feature-session-persistence/src/test/java/org/onap/policy/drools/persistence/PersistenceFeatureTest.java
diff options
context:
space:
mode:
Diffstat (limited to 'feature-session-persistence/src/test/java/org/onap/policy/drools/persistence/PersistenceFeatureTest.java')
-rw-r--r--feature-session-persistence/src/test/java/org/onap/policy/drools/persistence/PersistenceFeatureTest.java1291
1 files changed, 1291 insertions, 0 deletions
diff --git a/feature-session-persistence/src/test/java/org/onap/policy/drools/persistence/PersistenceFeatureTest.java b/feature-session-persistence/src/test/java/org/onap/policy/drools/persistence/PersistenceFeatureTest.java
new file mode 100644
index 00000000..e73031dd
--- /dev/null
+++ b/feature-session-persistence/src/test/java/org/onap/policy/drools/persistence/PersistenceFeatureTest.java
@@ -0,0 +1,1291 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * feature-session-persistence
+ * ================================================================================
+ * Copyright (C) 2017 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.drools.persistence;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.net.UnknownHostException;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import javax.persistence.EntityManagerFactory;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.kie.api.KieBase;
+import org.kie.api.KieServices;
+import org.kie.api.persistence.jpa.KieStoreServices;
+import org.kie.api.runtime.Environment;
+import org.kie.api.runtime.EnvironmentName;
+import org.kie.api.runtime.KieContainer;
+import org.kie.api.runtime.KieSession;
+import org.kie.api.runtime.KieSessionConfiguration;
+import org.mockito.ArgumentCaptor;
+import org.onap.policy.drools.persistence.DroolsPersistenceProperties;
+import org.onap.policy.drools.persistence.DroolsSession;
+import org.onap.policy.drools.persistence.DroolsSessionConnector;
+import org.onap.policy.drools.persistence.PersistenceFeature;
+import org.onap.policy.drools.core.PolicyContainer;
+import org.onap.policy.drools.core.PolicySession;
+import org.onap.policy.drools.system.PolicyController;
+
+import bitronix.tm.BitronixTransactionManager;
+import bitronix.tm.Configuration;
+import bitronix.tm.resource.jdbc.PoolingDataSource;
+
+public class PersistenceFeatureTest {
+
+ private static final String JDBC_DATASRC = "fake.datasource";
+ private static final String JDBC_DRIVER = "fake.driver";
+ private static final String JDBC_URL = "fake.url";
+ private static final String JDBC_USER = "fake.user";
+ private static final String JDBC_PASSWD = "fake.password";
+ private static final String SRC_TEST_RESOURCES = "src/test/resources";
+
+ private static Properties stdprops;
+
+ private DroolsSessionConnector jpa;
+ private DroolsSession sess;
+ private PoolingDataSource pds;
+ private KieSession kiesess;
+ private Properties dsprops;
+ private EntityManagerFactory emf;
+ private Connection conn;
+ private Properties props;
+ private KieServices kiesvc;
+ private Environment kieenv;
+ private KieSessionConfiguration kiecfg;
+ private KieBase kiebase;
+ private KieStoreServices kiestore;
+ private KieContainer kiecont;
+ private Configuration bitcfg;
+ private BitronixTransactionManager bittrans;
+ private PolicyController polctlr;
+ private PolicyContainer polcont;
+ private PolicySession polsess;
+ private PersistenceFeature.Factory fact;
+
+ private PersistenceFeature feat;
+
+
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ stdprops = new Properties();
+
+ stdprops.put(DroolsPersistenceProperties.DB_DATA_SOURCE, JDBC_DATASRC);
+ stdprops.put(DroolsPersistenceProperties.DB_DRIVER, JDBC_DRIVER);
+ stdprops.put(DroolsPersistenceProperties.DB_URL, JDBC_URL);
+ stdprops.put(DroolsPersistenceProperties.DB_USER, JDBC_USER);
+ stdprops.put(DroolsPersistenceProperties.DB_PWD, JDBC_PASSWD);
+ stdprops.put(DroolsPersistenceProperties.DB_SESSIONINFO_TIMEOUT, "50");
+ }
+
+ @AfterClass
+ public static void tearDownAfterClass() throws Exception {
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ jpa = mock(DroolsSessionConnector.class);
+ sess = mock(DroolsSession.class);
+ pds = mock(PoolingDataSource.class);
+ kiesess = mock(KieSession.class);
+ dsprops = new Properties();
+ emf = null;
+ conn = null;
+ props = new Properties();
+ kiesvc = mock(KieServices.class);
+ kieenv = mock(Environment.class);
+ kiecfg = mock(KieSessionConfiguration.class);
+ kiebase = mock(KieBase.class);
+ kiestore = mock(KieStoreServices.class);
+ kiecont = mock(KieContainer.class);
+ bitcfg = mock(Configuration.class);
+ bittrans = mock(BitronixTransactionManager.class);
+ polcont = mock(PolicyContainer.class);
+ polctlr = mock(PolicyController.class);
+ polsess = mock(PolicySession.class);
+ fact = mock(PersistenceFeature.Factory.class);
+
+ feat = new PersistenceFeature();
+ feat.setFactory(fact);
+
+ props.putAll(stdprops);
+
+ when(pds.getUniqueName()).thenReturn("myds");
+
+ when(fact.getKieServices()).thenReturn(kiesvc);
+ when(fact.getTransMgrConfig()).thenReturn(bitcfg);
+ when(fact.getTransMgr()).thenReturn(bittrans);
+ when(fact.loadProperties(anyString())).thenReturn(props);
+
+ when(kiesvc.newEnvironment()).thenReturn(kieenv);
+ when(kiesvc.getStoreServices()).thenReturn(kiestore);
+ when(kiesvc.newKieSessionConfiguration()).thenReturn(kiecfg);
+
+ when(polcont.getKieContainer()).thenReturn(kiecont);
+
+ when(polsess.getPolicyContainer()).thenReturn(polcont);
+
+ when(kiecont.getKieBase(anyString())).thenReturn(kiebase);
+ }
+
+ @After
+ public void tearDown() {
+ // this will cause the in-memory test DB to be dropped
+ if(conn != null) {
+ try { conn.close(); } catch (SQLException e) { }
+ }
+
+ if(emf != null) {
+ try { emf.close(); } catch (Exception e) { }
+ }
+ }
+
+ @Test
+ public void testGetContainerAdjunct_New() throws Exception {
+
+ feat.globalInit(null, SRC_TEST_RESOURCES);
+
+ mockDbConn(5);
+ setUpKie("myname", 999L, true);
+
+ // force getContainerAdjunct() to be invoked
+ feat.activatePolicySession(polcont, "myname", "mybase");
+
+ ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
+ ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
+
+ verify(polcont, times(1)).setAdjunct(any(), adjcap.capture());
+
+ assertNotNull( adjcap.getValue());
+ }
+
+ @Test
+ public void testGetContainerAdjunct_Existing() throws Exception {
+
+ feat.globalInit(null, SRC_TEST_RESOURCES);
+
+ mockDbConn(5);
+ setUpKie("myname", 999L, true);
+
+ // force getContainerAdjunct() to be invoked
+ feat.activatePolicySession(polcont, "myname", "mybase");
+
+ ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
+ ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
+
+ verify(polcont, times(1)).setAdjunct(any(), adjcap.capture());
+
+ // return adjunct on next call
+ when(polcont.getAdjunct(any())).thenReturn( adjcap.getValue());
+
+ // force getContainerAdjunct() to be invoked again
+ setUpKie("myname2", 999L, true);
+ feat.activatePolicySession(polcont, "myname2", "mybase");
+
+ // ensure it isn't invoked again
+ verify(polcont, times(1)).setAdjunct(any(), any());
+ }
+
+ @Test
+ public void testGetSequenceNumber() {
+ assertEquals(1, feat.getSequenceNumber());
+ }
+
+ @Test
+ public void testGlobalInit() throws Exception {
+ when(fact.getHostName()).thenReturn("myhost");
+
+ feat.globalInit(null, SRC_TEST_RESOURCES);
+
+ // verify that various factory methods were invoked
+ verify(fact).getHostName();
+ verify(fact).getKieServices();
+ verify(fact).getTransMgrConfig();
+ verify(fact).loadProperties("src/test/resources/feature-session-persistence.properties");
+
+ verify(bitcfg).setJournal(null);
+ verify(bitcfg).setServerId("myhost");
+ }
+
+ @Test
+ public void testActivatePolicySession() throws Exception {
+ PreparedStatement ps = mockDbConn(5);
+ setUpKie("myname", 999L, true);
+
+ feat.globalInit(null, SRC_TEST_RESOURCES);
+ feat.beforeActivate(null);
+
+ KieSession s =
+ feat.activatePolicySession(polcont, "myname", "mybase");
+
+ verify(kiestore).loadKieSession(anyLong(), any(), any(), any());
+ verify(kiestore, never()).newKieSession(any(), any(), any());
+
+ assertEquals(s, kiesess);
+
+ verify(ps).executeUpdate();
+
+ verify(kieenv, times(2)).set(anyString(), any());
+ verify(pds).init();
+ assertFalse( dsprops.isEmpty());
+
+ verify(jpa).get("myname");
+ verify(jpa).replace(any());
+ }
+
+ @Test
+ public void testActivatePolicySession_NoPersistence() throws Exception {
+ feat.globalInit(null, SRC_TEST_RESOURCES);
+
+ PreparedStatement ps = mockDbConn(5);
+ setUpKie("myname", 999L, true);
+
+ props.remove("persistence.type");
+
+ feat.beforeStart(null);
+
+ assertNull( feat.activatePolicySession(polcont, "myname", "mybase"));
+
+ verify(ps, never()).executeUpdate();
+ verify(kiestore, never()).loadKieSession(anyLong(), any(), any(), any());
+ verify(kiestore, never()).newKieSession(any(), any(), any());
+ }
+
+ /**
+ * Verifies that a new KIE session is created when there is no existing
+ * session entity.
+ */
+ @Test
+ public void testActivatePolicySession_New() throws Exception {
+ feat.globalInit(null, SRC_TEST_RESOURCES);
+
+ mockDbConn(5);
+ setUpKie("noName", 999L, true);
+
+
+ KieSession s =
+ feat.activatePolicySession(polcont, "myname", "mybase");
+
+ verify(kiestore, never()).loadKieSession(anyLong(), any(), any(), any());
+ verify(kiestore).newKieSession(any(), any(), any());
+
+ assertEquals(s, kiesess);
+
+ verify(kieenv, times(2)).set(anyString(), any());
+ verify(pds).init();
+ assertFalse( dsprops.isEmpty());
+
+ verify(jpa).get("myname");
+ verify(jpa).replace(any());
+ }
+
+ /**
+ * Verifies that a new KIE session is created when there KIE fails
+ * to load an existing session.
+ */
+ @Test
+ public void testActivatePolicySession_LoadFailed() throws Exception {
+ feat.globalInit(null, SRC_TEST_RESOURCES);
+
+ mockDbConn(5);
+ setUpKie("myname", 999L, false);
+
+
+ KieSession s =
+ feat.activatePolicySession(polcont, "myname", "mybase");
+
+ verify(kiestore).loadKieSession(anyLong(), any(), any(), any());
+ verify(kiestore).newKieSession(any(), any(), any());
+
+ assertEquals(s, kiesess);
+
+ verify(kieenv, times(2)).set(anyString(), any());
+ verify(pds).init();
+ assertFalse( dsprops.isEmpty());
+
+ verify(jpa).get("myname");
+
+ ArgumentCaptor<DroolsSession> d =
+ ArgumentCaptor.forClass(DroolsSession.class);
+ verify(jpa).replace( d.capture());
+
+ assertEquals("myname", d.getValue().getSessionName());
+ assertEquals(100L, d.getValue().getSessionId());
+ }
+
+ @Test
+ public void testConfigureKieEnv() throws Exception {
+ feat.globalInit(null, SRC_TEST_RESOURCES);
+
+ mockDbConn(5);
+ setUpKie("myname", 999L, false);
+
+ feat.activatePolicySession(polcont, "myname", "mybase");
+
+ verify(kieenv, times(2)).set(any(), any());
+
+ verify(kieenv).set(EnvironmentName.ENTITY_MANAGER_FACTORY, emf);
+ verify(kieenv).set(EnvironmentName.TRANSACTION_MANAGER, bittrans);
+ }
+
+ @Test
+ public void testInitDataSource() throws Exception {
+ feat.globalInit(null, SRC_TEST_RESOURCES);
+
+ mockDbConn(5);
+ setUpKie("myname", 999L, false);
+
+ feat.activatePolicySession(polcont, "myname", "mybase");
+
+ assertEquals(JDBC_URL, dsprops.getProperty("URL"));
+ assertEquals(JDBC_USER, dsprops.getProperty("user"));
+ assertEquals(JDBC_PASSWD, dsprops.getProperty("password"));
+
+ verify(pds).setUniqueName("jdbc/BitronixJTADataSource/myname");
+ verify(pds).setClassName(JDBC_DATASRC);
+ verify(pds).setMaxPoolSize(anyInt());
+ verify(pds).setIsolationLevel("SERIALIZABLE");
+ verify(pds).setAllowLocalTransactions(true);
+ verify(pds).init();
+ }
+
+ @Test
+ public void testLoadKieSession() throws Exception {
+ feat.globalInit(null, SRC_TEST_RESOURCES);
+
+ mockDbConn(5);
+ setUpKie("myname", 999L, true);
+
+
+ KieSession s =
+ feat.activatePolicySession(polcont, "myname", "mybase");
+
+ verify(kiestore).loadKieSession(999L, kiebase, kiecfg, kieenv);
+ verify(kiestore, never()).newKieSession(any(), any(), any());
+
+ assertEquals(s, kiesess);
+ }
+
+ /*
+ * Verifies that loadKieSession() returns null (thus causing newKieSession()
+ * to be called) when an Exception occurs.
+ */
+ @Test
+ public void testLoadKieSession_Ex() throws Exception {
+ feat.globalInit(null, SRC_TEST_RESOURCES);
+
+ mockDbConn(5);
+ setUpKie("myname", 999L, false);
+
+ when(kiestore.loadKieSession(anyLong(), any(), any(), any()))
+ .thenThrow( new RuntimeException("expected exception"));
+
+
+ KieSession s =
+ feat.activatePolicySession(polcont, "myname", "mybase");
+
+ verify(kiestore).loadKieSession(anyLong(), any(), any(), any());
+ verify(kiestore).newKieSession(any(), any(), any());
+
+ assertEquals(s, kiesess);
+ }
+
+ @Test
+ public void testNewKieSession() throws Exception {
+ feat.globalInit(null, SRC_TEST_RESOURCES);
+
+ mockDbConn(5);
+ setUpKie("myname", 999L, false);
+
+
+ KieSession s =
+ feat.activatePolicySession(polcont, "myname", "mybase");
+
+ verify(kiestore).newKieSession(kiebase, null, kieenv);
+
+ assertEquals(s, kiesess);
+ }
+
+ @Test
+ public void testLoadDataSource_RepeatSameSession() throws Exception {
+ feat.globalInit(null, SRC_TEST_RESOURCES);
+
+ mockDbConn(5);
+ setUpKie("myname", 999L, false);
+
+ feat.activatePolicySession(polcont, "myname", "mybase");
+
+ ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
+ ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
+
+ verify(polcont).setAdjunct(any(), adjcap.capture());
+
+ when(polcont.getAdjunct(any())).thenReturn( adjcap.getValue());
+
+ // invoke it again
+ feat.activatePolicySession(polcont, "myname", "mybase");
+
+ verify(fact, times(1)).makePoolingDataSource();
+ }
+
+ @Test
+ public void testLoadDataSource_DiffSession() throws Exception {
+ feat.globalInit(null, SRC_TEST_RESOURCES);
+
+ mockDbConn(5);
+ setUpKie("myname", 999L, false);
+ feat.activatePolicySession(polcont, "myname", "mybase");
+
+ ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
+ ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
+
+ verify(polcont).setAdjunct(any(), adjcap.capture());
+
+ when(polcont.getAdjunct(any())).thenReturn( adjcap.getValue());
+
+ setUpKie("myname2", 999L, false);
+
+ // invoke it again
+ feat.activatePolicySession(polcont, "myname2", "mybase");
+
+ verify(fact, times(2)).makePoolingDataSource();
+ }
+
+ @Test
+ public void testDisposeKieSession() throws Exception {
+ feat.globalInit(null, SRC_TEST_RESOURCES);
+
+ ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
+ ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
+
+ mockDbConn(5);
+ setUpKie("myname", 999L, false);
+
+ feat.activatePolicySession(polcont, "myname", "mybase");
+
+ verify(pds, never()).close();
+ verify(polcont).setAdjunct(any(), adjcap.capture());
+
+ when(polcont.getAdjunct(any())).thenReturn( adjcap.getValue());
+
+ feat.disposeKieSession(polsess);
+
+ // call twice to ensure it isn't re-closed
+ feat.disposeKieSession(polsess);
+
+ verify(pds, times(1)).close();
+ }
+
+ @Test
+ public void testDisposeKieSession_NoAdjunct() throws Exception {
+ feat.globalInit(null, SRC_TEST_RESOURCES);
+
+ feat.disposeKieSession(polsess);
+ }
+
+ @Test
+ public void testDisposeKieSession_NoPersistence() throws Exception {
+ feat.globalInit(null, SRC_TEST_RESOURCES);
+
+ ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
+ ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
+
+ mockDbConn(5);
+ setUpKie("myname", 999L, false);
+
+ feat.activatePolicySession(polcont, "myname", "mybase");
+
+ verify(pds, never()).close();
+ verify(polcont).setAdjunct(any(), adjcap.capture());
+
+ when(polcont.getAdjunct(any())).thenReturn( adjcap.getValue());
+
+ // specify a session that was never loaded
+ when(polsess.getName()).thenReturn("anotherName");
+
+ feat.disposeKieSession(polsess);
+
+ verify(pds, never()).close();
+ }
+
+ @Test
+ public void testDestroyKieSession() throws Exception {
+ feat.globalInit(null, SRC_TEST_RESOURCES);
+
+ ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
+ ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
+
+ mockDbConn(5);
+ setUpKie("myname", 999L, false);
+
+ feat.activatePolicySession(polcont, "myname", "mybase");
+
+ verify(pds, never()).close();
+ verify(polcont).setAdjunct(any(), adjcap.capture());
+
+ when(polcont.getAdjunct(any())).thenReturn( adjcap.getValue());
+
+ feat.destroyKieSession(polsess);
+
+ // call twice to ensure it isn't re-closed
+ feat.destroyKieSession(polsess);
+
+ verify(pds, times(1)).close();
+ }
+
+ @Test
+ public void testDestroyKieSession_NoAdjunct() throws Exception {
+ feat.globalInit(null, SRC_TEST_RESOURCES);
+
+ feat.destroyKieSession(polsess);
+ }
+
+ @Test
+ public void testDestroyKieSession_NoPersistence() throws Exception {
+ feat.globalInit(null, SRC_TEST_RESOURCES);
+
+ ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
+ ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
+
+ mockDbConn(5);
+ setUpKie("myname", 999L, false);
+
+ feat.activatePolicySession(polcont, "myname", "mybase");
+
+ verify(pds, never()).close();
+ verify(polcont).setAdjunct(any(), adjcap.capture());
+
+ when(polcont.getAdjunct(any())).thenReturn( adjcap.getValue());
+
+ // specify a session that was never loaded
+ when(polsess.getName()).thenReturn("anotherName");
+
+ feat.destroyKieSession(polsess);
+
+ verify(pds, never()).close();
+ }
+
+ @Test
+ public void testAfterStart() {
+ assertFalse( feat.afterStart(null));
+ }
+
+ @Test
+ public void testBeforeStart() {
+ assertFalse( feat.beforeStart(null));
+ }
+
+ @Test
+ public void testBeforeShutdown() {
+ assertFalse( feat.beforeShutdown(null));
+ }
+
+ @Test
+ public void testAfterShutdown() {
+ assertFalse( feat.afterShutdown(null));
+ }
+
+ @Test
+ public void testBeforeConfigure() {
+ assertFalse( feat.beforeConfigure(null, null));
+ }
+
+ @Test
+ public void testAfterConfigure() {
+ assertFalse( feat.afterConfigure(null));
+ }
+
+ @Test
+ public void testBeforeActivate() {
+ assertFalse( feat.beforeActivate(null));
+ }
+
+ @Test
+ public void testAfterActivate() {
+ assertFalse( feat.afterActivate(null));
+ }
+
+ @Test
+ public void testBeforeDeactivate() {
+ assertFalse( feat.beforeDeactivate(null));
+ }
+
+ @Test
+ public void testAfterDeactivate() {
+ assertFalse( feat.afterDeactivate(null));
+ }
+
+ @Test
+ public void testBeforeStop() {
+ assertFalse( feat.beforeStop(null));
+ }
+
+ @Test
+ public void testAfterStop() {
+ assertFalse( feat.afterStop(null));
+ }
+
+ @Test
+ public void testBeforeLock() {
+ assertFalse( feat.beforeLock(null));
+ }
+
+ @Test
+ public void testAfterLock() {
+ assertFalse( feat.afterLock(null));
+ }
+
+ @Test
+ public void testBeforeUnlock() {
+ assertFalse( feat.beforeUnlock(null));
+ }
+
+ @Test
+ public void testAfterUnlock() {
+ assertFalse( feat.afterUnlock(null));
+ }
+
+ @Test
+ public void testGetPersistenceTimeout_Valid() throws Exception {
+ PreparedStatement s = mockDbConn(5);
+
+ feat.globalInit(null, SRC_TEST_RESOURCES);
+
+ setUpKie("myname", 999L, true);
+
+ feat.activatePolicySession(polcont, "myname", "mybase");
+
+ verify(s).executeUpdate();
+ }
+
+ @Test
+ public void testGetPersistenceTimeout_Missing() throws Exception {
+
+ props.remove(DroolsPersistenceProperties.DB_SESSIONINFO_TIMEOUT);
+
+ PreparedStatement s = mockDbConn(0);
+
+ feat.globalInit(null, SRC_TEST_RESOURCES);
+
+ setUpKie("myname", 999L, true);
+
+ feat.activatePolicySession(polcont, "myname", "mybase");
+
+ verify(s, never()).executeUpdate();
+ }
+
+ @Test
+ public void testGetPersistenceTimeout_Invalid() throws Exception {
+ props.setProperty(DroolsPersistenceProperties.DB_SESSIONINFO_TIMEOUT, "abc");
+ PreparedStatement s = mockDbConn(0);
+
+ feat.globalInit(null, SRC_TEST_RESOURCES);
+
+ setUpKie("myname", 999L, true);
+
+ feat.activatePolicySession(polcont, "myname", "mybase");
+
+ verify(s, never()).executeUpdate();
+ }
+
+ @Test
+ public void testInitHostName() throws Exception {
+ when(fact.getHostName()).thenReturn("myhost");
+
+ feat.globalInit(null, SRC_TEST_RESOURCES);
+
+ verify(bitcfg).setServerId("myhost");
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testInitHostName_Ex() throws Exception {
+ when(fact.getHostName())
+ .thenThrow(
+ new UnknownHostException("expected exception"));
+
+ feat.globalInit(null, SRC_TEST_RESOURCES);
+ }
+
+ @Test
+ public void testCleanUpSessionInfo() throws Exception {
+ setUpKie("myname", 999L, true);
+
+ // use a real DB so we can verify that the "delete" works correctly
+ fact = new PartialFactory();
+ feat.setFactory(fact);
+
+ makeSessionInfoTbl(20000);
+
+
+ feat.globalInit(null, SRC_TEST_RESOURCES);
+
+ feat.beforeStart(null);
+ feat.activatePolicySession(polcont, "myname", "mybase");
+
+ assertEquals("[1, 4, 5]", getSessions().toString());
+ }
+
+ @Test
+ public void testCleanUpSessionInfo_WithBeforeStart() throws Exception {
+ PreparedStatement s = mockDbConn(0);
+
+ feat.globalInit(null, SRC_TEST_RESOURCES);
+
+ setUpKie("myname", 999L, true);
+
+ // reset
+ feat.beforeStart(null);
+
+ feat.activatePolicySession(polcont, "myname", "mybase");
+ verify(s, times(1)).executeUpdate();
+
+ // should not clean-up again
+ feat.activatePolicySession(polcont, "myname", "mybase");
+ feat.activatePolicySession(polcont, "myname", "mybase");
+ verify(s, times(1)).executeUpdate();
+
+
+ // reset
+ feat.beforeStart(null);
+
+ feat.activatePolicySession(polcont, "myname", "mybase");
+ verify(s, times(2)).executeUpdate();
+
+ // should not clean-up again
+ feat.activatePolicySession(polcont, "myname", "mybase");
+ feat.activatePolicySession(polcont, "myname", "mybase");
+ verify(s, times(2)).executeUpdate();
+ }
+
+ @Test
+ public void testCleanUpSessionInfo_WithBeforeActivate() throws Exception {
+ PreparedStatement s = mockDbConn(0);
+
+ feat.globalInit(null, SRC_TEST_RESOURCES);
+
+ setUpKie("myname", 999L, true);
+
+ // reset
+ feat.beforeActivate(null);
+
+ feat.activatePolicySession(polcont, "myname", "mybase");
+ verify(s, times(1)).executeUpdate();
+
+ // should not clean-up again
+ feat.activatePolicySession(polcont, "myname", "mybase");
+ feat.activatePolicySession(polcont, "myname", "mybase");
+ verify(s, times(1)).executeUpdate();
+
+
+ // reset
+ feat.beforeActivate(null);
+
+ feat.activatePolicySession(polcont, "myname", "mybase");
+ verify(s, times(2)).executeUpdate();
+
+ // should not clean-up again
+ feat.activatePolicySession(polcont, "myname", "mybase");
+ feat.activatePolicySession(polcont, "myname", "mybase");
+ verify(s, times(2)).executeUpdate();
+ }
+
+ @Test
+ public void testCleanUpSessionInfo_NoTimeout() throws Exception {
+
+ props.remove(DroolsPersistenceProperties.DB_SESSIONINFO_TIMEOUT);
+
+ PreparedStatement s = mockDbConn(0);
+
+ feat.globalInit(null, SRC_TEST_RESOURCES);
+
+ setUpKie("myname", 999L, true);
+
+ feat.activatePolicySession(polcont, "myname", "mybase");
+
+ verify(s, never()).executeUpdate();
+ }
+
+ @Test
+ public void testCleanUpSessionInfo_NoUrl() throws Exception {
+ PreparedStatement s = mockDbConn(0);
+
+ props.remove(DroolsPersistenceProperties.DB_URL);
+
+ feat.globalInit(null, SRC_TEST_RESOURCES);
+
+ setUpKie("myname", 999L, true);
+
+ feat.activatePolicySession(polcont, "myname", "mybase");
+
+ verify(s, never()).executeUpdate();
+ }
+
+ @Test
+ public void testCleanUpSessionInfo_NoUser() throws Exception {
+ PreparedStatement s = mockDbConn(0);
+
+ props.remove(DroolsPersistenceProperties.DB_USER);
+
+ feat.globalInit(null, SRC_TEST_RESOURCES);
+
+ setUpKie("myname", 999L, true);
+
+ feat.activatePolicySession(polcont, "myname", "mybase");
+
+ verify(s, never()).executeUpdate();
+ }
+
+ @Test
+ public void testCleanUpSessionInfo_NoPassword() throws Exception {
+ PreparedStatement s = mockDbConn(0);
+
+ props.remove(DroolsPersistenceProperties.DB_PWD);
+
+ feat.globalInit(null, SRC_TEST_RESOURCES);
+
+ setUpKie("myname", 999L, true);
+
+ feat.activatePolicySession(polcont, "myname", "mybase");
+
+ verify(s, never()).executeUpdate();
+ }
+
+ @Test
+ public void testCleanUpSessionInfo_SqlEx() throws Exception {
+ PreparedStatement s = mockDbConn(-1);
+
+ feat.globalInit(null, SRC_TEST_RESOURCES);
+
+ setUpKie("myname", 999L, true);
+
+ feat.activatePolicySession(polcont, "myname", "mybase");
+
+ verify(s).executeUpdate();
+ }
+
+ @Test
+ public void testGetDroolsSessionConnector() throws Exception {
+ feat.globalInit(null, SRC_TEST_RESOURCES);
+
+ mockDbConn(5);
+ setUpKie("myname", 999L, true);
+
+
+ feat.activatePolicySession(polcont, "myname", "mybase");
+
+
+ ArgumentCaptor<Properties> propcap =
+ ArgumentCaptor.forClass(Properties.class);
+
+ verify(fact).makeJpaConnector(anyString(), propcap.capture());
+
+ Properties p = propcap.getValue();
+ assertNotNull(p);
+
+ assertEquals(JDBC_DRIVER,
+ p.getProperty("javax.persistence.jdbc.driver"));
+
+ assertEquals(JDBC_URL,
+ p.getProperty("javax.persistence.jdbc.url"));
+
+ assertEquals(JDBC_USER,
+ p.getProperty("javax.persistence.jdbc.user"));
+
+ assertEquals(JDBC_PASSWD,
+ p.getProperty("javax.persistence.jdbc.password"));
+ }
+
+ @Test
+ public void testReplaceSession() throws Exception {
+ feat.globalInit(null, SRC_TEST_RESOURCES);
+
+ ArgumentCaptor<DroolsSession> sesscap =
+ ArgumentCaptor.forClass(DroolsSession.class);
+
+ mockDbConn(5);
+ setUpKie("myname", 999L, true);
+
+
+ feat.activatePolicySession(polcont, "myname", "mybase");
+
+ verify(jpa).replace( sesscap.capture());
+
+ assertEquals("myname", sesscap.getValue().getSessionName());
+ assertEquals(999L, sesscap.getValue().getSessionId());
+ }
+
+ @Test
+ public void testIsPersistenceEnabled_Auto() throws Exception {
+ feat.globalInit(null, SRC_TEST_RESOURCES);
+
+ mockDbConn(5);
+ setUpKie("myname", 999L, true);
+
+ props.setProperty("persistence.type", "auto");
+
+ assertNotNull( feat.activatePolicySession(polcont, "myname", "mybase"));
+ }
+
+ @Test
+ public void testIsPersistenceEnabled_Native() throws Exception {
+ feat.globalInit(null, SRC_TEST_RESOURCES);
+
+ mockDbConn(5);
+ setUpKie("myname", 999L, true);
+
+ props.setProperty("persistence.type", "native");
+
+ assertNotNull( feat.activatePolicySession(polcont, "myname", "mybase"));
+ }
+
+ @Test
+ public void testIsPersistenceEnabled_None() throws Exception {
+ feat.globalInit(null, SRC_TEST_RESOURCES);
+
+ mockDbConn(5);
+ setUpKie("myname", 999L, true);
+
+ props.remove("persistence.type");
+
+ assertNull( feat.activatePolicySession(polcont, "myname", "mybase"));
+ }
+
+ @Test
+ public void testGetProperties_Ex() throws Exception {
+ feat.globalInit(null, SRC_TEST_RESOURCES);
+
+ mockDbConn(5);
+ setUpKie("myname", 999L, true);
+
+ when(fact.getPolicyContainer(polcont))
+ .thenThrow( new IllegalArgumentException("expected exception"));
+
+ assertNull( feat.activatePolicySession(polcont, "myname", "mybase"));
+ }
+
+ @Test
+ public void testGetProperty_Specific() throws Exception {
+ feat.globalInit(null, SRC_TEST_RESOURCES);
+
+ mockDbConn(5);
+ setUpKie("myname", 999L, true);
+
+ props.remove("persistence.type");
+ props.setProperty("persistence.myname.type", "auto");
+
+ assertNotNull( feat.activatePolicySession(polcont, "myname", "mybase"));
+ }
+
+ @Test
+ public void testGetProperty_Specific_None() throws Exception {
+ feat.globalInit(null, SRC_TEST_RESOURCES);
+
+ mockDbConn(5);
+ setUpKie("myname", 999L, true);
+
+ props.remove("persistence.type");
+ props.setProperty("persistence.xxx.type", "auto");
+
+ assertNull( feat.activatePolicySession(polcont, "myname", "mybase"));
+ }
+
+ @Test
+ public void testGetProperty_Both_SpecificOn() throws Exception {
+ feat.globalInit(null, SRC_TEST_RESOURCES);
+
+ mockDbConn(5);
+ setUpKie("myname", 999L, true);
+
+ props.setProperty("persistence.type", "other");
+ props.setProperty("persistence.myname.type", "auto");
+
+ assertNotNull( feat.activatePolicySession(polcont, "myname", "mybase"));
+ }
+
+ @Test
+ public void testGetProperty_Both_SpecificDisabledOff() throws Exception {
+ feat.globalInit(null, SRC_TEST_RESOURCES);
+
+ mockDbConn(5);
+ setUpKie("myname", 999L, true);
+
+ props.setProperty("persistence.type", "auto");
+ props.setProperty("persistence.myname.type", "other");
+
+ assertNull( feat.activatePolicySession(polcont, "myname", "mybase"));
+ }
+
+ @Test
+ public void testGetProperty_None() throws Exception {
+ feat.globalInit(null, SRC_TEST_RESOURCES);
+
+ mockDbConn(5);
+ setUpKie("myname", 999L, true);
+
+ props.remove("persistence.type");
+
+ assertNull( feat.activatePolicySession(polcont, "myname", "mybase"));
+ }
+
+
+ /**
+ * Gets an ordered list of ids of the current SessionInfo records.
+ * @return ordered list of SessInfo IDs
+ * @throws SQLException
+ * @throws IOException
+ */
+ private List<Integer> getSessions() throws SQLException, IOException {
+ attachDb();
+
+ ArrayList<Integer> lst = new ArrayList<>(5);
+
+ try(
+ PreparedStatement stmt = conn.prepareStatement("SELECT id from sessioninfo order by id");
+ ResultSet rs = stmt.executeQuery()) {
+
+ while(rs.next()) {
+ lst.add( rs.getInt(1));
+ }
+ }
+
+ return lst;
+ }
+
+ /**
+ * Sets up for doing invoking the newKieSession() method.
+ * @param sessnm name to which JPA should respond with a session
+ * @param sessid session id to be returned by the session
+ * @param loadOk {@code true} if loadKieSession() should return a
+ * value, {@code false} to return null
+ */
+ private void setUpKie(String sessnm, long sessid, boolean loadOk) {
+
+ when(fact.makeJpaConnector(any(), any())).thenReturn(jpa);
+ when(fact.makePoolingDataSource()).thenReturn(pds);
+ when(fact.getPolicyContainer(polcont)).thenReturn(polctlr);
+
+ props.setProperty("persistence.type", "auto");
+
+ when(polctlr.getProperties()).thenReturn(props);
+
+ when(jpa.get(sessnm)).thenReturn(sess);
+
+ when(pds.getDriverProperties()).thenReturn(dsprops);
+
+ when(sess.getSessionId()).thenReturn(sessid);
+
+ when(polsess.getPolicyContainer()).thenReturn(polcont);
+ when(polsess.getName()).thenReturn(sessnm);
+
+ if(loadOk) {
+ when(kiesess.getIdentifier()).thenReturn(sessid);
+ when(kiestore.loadKieSession(anyLong(), any(), any(), any()))
+ .thenReturn(kiesess);
+
+ } else {
+ // use an alternate id for the new session
+ when(kiesess.getIdentifier()).thenReturn(100L);
+ when(kiestore.loadKieSession(anyLong(), any(), any(), any()))
+ .thenReturn(null);
+ }
+
+ when(kiestore.newKieSession(any(), any(), any())).thenReturn(kiesess);
+ }
+
+ /**
+ * Creates the SessionInfo DB table and populates it with some data.
+ * @param expMs number of milli-seconds for expired sessioninfo records
+ * @throws SQLException
+ * @throws IOException
+ */
+ private void makeSessionInfoTbl(int expMs)
+ throws SQLException, IOException {
+
+ attachDb();
+
+ try(
+ PreparedStatement stmt = conn.prepareStatement(
+ "CREATE TABLE sessioninfo(id int, lastmodificationdate timestamp)")) {
+
+ stmt.executeUpdate();
+ }
+
+ try(
+ PreparedStatement stmt = conn.prepareStatement(
+ "INSERT into sessioninfo(id, lastmodificationdate) values(?, ?)")) {
+
+ Timestamp ts;
+
+ // current data
+ ts = new Timestamp( System.currentTimeMillis());
+ stmt.setTimestamp(2, ts);
+
+ stmt.setInt(1, 1);
+ stmt.executeUpdate();
+
+ stmt.setInt(1, 4);
+ stmt.executeUpdate();
+
+ stmt.setInt(1, 5);
+ stmt.executeUpdate();
+
+ // expired data
+ ts = new Timestamp( System.currentTimeMillis() - expMs);
+ stmt.setTimestamp(2, ts);
+
+ stmt.setInt(1, 2);
+ stmt.executeUpdate();
+
+ stmt.setInt(1, 3);
+ stmt.executeUpdate();
+ }
+ }
+
+ /**
+ * Attaches {@link #conn} to the DB, if it isn't already attached.
+ * @throws SQLException
+ * @throws IOException if the property file cannot be read
+ */
+ private void attachDb() throws SQLException, IOException {
+ if(conn == null) {
+ Properties p = loadDbProps();
+
+ conn = DriverManager.getConnection(
+ p.getProperty(DroolsPersistenceProperties.DB_URL),
+ p.getProperty(DroolsPersistenceProperties.DB_USER),
+ p.getProperty(DroolsPersistenceProperties.DB_PWD));
+ conn.setAutoCommit(true);
+ }
+ }
+
+ /**
+ * Loads the DB properties from the file,
+ * <i>feature-session-persistence.properties</i>.
+ * @return the properties that were loaded
+ * @throws IOException if the property file cannot be read
+ * @throws FileNotFoundException if the property file does not exist
+ */
+ private Properties loadDbProps()
+ throws IOException, FileNotFoundException {
+
+ Properties p = new Properties();
+
+ try(FileReader rdr = new FileReader(
+ "src/test/resources/feature-session-persistence.properties")) {
+ p.load(rdr);
+ }
+
+ return p;
+ }
+
+ /**
+ * Create a mock DB connection and statement.
+ * @param retval value to be returned when the statement is executed,
+ * or negative to throw an exception
+ * @return the statement that will be returned by the connection
+ * @throws SQLException
+ */
+ private PreparedStatement mockDbConn(int retval) throws SQLException {
+ Connection c = mock(Connection.class);
+ PreparedStatement s = mock(PreparedStatement.class);
+
+ when(fact.makeDbConnection(anyString(), anyString(), anyString()))
+ .thenReturn(c);
+ when(c.prepareStatement(anyString())).thenReturn(s);
+
+ if(retval < 0) {
+ // should throw an exception
+ when(s.executeUpdate())
+ .thenThrow( new SQLException("expected exception"));
+
+ } else {
+ // should return the value
+ when(s.executeUpdate()).thenReturn(retval);
+ }
+
+ return s;
+ }
+
+ /**
+ * A partial factory, which exports a few of the real methods, but
+ * overrides the rest.
+ */
+ private class PartialFactory extends PersistenceFeature.Factory {
+
+ @Override
+ public PoolingDataSource makePoolingDataSource() {
+ return pds;
+ }
+
+ @Override
+ public KieServices getKieServices() {
+ return kiesvc;
+ }
+
+ @Override
+ public BitronixTransactionManager getTransMgr() {
+ return null;
+ }
+
+ @Override
+ public EntityManagerFactory makeEntMgrFact(String pu,
+ Properties propMap) {
+ if(pu.equals("onapsessionsPU")) {
+ return null;
+ }
+
+ return super.makeEntMgrFact("junitPersistenceFeaturePU", propMap);
+ }
+
+ @Override
+ public PolicyController getPolicyContainer(PolicyContainer container) {
+ return polctlr;
+ }
+
+ }
+}