Fix rules-test missing junit-jupiter at compile scope.
[policy/drools-applications.git] / controlloop / common / eventmanager / src / test / java / org / onap / policy / controlloop / eventmanager / ControlLoopEventManagerTest.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP
4  * ================================================================================
5  * Copyright (C) 2020-2021 AT&T Intellectual Property. All rights reserved.
6  * Modifications Copyright (C) 2023 Nordix Foundation.
7  * ================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END=========================================================
20  */
21
22 package org.onap.policy.controlloop.eventmanager;
23
24 import static org.assertj.core.api.Assertions.assertThat;
25 import static org.assertj.core.api.Assertions.assertThatCode;
26 import static org.junit.jupiter.api.Assertions.assertEquals;
27 import static org.junit.jupiter.api.Assertions.assertFalse;
28 import static org.junit.jupiter.api.Assertions.assertNotNull;
29 import static org.junit.jupiter.api.Assertions.assertSame;
30 import static org.junit.jupiter.api.Assertions.assertTrue;
31 import static org.mockito.Mockito.mock;
32 import static org.mockito.Mockito.verify;
33 import static org.mockito.Mockito.when;
34
35 import java.io.IOException;
36 import java.util.ArrayList;
37 import java.util.List;
38 import java.util.UUID;
39 import java.util.concurrent.ExecutorService;
40 import org.junit.jupiter.api.BeforeEach;
41 import org.junit.jupiter.api.Test;
42 import org.mockito.ArgumentCaptor;
43 import org.onap.policy.common.utils.coder.Coder;
44 import org.onap.policy.common.utils.coder.CoderException;
45 import org.onap.policy.common.utils.coder.StandardYamlCoder;
46 import org.onap.policy.common.utils.io.Serializer;
47 import org.onap.policy.common.utils.resources.ResourceUtils;
48 import org.onap.policy.controlloop.ControlLoopException;
49 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
50 import org.onap.policy.controlloop.actorserviceprovider.OperationResult;
51 import org.onap.policy.controlloop.drl.legacy.ControlLoopParams;
52 import org.onap.policy.controlloop.ophistory.OperationHistoryDataManager;
53 import org.onap.policy.controlloop.ophistory.OperationHistoryDataManagerStub;
54 import org.onap.policy.drools.core.lock.LockCallback;
55 import org.onap.policy.drools.core.lock.LockImpl;
56 import org.onap.policy.drools.core.lock.LockState;
57 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
58 import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
59
60 class ControlLoopEventManagerTest {
61     private static final UUID REQ_ID = UUID.randomUUID();
62     private static final String EXPECTED_EXCEPTION = "expected exception";
63     private static final String CL_NAME = "my-closed-loop-name";
64     private static final String POLICY_NAME = "my-policy-name";
65     private static final String POLICY_SCOPE = "my-scope";
66     private static final String POLICY_VERSION = "1.2.3";
67     private static final String LOCK1 = "my-lock-A";
68     private static final String LOCK2 = "my-lock-B";
69     private static final Coder yamlCoder = new StandardYamlCoder();
70     private static final String MY_KEY = "def";
71
72     private final ExecutorService executor = mock(ExecutorService.class);
73     private final EventManagerServices services = mock(EventManagerServices.class);
74     private final OperationHistoryDataManager dataMgr = mock(OperationHistoryDataManager.class);
75
76     private long preCreateTimeMs;
77     private List<LockImpl> locks;
78     private ToscaPolicy tosca;
79     private ControlLoopParams params;
80     private ControlLoopEventManager mgr;
81
82     /**
83      * Sets up.
84      */
85     @BeforeEach
86     public void setUp() throws ControlLoopException, CoderException {
87         when(services.getDataManager()).thenReturn(dataMgr);
88
89         params = new ControlLoopParams();
90         params.setClosedLoopControlName(CL_NAME);
91         params.setPolicyName(POLICY_NAME);
92         params.setPolicyScope(POLICY_SCOPE);
93         params.setPolicyVersion(POLICY_VERSION);
94
95         loadPolicy("eventManager/event-mgr-simple.yaml");
96
97         locks = new ArrayList<>();
98
99         preCreateTimeMs = System.currentTimeMillis();
100
101         MyManager.executor = executor;
102         MyManager.locks = locks;
103
104         mgr = new MyManager(services, params, REQ_ID);
105     }
106
107     @Test
108     void testConstructor() {
109         assertEquals(POLICY_NAME, mgr.getPolicyName());
110
111         assertTrue(mgr.isActive());
112         assertEquals(CL_NAME, mgr.getClosedLoopControlName());
113         assertSame(REQ_ID, mgr.getRequestId());
114         assertEquals(POLICY_NAME, mgr.getPolicyName());
115         assertEquals(POLICY_VERSION, mgr.getPolicyVersion());
116         assertNotNull(mgr.getProcessor());
117         assertThat(mgr.getEndTimeMs()).isGreaterThanOrEqualTo(preCreateTimeMs);
118     }
119
120     @Test
121     void testGetCreateCount() throws ControlLoopException {
122         long original = ControlLoopEventManager.getCreateCount();
123
124         new MyManager(services, params, REQ_ID);
125         assertEquals(original + 1, ControlLoopEventManager.getCreateCount());
126
127         new MyManager(services, params, REQ_ID);
128         assertEquals(original + 2, ControlLoopEventManager.getCreateCount());
129     }
130
131     @Test
132     void testIsActive() throws Exception {
133         mgr = new ControlLoopEventManager(services, params, REQ_ID);
134         assertTrue(mgr.isActive());
135
136         var mgr2 = Serializer.roundTrip(mgr);
137         assertFalse(mgr2.isActive());
138     }
139
140     @Test
141     void testDestroy() throws IOException {
142         mgr.requestLock(LOCK1);
143         mgr.requestLock(LOCK2);
144         mgr.requestLock(LOCK1);
145
146         // ensure destroy() doesn't throw an exception if the object is deserialized
147         var mgr2 = Serializer.roundTrip(mgr);
148         assertThatCode(() -> mgr2.destroy()).doesNotThrowAnyException();
149
150         // locks should not have been freed
151         for (var lock : locks) {
152             assertFalse(lock.isUnavailable());
153         }
154
155         mgr.destroy();
156
157         runExecutor();
158
159         for (var lock : locks) {
160             assertTrue(lock.isUnavailable());
161         }
162     }
163
164     @Test
165     void testDetmControlLoopTimeoutMs() throws Exception {
166         long timeMs = 1200 * 1000L;
167         long end = mgr.getEndTimeMs();
168         assertThat(end).isGreaterThanOrEqualTo(preCreateTimeMs + timeMs).isLessThan(preCreateTimeMs + timeMs + 5000);
169     }
170
171     @Test
172     void testRequestLock() {
173         final var future1 = mgr.requestLock(LOCK1);
174         assertTrue(mgr.getOutcomes().isEmpty());
175
176         final var future2 = mgr.requestLock(LOCK2);
177         assertTrue(mgr.getOutcomes().isEmpty());
178
179         assertSame(future1, mgr.requestLock(LOCK1));
180         assertTrue(mgr.getOutcomes().isEmpty());
181
182         assertEquals(2, locks.size());
183
184         assertTrue(future1.isDone());
185         assertTrue(future2.isDone());
186
187         // indicate that the first lock failed
188         locks.get(0).notifyUnavailable();
189
190         verifyLock(OperationResult.FAILURE, ActorConstants.LOCK_OPERATION);
191         assertTrue(mgr.getOutcomes().isEmpty());
192     }
193
194     @Test
195     void testReleaseLock() {
196         mgr.requestLock(LOCK1);
197         mgr.requestLock(LOCK2);
198
199         // release one lock
200         final var future = mgr.releaseLock(LOCK1);
201
202         // asynchronous, thus should not have executed yet
203         assertThat(future.isDone()).isFalse();
204
205         // asynchronous, thus everything should still be locked
206         for (var lock : locks) {
207             assertThat(lock.isUnavailable()).isFalse();
208         }
209
210         runExecutor();
211
212         verifyLock(OperationResult.SUCCESS, ActorConstants.UNLOCK_OPERATION);
213         assertThat(mgr.getOutcomes()).isEmpty();
214
215         // first lock should have been released, thus no longer available to the manager
216         assertThat(locks.get(0).isUnavailable()).isTrue();
217
218         // second should still be locked
219         assertThat(locks.get(1).isUnavailable()).isFalse();
220     }
221
222     /**
223      * Tests releaseLock() when there is no lock.
224      */
225     @Test
226     void testReleaseLockNotLocked() {
227         final var future = mgr.releaseLock(LOCK1);
228
229         // lock didn't exist, so the request should already be complete
230         assertThat(future.isDone()).isTrue();
231
232         verifyLock(OperationResult.SUCCESS, ActorConstants.UNLOCK_OPERATION);
233         assertThat(mgr.getOutcomes()).isEmpty();
234     }
235
236     /**
237      * Tests releaseLock() when lock.free() throws an exception.
238      */
239     @Test
240     void testReleaseLockException() throws ControlLoopException {
241         mgr = new MyManager(services, params, REQ_ID) {
242             private static final long serialVersionUID = 1L;
243
244             @Override
245             protected void makeLock(String targetEntity, String requestId, int holdSec, LockCallback callback) {
246
247                 var lock = new LockImpl(LockState.ACTIVE, targetEntity, requestId, holdSec, callback) {
248                     private static final long serialVersionUID = 1L;
249
250                     @Override
251                     public boolean free() {
252                         throw new RuntimeException(EXPECTED_EXCEPTION);
253                     }
254                 };
255
256                 locks.add(lock);
257                 callback.lockAvailable(lock);
258             }
259         };
260
261         mgr.requestLock(LOCK1);
262
263         // release the lock
264         final var future = mgr.releaseLock(LOCK1);
265
266         // asynchronous, thus should not have executed yet
267         assertThat(future.isDone()).isFalse();
268
269         runExecutor();
270
271         verifyLock(OperationResult.FAILURE_EXCEPTION, ActorConstants.UNLOCK_OPERATION);
272         assertThat(mgr.getOutcomes()).isEmpty();
273     }
274
275     private void verifyLock(OperationResult result, String lockOperation) {
276         var outcome = mgr.getOutcomes().poll();
277         assertNotNull(outcome);
278         assertEquals(ActorConstants.LOCK_ACTOR, outcome.getActor());
279         assertEquals(lockOperation, outcome.getOperation());
280         assertNotNull(outcome.getEnd());
281         assertTrue(outcome.isFinalOutcome());
282         assertEquals(result, outcome.getResult());
283     }
284
285     @Test
286     void testOnStart() {
287         var outcome1 = new OperationOutcome();
288         var outcome2 = new OperationOutcome();
289
290         mgr.onStart(outcome1);
291         mgr.onStart(outcome2);
292
293         assertSame(outcome1, mgr.getOutcomes().poll());
294         assertSame(outcome2, mgr.getOutcomes().poll());
295         assertTrue(mgr.getOutcomes().isEmpty());
296     }
297
298     @Test
299     void testOnComplete() {
300         var outcome1 = new OperationOutcome();
301         var outcome2 = new OperationOutcome();
302
303         mgr.onComplete(outcome1);
304         mgr.onComplete(outcome2);
305
306         assertSame(outcome1, mgr.getOutcomes().poll());
307         assertSame(outcome2, mgr.getOutcomes().poll());
308         assertTrue(mgr.getOutcomes().isEmpty());
309     }
310
311     @Test
312     void testContains_testGetProperty_testSetProperty_testRemoveProperty() {
313         mgr.setProperty("abc", "a string");
314         mgr.setProperty(MY_KEY, 100);
315
316         assertTrue(mgr.contains(MY_KEY));
317         assertFalse(mgr.contains("ghi"));
318
319         var strValue = mgr.getProperty("abc");
320         assertEquals("a string", strValue);
321
322         int intValue = mgr.getProperty(MY_KEY);
323         assertEquals(100, intValue);
324
325         mgr.removeProperty(MY_KEY);
326         assertFalse(mgr.contains(MY_KEY));
327     }
328
329     /**
330      * Tests getDataManager() when not disabled.
331      */
332     @Test
333     void testGetDataManagerNotDisabled() throws ControlLoopException {
334         assertThat(mgr.getDataManager()).isSameAs(dataMgr);
335     }
336
337     /**
338      * Tests getDataManager() when guard.disabled=true.
339      */
340     @Test
341     void testGetDataManagerDisabled() throws ControlLoopException {
342         mgr = new MyManager(services, params, REQ_ID) {
343             private static final long serialVersionUID = 1L;
344
345             @Override
346             protected String getEnvironmentProperty(String propName) {
347                 return ("guard.disabled".equals(propName) ? "true" : null);
348             }
349         };
350
351         assertThat(mgr.getDataManager()).isInstanceOf(OperationHistoryDataManagerStub.class);
352     }
353
354     @Test
355     void testToString() {
356         assertNotNull(mgr.toString());
357     }
358
359     private void loadPolicy(String fileName) throws CoderException {
360         var template = yamlCoder.decode(ResourceUtils.getResourceAsString(fileName), ToscaServiceTemplate.class);
361         tosca = template.getToscaTopologyTemplate().getPolicies().get(0).values().iterator().next();
362
363         params.setToscaPolicy(tosca);
364     }
365
366     private void runExecutor() {
367         var runCaptor = ArgumentCaptor.forClass(Runnable.class);
368         verify(executor).execute(runCaptor.capture());
369
370         runCaptor.getValue().run();
371     }
372
373
374     private static class MyManager extends ControlLoopEventManager {
375         private static final long serialVersionUID = 1L;
376
377         private static ExecutorService executor;
378         private static List<LockImpl> locks;
379
380         public MyManager(EventManagerServices services, ControlLoopParams params, UUID requestId)
381                         throws ControlLoopException {
382             super(services, params, requestId);
383         }
384
385         @Override
386         protected ExecutorService getBlockingExecutor() {
387             return executor;
388         }
389
390         @Override
391         protected void makeLock(String targetEntity, String requestId, int holdSec, LockCallback callback) {
392             var lock = new LockImpl(LockState.ACTIVE, targetEntity, requestId, holdSec, callback);
393             locks.add(lock);
394             callback.lockAvailable(lock);
395         }
396     }
397 }