0ce12dfc562879e2a2189bb1c4c072b4fceb2464
[policy/drools-pdp.git] /
1 /*
2  * ============LICENSE_START=======================================================
3  * feature-active-standby-management
4  * ================================================================================
5  * Copyright (C) 2017-2019 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.activestandby;
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.assertTrue;
27 import static org.mockito.Mockito.mock;
28 import static org.mockito.Mockito.when;
29
30 import java.io.FileInputStream;
31 import java.io.IOException;
32 import java.util.Date;
33 import java.util.Properties;
34 import java.util.concurrent.Callable;
35 import javax.persistence.EntityManager;
36 import javax.persistence.EntityManagerFactory;
37 import javax.persistence.EntityTransaction;
38 import javax.persistence.Persistence;
39 import org.apache.commons.lang3.time.DateUtils;
40 import org.junit.AfterClass;
41 import org.junit.Before;
42 import org.junit.BeforeClass;
43 import org.junit.Test;
44 import org.onap.policy.common.im.IntegrityMonitor;
45 import org.onap.policy.common.im.IntegrityMonitorException;
46 import org.onap.policy.common.im.MonitorTime;
47 import org.onap.policy.common.im.StateManagement;
48 import org.onap.policy.common.utils.time.CurrentTime;
49 import org.onap.policy.common.utils.time.PseudoTimer;
50 import org.onap.policy.common.utils.time.TestTimeMulti;
51 import org.onap.policy.drools.core.PolicySessionFeatureApi;
52 import org.onap.policy.drools.statemanagement.StateManagementFeatureApi;
53 import org.onap.policy.drools.statemanagement.StateManagementFeatureApiConstants;
54 import org.powermock.reflect.Whitebox;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
57
58 /*
59  * Testing the allSeemsWell interface to verify that it correctly affects the
60  * operational state.
61  */
62
63 public class AllSeemsWellTest {
64     private static final Logger  logger = LoggerFactory.getLogger(AllSeemsWellTest.class);
65
66     private static final String MONITOR_FIELD_NAME = "instance";
67     private static final String HANDLER_INSTANCE_FIELD = "electionHandler";
68
69     /*
70      * Currently, the DroolsPdpsElectionHandler.DesignationWaiter is invoked every 1 seconds, starting
71      * at the start of the next multiple of pdpUpdateInterval, but with a minimum of 5 sec cushion
72      * to ensure that we wait for the DesignationWaiter to do its job, before
73      * checking the results. Add a few seconds for safety
74      */
75
76     private static final int SLEEP_TIME_SEC = 10;
77
78     /*
79      * DroolsPdpsElectionHandler runs every 1 seconds, so it takes 10 seconds for the
80      * checkWaitTimer() method to time out and call allSeemsWell which then requires
81      * the forward progress counter to go stale which should add an additional 5 sec.
82      */
83
84     private static final int STALLED_ELECTION_HANDLER_SLEEP_TIME_SEC = 15;
85
86     /*
87      * As soon as the election hander successfully runs, it will resume the forward progress.
88      * If the election handler runs ever 1 sec and test transaction is run every 1 sec and
89      * then fpc is written every 1 sec and then the fpc is checked every 2 sec, that could
90      * take a total of 5 sec to recognize the resumption of progress.  So, add 1 for safety.
91      */
92     private static final int RESUMED_ELECTION_HANDLER_SLEEP_TIME_SEC = 6;
93
94     private static EntityManagerFactory emfx;
95     private static EntityManagerFactory emfd;
96     private static EntityManager emx;
97     private static EntityManager emd;
98     private static EntityTransaction et;
99
100     private static final String CONFIG_DIR = "src/test/resources/asw";
101
102     private static CurrentTime saveTime;
103     private static Factory saveFactory;
104
105     private TestTimeMulti testTime;
106
107     /*
108      * See the IntegrityMonitor.getJmxUrl() method for the rationale behind this jmx related processing.
109      */
110
111     /**
112      * Setup the class.
113      *
114      * @throws Exception exception
115      */
116     @BeforeClass
117     public static void setUpClass() throws Exception {
118
119         String userDir = System.getProperty("user.dir");
120         logger.debug("setUpClass: userDir={}", userDir);
121         System.setProperty("com.sun.management.jmxremote.port", "9980");
122         System.setProperty("com.sun.management.jmxremote.authenticate", "false");
123
124         DroolsPdpsElectionHandler.setIsUnitTesting(true);
125
126         saveTime = Whitebox.getInternalState(MonitorTime.class, MONITOR_FIELD_NAME);
127         saveFactory = Factory.getInstance();
128
129         resetInstanceObjects();
130
131         //Create the data access for xacml db
132         Properties stateManagementProperties = loadStateManagementProperties();
133
134         emfx = Persistence.createEntityManagerFactory("junitXacmlPU", stateManagementProperties);
135
136         // Create an entity manager to use the DB
137         emx = emfx.createEntityManager();
138
139         //Create the data access for drools db
140         Properties activeStandbyProperties = loadActiveStandbyProperties();
141
142         emfd = Persistence.createEntityManagerFactory("junitDroolsPU", activeStandbyProperties);
143
144         // Create an entity manager to use the DB
145         emd = emfd.createEntityManager();
146     }
147
148     /**
149      * Restores the system state.
150      *
151      * @throws IntegrityMonitorException if the integrity monitor cannot be shut down
152      */
153     @AfterClass
154     public static void tearDownClass() throws IntegrityMonitorException {
155         resetInstanceObjects();
156
157         Whitebox.setInternalState(MonitorTime.class, MONITOR_FIELD_NAME, saveTime);
158         Factory.setInstance(saveFactory);
159
160         DroolsPdpsElectionHandler.setIsUnitTesting(false);
161
162         emd.close();
163         emfd.close();
164
165         emx.close();
166         emfx.close();
167     }
168
169     /**
170      * Setup.
171      *
172      * @throws Exception exception
173      */
174     @Before
175     public void setUp() throws Exception {
176         resetInstanceObjects();
177
178         // set test time
179         testTime = new TestTimeMulti();
180         Whitebox.setInternalState(MonitorTime.class, MONITOR_FIELD_NAME, testTime);
181
182         Factory factory = mock(Factory.class);
183         when(factory.makeTimer()).thenAnswer(ans -> new PseudoTimer(testTime));
184         Factory.setInstance(factory);
185     }
186
187     private static void resetInstanceObjects() throws IntegrityMonitorException {
188         IntegrityMonitor.setUnitTesting(true);
189         IntegrityMonitor.deleteInstance();
190         IntegrityMonitor.setUnitTesting(false);
191
192         Whitebox.setInternalState(ActiveStandbyFeature.class, HANDLER_INSTANCE_FIELD, (Object) null);
193
194     }
195
196     /**
197      * Clean the xacml database.
198      */
199     public void cleanXacmlDb() {
200         et = emx.getTransaction();
201
202         et.begin();
203         // Make sure we leave the DB clean
204         emx.createQuery("DELETE FROM StateManagementEntity").executeUpdate();
205         emx.createQuery("DELETE FROM ResourceRegistrationEntity").executeUpdate();
206         emx.createQuery("DELETE FROM ForwardProgressEntity").executeUpdate();
207         emx.flush();
208         et.commit();
209     }
210
211     /**
212      * Clean the drools database.
213      */
214     public void cleanDroolsDb() {
215         et = emd.getTransaction();
216
217         et.begin();
218         // Make sure we leave the DB clean
219         emd.createQuery("DELETE FROM DroolsPdpEntity").executeUpdate();
220         emd.flush();
221         et.commit();
222     }
223
224
225     // Tests hot standby when there is only one PDP.
226
227     //@Ignore
228     @Test
229     public void testAllSeemsWell() throws Exception {
230
231         logger.debug("\n\ntestAllSeemsWell: Entering\n\n");
232         cleanXacmlDb();
233         cleanDroolsDb();
234
235         Properties stateManagementProperties = loadStateManagementProperties();
236
237         logger.debug("testAllSeemsWell: Creating emfXacml");
238         final EntityManagerFactory emfXacml = Persistence.createEntityManagerFactory(
239                 "junitXacmlPU", stateManagementProperties);
240
241         Properties activeStandbyProperties = loadActiveStandbyProperties();
242         final String thisPdpId = activeStandbyProperties
243                 .getProperty(ActiveStandbyProperties.NODE_NAME);
244
245         logger.debug("testAllSeemsWell: Creating emfDrools");
246         EntityManagerFactory emfDrools = Persistence.createEntityManagerFactory(
247                 "junitDroolsPU", activeStandbyProperties);
248
249         DroolsPdpsConnector conn = new JpaDroolsPdpsConnector(emfDrools);
250
251         logger.debug("testAllSeemsWell: Cleaning up tables");
252         conn.deleteAllPdps();
253
254         /*
255          * Insert this PDP as not designated.  Initial standby state will be
256          * either null or cold standby.   Demoting should transit state to
257          * hot standby.
258          */
259
260         logger.debug("testAllSeemsWell: Inserting PDP={} as not designated", thisPdpId);
261         Date yesterday = DateUtils.addDays(testTime.getDate(), -1);
262         DroolsPdpImpl pdp = new DroolsPdpImpl(thisPdpId, false, 4, yesterday);
263         conn.insertPdp(pdp);
264         DroolsPdpEntity droolsPdpEntity = conn.getPdp(thisPdpId);
265         logger.debug("testAllSeemsWell: After insertion, PDP={} has DESIGNATED={}",
266                 thisPdpId, droolsPdpEntity.isDesignated());
267         assertFalse(droolsPdpEntity.isDesignated());
268
269         logger.debug("testAllSeemsWell: Instantiating stateManagement object");
270         StateManagement sm = new StateManagement(emfXacml, "dummy");
271         sm.deleteAllStateManagementEntities();
272
273
274         // Now we want to create a StateManagementFeature and initialize it.  It will be
275         // discovered by the ActiveStandbyFeature when the election handler initializes.
276
277         StateManagementFeatureApi stateManagementFeatureApi = null;
278         for (StateManagementFeatureApi feature : StateManagementFeatureApiConstants.getImpl().getList()) {
279             ((PolicySessionFeatureApi) feature).globalInit(null, CONFIG_DIR);
280             stateManagementFeatureApi = feature;
281             logger.debug("testAllSeemsWell stateManagementFeature.getResourceName(): {}",
282                 stateManagementFeatureApi.getResourceName());
283             break;
284         }
285         assertNotNull(stateManagementFeatureApi);
286
287         final StateManagementFeatureApi smf = stateManagementFeatureApi;
288
289         // Create an ActiveStandbyFeature and initialize it. It will discover the StateManagementFeature
290         // that has been created.
291         ActiveStandbyFeatureApi activeStandbyFeature = null;
292         for (ActiveStandbyFeatureApi feature : ActiveStandbyFeatureApiConstants.getImpl().getList()) {
293             ((PolicySessionFeatureApi) feature).globalInit(null, CONFIG_DIR);
294             activeStandbyFeature = feature;
295             logger.debug("testAllSeemsWell activeStandbyFeature.getResourceName(): {}",
296                     activeStandbyFeature.getResourceName());
297             break;
298         }
299         assertNotNull(activeStandbyFeature);
300
301
302         logger.debug("testAllSeemsWell: Demoting PDP={}", thisPdpId);
303         // demoting should cause state to transit to hotstandby
304         smf.demote();
305
306
307         logger.debug("testAllSeemsWell: Sleeping {} s, to allow JpaDroolsPdpsConnector "
308                         + "time to check droolspdpentity table", SLEEP_TIME_SEC);
309         waitForCondition(() -> conn.getPdp(thisPdpId).isDesignated(), SLEEP_TIME_SEC);
310
311         // Verify that this formerly un-designated PDP in HOT_STANDBY is now designated and providing service.
312
313         droolsPdpEntity = conn.getPdp(thisPdpId);
314         logger.debug("testAllSeemsWell: After sm.demote() invoked, DESIGNATED= {} "
315                 + "for PDP= {}", droolsPdpEntity.isDesignated(), thisPdpId);
316         assertTrue(droolsPdpEntity.isDesignated());
317         String standbyStatus = smf.getStandbyStatus(thisPdpId);
318         logger.debug("testAllSeemsWell: After demotion, PDP= {} "
319                 + "has standbyStatus= {}", thisPdpId, standbyStatus);
320         assertTrue(standbyStatus != null  &&  standbyStatus.equals(StateManagement.PROVIDING_SERVICE));
321
322         //Now we want to stall the election handler and see the if AllSeemsWell will make the
323         //standbystatus = coldstandby
324
325         DroolsPdpsElectionHandler.setIsStalled(true);
326
327         logger.debug("testAllSeemsWell: Sleeping {} s, to allow checkWaitTimer to recognize "
328                 + "the election handler has stalled and for the testTransaction to fail to "
329                 + "increment forward progress and for the lack of forward progress to be recognized.",
330             STALLED_ELECTION_HANDLER_SLEEP_TIME_SEC);
331
332
333         //It takes 10x the update interval (1 sec) before the watcher will declare the election handler dead
334         //and that just stops forward progress counter.  So, the fp monitor must then run to determine
335         // if the fpc has stalled. That will take about another 5 sec.
336         waitForCondition(() -> smf.getStandbyStatus().equals(StateManagement.COLD_STANDBY),
337             STALLED_ELECTION_HANDLER_SLEEP_TIME_SEC);
338
339         logger.debug("testAllSeemsWell: After isStalled=true, PDP= {} "
340                 + "has standbyStatus= {}", thisPdpId, smf.getStandbyStatus(thisPdpId));
341         assertEquals(StateManagement.COLD_STANDBY, smf.getStandbyStatus());
342
343         //Now lets resume the election handler
344         DroolsPdpsElectionHandler.setIsStalled(false);
345
346         waitForCondition(() -> smf.getStandbyStatus().equals(StateManagement.PROVIDING_SERVICE),
347             RESUMED_ELECTION_HANDLER_SLEEP_TIME_SEC);
348
349         logger.debug("testAllSeemsWell: After isStalled=false, PDP= {} "
350                 + "has standbyStatus= {}", thisPdpId, smf.getStandbyStatus(thisPdpId));
351
352         assertEquals(StateManagement.PROVIDING_SERVICE, smf.getStandbyStatus());
353
354         //resumedElectionHandlerSleepTime = 5000;
355         logger.debug("\n\ntestAllSeemsWell: Exiting\n\n");
356
357     }
358
359     private static Properties loadStateManagementProperties() throws IOException {
360         try (FileInputStream input = new FileInputStream(CONFIG_DIR + "/feature-state-management.properties")) {
361             Properties props = new Properties();
362             props.load(input);
363             return props;
364         }
365     }
366
367     private static Properties loadActiveStandbyProperties() throws IOException {
368         try (FileInputStream input =
369                         new FileInputStream(CONFIG_DIR + "/feature-active-standby-management.properties")) {
370             Properties props = new Properties();
371             props.load(input);
372             return props;
373         }
374     }
375
376     private void waitForCondition(Callable<Boolean> testCondition, int timeoutInSeconds) throws InterruptedException {
377         testTime.waitUntil(testCondition);
378     }
379 }