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 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 * Setup before class.
123 * @throws Exception exception
126 public static void setUpBeforeClass() throws Exception {
127 stdprops = new Properties();
129 stdprops.put(DroolsPersistenceProperties.DB_DRIVER, JDBC_DRIVER);
130 stdprops.put(DroolsPersistenceProperties.DB_URL, JDBC_URL);
131 stdprops.put(DroolsPersistenceProperties.DB_USER, JDBC_USER);
132 stdprops.put(DroolsPersistenceProperties.DB_PWD, JDBC_PASSWD);
133 stdprops.put(DroolsPersistenceProperties.JTA_OBJECTSTORE_DIR, JTA_OSDIR);
134 stdprops.put(DroolsPersistenceProperties.DB_SESSIONINFO_TIMEOUT, "50");
136 System.setProperty("com.arjuna.ats.arjuna.objectstore.objectStoreDir", "target/tm");
137 System.setProperty("ObjectStoreEnvironmentBean.objectStoreDir", "target/tm");
143 * @throws Exception exception
146 public void setUp() throws Exception {
147 jpa = mock(JpaDroolsSessionConnector.class);
148 sess = mock(DroolsSession.class);
149 bds = mock(BasicDataSource.class);
150 emf = mock(EntityManagerFactory.class);
151 kiesess = mock(KieSession.class);
153 props = new Properties();
154 kiesvc = mock(KieServices.class);
155 kieenv = mock(Environment.class);
156 kiecfg = mock(KieSessionConfiguration.class);
157 kiebase = mock(KieBase.class);
158 kiestore = mock(KieStoreServices.class);
159 kiecont = mock(KieContainer.class);
160 transmgr = mock(TransactionManager.class);
161 usertrans = mock(UserTransaction.class);
162 transreg = mock(TransactionSynchronizationRegistry.class);
163 polcont = mock(PolicyContainer.class);
164 polctlr = mock(PolicyController.class);
165 polsess = mock(PolicySession.class);
166 fact = mock(PersistenceFeature.Factory.class);
168 feat = new PersistenceFeature();
169 feat.setFactory(fact);
171 props.putAll(stdprops);
173 System.setProperty("com.arjuna.ats.arjuna.objectstore.objectStoreDir", "target/tm");
174 System.setProperty("ObjectStoreEnvironmentBean.objectStoreDir", "target/tm");
176 when(fact.getKieServices()).thenReturn(kiesvc);
177 when(fact.getTransMgr()).thenReturn(transmgr);
178 when(fact.getUserTrans()).thenReturn(usertrans);
179 when(fact.getTransSyncReg()).thenReturn(transreg);
180 when(fact.loadProperties(anyString())).thenReturn(props);
182 when(kiesvc.newEnvironment()).thenReturn(kieenv);
183 when(kiesvc.getStoreServices()).thenReturn(kiestore);
184 when(kiesvc.newKieSessionConfiguration()).thenReturn(kiecfg);
186 when(polcont.getKieContainer()).thenReturn(kiecont);
188 when(polsess.getPolicyContainer()).thenReturn(polcont);
190 when(kiecont.getKieBase(anyString())).thenReturn(kiebase);
197 public void tearDown() {
198 // this will cause the in-memory test DB to be dropped
202 } catch (SQLException e) {
203 logger.warn("failed to close connection", e);
210 } catch (IllegalArgumentException e) {
211 logger.trace("ignored exception", e);
217 public void testGetContainerAdjunct_New() throws Exception {
219 feat.globalInit(null, SRC_TEST_RESOURCES);
222 setUpKie("myname", 999L, true);
224 // force getContainerAdjunct() to be invoked
225 feat.activatePolicySession(polcont, "myname", "mybase");
227 ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
228 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
230 verify(polcont, times(1)).setAdjunct(any(), adjcap.capture());
232 assertNotNull(adjcap.getValue());
236 public void testGetContainerAdjunct_Existing() throws Exception {
238 feat.globalInit(null, SRC_TEST_RESOURCES);
241 setUpKie("myname", 999L, true);
243 // force getContainerAdjunct() to be invoked
244 feat.activatePolicySession(polcont, "myname", "mybase");
246 ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
247 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
249 verify(polcont, times(1)).setAdjunct(any(), adjcap.capture());
251 // return adjunct on next call
252 when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
254 // force getContainerAdjunct() to be invoked again
255 setUpKie("myname2", 999L, true);
256 feat.activatePolicySession(polcont, "myname2", "mybase");
258 // ensure it isn't invoked again
259 verify(polcont, times(1)).setAdjunct(any(), any());
263 public void testGetContainerAdjunct_WrongType() throws Exception {
265 feat.globalInit(null, SRC_TEST_RESOURCES);
268 setUpKie("myname", 999L, true);
270 // return false adjunct on next call
271 when(polcont.getAdjunct(any())).thenReturn("not-a-real-adjunct");
273 // force getContainerAdjunct() to be invoked
274 setUpKie("myname2", 999L, true);
275 feat.activatePolicySession(polcont, "myname2", "mybase");
277 ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
278 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
280 verify(polcont, times(1)).setAdjunct(any(), adjcap.capture());
282 assertNotNull(adjcap.getValue());
286 public void testGetSequenceNumber() {
287 assertEquals(1, feat.getSequenceNumber());
291 public void testGlobalInit() throws Exception {
293 feat.globalInit(null, SRC_TEST_RESOURCES);
295 // verify that various factory methods were invoked
296 verify(fact).getKieServices();
297 verify(fact).loadProperties("src/test/resources/feature-session-persistence.properties");
300 @Test(expected = NullPointerException.class)
301 public void testGlobalInitIoEx() throws Exception {
303 when(fact.loadProperties(anyString())).thenThrow(new IOException("expected exception"));
305 feat.globalInit(null, SRC_TEST_RESOURCES);
309 public void testActivatePolicySession() throws Exception {
310 final PreparedStatement ps = mockDbConn(5);
311 setUpKie("myname", 999L, true);
313 feat.globalInit(null, SRC_TEST_RESOURCES);
314 feat.beforeActivate(null);
316 KieSession session = feat.activatePolicySession(polcont, "myname", "mybase");
318 verify(kiestore).loadKieSession(anyLong(), any(), any(), any());
319 verify(kiestore, never()).newKieSession(any(), any(), any());
321 assertEquals(session, kiesess);
323 verify(ps).executeUpdate();
325 verify(kieenv, times(4)).set(anyString(), any());
327 verify(jpa).get("myname");
328 verify(jpa).replace(any());
332 public void testActivatePolicySession_NoPersistence() throws Exception {
333 feat.globalInit(null, SRC_TEST_RESOURCES);
335 final PreparedStatement ps = mockDbConn(5);
336 setUpKie("myname", 999L, true);
338 props.remove("persistence.type");
340 feat.beforeStart(null);
342 assertNull(feat.activatePolicySession(polcont, "myname", "mybase"));
344 verify(ps, never()).executeUpdate();
345 verify(kiestore, never()).loadKieSession(anyLong(), any(), any(), any());
346 verify(kiestore, never()).newKieSession(any(), any(), any());
349 /** Verifies that a new KIE session is created when there is no existing session entity. */
351 public void testActivatePolicySession_New() throws Exception {
352 feat.globalInit(null, SRC_TEST_RESOURCES);
355 setUpKie("noName", 999L, true);
357 KieSession session = feat.activatePolicySession(polcont, "myname", "mybase");
359 verify(kiestore, never()).loadKieSession(anyLong(), any(), any(), any());
360 verify(kiestore).newKieSession(any(), any(), any());
362 assertEquals(session, kiesess);
364 verify(kieenv, times(4)).set(anyString(), any());
366 verify(jpa).get("myname");
367 verify(jpa).replace(any());
371 * Verifies that a new KIE session is created when there KIE fails to load an existing session.
374 public void testActivatePolicySession_LoadFailed() throws Exception {
375 feat.globalInit(null, SRC_TEST_RESOURCES);
378 setUpKie("myname", 999L, false);
380 KieSession session = feat.activatePolicySession(polcont, "myname", "mybase");
382 verify(kiestore).loadKieSession(anyLong(), any(), any(), any());
383 verify(kiestore).newKieSession(any(), any(), any());
385 assertEquals(session, kiesess);
387 verify(kieenv, times(4)).set(anyString(), any());
389 verify(jpa).get("myname");
391 ArgumentCaptor<DroolsSession> drools = ArgumentCaptor.forClass(DroolsSession.class);
392 verify(jpa).replace(drools.capture());
394 assertEquals("myname", drools.getValue().getSessionName());
395 assertEquals(100L, drools.getValue().getSessionId());
399 public void testLoadDataSource() throws Exception {
400 feat.globalInit(null, SRC_TEST_RESOURCES);
403 setUpKie("myname", 999L, false);
405 feat.activatePolicySession(polcont, "myname", "mybase");
407 verify(fact).makeEntMgrFact(any());
411 public void testConfigureSysProps() throws Exception {
412 feat.globalInit(null, SRC_TEST_RESOURCES);
415 setUpKie("myname", 999L, false);
417 feat.activatePolicySession(polcont, "myname", "mybase");
419 assertEquals("60", System.getProperty("com.arjuna.ats.arjuna.coordinator.defaultTimeout"));
420 assertEquals(JTA_OSDIR, System.getProperty("com.arjuna.ats.arjuna.objectstore.objectStoreDir"));
421 assertEquals(JTA_OSDIR, System.getProperty("ObjectStoreEnvironmentBean.objectStoreDir"));
425 public void testConfigureKieEnv() throws Exception {
426 feat.globalInit(null, SRC_TEST_RESOURCES);
429 setUpKie("myname", 999L, false);
431 feat.activatePolicySession(polcont, "myname", "mybase");
433 verify(kieenv, times(4)).set(any(), any());
435 verify(kieenv).set(EnvironmentName.ENTITY_MANAGER_FACTORY, emf);
436 verify(kieenv).set(EnvironmentName.TRANSACTION, usertrans);
437 verify(kieenv).set(EnvironmentName.TRANSACTION_MANAGER, transmgr);
438 verify(kieenv).set(EnvironmentName.TRANSACTION_SYNCHRONIZATION_REGISTRY, transreg);
440 verify(bds, times(1)).close();
444 public void testConfigureKieEnv_RtEx() throws Exception {
445 feat.globalInit(null, SRC_TEST_RESOURCES);
448 setUpKie("myname", 999L, false);
450 when(fact.getUserTrans()).thenThrow(new IllegalArgumentException("expected exception"));
453 feat.activatePolicySession(polcont, "myname", "mybase");
454 fail("missing exception");
456 } catch (IllegalArgumentException ex) {
457 logger.trace("expected exception", ex);
460 verify(bds, times(2)).close();
464 public void testLoadKieSession() throws Exception {
465 feat.globalInit(null, SRC_TEST_RESOURCES);
468 setUpKie("myname", 999L, true);
470 KieSession session = feat.activatePolicySession(polcont, "myname", "mybase");
472 verify(kiestore).loadKieSession(999L, kiebase, kiecfg, kieenv);
473 verify(kiestore, never()).newKieSession(any(), any(), any());
475 assertEquals(session, kiesess);
479 * Verifies that loadKieSession() returns null (thus causing newKieSession()
480 * to be called) when an Exception occurs.
483 public void testLoadKieSession_Ex() throws Exception {
484 feat.globalInit(null, SRC_TEST_RESOURCES);
487 setUpKie("myname", 999L, false);
489 when(kiestore.loadKieSession(anyLong(), any(), any(), any()))
490 .thenThrow(new IllegalArgumentException("expected exception"));
492 KieSession session = feat.activatePolicySession(polcont, "myname", "mybase");
494 verify(kiestore).loadKieSession(anyLong(), any(), any(), any());
495 verify(kiestore).newKieSession(any(), any(), any());
497 assertEquals(session, kiesess);
501 public void testNewKieSession() throws Exception {
502 feat.globalInit(null, SRC_TEST_RESOURCES);
505 setUpKie("myname", 999L, false);
507 KieSession session = feat.activatePolicySession(polcont, "myname", "mybase");
509 verify(kiestore).newKieSession(kiebase, null, kieenv);
511 assertEquals(session, kiesess);
515 public void testLoadDataSource_DiffSession() throws Exception {
516 feat.globalInit(null, SRC_TEST_RESOURCES);
519 setUpKie("myname", 999L, false);
520 feat.activatePolicySession(polcont, "myname", "mybase");
522 ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
523 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
525 verify(polcont).setAdjunct(any(), adjcap.capture());
527 when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
529 setUpKie("myname2", 999L, false);
532 feat.activatePolicySession(polcont, "myname2", "mybase");
534 verify(fact, times(2)).makeEntMgrFact(any());
538 public void testSelectThreadModel_Persistent() throws Exception {
539 setUpKie("myname", 999L, true);
541 ThreadModel model = feat.selectThreadModel(polsess);
542 assertNotNull(model);
543 assertTrue(model instanceof PersistentThreadModel);
547 public void testSelectThreadModel_NotPersistent() throws Exception {
548 when(fact.getPolicyController(any())).thenReturn(polctlr);
549 assertNull(feat.selectThreadModel(polsess));
553 public void testSelectThreadModel_Start__Run_Update_Stop() throws Exception {
554 setUpKie("myname", 999L, true);
556 ThreadModel model = feat.selectThreadModel(polsess);
557 assertNotNull(model);
558 assertTrue(model instanceof PersistentThreadModel);
560 when(polsess.getKieSession()).thenReturn(kiesess);
563 new CountDownLatch(1).await(10, TimeUnit.MILLISECONDS);
569 public void testDisposeKieSession() throws Exception {
570 feat.globalInit(null, SRC_TEST_RESOURCES);
572 final ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
573 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
576 setUpKie("myname", 999L, false);
578 feat.activatePolicySession(polcont, "myname", "mybase");
580 verify(emf, never()).close();
581 verify(polcont).setAdjunct(any(), adjcap.capture());
583 when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
585 feat.disposeKieSession(polsess);
587 // call twice to ensure it isn't re-closed
588 feat.disposeKieSession(polsess);
590 verify(emf, times(1)).close();
594 public void testDisposeKieSession_NoAdjunct() throws Exception {
595 feat.globalInit(null, SRC_TEST_RESOURCES);
597 feat.disposeKieSession(polsess);
601 public void testDisposeKieSession_NoPersistence() throws Exception {
602 feat.globalInit(null, SRC_TEST_RESOURCES);
604 final ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
605 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
608 setUpKie("myname", 999L, false);
610 feat.activatePolicySession(polcont, "myname", "mybase");
612 verify(emf, never()).close();
613 verify(polcont).setAdjunct(any(), adjcap.capture());
615 when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
617 // specify a session that was never loaded
618 when(polsess.getName()).thenReturn("anotherName");
620 feat.disposeKieSession(polsess);
622 verify(emf, never()).close();
626 public void testDestroyKieSession() throws Exception {
627 feat.globalInit(null, SRC_TEST_RESOURCES);
629 final ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
630 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
633 setUpKie("myname", 999L, false);
635 feat.activatePolicySession(polcont, "myname", "mybase");
637 verify(emf, never()).close();
638 verify(polcont).setAdjunct(any(), adjcap.capture());
640 when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
642 feat.destroyKieSession(polsess);
644 // call twice to ensure it isn't re-closed
645 feat.destroyKieSession(polsess);
647 verify(emf, times(1)).close();
651 public void testDestroyKieSession_NoAdjunct() throws Exception {
652 feat.globalInit(null, SRC_TEST_RESOURCES);
654 feat.destroyKieSession(polsess);
658 public void testDestroyKieSession_NoPersistence() throws Exception {
659 feat.globalInit(null, SRC_TEST_RESOURCES);
661 final ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
662 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
665 setUpKie("myname", 999L, false);
667 feat.activatePolicySession(polcont, "myname", "mybase");
669 verify(emf, never()).close();
670 verify(polcont).setAdjunct(any(), adjcap.capture());
672 when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
674 // specify a session that was never loaded
675 when(polsess.getName()).thenReturn("anotherName");
677 feat.destroyKieSession(polsess);
679 verify(emf, never()).close();
683 public void testAfterStart() {
684 assertFalse(feat.afterStart(null));
688 public void testBeforeStart() {
689 assertFalse(feat.beforeStart(null));
693 public void testBeforeShutdown() {
694 assertFalse(feat.beforeShutdown(null));
698 public void testAfterShutdown() {
699 assertFalse(feat.afterShutdown(null));
703 public void testBeforeConfigure() {
704 assertFalse(feat.beforeConfigure(null, null));
708 public void testAfterConfigure() {
709 assertFalse(feat.afterConfigure(null));
713 public void testBeforeActivate() {
714 assertFalse(feat.beforeActivate(null));
718 public void testAfterActivate() {
719 assertFalse(feat.afterActivate(null));
723 public void testBeforeDeactivate() {
724 assertFalse(feat.beforeDeactivate(null));
728 public void testAfterDeactivate() {
729 assertFalse(feat.afterDeactivate(null));
733 public void testBeforeStop() {
734 assertFalse(feat.beforeStop(null));
738 public void testAfterStop() {
739 assertFalse(feat.afterStop(null));
743 public void testBeforeLock() {
744 assertFalse(feat.beforeLock(null));
748 public void testAfterLock() {
749 assertFalse(feat.afterLock(null));
753 public void testBeforeUnlock() {
754 assertFalse(feat.beforeUnlock(null));
758 public void testAfterUnlock() {
759 assertFalse(feat.afterUnlock(null));
763 public void testGetPersistenceTimeout_Valid() throws Exception {
764 final PreparedStatement statement = mockDbConn(5);
766 feat.globalInit(null, SRC_TEST_RESOURCES);
768 setUpKie("myname", 999L, true);
770 feat.activatePolicySession(polcont, "myname", "mybase");
772 verify(statement).executeUpdate();
776 public void testGetPersistenceTimeout_Missing() throws Exception {
778 props.remove(DroolsPersistenceProperties.DB_SESSIONINFO_TIMEOUT);
780 final PreparedStatement statement = mockDbConn(0);
782 feat.globalInit(null, SRC_TEST_RESOURCES);
784 setUpKie("myname", 999L, true);
786 feat.activatePolicySession(polcont, "myname", "mybase");
788 verify(statement, never()).executeUpdate();
792 public void testGetPersistenceTimeout_Invalid() throws Exception {
793 props.setProperty(DroolsPersistenceProperties.DB_SESSIONINFO_TIMEOUT, "abc");
794 final PreparedStatement s = mockDbConn(0);
796 feat.globalInit(null, SRC_TEST_RESOURCES);
798 setUpKie("myname", 999L, true);
800 feat.activatePolicySession(polcont, "myname", "mybase");
802 verify(s, never()).executeUpdate();
806 public void testCleanUpSessionInfo() throws Exception {
807 setUpKie("myname", 999L, true);
809 // use a real DB so we can verify that the "delete" works correctly
810 fact = new PartialFactory();
811 feat.setFactory(fact);
813 makeSessionInfoTbl(20000);
815 // create mock entity manager for use by JPA connector
816 EntityManager em = mock(EntityManager.class);
817 when(emf.createEntityManager()).thenReturn(em);
819 feat.globalInit(null, SRC_TEST_RESOURCES);
821 feat.beforeStart(null);
822 feat.activatePolicySession(polcont, "myname", "mybase");
824 assertEquals("[1, 4, 5]", getSessions().toString());
828 public void testCleanUpSessionInfo_WithBeforeStart() throws Exception {
829 final PreparedStatement statement = mockDbConn(0);
831 feat.globalInit(null, SRC_TEST_RESOURCES);
833 setUpKie("myname", 999L, true);
836 feat.beforeStart(null);
838 feat.activatePolicySession(polcont, "myname", "mybase");
839 verify(statement, times(1)).executeUpdate();
841 // should not clean-up again
842 feat.activatePolicySession(polcont, "myname", "mybase");
843 feat.activatePolicySession(polcont, "myname", "mybase");
844 verify(statement, times(1)).executeUpdate();
847 feat.beforeStart(null);
849 feat.activatePolicySession(polcont, "myname", "mybase");
850 verify(statement, times(2)).executeUpdate();
852 // should not clean-up again
853 feat.activatePolicySession(polcont, "myname", "mybase");
854 feat.activatePolicySession(polcont, "myname", "mybase");
855 verify(statement, times(2)).executeUpdate();
859 public void testCleanUpSessionInfo_WithBeforeActivate() throws Exception {
860 final PreparedStatement statement = mockDbConn(0);
862 feat.globalInit(null, SRC_TEST_RESOURCES);
864 setUpKie("myname", 999L, true);
867 feat.beforeActivate(null);
869 feat.activatePolicySession(polcont, "myname", "mybase");
870 verify(statement, times(1)).executeUpdate();
872 // should not clean-up again
873 feat.activatePolicySession(polcont, "myname", "mybase");
874 feat.activatePolicySession(polcont, "myname", "mybase");
875 verify(statement, times(1)).executeUpdate();
878 feat.beforeActivate(null);
880 feat.activatePolicySession(polcont, "myname", "mybase");
881 verify(statement, times(2)).executeUpdate();
883 // should not clean-up again
884 feat.activatePolicySession(polcont, "myname", "mybase");
885 feat.activatePolicySession(polcont, "myname", "mybase");
886 verify(statement, times(2)).executeUpdate();
890 public void testCleanUpSessionInfo_NoTimeout() throws Exception {
892 props.remove(DroolsPersistenceProperties.DB_SESSIONINFO_TIMEOUT);
894 final PreparedStatement statement = mockDbConn(0);
896 feat.globalInit(null, SRC_TEST_RESOURCES);
898 setUpKie("myname", 999L, true);
900 feat.activatePolicySession(polcont, "myname", "mybase");
902 verify(statement, never()).executeUpdate();
906 public void testCleanUpSessionInfo_NoUrl() throws Exception {
907 final PreparedStatement statement = mockDbConn(0);
909 props.remove(DroolsPersistenceProperties.DB_URL);
911 feat.globalInit(null, SRC_TEST_RESOURCES);
913 setUpKie("myname", 999L, true);
916 feat.activatePolicySession(polcont, "myname", "mybase");
917 fail("missing exception");
918 } catch (RuntimeException e) {
919 logger.trace("expected exception", e);
922 verify(statement, never()).executeUpdate();
926 public void testCleanUpSessionInfo_NoUser() throws Exception {
927 final PreparedStatement statement = mockDbConn(0);
929 props.remove(DroolsPersistenceProperties.DB_USER);
931 feat.globalInit(null, SRC_TEST_RESOURCES);
933 setUpKie("myname", 999L, true);
936 feat.activatePolicySession(polcont, "myname", "mybase");
937 fail("missing exception");
938 } catch (RuntimeException e) {
939 logger.trace("expected exception", e);
942 verify(statement, never()).executeUpdate();
946 public void testCleanUpSessionInfo_NoPassword() throws Exception {
947 final PreparedStatement statement = mockDbConn(0);
949 props.remove(DroolsPersistenceProperties.DB_PWD);
951 feat.globalInit(null, SRC_TEST_RESOURCES);
953 setUpKie("myname", 999L, true);
956 feat.activatePolicySession(polcont, "myname", "mybase");
957 fail("missing exception");
958 } catch (RuntimeException e) {
959 logger.trace("expected exception", e);
962 verify(statement, never()).executeUpdate();
966 public void testCleanUpSessionInfo_SqlEx() throws Exception {
967 final PreparedStatement statement = mockDbConn(-1);
969 feat.globalInit(null, SRC_TEST_RESOURCES);
971 setUpKie("myname", 999L, true);
973 feat.activatePolicySession(polcont, "myname", "mybase");
975 verify(statement).executeUpdate();
979 public void testGetDroolsSessionConnector() throws Exception {
980 feat.globalInit(null, SRC_TEST_RESOURCES);
983 setUpKie("myname", 999L, true);
985 feat.activatePolicySession(polcont, "myname", "mybase");
987 verify(fact).makeJpaConnector(emf);
991 public void testReplaceSession() throws Exception {
992 feat.globalInit(null, SRC_TEST_RESOURCES);
994 final ArgumentCaptor<DroolsSession> sesscap = ArgumentCaptor.forClass(DroolsSession.class);
997 setUpKie("myname", 999L, true);
999 feat.activatePolicySession(polcont, "myname", "mybase");
1001 verify(jpa).replace(sesscap.capture());
1003 assertEquals("myname", sesscap.getValue().getSessionName());
1004 assertEquals(999L, sesscap.getValue().getSessionId());
1008 public void testIsPersistenceEnabled_Auto() throws Exception {
1009 feat.globalInit(null, SRC_TEST_RESOURCES);
1012 setUpKie("myname", 999L, true);
1014 props.setProperty("persistence.type", "auto");
1016 assertNotNull(feat.activatePolicySession(polcont, "myname", "mybase"));
1020 public void testIsPersistenceEnabled_Native() throws Exception {
1021 feat.globalInit(null, SRC_TEST_RESOURCES);
1024 setUpKie("myname", 999L, true);
1026 props.setProperty("persistence.type", "native");
1028 assertNotNull(feat.activatePolicySession(polcont, "myname", "mybase"));
1032 public void testIsPersistenceEnabled_None() throws Exception {
1033 feat.globalInit(null, SRC_TEST_RESOURCES);
1036 setUpKie("myname", 999L, true);
1038 props.remove("persistence.type");
1040 assertNull(feat.activatePolicySession(polcont, "myname", "mybase"));
1044 public void testGetProperties_Ex() throws Exception {
1045 feat.globalInit(null, SRC_TEST_RESOURCES);
1048 setUpKie("myname", 999L, true);
1050 when(fact.getPolicyController(polcont))
1051 .thenThrow(new IllegalArgumentException("expected exception"));
1053 assertNull(feat.activatePolicySession(polcont, "myname", "mybase"));
1057 public void testGetProperty_Specific() throws Exception {
1058 feat.globalInit(null, SRC_TEST_RESOURCES);
1061 setUpKie("myname", 999L, true);
1063 props.remove("persistence.type");
1064 props.setProperty("persistence.myname.type", "auto");
1066 assertNotNull(feat.activatePolicySession(polcont, "myname", "mybase"));
1070 public void testGetProperty_Specific_None() throws Exception {
1071 feat.globalInit(null, SRC_TEST_RESOURCES);
1074 setUpKie("myname", 999L, true);
1076 props.remove("persistence.type");
1077 props.setProperty("persistence.xxx.type", "auto");
1079 assertNull(feat.activatePolicySession(polcont, "myname", "mybase"));
1083 public void testGetProperty_Both_SpecificOn() throws Exception {
1084 feat.globalInit(null, SRC_TEST_RESOURCES);
1087 setUpKie("myname", 999L, true);
1089 props.setProperty("persistence.type", "other");
1090 props.setProperty("persistence.myname.type", "auto");
1092 assertNotNull(feat.activatePolicySession(polcont, "myname", "mybase"));
1096 public void testGetProperty_Both_SpecificDisabledOff() throws Exception {
1097 feat.globalInit(null, SRC_TEST_RESOURCES);
1100 setUpKie("myname", 999L, true);
1102 props.setProperty("persistence.type", "auto");
1103 props.setProperty("persistence.myname.type", "other");
1105 assertNull(feat.activatePolicySession(polcont, "myname", "mybase"));
1109 public void testGetProperty_None() throws Exception {
1110 feat.globalInit(null, SRC_TEST_RESOURCES);
1113 setUpKie("myname", 999L, true);
1115 props.remove("persistence.type");
1117 assertNull(feat.activatePolicySession(polcont, "myname", "mybase"));
1121 public void testPersistenceFeatureException() {
1122 SecurityException secex = new SecurityException("expected exception");
1123 PersistenceFeatureException ex = new PersistenceFeatureException(secex);
1125 assertEquals(secex, ex.getCause());
1129 public void testDsEmf_RtEx() throws Exception {
1130 feat.globalInit(null, SRC_TEST_RESOURCES);
1133 setUpKie("myname", 999L, false);
1135 when(fact.makeEntMgrFact(any())).thenThrow(new IllegalArgumentException("expected exception"));
1138 feat.activatePolicySession(polcont, "myname", "mybase");
1139 fail("missing exception");
1141 } catch (IllegalArgumentException ex) {
1142 logger.trace("expected exception", ex);
1145 verify(bds, times(2)).close();
1149 public void testDsEmf_Close_RtEx() throws Exception {
1150 feat.globalInit(null, SRC_TEST_RESOURCES);
1153 setUpKie("myname", 999L, false);
1155 feat.activatePolicySession(polcont, "myname", "mybase");
1157 ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
1158 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
1160 verify(polcont, times(1)).setAdjunct(any(), adjcap.capture());
1162 // return adjunct on next call
1163 when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
1166 doThrow(new IllegalArgumentException("expected exception")).when(emf).close();
1168 feat.destroyKieSession(polsess);
1169 fail("missing exception");
1171 } catch (IllegalArgumentException ex) {
1172 logger.trace("expected exception", ex);
1175 verify(bds, times(2)).close();
1179 public void testDsEmf_CloseDataSource_RtEx() throws Exception {
1180 feat.globalInit(null, SRC_TEST_RESOURCES);
1183 setUpKie("myname", 999L, false);
1185 feat.activatePolicySession(polcont, "myname", "mybase");
1187 ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
1188 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
1190 verify(polcont, times(1)).setAdjunct(any(), adjcap.capture());
1192 // return adjunct on next call
1193 when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
1196 doThrow(new SQLException("expected exception")).when(bds).close();
1198 feat.destroyKieSession(polsess);
1199 fail("missing exception");
1201 } catch (PersistenceFeatureException ex) {
1202 logger.trace("expected exception", ex);
1207 * Gets an ordered list of ids of the current SessionInfo records.
1209 * @return ordered list of SessInfo IDs
1210 * @throws SQLException sql exception
1211 * @throws IOException io exception
1213 private List<Integer> getSessions() throws SQLException, IOException {
1216 ArrayList<Integer> lst = new ArrayList<>(5);
1218 try (PreparedStatement stmt = conn.prepareStatement("SELECT id from sessioninfo order by id");
1219 ResultSet rs = stmt.executeQuery()) {
1222 lst.add(rs.getInt(1));
1230 * Sets up for doing invoking the newKieSession() method.
1232 * @param sessnm name to which JPA should respond with a session
1233 * @param sessid session id to be returned by the session
1234 * @param loadOk {@code true} if loadKieSession() should return a value, {@code false} to return
1236 * @throws Exception exception
1238 private void setUpKie(String sessnm, long sessid, boolean loadOk) throws Exception {
1240 when(fact.makeJpaConnector(emf)).thenReturn(jpa);
1241 when(fact.makeEntMgrFact(any())).thenReturn(emf);
1242 when(fact.getPolicyController(polcont)).thenReturn(polctlr);
1244 props.setProperty("persistence.type", "auto");
1246 when(polctlr.getProperties()).thenReturn(props);
1248 when(jpa.get(sessnm)).thenReturn(sess);
1250 when(sess.getSessionId()).thenReturn(sessid);
1252 when(polsess.getPolicyContainer()).thenReturn(polcont);
1253 when(polsess.getName()).thenReturn(sessnm);
1256 when(kiesess.getIdentifier()).thenReturn(sessid);
1257 when(kiestore.loadKieSession(anyLong(), any(), any(), any())).thenReturn(kiesess);
1260 // use an alternate id for the new session
1261 when(kiesess.getIdentifier()).thenReturn(100L);
1262 when(kiestore.loadKieSession(anyLong(), any(), any(), any())).thenReturn(null);
1265 when(kiestore.newKieSession(any(), any(), any())).thenReturn(kiesess);
1269 * Creates the SessionInfo DB table and populates it with some data.
1271 * @param expMs number of milli-seconds for expired sessioninfo records
1272 * @throws SQLException exception
1273 * @throws IOException exception
1275 private void makeSessionInfoTbl(int expMs) throws SQLException, IOException {
1279 try (PreparedStatement stmt =
1280 conn.prepareStatement("CREATE TABLE sessioninfo(id int, lastmodificationdate timestamp)")) {
1282 stmt.executeUpdate();
1285 try (PreparedStatement stmt =
1286 conn.prepareStatement("INSERT into sessioninfo(id, lastmodificationdate) values(?, ?)")) {
1291 ts = new Timestamp(System.currentTimeMillis());
1292 stmt.setTimestamp(2, ts);
1295 stmt.executeUpdate();
1298 stmt.executeUpdate();
1301 stmt.executeUpdate();
1304 ts = new Timestamp(System.currentTimeMillis() - expMs);
1305 stmt.setTimestamp(2, ts);
1308 stmt.executeUpdate();
1311 stmt.executeUpdate();
1316 * Attaches {@link #conn} to the DB, if it isn't already attached.
1318 * @throws SQLException sql exception
1319 * @throws IOException if the property file cannot be read
1321 private void attachDb() throws SQLException, IOException {
1323 Properties props = loadDbProps();
1326 DriverManager.getConnection(
1327 props.getProperty(DroolsPersistenceProperties.DB_URL),
1328 props.getProperty(DroolsPersistenceProperties.DB_USER),
1329 props.getProperty(DroolsPersistenceProperties.DB_PWD));
1330 conn.setAutoCommit(true);
1335 * Loads the DB properties from the file, <i>feature-session-persistence.properties</i>.
1337 * @return the properties that were loaded
1338 * @throws IOException if the property file cannot be read
1339 * @throws FileNotFoundException if the property file does not exist
1341 private Properties loadDbProps() throws IOException, FileNotFoundException {
1343 Properties props = new Properties();
1345 try (FileReader rdr =
1346 new FileReader("src/test/resources/feature-session-persistence.properties")) {
1354 * Create a mock DB connection and statement.
1356 * @param retval value to be returned when the statement is executed, or negative to throw an
1358 * @return the statement that will be returned by the connection
1359 * @throws SQLException sql exception
1361 private PreparedStatement mockDbConn(int retval) throws SQLException {
1362 Connection connection = mock(Connection.class);
1363 PreparedStatement statement = mock(PreparedStatement.class);
1365 when(bds.getConnection()).thenReturn(connection);
1366 when(fact.makeDataSource(any())).thenReturn(bds);
1367 when(connection.prepareStatement(anyString())).thenReturn(statement);
1370 // should throw an exception
1371 when(statement.executeUpdate()).thenThrow(new SQLException("expected exception"));
1374 // should return the value
1375 when(statement.executeUpdate()).thenReturn(retval);
1381 /** A partial factory, which exports a few of the real methods, but overrides the rest. */
1382 private class PartialFactory extends PersistenceFeature.Factory {
1385 public TransactionManager getTransMgr() {
1390 public UserTransaction getUserTrans() {
1395 public TransactionSynchronizationRegistry getTransSyncReg() {
1400 public KieServices getKieServices() {
1405 public EntityManagerFactory makeEntMgrFact(Map<String, Object> props) {
1410 public PolicyController getPolicyController(PolicyContainer container) {