e73031dd886aa1e5d281b917c004161238f0abbc
[policy/drools-pdp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * feature-session-persistence
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
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=========================================================
19  */
20
21 package org.onap.policy.drools.persistence;
22
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.mockito.Matchers.any;
28 import static org.mockito.Matchers.anyInt;
29 import static org.mockito.Matchers.anyLong;
30 import static org.mockito.Matchers.anyString;
31 import static org.mockito.Mockito.mock;
32 import static org.mockito.Mockito.never;
33 import static org.mockito.Mockito.times;
34 import static org.mockito.Mockito.verify;
35 import static org.mockito.Mockito.when;
36
37 import java.io.FileNotFoundException;
38 import java.io.FileReader;
39 import java.io.IOException;
40 import java.net.UnknownHostException;
41 import java.sql.Connection;
42 import java.sql.DriverManager;
43 import java.sql.PreparedStatement;
44 import java.sql.ResultSet;
45 import java.sql.SQLException;
46 import java.sql.Timestamp;
47 import java.util.ArrayList;
48 import java.util.List;
49 import java.util.Properties;
50
51 import javax.persistence.EntityManagerFactory;
52
53 import org.junit.After;
54 import org.junit.AfterClass;
55 import org.junit.Before;
56 import org.junit.BeforeClass;
57 import org.junit.Test;
58 import org.kie.api.KieBase;
59 import org.kie.api.KieServices;
60 import org.kie.api.persistence.jpa.KieStoreServices;
61 import org.kie.api.runtime.Environment;
62 import org.kie.api.runtime.EnvironmentName;
63 import org.kie.api.runtime.KieContainer;
64 import org.kie.api.runtime.KieSession;
65 import org.kie.api.runtime.KieSessionConfiguration;
66 import org.mockito.ArgumentCaptor;
67 import org.onap.policy.drools.persistence.DroolsPersistenceProperties;
68 import org.onap.policy.drools.persistence.DroolsSession;
69 import org.onap.policy.drools.persistence.DroolsSessionConnector;
70 import org.onap.policy.drools.persistence.PersistenceFeature;
71 import org.onap.policy.drools.core.PolicyContainer;
72 import org.onap.policy.drools.core.PolicySession;
73 import org.onap.policy.drools.system.PolicyController;
74
75 import bitronix.tm.BitronixTransactionManager;
76 import bitronix.tm.Configuration;
77 import bitronix.tm.resource.jdbc.PoolingDataSource;
78
79 public class PersistenceFeatureTest {
80
81         private static final String JDBC_DATASRC = "fake.datasource";
82         private static final String JDBC_DRIVER = "fake.driver";
83         private static final String JDBC_URL = "fake.url";
84         private static final String JDBC_USER = "fake.user";
85         private static final String JDBC_PASSWD = "fake.password";
86         private static final String SRC_TEST_RESOURCES = "src/test/resources";
87
88         private static Properties stdprops;
89
90         private DroolsSessionConnector jpa;
91         private DroolsSession sess;
92         private PoolingDataSource pds;
93         private KieSession kiesess;
94         private Properties dsprops;
95         private EntityManagerFactory emf;
96         private Connection conn;
97         private Properties props;
98         private KieServices kiesvc;
99         private Environment kieenv;
100         private KieSessionConfiguration kiecfg;
101         private KieBase kiebase;
102         private KieStoreServices kiestore;
103         private KieContainer kiecont;
104         private Configuration bitcfg;
105         private BitronixTransactionManager bittrans;
106         private PolicyController polctlr;
107         private PolicyContainer polcont;
108         private PolicySession polsess;
109         private PersistenceFeature.Factory fact;
110         
111         private PersistenceFeature feat;
112         
113
114         @BeforeClass
115         public static void setUpBeforeClass() throws Exception {
116                 stdprops = new Properties();
117
118                 stdprops.put(DroolsPersistenceProperties.DB_DATA_SOURCE, JDBC_DATASRC);
119                 stdprops.put(DroolsPersistenceProperties.DB_DRIVER, JDBC_DRIVER);
120                 stdprops.put(DroolsPersistenceProperties.DB_URL, JDBC_URL);
121                 stdprops.put(DroolsPersistenceProperties.DB_USER, JDBC_USER);
122                 stdprops.put(DroolsPersistenceProperties.DB_PWD, JDBC_PASSWD);
123                 stdprops.put(DroolsPersistenceProperties.DB_SESSIONINFO_TIMEOUT, "50");
124         }
125
126         @AfterClass
127         public static void tearDownAfterClass() throws Exception {
128         }
129
130         @Before
131         public void setUp() throws Exception {
132                 jpa = mock(DroolsSessionConnector.class);
133                 sess = mock(DroolsSession.class);
134                 pds = mock(PoolingDataSource.class);
135                 kiesess = mock(KieSession.class);
136                 dsprops = new Properties();
137                 emf = null;
138                 conn = null;
139                 props = new Properties();
140                 kiesvc = mock(KieServices.class);
141                 kieenv = mock(Environment.class);
142                 kiecfg = mock(KieSessionConfiguration.class);
143                 kiebase = mock(KieBase.class);
144                 kiestore = mock(KieStoreServices.class);
145                 kiecont = mock(KieContainer.class);
146                 bitcfg = mock(Configuration.class);
147                 bittrans = mock(BitronixTransactionManager.class);
148                 polcont = mock(PolicyContainer.class);
149                 polctlr = mock(PolicyController.class);
150                 polsess = mock(PolicySession.class);
151                 fact = mock(PersistenceFeature.Factory.class);
152                 
153                 feat = new PersistenceFeature();
154                 feat.setFactory(fact);
155                 
156                 props.putAll(stdprops);
157                 
158                 when(pds.getUniqueName()).thenReturn("myds");
159                 
160                 when(fact.getKieServices()).thenReturn(kiesvc);
161                 when(fact.getTransMgrConfig()).thenReturn(bitcfg);
162                 when(fact.getTransMgr()).thenReturn(bittrans);
163                 when(fact.loadProperties(anyString())).thenReturn(props);
164                 
165                 when(kiesvc.newEnvironment()).thenReturn(kieenv);
166                 when(kiesvc.getStoreServices()).thenReturn(kiestore);
167                 when(kiesvc.newKieSessionConfiguration()).thenReturn(kiecfg);
168                 
169                 when(polcont.getKieContainer()).thenReturn(kiecont);
170                 
171                 when(polsess.getPolicyContainer()).thenReturn(polcont);
172                 
173                 when(kiecont.getKieBase(anyString())).thenReturn(kiebase);
174         }
175
176         @After
177         public void tearDown() {
178                 // this will cause the in-memory test DB to be dropped
179                 if(conn != null) {
180                         try { conn.close(); } catch (SQLException e) { }
181                 }
182
183                 if(emf != null) {
184                         try { emf.close(); } catch (Exception e) { }
185                 }
186         }
187
188         @Test
189         public void testGetContainerAdjunct_New() throws Exception {
190
191                 feat.globalInit(null, SRC_TEST_RESOURCES);
192
193                 mockDbConn(5);
194                 setUpKie("myname", 999L, true);
195
196                 // force getContainerAdjunct() to be invoked
197                 feat.activatePolicySession(polcont, "myname", "mybase");
198
199                 ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
200                                 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
201
202                 verify(polcont, times(1)).setAdjunct(any(), adjcap.capture());
203                 
204                 assertNotNull( adjcap.getValue());
205         }
206
207         @Test
208         public void testGetContainerAdjunct_Existing() throws Exception {
209
210                 feat.globalInit(null, SRC_TEST_RESOURCES);
211
212                 mockDbConn(5);
213                 setUpKie("myname", 999L, true);
214
215                 // force getContainerAdjunct() to be invoked
216                 feat.activatePolicySession(polcont, "myname", "mybase");
217
218                 ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
219                                 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
220
221                 verify(polcont, times(1)).setAdjunct(any(), adjcap.capture());
222                 
223                 // return adjunct on next call
224                 when(polcont.getAdjunct(any())).thenReturn( adjcap.getValue());
225
226                 // force getContainerAdjunct() to be invoked again
227                 setUpKie("myname2", 999L, true);
228                 feat.activatePolicySession(polcont, "myname2", "mybase");
229                 
230                 // ensure it isn't invoked again
231                 verify(polcont, times(1)).setAdjunct(any(), any());
232         }
233
234         @Test
235         public void testGetSequenceNumber() {
236                 assertEquals(1, feat.getSequenceNumber());
237         }
238
239         @Test
240         public void testGlobalInit() throws Exception {
241                 when(fact.getHostName()).thenReturn("myhost");
242                 
243                 feat.globalInit(null, SRC_TEST_RESOURCES);
244                 
245                 // verify that various factory methods were invoked
246                 verify(fact).getHostName();
247                 verify(fact).getKieServices();
248                 verify(fact).getTransMgrConfig();
249                 verify(fact).loadProperties("src/test/resources/feature-session-persistence.properties");
250                 
251                 verify(bitcfg).setJournal(null);
252                 verify(bitcfg).setServerId("myhost");
253         }
254
255         @Test
256         public void testActivatePolicySession() throws Exception {
257                 PreparedStatement ps = mockDbConn(5);
258                 setUpKie("myname", 999L, true);
259
260                 feat.globalInit(null, SRC_TEST_RESOURCES);
261                 feat.beforeActivate(null);
262                 
263                 KieSession s =
264                                 feat.activatePolicySession(polcont, "myname", "mybase");
265
266                 verify(kiestore).loadKieSession(anyLong(), any(), any(), any());
267                 verify(kiestore, never()).newKieSession(any(), any(), any());
268                 
269                 assertEquals(s, kiesess);
270                 
271                 verify(ps).executeUpdate();
272
273                 verify(kieenv, times(2)).set(anyString(), any());
274                 verify(pds).init();
275                 assertFalse( dsprops.isEmpty());
276                 
277                 verify(jpa).get("myname");
278                 verify(jpa).replace(any());
279         }
280
281         @Test
282         public void testActivatePolicySession_NoPersistence() throws Exception {
283                 feat.globalInit(null, SRC_TEST_RESOURCES);
284
285                 PreparedStatement ps = mockDbConn(5);
286                 setUpKie("myname", 999L, true);
287                 
288                 props.remove("persistence.type");
289                 
290                 feat.beforeStart(null);
291                 
292                 assertNull( feat.activatePolicySession(polcont, "myname", "mybase"));
293
294                 verify(ps, never()).executeUpdate();
295                 verify(kiestore, never()).loadKieSession(anyLong(), any(), any(), any());
296                 verify(kiestore, never()).newKieSession(any(), any(), any());
297         }
298
299         /**
300          * Verifies that a new KIE session is created when there is no existing
301          * session entity. 
302          */
303         @Test
304         public void testActivatePolicySession_New() throws Exception {
305                 feat.globalInit(null, SRC_TEST_RESOURCES);
306
307                 mockDbConn(5);
308                 setUpKie("noName", 999L, true);
309                 
310                 
311                 KieSession s =
312                                 feat.activatePolicySession(polcont, "myname", "mybase");
313
314                 verify(kiestore, never()).loadKieSession(anyLong(), any(), any(), any());
315                 verify(kiestore).newKieSession(any(), any(), any());
316                 
317                 assertEquals(s, kiesess);
318
319                 verify(kieenv, times(2)).set(anyString(), any());
320                 verify(pds).init();
321                 assertFalse( dsprops.isEmpty());
322
323                 verify(jpa).get("myname");
324                 verify(jpa).replace(any());
325         }
326
327         /**
328          * Verifies that a new KIE session is created when there KIE fails
329          * to load an existing session.
330          */
331         @Test
332         public void testActivatePolicySession_LoadFailed() throws Exception {
333                 feat.globalInit(null, SRC_TEST_RESOURCES);
334
335                 mockDbConn(5);
336                 setUpKie("myname", 999L, false);
337                 
338                 
339                 KieSession s =
340                                 feat.activatePolicySession(polcont, "myname", "mybase");
341
342                 verify(kiestore).loadKieSession(anyLong(), any(), any(), any());
343                 verify(kiestore).newKieSession(any(), any(), any());
344                 
345                 assertEquals(s, kiesess);
346
347                 verify(kieenv, times(2)).set(anyString(), any());
348                 verify(pds).init();
349                 assertFalse( dsprops.isEmpty());
350
351                 verify(jpa).get("myname");
352                 
353                 ArgumentCaptor<DroolsSession> d =
354                                 ArgumentCaptor.forClass(DroolsSession.class);
355                 verify(jpa).replace( d.capture());
356                 
357                 assertEquals("myname", d.getValue().getSessionName());
358                 assertEquals(100L, d.getValue().getSessionId());
359         }
360
361         @Test
362         public void testConfigureKieEnv() throws Exception {
363                 feat.globalInit(null, SRC_TEST_RESOURCES);
364
365                 mockDbConn(5);
366                 setUpKie("myname", 999L, false);
367                 
368                 feat.activatePolicySession(polcont, "myname", "mybase");
369
370                 verify(kieenv, times(2)).set(any(), any());
371                 
372                 verify(kieenv).set(EnvironmentName.ENTITY_MANAGER_FACTORY, emf);
373                 verify(kieenv).set(EnvironmentName.TRANSACTION_MANAGER, bittrans);
374         }
375
376         @Test
377         public void testInitDataSource() throws Exception {
378                 feat.globalInit(null, SRC_TEST_RESOURCES);
379
380                 mockDbConn(5);
381                 setUpKie("myname", 999L, false);
382                 
383                 feat.activatePolicySession(polcont, "myname", "mybase");
384                 
385                 assertEquals(JDBC_URL, dsprops.getProperty("URL"));
386                 assertEquals(JDBC_USER, dsprops.getProperty("user"));
387                 assertEquals(JDBC_PASSWD, dsprops.getProperty("password"));
388                 
389                 verify(pds).setUniqueName("jdbc/BitronixJTADataSource/myname");
390                 verify(pds).setClassName(JDBC_DATASRC);
391                 verify(pds).setMaxPoolSize(anyInt());
392                 verify(pds).setIsolationLevel("SERIALIZABLE");
393                 verify(pds).setAllowLocalTransactions(true);
394                 verify(pds).init();
395         }
396
397         @Test
398         public void testLoadKieSession() throws Exception {
399                 feat.globalInit(null, SRC_TEST_RESOURCES);
400
401                 mockDbConn(5);
402                 setUpKie("myname", 999L, true);
403                 
404                 
405                 KieSession s =
406                                 feat.activatePolicySession(polcont, "myname", "mybase");
407
408                 verify(kiestore).loadKieSession(999L, kiebase, kiecfg, kieenv);
409                 verify(kiestore, never()).newKieSession(any(), any(), any());
410                 
411                 assertEquals(s, kiesess);
412         }
413
414         /*
415          * Verifies that loadKieSession() returns null (thus causing newKieSession()
416          * to be called) when an Exception occurs.
417          */
418         @Test
419         public void testLoadKieSession_Ex() throws Exception {
420                 feat.globalInit(null, SRC_TEST_RESOURCES);
421
422                 mockDbConn(5);
423                 setUpKie("myname", 999L, false);
424                 
425                 when(kiestore.loadKieSession(anyLong(), any(), any(), any()))
426                                 .thenThrow( new RuntimeException("expected exception"));
427                 
428                 
429                 KieSession s =
430                                 feat.activatePolicySession(polcont, "myname", "mybase");
431
432                 verify(kiestore).loadKieSession(anyLong(), any(), any(), any());
433                 verify(kiestore).newKieSession(any(), any(), any());
434                 
435                 assertEquals(s, kiesess);
436         }
437
438         @Test
439         public void testNewKieSession() throws Exception {
440                 feat.globalInit(null, SRC_TEST_RESOURCES);
441
442                 mockDbConn(5);
443                 setUpKie("myname", 999L, false);
444                 
445                 
446                 KieSession s =
447                                 feat.activatePolicySession(polcont, "myname", "mybase");
448
449                 verify(kiestore).newKieSession(kiebase, null, kieenv);
450                 
451                 assertEquals(s, kiesess);
452         }
453
454         @Test
455         public void testLoadDataSource_RepeatSameSession() throws Exception {
456                 feat.globalInit(null, SRC_TEST_RESOURCES);
457
458                 mockDbConn(5);
459                 setUpKie("myname", 999L, false);
460
461                 feat.activatePolicySession(polcont, "myname", "mybase");
462
463                 ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
464                                 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
465                 
466                 verify(polcont).setAdjunct(any(), adjcap.capture());
467                 
468                 when(polcont.getAdjunct(any())).thenReturn( adjcap.getValue());
469                 
470                 // invoke it again
471                 feat.activatePolicySession(polcont, "myname", "mybase");
472                 
473                 verify(fact, times(1)).makePoolingDataSource();
474         }
475
476         @Test
477         public void testLoadDataSource_DiffSession() throws Exception {
478                 feat.globalInit(null, SRC_TEST_RESOURCES);
479
480                 mockDbConn(5);
481                 setUpKie("myname", 999L, false);
482                 feat.activatePolicySession(polcont, "myname", "mybase");
483
484                 ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
485                                 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
486                 
487                 verify(polcont).setAdjunct(any(), adjcap.capture());
488                 
489                 when(polcont.getAdjunct(any())).thenReturn( adjcap.getValue());
490
491                 setUpKie("myname2", 999L, false);
492                 
493                 // invoke it again
494                 feat.activatePolicySession(polcont, "myname2", "mybase");
495                 
496                 verify(fact, times(2)).makePoolingDataSource();
497         }
498
499         @Test
500         public void testDisposeKieSession() throws Exception {
501                 feat.globalInit(null, SRC_TEST_RESOURCES);
502
503                 ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
504                                 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
505
506                 mockDbConn(5);
507                 setUpKie("myname", 999L, false);
508                 
509                 feat.activatePolicySession(polcont, "myname", "mybase");
510                 
511                 verify(pds, never()).close();
512                 verify(polcont).setAdjunct(any(), adjcap.capture());
513                 
514                 when(polcont.getAdjunct(any())).thenReturn( adjcap.getValue());
515                 
516                 feat.disposeKieSession(polsess);
517
518                 // call twice to ensure it isn't re-closed
519                 feat.disposeKieSession(polsess);
520                 
521                 verify(pds, times(1)).close();
522         }
523
524         @Test
525         public void testDisposeKieSession_NoAdjunct() throws Exception {
526                 feat.globalInit(null, SRC_TEST_RESOURCES);
527                 
528                 feat.disposeKieSession(polsess);
529         }
530
531         @Test
532         public void testDisposeKieSession_NoPersistence() throws Exception {
533                 feat.globalInit(null, SRC_TEST_RESOURCES);
534
535                 ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
536                                 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
537
538                 mockDbConn(5);
539                 setUpKie("myname", 999L, false);
540                 
541                 feat.activatePolicySession(polcont, "myname", "mybase");
542                 
543                 verify(pds, never()).close();
544                 verify(polcont).setAdjunct(any(), adjcap.capture());
545                 
546                 when(polcont.getAdjunct(any())).thenReturn( adjcap.getValue());
547
548                 // specify a session that was never loaded
549                 when(polsess.getName()).thenReturn("anotherName");
550                 
551                 feat.disposeKieSession(polsess);
552                 
553                 verify(pds, never()).close();
554         }
555
556         @Test
557         public void testDestroyKieSession() throws Exception {
558                 feat.globalInit(null, SRC_TEST_RESOURCES);
559
560                 ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
561                                 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
562
563                 mockDbConn(5);
564                 setUpKie("myname", 999L, false);
565                 
566                 feat.activatePolicySession(polcont, "myname", "mybase");
567                 
568                 verify(pds, never()).close();
569                 verify(polcont).setAdjunct(any(), adjcap.capture());
570                 
571                 when(polcont.getAdjunct(any())).thenReturn( adjcap.getValue());
572                 
573                 feat.destroyKieSession(polsess);
574
575                 // call twice to ensure it isn't re-closed
576                 feat.destroyKieSession(polsess);
577                 
578                 verify(pds, times(1)).close();
579         }
580
581         @Test
582         public void testDestroyKieSession_NoAdjunct() throws Exception {
583                 feat.globalInit(null, SRC_TEST_RESOURCES);
584                 
585                 feat.destroyKieSession(polsess);
586         }
587
588         @Test
589         public void testDestroyKieSession_NoPersistence() throws Exception {
590                 feat.globalInit(null, SRC_TEST_RESOURCES);
591
592                 ArgumentCaptor<PersistenceFeature.ContainerAdjunct> adjcap =
593                                 ArgumentCaptor.forClass(PersistenceFeature.ContainerAdjunct.class);
594
595                 mockDbConn(5);
596                 setUpKie("myname", 999L, false);
597                 
598                 feat.activatePolicySession(polcont, "myname", "mybase");
599                 
600                 verify(pds, never()).close();
601                 verify(polcont).setAdjunct(any(), adjcap.capture());
602                 
603                 when(polcont.getAdjunct(any())).thenReturn( adjcap.getValue());
604
605                 // specify a session that was never loaded
606                 when(polsess.getName()).thenReturn("anotherName");
607                 
608                 feat.destroyKieSession(polsess);
609
610                 verify(pds, never()).close();
611         }
612
613         @Test
614         public void testAfterStart() {
615                 assertFalse( feat.afterStart(null));
616         }
617
618         @Test
619         public void testBeforeStart() {
620                 assertFalse( feat.beforeStart(null));
621         }
622
623         @Test
624         public void testBeforeShutdown() {
625                 assertFalse( feat.beforeShutdown(null));
626         }
627
628         @Test
629         public void testAfterShutdown() {
630                 assertFalse( feat.afterShutdown(null));
631         }
632
633         @Test
634         public void testBeforeConfigure() {
635                 assertFalse( feat.beforeConfigure(null, null));
636         }
637
638         @Test
639         public void testAfterConfigure() {
640                 assertFalse( feat.afterConfigure(null));
641         }
642
643         @Test
644         public void testBeforeActivate() {
645                 assertFalse( feat.beforeActivate(null));
646         }
647
648         @Test
649         public void testAfterActivate() {
650                 assertFalse( feat.afterActivate(null));
651         }
652
653         @Test
654         public void testBeforeDeactivate() {
655                 assertFalse( feat.beforeDeactivate(null));
656         }
657
658         @Test
659         public void testAfterDeactivate() {
660                 assertFalse( feat.afterDeactivate(null));
661         }
662
663         @Test
664         public void testBeforeStop() {
665                 assertFalse( feat.beforeStop(null));
666         }
667
668         @Test
669         public void testAfterStop() {
670                 assertFalse( feat.afterStop(null));
671         }
672
673         @Test
674         public void testBeforeLock() {
675                 assertFalse( feat.beforeLock(null));
676         }
677
678         @Test
679         public void testAfterLock() {
680                 assertFalse( feat.afterLock(null));
681         }
682
683         @Test
684         public void testBeforeUnlock() {
685                 assertFalse( feat.beforeUnlock(null));
686         }
687
688         @Test
689         public void testAfterUnlock() {
690                 assertFalse( feat.afterUnlock(null));
691         }
692
693         @Test
694         public void testGetPersistenceTimeout_Valid() throws Exception {
695                 PreparedStatement s = mockDbConn(5);
696
697                 feat.globalInit(null, SRC_TEST_RESOURCES);
698
699                 setUpKie("myname", 999L, true);
700                 
701                 feat.activatePolicySession(polcont, "myname", "mybase");
702                 
703                 verify(s).executeUpdate();
704         }
705
706         @Test
707         public void testGetPersistenceTimeout_Missing() throws Exception {
708                 
709                 props.remove(DroolsPersistenceProperties.DB_SESSIONINFO_TIMEOUT);
710                 
711                 PreparedStatement s = mockDbConn(0);
712
713                 feat.globalInit(null, SRC_TEST_RESOURCES);
714
715                 setUpKie("myname", 999L, true);
716                 
717                 feat.activatePolicySession(polcont, "myname", "mybase");
718                 
719                 verify(s, never()).executeUpdate();
720         }
721
722         @Test
723         public void testGetPersistenceTimeout_Invalid() throws Exception {
724                 props.setProperty(DroolsPersistenceProperties.DB_SESSIONINFO_TIMEOUT, "abc");
725                 PreparedStatement s = mockDbConn(0);
726
727                 feat.globalInit(null, SRC_TEST_RESOURCES);
728
729                 setUpKie("myname", 999L, true);
730                 
731                 feat.activatePolicySession(polcont, "myname", "mybase");
732                 
733                 verify(s, never()).executeUpdate();
734         }
735
736         @Test
737         public void testInitHostName() throws Exception {
738                 when(fact.getHostName()).thenReturn("myhost");
739                 
740                 feat.globalInit(null, SRC_TEST_RESOURCES);
741                 
742                 verify(bitcfg).setServerId("myhost");
743         }
744
745         @Test(expected = RuntimeException.class)
746         public void testInitHostName_Ex() throws Exception {
747                 when(fact.getHostName())
748                                 .thenThrow(
749                                                 new UnknownHostException("expected exception"));
750                 
751                 feat.globalInit(null, SRC_TEST_RESOURCES);
752         }
753
754         @Test
755         public void testCleanUpSessionInfo() throws Exception {
756                 setUpKie("myname", 999L, true);
757                 
758                 // use a real DB so we can verify that the "delete" works correctly
759                 fact = new PartialFactory();
760                 feat.setFactory(fact);
761                 
762                 makeSessionInfoTbl(20000);
763
764                 
765                 feat.globalInit(null, SRC_TEST_RESOURCES);
766                 
767                 feat.beforeStart(null);
768                 feat.activatePolicySession(polcont, "myname", "mybase");
769                 
770                 assertEquals("[1, 4, 5]", getSessions().toString());
771         }
772
773         @Test
774         public void testCleanUpSessionInfo_WithBeforeStart() throws Exception {
775                 PreparedStatement s = mockDbConn(0);
776
777                 feat.globalInit(null, SRC_TEST_RESOURCES);
778
779                 setUpKie("myname", 999L, true);
780                 
781                 // reset
782                 feat.beforeStart(null);
783                 
784                 feat.activatePolicySession(polcont, "myname", "mybase");
785                 verify(s, times(1)).executeUpdate();
786
787                 // should not clean-up again
788                 feat.activatePolicySession(polcont, "myname", "mybase");
789                 feat.activatePolicySession(polcont, "myname", "mybase");
790                 verify(s, times(1)).executeUpdate();
791                 
792
793                 // reset
794                 feat.beforeStart(null);
795                 
796                 feat.activatePolicySession(polcont, "myname", "mybase");
797                 verify(s, times(2)).executeUpdate();
798
799                 // should not clean-up again
800                 feat.activatePolicySession(polcont, "myname", "mybase");
801                 feat.activatePolicySession(polcont, "myname", "mybase");
802                 verify(s, times(2)).executeUpdate();
803         }
804
805         @Test
806         public void testCleanUpSessionInfo_WithBeforeActivate() throws Exception {
807                 PreparedStatement s = mockDbConn(0);
808
809                 feat.globalInit(null, SRC_TEST_RESOURCES);
810
811                 setUpKie("myname", 999L, true);
812                 
813                 // reset
814                 feat.beforeActivate(null);
815                 
816                 feat.activatePolicySession(polcont, "myname", "mybase");
817                 verify(s, times(1)).executeUpdate();
818
819                 // should not clean-up again
820                 feat.activatePolicySession(polcont, "myname", "mybase");
821                 feat.activatePolicySession(polcont, "myname", "mybase");
822                 verify(s, times(1)).executeUpdate();
823                 
824
825                 // reset
826                 feat.beforeActivate(null);
827                 
828                 feat.activatePolicySession(polcont, "myname", "mybase");
829                 verify(s, times(2)).executeUpdate();
830
831                 // should not clean-up again
832                 feat.activatePolicySession(polcont, "myname", "mybase");
833                 feat.activatePolicySession(polcont, "myname", "mybase");
834                 verify(s, times(2)).executeUpdate();
835         }
836
837         @Test
838         public void testCleanUpSessionInfo_NoTimeout() throws Exception {
839
840                 props.remove(DroolsPersistenceProperties.DB_SESSIONINFO_TIMEOUT);
841                 
842                 PreparedStatement s = mockDbConn(0);
843
844                 feat.globalInit(null, SRC_TEST_RESOURCES);
845
846                 setUpKie("myname", 999L, true);
847                 
848                 feat.activatePolicySession(polcont, "myname", "mybase");
849                 
850                 verify(s, never()).executeUpdate();
851         }
852
853         @Test
854         public void testCleanUpSessionInfo_NoUrl() throws Exception {
855                 PreparedStatement s = mockDbConn(0);
856                 
857                 props.remove(DroolsPersistenceProperties.DB_URL);
858
859                 feat.globalInit(null, SRC_TEST_RESOURCES);
860
861                 setUpKie("myname", 999L, true);
862                 
863                 feat.activatePolicySession(polcont, "myname", "mybase");
864                 
865                 verify(s, never()).executeUpdate();
866         }
867
868         @Test
869         public void testCleanUpSessionInfo_NoUser() throws Exception {
870                 PreparedStatement s = mockDbConn(0);
871                 
872                 props.remove(DroolsPersistenceProperties.DB_USER);
873
874                 feat.globalInit(null, SRC_TEST_RESOURCES);
875
876                 setUpKie("myname", 999L, true);
877                 
878                 feat.activatePolicySession(polcont, "myname", "mybase");
879                 
880                 verify(s, never()).executeUpdate();
881         }
882
883         @Test
884         public void testCleanUpSessionInfo_NoPassword() throws Exception {
885                 PreparedStatement s = mockDbConn(0);
886                 
887                 props.remove(DroolsPersistenceProperties.DB_PWD);
888
889                 feat.globalInit(null, SRC_TEST_RESOURCES);
890
891                 setUpKie("myname", 999L, true);
892                 
893                 feat.activatePolicySession(polcont, "myname", "mybase");
894                 
895                 verify(s, never()).executeUpdate();
896         }
897
898         @Test
899         public void testCleanUpSessionInfo_SqlEx() throws Exception {
900                 PreparedStatement s = mockDbConn(-1);
901
902                 feat.globalInit(null, SRC_TEST_RESOURCES);
903
904                 setUpKie("myname", 999L, true);
905                 
906                 feat.activatePolicySession(polcont, "myname", "mybase");
907                 
908                 verify(s).executeUpdate();
909         }
910
911         @Test
912         public void testGetDroolsSessionConnector() throws Exception {
913                 feat.globalInit(null, SRC_TEST_RESOURCES);
914
915                 mockDbConn(5);
916                 setUpKie("myname", 999L, true);
917                 
918                 
919                 feat.activatePolicySession(polcont, "myname", "mybase");
920
921
922                 ArgumentCaptor<Properties> propcap =
923                                 ArgumentCaptor.forClass(Properties.class);
924                 
925                 verify(fact).makeJpaConnector(anyString(), propcap.capture());
926                 
927                 Properties p = propcap.getValue();
928                 assertNotNull(p);
929                 
930                 assertEquals(JDBC_DRIVER,
931                                 p.getProperty("javax.persistence.jdbc.driver"));
932                 
933                 assertEquals(JDBC_URL,
934                                 p.getProperty("javax.persistence.jdbc.url"));
935                 
936                 assertEquals(JDBC_USER,
937                                 p.getProperty("javax.persistence.jdbc.user"));
938                 
939                 assertEquals(JDBC_PASSWD,
940                                 p.getProperty("javax.persistence.jdbc.password"));
941         }
942
943         @Test
944         public void testReplaceSession() throws Exception {
945                 feat.globalInit(null, SRC_TEST_RESOURCES);
946
947                 ArgumentCaptor<DroolsSession> sesscap =
948                                 ArgumentCaptor.forClass(DroolsSession.class);
949
950                 mockDbConn(5);
951                 setUpKie("myname", 999L, true);
952                 
953                 
954                 feat.activatePolicySession(polcont, "myname", "mybase");
955                 
956                 verify(jpa).replace( sesscap.capture());
957                 
958                 assertEquals("myname", sesscap.getValue().getSessionName());
959                 assertEquals(999L, sesscap.getValue().getSessionId());
960         }
961         
962         @Test
963         public void testIsPersistenceEnabled_Auto() throws Exception {
964                 feat.globalInit(null, SRC_TEST_RESOURCES);
965
966                 mockDbConn(5);
967                 setUpKie("myname", 999L, true);
968
969                 props.setProperty("persistence.type", "auto");
970                 
971                 assertNotNull( feat.activatePolicySession(polcont, "myname", "mybase"));
972         }
973         
974         @Test
975         public void testIsPersistenceEnabled_Native() throws Exception {
976                 feat.globalInit(null, SRC_TEST_RESOURCES);
977
978                 mockDbConn(5);
979                 setUpKie("myname", 999L, true);
980
981                 props.setProperty("persistence.type", "native");
982                 
983                 assertNotNull( feat.activatePolicySession(polcont, "myname", "mybase"));
984         }
985         
986         @Test
987         public void testIsPersistenceEnabled_None() throws Exception {
988                 feat.globalInit(null, SRC_TEST_RESOURCES);
989
990                 mockDbConn(5);
991                 setUpKie("myname", 999L, true);
992
993                 props.remove("persistence.type");
994                 
995                 assertNull( feat.activatePolicySession(polcont, "myname", "mybase"));
996         }
997         
998         @Test
999         public void testGetProperties_Ex() throws Exception {
1000                 feat.globalInit(null, SRC_TEST_RESOURCES);
1001
1002                 mockDbConn(5);
1003                 setUpKie("myname", 999L, true);
1004                 
1005                 when(fact.getPolicyContainer(polcont))
1006                         .thenThrow( new IllegalArgumentException("expected exception"));
1007
1008                 assertNull( feat.activatePolicySession(polcont, "myname", "mybase"));
1009         }
1010         
1011         @Test
1012         public void testGetProperty_Specific() throws Exception {
1013                 feat.globalInit(null, SRC_TEST_RESOURCES);
1014
1015                 mockDbConn(5);
1016                 setUpKie("myname", 999L, true);
1017
1018                 props.remove("persistence.type");
1019                 props.setProperty("persistence.myname.type", "auto");
1020                 
1021                 assertNotNull( feat.activatePolicySession(polcont, "myname", "mybase"));
1022         }
1023         
1024         @Test
1025         public void testGetProperty_Specific_None() throws Exception {
1026                 feat.globalInit(null, SRC_TEST_RESOURCES);
1027
1028                 mockDbConn(5);
1029                 setUpKie("myname", 999L, true);
1030
1031                 props.remove("persistence.type");
1032                 props.setProperty("persistence.xxx.type", "auto");
1033                 
1034                 assertNull( feat.activatePolicySession(polcont, "myname", "mybase"));
1035         }
1036         
1037         @Test
1038         public void testGetProperty_Both_SpecificOn() throws Exception {
1039                 feat.globalInit(null, SRC_TEST_RESOURCES);
1040
1041                 mockDbConn(5);
1042                 setUpKie("myname", 999L, true);
1043
1044                 props.setProperty("persistence.type", "other");
1045                 props.setProperty("persistence.myname.type", "auto");
1046                 
1047                 assertNotNull( feat.activatePolicySession(polcont, "myname", "mybase"));
1048         }
1049         
1050         @Test
1051         public void testGetProperty_Both_SpecificDisabledOff() throws Exception {
1052                 feat.globalInit(null, SRC_TEST_RESOURCES);
1053
1054                 mockDbConn(5);
1055                 setUpKie("myname", 999L, true);
1056
1057                 props.setProperty("persistence.type", "auto");
1058                 props.setProperty("persistence.myname.type", "other");
1059                 
1060                 assertNull( feat.activatePolicySession(polcont, "myname", "mybase"));
1061         }
1062         
1063         @Test
1064         public void testGetProperty_None() throws Exception {
1065                 feat.globalInit(null, SRC_TEST_RESOURCES);
1066
1067                 mockDbConn(5);
1068                 setUpKie("myname", 999L, true);
1069
1070                 props.remove("persistence.type");
1071                 
1072                 assertNull( feat.activatePolicySession(polcont, "myname", "mybase"));
1073         }
1074
1075         
1076         /**
1077          * Gets an ordered list of ids of the current SessionInfo records.
1078          * @return ordered list of SessInfo IDs
1079          * @throws SQLException 
1080          * @throws IOException 
1081          */
1082         private List<Integer> getSessions() throws SQLException, IOException {
1083                 attachDb();
1084                 
1085                 ArrayList<Integer> lst = new ArrayList<>(5);
1086
1087                 try(
1088                                 PreparedStatement stmt = conn.prepareStatement("SELECT id from sessioninfo order by id");
1089                                 ResultSet rs = stmt.executeQuery()) {
1090                         
1091                         while(rs.next()) {
1092                                 lst.add( rs.getInt(1));
1093                         }
1094                 }
1095                 
1096                 return lst;
1097         }
1098         
1099         /**
1100          * Sets up for doing invoking the newKieSession() method.
1101          * @param sessnm        name to which JPA should respond with a session
1102          * @param sessid        session id to be returned by the session
1103          * @param loadOk        {@code true} if loadKieSession() should return a
1104          *                                      value, {@code false} to return null
1105          */
1106         private void setUpKie(String sessnm, long sessid, boolean loadOk) {
1107                 
1108                 when(fact.makeJpaConnector(any(), any())).thenReturn(jpa);
1109                 when(fact.makePoolingDataSource()).thenReturn(pds);
1110                 when(fact.getPolicyContainer(polcont)).thenReturn(polctlr);
1111                 
1112                 props.setProperty("persistence.type", "auto");
1113                 
1114                 when(polctlr.getProperties()).thenReturn(props);
1115                 
1116                 when(jpa.get(sessnm)).thenReturn(sess);
1117                 
1118                 when(pds.getDriverProperties()).thenReturn(dsprops);
1119                 
1120                 when(sess.getSessionId()).thenReturn(sessid);
1121                 
1122                 when(polsess.getPolicyContainer()).thenReturn(polcont);
1123                 when(polsess.getName()).thenReturn(sessnm);
1124                 
1125                 if(loadOk) {
1126                         when(kiesess.getIdentifier()).thenReturn(sessid);
1127                         when(kiestore.loadKieSession(anyLong(), any(), any(), any()))
1128                                         .thenReturn(kiesess);
1129                         
1130                 } else {
1131                         // use an alternate id for the new session
1132                         when(kiesess.getIdentifier()).thenReturn(100L);
1133                         when(kiestore.loadKieSession(anyLong(), any(), any(), any()))
1134                                         .thenReturn(null);
1135                 }
1136
1137                 when(kiestore.newKieSession(any(), any(), any())).thenReturn(kiesess);
1138         }
1139
1140         /**
1141          * Creates the SessionInfo DB table and populates it with some data.
1142          * @param expMs         number of milli-seconds for expired sessioninfo records
1143          * @throws SQLException 
1144          * @throws IOException 
1145          */
1146         private void makeSessionInfoTbl(int expMs)
1147                                 throws SQLException, IOException {
1148                 
1149                 attachDb();
1150
1151                 try(
1152                                 PreparedStatement stmt = conn.prepareStatement(
1153                                                 "CREATE TABLE sessioninfo(id int, lastmodificationdate timestamp)")) {
1154
1155                         stmt.executeUpdate();   
1156                 }
1157
1158                 try(
1159                                 PreparedStatement stmt = conn.prepareStatement(
1160                                                 "INSERT into sessioninfo(id, lastmodificationdate) values(?, ?)")) {
1161
1162                         Timestamp ts;
1163                         
1164                         // current data
1165                         ts = new Timestamp( System.currentTimeMillis());
1166                         stmt.setTimestamp(2, ts);
1167         
1168                         stmt.setInt(1, 1);
1169                         stmt.executeUpdate();
1170         
1171                         stmt.setInt(1, 4);
1172                         stmt.executeUpdate();
1173         
1174                         stmt.setInt(1, 5);
1175                         stmt.executeUpdate();
1176                         
1177                         // expired data
1178                         ts = new Timestamp( System.currentTimeMillis() - expMs);
1179                         stmt.setTimestamp(2, ts);
1180         
1181                         stmt.setInt(1, 2);
1182                         stmt.executeUpdate();
1183         
1184                         stmt.setInt(1, 3);
1185                         stmt.executeUpdate();
1186                 }
1187         }
1188
1189         /**
1190          * Attaches {@link #conn} to the DB, if it isn't already attached.
1191          * @throws SQLException
1192          * @throws IOException if the property file cannot be read
1193          */
1194         private void attachDb() throws SQLException, IOException {
1195                 if(conn == null) {
1196                         Properties p = loadDbProps();
1197                         
1198                         conn = DriverManager.getConnection(
1199                                                 p.getProperty(DroolsPersistenceProperties.DB_URL),
1200                                                 p.getProperty(DroolsPersistenceProperties.DB_USER),
1201                                                 p.getProperty(DroolsPersistenceProperties.DB_PWD));
1202                         conn.setAutoCommit(true);
1203                 }
1204         }
1205
1206         /**
1207          * Loads the DB properties from the file,
1208          * <i>feature-session-persistence.properties</i>.
1209          * @return the properties that were loaded
1210          * @throws IOException if the property file cannot be read
1211          * @throws FileNotFoundException if the property file does not exist
1212          */
1213         private Properties loadDbProps()
1214                                 throws IOException, FileNotFoundException {
1215                 
1216                 Properties p = new Properties();
1217                 
1218                 try(FileReader rdr = new FileReader(
1219                                 "src/test/resources/feature-session-persistence.properties")) {
1220                         p.load(rdr);
1221                 }
1222                 
1223                 return p;
1224         }
1225
1226         /**
1227          * Create a mock DB connection and statement.
1228          * @param retval        value to be returned when the statement is executed,
1229          *                                      or negative to throw an exception
1230          * @return the statement that will be returned by the connection
1231          * @throws SQLException
1232          */
1233         private PreparedStatement mockDbConn(int retval) throws SQLException {
1234                 Connection c = mock(Connection.class);
1235                 PreparedStatement s = mock(PreparedStatement.class);
1236
1237                 when(fact.makeDbConnection(anyString(), anyString(), anyString()))
1238                                 .thenReturn(c);
1239                 when(c.prepareStatement(anyString())).thenReturn(s);
1240                 
1241                 if(retval < 0) {
1242                         // should throw an exception
1243                         when(s.executeUpdate())
1244                                 .thenThrow( new SQLException("expected exception"));
1245                         
1246                 } else {
1247                         // should return the value
1248                         when(s.executeUpdate()).thenReturn(retval);
1249                 }
1250                 
1251                 return s;
1252         }
1253         
1254         /**
1255          * A partial factory, which exports a few of the real methods, but
1256          * overrides the rest.
1257          */
1258         private class PartialFactory extends PersistenceFeature.Factory {
1259                 
1260                 @Override
1261                 public PoolingDataSource makePoolingDataSource() {
1262                         return pds;
1263                 }
1264
1265                 @Override
1266                 public KieServices getKieServices() {
1267                         return kiesvc;
1268                 }
1269
1270                 @Override
1271                 public BitronixTransactionManager getTransMgr() {
1272                         return null;
1273                 }
1274
1275                 @Override
1276                 public EntityManagerFactory makeEntMgrFact(String pu,
1277                                                                                                         Properties propMap) {
1278                         if(pu.equals("onapsessionsPU")) {
1279                                 return null;
1280                         }
1281                         
1282                         return super.makeEntMgrFact("junitPersistenceFeaturePU", propMap);
1283                 }
1284
1285                 @Override
1286                 public PolicyController getPolicyContainer(PolicyContainer container) {
1287                         return polctlr;
1288                 }
1289                 
1290         }
1291 }