2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2020 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.common.rules.test;
23 import static org.junit.Assert.assertEquals;
25 import java.util.List;
26 import java.util.UUID;
27 import java.util.function.Function;
28 import java.util.function.Supplier;
29 import java.util.stream.Collectors;
30 import lombok.AccessLevel;
33 import org.junit.Ignore;
34 import org.junit.Test;
35 import org.onap.policy.appc.Request;
36 import org.onap.policy.appclcm.AppcLcmDmaapWrapper;
37 import org.onap.policy.common.utils.coder.Coder;
38 import org.onap.policy.common.utils.coder.StandardCoder;
39 import org.onap.policy.common.utils.coder.StandardCoderInstantAsMillis;
40 import org.onap.policy.controlloop.ControlLoopNotificationType;
41 import org.onap.policy.controlloop.VirtualControlLoopNotification;
42 import org.onap.policy.drools.system.PolicyController;
43 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
46 * Superclass used for rule tests.
48 public abstract class BaseRuleTest {
49 private static final String APPC_RESTART_OP = "restart";
50 private static final String APPC_MODIFY_CONFIG_OP = "ModifyConfig";
53 * Canonical Topic Names.
55 protected static final String DCAE_TOPIC = "DCAE_TOPIC";
56 protected static final String APPC_LCM_WRITE_TOPIC = "APPC-LCM-WRITE";
57 protected static final String POLICY_CL_MGT_TOPIC = "POLICY-CL-MGT";
58 protected static final String APPC_LCM_READ_TOPIC = "APPC-LCM-READ";
59 protected static final String APPC_CL_TOPIC = "APPC-CL";
62 * Constants for each test case.
65 // service123 (i.e., multi-operation policy)
66 private static final String SERVICE123_TOSCA_COMPLIANT_POLICY = "service123/tosca-compliant-service123.json";
67 private static final String SERVICE123_ONSET = "service123/service123.onset.json";
68 private static final String SERVICE123_APPC_RESTART_FAILURE = "service123/service123.appc.restart.failure.json";
69 private static final String SERVICE123_APPC_REBUILD_FAILURE = "service123/service123.appc.rebuild.failure.json";
70 private static final String SERVICE123_APPC_MIGRATE_SUCCESS = "service123/service123.appc.migrate.success.json";
72 // duplicates (i.e., mutliple events in the engine at the same time)
73 private static final String DUPLICATES_TOSCA_COMPLIANT_POLICY = "duplicates/tosca-compliant-duplicates.json";
74 private static final String DUPLICATES_ONSET_1 = "duplicates/duplicates.onset.1.json";
75 private static final String DUPLICATES_ONSET_2 = "duplicates/duplicates.onset.2.json";
76 private static final String DUPLICATES_APPC_SUCCESS = "duplicates/duplicates.appc.success.json";
79 private static final String VCPE_TOSCA_LEGACY_POLICY = "vcpe/tosca-legacy-vcpe.json";
80 private static final String VCPE_TOSCA_COMPLIANT_POLICY = "vcpe/tosca-compliant-vcpe.json";
81 private static final String VCPE_ONSET_1 = "vcpe/vcpe.onset.1.json";
82 private static final String VCPE_ONSET_2 = "vcpe/vcpe.onset.2.json";
83 private static final String VCPE_ONSET_3 = "vcpe/vcpe.onset.3.json";
84 private static final String VCPE_APPC_SUCCESS = "vcpe/vcpe.appc.success.json";
87 private static final String VDNS_TOSCA_LEGACY_POLICY = "vdns/tosca-legacy-vdns.json";
88 private static final String VDNS_TOSCA_COMPLIANT_POLICY = "vdns/tosca-compliant-vdns.json";
89 private static final String VDNS_ONSET = "vdns/vdns.onset.json";
92 private static final String VFW_TOSCA_LEGACY_POLICY = "vfw/tosca-vfw.json";
93 private static final String VFW_TOSCA_COMPLIANT_POLICY = "vfw/tosca-compliant-vfw.json";
94 private static final String VFW_TOSCA_COMPLIANT_TIME_OUT_POLICY = "vfw/tosca-compliant-timeout-vfw.json";
95 private static final String VFW_ONSET = "vfw/vfw.onset.json";
96 private static final String VFW_APPC_SUCCESS = "vfw/vfw.appc.success.json";
97 private static final String VFW_APPC_FAILURE = "vfw/vfw.appc.failure.json";
100 * Coders used to decode requests and responses.
102 private static final Coder APPC_LEGACY_CODER = new StandardCoderInstantAsMillis();
103 private static final Coder APPC_LCM_CODER = new StandardCoder();
105 // these may be overridden by junit tests
106 private static Function<String, Rules> ruleMaker = Rules::new;
107 private static Supplier<HttpClients> httpClientMaker = HttpClients::new;
108 private static Supplier<Simulators> simMaker = Simulators::new;
109 private static Supplier<Topics> topicMaker = Topics::new;
111 protected static Rules rules;
112 protected static HttpClients httpClients;
113 protected static Simulators simulators;
115 // used to inject and wait for messages
116 @Getter(AccessLevel.PROTECTED)
117 private Topics topics;
119 // used to wait for messages on SINK topics
120 protected Listener<VirtualControlLoopNotification> policyClMgt;
121 protected Listener<Request> appcClSink;
122 protected Listener<AppcLcmDmaapWrapper> appcLcmRead;
124 protected PolicyController controller;
127 * Tosca Policy that was loaded.
129 protected ToscaPolicy policy;
133 * Initializes {@link #rules}, {@link #httpClients}, and {@link #simulators}.
135 * @param controllerName the rule controller name
137 public static void initStatics(String controllerName) {
138 rules = ruleMaker.apply(controllerName);
139 httpClients = httpClientMaker.get();
140 simulators = simMaker.get();
144 * Destroys {@link #httpClients}, {@link #simulators}, and {@link #rules}.
146 public static void finishStatics() {
147 httpClients.destroy();
148 simulators.destroy();
153 * Initializes {@link #topics} and {@link #controller}.
156 topics = topicMaker.get();
157 controller = rules.getController();
161 * Destroys {@link #topics} and resets the rule facts.
163 public void finish() {
168 // Service123 (i.e., Policy with multiple operations)
171 * Service123 with Tosca Compliant Policy.
174 public void testService123Compliant() {
175 policyClMgt = topics.createListener(POLICY_CL_MGT_TOPIC, VirtualControlLoopNotification.class, controller);
176 appcLcmRead = topics.createListener(APPC_LCM_READ_TOPIC, AppcLcmDmaapWrapper.class, APPC_LCM_CODER);
178 assertEquals(0, controller.getDrools().factCount(rules.getControllerName()));
179 policy = rules.setupPolicyFromFile(SERVICE123_TOSCA_COMPLIANT_POLICY);
180 assertEquals(2, controller.getDrools().factCount(rules.getControllerName()));
182 // inject an ONSET event over the DCAE topic
183 topics.inject(DCAE_TOPIC, SERVICE123_ONSET);
185 /* Wait to acquire a LOCK and a PDP-X PERMIT */
186 waitForLockAndPermit(policy, policyClMgt);
188 // restart request should be sent and fail four times (i.e., because retry=3)
189 for (int count = 0; count < 4; ++count) {
190 AppcLcmDmaapWrapper appcreq = appcLcmRead.await(req -> APPC_RESTART_OP.equals(req.getRpcName()));
192 topics.inject(APPC_LCM_WRITE_TOPIC, SERVICE123_APPC_RESTART_FAILURE,
193 appcreq.getBody().getInput().getCommonHeader().getSubRequestId());
196 // rebuild request should be sent and fail once
197 AppcLcmDmaapWrapper appcreq = appcLcmRead.await(req -> "rebuild".equals(req.getRpcName()));
199 topics.inject(APPC_LCM_WRITE_TOPIC, SERVICE123_APPC_REBUILD_FAILURE,
200 appcreq.getBody().getInput().getCommonHeader().getSubRequestId());
202 // migrate request should be sent and succeed
203 appcreq = appcLcmRead.await(req -> "migrate".equals(req.getRpcName()));
205 topics.inject(APPC_LCM_WRITE_TOPIC, SERVICE123_APPC_MIGRATE_SUCCESS,
206 appcreq.getBody().getInput().getCommonHeader().getSubRequestId());
208 /* --- Operation Completed --- */
210 waitForOperationSuccess();
212 /* --- Transaction Completed --- */
213 waitForFinalSuccess(policy, policyClMgt);
219 * This test case tests the scenario where 3 events occur and 2 of the requests refer
220 * to the same target entity while the 3rd is for another entity. The expected result
221 * is that the event with the duplicate target entity will have a final success result
222 * for one of the events, and a rejected message for the one that was unable to obtain
223 * the lock. The event that is referring to a different target entity should be able
224 * to obtain a lock since it is a different target. After processing of all events
225 * there should only be the policy and params objects left in memory.
227 // Ignoring test due to TimeoutException (for some reason this test fails only on docker build)
228 // https://jenkins.onap.org/job/policy-drools-applications-maven-docker-stage-master/294/
231 public void testDuplicatesEvents() {
232 policyClMgt = topics.createListener(POLICY_CL_MGT_TOPIC, VirtualControlLoopNotification.class, controller);
233 appcLcmRead = topics.createListener(APPC_LCM_READ_TOPIC, AppcLcmDmaapWrapper.class, APPC_LCM_CODER);
235 assertEquals(0, controller.getDrools().factCount(rules.getControllerName()));
236 policy = rules.setupPolicyFromFile(DUPLICATES_TOSCA_COMPLIANT_POLICY);
237 assertEquals(2, controller.getDrools().factCount(rules.getControllerName()));
240 * Inject ONSET events over the DCAE topic. First and last have the same target
241 * entity, but different request IDs - only one should succeed. The middle one is
242 * for a different target entity, so it should succeed.
244 topics.inject(DCAE_TOPIC, DUPLICATES_ONSET_1, UUID.randomUUID().toString());
245 topics.inject(DCAE_TOPIC, DUPLICATES_ONSET_2);
246 topics.inject(DCAE_TOPIC, DUPLICATES_ONSET_1, UUID.randomUUID().toString());
248 // one should immediately generate a FINAL failure
249 waitForFinal(policy, policyClMgt, ControlLoopNotificationType.FINAL_FAILURE);
251 // should see two restarts
252 for (int count = 0; count < 2; ++count) {
253 AppcLcmDmaapWrapper appcreq = appcLcmRead.await(req -> APPC_RESTART_OP.equals(req.getRpcName()));
256 topics.inject(APPC_LCM_WRITE_TOPIC, DUPLICATES_APPC_SUCCESS,
257 appcreq.getBody().getInput().getCommonHeader().getSubRequestId());
260 // should see two FINAL successes
261 VirtualControlLoopNotification notif1 = waitForFinalSuccess(policy, policyClMgt);
262 VirtualControlLoopNotification notif2 = waitForFinalSuccess(policy, policyClMgt);
264 // get the list of target names so we can ensure there's one of each
265 List<String> actual = List.of(notif1, notif2).stream().map(notif -> notif.getAai().get("generic-vnf.vnf-id"))
266 .sorted().collect(Collectors.toList());
268 assertEquals(List.of("duplicate-VNF", "vCPE_Infrastructure_vGMUX_demo_app").toString(), actual.toString());
274 * Sunny Day with Legacy Tosca Policy.
277 public void testVcpeSunnyDayLegacy() {
278 appcLcmSunnyDay(VCPE_TOSCA_LEGACY_POLICY, VCPE_ONSET_1, APPC_RESTART_OP);
282 * Sunny Day with Tosca Compliant Policy.
285 public void testVcpeSunnyDayCompliant() {
286 appcLcmSunnyDay(VCPE_TOSCA_COMPLIANT_POLICY, VCPE_ONSET_1, APPC_RESTART_OP);
290 * An ONSET flood prevention test that injects a few ONSETs at once. It attempts to
291 * simulate the flooding behavior of the DCAE TCA microservice. TCA could blast tens
292 * or hundreds of ONSETs within sub-second intervals.
295 public void testVcpeOnsetFloodPrevention() {
296 appcLcmSunnyDay(VCPE_TOSCA_COMPLIANT_POLICY, List.of(VCPE_ONSET_1, VCPE_ONSET_2, VCPE_ONSET_3),
303 * Sunny Day with Legacy Tosca Policy.
306 public void testVdnsSunnyDayLegacy() {
307 httpSunnyDay(VDNS_TOSCA_LEGACY_POLICY, VDNS_ONSET);
311 * Sunny Day with Tosca Compliant Policy.
314 public void testVdnsSunnyDayCompliant() {
315 httpSunnyDay(VDNS_TOSCA_COMPLIANT_POLICY, VDNS_ONSET);
321 * VFW Sunny Day with Legacy Tosca Policy.
324 public void testVfwSunnyDayLegacy() {
325 appcLegacySunnyDay(VFW_TOSCA_LEGACY_POLICY, VFW_ONSET, APPC_MODIFY_CONFIG_OP);
329 * VFW Sunny Day with Tosca Compliant Policy.
332 public void testVfwSunnyDayCompliant() {
333 appcLegacySunnyDay(VFW_TOSCA_COMPLIANT_POLICY, VFW_ONSET, APPC_MODIFY_CONFIG_OP);
337 * VFW Rainy Day using legacy tosca policy (operation and final failure).
340 public void testVfwRainyDayLegacyFailure() {
341 appcLegacyRainyDay(VFW_TOSCA_LEGACY_POLICY, VFW_ONSET, APPC_MODIFY_CONFIG_OP);
345 * VFW Rainy Day using compliant tosca policy (final failure).
348 public void testVfwRainyDayOverallTimeout() {
349 appcLegacyRainyDayNoResponse(VFW_TOSCA_COMPLIANT_TIME_OUT_POLICY, VFW_ONSET, APPC_MODIFY_CONFIG_OP);
353 * VFW Rainy day using compliant tosca policy (final failure due to timeout).
356 public void testVfwRainyDayCompliantTimeout() {
357 appcLegacyRainyDayNoResponse(VFW_TOSCA_COMPLIANT_POLICY, VFW_ONSET, APPC_MODIFY_CONFIG_OP);
361 * Sunny day scenario for use cases that use APPC-LCM.
363 * @param policyFile file containing the ToscaPolicy to be loaded
364 * @param onsetFile file containing the ONSET to be injected
365 * @param operation expected APPC operation request
367 protected void appcLcmSunnyDay(String policyFile, String onsetFile, String operation) {
368 appcLcmSunnyDay(policyFile, List.of(onsetFile), operation);
372 * Sunny day scenario for use cases that use APPC-LCM.
374 * @param policyFile file containing the ToscaPolicy to be loaded
375 * @param onsetFiles list of files containing the ONSET to be injected
376 * @param operation expected APPC operation request
378 protected void appcLcmSunnyDay(String policyFile, List<String> onsetFiles, String operation) {
379 policyClMgt = topics.createListener(POLICY_CL_MGT_TOPIC, VirtualControlLoopNotification.class, controller);
380 appcLcmRead = topics.createListener(APPC_LCM_READ_TOPIC, AppcLcmDmaapWrapper.class, APPC_LCM_CODER);
382 assertEquals(0, controller.getDrools().factCount(rules.getControllerName()));
383 policy = rules.setupPolicyFromFile(policyFile);
384 assertEquals(2, controller.getDrools().factCount(rules.getControllerName()));
386 // inject several ONSET events over the DCAE topic
387 for (String onsetFile : onsetFiles) {
388 topics.inject(DCAE_TOPIC, onsetFile);
391 /* Wait to acquire a LOCK and a PDP-X PERMIT */
392 waitForLockAndPermit(policy, policyClMgt);
395 * Ensure that an APPC RESTART request was sent in response to the matching ONSET
397 AppcLcmDmaapWrapper appcreq = appcLcmRead.await(req -> operation.equals(req.getRpcName()));
400 * Inject a 400 APPC Response Return over the APPC topic, with appropriate
403 topics.inject(APPC_LCM_WRITE_TOPIC, VCPE_APPC_SUCCESS,
404 appcreq.getBody().getInput().getCommonHeader().getSubRequestId());
406 /* --- Operation Completed --- */
408 waitForOperationSuccess();
410 /* --- Transaction Completed --- */
411 waitForFinalSuccess(policy, policyClMgt);
415 * Sunny day scenario for use cases that use Legacy APPC.
417 * @param policyFile file containing the ToscaPolicy to be loaded
418 * @param onsetFile file containing the ONSET to be injected
419 * @param operation expected APPC operation request
421 protected void appcLegacySunnyDay(String policyFile, String onsetFile, String operation) {
422 policyClMgt = topics.createListener(POLICY_CL_MGT_TOPIC, VirtualControlLoopNotification.class, controller);
423 appcClSink = topics.createListener(APPC_CL_TOPIC, Request.class, APPC_LEGACY_CODER);
425 assertEquals(0, controller.getDrools().factCount(rules.getControllerName()));
426 policy = rules.setupPolicyFromFile(policyFile);
427 assertEquals(2, controller.getDrools().factCount(rules.getControllerName()));
429 /* Inject an ONSET event over the DCAE topic */
430 topics.inject(DCAE_TOPIC, onsetFile);
432 /* Wait to acquire a LOCK and a PDP-X PERMIT */
433 waitForLockAndPermit(policy, policyClMgt);
436 * Ensure that an APPC RESTART request was sent in response to the matching ONSET
438 Request appcreq = appcClSink.await(req -> operation.equals(req.getAction()));
441 * Inject a 400 APPC Response Return over the APPC topic, with appropriate
444 topics.inject(APPC_CL_TOPIC, VFW_APPC_SUCCESS, appcreq.getCommonHeader().getSubRequestId());
446 /* --- Operation Completed --- */
448 waitForOperationSuccess();
450 /* --- Transaction Completed --- */
451 waitForFinalSuccess(policy, policyClMgt);
455 * Rainy day scenario for use cases that use Legacy APPC.
457 * @param policyFile file containing the ToscaPolicy to be loaded
458 * @param onsetFile file containing the ONSET to be injected
459 * @param operation expected APPC operation request
460 * @param checkOperation flag to determine whether or not to wait for operation timeout
462 protected void appcLegacyRainyDay(String policyFile, String onsetFile, String operation) {
463 policyClMgt = topics.createListener(POLICY_CL_MGT_TOPIC, VirtualControlLoopNotification.class, controller);
464 appcClSink = topics.createListener(APPC_CL_TOPIC, Request.class, APPC_LEGACY_CODER);
466 assertEquals(0, controller.getDrools().factCount(rules.getControllerName()));
467 policy = rules.setupPolicyFromFile(policyFile);
468 assertEquals(2, controller.getDrools().factCount(rules.getControllerName()));
470 /* Inject an ONSET event over the DCAE topic */
471 topics.inject(DCAE_TOPIC, onsetFile);
473 /* Wait to acquire a LOCK and a PDP-X PERMIT */
474 waitForLockAndPermit(policy, policyClMgt);
477 * Ensure that an APPC RESTART request was sent in response to the matching ONSET
479 Request appcreq = appcClSink.await(req -> operation.equals(req.getAction()));
482 * Inject a 401 APPC Response Return over the APPC topic, with appropriate
485 topics.inject(APPC_CL_TOPIC, VFW_APPC_FAILURE, appcreq.getCommonHeader().getSubRequestId());
487 /* --- Operation Completed --- */
488 waitForOperationFailure();
490 /* --- Transaction Completed --- */
491 waitForFinalFailure(policy, policyClMgt);
495 * Rainy day scenario for use cases that use Legacy APPC.
496 * Expected to fail due to timeout.
498 * @param policyFile file containing the ToscaPolicy to be loaded
499 * @param onsetFile file containing the ONSET to be injected
500 * @param operation expected APPC operation request
502 protected void appcLegacyRainyDayNoResponse(String policyFile, String onsetFile, String operation) {
503 policyClMgt = topics.createListener(POLICY_CL_MGT_TOPIC, VirtualControlLoopNotification.class, controller);
504 appcClSink = topics.createListener(APPC_CL_TOPIC, Request.class, APPC_LEGACY_CODER);
506 assertEquals(0, controller.getDrools().factCount(rules.getControllerName()));
507 policy = rules.setupPolicyFromFile(policyFile);
508 assertEquals(2, controller.getDrools().factCount(rules.getControllerName()));
510 /* Inject an ONSET event over the DCAE topic */
511 topics.inject(DCAE_TOPIC, onsetFile);
513 /* Wait to acquire a LOCK and a PDP-X PERMIT */
514 waitForLockAndPermit(policy, policyClMgt);
517 * Ensure that an APPC RESTART request was sent in response to the matching ONSET
519 appcClSink.await(req -> operation.equals(req.getAction()));
522 * Do not inject an APPC Response.
525 /* --- Transaction Completed --- */
526 waitForFinalFailure(policy, policyClMgt);
530 * Sunny day scenario for use cases that use an HTTP simulator.
532 * @param policyFile file containing the ToscaPolicy to be loaded
533 * @param onsetFile file containing the ONSET to be injected
534 * @param operation expected APPC operation request
536 protected void httpSunnyDay(String policyFile, String onsetFile) {
537 policyClMgt = topics.createListener(POLICY_CL_MGT_TOPIC, VirtualControlLoopNotification.class, controller);
539 assertEquals(0, controller.getDrools().factCount(rules.getControllerName()));
540 policy = rules.setupPolicyFromFile(policyFile);
541 assertEquals(2, controller.getDrools().factCount(rules.getControllerName()));
543 /* Inject an ONSET event over the DCAE topic */
544 topics.inject(DCAE_TOPIC, onsetFile);
546 /* Wait to acquire a LOCK and a PDP-X PERMIT */
547 waitForLockAndPermit(policy, policyClMgt);
549 /* --- Operation Completed --- */
551 waitForOperationSuccess();
553 /* --- Transaction Completed --- */
554 waitForFinalSuccess(policy, policyClMgt);
558 * Waits for a OPERATION SUCCESS transaction notification.
560 protected void waitForOperationSuccess() {
561 policyClMgt.await(notif -> notif.getNotification() == ControlLoopNotificationType.OPERATION_SUCCESS);
565 * Waits for a FINAL SUCCESS transaction notification.
567 * @return the FINAL SUCCESS notification
569 protected VirtualControlLoopNotification waitForFinalSuccess(ToscaPolicy policy,
570 Listener<VirtualControlLoopNotification> policyClMgt) {
572 return this.waitForFinal(policy, policyClMgt, ControlLoopNotificationType.FINAL_SUCCESS);
576 * Waits for a OPERATION FAILURE transaction notification.
578 protected void waitForOperationFailure() {
579 policyClMgt.await(notif -> notif.getNotification() == ControlLoopNotificationType.OPERATION_FAILURE);
583 * Waits for a FINAL FAILURE transaction notification.
585 * @return the FINAL FAILURE notification
587 protected VirtualControlLoopNotification waitForFinalFailure(ToscaPolicy policy,
588 Listener<VirtualControlLoopNotification> policyClMgt) {
590 return this.waitForFinal(policy, policyClMgt, ControlLoopNotificationType.FINAL_FAILURE);
594 * Waits for notifications for LOCK acquisition and GUARD Permit so that event
595 * processing may proceed.
597 protected abstract void waitForLockAndPermit(ToscaPolicy policy,
598 Listener<VirtualControlLoopNotification> policyClMgt);
601 * Waits for a FINAL transaction notification.
603 * @param finalType FINAL_xxx type for which to wait
605 * @return the FINAL notification
607 protected abstract VirtualControlLoopNotification waitForFinal(ToscaPolicy policy,
608 Listener<VirtualControlLoopNotification> policyClMgt, ControlLoopNotificationType finalType);