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;
31 import static org.mockito.Mockito.when;
33 import java.io.IOException;
34 import java.util.ArrayList;
35 import java.util.List;
36 import java.util.UUID;
37 import java.util.concurrent.CompletableFuture;
38 import java.util.concurrent.ExecutorService;
39 import org.junit.Before;
40 import org.junit.Test;
41 import org.junit.runner.RunWith;
42 import org.mockito.ArgumentCaptor;
43 import org.mockito.Mock;
44 import org.mockito.junit.MockitoJUnitRunner;
45 import org.onap.policy.common.utils.coder.Coder;
46 import org.onap.policy.common.utils.coder.CoderException;
47 import org.onap.policy.common.utils.coder.StandardYamlCoder;
48 import org.onap.policy.common.utils.io.Serializer;
49 import org.onap.policy.common.utils.resources.ResourceUtils;
50 import org.onap.policy.controlloop.ControlLoopException;
51 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
52 import org.onap.policy.controlloop.actorserviceprovider.OperationResult;
53 import org.onap.policy.controlloop.drl.legacy.ControlLoopParams;
54 import org.onap.policy.controlloop.ophistory.OperationHistoryDataManager;
55 import org.onap.policy.controlloop.ophistory.OperationHistoryDataManagerStub;
56 import org.onap.policy.drools.core.lock.LockCallback;
57 import org.onap.policy.drools.core.lock.LockImpl;
58 import org.onap.policy.drools.core.lock.LockState;
59 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
60 import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
62 @RunWith(MockitoJUnitRunner.class)
63 public class ControlLoopEventManagerTest {
64 private static final UUID REQ_ID = UUID.randomUUID();
65 private static final String EXPECTED_EXCEPTION = "expected exception";
66 private static final String CL_NAME = "my-closed-loop-name";
67 private static final String POLICY_NAME = "my-policy-name";
68 private static final String POLICY_SCOPE = "my-scope";
69 private static final String POLICY_VERSION = "1.2.3";
70 private static final String LOCK1 = "my-lock-A";
71 private static final String LOCK2 = "my-lock-B";
72 private static final Coder yamlCoder = new StandardYamlCoder();
73 private static final String MY_KEY = "def";
76 private ExecutorService executor;
78 private EventManagerServices services;
80 private OperationHistoryDataManager dataMgr;
82 private long preCreateTimeMs;
83 private List<LockImpl> locks;
84 private ToscaPolicy tosca;
85 private ControlLoopParams params;
86 private ControlLoopEventManager mgr;
92 public void setUp() throws ControlLoopException, CoderException {
93 when(services.getDataManager()).thenReturn(dataMgr);
95 params = new ControlLoopParams();
96 params.setClosedLoopControlName(CL_NAME);
97 params.setPolicyName(POLICY_NAME);
98 params.setPolicyScope(POLICY_SCOPE);
99 params.setPolicyVersion(POLICY_VERSION);
101 loadPolicy("eventManager/event-mgr-simple.yaml");
103 locks = new ArrayList<>();
105 preCreateTimeMs = System.currentTimeMillis();
107 MyManager.executor = executor;
108 MyManager.locks = locks;
110 mgr = new MyManager(services, params, REQ_ID);
114 public void testConstructor() {
115 assertEquals(POLICY_NAME, mgr.getPolicyName());
117 assertTrue(mgr.isActive());
118 assertEquals(CL_NAME, mgr.getClosedLoopControlName());
119 assertSame(REQ_ID, mgr.getRequestId());
120 assertEquals(POLICY_NAME, mgr.getPolicyName());
121 assertEquals(POLICY_VERSION, mgr.getPolicyVersion());
122 assertNotNull(mgr.getProcessor());
123 assertThat(mgr.getEndTimeMs()).isGreaterThanOrEqualTo(preCreateTimeMs);
127 public void testGetCreateCount() throws ControlLoopException {
128 long original = ControlLoopEventManager.getCreateCount();
130 new MyManager(services, params, REQ_ID);
131 assertEquals(original + 1, ControlLoopEventManager.getCreateCount());
133 new MyManager(services, params, REQ_ID);
134 assertEquals(original + 2, ControlLoopEventManager.getCreateCount());
138 public void testIsActive() throws Exception {
139 mgr = new ControlLoopEventManager(services, params, REQ_ID);
140 assertTrue(mgr.isActive());
142 ControlLoopEventManager mgr2 = Serializer.roundTrip(mgr);
143 assertFalse(mgr2.isActive());
147 public void testDestroy() throws IOException {
148 mgr.requestLock(LOCK1);
149 mgr.requestLock(LOCK2);
150 mgr.requestLock(LOCK1);
152 // ensure destroy() doesn't throw an exception if the object is deserialized
153 ControlLoopEventManager mgr2 = Serializer.roundTrip(mgr);
154 assertThatCode(() -> mgr2.destroy()).doesNotThrowAnyException();
156 // locks should not have been freed
157 for (LockImpl lock : locks) {
158 assertFalse(lock.isUnavailable());
165 for (LockImpl lock : locks) {
166 assertTrue(lock.isUnavailable());
171 public void testDetmControlLoopTimeoutMs() throws Exception {
172 long timeMs = 1200 * 1000L;
173 long end = mgr.getEndTimeMs();
174 assertThat(end).isGreaterThanOrEqualTo(preCreateTimeMs + timeMs).isLessThan(preCreateTimeMs + timeMs + 5000);
178 public void testRequestLock() {
179 final CompletableFuture<OperationOutcome> future1 = mgr.requestLock(LOCK1);
180 assertTrue(mgr.getOutcomes().isEmpty());
182 final CompletableFuture<OperationOutcome> future2 = mgr.requestLock(LOCK2);
183 assertTrue(mgr.getOutcomes().isEmpty());
185 assertSame(future1, mgr.requestLock(LOCK1));
186 assertTrue(mgr.getOutcomes().isEmpty());
188 assertEquals(2, locks.size());
190 assertTrue(future1.isDone());
191 assertTrue(future2.isDone());
193 // indicate that the first lock failed
194 locks.get(0).notifyUnavailable();
196 verifyLock(OperationResult.FAILURE, ActorConstants.LOCK_OPERATION);
197 assertTrue(mgr.getOutcomes().isEmpty());
201 public void testReleaseLock() {
202 mgr.requestLock(LOCK1);
203 mgr.requestLock(LOCK2);
206 final CompletableFuture<OperationOutcome> future = mgr.releaseLock(LOCK1);
208 // asynchronous, thus should not have executed yet
209 assertThat(future.isDone()).isFalse();
211 // asynchronous, thus everything should still be locked
212 for (LockImpl lock : locks) {
213 assertThat(lock.isUnavailable()).isFalse();
218 verifyLock(OperationResult.SUCCESS, ActorConstants.UNLOCK_OPERATION);
219 assertThat(mgr.getOutcomes()).isEmpty();
221 // first lock should have been released, thus no longer available to the manager
222 assertThat(locks.get(0).isUnavailable()).isTrue();
224 // second should still be locked
225 assertThat(locks.get(1).isUnavailable()).isFalse();
229 * Tests releaseLock() when there is no lock.
232 public void testReleaseLockNotLocked() {
233 final CompletableFuture<OperationOutcome> future = mgr.releaseLock(LOCK1);
235 // lock didn't exist, so the request should already be complete
236 assertThat(future.isDone()).isTrue();
238 verifyLock(OperationResult.SUCCESS, ActorConstants.UNLOCK_OPERATION);
239 assertThat(mgr.getOutcomes()).isEmpty();
243 * Tests releaseLock() when lock.free() throws an exception.
246 public void testReleaseLockException() throws ControlLoopException {
247 mgr = new MyManager(services, params, REQ_ID) {
248 private static final long serialVersionUID = 1L;
251 protected void makeLock(String targetEntity, String requestId, int holdSec, LockCallback callback) {
253 LockImpl lock = new LockImpl(LockState.ACTIVE, targetEntity, requestId, holdSec, callback) {
254 private static final long serialVersionUID = 1L;
257 public boolean free() {
258 throw new RuntimeException(EXPECTED_EXCEPTION);
263 callback.lockAvailable(lock);
267 mgr.requestLock(LOCK1);
270 final CompletableFuture<OperationOutcome> future = mgr.releaseLock(LOCK1);
272 // asynchronous, thus should not have executed yet
273 assertThat(future.isDone()).isFalse();
277 verifyLock(OperationResult.FAILURE_EXCEPTION, ActorConstants.UNLOCK_OPERATION);
278 assertThat(mgr.getOutcomes()).isEmpty();
281 private void verifyLock(OperationResult result, String lockOperation) {
282 OperationOutcome outcome = mgr.getOutcomes().poll();
283 assertNotNull(outcome);
284 assertEquals(ActorConstants.LOCK_ACTOR, outcome.getActor());
285 assertEquals(lockOperation, outcome.getOperation());
286 assertNotNull(outcome.getEnd());
287 assertTrue(outcome.isFinalOutcome());
288 assertEquals(result, outcome.getResult());
292 public void testOnStart() {
293 OperationOutcome outcome1 = new OperationOutcome();
294 OperationOutcome outcome2 = new OperationOutcome();
296 mgr.onStart(outcome1);
297 mgr.onStart(outcome2);
299 assertSame(outcome1, mgr.getOutcomes().poll());
300 assertSame(outcome2, mgr.getOutcomes().poll());
301 assertTrue(mgr.getOutcomes().isEmpty());
305 public void testOnComplete() {
306 OperationOutcome outcome1 = new OperationOutcome();
307 OperationOutcome outcome2 = new OperationOutcome();
309 mgr.onComplete(outcome1);
310 mgr.onComplete(outcome2);
312 assertSame(outcome1, mgr.getOutcomes().poll());
313 assertSame(outcome2, mgr.getOutcomes().poll());
314 assertTrue(mgr.getOutcomes().isEmpty());
318 public void testContains_testGetProperty_testSetProperty_testRemoveProperty() {
319 mgr.setProperty("abc", "a string");
320 mgr.setProperty(MY_KEY, 100);
322 assertTrue(mgr.contains(MY_KEY));
323 assertFalse(mgr.contains("ghi"));
325 String strValue = mgr.getProperty("abc");
326 assertEquals("a string", strValue);
328 int intValue = mgr.getProperty(MY_KEY);
329 assertEquals(100, intValue);
331 mgr.removeProperty(MY_KEY);
332 assertFalse(mgr.contains(MY_KEY));
336 * Tests getDataManager() when not disabled.
339 public void testGetDataManagerNotDisabled() throws ControlLoopException {
340 assertThat(mgr.getDataManager()).isSameAs(dataMgr);
344 * Tests getDataManager() when guard.disabled=true.
347 public void testGetDataManagerDisabled() throws ControlLoopException {
348 mgr = new MyManager(services, params, REQ_ID) {
349 private static final long serialVersionUID = 1L;
352 protected String getEnvironmentProperty(String propName) {
353 return ("guard.disabled".equals(propName) ? "true" : null);
357 assertThat(mgr.getDataManager()).isInstanceOf(OperationHistoryDataManagerStub.class);
361 public void testToString() {
362 assertNotNull(mgr.toString());
365 private void loadPolicy(String fileName) throws CoderException {
366 ToscaServiceTemplate template =
367 yamlCoder.decode(ResourceUtils.getResourceAsString(fileName), ToscaServiceTemplate.class);
368 tosca = template.getToscaTopologyTemplate().getPolicies().get(0).values().iterator().next();
370 params.setToscaPolicy(tosca);
373 private void runExecutor() {
374 ArgumentCaptor<Runnable> runCaptor = ArgumentCaptor.forClass(Runnable.class);
375 verify(executor).execute(runCaptor.capture());
377 runCaptor.getValue().run();
381 private static class MyManager extends ControlLoopEventManager {
382 private static final long serialVersionUID = 1L;
384 private static ExecutorService executor;
385 private static List<LockImpl> locks;
387 public MyManager(EventManagerServices services, ControlLoopParams params, UUID requestId)
388 throws ControlLoopException {
389 super(services, params, requestId);
393 protected ExecutorService getBlockingExecutor() {
398 protected void makeLock(String targetEntity, String requestId, int holdSec, LockCallback callback) {
399 LockImpl lock = new LockImpl(LockState.ACTIVE, targetEntity, requestId, holdSec, callback);
401 callback.lockAvailable(lock);