2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2020-2021 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 package org.onap.policy.controlloop.eventmanager;
23 import static org.assertj.core.api.Assertions.assertThat;
24 import static org.assertj.core.api.Assertions.assertThatCode;
25 import static org.junit.Assert.assertEquals;
26 import static org.junit.Assert.assertFalse;
27 import static org.junit.Assert.assertNotNull;
28 import static org.junit.Assert.assertSame;
29 import static org.junit.Assert.assertTrue;
30 import static org.mockito.Mockito.verify;
32 import java.io.IOException;
33 import java.util.ArrayList;
34 import java.util.List;
35 import java.util.UUID;
36 import java.util.concurrent.CompletableFuture;
37 import java.util.concurrent.ExecutorService;
38 import org.junit.Before;
39 import org.junit.Test;
40 import org.junit.runner.RunWith;
41 import org.mockito.ArgumentCaptor;
42 import org.mockito.Mock;
43 import org.mockito.junit.MockitoJUnitRunner;
44 import org.onap.policy.common.utils.coder.Coder;
45 import org.onap.policy.common.utils.coder.CoderException;
46 import org.onap.policy.common.utils.coder.StandardYamlCoder;
47 import org.onap.policy.common.utils.io.Serializer;
48 import org.onap.policy.common.utils.resources.ResourceUtils;
49 import org.onap.policy.controlloop.ControlLoopException;
50 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
51 import org.onap.policy.controlloop.actorserviceprovider.OperationResult;
52 import org.onap.policy.controlloop.drl.legacy.ControlLoopParams;
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;
60 @RunWith(MockitoJUnitRunner.class)
61 public class ControlLoopEventManagerTest {
62 private static final UUID REQ_ID = UUID.randomUUID();
63 private static final String EXPECTED_EXCEPTION = "expected exception";
64 private static final String CL_NAME = "my-closed-loop-name";
65 private static final String POLICY_NAME = "my-policy-name";
66 private static final String POLICY_SCOPE = "my-scope";
67 private static final String POLICY_VERSION = "1.2.3";
68 private static final String LOCK1 = "my-lock-A";
69 private static final String LOCK2 = "my-lock-B";
70 private static final Coder yamlCoder = new StandardYamlCoder();
71 private static final String MY_KEY = "def";
74 private ExecutorService executor;
76 private long preCreateTimeMs;
77 private List<LockImpl> locks;
78 private ToscaPolicy tosca;
79 private ControlLoopParams params;
80 private ControlLoopEventManager mgr;
86 public void setUp() throws ControlLoopException, CoderException {
87 params = new ControlLoopParams();
88 params.setClosedLoopControlName(CL_NAME);
89 params.setPolicyName(POLICY_NAME);
90 params.setPolicyScope(POLICY_SCOPE);
91 params.setPolicyVersion(POLICY_VERSION);
93 loadPolicy("eventManager/event-mgr-simple.yaml");
95 locks = new ArrayList<>();
97 preCreateTimeMs = System.currentTimeMillis();
99 MyManager.executor = executor;
100 MyManager.locks = locks;
102 mgr = new MyManager(params, REQ_ID);
106 public void testConstructor() {
107 assertEquals(POLICY_NAME, mgr.getPolicyName());
109 assertTrue(mgr.isActive());
110 assertEquals(CL_NAME, mgr.getClosedLoopControlName());
111 assertSame(REQ_ID, mgr.getRequestId());
112 assertEquals(POLICY_NAME, mgr.getPolicyName());
113 assertEquals(POLICY_VERSION, mgr.getPolicyVersion());
114 assertNotNull(mgr.getProcessor());
115 assertThat(mgr.getEndTimeMs()).isGreaterThanOrEqualTo(preCreateTimeMs);
119 public void testGetCreateCount() throws ControlLoopException {
120 long original = ControlLoopEventManager.getCreateCount();
122 new MyManager(params, REQ_ID);
123 assertEquals(original + 1, ControlLoopEventManager.getCreateCount());
125 new MyManager(params, REQ_ID);
126 assertEquals(original + 2, ControlLoopEventManager.getCreateCount());
130 public void testIsActive() throws Exception {
131 mgr = new ControlLoopEventManager(params, REQ_ID);
132 assertTrue(mgr.isActive());
134 ControlLoopEventManager mgr2 = Serializer.roundTrip(mgr);
135 assertFalse(mgr2.isActive());
139 public void testDestroy() throws IOException {
140 mgr.requestLock(LOCK1);
141 mgr.requestLock(LOCK2);
142 mgr.requestLock(LOCK1);
144 // ensure destroy() doesn't throw an exception if the object is deserialized
145 ControlLoopEventManager mgr2 = Serializer.roundTrip(mgr);
146 assertThatCode(() -> mgr2.destroy()).doesNotThrowAnyException();
148 // locks should not have been freed
149 for (LockImpl lock : locks) {
150 assertFalse(lock.isUnavailable());
157 for (LockImpl lock : locks) {
158 assertTrue(lock.isUnavailable());
163 public void testDetmControlLoopTimeoutMs() throws Exception {
164 long timeMs = 1200 * 1000L;
165 long end = mgr.getEndTimeMs();
166 assertThat(end).isGreaterThanOrEqualTo(preCreateTimeMs + timeMs).isLessThan(preCreateTimeMs + timeMs + 5000);
170 public void testRequestLock() {
171 final CompletableFuture<OperationOutcome> future1 = mgr.requestLock(LOCK1);
172 assertTrue(mgr.getOutcomes().isEmpty());
174 final CompletableFuture<OperationOutcome> future2 = mgr.requestLock(LOCK2);
175 assertTrue(mgr.getOutcomes().isEmpty());
177 assertSame(future1, mgr.requestLock(LOCK1));
178 assertTrue(mgr.getOutcomes().isEmpty());
180 assertEquals(2, locks.size());
182 assertTrue(future1.isDone());
183 assertTrue(future2.isDone());
185 // indicate that the first lock failed
186 locks.get(0).notifyUnavailable();
188 verifyLock(OperationResult.FAILURE, ActorConstants.LOCK_OPERATION);
189 assertTrue(mgr.getOutcomes().isEmpty());
193 public void testReleaseLock() {
194 mgr.requestLock(LOCK1);
195 mgr.requestLock(LOCK2);
198 final CompletableFuture<OperationOutcome> future = mgr.releaseLock(LOCK1);
200 // asynchronous, thus should not have executed yet
201 assertThat(future.isDone()).isFalse();
203 // asynchronous, thus everything should still be locked
204 for (LockImpl lock : locks) {
205 assertThat(lock.isUnavailable()).isFalse();
210 verifyLock(OperationResult.SUCCESS, ActorConstants.UNLOCK_OPERATION);
211 assertThat(mgr.getOutcomes()).isEmpty();
213 // first lock should have been released, thus no longer available to the manager
214 assertThat(locks.get(0).isUnavailable()).isTrue();
216 // second should still be locked
217 assertThat(locks.get(1).isUnavailable()).isFalse();
221 * Tests releaseLock() when there is no lock.
224 public void testReleaseLockNotLocked() {
225 final CompletableFuture<OperationOutcome> future = mgr.releaseLock(LOCK1);
227 // lock didn't exist, so the request should already be complete
228 assertThat(future.isDone()).isTrue();
230 verifyLock(OperationResult.SUCCESS, ActorConstants.UNLOCK_OPERATION);
231 assertThat(mgr.getOutcomes()).isEmpty();
235 * Tests releaseLock() when lock.free() throws an exception.
238 public void testReleaseLockException() throws ControlLoopException {
239 mgr = new MyManager(params, REQ_ID) {
240 private static final long serialVersionUID = 1L;
243 protected void makeLock(String targetEntity, String requestId, int holdSec, LockCallback callback) {
245 LockImpl lock = new LockImpl(LockState.ACTIVE, targetEntity, requestId, holdSec, callback) {
246 private static final long serialVersionUID = 1L;
249 public boolean free() {
250 throw new RuntimeException(EXPECTED_EXCEPTION);
255 callback.lockAvailable(lock);
259 mgr.requestLock(LOCK1);
262 final CompletableFuture<OperationOutcome> future = mgr.releaseLock(LOCK1);
264 // asynchronous, thus should not have executed yet
265 assertThat(future.isDone()).isFalse();
269 verifyLock(OperationResult.FAILURE_EXCEPTION, ActorConstants.UNLOCK_OPERATION);
270 assertThat(mgr.getOutcomes()).isEmpty();
273 private void verifyLock(OperationResult result, String lockOperation) {
274 OperationOutcome outcome = mgr.getOutcomes().poll();
275 assertNotNull(outcome);
276 assertEquals(ActorConstants.LOCK_ACTOR, outcome.getActor());
277 assertEquals(lockOperation, outcome.getOperation());
278 assertNotNull(outcome.getEnd());
279 assertTrue(outcome.isFinalOutcome());
280 assertEquals(result, outcome.getResult());
284 public void testOnStart() {
285 OperationOutcome outcome1 = new OperationOutcome();
286 OperationOutcome outcome2 = new OperationOutcome();
288 mgr.onStart(outcome1);
289 mgr.onStart(outcome2);
291 assertSame(outcome1, mgr.getOutcomes().poll());
292 assertSame(outcome2, mgr.getOutcomes().poll());
293 assertTrue(mgr.getOutcomes().isEmpty());
297 public void testOnComplete() {
298 OperationOutcome outcome1 = new OperationOutcome();
299 OperationOutcome outcome2 = new OperationOutcome();
301 mgr.onComplete(outcome1);
302 mgr.onComplete(outcome2);
304 assertSame(outcome1, mgr.getOutcomes().poll());
305 assertSame(outcome2, mgr.getOutcomes().poll());
306 assertTrue(mgr.getOutcomes().isEmpty());
310 public void testContains_testGetProperty_testSetProperty_testRemoveProperty() {
311 mgr.setProperty("abc", "a string");
312 mgr.setProperty(MY_KEY, 100);
314 assertTrue(mgr.contains(MY_KEY));
315 assertFalse(mgr.contains("ghi"));
317 String strValue = mgr.getProperty("abc");
318 assertEquals("a string", strValue);
320 int intValue = mgr.getProperty(MY_KEY);
321 assertEquals(100, intValue);
323 mgr.removeProperty(MY_KEY);
324 assertFalse(mgr.contains(MY_KEY));
328 * Tests getDataManager() when guard.disabled=true.
331 public void testGetDataManagerDisabled() throws ControlLoopException {
332 mgr = new MyManager(params, REQ_ID) {
333 private static final long serialVersionUID = 1L;
336 protected String getEnvironmentProperty(String propName) {
337 return ("guard.disabled".equals(propName) ? "true" : null);
341 assertThat(mgr.getDataManager()).isInstanceOf(OperationHistoryDataManagerStub.class);
345 public void testToString() {
346 assertNotNull(mgr.toString());
349 private void loadPolicy(String fileName) throws CoderException {
350 ToscaServiceTemplate template =
351 yamlCoder.decode(ResourceUtils.getResourceAsString(fileName), ToscaServiceTemplate.class);
352 tosca = template.getToscaTopologyTemplate().getPolicies().get(0).values().iterator().next();
354 params.setToscaPolicy(tosca);
357 private void runExecutor() {
358 ArgumentCaptor<Runnable> runCaptor = ArgumentCaptor.forClass(Runnable.class);
359 verify(executor).execute(runCaptor.capture());
361 runCaptor.getValue().run();
365 private static class MyManager extends ControlLoopEventManager {
366 private static final long serialVersionUID = 1L;
368 private static ExecutorService executor;
369 private static List<LockImpl> locks;
371 public MyManager(ControlLoopParams params, UUID requestId) throws ControlLoopException {
372 super(params, requestId);
376 protected ExecutorService getBlockingExecutor() {
381 protected void makeLock(String targetEntity, String requestId, int holdSec, LockCallback callback) {
382 LockImpl lock = new LockImpl(LockState.ACTIVE, targetEntity, requestId, holdSec, callback);
384 callback.lockAvailable(lock);