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;
32 import org.junit.Test;
33 import org.onap.policy.appc.Request;
34 import org.onap.policy.appclcm.AppcLcmDmaapWrapper;
35 import org.onap.policy.common.utils.coder.Coder;
36 import org.onap.policy.common.utils.coder.StandardCoder;
37 import org.onap.policy.common.utils.coder.StandardCoderInstantAsMillis;
38 import org.onap.policy.controlloop.ControlLoopNotificationType;
39 import org.onap.policy.controlloop.VirtualControlLoopNotification;
40 import org.onap.policy.drools.system.PolicyController;
41 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
44 * Superclass used for rule tests.
46 public abstract class BaseRuleTest {
48 * Canonical Topic Names.
50 protected static final String DCAE_TOPIC = "DCAE_TOPIC";
51 protected static final String APPC_LCM_WRITE_TOPIC = "APPC-LCM-WRITE";
52 protected static final String POLICY_CL_MGT_TOPIC = "POLICY-CL-MGT";
53 protected static final String APPC_LCM_READ_TOPIC = "APPC-LCM-READ";
54 protected static final String APPC_CL_TOPIC = "APPC-CL";
57 * Constants for each test case.
60 // service123 (i.e., multi-operation policy)
61 private static final String SERVICE123_TOSCA_COMPLIANT_POLICY = "service123/tosca-compliant-service123.json";
62 private static final String SERVICE123_ONSET = "service123/service123.onset.json";
63 private static final String SERVICE123_APPC_RESTART_FAILURE = "service123/service123.appc.restart.failure.json";
64 private static final String SERVICE123_APPC_REBUILD_FAILURE = "service123/service123.appc.rebuild.failure.json";
65 private static final String SERVICE123_APPC_MIGRATE_SUCCESS = "service123/service123.appc.migrate.success.json";
67 // duplicates (i.e., mutliple events in the engine at the same time)
68 private static final String DUPLICATES_TOSCA_COMPLIANT_POLICY = "duplicates/tosca-compliant-duplicates.json";
69 private static final String DUPLICATES_ONSET_1 = "duplicates/duplicates.onset.1.json";
70 private static final String DUPLICATES_ONSET_2 = "duplicates/duplicates.onset.2.json";
71 private static final String DUPLICATES_APPC_SUCCESS = "duplicates/duplicates.appc.success.json";
74 private static final String VCPE_TOSCA_LEGACY_POLICY = "vcpe/tosca-legacy-vcpe.json";
75 private static final String VCPE_TOSCA_COMPLIANT_POLICY = "vcpe/tosca-compliant-vcpe.json";
76 private static final String VCPE_ONSET_1 = "vcpe/vcpe.onset.1.json";
77 private static final String VCPE_ONSET_2 = "vcpe/vcpe.onset.2.json";
78 private static final String VCPE_ONSET_3 = "vcpe/vcpe.onset.3.json";
79 private static final String VCPE_APPC_SUCCESS = "vcpe/vcpe.appc.success.json";
82 private static final String VDNS_TOSCA_COMPLIANT_POLICY = "vdns/tosca-compliant-vdns.json";
83 private static final String VDNS_ONSET = "vdns/vdns.onset.json";
86 private static final String VFW_TOSCA_LEGACY_POLICY = "vfw/tosca-vfw.json";
87 private static final String VFW_TOSCA_COMPLIANT_POLICY = "vfw/tosca-compliant-vfw.json";
88 private static final String VFW_ONSET = "vfw/vfw.onset.json";
89 private static final String VFW_APPC_SUCCESS = "vfw/vfw.appc.success.json";
92 private static final String VLB_TOSCA_LEGACY_POLICY = "vlb/tosca-vlb.json";
93 private static final String VLB_TOSCA_COMPLIANT_POLICY = "vlb/tosca-compliant-vlb.json";
94 private static final String VLB_ONSET = "vlb/vlb.onset.json";
97 * Coders used to decode requests and responses.
99 private static final Coder APPC_LEGACY_CODER = new StandardCoderInstantAsMillis();
100 private static final Coder APPC_LCM_CODER = new StandardCoder();
102 // these may be overridden by junit tests
103 private static Function<String, Rules> ruleMaker = Rules::new;
104 private static Supplier<HttpClients> httpClientMaker = HttpClients::new;
105 private static Supplier<Simulators> simMaker = Simulators::new;
106 private static Supplier<Topics> topicMaker = Topics::new;
108 protected static Rules rules;
109 protected static HttpClients httpClients;
110 protected static Simulators simulators;
113 // used to inject and wait for messages
114 @Getter(AccessLevel.PROTECTED)
115 private Topics topics;
117 // used to wait for messages on SINK topics
118 protected Listener<VirtualControlLoopNotification> policyClMgt;
119 protected Listener<Request> appcClSink;
120 protected Listener<AppcLcmDmaapWrapper> appcLcmRead;
122 protected PolicyController controller;
125 * Tosca Policy that was loaded.
127 protected ToscaPolicy policy;
131 * Initializes {@link #rules}, {@link #httpClients}, and {@link #simulators}.
133 * @param controllerName the rule controller name
135 public static void initStatics(String controllerName) {
136 rules = ruleMaker.apply(controllerName);
137 httpClients = httpClientMaker.get();
138 simulators = simMaker.get();
142 * Destroys {@link #httpClients}, {@link #simulators}, and {@link #rules}.
144 public static void finishStatics() {
145 httpClients.destroy();
146 simulators.destroy();
151 * Initializes {@link #topics} and {@link #controller}.
154 topics = topicMaker.get();
155 controller = rules.getController();
159 * Destroys {@link #topics} and resets the rule facts.
161 public void finish() {
166 // Service123 (i.e., Policy with multiple operations)
169 * Service123 with Tosca Compliant Policy.
172 public void testService123Compliant() {
173 policyClMgt = topics.createListener(POLICY_CL_MGT_TOPIC, VirtualControlLoopNotification.class, controller);
174 appcLcmRead = topics.createListener(APPC_LCM_READ_TOPIC, AppcLcmDmaapWrapper.class, APPC_LCM_CODER);
176 assertEquals(0, controller.getDrools().factCount(rules.getControllerName()));
177 policy = rules.setupPolicyFromFile(SERVICE123_TOSCA_COMPLIANT_POLICY);
178 assertEquals(2, controller.getDrools().factCount(rules.getControllerName()));
180 // inject an ONSET event over the DCAE topic
181 topics.inject(DCAE_TOPIC, SERVICE123_ONSET);
183 /* Wait to acquire a LOCK and a PDP-X PERMIT */
184 waitForLockAndPermit(policy, policyClMgt);
186 // restart request should be sent and fail four times (i.e., because retry=3)
187 for (int count = 0; count < 4; ++count) {
188 AppcLcmDmaapWrapper appcreq = appcLcmRead.await(req -> "restart".equals(req.getRpcName()));
190 topics.inject(APPC_LCM_WRITE_TOPIC, SERVICE123_APPC_RESTART_FAILURE,
191 appcreq.getBody().getInput().getCommonHeader().getSubRequestId());
194 // rebuild request should be sent and fail once
195 AppcLcmDmaapWrapper appcreq = appcLcmRead.await(req -> "rebuild".equals(req.getRpcName()));
197 topics.inject(APPC_LCM_WRITE_TOPIC, SERVICE123_APPC_REBUILD_FAILURE,
198 appcreq.getBody().getInput().getCommonHeader().getSubRequestId());
200 // migrate request should be sent and succeed
201 appcreq = appcLcmRead.await(req -> "migrate".equals(req.getRpcName()));
203 topics.inject(APPC_LCM_WRITE_TOPIC, SERVICE123_APPC_MIGRATE_SUCCESS,
204 appcreq.getBody().getInput().getCommonHeader().getSubRequestId());
206 /* --- Operation Completed --- */
208 waitForOperationSuccess();
210 /* --- Transaction Completed --- */
211 waitForFinalSuccess(policy, policyClMgt);
217 * This test case tests the scenario where 3 events occur and 2 of the requests refer
218 * to the same target entity while the 3rd is for another entity. The expected result
219 * is that the event with the duplicate target entity will have a final success result
220 * for one of the events, and a rejected message for the one that was unable to obtain
221 * the lock. The event that is referring to a different target entity should be able
222 * to obtain a lock since it is a different target. After processing of all events
223 * there should only be the policy and params objects left in memory.
226 public void testDuplicatesEvents() {
227 policyClMgt = topics.createListener(POLICY_CL_MGT_TOPIC, VirtualControlLoopNotification.class, controller);
228 appcLcmRead = topics.createListener(APPC_LCM_READ_TOPIC, AppcLcmDmaapWrapper.class, APPC_LCM_CODER);
230 assertEquals(0, controller.getDrools().factCount(rules.getControllerName()));
231 policy = rules.setupPolicyFromFile(DUPLICATES_TOSCA_COMPLIANT_POLICY);
232 assertEquals(2, controller.getDrools().factCount(rules.getControllerName()));
235 * Inject ONSET events over the DCAE topic. First and last have the same target
236 * entity, but different request IDs - only one should succeed. The middle one is
237 * for a different target entity, so it should succeed.
239 topics.inject(DCAE_TOPIC, DUPLICATES_ONSET_1, UUID.randomUUID().toString());
240 topics.inject(DCAE_TOPIC, DUPLICATES_ONSET_2);
241 topics.inject(DCAE_TOPIC, DUPLICATES_ONSET_1, UUID.randomUUID().toString());
243 // one should immediately generate a FINAL failure
244 waitForFinal(policy, policyClMgt, ControlLoopNotificationType.FINAL_FAILURE);
246 // should see two restarts
247 for (int count = 0; count < 2; ++count) {
248 AppcLcmDmaapWrapper appcreq = appcLcmRead.await(req -> "restart".equals(req.getRpcName()));
251 topics.inject(APPC_LCM_WRITE_TOPIC, DUPLICATES_APPC_SUCCESS,
252 appcreq.getBody().getInput().getCommonHeader().getSubRequestId());
255 // should see two FINAL successes
256 VirtualControlLoopNotification notif1 = waitForFinalSuccess(policy, policyClMgt);
257 VirtualControlLoopNotification notif2 = waitForFinalSuccess(policy, policyClMgt);
259 // get the list of target names so we can ensure there's one of each
260 List<String> actual = List.of(notif1, notif2).stream().map(notif -> notif.getAai().get("generic-vnf.vnf-id"))
261 .sorted().collect(Collectors.toList());
263 assertEquals(List.of("duplicate-VNF", "vCPE_Infrastructure_vGMUX_demo_app").toString(), actual.toString());
269 * Sunny Day with Legacy Tosca Policy.
272 public void testVcpeSunnyDayLegacy() {
273 appcLcmSunnyDay(VCPE_TOSCA_LEGACY_POLICY, VCPE_ONSET_1, "restart");
277 * Sunny Day with Tosca Compliant Policy.
280 public void testVcpeSunnyDayCompliant() {
281 appcLcmSunnyDay(VCPE_TOSCA_COMPLIANT_POLICY, VCPE_ONSET_1, "restart");
285 * An ONSET flood prevention test that injects a few ONSETs at once. It attempts to
286 * simulate the flooding behavior of the DCAE TCA microservice. TCA could blast tens
287 * or hundreds of ONSETs within sub-second intervals.
290 public void testVcpeOnsetFloodPrevention() {
291 appcLcmSunnyDay(VCPE_TOSCA_COMPLIANT_POLICY, List.of(VCPE_ONSET_1, VCPE_ONSET_2, VCPE_ONSET_3), "restart");
297 * Sunny Day with Tosca Compliant Policy.
300 public void testVdnsSunnyDayCompliant() {
301 httpSunnyDay(VDNS_TOSCA_COMPLIANT_POLICY, VDNS_ONSET);
307 * VFW Sunny Day with Legacy Tosca Policy.
310 public void testVfwSunnyDayLegacy() {
311 appcLegacySunnyDay(VFW_TOSCA_LEGACY_POLICY, VFW_ONSET, "ModifyConfig");
315 * VFW Sunny Day with Tosca Compliant Policy.
318 public void testVfwSunnyDayCompliant() {
319 appcLegacySunnyDay(VFW_TOSCA_COMPLIANT_POLICY, VFW_ONSET, "ModifyConfig");
325 * Sunny Day with Legacy Tosca Policy.
328 public void testVlbSunnyDayLegacy() {
329 httpSunnyDay(VLB_TOSCA_LEGACY_POLICY, VLB_ONSET);
333 * Sunny Day with Tosca Compliant Policy.
336 public void testVlbSunnyDayCompliant() {
337 httpSunnyDay(VLB_TOSCA_COMPLIANT_POLICY, VLB_ONSET);
341 * Sunny day scenario for use cases that use APPC-LCM.
343 * @param policyFile file containing the ToscaPolicy to be loaded
344 * @param onsetFile file containing the ONSET to be injected
345 * @param operation expected APPC operation request
347 protected void appcLcmSunnyDay(String policyFile, String onsetFile, String operation) {
348 appcLcmSunnyDay(policyFile, List.of(onsetFile), operation);
352 * Sunny day scenario for use cases that use APPC-LCM.
354 * @param policyFile file containing the ToscaPolicy to be loaded
355 * @param onsetFiles list of files containing the ONSET to be injected
356 * @param operation expected APPC operation request
358 protected void appcLcmSunnyDay(String policyFile, List<String> onsetFiles, String operation) {
359 policyClMgt = topics.createListener(POLICY_CL_MGT_TOPIC, VirtualControlLoopNotification.class, controller);
360 appcLcmRead = topics.createListener(APPC_LCM_READ_TOPIC, AppcLcmDmaapWrapper.class, APPC_LCM_CODER);
362 assertEquals(0, controller.getDrools().factCount(rules.getControllerName()));
363 policy = rules.setupPolicyFromFile(policyFile);
364 assertEquals(2, controller.getDrools().factCount(rules.getControllerName()));
366 // inject several ONSET events over the DCAE topic
367 for (String onsetFile : onsetFiles) {
368 topics.inject(DCAE_TOPIC, onsetFile);
371 /* Wait to acquire a LOCK and a PDP-X PERMIT */
372 waitForLockAndPermit(policy, policyClMgt);
375 * Ensure that an APPC RESTART request was sent in response to the matching ONSET
377 AppcLcmDmaapWrapper appcreq = appcLcmRead.await(req -> operation.equals(req.getRpcName()));
380 * Inject a 400 APPC Response Return over the APPC topic, with appropriate
383 topics.inject(APPC_LCM_WRITE_TOPIC, VCPE_APPC_SUCCESS,
384 appcreq.getBody().getInput().getCommonHeader().getSubRequestId());
386 /* --- Operation Completed --- */
388 waitForOperationSuccess();
390 /* --- Transaction Completed --- */
391 waitForFinalSuccess(policy, policyClMgt);
395 * Sunny day scenario for use cases that use Legacy APPC.
397 * @param policyFile file containing the ToscaPolicy to be loaded
398 * @param onsetFile file containing the ONSET to be injected
399 * @param operation expected APPC operation request
401 protected void appcLegacySunnyDay(String policyFile, String onsetFile, String operation) {
402 policyClMgt = topics.createListener(POLICY_CL_MGT_TOPIC, VirtualControlLoopNotification.class, controller);
403 appcClSink = topics.createListener(APPC_CL_TOPIC, Request.class, APPC_LEGACY_CODER);
405 assertEquals(0, controller.getDrools().factCount(rules.getControllerName()));
406 policy = rules.setupPolicyFromFile(policyFile);
407 assertEquals(2, controller.getDrools().factCount(rules.getControllerName()));
409 /* Inject an ONSET event over the DCAE topic */
410 topics.inject(DCAE_TOPIC, onsetFile);
412 /* Wait to acquire a LOCK and a PDP-X PERMIT */
413 waitForLockAndPermit(policy, policyClMgt);
416 * Ensure that an APPC RESTART request was sent in response to the matching ONSET
418 Request appcreq = appcClSink.await(req -> operation.equals(req.getAction()));
421 * Inject a 400 APPC Response Return over the APPC topic, with appropriate
424 topics.inject(APPC_CL_TOPIC, VFW_APPC_SUCCESS, appcreq.getCommonHeader().getSubRequestId());
426 /* --- Operation Completed --- */
428 waitForOperationSuccess();
430 /* --- Transaction Completed --- */
431 waitForFinalSuccess(policy, policyClMgt);
435 * Sunny day scenario for use cases that use an HTTP simulator.
437 * @param policyFile file containing the ToscaPolicy to be loaded
438 * @param onsetFile file containing the ONSET to be injected
439 * @param operation expected APPC operation request
441 protected void httpSunnyDay(String policyFile, String onsetFile) {
442 policyClMgt = topics.createListener(POLICY_CL_MGT_TOPIC, VirtualControlLoopNotification.class, controller);
444 assertEquals(0, controller.getDrools().factCount(rules.getControllerName()));
445 policy = rules.setupPolicyFromFile(policyFile);
446 assertEquals(2, controller.getDrools().factCount(rules.getControllerName()));
448 /* Inject an ONSET event over the DCAE topic */
449 topics.inject(DCAE_TOPIC, onsetFile);
451 /* Wait to acquire a LOCK and a PDP-X PERMIT */
452 waitForLockAndPermit(policy, policyClMgt);
454 /* --- Operation Completed --- */
456 waitForOperationSuccess();
458 /* --- Transaction Completed --- */
459 waitForFinalSuccess(policy, policyClMgt);
463 * Waits for a OPERATION SUCCESS transaction notification.
465 protected void waitForOperationSuccess() {
466 policyClMgt.await(notif -> notif.getNotification() == ControlLoopNotificationType.OPERATION_SUCCESS);
470 * Waits for a FINAL SUCCESS transaction notification.
472 * @return the FINAL SUCCESS notification
474 protected VirtualControlLoopNotification waitForFinalSuccess(ToscaPolicy policy,
475 Listener<VirtualControlLoopNotification> policyClMgt) {
477 return this.waitForFinal(policy, policyClMgt, ControlLoopNotificationType.FINAL_SUCCESS);
481 * Waits for notifications for LOCK acquisition and GUARD Permit so that event
482 * processing may proceed.
484 protected abstract void waitForLockAndPermit(ToscaPolicy policy,
485 Listener<VirtualControlLoopNotification> policyClMgt);
488 * Waits for a FINAL transaction notification.
490 * @param finalType FINAL_xxx type for which to wait
492 * @return the FINAL notification
494 protected abstract VirtualControlLoopNotification waitForFinal(ToscaPolicy policy,
495 Listener<VirtualControlLoopNotification> policyClMgt, ControlLoopNotificationType finalType);