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 TransactionManager transmgr;
118 private UserTransaction usertrans;
119 private TransactionSynchronizationRegistry transreg;
120 private PolicyController polctlr;
121 private PolicyContainer polcont;
122 private PolicySession polsess;
123 private int emfCount;
124 private int jpaCount;
125 private String propName;
127 private PersistenceFeature feat;
130 * Setup before class.
132 * @throws Exception exception
135 public static void setUpBeforeClass() throws Exception {
136 stdprops = new Properties();
138 stdprops.put(DroolsPersistenceProperties.DB_DRIVER, JDBC_DRIVER);
139 stdprops.put(DroolsPersistenceProperties.DB_URL, JDBC_URL);
140 stdprops.put(DroolsPersistenceProperties.DB_USER, JDBC_USER);
141 stdprops.put(DroolsPersistenceProperties.DB_PWD, JDBC_PASSWD);
142 stdprops.put(DroolsPersistenceProperties.JTA_OBJECTSTORE_DIR, JTA_OSDIR);
143 stdprops.put(DroolsPersistenceProperties.DB_SESSIONINFO_TIMEOUT, "50");
145 System.setProperty("com.arjuna.ats.arjuna.objectstore.objectStoreDir", "target/tm");
146 System.setProperty("ObjectStoreEnvironmentBean.objectStoreDir", "target/tm");
152 * @throws Exception exception
155 public void setUp() throws Exception {
156 jpa = mock(JpaDroolsSessionConnector.class);
157 sess = mock(DroolsSession.class);
158 bds = mock(BasicDataSource.class);
159 emf = mock(EntityManagerFactory.class);
160 kiesess = mock(KieSession.class);
162 props = new Properties();
163 kiesvc = mock(KieServices.class);
164 kieenv = mock(Environment.class);
165 kiecfg = mock(KieSessionConfiguration.class);
166 kiebase = mock(KieBase.class);
167 kiestore = mock(KieStoreServices.class);
168 transmgr = mock(TransactionManager.class);
169 usertrans = mock(UserTransaction.class);
170 transreg = mock(TransactionSynchronizationRegistry.class);
171 polcont = mock(PolicyContainer.class);
172 polctlr = mock(PolicyController.class);
173 polsess = mock(PolicySession.class);
178 feat = new PersistenceFeatureImpl();
180 props.putAll(stdprops);
182 System.setProperty("com.arjuna.ats.arjuna.objectstore.objectStoreDir", "target/tm");
183 System.setProperty("ObjectStoreEnvironmentBean.objectStoreDir", "target/tm");
185 when(kiesvc.newEnvironment()).thenReturn(kieenv);
186 when(kiesvc.getStoreServices()).thenReturn(kiestore);
187 when(kiesvc.newKieSessionConfiguration()).thenReturn(kiecfg);
189 KieContainer kiecont = mock(KieContainer.class);
190 when(polcont.getKieContainer()).thenReturn(kiecont);
192 when(polsess.getPolicyContainer()).thenReturn(polcont);
194 when(kiecont.getKieBase(anyString())).thenReturn(kiebase);
201 public void tearDown() {
202 // this will cause the in-memory test DB to be dropped
206 } catch (SQLException e) {
207 logger.warn("failed to close connection", e);
214 } catch (IllegalArgumentException e) {
215 logger.trace("ignored exception", e);
221 public void testGetContainerAdjunct_New() throws Exception {
222 setUpKie(MY_SESS_NAME, 999L, true);
225 // force getContainerAdjunct() to be invoked
226 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
228 ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
229 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
231 verify(polcont, times(1)).setAdjunct(any(), adjcap.capture());
233 assertNotNull(adjcap.getValue());
237 public void testGetContainerAdjunct_Existing() throws Exception {
238 setUpKie(MY_SESS_NAME, 999L, true);
241 // force getContainerAdjunct() to be invoked
242 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
244 ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
245 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
247 verify(polcont, times(1)).setAdjunct(any(), adjcap.capture());
249 // return adjunct on next call
250 when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
252 // force getContainerAdjunct() to be invoked again
253 setUpKie("myname2", 999L, true);
255 feat.activatePolicySession(polcont, "myname2", MY_KIE_BASE);
257 // ensure it isn't invoked again
258 verify(polcont, times(1)).setAdjunct(any(), any());
262 public void testGetContainerAdjunct_WrongType() throws Exception {
263 setUpKie(MY_SESS_NAME, 999L, true);
266 // return false adjunct on next call
267 when(polcont.getAdjunct(any())).thenReturn("not-a-real-adjunct");
269 // force getContainerAdjunct() to be invoked
270 setUpKie("myname2", 999L, true);
272 feat.activatePolicySession(polcont, "myname2", MY_KIE_BASE);
274 ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
275 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
277 verify(polcont, times(1)).setAdjunct(any(), adjcap.capture());
279 assertNotNull(adjcap.getValue());
283 public void testGetSequenceNumber() {
284 assertEquals(1, feat.getSequenceNumber());
288 public void testGlobalInit() throws Exception {
290 feat.globalInit(null, SRC_TEST_RESOURCES);
292 // verify that various factory methods were invoked
293 assertEquals("src/test/resources/feature-session-persistence.properties", propName);
296 @Test(expected = NullPointerException.class)
297 public void testGlobalInitIoEx() throws Exception {
299 feat = new PersistenceFeatureImpl() {
301 protected Properties loadProperties(String filenm) throws IOException {
302 throw new IOException(EXPECTED);
306 feat.globalInit(null, SRC_TEST_RESOURCES);
310 public void testActivatePolicySession() throws Exception {
311 setUpKie(MY_SESS_NAME, 999L, true);
312 final PreparedStatement ps = mockDbConn(5);
314 feat.beforeActivate(null);
316 KieSession session = feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
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(MY_SESS_NAME);
328 verify(jpa).replace(any());
332 public void testActivatePolicySession_NoPersistence() throws Exception {
333 setUpKie(MY_SESS_NAME, 999L, true);
334 final PreparedStatement ps = mockDbConn(5);
336 props.remove("persistence.type");
338 feat.beforeStart(null);
340 assertNull(feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE));
342 verify(ps, never()).executeUpdate();
343 verify(kiestore, never()).loadKieSession(anyLong(), any(), any(), any());
344 verify(kiestore, never()).newKieSession(any(), any(), any());
347 /** Verifies that a new KIE session is created when there is no existing session entity. */
349 public void testActivatePolicySession_New() throws Exception {
350 setUpKie("noName", 999L, true);
353 KieSession session = feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
355 verify(kiestore, never()).loadKieSession(anyLong(), any(), any(), any());
356 verify(kiestore).newKieSession(any(), any(), any());
358 assertEquals(session, kiesess);
360 verify(kieenv, times(4)).set(anyString(), any());
362 verify(jpa).get(MY_SESS_NAME);
363 verify(jpa).replace(any());
367 * Verifies that a new KIE session is created when there KIE fails to load an existing session.
370 public void testActivatePolicySession_LoadFailed() throws Exception {
371 setUpKie(MY_SESS_NAME, 999L, false);
374 KieSession session = feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
376 verify(kiestore).loadKieSession(anyLong(), any(), any(), any());
377 verify(kiestore).newKieSession(any(), any(), any());
379 assertEquals(session, kiesess);
381 verify(kieenv, times(4)).set(anyString(), any());
383 verify(jpa).get(MY_SESS_NAME);
385 ArgumentCaptor<DroolsSession> drools = ArgumentCaptor.forClass(DroolsSession.class);
386 verify(jpa).replace(drools.capture());
388 assertEquals(MY_SESS_NAME, drools.getValue().getSessionName());
389 assertEquals(100L, drools.getValue().getSessionId());
393 public void testLoadDataSource() throws Exception {
394 setUpKie(MY_SESS_NAME, 999L, false);
397 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
399 assertEquals(1, emfCount);
403 public void testConfigureSysProps() throws Exception {
404 setUpKie(MY_SESS_NAME, 999L, false);
407 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
409 assertEquals("60", System.getProperty("com.arjuna.ats.arjuna.coordinator.defaultTimeout"));
410 assertEquals(JTA_OSDIR, System.getProperty("com.arjuna.ats.arjuna.objectstore.objectStoreDir"));
411 assertEquals(JTA_OSDIR, System.getProperty("ObjectStoreEnvironmentBean.objectStoreDir"));
415 public void testConfigureKieEnv() throws Exception {
416 setUpKie(MY_SESS_NAME, 999L, false);
419 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
421 verify(kieenv, times(4)).set(any(), any());
423 verify(kieenv).set(EnvironmentName.ENTITY_MANAGER_FACTORY, emf);
424 verify(kieenv).set(EnvironmentName.TRANSACTION, usertrans);
425 verify(kieenv).set(EnvironmentName.TRANSACTION_MANAGER, transmgr);
426 verify(kieenv).set(EnvironmentName.TRANSACTION_SYNCHRONIZATION_REGISTRY, transreg);
428 verify(bds, times(1)).close();
432 public void testConfigureKieEnv_RtEx() throws Exception {
433 setUpKie(MY_SESS_NAME, 999L, false);
436 feat = new PersistenceFeatureMockDb() {
438 protected UserTransaction getUserTrans() {
439 throw new IllegalArgumentException(EXPECTED);
443 feat.globalInit(null, SRC_TEST_RESOURCES);
446 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
447 fail(MISSING_EXCEPTION);
449 } catch (IllegalArgumentException ex) {
450 logger.trace(EXPECTED, ex);
453 verify(bds, times(2)).close();
457 public void testLoadKieSession() throws Exception {
458 setUpKie(MY_SESS_NAME, 999L, true);
461 KieSession session = feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
463 verify(kiestore).loadKieSession(999L, kiebase, kiecfg, kieenv);
464 verify(kiestore, never()).newKieSession(any(), any(), any());
466 assertEquals(session, 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 setUpKie(MY_SESS_NAME, 999L, false);
478 when(kiestore.loadKieSession(anyLong(), any(), any(), any()))
479 .thenThrow(new IllegalArgumentException(EXPECTED));
481 KieSession session = feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
483 verify(kiestore).loadKieSession(anyLong(), any(), any(), any());
484 verify(kiestore).newKieSession(any(), any(), any());
486 assertEquals(session, kiesess);
490 public void testNewKieSession() throws Exception {
491 setUpKie(MY_SESS_NAME, 999L, false);
494 KieSession session = feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
496 verify(kiestore).newKieSession(kiebase, null, kieenv);
498 assertEquals(session, kiesess);
502 public void testLoadDataSource_DiffSession() throws Exception {
503 setUpKie(MY_SESS_NAME, 999L, false);
506 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
508 ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
509 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
511 verify(polcont).setAdjunct(any(), adjcap.capture());
513 when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
515 setUpKie("myname2", 999L, false);
519 feat.activatePolicySession(polcont, "myname2", MY_KIE_BASE);
521 assertEquals(2, emfCount);
525 public void testSelectThreadModel_Persistent() throws Exception {
526 setUpKie(MY_SESS_NAME, 999L, true);
528 ThreadModel model = feat.selectThreadModel(polsess);
529 assertNotNull(model);
530 assertTrue(model instanceof PersistentThreadModel);
534 public void testSelectThreadModel_NotPersistent() throws Exception {
535 assertNull(feat.selectThreadModel(polsess));
539 public void testSelectThreadModel_Start__Run_Update_Stop() throws Exception {
540 setUpKie(MY_SESS_NAME, 999L, true);
542 ThreadModel model = feat.selectThreadModel(polsess);
543 assertNotNull(model);
544 assertTrue(model instanceof PersistentThreadModel);
546 when(polsess.getKieSession()).thenReturn(kiesess);
549 new CountDownLatch(1).await(10, TimeUnit.MILLISECONDS);
555 public void testDisposeKieSession() throws Exception {
556 setUpKie(MY_SESS_NAME, 999L, false);
559 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
561 verify(emf, never()).close();
563 final ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
564 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
566 verify(polcont).setAdjunct(any(), adjcap.capture());
568 when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
570 feat.disposeKieSession(polsess);
572 // call twice to ensure it isn't re-closed
573 feat.disposeKieSession(polsess);
575 verify(emf, times(1)).close();
579 public void testDisposeKieSession_NoAdjunct() throws Exception {
580 feat.globalInit(null, SRC_TEST_RESOURCES);
582 feat.disposeKieSession(polsess);
586 public void testDisposeKieSession_NoPersistence() throws Exception {
587 setUpKie(MY_SESS_NAME, 999L, false);
590 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
592 verify(emf, never()).close();
594 final ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
595 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
597 verify(polcont).setAdjunct(any(), adjcap.capture());
599 when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
601 // specify a session that was never loaded
602 when(polsess.getName()).thenReturn("anotherName");
604 feat.disposeKieSession(polsess);
606 verify(emf, never()).close();
610 public void testDestroyKieSession() throws Exception {
611 setUpKie(MY_SESS_NAME, 999L, false);
614 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
616 verify(emf, never()).close();
618 final ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
619 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
621 verify(polcont).setAdjunct(any(), adjcap.capture());
623 when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
625 feat.destroyKieSession(polsess);
627 // call twice to ensure it isn't re-closed
628 feat.destroyKieSession(polsess);
630 verify(emf, times(1)).close();
634 public void testDestroyKieSession_NoAdjunct() throws Exception {
635 feat.globalInit(null, SRC_TEST_RESOURCES);
637 feat.destroyKieSession(polsess);
641 public void testDestroyKieSession_NoPersistence() throws Exception {
642 setUpKie(MY_SESS_NAME, 999L, false);
645 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
647 verify(emf, never()).close();
649 final ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
650 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
652 verify(polcont).setAdjunct(any(), adjcap.capture());
654 when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
656 // specify a session that was never loaded
657 when(polsess.getName()).thenReturn("anotherName");
659 feat.destroyKieSession(polsess);
661 verify(emf, never()).close();
665 public void testAfterStart() {
666 assertFalse(feat.afterStart(null));
670 public void testBeforeStart() {
671 assertFalse(feat.beforeStart(null));
675 public void testBeforeShutdown() {
676 assertFalse(feat.beforeShutdown(null));
680 public void testAfterShutdown() {
681 assertFalse(feat.afterShutdown(null));
685 public void testBeforeConfigure() {
686 assertFalse(feat.beforeConfigure(null, null));
690 public void testAfterConfigure() {
691 assertFalse(feat.afterConfigure(null));
695 public void testBeforeActivate() {
696 assertFalse(feat.beforeActivate(null));
700 public void testAfterActivate() {
701 assertFalse(feat.afterActivate(null));
705 public void testBeforeDeactivate() {
706 assertFalse(feat.beforeDeactivate(null));
710 public void testAfterDeactivate() {
711 assertFalse(feat.afterDeactivate(null));
715 public void testBeforeStop() {
716 assertFalse(feat.beforeStop(null));
720 public void testAfterStop() {
721 assertFalse(feat.afterStop(null));
725 public void testBeforeLock() {
726 assertFalse(feat.beforeLock(null));
730 public void testAfterLock() {
731 assertFalse(feat.afterLock(null));
735 public void testBeforeUnlock() {
736 assertFalse(feat.beforeUnlock(null));
740 public void testAfterUnlock() {
741 assertFalse(feat.afterUnlock(null));
745 public void testGetPersistenceTimeout_Valid() throws Exception {
746 setUpKie(MY_SESS_NAME, 999L, true);
747 final PreparedStatement statement = mockDbConn(5);
749 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
751 verify(statement).executeUpdate();
755 public void testGetPersistenceTimeout_Missing() throws Exception {
757 props.remove(DroolsPersistenceProperties.DB_SESSIONINFO_TIMEOUT);
759 setUpKie(MY_SESS_NAME, 999L, true);
760 final PreparedStatement statement = mockDbConn(0);
762 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
764 verify(statement, never()).executeUpdate();
768 public void testGetPersistenceTimeout_Invalid() throws Exception {
769 props.setProperty(DroolsPersistenceProperties.DB_SESSIONINFO_TIMEOUT, "abc");
771 setUpKie(MY_SESS_NAME, 999L, true);
772 final PreparedStatement s = mockDbConn(0);
774 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
776 verify(s, never()).executeUpdate();
780 public void testCleanUpSessionInfo() throws Exception {
781 setUpKie(MY_SESS_NAME, 999L, true);
783 // use a real DB so we can verify that the "delete" works correctly
784 feat = new PartialFeature();
786 makeSessionInfoTbl(20000);
788 // create mock entity manager for use by JPA connector
789 EntityManager em = mock(EntityManager.class);
790 when(emf.createEntityManager()).thenReturn(em);
792 feat.globalInit(null, SRC_TEST_RESOURCES);
794 feat.beforeStart(null);
795 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
797 assertEquals("[1, 4, 5]", getSessions().toString());
801 public void testCleanUpSessionInfo_WithBeforeStart() throws Exception {
802 setUpKie(MY_SESS_NAME, 999L, true);
803 final PreparedStatement statement = mockDbConn(0);
806 feat.beforeStart(null);
808 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
809 verify(statement, times(1)).executeUpdate();
811 // should not clean-up again
812 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
813 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
814 verify(statement, times(1)).executeUpdate();
817 feat.beforeStart(null);
819 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
820 verify(statement, times(2)).executeUpdate();
822 // should not clean-up again
823 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
824 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
825 verify(statement, times(2)).executeUpdate();
829 public void testCleanUpSessionInfo_WithBeforeActivate() throws Exception {
830 setUpKie(MY_SESS_NAME, 999L, true);
831 final PreparedStatement statement = mockDbConn(0);
834 feat.beforeActivate(null);
836 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
837 verify(statement, times(1)).executeUpdate();
839 // should not clean-up again
840 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
841 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
842 verify(statement, times(1)).executeUpdate();
845 feat.beforeActivate(null);
847 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
848 verify(statement, times(2)).executeUpdate();
850 // should not clean-up again
851 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
852 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
853 verify(statement, times(2)).executeUpdate();
857 public void testCleanUpSessionInfo_NoTimeout() throws Exception {
859 props.remove(DroolsPersistenceProperties.DB_SESSIONINFO_TIMEOUT);
861 setUpKie(MY_SESS_NAME, 999L, true);
862 final PreparedStatement statement = mockDbConn(0);
864 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
866 verify(statement, never()).executeUpdate();
870 public void testCleanUpSessionInfo_NoUrl() throws Exception {
871 props.remove(DroolsPersistenceProperties.DB_URL);
873 setUpKie(MY_SESS_NAME, 999L, true);
874 final PreparedStatement statement = mockDbConn(0);
877 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
878 fail(MISSING_EXCEPTION);
879 } catch (RuntimeException e) {
880 logger.trace(EXPECTED, e);
883 verify(statement, never()).executeUpdate();
887 public void testCleanUpSessionInfo_NoUser() throws Exception {
888 props.remove(DroolsPersistenceProperties.DB_USER);
890 setUpKie(MY_SESS_NAME, 999L, true);
891 final PreparedStatement statement = mockDbConn(0);
894 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
895 fail(MISSING_EXCEPTION);
896 } catch (RuntimeException e) {
897 logger.trace(EXPECTED, e);
900 verify(statement, never()).executeUpdate();
904 public void testCleanUpSessionInfo_NoPassword() throws Exception {
905 props.remove(DroolsPersistenceProperties.DB_PWD);
907 setUpKie(MY_SESS_NAME, 999L, true);
908 final PreparedStatement statement = mockDbConn(0);
911 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
912 fail(MISSING_EXCEPTION);
913 } catch (RuntimeException e) {
914 logger.trace(EXPECTED, e);
917 verify(statement, never()).executeUpdate();
921 public void testCleanUpSessionInfo_SqlEx() throws Exception {
922 setUpKie(MY_SESS_NAME, 999L, true);
923 final PreparedStatement statement = mockDbConn(-1);
925 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
927 verify(statement).executeUpdate();
931 public void testGetDroolsSessionConnector() throws Exception {
932 setUpKie(MY_SESS_NAME, 999L, true);
935 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
937 assertEquals(1, jpaCount);
941 public void testReplaceSession() throws Exception {
942 setUpKie(MY_SESS_NAME, 999L, true);
945 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
947 final ArgumentCaptor<DroolsSession> sesscap = ArgumentCaptor.forClass(DroolsSession.class);
949 verify(jpa).replace(sesscap.capture());
951 assertEquals(MY_SESS_NAME, sesscap.getValue().getSessionName());
952 assertEquals(999L, sesscap.getValue().getSessionId());
956 public void testIsPersistenceEnabled_Auto() throws Exception {
957 setUpKie(MY_SESS_NAME, 999L, true);
960 props.setProperty("persistence.type", "auto");
962 assertNotNull(feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE));
966 public void testIsPersistenceEnabled_Native() throws Exception {
967 setUpKie(MY_SESS_NAME, 999L, true);
970 props.setProperty("persistence.type", "native");
972 assertNotNull(feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE));
976 public void testIsPersistenceEnabled_None() throws Exception {
977 setUpKie(MY_SESS_NAME, 999L, true);
980 props.remove("persistence.type");
982 assertNull(feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE));
986 public void testGetProperties_Ex() throws Exception {
987 setUpKie(MY_SESS_NAME, 999L, true);
990 feat = new PersistenceFeatureMockDb() {
992 protected PolicyController getPolicyController(PolicyContainer container) {
993 throw new IllegalArgumentException(EXPECTED);
997 assertNull(feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE));
1001 public void testGetProperty_Specific() throws Exception {
1002 setUpKie(MY_SESS_NAME, 999L, true);
1005 props.remove("persistence.type");
1006 props.setProperty("persistence.myname.type", "auto");
1008 assertNotNull(feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE));
1012 public void testGetProperty_Specific_None() throws Exception {
1013 setUpKie(MY_SESS_NAME, 999L, true);
1016 props.remove("persistence.type");
1017 props.setProperty("persistence.xxx.type", "auto");
1019 assertNull(feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE));
1023 public void testGetProperty_Both_SpecificOn() throws Exception {
1024 setUpKie(MY_SESS_NAME, 999L, true);
1027 props.setProperty("persistence.type", "other");
1028 props.setProperty("persistence.myname.type", "auto");
1030 assertNotNull(feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE));
1034 public void testGetProperty_Both_SpecificDisabledOff() throws Exception {
1035 setUpKie(MY_SESS_NAME, 999L, true);
1038 props.setProperty("persistence.type", "auto");
1039 props.setProperty("persistence.myname.type", "other");
1041 assertNull(feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE));
1045 public void testGetProperty_None() throws Exception {
1046 setUpKie(MY_SESS_NAME, 999L, true);
1049 props.remove("persistence.type");
1051 assertNull(feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE));
1055 public void testPersistenceFeatureException() {
1056 SecurityException secex = new SecurityException(EXPECTED);
1057 PersistenceFeatureException ex = new PersistenceFeatureException(secex);
1059 assertEquals(secex, ex.getCause());
1063 public void testDsEmf_RtEx() throws Exception {
1064 setUpKie(MY_SESS_NAME, 999L, false);
1067 feat = new PersistenceFeatureMockDb() {
1069 protected EntityManagerFactory makeEntMgrFact(Map<String, Object> props) {
1070 throw new IllegalArgumentException(EXPECTED);
1074 feat.globalInit(null, SRC_TEST_RESOURCES);
1077 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
1078 fail(MISSING_EXCEPTION);
1080 } catch (IllegalArgumentException ex) {
1081 logger.trace(EXPECTED, ex);
1084 verify(bds, times(2)).close();
1088 public void testDsEmf_Close_RtEx() throws Exception {
1089 setUpKie(MY_SESS_NAME, 999L, false);
1092 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
1094 ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
1095 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
1097 verify(polcont, times(1)).setAdjunct(any(), adjcap.capture());
1099 // return adjunct on next call
1100 when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
1103 doThrow(new IllegalArgumentException(EXPECTED)).when(emf).close();
1105 feat.destroyKieSession(polsess);
1106 fail(MISSING_EXCEPTION);
1108 } catch (IllegalArgumentException ex) {
1109 logger.trace(EXPECTED, ex);
1112 verify(bds, times(2)).close();
1116 public void testDsEmf_CloseDataSource_RtEx() throws Exception {
1117 setUpKie(MY_SESS_NAME, 999L, false);
1120 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
1122 ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
1123 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
1125 verify(polcont, times(1)).setAdjunct(any(), adjcap.capture());
1127 // return adjunct on next call
1128 when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
1131 doThrow(new SQLException(EXPECTED)).when(bds).close();
1133 feat.destroyKieSession(polsess);
1134 fail(MISSING_EXCEPTION);
1136 } catch (PersistenceFeatureException ex) {
1137 logger.trace(EXPECTED, ex);
1142 * Gets an ordered list of ids of the current SessionInfo records.
1144 * @return ordered list of SessInfo IDs
1145 * @throws SQLException sql exception
1146 * @throws IOException io exception
1148 private List<Integer> getSessions() throws SQLException, IOException {
1151 ArrayList<Integer> lst = new ArrayList<>(5);
1153 try (PreparedStatement stmt = conn.prepareStatement("SELECT id from sessioninfo order by id");
1154 ResultSet rs = stmt.executeQuery()) {
1157 lst.add(rs.getInt(1));
1165 * Sets up for doing invoking the newKieSession() method.
1167 * @param sessnm name to which JPA should respond with a session
1168 * @param sessid session id to be returned by the session
1169 * @param loadOk {@code true} if loadKieSession() should return a value, {@code false} to return
1171 * @throws Exception exception
1173 private void setUpKie(String sessnm, long sessid, boolean loadOk) throws Exception {
1174 props.setProperty("persistence.type", "auto");
1176 when(polctlr.getProperties()).thenReturn(props);
1178 when(jpa.get(sessnm)).thenReturn(sess);
1180 when(sess.getSessionId()).thenReturn(sessid);
1182 when(polsess.getPolicyContainer()).thenReturn(polcont);
1183 when(polsess.getName()).thenReturn(sessnm);
1186 when(kiesess.getIdentifier()).thenReturn(sessid);
1187 when(kiestore.loadKieSession(anyLong(), any(), any(), any())).thenReturn(kiesess);
1190 // use an alternate id for the new session
1191 when(kiesess.getIdentifier()).thenReturn(100L);
1192 when(kiestore.loadKieSession(anyLong(), any(), any(), any())).thenReturn(null);
1195 when(kiestore.newKieSession(any(), any(), any())).thenReturn(kiesess);
1197 feat = new PersistenceFeatureKie();
1198 feat.globalInit(null, SRC_TEST_RESOURCES);
1202 * Creates the SessionInfo DB table and populates it with some data.
1204 * @param expMs number of milli-seconds for expired sessioninfo records
1205 * @throws SQLException exception
1206 * @throws IOException exception
1208 private void makeSessionInfoTbl(int expMs) throws SQLException, IOException {
1212 try (PreparedStatement stmt =
1213 conn.prepareStatement("CREATE TABLE sessioninfo(id int, lastmodificationdate timestamp)")) {
1215 stmt.executeUpdate();
1218 try (PreparedStatement stmt =
1219 conn.prepareStatement("INSERT into sessioninfo(id, lastmodificationdate) values(?, ?)")) {
1224 ts = new Timestamp(System.currentTimeMillis());
1225 stmt.setTimestamp(2, ts);
1228 stmt.executeUpdate();
1231 stmt.executeUpdate();
1234 stmt.executeUpdate();
1237 ts = new Timestamp(System.currentTimeMillis() - expMs);
1238 stmt.setTimestamp(2, ts);
1241 stmt.executeUpdate();
1244 stmt.executeUpdate();
1249 * Attaches {@link #conn} to the DB, if it isn't already attached.
1251 * @throws SQLException sql exception
1252 * @throws IOException if the property file cannot be read
1254 private void attachDb() throws SQLException, IOException {
1256 Properties props = loadDbProps();
1259 DriverManager.getConnection(
1260 props.getProperty(DroolsPersistenceProperties.DB_URL),
1261 props.getProperty(DroolsPersistenceProperties.DB_USER),
1262 props.getProperty(DroolsPersistenceProperties.DB_PWD));
1263 conn.setAutoCommit(true);
1268 * Loads the DB properties from the file, <i>feature-session-persistence.properties</i>.
1270 * @return the properties that were loaded
1271 * @throws IOException if the property file cannot be read
1272 * @throws FileNotFoundException if the property file does not exist
1274 private Properties loadDbProps() throws IOException, FileNotFoundException {
1276 Properties props = new Properties();
1278 try (FileReader rdr =
1279 new FileReader("src/test/resources/feature-session-persistence.properties")) {
1287 * Create a mock DB connection and statement.
1289 * @param retval value to be returned when the statement is executed, or negative to throw an
1291 * @return the statement that will be returned by the connection
1292 * @throws SQLException sql exception
1294 private PreparedStatement mockDbConn(int retval) throws SQLException {
1295 Connection connection = mock(Connection.class);
1296 PreparedStatement statement = mock(PreparedStatement.class);
1298 when(bds.getConnection()).thenReturn(connection);
1299 when(connection.prepareStatement(anyString())).thenReturn(statement);
1302 // should throw an exception
1303 when(statement.executeUpdate()).thenThrow(new SQLException(EXPECTED));
1306 // should return the value
1307 when(statement.executeUpdate()).thenReturn(retval);
1310 feat = new PersistenceFeatureMockDb();
1311 feat.globalInit(null, SRC_TEST_RESOURCES);
1317 * Feature with a mock DB.
1319 private class PersistenceFeatureMockDb extends PersistenceFeatureKie {
1322 protected BasicDataSource makeDataSource(Properties dsProps) {
1328 * Feature supporting newKieSession.
1330 private class PersistenceFeatureKie extends PersistenceFeatureImpl {
1333 protected EntityManagerFactory makeEntMgrFact(Map<String, Object> props) {
1339 protected DroolsSessionConnector makeJpaConnector(EntityManagerFactory emf) {
1346 * Feature with overrides.
1348 private class PersistenceFeatureImpl extends PartialFeature {
1351 protected Properties loadProperties(String filenm) throws IOException {
1357 protected BasicDataSource makeDataSource(Properties dsProps) {
1362 protected DroolsSessionConnector makeJpaConnector(EntityManagerFactory emf) {
1369 * Feature with <i>some</i> overrides.
1371 private class PartialFeature extends PersistenceFeature {
1374 protected TransactionManager getTransMgr() {
1379 protected UserTransaction getUserTrans() {
1384 protected TransactionSynchronizationRegistry getTransSyncReg() {
1389 protected KieServices getKieServices() {
1394 protected EntityManagerFactory makeEntMgrFact(Map<String, Object> props) {
1400 protected PolicyController getPolicyController(PolicyContainer container) {