diff options
Diffstat (limited to 'feature-session-persistence/src/test')
9 files changed, 2148 insertions, 0 deletions
diff --git a/feature-session-persistence/src/test/java/org/onap/policy/drools/persistence/DroolsSessionEntityTest.java b/feature-session-persistence/src/test/java/org/onap/policy/drools/persistence/DroolsSessionEntityTest.java new file mode 100644 index 00000000..c7fa8486 --- /dev/null +++ b/feature-session-persistence/src/test/java/org/onap/policy/drools/persistence/DroolsSessionEntityTest.java @@ -0,0 +1,198 @@ +/*- + * ============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.assertTrue; + +import java.util.Date; + +import org.junit.Test; +import org.onap.policy.drools.persistence.DroolsSessionEntity; + +public class DroolsSessionEntityTest { + + @Test + public void testHashCode() { + DroolsSessionEntity e = makeEnt("mynameA", 1); + + DroolsSessionEntity e2 = makeEnt("mynameA", 2); + + // session id is not part of hash code + assertTrue(e.hashCode() == e2.hashCode()); + + // diff sess name + e2 = makeEnt("mynameB", 1); + assertTrue(e.hashCode() != e2.hashCode()); + } + + /** + * Ensures that hashCode() functions as expected when the getXxx methods + * are overridden. + */ + @Test + public void testHashCode_Subclass() { + DroolsSessionEntity e = makeEnt2("mynameA", 1); + + DroolsSessionEntity e2 = makeEnt("mynameA", 2); + + // session id is not part of hash code + assertTrue(e.hashCode() == e2.hashCode()); + + // diff sess name + e2 = makeEnt("mynameB", 1); + assertTrue(e.hashCode() != e2.hashCode()); + } + + @Test + public void testGetSessionName_testSetSessionName() { + DroolsSessionEntity e = makeEnt("mynameZ", 1); + + assertEquals("mynameZ", e.getSessionName()); + + e.setSessionName("another"); + assertEquals("another", e.getSessionName()); + + // others unchanged + assertEquals(1, e.getSessionId()); + } + + @Test + public void testGetSessionId_testSetSessionId() { + DroolsSessionEntity e = makeEnt("mynameA", 1); + + assertEquals(1, e.getSessionId()); + + e.setSessionId(20); + assertEquals(20, e.getSessionId()); + + // others unchanged + assertEquals("mynameA", e.getSessionName()); + } + + @Test + public void testGetCreatedDate_testSetCreatedDate_testGetUpdatedDate_testSetUpdatedDate() { + DroolsSessionEntity e = new DroolsSessionEntity(); + + Date crtdt = new Date(System.currentTimeMillis() - 100); + e.setCreatedDate(crtdt); + + Date updt = new Date(System.currentTimeMillis() - 200); + e.setUpdatedDate(updt); + + assertEquals(crtdt, e.getCreatedDate()); + assertEquals(updt, e.getUpdatedDate()); + } + + @Test + public void testEqualsObject() { + DroolsSessionEntity e = makeEnt("mynameA", 1); + + // reflexive + assertTrue(e.equals(e)); + + DroolsSessionEntity e2 = makeEnt("mynameA", 2); + + // session id is not part of hash code + assertTrue(e.equals(e2)); + assertTrue(e.equals(e2)); + + // diff sess name + e2 = makeEnt("mynameB", 1); + assertFalse(e.equals(e2)); + assertFalse(e.equals(e2)); + } + + /** + * Ensures that equals() functions as expected when the getXxx methods + * are overridden. + */ + @Test + public void testEqualsObject_Subclass() { + DroolsSessionEntity e = makeEnt2("mynameA", 1); + + // reflexive + assertTrue(e.equals(e)); + + DroolsSessionEntity e2 = makeEnt("mynameA", 2); + + // session id is not part of hash code + assertTrue(e.equals(e2)); + assertTrue(e.equals(e2)); + + // diff sess name + e2 = makeEnt("mynameB", 1); + assertFalse(e.equals(e2)); + assertFalse(e.equals(e2)); + } + + @Test + public void testToString() { + DroolsSessionEntity e = makeEnt("mynameA", 23); + + assertEquals("{name=mynameA, id=23}", e.toString()); + } + + /** + * Makes a session Entity. The parameters are stored into the Entity + * object via the setXxx methods. + * @param sessnm session name + * @param sessid session id + * @return a new session Entity + */ + private DroolsSessionEntity makeEnt(String sessnm, long sessid) { + + DroolsSessionEntity e = new DroolsSessionEntity(); + + e.setSessionName(sessnm); + e.setSessionId(sessid); + + return e; + } + + /** + * Makes a session Entity that overrides the getXxx methods. The + * parameters that are provided are returned by the overridden methods, + * but they are <i>not</i> stored into the Entity object via the setXxx + * methods. + * @param sessnm session name + * @param sessid session id + * @return a new session Entity + */ + @SuppressWarnings("serial") + private DroolsSessionEntity makeEnt2(String sessnm, long sessid) { + + return new DroolsSessionEntity() { + + @Override + public String getSessionName() { + return sessnm; + } + + @Override + public long getSessionId() { + return sessid; + } + }; + } + +} diff --git a/feature-session-persistence/src/test/java/org/onap/policy/drools/persistence/EntityMgrCloserTest.java b/feature-session-persistence/src/test/java/org/onap/policy/drools/persistence/EntityMgrCloserTest.java new file mode 100644 index 00000000..7350a7f7 --- /dev/null +++ b/feature-session-persistence/src/test/java/org/onap/policy/drools/persistence/EntityMgrCloserTest.java @@ -0,0 +1,100 @@ +/*- + * ============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.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +import javax.persistence.EntityManager; + +import org.junit.Before; +import org.junit.Test; +import org.onap.policy.drools.persistence.EntityMgrCloser; + +public class EntityMgrCloserTest { + + private EntityManager mgr; + + + @Before + public void setUp() throws Exception { + mgr = mock(EntityManager.class); + } + + + /** + * Verifies that the constructor does not do anything extra before + * being closed. + */ + @Test + public void testEntityMgrCloser() { + EntityMgrCloser c = new EntityMgrCloser(mgr); + + // verify not closed yet + verify(mgr, never()).close(); + + c.close(); + } + + /** + * Verifies that the manager gets closed when close() is invoked. + */ + @Test + public void testClose() { + EntityMgrCloser c = new EntityMgrCloser(mgr); + + c.close(); + + // should be closed + verify(mgr).close(); + } + + /** + * Ensures that the manager gets closed when "try" block exits normally. + */ + @Test + public void testClose_TryWithoutExcept() { + try(EntityMgrCloser c = new EntityMgrCloser(mgr)) { + + } + + verify(mgr).close(); + } + + /** + * Ensures that the manager gets closed when "try" block throws an + * exception. + */ + @Test + public void testClose_TryWithExcept() { + try { + try(EntityMgrCloser c = new EntityMgrCloser(mgr)) { + throw new Exception("expected exception"); + } + + } catch (Exception e) { + } + + verify(mgr).close(); + } + +} diff --git a/feature-session-persistence/src/test/java/org/onap/policy/drools/persistence/EntityMgrTransTest.java b/feature-session-persistence/src/test/java/org/onap/policy/drools/persistence/EntityMgrTransTest.java new file mode 100644 index 00000000..0165b1e4 --- /dev/null +++ b/feature-session-persistence/src/test/java/org/onap/policy/drools/persistence/EntityMgrTransTest.java @@ -0,0 +1,232 @@ +/*- + * ============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.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 javax.persistence.EntityManager; +import javax.persistence.EntityTransaction; + +import org.junit.Before; +import org.junit.Test; +import org.onap.policy.drools.persistence.EntityMgrTrans; + +public class EntityMgrTransTest { + + private EntityTransaction trans; + private EntityManager mgr; + + @Before + public void setUp() throws Exception { + trans = mock(EntityTransaction.class); + mgr = mock(EntityManager.class); + + when(mgr.getTransaction()).thenReturn(trans); + } + + + + /** + * Verifies that the constructor starts a transaction, but does not do + * anything extra before being closed. + */ + @Test + public void testEntityMgrTrans() { + EntityMgrTrans t = new EntityMgrTrans(mgr); + + // verify that transaction was started + verify(trans).begin(); + + // verify not closed, committed, or rolled back yet + verify(trans, never()).commit(); + verify(trans, never()).rollback(); + verify(mgr, never()).close(); + + t.close(); + } + + /** + * Verifies that the transaction is rolled back and the manager is + * closed when and a transaction is active. + */ + @Test + public void testClose_Active() { + EntityMgrTrans t = new EntityMgrTrans(mgr); + + when(trans.isActive()).thenReturn(true); + + t.close(); + + // closed and rolled back, but not committed + verify(trans, never()).commit(); + verify(trans).rollback(); + verify(mgr).close(); + } + + /** + * Verifies that the manager is closed, but that the transaction is + * <i>not</i> rolled back and when and no transaction is active. + */ + @Test + public void testClose_Inactive() { + EntityMgrTrans t = new EntityMgrTrans(mgr); + + when(trans.isActive()).thenReturn(false); + + t.close(); + + // closed, but not committed or rolled back + verify(mgr).close(); + verify(trans, never()).commit(); + verify(trans, never()).rollback(); + } + + /** + * Verifies that the manager is closed and the transaction rolled back + * when "try" block exits normally and a transaction is active. + */ + @Test + public void testClose_TryWithoutExcept_Active() { + when(trans.isActive()).thenReturn(true); + + try(EntityMgrTrans t = new EntityMgrTrans(mgr)) { + + } + + // closed and rolled back, but not committed + verify(trans, never()).commit(); + verify(trans).rollback(); + verify(mgr).close(); + } + + /** + * Verifies that the manager is closed, but that the transaction is + * <i>not</i> rolled back when "try" block exits normally and no + * transaction is active. + */ + @Test + public void testClose_TryWithoutExcept_Inactive() { + when(trans.isActive()).thenReturn(false); + + try(EntityMgrTrans t = new EntityMgrTrans(mgr)) { + + } + + // closed, but not rolled back or committed + verify(trans, never()).commit(); + verify(trans, never()).rollback(); + verify(mgr).close(); + } + + /** + * Verifies that the manager is closed and the transaction rolled back + * when "try" block throws an exception and a transaction is active. + */ + @Test + public void testClose_TryWithExcept_Active() { + when(trans.isActive()).thenReturn(true); + + try { + try(EntityMgrTrans t = new EntityMgrTrans(mgr)) { + throw new Exception("expected exception"); + } + + } catch (Exception e) { + } + + // closed and rolled back, but not committed + verify(trans, never()).commit(); + verify(trans).rollback(); + verify(mgr).close(); + } + + /** + * Verifies that the manager is closed, but that the transaction is + * <i>not</i> rolled back when "try" block throws an exception and no + * transaction is active. + */ + @Test + public void testClose_TryWithExcept_Inactive() { + when(trans.isActive()).thenReturn(false); + + try { + try(EntityMgrTrans t = new EntityMgrTrans(mgr)) { + throw new Exception("expected exception"); + } + + } catch (Exception e) { + } + + // closed, but not rolled back or committed + verify(trans, never()).commit(); + verify(trans, never()).rollback(); + verify(mgr).close(); + } + + /** + * Verifies that commit() only commits, and that the subsequent close() + * does not re-commit. + */ + @Test + public void testCommit() { + EntityMgrTrans t = new EntityMgrTrans(mgr); + + t.commit(); + + // committed, but not closed or rolled back + verify(trans).commit(); + verify(trans, never()).rollback(); + verify(mgr, never()).close(); + + // closed, but not re-committed + t.close(); + + verify(trans, times(1)).commit(); + verify(mgr).close(); + } + + /** + * Verifies that rollback() only rolls back, and that the subsequent + * close() does not re-roll back. + */ + @Test + public void testRollback() { + EntityMgrTrans t = new EntityMgrTrans(mgr); + + t.rollback(); + + // rolled back, but not closed or committed + verify(trans, never()).commit(); + verify(trans).rollback(); + verify(mgr, never()).close(); + + // closed, but not re-rolled back + t.close(); + + verify(trans, times(1)).rollback(); + verify(mgr).close(); + } + +} diff --git a/feature-session-persistence/src/test/java/org/onap/policy/drools/persistence/GenSchemaTest.java b/feature-session-persistence/src/test/java/org/onap/policy/drools/persistence/GenSchemaTest.java new file mode 100644 index 00000000..b58c22c6 --- /dev/null +++ b/feature-session-persistence/src/test/java/org/onap/policy/drools/persistence/GenSchemaTest.java @@ -0,0 +1,58 @@ +/*- + * ============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 java.util.HashMap; +import java.util.Map; + +import javax.persistence.EntityManagerFactory; +import javax.persistence.Persistence; + +import org.junit.Test; + +/** + * Generates the schema DDL files. + */ +public class GenSchemaTest { + + private EntityManagerFactory emf; + + + /* + * This is a JUnit which is provided as a utility for producing a basic + * ddl schema file in the sql directory. + * + * To run this simple add @Test ahead of the method and then run this + * as a JUnit. + */ + public void generate() throws Exception { + Map<String, Object> propMap = new HashMap<>(); + + propMap.put("javax.persistence.jdbc.driver", "org.h2.Driver"); + propMap.put("javax.persistence.jdbc.url", + "jdbc:h2:mem:JpaDroolsSessionConnectorTest"); + + emf = Persistence.createEntityManagerFactory( + "schemaDroolsPU", propMap); + + emf.close(); + } +} diff --git a/feature-session-persistence/src/test/java/org/onap/policy/drools/persistence/JpaDroolsSessionConnectorTest.java b/feature-session-persistence/src/test/java/org/onap/policy/drools/persistence/JpaDroolsSessionConnectorTest.java new file mode 100644 index 00000000..c16a1bbd --- /dev/null +++ b/feature-session-persistence/src/test/java/org/onap/policy/drools/persistence/JpaDroolsSessionConnectorTest.java @@ -0,0 +1,160 @@ +/*- + * ============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.assertNull; + +import java.util.HashMap; +import java.util.Map; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.Persistence; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.onap.policy.drools.persistence.DroolsSessionEntity; +import org.onap.policy.drools.persistence.EntityMgrTrans; +import org.onap.policy.drools.persistence.JpaDroolsSessionConnector; + +public class JpaDroolsSessionConnectorTest { + + private EntityManagerFactory emf; + private JpaDroolsSessionConnector conn; + + + @Before + public void setUp() throws Exception { + Map<String, Object> propMap = new HashMap<>(); + + propMap.put("javax.persistence.jdbc.driver", "org.h2.Driver"); + propMap.put("javax.persistence.jdbc.url", + "jdbc:h2:mem:JpaDroolsSessionConnectorTest"); + + emf = Persistence.createEntityManagerFactory( + "junitDroolsSessionEntityPU", propMap); + + conn = new JpaDroolsSessionConnector(emf); + } + + @After + public void tearDown() { + // this will cause the memory db to be dropped + emf.close(); + } + + @Test + public void testGet() { + /* + * Load up the DB with some data. + */ + + addSession("nameA", 10); + addSession("nameY", 20); + + + /* + * Now test the functionality. + */ + + // not found + assertNull( conn.get("unknown")); + + assertEquals("{name=nameA, id=10}", + conn.get("nameA").toString()); + + assertEquals("{name=nameY, id=20}", + conn.get("nameY").toString()); + } + + @Test + public void testReplace_Existing() { + addSession("nameA", 10); + + DroolsSessionEntity sess = + new DroolsSessionEntity("nameA", 30); + + conn.replace(sess); + + // id should be changed + assertEquals(sess.toString(), + conn.get("nameA").toString()); + } + + @Test + public void testReplace_New() { + DroolsSessionEntity sess = + new DroolsSessionEntity("nameA", 30); + + conn.replace(sess); + + assertEquals(sess.toString(), + conn.get("nameA").toString()); + } + + @Test + public void testAdd() { + DroolsSessionEntity sess = + new DroolsSessionEntity("nameA", 30); + + conn.replace(sess); + + assertEquals(sess.toString(), + conn.get("nameA").toString()); + } + + @Test + public void testUpdate() { + addSession("nameA", 10); + + DroolsSessionEntity sess = + new DroolsSessionEntity("nameA", 30); + + conn.replace(sess); + + // id should be changed + assertEquals("{name=nameA, id=30}", + conn.get("nameA").toString()); + } + + + /** + * Adds a session to the DB. + * @param sessnm session name + * @param sessid session id + */ + private void addSession(String sessnm, int sessid) { + EntityManager em = emf.createEntityManager(); + + try(EntityMgrTrans trans = new EntityMgrTrans(em)) { + DroolsSessionEntity ent = new DroolsSessionEntity(); + + ent.setSessionName(sessnm); + ent.setSessionId(sessid); + + em.persist(ent); + + trans.commit(); + } + } +} 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; + } + + } +} diff --git a/feature-session-persistence/src/test/resources/META-INF/persistence.xml b/feature-session-persistence/src/test/resources/META-INF/persistence.xml new file mode 100644 index 00000000..6794e24e --- /dev/null +++ b/feature-session-persistence/src/test/resources/META-INF/persistence.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ============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========================================================= + --> + +<persistence version="2.1" + xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"> + + <persistence-unit name="junitDroolsSessionEntityPU" transaction-type="RESOURCE_LOCAL"> + <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> + <class>org.onap.policy.drools.persistence.DroolsSessionEntity</class> + <properties> + <property name="javax.persistence.schema-generation.database.action" value="create"/> + </properties> + </persistence-unit> + + <persistence-unit name="junitPersistenceFeaturePU" transaction-type="RESOURCE_LOCAL"> + <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> + <class>org.onap.policy.drools.persistence.DroolsSessionEntity</class> + <properties> + <property name="javax.persistence.schema-generation.database.action" value="create"/> + </properties> + </persistence-unit> + +</persistence> diff --git a/feature-session-persistence/src/test/resources/feature-session-persistence.properties b/feature-session-persistence/src/test/resources/feature-session-persistence.properties new file mode 100644 index 00000000..6b448dc8 --- /dev/null +++ b/feature-session-persistence/src/test/resources/feature-session-persistence.properties @@ -0,0 +1,28 @@ +### +# ============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========================================================= +### + +javax.persistence.jdbc.driver=org.h2.Driver +javax.persistence.jdbc.url=jdbc:h2:mem:TestPersistenceFeature +javax.persistence.jdbc.user=testuser +javax.persistence.jdbc.password=testpass + +hibernate.dataSource=org.h2.jdbcx.JdbcDataSource + +persistence.sessioninfo.timeout=10 diff --git a/feature-session-persistence/src/test/resources/logback-test.xml b/feature-session-persistence/src/test/resources/logback-test.xml new file mode 100644 index 00000000..5aeaf90f --- /dev/null +++ b/feature-session-persistence/src/test/resources/logback-test.xml @@ -0,0 +1,39 @@ +<!-- + ============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========================================================= + --> + +<!-- Controls the output of logs for JUnit tests --> + +<configuration> + + <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> + <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> + <Pattern> + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%M\(%line\) - %msg%n + </Pattern> + </encoder> + </appender> + + <logger name="org.onap.policy.drools.persistence" level="INFO"/> + + <root level="warn"> + <appender-ref ref="STDOUT"/> + </root> + +</configuration> |