2 * ============LICENSE_START=======================================================
3 * feature-session-persistence
4 * ================================================================================
5 * Copyright (C) 2017-2018, 2020 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.assertj.core.api.Assertions.assertThatCode;
24 import static org.junit.Assert.assertEquals;
25 import static org.junit.Assert.assertFalse;
26 import static org.junit.Assert.assertNotNull;
27 import static org.junit.Assert.assertNull;
28 import static org.junit.Assert.assertTrue;
29 import static org.junit.Assert.fail;
30 import static org.mockito.ArgumentMatchers.any;
31 import static org.mockito.ArgumentMatchers.anyLong;
32 import static org.mockito.ArgumentMatchers.anyString;
33 import static org.mockito.Mockito.doThrow;
34 import static org.mockito.Mockito.mock;
35 import static org.mockito.Mockito.never;
36 import static org.mockito.Mockito.times;
37 import static org.mockito.Mockito.verify;
38 import static org.mockito.Mockito.when;
40 import java.io.FileNotFoundException;
41 import java.io.FileReader;
42 import java.io.IOException;
43 import java.sql.Connection;
44 import java.sql.DriverManager;
45 import java.sql.PreparedStatement;
46 import java.sql.ResultSet;
47 import java.sql.SQLException;
48 import java.sql.Timestamp;
49 import java.util.ArrayList;
50 import java.util.List;
52 import java.util.Properties;
53 import java.util.concurrent.CountDownLatch;
54 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;
60 import org.apache.commons.dbcp2.BasicDataSource;
61 import org.junit.After;
62 import org.junit.Before;
63 import org.junit.BeforeClass;
64 import org.junit.Test;
65 import org.kie.api.KieBase;
66 import org.kie.api.KieServices;
67 import org.kie.api.persistence.jpa.KieStoreServices;
68 import org.kie.api.runtime.Environment;
69 import org.kie.api.runtime.EnvironmentName;
70 import org.kie.api.runtime.KieContainer;
71 import org.kie.api.runtime.KieSession;
72 import org.kie.api.runtime.KieSessionConfiguration;
73 import org.mockito.ArgumentCaptor;
74 import org.onap.policy.drools.core.PolicyContainer;
75 import org.onap.policy.drools.core.PolicySession;
76 import org.onap.policy.drools.core.PolicySession.ThreadModel;
77 import org.onap.policy.drools.persistence.PersistenceFeature.PersistenceFeatureException;
78 import org.onap.policy.drools.persistence.PersistenceFeature.PersistentThreadModel;
79 import org.onap.policy.drools.system.PolicyController;
80 import org.slf4j.Logger;
81 import org.slf4j.LoggerFactory;
83 public class PersistenceFeatureTest {
85 private static final String MY_KIE_BASE = "mybase";
87 private static final String MY_SESS_NAME = "myname";
89 private static final String MISSING_EXCEPTION = "missing exception";
91 private static final String EXPECTED = "expected exception";
93 private static final Logger logger = LoggerFactory.getLogger(PersistenceFeatureTest.class);
95 private static final String JDBC_DRIVER = "fake.driver";
96 private static final String JDBC_URL = "fake.url";
97 private static final String JDBC_USER = "fake.user";
98 private static final String JDBC_PASSWD = "fake.password";
99 private static final String JTA_OSDIR = "target";
100 private static final String SRC_TEST_RESOURCES = "src/test/resources";
102 private static Properties stdprops;
104 private JpaDroolsSessionConnector jpa;
105 private DroolsSession sess;
106 private KieSession kiesess;
107 private BasicDataSource bds;
108 private EntityManagerFactory emf;
109 private Connection conn;
110 private Properties props;
111 private KieServices kiesvc;
112 private Environment kieenv;
113 private KieSessionConfiguration kiecfg;
114 private KieBase kiebase;
115 private KieStoreServices kiestore;
116 private TransactionManager transmgr;
117 private UserTransaction usertrans;
118 private TransactionSynchronizationRegistry transreg;
119 private PolicyController polctlr;
120 private PolicyContainer polcont;
121 private PolicySession polsess;
122 private int emfCount;
123 private int jpaCount;
124 private String propName;
126 private PersistenceFeature feat;
129 * Setup before class.
131 * @throws Exception exception
134 public static void setUpBeforeClass() throws Exception {
135 stdprops = new Properties();
137 stdprops.put(DroolsPersistenceProperties.DB_DRIVER, JDBC_DRIVER);
138 stdprops.put(DroolsPersistenceProperties.DB_URL, JDBC_URL);
139 stdprops.put(DroolsPersistenceProperties.DB_USER, JDBC_USER);
140 stdprops.put(DroolsPersistenceProperties.DB_PWD, JDBC_PASSWD);
141 stdprops.put(DroolsPersistenceProperties.JTA_OBJECTSTORE_DIR, JTA_OSDIR);
142 stdprops.put(DroolsPersistenceProperties.DB_SESSIONINFO_TIMEOUT, "50");
144 System.setProperty("com.arjuna.ats.arjuna.objectstore.objectStoreDir", "target/tm");
145 System.setProperty("ObjectStoreEnvironmentBean.objectStoreDir", "target/tm");
151 * @throws Exception exception
154 public void setUp() throws Exception {
155 jpa = mock(JpaDroolsSessionConnector.class);
156 sess = mock(DroolsSession.class);
157 bds = mock(BasicDataSource.class);
158 emf = mock(EntityManagerFactory.class);
159 kiesess = mock(KieSession.class);
161 props = new Properties();
162 kiesvc = mock(KieServices.class);
163 kieenv = mock(Environment.class);
164 kiecfg = mock(KieSessionConfiguration.class);
165 kiebase = mock(KieBase.class);
166 kiestore = mock(KieStoreServices.class);
167 transmgr = mock(TransactionManager.class);
168 usertrans = mock(UserTransaction.class);
169 transreg = mock(TransactionSynchronizationRegistry.class);
170 polcont = mock(PolicyContainer.class);
171 polctlr = mock(PolicyController.class);
172 polsess = mock(PolicySession.class);
177 feat = new PersistenceFeatureImpl();
179 props.putAll(stdprops);
181 System.setProperty("com.arjuna.ats.arjuna.objectstore.objectStoreDir", "target/tm");
182 System.setProperty("ObjectStoreEnvironmentBean.objectStoreDir", "target/tm");
184 when(kiesvc.newEnvironment()).thenReturn(kieenv);
185 when(kiesvc.getStoreServices()).thenReturn(kiestore);
186 when(kiesvc.newKieSessionConfiguration()).thenReturn(kiecfg);
188 KieContainer kiecont = mock(KieContainer.class);
189 when(polcont.getKieContainer()).thenReturn(kiecont);
191 when(polsess.getPolicyContainer()).thenReturn(polcont);
193 when(kiecont.getKieBase(anyString())).thenReturn(kiebase);
200 public void tearDown() {
201 // this will cause the in-memory test DB to be dropped
205 } catch (SQLException e) {
206 logger.warn("failed to close connection", e);
213 } catch (IllegalArgumentException e) {
214 logger.trace("ignored exception", e);
220 public void testGetContainerAdjunct_New() throws Exception {
221 setUpKie(MY_SESS_NAME, 999L, true);
224 // force getContainerAdjunct() to be invoked
225 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
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 {
237 setUpKie(MY_SESS_NAME, 999L, true);
240 // force getContainerAdjunct() to be invoked
241 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
243 ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
244 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
246 verify(polcont, times(1)).setAdjunct(any(), adjcap.capture());
248 // return adjunct on next call
249 when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
251 // force getContainerAdjunct() to be invoked again
252 setUpKie("myname2", 999L, true);
254 feat.activatePolicySession(polcont, "myname2", MY_KIE_BASE);
256 // ensure it isn't invoked again
257 verify(polcont, times(1)).setAdjunct(any(), any());
261 public void testGetContainerAdjunct_WrongType() throws Exception {
262 setUpKie(MY_SESS_NAME, 999L, true);
265 // return false adjunct on next call
266 when(polcont.getAdjunct(any())).thenReturn("not-a-real-adjunct");
268 // force getContainerAdjunct() to be invoked
269 setUpKie("myname2", 999L, true);
271 feat.activatePolicySession(polcont, "myname2", MY_KIE_BASE);
273 ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
274 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
276 verify(polcont, times(1)).setAdjunct(any(), adjcap.capture());
278 assertNotNull(adjcap.getValue());
282 public void testGetSequenceNumber() {
283 assertEquals(1, feat.getSequenceNumber());
287 public void testGlobalInit() throws Exception {
289 feat.globalInit(null, SRC_TEST_RESOURCES);
291 // verify that various factory methods were invoked
292 assertEquals("src/test/resources/feature-session-persistence.properties", propName);
295 @Test(expected = NullPointerException.class)
296 public void testGlobalInitIoEx() throws Exception {
298 feat = new PersistenceFeatureImpl() {
300 protected Properties loadProperties(String filenm) throws IOException {
301 throw new IOException(EXPECTED);
305 feat.globalInit(null, SRC_TEST_RESOURCES);
309 public void testActivatePolicySession() throws Exception {
310 setUpKie(MY_SESS_NAME, 999L, true);
311 final PreparedStatement ps = mockDbConn(5);
313 feat.beforeActivate(null);
315 KieSession session = feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
317 verify(kiestore).loadKieSession(anyLong(), any(), any(), any());
318 verify(kiestore, never()).newKieSession(any(), any(), any());
320 assertEquals(session, kiesess);
322 verify(ps).executeUpdate();
324 verify(kieenv, times(4)).set(anyString(), any());
326 verify(jpa).get(MY_SESS_NAME);
327 verify(jpa).replace(any());
331 public void testActivatePolicySession_NoPersistence() throws Exception {
332 setUpKie(MY_SESS_NAME, 999L, true);
333 final PreparedStatement ps = mockDbConn(5);
335 props.remove("persistence.type");
337 feat.beforeStart(null);
339 assertNull(feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE));
341 verify(ps, never()).executeUpdate();
342 verify(kiestore, never()).loadKieSession(anyLong(), any(), any(), any());
343 verify(kiestore, never()).newKieSession(any(), any(), any());
346 /** Verifies that a new KIE session is created when there is no existing session entity. */
348 public void testActivatePolicySession_New() throws Exception {
349 setUpKie("noName", 999L, true);
352 KieSession session = feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
354 verify(kiestore, never()).loadKieSession(anyLong(), any(), any(), any());
355 verify(kiestore).newKieSession(any(), any(), any());
357 assertEquals(session, kiesess);
359 verify(kieenv, times(4)).set(anyString(), any());
361 verify(jpa).get(MY_SESS_NAME);
362 verify(jpa).replace(any());
366 * Verifies that a new KIE session is created when there KIE fails to load an existing session.
369 public void testActivatePolicySession_LoadFailed() throws Exception {
370 setUpKie(MY_SESS_NAME, 999L, false);
373 KieSession session = feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
375 verify(kiestore).loadKieSession(anyLong(), any(), any(), any());
376 verify(kiestore).newKieSession(any(), any(), any());
378 assertEquals(session, kiesess);
380 verify(kieenv, times(4)).set(anyString(), any());
382 verify(jpa).get(MY_SESS_NAME);
384 ArgumentCaptor<DroolsSession> drools = ArgumentCaptor.forClass(DroolsSession.class);
385 verify(jpa).replace(drools.capture());
387 assertEquals(MY_SESS_NAME, drools.getValue().getSessionName());
388 assertEquals(100L, drools.getValue().getSessionId());
392 public void testLoadDataSource() throws Exception {
393 setUpKie(MY_SESS_NAME, 999L, false);
396 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
398 assertEquals(1, emfCount);
402 public void testConfigureSysProps() throws Exception {
403 setUpKie(MY_SESS_NAME, 999L, false);
406 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
408 assertEquals("60", System.getProperty("com.arjuna.ats.arjuna.coordinator.defaultTimeout"));
409 assertEquals(JTA_OSDIR, System.getProperty("com.arjuna.ats.arjuna.objectstore.objectStoreDir"));
410 assertEquals(JTA_OSDIR, System.getProperty("ObjectStoreEnvironmentBean.objectStoreDir"));
414 public void testConfigureKieEnv() throws Exception {
415 setUpKie(MY_SESS_NAME, 999L, false);
418 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
420 verify(kieenv, times(4)).set(any(), any());
422 verify(kieenv).set(EnvironmentName.ENTITY_MANAGER_FACTORY, emf);
423 verify(kieenv).set(EnvironmentName.TRANSACTION, usertrans);
424 verify(kieenv).set(EnvironmentName.TRANSACTION_MANAGER, transmgr);
425 verify(kieenv).set(EnvironmentName.TRANSACTION_SYNCHRONIZATION_REGISTRY, transreg);
427 verify(bds, times(1)).close();
431 public void testConfigureKieEnv_RtEx() throws Exception {
432 setUpKie(MY_SESS_NAME, 999L, false);
435 feat = new PersistenceFeatureMockDb() {
437 protected UserTransaction getUserTrans() {
438 throw new IllegalArgumentException(EXPECTED);
442 feat.globalInit(null, SRC_TEST_RESOURCES);
445 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
446 fail(MISSING_EXCEPTION);
448 } catch (IllegalArgumentException ex) {
449 logger.trace(EXPECTED, ex);
452 verify(bds, times(2)).close();
456 public void testLoadKieSession() throws Exception {
457 setUpKie(MY_SESS_NAME, 999L, true);
460 KieSession session = feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
462 verify(kiestore).loadKieSession(999L, kiebase, kiecfg, kieenv);
463 verify(kiestore, never()).newKieSession(any(), any(), any());
465 assertEquals(session, kiesess);
469 * Verifies that loadKieSession() returns null (thus causing newKieSession()
470 * to be called) when an Exception occurs.
473 public void testLoadKieSession_Ex() throws Exception {
474 setUpKie(MY_SESS_NAME, 999L, false);
477 when(kiestore.loadKieSession(anyLong(), any(), any(), any()))
478 .thenThrow(new IllegalArgumentException(EXPECTED));
480 KieSession session = feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
482 verify(kiestore).loadKieSession(anyLong(), any(), any(), any());
483 verify(kiestore).newKieSession(any(), any(), any());
485 assertEquals(session, kiesess);
489 public void testNewKieSession() throws Exception {
490 setUpKie(MY_SESS_NAME, 999L, false);
493 KieSession session = feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
495 verify(kiestore).newKieSession(kiebase, null, kieenv);
497 assertEquals(session, kiesess);
501 public void testLoadDataSource_DiffSession() throws Exception {
502 setUpKie(MY_SESS_NAME, 999L, false);
505 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
507 ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
508 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
510 verify(polcont).setAdjunct(any(), adjcap.capture());
512 when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
514 setUpKie("myname2", 999L, false);
518 feat.activatePolicySession(polcont, "myname2", MY_KIE_BASE);
520 assertEquals(2, emfCount);
524 public void testSelectThreadModel_Persistent() throws Exception {
525 setUpKie(MY_SESS_NAME, 999L, true);
527 ThreadModel model = feat.selectThreadModel(polsess);
528 assertNotNull(model);
529 assertTrue(model instanceof PersistentThreadModel);
533 public void testSelectThreadModel_NotPersistent() throws Exception {
534 assertNull(feat.selectThreadModel(polsess));
538 public void testSelectThreadModel_Start__Run_Update_Stop() throws Exception {
539 setUpKie(MY_SESS_NAME, 999L, true);
541 ThreadModel model = feat.selectThreadModel(polsess);
542 assertNotNull(model);
543 assertTrue(model instanceof PersistentThreadModel);
545 when(polsess.getKieSession()).thenReturn(kiesess);
548 new CountDownLatch(1).await(10, TimeUnit.MILLISECONDS);
554 public void testDisposeKieSession() throws Exception {
555 setUpKie(MY_SESS_NAME, 999L, false);
558 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
560 verify(emf, never()).close();
562 final ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
563 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
565 verify(polcont).setAdjunct(any(), adjcap.capture());
567 when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
569 feat.disposeKieSession(polsess);
571 // call twice to ensure it isn't re-closed
572 feat.disposeKieSession(polsess);
574 verify(emf, times(1)).close();
578 public void testDisposeKieSession_NoAdjunct() throws Exception {
579 feat.globalInit(null, SRC_TEST_RESOURCES);
581 assertThatCode(() -> feat.disposeKieSession(polsess)).doesNotThrowAnyException();
585 public void testDisposeKieSession_NoPersistence() throws Exception {
586 setUpKie(MY_SESS_NAME, 999L, false);
589 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
591 verify(emf, never()).close();
593 final ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
594 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
596 verify(polcont).setAdjunct(any(), adjcap.capture());
598 when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
600 // specify a session that was never loaded
601 when(polsess.getName()).thenReturn("anotherName");
603 feat.disposeKieSession(polsess);
605 verify(emf, never()).close();
609 public void testDestroyKieSession() throws Exception {
610 setUpKie(MY_SESS_NAME, 999L, false);
613 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
615 verify(emf, never()).close();
617 final ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
618 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
620 verify(polcont).setAdjunct(any(), adjcap.capture());
622 when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
624 feat.destroyKieSession(polsess);
626 // call twice to ensure it isn't re-closed
627 feat.destroyKieSession(polsess);
629 verify(emf, times(1)).close();
633 public void testDestroyKieSession_NoAdjunct() throws Exception {
634 feat.globalInit(null, SRC_TEST_RESOURCES);
636 assertThatCode(() -> feat.destroyKieSession(polsess)).doesNotThrowAnyException();
640 public void testDestroyKieSession_NoPersistence() throws Exception {
641 setUpKie(MY_SESS_NAME, 999L, false);
644 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
646 verify(emf, never()).close();
648 final ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
649 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
651 verify(polcont).setAdjunct(any(), adjcap.capture());
653 when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
655 // specify a session that was never loaded
656 when(polsess.getName()).thenReturn("anotherName");
658 feat.destroyKieSession(polsess);
660 verify(emf, never()).close();
664 public void testAfterStart() {
665 assertFalse(feat.afterStart(null));
669 public void testBeforeStart() {
670 assertFalse(feat.beforeStart(null));
674 public void testBeforeShutdown() {
675 assertFalse(feat.beforeShutdown(null));
679 public void testAfterShutdown() {
680 assertFalse(feat.afterShutdown(null));
684 public void testBeforeConfigure() {
685 assertFalse(feat.beforeConfigure(null, null));
689 public void testAfterConfigure() {
690 assertFalse(feat.afterConfigure(null));
694 public void testBeforeActivate() {
695 assertFalse(feat.beforeActivate(null));
699 public void testAfterActivate() {
700 assertFalse(feat.afterActivate(null));
704 public void testBeforeDeactivate() {
705 assertFalse(feat.beforeDeactivate(null));
709 public void testAfterDeactivate() {
710 assertFalse(feat.afterDeactivate(null));
714 public void testBeforeStop() {
715 assertFalse(feat.beforeStop(null));
719 public void testAfterStop() {
720 assertFalse(feat.afterStop(null));
724 public void testBeforeLock() {
725 assertFalse(feat.beforeLock(null));
729 public void testAfterLock() {
730 assertFalse(feat.afterLock(null));
734 public void testBeforeUnlock() {
735 assertFalse(feat.beforeUnlock(null));
739 public void testAfterUnlock() {
740 assertFalse(feat.afterUnlock(null));
744 public void testGetPersistenceTimeout_Valid() throws Exception {
745 setUpKie(MY_SESS_NAME, 999L, true);
746 final PreparedStatement statement = mockDbConn(5);
748 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
750 verify(statement).executeUpdate();
754 public void testGetPersistenceTimeout_Missing() throws Exception {
756 props.remove(DroolsPersistenceProperties.DB_SESSIONINFO_TIMEOUT);
758 setUpKie(MY_SESS_NAME, 999L, true);
759 final PreparedStatement statement = mockDbConn(0);
761 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
763 verify(statement, never()).executeUpdate();
767 public void testGetPersistenceTimeout_Invalid() throws Exception {
768 props.setProperty(DroolsPersistenceProperties.DB_SESSIONINFO_TIMEOUT, "abc");
770 setUpKie(MY_SESS_NAME, 999L, true);
771 final PreparedStatement s = mockDbConn(0);
773 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
775 verify(s, never()).executeUpdate();
779 public void testCleanUpSessionInfo() throws Exception {
780 setUpKie(MY_SESS_NAME, 999L, true);
782 // use a real DB so we can verify that the "delete" works correctly
783 feat = new PartialFeature();
785 makeSessionInfoTbl(20000);
787 // create mock entity manager for use by JPA connector
788 EntityManager em = mock(EntityManager.class);
789 when(emf.createEntityManager()).thenReturn(em);
791 feat.globalInit(null, SRC_TEST_RESOURCES);
793 feat.beforeStart(null);
794 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
796 assertEquals("[1, 4, 5]", getSessions().toString());
800 public void testCleanUpSessionInfo_WithBeforeStart() throws Exception {
801 setUpKie(MY_SESS_NAME, 999L, true);
802 final PreparedStatement statement = mockDbConn(0);
805 feat.beforeStart(null);
807 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
808 verify(statement, times(1)).executeUpdate();
810 // should not clean-up again
811 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
812 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
813 verify(statement, times(1)).executeUpdate();
816 feat.beforeStart(null);
818 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
819 verify(statement, times(2)).executeUpdate();
821 // should not clean-up again
822 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
823 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
824 verify(statement, times(2)).executeUpdate();
828 public void testCleanUpSessionInfo_WithBeforeActivate() throws Exception {
829 setUpKie(MY_SESS_NAME, 999L, true);
830 final PreparedStatement statement = mockDbConn(0);
833 feat.beforeActivate(null);
835 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
836 verify(statement, times(1)).executeUpdate();
838 // should not clean-up again
839 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
840 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
841 verify(statement, times(1)).executeUpdate();
844 feat.beforeActivate(null);
846 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
847 verify(statement, times(2)).executeUpdate();
849 // should not clean-up again
850 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
851 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
852 verify(statement, times(2)).executeUpdate();
856 public void testCleanUpSessionInfo_NoTimeout() throws Exception {
858 props.remove(DroolsPersistenceProperties.DB_SESSIONINFO_TIMEOUT);
860 setUpKie(MY_SESS_NAME, 999L, true);
861 final PreparedStatement statement = mockDbConn(0);
863 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
865 verify(statement, never()).executeUpdate();
869 public void testCleanUpSessionInfo_NoUrl() throws Exception {
870 props.remove(DroolsPersistenceProperties.DB_URL);
872 setUpKie(MY_SESS_NAME, 999L, true);
873 final PreparedStatement statement = mockDbConn(0);
876 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
877 fail(MISSING_EXCEPTION);
878 } catch (RuntimeException e) {
879 logger.trace(EXPECTED, e);
882 verify(statement, never()).executeUpdate();
886 public void testCleanUpSessionInfo_NoUser() throws Exception {
887 props.remove(DroolsPersistenceProperties.DB_USER);
889 setUpKie(MY_SESS_NAME, 999L, true);
890 final PreparedStatement statement = mockDbConn(0);
893 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
894 fail(MISSING_EXCEPTION);
895 } catch (RuntimeException e) {
896 logger.trace(EXPECTED, e);
899 verify(statement, never()).executeUpdate();
903 public void testCleanUpSessionInfo_NoPassword() throws Exception {
904 props.remove(DroolsPersistenceProperties.DB_PWD);
906 setUpKie(MY_SESS_NAME, 999L, true);
907 final PreparedStatement statement = mockDbConn(0);
910 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
911 fail(MISSING_EXCEPTION);
912 } catch (RuntimeException e) {
913 logger.trace(EXPECTED, e);
916 verify(statement, never()).executeUpdate();
920 public void testCleanUpSessionInfo_SqlEx() throws Exception {
921 setUpKie(MY_SESS_NAME, 999L, true);
922 final PreparedStatement statement = mockDbConn(-1);
924 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
926 verify(statement).executeUpdate();
930 public void testGetDroolsSessionConnector() throws Exception {
931 setUpKie(MY_SESS_NAME, 999L, true);
934 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
936 assertEquals(1, jpaCount);
940 public void testReplaceSession() throws Exception {
941 setUpKie(MY_SESS_NAME, 999L, true);
944 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
946 final ArgumentCaptor<DroolsSession> sesscap = ArgumentCaptor.forClass(DroolsSession.class);
948 verify(jpa).replace(sesscap.capture());
950 assertEquals(MY_SESS_NAME, sesscap.getValue().getSessionName());
951 assertEquals(999L, sesscap.getValue().getSessionId());
955 public void testIsPersistenceEnabled_Auto() throws Exception {
956 setUpKie(MY_SESS_NAME, 999L, true);
959 props.setProperty("persistence.type", "auto");
961 assertNotNull(feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE));
965 public void testIsPersistenceEnabled_Native() throws Exception {
966 setUpKie(MY_SESS_NAME, 999L, true);
969 props.setProperty("persistence.type", "native");
971 assertNotNull(feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE));
975 public void testIsPersistenceEnabled_None() throws Exception {
976 setUpKie(MY_SESS_NAME, 999L, true);
979 props.remove("persistence.type");
981 assertNull(feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE));
985 public void testGetProperties_Ex() throws Exception {
986 setUpKie(MY_SESS_NAME, 999L, true);
989 feat = new PersistenceFeatureMockDb() {
991 protected PolicyController getPolicyController(PolicyContainer container) {
992 throw new IllegalArgumentException(EXPECTED);
996 assertNull(feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE));
1000 public void testGetProperty_Specific() throws Exception {
1001 setUpKie(MY_SESS_NAME, 999L, true);
1004 props.remove("persistence.type");
1005 props.setProperty("persistence.myname.type", "auto");
1007 assertNotNull(feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE));
1011 public void testGetProperty_Specific_None() throws Exception {
1012 setUpKie(MY_SESS_NAME, 999L, true);
1015 props.remove("persistence.type");
1016 props.setProperty("persistence.xxx.type", "auto");
1018 assertNull(feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE));
1022 public void testGetProperty_Both_SpecificOn() throws Exception {
1023 setUpKie(MY_SESS_NAME, 999L, true);
1026 props.setProperty("persistence.type", "other");
1027 props.setProperty("persistence.myname.type", "auto");
1029 assertNotNull(feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE));
1033 public void testGetProperty_Both_SpecificDisabledOff() throws Exception {
1034 setUpKie(MY_SESS_NAME, 999L, true);
1037 props.setProperty("persistence.type", "auto");
1038 props.setProperty("persistence.myname.type", "other");
1040 assertNull(feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE));
1044 public void testGetProperty_None() throws Exception {
1045 setUpKie(MY_SESS_NAME, 999L, true);
1048 props.remove("persistence.type");
1050 assertNull(feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE));
1054 public void testPersistenceFeatureException() {
1055 SecurityException secex = new SecurityException(EXPECTED);
1056 PersistenceFeatureException ex = new PersistenceFeatureException(secex);
1058 assertEquals(secex, ex.getCause());
1062 public void testDsEmf_RtEx() throws Exception {
1063 setUpKie(MY_SESS_NAME, 999L, false);
1066 feat = new PersistenceFeatureMockDb() {
1068 protected EntityManagerFactory makeEntMgrFact(Map<String, Object> props) {
1069 throw new IllegalArgumentException(EXPECTED);
1073 feat.globalInit(null, SRC_TEST_RESOURCES);
1076 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
1077 fail(MISSING_EXCEPTION);
1079 } catch (IllegalArgumentException ex) {
1080 logger.trace(EXPECTED, ex);
1083 verify(bds, times(2)).close();
1087 public void testDsEmf_Close_RtEx() throws Exception {
1088 setUpKie(MY_SESS_NAME, 999L, false);
1091 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
1093 ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
1094 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
1096 verify(polcont, times(1)).setAdjunct(any(), adjcap.capture());
1098 // return adjunct on next call
1099 when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
1101 IllegalArgumentException exception = new IllegalArgumentException(EXPECTED);
1102 doThrow(exception).when(emf).close();
1103 assertThatCode(() -> feat.destroyKieSession(polsess)).isEqualTo(exception);
1105 verify(bds, times(2)).close();
1109 public void testDsEmf_CloseDataSource_RtEx() throws Exception {
1110 setUpKie(MY_SESS_NAME, 999L, false);
1113 feat.activatePolicySession(polcont, MY_SESS_NAME, MY_KIE_BASE);
1115 ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
1116 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
1118 verify(polcont, times(1)).setAdjunct(any(), adjcap.capture());
1120 // return adjunct on next call
1121 when(polcont.getAdjunct(any())).thenReturn(adjcap.getValue());
1123 SQLException cause = new SQLException(EXPECTED);
1124 doThrow(cause).when(bds).close();
1125 assertThatCode(() -> feat.destroyKieSession(polsess)).isInstanceOf(PersistenceFeatureException.class)
1130 * Gets an ordered list of ids of the current SessionInfo records.
1132 * @return ordered list of SessInfo IDs
1133 * @throws SQLException sql exception
1134 * @throws IOException io exception
1136 private List<Integer> getSessions() throws SQLException, IOException {
1139 ArrayList<Integer> lst = new ArrayList<>(5);
1141 try (PreparedStatement stmt = conn.prepareStatement("SELECT id from sessioninfo order by id");
1142 ResultSet rs = stmt.executeQuery()) {
1145 lst.add(rs.getInt(1));
1153 * Sets up for doing invoking the newKieSession() method.
1155 * @param sessnm name to which JPA should respond with a session
1156 * @param sessid session id to be returned by the session
1157 * @param loadOk {@code true} if loadKieSession() should return a value, {@code false} to return
1159 * @throws Exception exception
1161 private void setUpKie(String sessnm, long sessid, boolean loadOk) throws Exception {
1162 props.setProperty("persistence.type", "auto");
1164 when(polctlr.getProperties()).thenReturn(props);
1166 when(jpa.get(sessnm)).thenReturn(sess);
1168 when(sess.getSessionId()).thenReturn(sessid);
1170 when(polsess.getPolicyContainer()).thenReturn(polcont);
1171 when(polsess.getName()).thenReturn(sessnm);
1174 when(kiesess.getIdentifier()).thenReturn(sessid);
1175 when(kiestore.loadKieSession(anyLong(), any(), any(), any())).thenReturn(kiesess);
1178 // use an alternate id for the new session
1179 when(kiesess.getIdentifier()).thenReturn(100L);
1180 when(kiestore.loadKieSession(anyLong(), any(), any(), any())).thenReturn(null);
1183 when(kiestore.newKieSession(any(), any(), any())).thenReturn(kiesess);
1185 feat = new PersistenceFeatureKie();
1186 feat.globalInit(null, SRC_TEST_RESOURCES);
1190 * Creates the SessionInfo DB table and populates it with some data.
1192 * @param expMs number of milli-seconds for expired sessioninfo records
1193 * @throws SQLException exception
1194 * @throws IOException exception
1196 private void makeSessionInfoTbl(int expMs) throws SQLException, IOException {
1200 try (PreparedStatement stmt =
1201 conn.prepareStatement("CREATE TABLE sessioninfo(id int, lastmodificationdate timestamp)")) {
1203 stmt.executeUpdate();
1206 try (PreparedStatement stmt =
1207 conn.prepareStatement("INSERT into sessioninfo(id, lastmodificationdate) values(?, ?)")) {
1212 ts = new Timestamp(System.currentTimeMillis());
1213 stmt.setTimestamp(2, ts);
1216 stmt.executeUpdate();
1219 stmt.executeUpdate();
1222 stmt.executeUpdate();
1225 ts = new Timestamp(System.currentTimeMillis() - expMs);
1226 stmt.setTimestamp(2, ts);
1229 stmt.executeUpdate();
1232 stmt.executeUpdate();
1237 * Attaches {@link #conn} to the DB, if it isn't already attached.
1239 * @throws SQLException sql exception
1240 * @throws IOException if the property file cannot be read
1242 private void attachDb() throws SQLException, IOException {
1244 Properties props = loadDbProps();
1247 DriverManager.getConnection(
1248 props.getProperty(DroolsPersistenceProperties.DB_URL),
1249 props.getProperty(DroolsPersistenceProperties.DB_USER),
1250 props.getProperty(DroolsPersistenceProperties.DB_PWD));
1251 conn.setAutoCommit(true);
1256 * Loads the DB properties from the file, <i>feature-session-persistence.properties</i>.
1258 * @return the properties that were loaded
1259 * @throws IOException if the property file cannot be read
1260 * @throws FileNotFoundException if the property file does not exist
1262 private Properties loadDbProps() throws IOException, FileNotFoundException {
1264 Properties props = new Properties();
1266 try (FileReader rdr =
1267 new FileReader("src/test/resources/feature-session-persistence.properties")) {
1275 * Create a mock DB connection and statement.
1277 * @param retval value to be returned when the statement is executed, or negative to throw an
1279 * @return the statement that will be returned by the connection
1280 * @throws SQLException sql exception
1282 private PreparedStatement mockDbConn(int retval) throws SQLException {
1283 Connection connection = mock(Connection.class);
1284 PreparedStatement statement = mock(PreparedStatement.class);
1286 when(bds.getConnection()).thenReturn(connection);
1287 when(connection.prepareStatement(anyString())).thenReturn(statement);
1290 // should throw an exception
1291 when(statement.executeUpdate()).thenThrow(new SQLException(EXPECTED));
1294 // should return the value
1295 when(statement.executeUpdate()).thenReturn(retval);
1298 feat = new PersistenceFeatureMockDb();
1299 feat.globalInit(null, SRC_TEST_RESOURCES);
1305 * Feature with a mock DB.
1307 private class PersistenceFeatureMockDb extends PersistenceFeatureKie {
1310 protected BasicDataSource makeDataSource(Properties dsProps) {
1316 * Feature supporting newKieSession.
1318 private class PersistenceFeatureKie extends PersistenceFeatureImpl {
1321 protected EntityManagerFactory makeEntMgrFact(Map<String, Object> props) {
1327 protected DroolsSessionConnector makeJpaConnector(EntityManagerFactory emf) {
1334 * Feature with overrides.
1336 private class PersistenceFeatureImpl extends PartialFeature {
1339 protected Properties loadProperties(String filenm) throws IOException {
1345 protected BasicDataSource makeDataSource(Properties dsProps) {
1350 protected DroolsSessionConnector makeJpaConnector(EntityManagerFactory emf) {
1357 * Feature with <i>some</i> overrides.
1359 private class PartialFeature extends PersistenceFeature {
1362 protected TransactionManager getTransMgr() {
1367 protected UserTransaction getUserTrans() {
1372 protected TransactionSynchronizationRegistry getTransSyncReg() {
1377 protected KieServices getKieServices() {
1382 protected EntityManagerFactory makeEntMgrFact(Map<String, Object> props) {
1388 protected PolicyController getPolicyController(PolicyContainer container) {