2 * ============LICENSE_START=======================================================
3 * feature-session-persistence
4 * ================================================================================
5 * Copyright (C) 2017 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.mock;
33 import static org.mockito.Mockito.never;
34 import static org.mockito.Mockito.times;
35 import static org.mockito.Mockito.verify;
36 import static org.mockito.Mockito.when;
37 import static org.mockito.Mockito.doThrow;
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 Logger logger = LoggerFactory.getLogger(PersistenceFeatureTest.class);
88 private static final String JDBC_DRIVER = "fake.driver";
89 private static final String JDBC_URL = "fake.url";
90 private static final String JDBC_USER = "fake.user";
91 private static final String JDBC_PASSWD = "fake.password";
92 private static final String JTA_OSDIR = "target";
93 private static final String SRC_TEST_RESOURCES = "src/test/resources";
95 private static Properties stdprops;
97 private JpaDroolsSessionConnector jpa;
98 private DroolsSession sess;
99 private KieSession kiesess;
100 private BasicDataSource bds;
101 private EntityManagerFactory emf;
102 private Connection conn;
103 private Properties props;
104 private KieServices kiesvc;
105 private Environment kieenv;
106 private KieSessionConfiguration kiecfg;
107 private KieBase kiebase;
108 private KieStoreServices kiestore;
109 private KieContainer kiecont;
110 private TransactionManager transmgr;
111 private UserTransaction usertrans;
112 private TransactionSynchronizationRegistry transreg;
113 private PolicyController polctlr;
114 private PolicyContainer polcont;
115 private PolicySession polsess;
116 private PersistenceFeature.Factory fact;
118 private PersistenceFeature feat;
121 public static void setUpBeforeClass() throws Exception {
122 stdprops = new Properties();
124 stdprops.put(DroolsPersistenceProperties.DB_DRIVER, JDBC_DRIVER);
125 stdprops.put(DroolsPersistenceProperties.DB_URL, JDBC_URL);
126 stdprops.put(DroolsPersistenceProperties.DB_USER, JDBC_USER);
127 stdprops.put(DroolsPersistenceProperties.DB_PWD, JDBC_PASSWD);
128 stdprops.put(DroolsPersistenceProperties.JTA_OBJECTSTORE_DIR, JTA_OSDIR);
129 stdprops.put(DroolsPersistenceProperties.DB_SESSIONINFO_TIMEOUT, "50");
131 System.setProperty("com.arjuna.ats.arjuna.objectstore.objectStoreDir", "target/tm");
132 System.setProperty("ObjectStoreEnvironmentBean.objectStoreDir", "target/tm");
136 public void setUp() throws Exception {
137 jpa = mock(JpaDroolsSessionConnector.class);
138 sess = mock(DroolsSession.class);
139 bds = mock(BasicDataSource.class);
140 emf = mock(EntityManagerFactory.class);
141 kiesess = mock(KieSession.class);
143 props = new Properties();
144 kiesvc = mock(KieServices.class);
145 kieenv = mock(Environment.class);
146 kiecfg = mock(KieSessionConfiguration.class);
147 kiebase = mock(KieBase.class);
148 kiestore = mock(KieStoreServices.class);
149 kiecont = mock(KieContainer.class);
150 transmgr = mock(TransactionManager.class);
151 usertrans = mock(UserTransaction.class);
152 transreg = mock(TransactionSynchronizationRegistry.class);
153 polcont = mock(PolicyContainer.class);
154 polctlr = mock(PolicyController.class);
155 polsess = mock(PolicySession.class);
156 fact = mock(PersistenceFeature.Factory.class);
158 feat = new PersistenceFeature();
159 feat.setFactory(fact);
161 props.putAll(stdprops);
163 System.setProperty("com.arjuna.ats.arjuna.objectstore.objectStoreDir", "target/tm");
164 System.setProperty("ObjectStoreEnvironmentBean.objectStoreDir", "target/tm");
166 when(fact.getKieServices()).thenReturn(kiesvc);
167 when(fact.getTransMgr()).thenReturn(transmgr);
168 when(fact.getUserTrans()).thenReturn(usertrans);
169 when(fact.getTransSyncReg()).thenReturn(transreg);
170 when(fact.loadProperties(anyString())).thenReturn(props);
172 when(kiesvc.newEnvironment()).thenReturn(kieenv);
173 when(kiesvc.getStoreServices()).thenReturn(kiestore);
174 when(kiesvc.newKieSessionConfiguration()).thenReturn(kiecfg);
176 when(polcont.getKieContainer()).thenReturn(kiecont);
178 when(polsess.getPolicyContainer()).thenReturn(polcont);
180 when(kiecont.getKieBase(anyString())).thenReturn(kiebase);
184 public void tearDown() {
185 // this will cause the in-memory test DB to be dropped
189 } catch (SQLException e) {
190 logger.warn("failed to close connection", e);
197 } catch (IllegalArgumentException e) {
198 logger.trace("ignored exception", e);
204 public void testGetContainerAdjunct_New() throws Exception {
206 feat.globalInit(null, SRC_TEST_RESOURCES);
209 setUpKie("myname", 999L, true);
211 // force getContainerAdjunct() to be invoked
212 feat.activatePolicySession(polcont, "myname", "mybase");
214 ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap = ArgumentCaptor
215 .forClass(PersistenceFeature.ContainerAdjunct.class);
217 verify(polcont, times(1)).setAdjunct(any(), adjcap.capture());
219 assertNotNull(adjcap.getValue());
223 public void testGetContainerAdjunct_Existing() throws Exception {
225 feat.globalInit(null, SRC_TEST_RESOURCES);
228 setUpKie("myname", 999L, true);
230 // force getContainerAdjunct() to be invoked
231 feat.activatePolicySession(polcont, "myname", "mybase");
233 ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap = ArgumentCaptor
234 .forClass(PersistenceFeature.ContainerAdjunct.class);
236 verify(polcont, times(1)).setAdjunct(any(), adjcap.capture());
238 // return adjunct on next call
239 when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
241 // force getContainerAdjunct() to be invoked again
242 setUpKie("myname2", 999L, true);
243 feat.activatePolicySession(polcont, "myname2", "mybase");
245 // ensure it isn't invoked again
246 verify(polcont, times(1)).setAdjunct(any(), any());
250 public void testGetContainerAdjunct_WrongType() throws Exception {
252 feat.globalInit(null, SRC_TEST_RESOURCES);
255 setUpKie("myname", 999L, true);
257 // return false adjunct on next call
258 when(polcont.getAdjunct(any())).thenReturn("not-a-real-adjunct");
260 // force getContainerAdjunct() to be invoked
261 setUpKie("myname2", 999L, true);
262 feat.activatePolicySession(polcont, "myname2", "mybase");
264 ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap = ArgumentCaptor
265 .forClass(PersistenceFeature.ContainerAdjunct.class);
267 verify(polcont, times(1)).setAdjunct(any(), adjcap.capture());
269 assertNotNull(adjcap.getValue());
273 public void testGetSequenceNumber() {
274 assertEquals(1, feat.getSequenceNumber());
278 public void testGlobalInit() throws Exception {
280 feat.globalInit(null, SRC_TEST_RESOURCES);
282 // verify that various factory methods were invoked
283 verify(fact).getKieServices();
284 verify(fact).loadProperties("src/test/resources/feature-session-persistence.properties");
287 @Test(expected = NullPointerException.class)
288 public void testGlobalInit_IOEx() throws Exception {
290 when(fact.loadProperties(anyString())).thenThrow(new IOException("expected exception"));
292 feat.globalInit(null, SRC_TEST_RESOURCES);
296 public void testActivatePolicySession() throws Exception {
297 PreparedStatement ps = mockDbConn(5);
298 setUpKie("myname", 999L, true);
300 feat.globalInit(null, SRC_TEST_RESOURCES);
301 feat.beforeActivate(null);
303 KieSession s = feat.activatePolicySession(polcont, "myname", "mybase");
305 verify(kiestore).loadKieSession(anyLong(), any(), any(), any());
306 verify(kiestore, never()).newKieSession(any(), any(), any());
308 assertEquals(s, kiesess);
310 verify(ps).executeUpdate();
312 verify(kieenv, times(4)).set(anyString(), any());
314 verify(jpa).get("myname");
315 verify(jpa).replace(any());
319 public void testActivatePolicySession_NoPersistence() throws Exception {
320 feat.globalInit(null, SRC_TEST_RESOURCES);
322 PreparedStatement ps = mockDbConn(5);
323 setUpKie("myname", 999L, true);
325 props.remove("persistence.type");
327 feat.beforeStart(null);
329 assertNull(feat.activatePolicySession(polcont, "myname", "mybase"));
331 verify(ps, never()).executeUpdate();
332 verify(kiestore, never()).loadKieSession(anyLong(), any(), any(), any());
333 verify(kiestore, never()).newKieSession(any(), any(), any());
337 * Verifies that a new KIE session is created when there is no existing
341 public void testActivatePolicySession_New() throws Exception {
342 feat.globalInit(null, SRC_TEST_RESOURCES);
345 setUpKie("noName", 999L, true);
347 KieSession s = feat.activatePolicySession(polcont, "myname", "mybase");
349 verify(kiestore, never()).loadKieSession(anyLong(), any(), any(), any());
350 verify(kiestore).newKieSession(any(), any(), any());
352 assertEquals(s, kiesess);
354 verify(kieenv, times(4)).set(anyString(), any());
356 verify(jpa).get("myname");
357 verify(jpa).replace(any());
361 * Verifies that a new KIE session is created when there KIE fails to load
362 * an existing session.
365 public void testActivatePolicySession_LoadFailed() throws Exception {
366 feat.globalInit(null, SRC_TEST_RESOURCES);
369 setUpKie("myname", 999L, false);
371 KieSession s = feat.activatePolicySession(polcont, "myname", "mybase");
373 verify(kiestore).loadKieSession(anyLong(), any(), any(), any());
374 verify(kiestore).newKieSession(any(), any(), any());
376 assertEquals(s, kiesess);
378 verify(kieenv, times(4)).set(anyString(), any());
380 verify(jpa).get("myname");
382 ArgumentCaptor<DroolsSession> d = ArgumentCaptor.forClass(DroolsSession.class);
383 verify(jpa).replace(d.capture());
385 assertEquals("myname", d.getValue().getSessionName());
386 assertEquals(100L, d.getValue().getSessionId());
390 public void testLoadDataSource() throws Exception {
391 feat.globalInit(null, SRC_TEST_RESOURCES);
394 setUpKie("myname", 999L, false);
396 feat.activatePolicySession(polcont, "myname", "mybase");
398 verify(fact).makeEntMgrFact(any());
402 public void testConfigureSysProps() throws Exception {
403 feat.globalInit(null, SRC_TEST_RESOURCES);
406 setUpKie("myname", 999L, false);
408 feat.activatePolicySession(polcont, "myname", "mybase");
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 feat.globalInit(null, SRC_TEST_RESOURCES);
420 setUpKie("myname", 999L, false);
422 feat.activatePolicySession(polcont, "myname", "mybase");
424 verify(kieenv, times(4)).set(any(), any());
426 verify(kieenv).set(EnvironmentName.ENTITY_MANAGER_FACTORY, emf);
427 verify(kieenv).set(EnvironmentName.TRANSACTION, usertrans);
428 verify(kieenv).set(EnvironmentName.TRANSACTION_MANAGER, transmgr);
429 verify(kieenv).set(EnvironmentName.TRANSACTION_SYNCHRONIZATION_REGISTRY, transreg);
431 verify(bds, times(1)).close();
435 public void testConfigureKieEnv_RtEx() throws Exception {
436 feat.globalInit(null, SRC_TEST_RESOURCES);
439 setUpKie("myname", 999L, false);
441 when(fact.getUserTrans()).thenThrow(new IllegalArgumentException("expected exception"));
444 feat.activatePolicySession(polcont, "myname", "mybase");
445 fail("missing exception");
447 } catch(IllegalArgumentException ex) {
448 logger.trace("expected exception", ex);
451 verify(bds, times(2)).close();
455 public void testLoadKieSession() throws Exception {
456 feat.globalInit(null, SRC_TEST_RESOURCES);
459 setUpKie("myname", 999L, true);
461 KieSession s = feat.activatePolicySession(polcont, "myname", "mybase");
463 verify(kiestore).loadKieSession(999L, kiebase, kiecfg, kieenv);
464 verify(kiestore, never()).newKieSession(any(), any(), any());
466 assertEquals(s, kiesess);
470 * Verifies that loadKieSession() returns null (thus causing newKieSession()
471 * to be called) when an Exception occurs.
474 public void testLoadKieSession_Ex() throws Exception {
475 feat.globalInit(null, SRC_TEST_RESOURCES);
478 setUpKie("myname", 999L, false);
480 when(kiestore.loadKieSession(anyLong(), any(), any(), any()))
481 .thenThrow(new IllegalArgumentException("expected exception"));
483 KieSession s = feat.activatePolicySession(polcont, "myname", "mybase");
485 verify(kiestore).loadKieSession(anyLong(), any(), any(), any());
486 verify(kiestore).newKieSession(any(), any(), any());
488 assertEquals(s, kiesess);
492 public void testNewKieSession() throws Exception {
493 feat.globalInit(null, SRC_TEST_RESOURCES);
496 setUpKie("myname", 999L, false);
498 KieSession s = feat.activatePolicySession(polcont, "myname", "mybase");
500 verify(kiestore).newKieSession(kiebase, null, kieenv);
502 assertEquals(s, kiesess);
506 public void testLoadDataSource_DiffSession() throws Exception {
507 feat.globalInit(null, SRC_TEST_RESOURCES);
510 setUpKie("myname", 999L, false);
511 feat.activatePolicySession(polcont, "myname", "mybase");
513 ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap = ArgumentCaptor
514 .forClass(PersistenceFeature.ContainerAdjunct.class);
516 verify(polcont).setAdjunct(any(), adjcap.capture());
518 when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
520 setUpKie("myname2", 999L, false);
523 feat.activatePolicySession(polcont, "myname2", "mybase");
525 verify(fact, times(2)).makeEntMgrFact(any());
529 public void testSelectThreadModel_Persistent() throws Exception {
530 setUpKie("myname", 999L, true);
532 ThreadModel m = feat.selectThreadModel(polsess);
534 assertTrue(m instanceof PersistentThreadModel);
539 public void testSelectThreadModel_NotPersistent() throws Exception {
540 when(fact.getPolicyController(any())).thenReturn(polctlr);
541 assertNull(feat.selectThreadModel(polsess));
546 public void testSelectThreadModel_Start__Run_Update_Stop() throws Exception {
547 setUpKie("myname", 999L, true);
549 ThreadModel m = feat.selectThreadModel(polsess);
551 assertTrue(m instanceof PersistentThreadModel);
553 when(polsess.getKieSession()).thenReturn(kiesess);
556 new CountDownLatch(1).await(10, TimeUnit.MILLISECONDS);
562 public void testDisposeKieSession() throws Exception {
563 feat.globalInit(null, SRC_TEST_RESOURCES);
565 ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap = ArgumentCaptor
566 .forClass(PersistenceFeature.ContainerAdjunct.class);
569 setUpKie("myname", 999L, false);
571 feat.activatePolicySession(polcont, "myname", "mybase");
573 verify(emf, never()).close();
574 verify(polcont).setAdjunct(any(), adjcap.capture());
576 when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
578 feat.disposeKieSession(polsess);
580 // call twice to ensure it isn't re-closed
581 feat.disposeKieSession(polsess);
583 verify(emf, times(1)).close();
587 public void testDisposeKieSession_NoAdjunct() throws Exception {
588 feat.globalInit(null, SRC_TEST_RESOURCES);
590 feat.disposeKieSession(polsess);
594 public void testDisposeKieSession_NoPersistence() throws Exception {
595 feat.globalInit(null, SRC_TEST_RESOURCES);
597 ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap = ArgumentCaptor
598 .forClass(PersistenceFeature.ContainerAdjunct.class);
601 setUpKie("myname", 999L, false);
603 feat.activatePolicySession(polcont, "myname", "mybase");
605 verify(emf, never()).close();
606 verify(polcont).setAdjunct(any(), adjcap.capture());
608 when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
610 // specify a session that was never loaded
611 when(polsess.getName()).thenReturn("anotherName");
613 feat.disposeKieSession(polsess);
615 verify(emf, never()).close();
619 public void testDestroyKieSession() throws Exception {
620 feat.globalInit(null, SRC_TEST_RESOURCES);
622 ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap = ArgumentCaptor
623 .forClass(PersistenceFeature.ContainerAdjunct.class);
626 setUpKie("myname", 999L, false);
628 feat.activatePolicySession(polcont, "myname", "mybase");
630 verify(emf, never()).close();
631 verify(polcont).setAdjunct(any(), adjcap.capture());
633 when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
635 feat.destroyKieSession(polsess);
637 // call twice to ensure it isn't re-closed
638 feat.destroyKieSession(polsess);
640 verify(emf, times(1)).close();
644 public void testDestroyKieSession_NoAdjunct() throws Exception {
645 feat.globalInit(null, SRC_TEST_RESOURCES);
647 feat.destroyKieSession(polsess);
651 public void testDestroyKieSession_NoPersistence() throws Exception {
652 feat.globalInit(null, SRC_TEST_RESOURCES);
654 ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap = ArgumentCaptor
655 .forClass(PersistenceFeature.ContainerAdjunct.class);
658 setUpKie("myname", 999L, false);
660 feat.activatePolicySession(polcont, "myname", "mybase");
662 verify(emf, never()).close();
663 verify(polcont).setAdjunct(any(), adjcap.capture());
665 when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
667 // specify a session that was never loaded
668 when(polsess.getName()).thenReturn("anotherName");
670 feat.destroyKieSession(polsess);
672 verify(emf, never()).close();
676 public void testAfterStart() {
677 assertFalse(feat.afterStart(null));
681 public void testBeforeStart() {
682 assertFalse(feat.beforeStart(null));
686 public void testBeforeShutdown() {
687 assertFalse(feat.beforeShutdown(null));
691 public void testAfterShutdown() {
692 assertFalse(feat.afterShutdown(null));
696 public void testBeforeConfigure() {
697 assertFalse(feat.beforeConfigure(null, null));
701 public void testAfterConfigure() {
702 assertFalse(feat.afterConfigure(null));
706 public void testBeforeActivate() {
707 assertFalse(feat.beforeActivate(null));
711 public void testAfterActivate() {
712 assertFalse(feat.afterActivate(null));
716 public void testBeforeDeactivate() {
717 assertFalse(feat.beforeDeactivate(null));
721 public void testAfterDeactivate() {
722 assertFalse(feat.afterDeactivate(null));
726 public void testBeforeStop() {
727 assertFalse(feat.beforeStop(null));
731 public void testAfterStop() {
732 assertFalse(feat.afterStop(null));
736 public void testBeforeLock() {
737 assertFalse(feat.beforeLock(null));
741 public void testAfterLock() {
742 assertFalse(feat.afterLock(null));
746 public void testBeforeUnlock() {
747 assertFalse(feat.beforeUnlock(null));
751 public void testAfterUnlock() {
752 assertFalse(feat.afterUnlock(null));
756 public void testGetPersistenceTimeout_Valid() throws Exception {
757 PreparedStatement s = mockDbConn(5);
759 feat.globalInit(null, SRC_TEST_RESOURCES);
761 setUpKie("myname", 999L, true);
763 feat.activatePolicySession(polcont, "myname", "mybase");
765 verify(s).executeUpdate();
769 public void testGetPersistenceTimeout_Missing() throws Exception {
771 props.remove(DroolsPersistenceProperties.DB_SESSIONINFO_TIMEOUT);
773 PreparedStatement s = mockDbConn(0);
775 feat.globalInit(null, SRC_TEST_RESOURCES);
777 setUpKie("myname", 999L, true);
779 feat.activatePolicySession(polcont, "myname", "mybase");
781 verify(s, never()).executeUpdate();
785 public void testGetPersistenceTimeout_Invalid() throws Exception {
786 props.setProperty(DroolsPersistenceProperties.DB_SESSIONINFO_TIMEOUT, "abc");
787 PreparedStatement s = mockDbConn(0);
789 feat.globalInit(null, SRC_TEST_RESOURCES);
791 setUpKie("myname", 999L, true);
793 feat.activatePolicySession(polcont, "myname", "mybase");
795 verify(s, never()).executeUpdate();
799 public void testCleanUpSessionInfo() throws Exception {
800 setUpKie("myname", 999L, true);
802 // use a real DB so we can verify that the "delete" works correctly
803 fact = new PartialFactory();
804 feat.setFactory(fact);
806 makeSessionInfoTbl(20000);
808 // create mock entity manager for use by JPA connector
809 EntityManager em = mock(EntityManager.class);
810 when(emf.createEntityManager()).thenReturn(em);
812 feat.globalInit(null, SRC_TEST_RESOURCES);
814 feat.beforeStart(null);
815 feat.activatePolicySession(polcont, "myname", "mybase");
817 assertEquals("[1, 4, 5]", getSessions().toString());
821 public void testCleanUpSessionInfo_WithBeforeStart() throws Exception {
822 PreparedStatement s = mockDbConn(0);
824 feat.globalInit(null, SRC_TEST_RESOURCES);
826 setUpKie("myname", 999L, true);
829 feat.beforeStart(null);
831 feat.activatePolicySession(polcont, "myname", "mybase");
832 verify(s, times(1)).executeUpdate();
834 // should not clean-up again
835 feat.activatePolicySession(polcont, "myname", "mybase");
836 feat.activatePolicySession(polcont, "myname", "mybase");
837 verify(s, times(1)).executeUpdate();
840 feat.beforeStart(null);
842 feat.activatePolicySession(polcont, "myname", "mybase");
843 verify(s, times(2)).executeUpdate();
845 // should not clean-up again
846 feat.activatePolicySession(polcont, "myname", "mybase");
847 feat.activatePolicySession(polcont, "myname", "mybase");
848 verify(s, times(2)).executeUpdate();
852 public void testCleanUpSessionInfo_WithBeforeActivate() throws Exception {
853 PreparedStatement s = mockDbConn(0);
855 feat.globalInit(null, SRC_TEST_RESOURCES);
857 setUpKie("myname", 999L, true);
860 feat.beforeActivate(null);
862 feat.activatePolicySession(polcont, "myname", "mybase");
863 verify(s, times(1)).executeUpdate();
865 // should not clean-up again
866 feat.activatePolicySession(polcont, "myname", "mybase");
867 feat.activatePolicySession(polcont, "myname", "mybase");
868 verify(s, times(1)).executeUpdate();
871 feat.beforeActivate(null);
873 feat.activatePolicySession(polcont, "myname", "mybase");
874 verify(s, times(2)).executeUpdate();
876 // should not clean-up again
877 feat.activatePolicySession(polcont, "myname", "mybase");
878 feat.activatePolicySession(polcont, "myname", "mybase");
879 verify(s, times(2)).executeUpdate();
883 public void testCleanUpSessionInfo_NoTimeout() throws Exception {
885 props.remove(DroolsPersistenceProperties.DB_SESSIONINFO_TIMEOUT);
887 PreparedStatement s = mockDbConn(0);
889 feat.globalInit(null, SRC_TEST_RESOURCES);
891 setUpKie("myname", 999L, true);
893 feat.activatePolicySession(polcont, "myname", "mybase");
895 verify(s, never()).executeUpdate();
899 public void testCleanUpSessionInfo_NoUrl() throws Exception {
900 PreparedStatement s = mockDbConn(0);
902 props.remove(DroolsPersistenceProperties.DB_URL);
904 feat.globalInit(null, SRC_TEST_RESOURCES);
906 setUpKie("myname", 999L, true);
909 feat.activatePolicySession(polcont, "myname", "mybase");
910 fail("missing exception");
911 } catch (RuntimeException e) {
912 logger.trace("expected exception", e);
915 verify(s, never()).executeUpdate();
919 public void testCleanUpSessionInfo_NoUser() throws Exception {
920 PreparedStatement s = mockDbConn(0);
922 props.remove(DroolsPersistenceProperties.DB_USER);
924 feat.globalInit(null, SRC_TEST_RESOURCES);
926 setUpKie("myname", 999L, true);
929 feat.activatePolicySession(polcont, "myname", "mybase");
930 fail("missing exception");
931 } catch (RuntimeException e) {
932 logger.trace("expected exception", e);
935 verify(s, never()).executeUpdate();
939 public void testCleanUpSessionInfo_NoPassword() throws Exception {
940 PreparedStatement s = mockDbConn(0);
942 props.remove(DroolsPersistenceProperties.DB_PWD);
944 feat.globalInit(null, SRC_TEST_RESOURCES);
946 setUpKie("myname", 999L, true);
949 feat.activatePolicySession(polcont, "myname", "mybase");
950 fail("missing exception");
951 } catch (RuntimeException e) {
952 logger.trace("expected exception", e);
955 verify(s, never()).executeUpdate();
959 public void testCleanUpSessionInfo_SqlEx() throws Exception {
960 PreparedStatement s = mockDbConn(-1);
962 feat.globalInit(null, SRC_TEST_RESOURCES);
964 setUpKie("myname", 999L, true);
966 feat.activatePolicySession(polcont, "myname", "mybase");
968 verify(s).executeUpdate();
972 public void testGetDroolsSessionConnector() throws Exception {
973 feat.globalInit(null, SRC_TEST_RESOURCES);
976 setUpKie("myname", 999L, true);
978 feat.activatePolicySession(polcont, "myname", "mybase");
980 verify(fact).makeJpaConnector(emf);
984 public void testReplaceSession() throws Exception {
985 feat.globalInit(null, SRC_TEST_RESOURCES);
987 ArgumentCaptor<DroolsSession> sesscap = ArgumentCaptor.forClass(DroolsSession.class);
990 setUpKie("myname", 999L, true);
992 feat.activatePolicySession(polcont, "myname", "mybase");
994 verify(jpa).replace(sesscap.capture());
996 assertEquals("myname", sesscap.getValue().getSessionName());
997 assertEquals(999L, sesscap.getValue().getSessionId());
1001 public void testIsPersistenceEnabled_Auto() throws Exception {
1002 feat.globalInit(null, SRC_TEST_RESOURCES);
1005 setUpKie("myname", 999L, true);
1007 props.setProperty("persistence.type", "auto");
1009 assertNotNull(feat.activatePolicySession(polcont, "myname", "mybase"));
1013 public void testIsPersistenceEnabled_Native() throws Exception {
1014 feat.globalInit(null, SRC_TEST_RESOURCES);
1017 setUpKie("myname", 999L, true);
1019 props.setProperty("persistence.type", "native");
1021 assertNotNull(feat.activatePolicySession(polcont, "myname", "mybase"));
1025 public void testIsPersistenceEnabled_None() throws Exception {
1026 feat.globalInit(null, SRC_TEST_RESOURCES);
1029 setUpKie("myname", 999L, true);
1031 props.remove("persistence.type");
1033 assertNull(feat.activatePolicySession(polcont, "myname", "mybase"));
1037 public void testGetProperties_Ex() throws Exception {
1038 feat.globalInit(null, SRC_TEST_RESOURCES);
1041 setUpKie("myname", 999L, true);
1043 when(fact.getPolicyController(polcont)).thenThrow(new IllegalArgumentException("expected exception"));
1045 assertNull(feat.activatePolicySession(polcont, "myname", "mybase"));
1049 public void testGetProperty_Specific() throws Exception {
1050 feat.globalInit(null, SRC_TEST_RESOURCES);
1053 setUpKie("myname", 999L, true);
1055 props.remove("persistence.type");
1056 props.setProperty("persistence.myname.type", "auto");
1058 assertNotNull(feat.activatePolicySession(polcont, "myname", "mybase"));
1062 public void testGetProperty_Specific_None() throws Exception {
1063 feat.globalInit(null, SRC_TEST_RESOURCES);
1066 setUpKie("myname", 999L, true);
1068 props.remove("persistence.type");
1069 props.setProperty("persistence.xxx.type", "auto");
1071 assertNull(feat.activatePolicySession(polcont, "myname", "mybase"));
1075 public void testGetProperty_Both_SpecificOn() throws Exception {
1076 feat.globalInit(null, SRC_TEST_RESOURCES);
1079 setUpKie("myname", 999L, true);
1081 props.setProperty("persistence.type", "other");
1082 props.setProperty("persistence.myname.type", "auto");
1084 assertNotNull(feat.activatePolicySession(polcont, "myname", "mybase"));
1088 public void testGetProperty_Both_SpecificDisabledOff() throws Exception {
1089 feat.globalInit(null, SRC_TEST_RESOURCES);
1092 setUpKie("myname", 999L, true);
1094 props.setProperty("persistence.type", "auto");
1095 props.setProperty("persistence.myname.type", "other");
1097 assertNull(feat.activatePolicySession(polcont, "myname", "mybase"));
1101 public void testGetProperty_None() throws Exception {
1102 feat.globalInit(null, SRC_TEST_RESOURCES);
1105 setUpKie("myname", 999L, true);
1107 props.remove("persistence.type");
1109 assertNull(feat.activatePolicySession(polcont, "myname", "mybase"));
1113 public void testPersistenceFeatureException() {
1114 SecurityException secex = new SecurityException("expected exception");
1115 PersistenceFeatureException ex = new PersistenceFeatureException(secex);
1117 assertEquals(secex, ex.getCause());
1122 public void testDsEmf_RtEx() throws Exception {
1123 feat.globalInit(null, SRC_TEST_RESOURCES);
1126 setUpKie("myname", 999L, false);
1128 when(fact.makeEntMgrFact(any())).thenThrow(new IllegalArgumentException("expected exception"));
1131 feat.activatePolicySession(polcont, "myname", "mybase");
1132 fail("missing exception");
1134 } catch(IllegalArgumentException ex) {
1135 logger.trace("expected exception", ex);
1138 verify(bds, times(2)).close();
1142 public void testDsEmf_Close_RtEx() throws Exception {
1143 feat.globalInit(null, SRC_TEST_RESOURCES);
1146 setUpKie("myname", 999L, false);
1148 feat.activatePolicySession(polcont, "myname", "mybase");
1150 ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap = ArgumentCaptor
1151 .forClass(PersistenceFeature.ContainerAdjunct.class);
1153 verify(polcont, times(1)).setAdjunct(any(), adjcap.capture());
1155 // return adjunct on next call
1156 when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
1159 doThrow(new IllegalArgumentException("expected exception")).when(emf).close();
1161 feat.destroyKieSession(polsess);
1162 fail("missing exception");
1164 } catch(IllegalArgumentException ex) {
1165 logger.trace("expected exception", ex);
1168 verify(bds, times(2)).close();
1172 public void testDsEmf_CloseDataSource_RtEx() throws Exception {
1173 feat.globalInit(null, SRC_TEST_RESOURCES);
1176 setUpKie("myname", 999L, false);
1178 feat.activatePolicySession(polcont, "myname", "mybase");
1180 ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap = ArgumentCaptor
1181 .forClass(PersistenceFeature.ContainerAdjunct.class);
1183 verify(polcont, times(1)).setAdjunct(any(), adjcap.capture());
1185 // return adjunct on next call
1186 when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
1189 doThrow(new SQLException("expected exception")).when(bds).close();
1191 feat.destroyKieSession(polsess);
1192 fail("missing exception");
1194 } catch(PersistenceFeatureException ex) {
1195 logger.trace("expected exception", ex);
1200 * Gets an ordered list of ids of the current SessionInfo records.
1202 * @return ordered list of SessInfo IDs
1203 * @throws SQLException
1204 * @throws IOException
1206 private List<Integer> getSessions() throws SQLException, IOException {
1209 ArrayList<Integer> lst = new ArrayList<>(5);
1211 try (PreparedStatement stmt = conn.prepareStatement("SELECT id from sessioninfo order by id");
1212 ResultSet rs = stmt.executeQuery()) {
1215 lst.add(rs.getInt(1));
1223 * Sets up for doing invoking the newKieSession() method.
1226 * name to which JPA should respond with a session
1228 * session id to be returned by the session
1230 * {@code true} if loadKieSession() should return a value,
1231 * {@code false} to return null
1234 private void setUpKie(String sessnm, long sessid, boolean loadOk) throws Exception {
1236 when(fact.makeJpaConnector(emf)).thenReturn(jpa);
1237 when(fact.makeEntMgrFact(any())).thenReturn(emf);
1238 when(fact.getPolicyController(polcont)).thenReturn(polctlr);
1240 props.setProperty("persistence.type", "auto");
1242 when(polctlr.getProperties()).thenReturn(props);
1244 when(jpa.get(sessnm)).thenReturn(sess);
1246 when(sess.getSessionId()).thenReturn(sessid);
1248 when(polsess.getPolicyContainer()).thenReturn(polcont);
1249 when(polsess.getName()).thenReturn(sessnm);
1252 when(kiesess.getIdentifier()).thenReturn(sessid);
1253 when(kiestore.loadKieSession(anyLong(), any(), any(), any())).thenReturn(kiesess);
1256 // use an alternate id for the new session
1257 when(kiesess.getIdentifier()).thenReturn(100L);
1258 when(kiestore.loadKieSession(anyLong(), any(), any(), any())).thenReturn(null);
1261 when(kiestore.newKieSession(any(), any(), any())).thenReturn(kiesess);
1265 * Creates the SessionInfo DB table and populates it with some data.
1268 * number of milli-seconds for expired sessioninfo records
1269 * @throws SQLException
1270 * @throws IOException
1272 private void makeSessionInfoTbl(int expMs) throws SQLException, IOException {
1276 try (PreparedStatement stmt = conn
1277 .prepareStatement("CREATE TABLE sessioninfo(id int, lastmodificationdate timestamp)")) {
1279 stmt.executeUpdate();
1282 try (PreparedStatement stmt = conn
1283 .prepareStatement("INSERT into sessioninfo(id, lastmodificationdate) values(?, ?)")) {
1288 ts = new Timestamp(System.currentTimeMillis());
1289 stmt.setTimestamp(2, ts);
1292 stmt.executeUpdate();
1295 stmt.executeUpdate();
1298 stmt.executeUpdate();
1301 ts = new Timestamp(System.currentTimeMillis() - expMs);
1302 stmt.setTimestamp(2, ts);
1305 stmt.executeUpdate();
1308 stmt.executeUpdate();
1313 * Attaches {@link #conn} to the DB, if it isn't already attached.
1315 * @throws SQLException
1316 * @throws IOException
1317 * if the property file cannot be read
1319 private void attachDb() throws SQLException, IOException {
1321 Properties p = loadDbProps();
1323 conn = DriverManager.getConnection(p.getProperty(DroolsPersistenceProperties.DB_URL),
1324 p.getProperty(DroolsPersistenceProperties.DB_USER),
1325 p.getProperty(DroolsPersistenceProperties.DB_PWD));
1326 conn.setAutoCommit(true);
1331 * Loads the DB properties from the file,
1332 * <i>feature-session-persistence.properties</i>.
1334 * @return the properties that were loaded
1335 * @throws IOException
1336 * if the property file cannot be read
1337 * @throws FileNotFoundException
1338 * if the property file does not exist
1340 private Properties loadDbProps() throws IOException, FileNotFoundException {
1342 Properties p = new Properties();
1344 try (FileReader rdr = new FileReader("src/test/resources/feature-session-persistence.properties")) {
1352 * Create a mock DB connection and statement.
1355 * value to be returned when the statement is executed, or
1356 * negative to throw an exception
1357 * @return the statement that will be returned by the connection
1358 * @throws SQLException
1360 private PreparedStatement mockDbConn(int retval) throws SQLException {
1361 Connection c = mock(Connection.class);
1362 PreparedStatement s = mock(PreparedStatement.class);
1364 when(bds.getConnection()).thenReturn(c);
1365 when(fact.makeDataSource(any())).thenReturn(bds);
1366 when(c.prepareStatement(anyString())).thenReturn(s);
1369 // should throw an exception
1370 when(s.executeUpdate()).thenThrow(new SQLException("expected exception"));
1373 // should return the value
1374 when(s.executeUpdate()).thenReturn(retval);
1381 * A partial factory, which exports a few of the real methods, but overrides
1384 private class PartialFactory extends PersistenceFeature.Factory {
1387 public TransactionManager getTransMgr() {
1392 public UserTransaction getUserTrans() {
1397 public TransactionSynchronizationRegistry getTransSyncReg() {
1402 public KieServices getKieServices() {
1407 public EntityManagerFactory makeEntMgrFact(Map<String, Object> props) {
1412 public PolicyController getPolicyController(PolicyContainer container) {