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