2 * ============LICENSE_START=======================================================
3 * feature-session-persistence
4 * ================================================================================
5 * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 package org.onap.policy.drools.persistence;
23 import static org.junit.Assert.assertEquals;
24 import static org.junit.Assert.assertFalse;
25 import static org.junit.Assert.assertNotNull;
26 import static org.junit.Assert.assertNull;
27 import static org.junit.Assert.assertTrue;
28 import static org.junit.Assert.fail;
29 import static org.mockito.Matchers.any;
30 import static org.mockito.Matchers.anyLong;
31 import static org.mockito.Matchers.anyString;
32 import static org.mockito.Mockito.doThrow;
33 import static org.mockito.Mockito.mock;
34 import static org.mockito.Mockito.never;
35 import static org.mockito.Mockito.times;
36 import static org.mockito.Mockito.verify;
37 import static org.mockito.Mockito.when;
39 import java.io.FileNotFoundException;
40 import java.io.FileReader;
41 import java.io.IOException;
42 import java.sql.Connection;
43 import java.sql.DriverManager;
44 import java.sql.PreparedStatement;
45 import java.sql.ResultSet;
46 import java.sql.SQLException;
47 import java.sql.Timestamp;
48 import java.util.ArrayList;
49 import java.util.List;
51 import java.util.Properties;
52 import java.util.concurrent.CountDownLatch;
53 import java.util.concurrent.TimeUnit;
55 import javax.persistence.EntityManager;
56 import javax.persistence.EntityManagerFactory;
57 import javax.transaction.TransactionManager;
58 import javax.transaction.TransactionSynchronizationRegistry;
59 import javax.transaction.UserTransaction;
61 import org.apache.commons.dbcp2.BasicDataSource;
62 import org.junit.After;
63 import org.junit.Before;
64 import org.junit.BeforeClass;
65 import org.junit.Test;
66 import org.kie.api.KieBase;
67 import org.kie.api.KieServices;
68 import org.kie.api.persistence.jpa.KieStoreServices;
69 import org.kie.api.runtime.Environment;
70 import org.kie.api.runtime.EnvironmentName;
71 import org.kie.api.runtime.KieContainer;
72 import org.kie.api.runtime.KieSession;
73 import org.kie.api.runtime.KieSessionConfiguration;
74 import org.mockito.ArgumentCaptor;
75 import org.onap.policy.drools.core.PolicyContainer;
76 import org.onap.policy.drools.core.PolicySession;
77 import org.onap.policy.drools.core.PolicySession.ThreadModel;
78 import org.onap.policy.drools.persistence.PersistenceFeature.PersistenceFeatureException;
79 import org.onap.policy.drools.persistence.PersistenceFeature.PersistentThreadModel;
80 import org.onap.policy.drools.system.PolicyController;
81 import org.slf4j.Logger;
82 import org.slf4j.LoggerFactory;
84 public class PersistenceFeatureTest {
86 private static final String MY_KIE_BASE = "mybase";
88 private static final String MY_SESS_NAME = "myname";
90 private static final String MISSING_EXCEPTION = "missing exception";
92 private static final String EXPECTED = "expected exception";
94 private static final Logger logger = LoggerFactory.getLogger(PersistenceFeatureTest.class);
96 private static final String JDBC_DRIVER = "fake.driver";
97 private static final String JDBC_URL = "fake.url";
98 private static final String JDBC_USER = "fake.user";
99 private static final String JDBC_PASSWD = "fake.password";
100 private static final String JTA_OSDIR = "target";
101 private static final String SRC_TEST_RESOURCES = "src/test/resources";
103 private static Properties stdprops;
105 private JpaDroolsSessionConnector jpa;
106 private DroolsSession sess;
107 private KieSession kiesess;
108 private BasicDataSource bds;
109 private EntityManagerFactory emf;
110 private Connection conn;
111 private Properties props;
112 private KieServices kiesvc;
113 private Environment kieenv;
114 private KieSessionConfiguration kiecfg;
115 private KieBase kiebase;
116 private KieStoreServices kiestore;
117 private KieContainer kiecont;
118 private TransactionManager transmgr;
119 private UserTransaction usertrans;
120 private TransactionSynchronizationRegistry transreg;
121 private PolicyController polctlr;
122 private PolicyContainer polcont;
123 private PolicySession polsess;
124 private int emfCount;
125 private int jpaCount;
126 private String propName;
128 private PersistenceFeature feat;
131 * Setup before class.
133 * @throws Exception exception
136 public static void setUpBeforeClass() throws Exception {
137 stdprops = new Properties();
139 stdprops.put(DroolsPersistenceProperties.DB_DRIVER, JDBC_DRIVER);
140 stdprops.put(DroolsPersistenceProperties.DB_URL, JDBC_URL);
141 stdprops.put(DroolsPersistenceProperties.DB_USER, JDBC_USER);
142 stdprops.put(DroolsPersistenceProperties.DB_PWD, JDBC_PASSWD);
143 stdprops.put(DroolsPersistenceProperties.JTA_OBJECTSTORE_DIR, JTA_OSDIR);
144 stdprops.put(DroolsPersistenceProperties.DB_SESSIONINFO_TIMEOUT, "50");
146 System.setProperty("com.arjuna.ats.arjuna.objectstore.objectStoreDir", "target/tm");
147 System.setProperty("ObjectStoreEnvironmentBean.objectStoreDir", "target/tm");
153 * @throws Exception exception
156 public void setUp() throws Exception {
157 jpa = mock(JpaDroolsSessionConnector.class);
158 sess = mock(DroolsSession.class);
159 bds = mock(BasicDataSource.class);
160 emf = mock(EntityManagerFactory.class);
161 kiesess = mock(KieSession.class);
163 props = new Properties();
164 kiesvc = mock(KieServices.class);
165 kieenv = mock(Environment.class);
166 kiecfg = mock(KieSessionConfiguration.class);
167 kiebase = mock(KieBase.class);
168 kiestore = mock(KieStoreServices.class);
169 kiecont = mock(KieContainer.class);
170 transmgr = mock(TransactionManager.class);
171 usertrans = mock(UserTransaction.class);
172 transreg = mock(TransactionSynchronizationRegistry.class);
173 polcont = mock(PolicyContainer.class);
174 polctlr = mock(PolicyController.class);
175 polsess = mock(PolicySession.class);
180 feat = new PersistenceFeatureImpl();
182 props.putAll(stdprops);
184 System.setProperty("com.arjuna.ats.arjuna.objectstore.objectStoreDir", "target/tm");
185 System.setProperty("ObjectStoreEnvironmentBean.objectStoreDir", "target/tm");
187 when(kiesvc.newEnvironment()).thenReturn(kieenv);
188 when(kiesvc.getStoreServices()).thenReturn(kiestore);
189 when(kiesvc.newKieSessionConfiguration()).thenReturn(kiecfg);
191 when(polcont.getKieContainer()).thenReturn(kiecont);
193 when(polsess.getPolicyContainer()).thenReturn(polcont);
195 when(kiecont.getKieBase(anyString())).thenReturn(kiebase);
202 public void tearDown() {
203 // this will cause the in-memory test DB to be dropped
207 } catch (SQLException e) {
208 logger.warn("failed to close connection", e);
215 } catch (IllegalArgumentException e) {
216 logger.trace("ignored exception", e);
222 public void testGetContainerAdjunct_New() throws Exception {
223 setUpKie(MY_SESS_NAME, 999L, true);
226 // force getContainerAdjunct() to be invoked
227 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
229 ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
230 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
232 verify(polcont, times(1)).setAdjunct(any(), adjcap.capture());
234 assertNotNull(adjcap.getValue());
238 public void testGetContainerAdjunct_Existing() throws Exception {
239 setUpKie(MY_SESS_NAME, 999L, true);
242 // force getContainerAdjunct() to be invoked
243 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
245 ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
246 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
248 verify(polcont, times(1)).setAdjunct(any(), adjcap.capture());
250 // return adjunct on next call
251 when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
253 // force getContainerAdjunct() to be invoked again
254 setUpKie("myname2", 999L, true);
256 feat.activatePolicySession(polcont, "myname2", MY_KIE_BASE);
258 // ensure it isn't invoked again
259 verify(polcont, times(1)).setAdjunct(any(), any());
263 public void testGetContainerAdjunct_WrongType() throws Exception {
264 setUpKie(MY_SESS_NAME, 999L, true);
267 // return false adjunct on next call
268 when(polcont.getAdjunct(any())).thenReturn("not-a-real-adjunct");
270 // force getContainerAdjunct() to be invoked
271 setUpKie("myname2", 999L, true);
273 feat.activatePolicySession(polcont, "myname2", MY_KIE_BASE);
275 ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
276 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
278 verify(polcont, times(1)).setAdjunct(any(), adjcap.capture());
280 assertNotNull(adjcap.getValue());
284 public void testGetSequenceNumber() {
285 assertEquals(1, feat.getSequenceNumber());
289 public void testGlobalInit() throws Exception {
291 feat.globalInit(null, SRC_TEST_RESOURCES);
293 // verify that various factory methods were invoked
294 assertEquals("src/test/resources/feature-session-persistence.properties", propName);
297 @Test(expected = NullPointerException.class)
298 public void testGlobalInitIoEx() throws Exception {
300 feat = new PersistenceFeatureImpl() {
302 protected Properties loadProperties(String filenm) throws IOException {
303 throw new IOException(EXPECTED);
307 feat.globalInit(null, SRC_TEST_RESOURCES);
311 public void testActivatePolicySession() throws Exception {
312 setUpKie(MY_SESS_NAME, 999L, true);
313 final PreparedStatement ps = mockDbConn(5);
315 feat.beforeActivate(null);
317 KieSession session = feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
319 verify(kiestore).loadKieSession(anyLong(), any(), any(), any());
320 verify(kiestore, never()).newKieSession(any(), any(), any());
322 assertEquals(session, kiesess);
324 verify(ps).executeUpdate();
326 verify(kieenv, times(4)).set(anyString(), any());
328 verify(jpa).get(MY_SESS_NAME);
329 verify(jpa).replace(any());
333 public void testActivatePolicySession_NoPersistence() throws Exception {
334 setUpKie(MY_SESS_NAME, 999L, true);
335 final PreparedStatement ps = mockDbConn(5);
337 props.remove("persistence.type");
339 feat.beforeStart(null);
341 assertNull(feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE));
343 verify(ps, never()).executeUpdate();
344 verify(kiestore, never()).loadKieSession(anyLong(), any(), any(), any());
345 verify(kiestore, never()).newKieSession(any(), any(), any());
348 /** Verifies that a new KIE session is created when there is no existing session entity. */
350 public void testActivatePolicySession_New() throws Exception {
351 setUpKie("noName", 999L, true);
354 KieSession session = feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
356 verify(kiestore, never()).loadKieSession(anyLong(), any(), any(), any());
357 verify(kiestore).newKieSession(any(), any(), any());
359 assertEquals(session, kiesess);
361 verify(kieenv, times(4)).set(anyString(), any());
363 verify(jpa).get(MY_SESS_NAME);
364 verify(jpa).replace(any());
368 * Verifies that a new KIE session is created when there KIE fails to load an existing session.
371 public void testActivatePolicySession_LoadFailed() throws Exception {
372 setUpKie(MY_SESS_NAME, 999L, false);
375 KieSession session = feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
377 verify(kiestore).loadKieSession(anyLong(), any(), any(), any());
378 verify(kiestore).newKieSession(any(), any(), any());
380 assertEquals(session, kiesess);
382 verify(kieenv, times(4)).set(anyString(), any());
384 verify(jpa).get(MY_SESS_NAME);
386 ArgumentCaptor<DroolsSession> drools = ArgumentCaptor.forClass(DroolsSession.class);
387 verify(jpa).replace(drools.capture());
389 assertEquals(MY_SESS_NAME, drools.getValue().getSessionName());
390 assertEquals(100L, drools.getValue().getSessionId());
394 public void testLoadDataSource() throws Exception {
395 setUpKie(MY_SESS_NAME, 999L, false);
398 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
400 assertEquals(1, emfCount);
404 public void testConfigureSysProps() throws Exception {
405 setUpKie(MY_SESS_NAME, 999L, false);
408 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
410 assertEquals("60", System.getProperty("com.arjuna.ats.arjuna.coordinator.defaultTimeout"));
411 assertEquals(JTA_OSDIR, System.getProperty("com.arjuna.ats.arjuna.objectstore.objectStoreDir"));
412 assertEquals(JTA_OSDIR, System.getProperty("ObjectStoreEnvironmentBean.objectStoreDir"));
416 public void testConfigureKieEnv() throws Exception {
417 setUpKie(MY_SESS_NAME, 999L, false);
420 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
422 verify(kieenv, times(4)).set(any(), any());
424 verify(kieenv).set(EnvironmentName.ENTITY_MANAGER_FACTORY, emf);
425 verify(kieenv).set(EnvironmentName.TRANSACTION, usertrans);
426 verify(kieenv).set(EnvironmentName.TRANSACTION_MANAGER, transmgr);
427 verify(kieenv).set(EnvironmentName.TRANSACTION_SYNCHRONIZATION_REGISTRY, transreg);
429 verify(bds, times(1)).close();
433 public void testConfigureKieEnv_RtEx() throws Exception {
434 setUpKie(MY_SESS_NAME, 999L, false);
437 feat = new PersistenceFeatureMockDb() {
439 protected UserTransaction getUserTrans() {
440 throw new IllegalArgumentException(EXPECTED);
444 feat.globalInit(null, SRC_TEST_RESOURCES);
447 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
448 fail(MISSING_EXCEPTION);
450 } catch (IllegalArgumentException ex) {
451 logger.trace(EXPECTED, ex);
454 verify(bds, times(2)).close();
458 public void testLoadKieSession() throws Exception {
459 setUpKie(MY_SESS_NAME, 999L, true);
462 KieSession session = feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
464 verify(kiestore).loadKieSession(999L, kiebase, kiecfg, kieenv);
465 verify(kiestore, never()).newKieSession(any(), any(), any());
467 assertEquals(session, kiesess);
471 * Verifies that loadKieSession() returns null (thus causing newKieSession()
472 * to be called) when an Exception occurs.
475 public void testLoadKieSession_Ex() throws Exception {
476 setUpKie(MY_SESS_NAME, 999L, false);
479 when(kiestore.loadKieSession(anyLong(), any(), any(), any()))
480 .thenThrow(new IllegalArgumentException(EXPECTED));
482 KieSession session = feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
484 verify(kiestore).loadKieSession(anyLong(), any(), any(), any());
485 verify(kiestore).newKieSession(any(), any(), any());
487 assertEquals(session, kiesess);
491 public void testNewKieSession() throws Exception {
492 setUpKie(MY_SESS_NAME, 999L, false);
495 KieSession session = feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
497 verify(kiestore).newKieSession(kiebase, null, kieenv);
499 assertEquals(session, kiesess);
503 public void testLoadDataSource_DiffSession() throws Exception {
504 setUpKie(MY_SESS_NAME, 999L, false);
507 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
509 ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
510 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
512 verify(polcont).setAdjunct(any(), adjcap.capture());
514 when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
516 setUpKie("myname2", 999L, false);
520 feat.activatePolicySession(polcont, "myname2", MY_KIE_BASE);
522 assertEquals(2, emfCount);
526 public void testSelectThreadModel_Persistent() throws Exception {
527 setUpKie(MY_SESS_NAME, 999L, true);
529 ThreadModel model = feat.selectThreadModel(polsess);
530 assertNotNull(model);
531 assertTrue(model instanceof PersistentThreadModel);
535 public void testSelectThreadModel_NotPersistent() throws Exception {
536 assertNull(feat.selectThreadModel(polsess));
540 public void testSelectThreadModel_Start__Run_Update_Stop() throws Exception {
541 setUpKie(MY_SESS_NAME, 999L, true);
543 ThreadModel model = feat.selectThreadModel(polsess);
544 assertNotNull(model);
545 assertTrue(model instanceof PersistentThreadModel);
547 when(polsess.getKieSession()).thenReturn(kiesess);
550 new CountDownLatch(1).await(10, TimeUnit.MILLISECONDS);
556 public void testDisposeKieSession() throws Exception {
557 setUpKie(MY_SESS_NAME, 999L, false);
560 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
562 verify(emf, never()).close();
564 final ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
565 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
567 verify(polcont).setAdjunct(any(), adjcap.capture());
569 when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
571 feat.disposeKieSession(polsess);
573 // call twice to ensure it isn't re-closed
574 feat.disposeKieSession(polsess);
576 verify(emf, times(1)).close();
580 public void testDisposeKieSession_NoAdjunct() throws Exception {
581 feat.globalInit(null, SRC_TEST_RESOURCES);
583 feat.disposeKieSession(polsess);
587 public void testDisposeKieSession_NoPersistence() throws Exception {
588 setUpKie(MY_SESS_NAME, 999L, false);
591 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
593 verify(emf, never()).close();
595 final ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
596 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
598 verify(polcont).setAdjunct(any(), adjcap.capture());
600 when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
602 // specify a session that was never loaded
603 when(polsess.getName()).thenReturn("anotherName");
605 feat.disposeKieSession(polsess);
607 verify(emf, never()).close();
611 public void testDestroyKieSession() throws Exception {
612 setUpKie(MY_SESS_NAME, 999L, false);
615 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
617 verify(emf, never()).close();
619 final ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
620 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
622 verify(polcont).setAdjunct(any(), adjcap.capture());
624 when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
626 feat.destroyKieSession(polsess);
628 // call twice to ensure it isn't re-closed
629 feat.destroyKieSession(polsess);
631 verify(emf, times(1)).close();
635 public void testDestroyKieSession_NoAdjunct() throws Exception {
636 feat.globalInit(null, SRC_TEST_RESOURCES);
638 feat.destroyKieSession(polsess);
642 public void testDestroyKieSession_NoPersistence() throws Exception {
643 setUpKie(MY_SESS_NAME, 999L, false);
646 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
648 verify(emf, never()).close();
650 final ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
651 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
653 verify(polcont).setAdjunct(any(), adjcap.capture());
655 when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
657 // specify a session that was never loaded
658 when(polsess.getName()).thenReturn("anotherName");
660 feat.destroyKieSession(polsess);
662 verify(emf, never()).close();
666 public void testAfterStart() {
667 assertFalse(feat.afterStart(null));
671 public void testBeforeStart() {
672 assertFalse(feat.beforeStart(null));
676 public void testBeforeShutdown() {
677 assertFalse(feat.beforeShutdown(null));
681 public void testAfterShutdown() {
682 assertFalse(feat.afterShutdown(null));
686 public void testBeforeConfigure() {
687 assertFalse(feat.beforeConfigure(null, null));
691 public void testAfterConfigure() {
692 assertFalse(feat.afterConfigure(null));
696 public void testBeforeActivate() {
697 assertFalse(feat.beforeActivate(null));
701 public void testAfterActivate() {
702 assertFalse(feat.afterActivate(null));
706 public void testBeforeDeactivate() {
707 assertFalse(feat.beforeDeactivate(null));
711 public void testAfterDeactivate() {
712 assertFalse(feat.afterDeactivate(null));
716 public void testBeforeStop() {
717 assertFalse(feat.beforeStop(null));
721 public void testAfterStop() {
722 assertFalse(feat.afterStop(null));
726 public void testBeforeLock() {
727 assertFalse(feat.beforeLock(null));
731 public void testAfterLock() {
732 assertFalse(feat.afterLock(null));
736 public void testBeforeUnlock() {
737 assertFalse(feat.beforeUnlock(null));
741 public void testAfterUnlock() {
742 assertFalse(feat.afterUnlock(null));
746 public void testGetPersistenceTimeout_Valid() throws Exception {
747 setUpKie(MY_SESS_NAME, 999L, true);
748 final PreparedStatement statement = mockDbConn(5);
750 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
752 verify(statement).executeUpdate();
756 public void testGetPersistenceTimeout_Missing() throws Exception {
758 props.remove(DroolsPersistenceProperties.DB_SESSIONINFO_TIMEOUT);
760 setUpKie(MY_SESS_NAME, 999L, true);
761 final PreparedStatement statement = mockDbConn(0);
763 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
765 verify(statement, never()).executeUpdate();
769 public void testGetPersistenceTimeout_Invalid() throws Exception {
770 props.setProperty(DroolsPersistenceProperties.DB_SESSIONINFO_TIMEOUT, "abc");
772 setUpKie(MY_SESS_NAME, 999L, true);
773 final PreparedStatement s = mockDbConn(0);
775 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
777 verify(s, never()).executeUpdate();
781 public void testCleanUpSessionInfo() throws Exception {
782 setUpKie(MY_SESS_NAME, 999L, true);
784 // use a real DB so we can verify that the "delete" works correctly
785 feat = new PartialFeature();
787 makeSessionInfoTbl(20000);
789 // create mock entity manager for use by JPA connector
790 EntityManager em = mock(EntityManager.class);
791 when(emf.createEntityManager()).thenReturn(em);
793 feat.globalInit(null, SRC_TEST_RESOURCES);
795 feat.beforeStart(null);
796 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
798 assertEquals("[1, 4, 5]", getSessions().toString());
802 public void testCleanUpSessionInfo_WithBeforeStart() throws Exception {
803 setUpKie(MY_SESS_NAME, 999L, true);
804 final PreparedStatement statement = mockDbConn(0);
807 feat.beforeStart(null);
809 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
810 verify(statement, times(1)).executeUpdate();
812 // should not clean-up again
813 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
814 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
815 verify(statement, times(1)).executeUpdate();
818 feat.beforeStart(null);
820 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
821 verify(statement, times(2)).executeUpdate();
823 // should not clean-up again
824 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
825 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
826 verify(statement, times(2)).executeUpdate();
830 public void testCleanUpSessionInfo_WithBeforeActivate() throws Exception {
831 setUpKie(MY_SESS_NAME, 999L, true);
832 final PreparedStatement statement = mockDbConn(0);
835 feat.beforeActivate(null);
837 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
838 verify(statement, times(1)).executeUpdate();
840 // should not clean-up again
841 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
842 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
843 verify(statement, times(1)).executeUpdate();
846 feat.beforeActivate(null);
848 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
849 verify(statement, times(2)).executeUpdate();
851 // should not clean-up again
852 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
853 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
854 verify(statement, times(2)).executeUpdate();
858 public void testCleanUpSessionInfo_NoTimeout() throws Exception {
860 props.remove(DroolsPersistenceProperties.DB_SESSIONINFO_TIMEOUT);
862 setUpKie(MY_SESS_NAME, 999L, true);
863 final PreparedStatement statement = mockDbConn(0);
865 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
867 verify(statement, never()).executeUpdate();
871 public void testCleanUpSessionInfo_NoUrl() throws Exception {
872 props.remove(DroolsPersistenceProperties.DB_URL);
874 setUpKie(MY_SESS_NAME, 999L, true);
875 final PreparedStatement statement = mockDbConn(0);
878 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
879 fail(MISSING_EXCEPTION);
880 } catch (RuntimeException e) {
881 logger.trace(EXPECTED, e);
884 verify(statement, never()).executeUpdate();
888 public void testCleanUpSessionInfo_NoUser() throws Exception {
889 props.remove(DroolsPersistenceProperties.DB_USER);
891 setUpKie(MY_SESS_NAME, 999L, true);
892 final PreparedStatement statement = mockDbConn(0);
895 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
896 fail(MISSING_EXCEPTION);
897 } catch (RuntimeException e) {
898 logger.trace(EXPECTED, e);
901 verify(statement, never()).executeUpdate();
905 public void testCleanUpSessionInfo_NoPassword() throws Exception {
906 props.remove(DroolsPersistenceProperties.DB_PWD);
908 setUpKie(MY_SESS_NAME, 999L, true);
909 final PreparedStatement statement = mockDbConn(0);
912 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
913 fail(MISSING_EXCEPTION);
914 } catch (RuntimeException e) {
915 logger.trace(EXPECTED, e);
918 verify(statement, never()).executeUpdate();
922 public void testCleanUpSessionInfo_SqlEx() throws Exception {
923 setUpKie(MY_SESS_NAME, 999L, true);
924 final PreparedStatement statement = mockDbConn(-1);
926 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
928 verify(statement).executeUpdate();
932 public void testGetDroolsSessionConnector() throws Exception {
933 setUpKie(MY_SESS_NAME, 999L, true);
936 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
938 assertEquals(1, jpaCount);
942 public void testReplaceSession() throws Exception {
943 setUpKie(MY_SESS_NAME, 999L, true);
946 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
948 final ArgumentCaptor<DroolsSession> sesscap = ArgumentCaptor.forClass(DroolsSession.class);
950 verify(jpa).replace(sesscap.capture());
952 assertEquals(MY_SESS_NAME, sesscap.getValue().getSessionName());
953 assertEquals(999L, sesscap.getValue().getSessionId());
957 public void testIsPersistenceEnabled_Auto() throws Exception {
958 setUpKie(MY_SESS_NAME, 999L, true);
961 props.setProperty("persistence.type", "auto");
963 assertNotNull(feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE));
967 public void testIsPersistenceEnabled_Native() throws Exception {
968 setUpKie(MY_SESS_NAME, 999L, true);
971 props.setProperty("persistence.type", "native");
973 assertNotNull(feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE));
977 public void testIsPersistenceEnabled_None() throws Exception {
978 setUpKie(MY_SESS_NAME, 999L, true);
981 props.remove("persistence.type");
983 assertNull(feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE));
987 public void testGetProperties_Ex() throws Exception {
988 setUpKie(MY_SESS_NAME, 999L, true);
991 feat = new PersistenceFeatureMockDb() {
993 protected PolicyController getPolicyController(PolicyContainer container) {
994 throw new IllegalArgumentException(EXPECTED);
998 assertNull(feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE));
1002 public void testGetProperty_Specific() throws Exception {
1003 setUpKie(MY_SESS_NAME, 999L, true);
1006 props.remove("persistence.type");
1007 props.setProperty("persistence.myname.type", "auto");
1009 assertNotNull(feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE));
1013 public void testGetProperty_Specific_None() throws Exception {
1014 setUpKie(MY_SESS_NAME, 999L, true);
1017 props.remove("persistence.type");
1018 props.setProperty("persistence.xxx.type", "auto");
1020 assertNull(feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE));
1024 public void testGetProperty_Both_SpecificOn() throws Exception {
1025 setUpKie(MY_SESS_NAME, 999L, true);
1028 props.setProperty("persistence.type", "other");
1029 props.setProperty("persistence.myname.type", "auto");
1031 assertNotNull(feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE));
1035 public void testGetProperty_Both_SpecificDisabledOff() throws Exception {
1036 setUpKie(MY_SESS_NAME, 999L, true);
1039 props.setProperty("persistence.type", "auto");
1040 props.setProperty("persistence.myname.type", "other");
1042 assertNull(feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE));
1046 public void testGetProperty_None() throws Exception {
1047 setUpKie(MY_SESS_NAME, 999L, true);
1050 props.remove("persistence.type");
1052 assertNull(feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE));
1056 public void testPersistenceFeatureException() {
1057 SecurityException secex = new SecurityException(EXPECTED);
1058 PersistenceFeatureException ex = new PersistenceFeatureException(secex);
1060 assertEquals(secex, ex.getCause());
1064 public void testDsEmf_RtEx() throws Exception {
1065 setUpKie(MY_SESS_NAME, 999L, false);
1068 feat = new PersistenceFeatureMockDb() {
1070 protected EntityManagerFactory makeEntMgrFact(Map<String, Object> props) {
1071 throw new IllegalArgumentException(EXPECTED);
1075 feat.globalInit(null, SRC_TEST_RESOURCES);
1078 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
1079 fail(MISSING_EXCEPTION);
1081 } catch (IllegalArgumentException ex) {
1082 logger.trace(EXPECTED, ex);
1085 verify(bds, times(2)).close();
1089 public void testDsEmf_Close_RtEx() throws Exception {
1090 setUpKie(MY_SESS_NAME, 999L, false);
1093 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
1095 ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
1096 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
1098 verify(polcont, times(1)).setAdjunct(any(), adjcap.capture());
1100 // return adjunct on next call
1101 when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
1104 doThrow(new IllegalArgumentException(EXPECTED)).when(emf).close();
1106 feat.destroyKieSession(polsess);
1107 fail(MISSING_EXCEPTION);
1109 } catch (IllegalArgumentException ex) {
1110 logger.trace(EXPECTED, ex);
1113 verify(bds, times(2)).close();
1117 public void testDsEmf_CloseDataSource_RtEx() throws Exception {
1118 setUpKie(MY_SESS_NAME, 999L, false);
1121 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
1123 ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
1124 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
1126 verify(polcont, times(1)).setAdjunct(any(), adjcap.capture());
1128 // return adjunct on next call
1129 when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
1132 doThrow(new SQLException(EXPECTED)).when(bds).close();
1134 feat.destroyKieSession(polsess);
1135 fail(MISSING_EXCEPTION);
1137 } catch (PersistenceFeatureException ex) {
1138 logger.trace(EXPECTED, ex);
1143 * Gets an ordered list of ids of the current SessionInfo records.
1145 * @return ordered list of SessInfo IDs
1146 * @throws SQLException sql exception
1147 * @throws IOException io exception
1149 private List<Integer> getSessions() throws SQLException, IOException {
1152 ArrayList<Integer> lst = new ArrayList<>(5);
1154 try (PreparedStatement stmt = conn.prepareStatement("SELECT id from sessioninfo order by id");
1155 ResultSet rs = stmt.executeQuery()) {
1158 lst.add(rs.getInt(1));
1166 * Sets up for doing invoking the newKieSession() method.
1168 * @param sessnm name to which JPA should respond with a session
1169 * @param sessid session id to be returned by the session
1170 * @param loadOk {@code true} if loadKieSession() should return a value, {@code false} to return
1172 * @throws Exception exception
1174 private void setUpKie(String sessnm, long sessid, boolean loadOk) throws Exception {
1175 props.setProperty("persistence.type", "auto");
1177 when(polctlr.getProperties()).thenReturn(props);
1179 when(jpa.get(sessnm)).thenReturn(sess);
1181 when(sess.getSessionId()).thenReturn(sessid);
1183 when(polsess.getPolicyContainer()).thenReturn(polcont);
1184 when(polsess.getName()).thenReturn(sessnm);
1187 when(kiesess.getIdentifier()).thenReturn(sessid);
1188 when(kiestore.loadKieSession(anyLong(), any(), any(), any())).thenReturn(kiesess);
1191 // use an alternate id for the new session
1192 when(kiesess.getIdentifier()).thenReturn(100L);
1193 when(kiestore.loadKieSession(anyLong(), any(), any(), any())).thenReturn(null);
1196 when(kiestore.newKieSession(any(), any(), any())).thenReturn(kiesess);
1198 feat = new PersistenceFeatureKie();
1199 feat.globalInit(null, SRC_TEST_RESOURCES);
1203 * Creates the SessionInfo DB table and populates it with some data.
1205 * @param expMs number of milli-seconds for expired sessioninfo records
1206 * @throws SQLException exception
1207 * @throws IOException exception
1209 private void makeSessionInfoTbl(int expMs) throws SQLException, IOException {
1213 try (PreparedStatement stmt =
1214 conn.prepareStatement("CREATE TABLE sessioninfo(id int, lastmodificationdate timestamp)")) {
1216 stmt.executeUpdate();
1219 try (PreparedStatement stmt =
1220 conn.prepareStatement("INSERT into sessioninfo(id, lastmodificationdate) values(?, ?)")) {
1225 ts = new Timestamp(System.currentTimeMillis());
1226 stmt.setTimestamp(2, ts);
1229 stmt.executeUpdate();
1232 stmt.executeUpdate();
1235 stmt.executeUpdate();
1238 ts = new Timestamp(System.currentTimeMillis() - expMs);
1239 stmt.setTimestamp(2, ts);
1242 stmt.executeUpdate();
1245 stmt.executeUpdate();
1250 * Attaches {@link #conn} to the DB, if it isn't already attached.
1252 * @throws SQLException sql exception
1253 * @throws IOException if the property file cannot be read
1255 private void attachDb() throws SQLException, IOException {
1257 Properties props = loadDbProps();
1260 DriverManager.getConnection(
1261 props.getProperty(DroolsPersistenceProperties.DB_URL),
1262 props.getProperty(DroolsPersistenceProperties.DB_USER),
1263 props.getProperty(DroolsPersistenceProperties.DB_PWD));
1264 conn.setAutoCommit(true);
1269 * Loads the DB properties from the file, <i>feature-session-persistence.properties</i>.
1271 * @return the properties that were loaded
1272 * @throws IOException if the property file cannot be read
1273 * @throws FileNotFoundException if the property file does not exist
1275 private Properties loadDbProps() throws IOException, FileNotFoundException {
1277 Properties props = new Properties();
1279 try (FileReader rdr =
1280 new FileReader("src/test/resources/feature-session-persistence.properties")) {
1288 * Create a mock DB connection and statement.
1290 * @param retval value to be returned when the statement is executed, or negative to throw an
1292 * @return the statement that will be returned by the connection
1293 * @throws SQLException sql exception
1295 private PreparedStatement mockDbConn(int retval) throws SQLException {
1296 Connection connection = mock(Connection.class);
1297 PreparedStatement statement = mock(PreparedStatement.class);
1299 when(bds.getConnection()).thenReturn(connection);
1300 when(connection.prepareStatement(anyString())).thenReturn(statement);
1303 // should throw an exception
1304 when(statement.executeUpdate()).thenThrow(new SQLException(EXPECTED));
1307 // should return the value
1308 when(statement.executeUpdate()).thenReturn(retval);
1311 feat = new PersistenceFeatureMockDb();
1312 feat.globalInit(null, SRC_TEST_RESOURCES);
1318 * Feature with a mock DB.
1320 private class PersistenceFeatureMockDb extends PersistenceFeatureKie {
1323 protected BasicDataSource makeDataSource(Properties dsProps) {
1329 * Feature supporting newKieSession.
1331 private class PersistenceFeatureKie extends PersistenceFeatureImpl {
1334 protected EntityManagerFactory makeEntMgrFact(Map<String, Object> props) {
1340 protected DroolsSessionConnector makeJpaConnector(EntityManagerFactory emf) {
1347 * Feature with overrides.
1349 private class PersistenceFeatureImpl extends PartialFeature {
1352 protected Properties loadProperties(String filenm) throws IOException {
1358 protected BasicDataSource makeDataSource(Properties dsProps) {
1363 protected DroolsSessionConnector makeJpaConnector(EntityManagerFactory emf) {
1370 * Feature with <i>some</i> overrides.
1372 private class PartialFeature extends PersistenceFeature {
1375 protected TransactionManager getTransMgr() {
1380 protected UserTransaction getUserTrans() {
1385 protected TransactionSynchronizationRegistry getTransSyncReg() {
1390 protected KieServices getKieServices() {
1395 protected EntityManagerFactory makeEntMgrFact(Map<String, Object> props) {
1401 protected PolicyController getPolicyController(PolicyContainer container) {