aboutsummaryrefslogtreecommitdiffstats
path: root/feature-session-persistence/src/test
diff options
context:
space:
mode:
Diffstat (limited to 'feature-session-persistence/src/test')
-rw-r--r--feature-session-persistence/src/test/java/org/onap/policy/drools/persistence/DroolsSessionEntityTest.java198
-rw-r--r--feature-session-persistence/src/test/java/org/onap/policy/drools/persistence/EntityMgrCloserTest.java100
-rw-r--r--feature-session-persistence/src/test/java/org/onap/policy/drools/persistence/EntityMgrTransTest.java232
-rw-r--r--feature-session-persistence/src/test/java/org/onap/policy/drools/persistence/GenSchemaTest.java58
-rw-r--r--feature-session-persistence/src/test/java/org/onap/policy/drools/persistence/JpaDroolsSessionConnectorTest.java160
-rw-r--r--feature-session-persistence/src/test/java/org/onap/policy/drools/persistence/PersistenceFeatureTest.java1291
-rw-r--r--feature-session-persistence/src/test/resources/META-INF/persistence.xml42
-rw-r--r--feature-session-persistence/src/test/resources/feature-session-persistence.properties28
-rw-r--r--feature-session-persistence/src/test/resources/logback-test.xml39
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>