summaryrefslogtreecommitdiffstats
path: root/controlloop/common/rules-test/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'controlloop/common/rules-test/src/main')
-rw-r--r--controlloop/common/rules-test/src/main/java/org/onap/policy/controlloop/common/rules/test/BaseRuleTest.java496
-rw-r--r--controlloop/common/rules-test/src/main/java/org/onap/policy/controlloop/common/rules/test/HttpClients.java67
-rw-r--r--controlloop/common/rules-test/src/main/java/org/onap/policy/controlloop/common/rules/test/Listener.java180
-rw-r--r--controlloop/common/rules-test/src/main/java/org/onap/policy/controlloop/common/rules/test/NamedRunner.java85
-rw-r--r--controlloop/common/rules-test/src/main/java/org/onap/policy/controlloop/common/rules/test/Rules.java413
-rw-r--r--controlloop/common/rules-test/src/main/java/org/onap/policy/controlloop/common/rules/test/SimulatorException.java44
-rw-r--r--controlloop/common/rules-test/src/main/java/org/onap/policy/controlloop/common/rules/test/Simulators.java85
-rw-r--r--controlloop/common/rules-test/src/main/java/org/onap/policy/controlloop/common/rules/test/TestNames.java44
-rw-r--r--controlloop/common/rules-test/src/main/java/org/onap/policy/controlloop/common/rules/test/TopicException.java44
-rw-r--r--controlloop/common/rules-test/src/main/java/org/onap/policy/controlloop/common/rules/test/Topics.java176
-rw-r--r--controlloop/common/rules-test/src/main/resources/duplicates/duplicates.appc.success.json22
-rw-r--r--controlloop/common/rules-test/src/main/resources/duplicates/duplicates.onset.1.json16
-rw-r--r--controlloop/common/rules-test/src/main/resources/duplicates/duplicates.onset.2.json16
-rw-r--r--controlloop/common/rules-test/src/main/resources/duplicates/tosca-compliant-duplicates.json37
-rw-r--r--controlloop/common/rules-test/src/main/resources/service123/service123.appc.migrate.success.json22
-rw-r--r--controlloop/common/rules-test/src/main/resources/service123/service123.appc.rebuild.failure.json22
-rw-r--r--controlloop/common/rules-test/src/main/resources/service123/service123.appc.restart.failure.json22
-rw-r--r--controlloop/common/rules-test/src/main/resources/service123/service123.onset.json17
-rw-r--r--controlloop/common/rules-test/src/main/resources/service123/tosca-compliant-service123.json75
-rw-r--r--controlloop/common/rules-test/src/main/resources/vcpe/tosca-compliant-vcpe.json37
-rw-r--r--controlloop/common/rules-test/src/main/resources/vcpe/tosca-legacy-vcpe.json9
-rw-r--r--controlloop/common/rules-test/src/main/resources/vcpe/vcpe.appc.success.json22
-rw-r--r--controlloop/common/rules-test/src/main/resources/vcpe/vcpe.onset.1.json16
-rw-r--r--controlloop/common/rules-test/src/main/resources/vcpe/vcpe.onset.2.json16
-rw-r--r--controlloop/common/rules-test/src/main/resources/vcpe/vcpe.onset.3.json17
-rw-r--r--controlloop/common/rules-test/src/main/resources/vdns/tosca-compliant-vdns.json48
-rw-r--r--controlloop/common/rules-test/src/main/resources/vdns/vdns.onset.json16
-rw-r--r--controlloop/common/rules-test/src/main/resources/vfw/tosca-compliant-vfw.json40
-rw-r--r--controlloop/common/rules-test/src/main/resources/vfw/tosca-vfw.json9
-rw-r--r--controlloop/common/rules-test/src/main/resources/vfw/vfw.appc.success.json17
-rw-r--r--controlloop/common/rules-test/src/main/resources/vfw/vfw.onset.json17
-rw-r--r--controlloop/common/rules-test/src/main/resources/vlb/tosca-compliant-vlb.json48
-rw-r--r--controlloop/common/rules-test/src/main/resources/vlb/tosca-vlb.json9
-rw-r--r--controlloop/common/rules-test/src/main/resources/vlb/vlb.onset.json16
34 files changed, 2220 insertions, 0 deletions
diff --git a/controlloop/common/rules-test/src/main/java/org/onap/policy/controlloop/common/rules/test/BaseRuleTest.java b/controlloop/common/rules-test/src/main/java/org/onap/policy/controlloop/common/rules/test/BaseRuleTest.java
new file mode 100644
index 000000000..711a61738
--- /dev/null
+++ b/controlloop/common/rules-test/src/main/java/org/onap/policy/controlloop/common/rules/test/BaseRuleTest.java
@@ -0,0 +1,496 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.controlloop.common.rules.test;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.List;
+import java.util.UUID;
+import java.util.function.Function;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+import lombok.AccessLevel;
+import lombok.Getter;
+import org.junit.Test;
+import org.onap.policy.appc.Request;
+import org.onap.policy.appclcm.AppcLcmDmaapWrapper;
+import org.onap.policy.common.utils.coder.Coder;
+import org.onap.policy.common.utils.coder.StandardCoder;
+import org.onap.policy.common.utils.coder.StandardCoderInstantAsMillis;
+import org.onap.policy.controlloop.ControlLoopNotificationType;
+import org.onap.policy.controlloop.VirtualControlLoopNotification;
+import org.onap.policy.drools.system.PolicyController;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
+
+/**
+ * Superclass used for rule tests.
+ */
+public abstract class BaseRuleTest {
+ /*
+ * Canonical Topic Names.
+ */
+ protected static final String DCAE_TOPIC = "DCAE_TOPIC";
+ protected static final String APPC_LCM_WRITE_TOPIC = "APPC-LCM-WRITE";
+ protected static final String POLICY_CL_MGT_TOPIC = "POLICY-CL-MGT";
+ protected static final String APPC_LCM_READ_TOPIC = "APPC-LCM-READ";
+ protected static final String APPC_CL_TOPIC = "APPC-CL";
+
+ /*
+ * Constants for each test case.
+ */
+
+ // service123 (i.e., multi-operation policy)
+ private static final String SERVICE123_TOSCA_COMPLIANT_POLICY = "service123/tosca-compliant-service123.json";
+ private static final String SERVICE123_ONSET = "service123/service123.onset.json";
+ private static final String SERVICE123_APPC_RESTART_FAILURE = "service123/service123.appc.restart.failure.json";
+ private static final String SERVICE123_APPC_REBUILD_FAILURE = "service123/service123.appc.rebuild.failure.json";
+ private static final String SERVICE123_APPC_MIGRATE_SUCCESS = "service123/service123.appc.migrate.success.json";
+
+ // duplicates (i.e., mutliple events in the engine at the same time)
+ private static final String DUPLICATES_TOSCA_COMPLIANT_POLICY = "duplicates/tosca-compliant-duplicates.json";
+ private static final String DUPLICATES_ONSET_1 = "duplicates/duplicates.onset.1.json";
+ private static final String DUPLICATES_ONSET_2 = "duplicates/duplicates.onset.2.json";
+ private static final String DUPLICATES_APPC_SUCCESS = "duplicates/duplicates.appc.success.json";
+
+ // VCPE
+ private static final String VCPE_TOSCA_LEGACY_POLICY = "vcpe/tosca-legacy-vcpe.json";
+ private static final String VCPE_TOSCA_COMPLIANT_POLICY = "vcpe/tosca-compliant-vcpe.json";
+ private static final String VCPE_ONSET_1 = "vcpe/vcpe.onset.1.json";
+ private static final String VCPE_ONSET_2 = "vcpe/vcpe.onset.2.json";
+ private static final String VCPE_ONSET_3 = "vcpe/vcpe.onset.3.json";
+ private static final String VCPE_APPC_SUCCESS = "vcpe/vcpe.appc.success.json";
+
+ // VDNS
+ private static final String VDNS_TOSCA_COMPLIANT_POLICY = "vdns/tosca-compliant-vdns.json";
+ private static final String VDNS_ONSET = "vdns/vdns.onset.json";
+
+ // VFW
+ private static final String VFW_TOSCA_LEGACY_POLICY = "vfw/tosca-vfw.json";
+ private static final String VFW_TOSCA_COMPLIANT_POLICY = "vfw/tosca-compliant-vfw.json";
+ private static final String VFW_ONSET = "vfw/vfw.onset.json";
+ private static final String VFW_APPC_SUCCESS = "vfw/vfw.appc.success.json";
+
+ // VLB
+ private static final String VLB_TOSCA_LEGACY_POLICY = "vlb/tosca-vlb.json";
+ private static final String VLB_TOSCA_COMPLIANT_POLICY = "vlb/tosca-compliant-vlb.json";
+ private static final String VLB_ONSET = "vlb/vlb.onset.json";
+
+ /*
+ * Coders used to decode requests and responses.
+ */
+ private static final Coder APPC_LEGACY_CODER = new StandardCoderInstantAsMillis();
+ private static final Coder APPC_LCM_CODER = new StandardCoder();
+
+ // these may be overridden by junit tests
+ private static Function<String, Rules> ruleMaker = Rules::new;
+ private static Supplier<HttpClients> httpClientMaker = HttpClients::new;
+ private static Supplier<Simulators> simMaker = Simulators::new;
+ private static Supplier<Topics> topicMaker = Topics::new;
+
+ protected static Rules rules;
+ protected static HttpClients httpClients;
+ protected static Simulators simulators;
+
+
+ // used to inject and wait for messages
+ @Getter(AccessLevel.PROTECTED)
+ private Topics topics;
+
+ // used to wait for messages on SINK topics
+ protected Listener<VirtualControlLoopNotification> policyClMgt;
+ protected Listener<Request> appcClSink;
+ protected Listener<AppcLcmDmaapWrapper> appcLcmRead;
+
+ protected PolicyController controller;
+
+ /*
+ * Tosca Policy that was loaded.
+ */
+ protected ToscaPolicy policy;
+
+
+ /**
+ * Initializes {@link #rules}, {@link #httpClients}, and {@link #simulators}.
+ *
+ * @param controllerName the rule controller name
+ */
+ public static void initStatics(String controllerName) {
+ rules = ruleMaker.apply(controllerName);
+ httpClients = httpClientMaker.get();
+ simulators = simMaker.get();
+ }
+
+ /**
+ * Destroys {@link #httpClients}, {@link #simulators}, and {@link #rules}.
+ */
+ public static void finishStatics() {
+ httpClients.destroy();
+ simulators.destroy();
+ rules.destroy();
+ }
+
+ /**
+ * Initializes {@link #topics} and {@link #controller}.
+ */
+ public void init() {
+ topics = topicMaker.get();
+ controller = rules.getController();
+ }
+
+ /**
+ * Destroys {@link #topics} and resets the rule facts.
+ */
+ public void finish() {
+ topics.destroy();
+ rules.resetFacts();
+ }
+
+ // Service123 (i.e., Policy with multiple operations)
+
+ /**
+ * Service123 with Tosca Compliant Policy.
+ */
+ @Test
+ public void testService123Compliant() {
+ policyClMgt = topics.createListener(POLICY_CL_MGT_TOPIC, VirtualControlLoopNotification.class, controller);
+ appcLcmRead = topics.createListener(APPC_LCM_READ_TOPIC, AppcLcmDmaapWrapper.class, APPC_LCM_CODER);
+
+ assertEquals(0, controller.getDrools().factCount(rules.getControllerName()));
+ policy = rules.setupPolicyFromFile(SERVICE123_TOSCA_COMPLIANT_POLICY);
+ assertEquals(2, controller.getDrools().factCount(rules.getControllerName()));
+
+ // inject an ONSET event over the DCAE topic
+ topics.inject(DCAE_TOPIC, SERVICE123_ONSET);
+
+ /* Wait to acquire a LOCK and a PDP-X PERMIT */
+ waitForLockAndPermit(policy, policyClMgt);
+
+ // restart request should be sent and fail four times (i.e., because retry=3)
+ for (int count = 0; count < 4; ++count) {
+ AppcLcmDmaapWrapper appcreq = appcLcmRead.await(req -> "restart".equals(req.getRpcName()));
+
+ topics.inject(APPC_LCM_WRITE_TOPIC, SERVICE123_APPC_RESTART_FAILURE,
+ appcreq.getBody().getInput().getCommonHeader().getSubRequestId());
+ }
+
+ // rebuild request should be sent and fail once
+ AppcLcmDmaapWrapper appcreq = appcLcmRead.await(req -> "rebuild".equals(req.getRpcName()));
+
+ topics.inject(APPC_LCM_WRITE_TOPIC, SERVICE123_APPC_REBUILD_FAILURE,
+ appcreq.getBody().getInput().getCommonHeader().getSubRequestId());
+
+ // migrate request should be sent and succeed
+ appcreq = appcLcmRead.await(req -> "migrate".equals(req.getRpcName()));
+
+ topics.inject(APPC_LCM_WRITE_TOPIC, SERVICE123_APPC_MIGRATE_SUCCESS,
+ appcreq.getBody().getInput().getCommonHeader().getSubRequestId());
+
+ /* --- Operation Completed --- */
+
+ waitForOperationSuccess();
+
+ /* --- Transaction Completed --- */
+ waitForFinalSuccess(policy, policyClMgt);
+ }
+
+ // Duplicate events
+
+ /**
+ * This test case tests the scenario where 3 events occur and 2 of the requests refer
+ * to the same target entity while the 3rd is for another entity. The expected result
+ * is that the event with the duplicate target entity will have a final success result
+ * for one of the events, and a rejected message for the one that was unable to obtain
+ * the lock. The event that is referring to a different target entity should be able
+ * to obtain a lock since it is a different target. After processing of all events
+ * there should only be the policy and params objects left in memory.
+ */
+ @Test
+ public void testDuplicatesEvents() {
+ policyClMgt = topics.createListener(POLICY_CL_MGT_TOPIC, VirtualControlLoopNotification.class, controller);
+ appcLcmRead = topics.createListener(APPC_LCM_READ_TOPIC, AppcLcmDmaapWrapper.class, APPC_LCM_CODER);
+
+ assertEquals(0, controller.getDrools().factCount(rules.getControllerName()));
+ policy = rules.setupPolicyFromFile(DUPLICATES_TOSCA_COMPLIANT_POLICY);
+ assertEquals(2, controller.getDrools().factCount(rules.getControllerName()));
+
+ /*
+ * Inject ONSET events over the DCAE topic. First and last have the same target
+ * entity, but different request IDs - only one should succeed. The middle one is
+ * for a different target entity, so it should succeed.
+ */
+ topics.inject(DCAE_TOPIC, DUPLICATES_ONSET_1, UUID.randomUUID().toString());
+ topics.inject(DCAE_TOPIC, DUPLICATES_ONSET_2);
+ topics.inject(DCAE_TOPIC, DUPLICATES_ONSET_1, UUID.randomUUID().toString());
+
+ // one should immediately generate a FINAL failure
+ waitForFinal(policy, policyClMgt, ControlLoopNotificationType.FINAL_FAILURE);
+
+ // should see two restarts
+ for (int count = 0; count < 2; ++count) {
+ AppcLcmDmaapWrapper appcreq = appcLcmRead.await(req -> "restart".equals(req.getRpcName()));
+
+ // indicate success
+ topics.inject(APPC_LCM_WRITE_TOPIC, DUPLICATES_APPC_SUCCESS,
+ appcreq.getBody().getInput().getCommonHeader().getSubRequestId());
+ }
+
+ // should see two FINAL successes
+ VirtualControlLoopNotification notif1 = waitForFinalSuccess(policy, policyClMgt);
+ VirtualControlLoopNotification notif2 = waitForFinalSuccess(policy, policyClMgt);
+
+ // get the list of target names so we can ensure there's one of each
+ List<String> actual = List.of(notif1, notif2).stream().map(notif -> notif.getAai().get("generic-vnf.vnf-id"))
+ .sorted().collect(Collectors.toList());
+
+ assertEquals(List.of("duplicate-VNF", "vCPE_Infrastructure_vGMUX_demo_app").toString(), actual.toString());
+ }
+
+ // VCPE
+
+ /**
+ * Sunny Day with Legacy Tosca Policy.
+ */
+ @Test
+ public void testVcpeSunnyDayLegacy() {
+ appcLcmSunnyDay(VCPE_TOSCA_LEGACY_POLICY, VCPE_ONSET_1, "restart");
+ }
+
+ /**
+ * Sunny Day with Tosca Compliant Policy.
+ */
+ @Test
+ public void testVcpeSunnyDayCompliant() {
+ appcLcmSunnyDay(VCPE_TOSCA_COMPLIANT_POLICY, VCPE_ONSET_1, "restart");
+ }
+
+ /**
+ * An ONSET flood prevention test that injects a few ONSETs at once. It attempts to
+ * simulate the flooding behavior of the DCAE TCA microservice. TCA could blast tens
+ * or hundreds of ONSETs within sub-second intervals.
+ */
+ @Test
+ public void testVcpeOnsetFloodPrevention() {
+ appcLcmSunnyDay(VCPE_TOSCA_COMPLIANT_POLICY, List.of(VCPE_ONSET_1, VCPE_ONSET_2, VCPE_ONSET_3), "restart");
+ }
+
+ // VDNS
+
+ /**
+ * Sunny Day with Tosca Compliant Policy.
+ */
+ @Test
+ public void testVdnsSunnyDayCompliant() {
+ httpSunnyDay(VDNS_TOSCA_COMPLIANT_POLICY, VDNS_ONSET);
+ }
+
+ // VFW
+
+ /**
+ * VFW Sunny Day with Legacy Tosca Policy.
+ */
+ @Test
+ public void testVfwSunnyDayLegacy() {
+ appcLegacySunnyDay(VFW_TOSCA_LEGACY_POLICY, VFW_ONSET, "ModifyConfig");
+ }
+
+ /**
+ * VFW Sunny Day with Tosca Compliant Policy.
+ */
+ @Test
+ public void testVfwSunnyDayCompliant() {
+ appcLegacySunnyDay(VFW_TOSCA_COMPLIANT_POLICY, VFW_ONSET, "ModifyConfig");
+ }
+
+ // VLB
+
+ /**
+ * Sunny Day with Legacy Tosca Policy.
+ */
+ @Test
+ public void testVlbSunnyDayLegacy() {
+ httpSunnyDay(VLB_TOSCA_LEGACY_POLICY, VLB_ONSET);
+ }
+
+ /**
+ * Sunny Day with Tosca Compliant Policy.
+ */
+ @Test
+ public void testVlbSunnyDayCompliant() {
+ httpSunnyDay(VLB_TOSCA_COMPLIANT_POLICY, VLB_ONSET);
+ }
+
+ /**
+ * Sunny day scenario for use cases that use APPC-LCM.
+ *
+ * @param policyFile file containing the ToscaPolicy to be loaded
+ * @param onsetFile file containing the ONSET to be injected
+ * @param operation expected APPC operation request
+ */
+ protected void appcLcmSunnyDay(String policyFile, String onsetFile, String operation) {
+ appcLcmSunnyDay(policyFile, List.of(onsetFile), operation);
+ }
+
+ /**
+ * Sunny day scenario for use cases that use APPC-LCM.
+ *
+ * @param policyFile file containing the ToscaPolicy to be loaded
+ * @param onsetFiles list of files containing the ONSET to be injected
+ * @param operation expected APPC operation request
+ */
+ protected void appcLcmSunnyDay(String policyFile, List<String> onsetFiles, String operation) {
+ policyClMgt = topics.createListener(POLICY_CL_MGT_TOPIC, VirtualControlLoopNotification.class, controller);
+ appcLcmRead = topics.createListener(APPC_LCM_READ_TOPIC, AppcLcmDmaapWrapper.class, APPC_LCM_CODER);
+
+ assertEquals(0, controller.getDrools().factCount(rules.getControllerName()));
+ policy = rules.setupPolicyFromFile(policyFile);
+ assertEquals(2, controller.getDrools().factCount(rules.getControllerName()));
+
+ // inject several ONSET events over the DCAE topic
+ for (String onsetFile : onsetFiles) {
+ topics.inject(DCAE_TOPIC, onsetFile);
+ }
+
+ /* Wait to acquire a LOCK and a PDP-X PERMIT */
+ waitForLockAndPermit(policy, policyClMgt);
+
+ /*
+ * Ensure that an APPC RESTART request was sent in response to the matching ONSET
+ */
+ AppcLcmDmaapWrapper appcreq = appcLcmRead.await(req -> operation.equals(req.getRpcName()));
+
+ /*
+ * Inject a 400 APPC Response Return over the APPC topic, with appropriate
+ * subRequestId
+ */
+ topics.inject(APPC_LCM_WRITE_TOPIC, VCPE_APPC_SUCCESS,
+ appcreq.getBody().getInput().getCommonHeader().getSubRequestId());
+
+ /* --- Operation Completed --- */
+
+ waitForOperationSuccess();
+
+ /* --- Transaction Completed --- */
+ waitForFinalSuccess(policy, policyClMgt);
+ }
+
+ /**
+ * Sunny day scenario for use cases that use Legacy APPC.
+ *
+ * @param policyFile file containing the ToscaPolicy to be loaded
+ * @param onsetFile file containing the ONSET to be injected
+ * @param operation expected APPC operation request
+ */
+ protected void appcLegacySunnyDay(String policyFile, String onsetFile, String operation) {
+ policyClMgt = topics.createListener(POLICY_CL_MGT_TOPIC, VirtualControlLoopNotification.class, controller);
+ appcClSink = topics.createListener(APPC_CL_TOPIC, Request.class, APPC_LEGACY_CODER);
+
+ assertEquals(0, controller.getDrools().factCount(rules.getControllerName()));
+ policy = rules.setupPolicyFromFile(policyFile);
+ assertEquals(2, controller.getDrools().factCount(rules.getControllerName()));
+
+ /* Inject an ONSET event over the DCAE topic */
+ topics.inject(DCAE_TOPIC, onsetFile);
+
+ /* Wait to acquire a LOCK and a PDP-X PERMIT */
+ waitForLockAndPermit(policy, policyClMgt);
+
+ /*
+ * Ensure that an APPC RESTART request was sent in response to the matching ONSET
+ */
+ Request appcreq = appcClSink.await(req -> operation.equals(req.getAction()));
+
+ /*
+ * Inject a 400 APPC Response Return over the APPC topic, with appropriate
+ * subRequestId
+ */
+ topics.inject(APPC_CL_TOPIC, VFW_APPC_SUCCESS, appcreq.getCommonHeader().getSubRequestId());
+
+ /* --- Operation Completed --- */
+
+ waitForOperationSuccess();
+
+ /* --- Transaction Completed --- */
+ waitForFinalSuccess(policy, policyClMgt);
+ }
+
+ /**
+ * Sunny day scenario for use cases that use an HTTP simulator.
+ *
+ * @param policyFile file containing the ToscaPolicy to be loaded
+ * @param onsetFile file containing the ONSET to be injected
+ * @param operation expected APPC operation request
+ */
+ protected void httpSunnyDay(String policyFile, String onsetFile) {
+ policyClMgt = topics.createListener(POLICY_CL_MGT_TOPIC, VirtualControlLoopNotification.class, controller);
+
+ assertEquals(0, controller.getDrools().factCount(rules.getControllerName()));
+ policy = rules.setupPolicyFromFile(policyFile);
+ assertEquals(2, controller.getDrools().factCount(rules.getControllerName()));
+
+ /* Inject an ONSET event over the DCAE topic */
+ topics.inject(DCAE_TOPIC, onsetFile);
+
+ /* Wait to acquire a LOCK and a PDP-X PERMIT */
+ waitForLockAndPermit(policy, policyClMgt);
+
+ /* --- Operation Completed --- */
+
+ waitForOperationSuccess();
+
+ /* --- Transaction Completed --- */
+ waitForFinalSuccess(policy, policyClMgt);
+ }
+
+ /**
+ * Waits for a OPERATION SUCCESS transaction notification.
+ */
+ protected void waitForOperationSuccess() {
+ policyClMgt.await(notif -> notif.getNotification() == ControlLoopNotificationType.OPERATION_SUCCESS);
+ }
+
+ /**
+ * Waits for a FINAL SUCCESS transaction notification.
+ *
+ * @return the FINAL SUCCESS notification
+ */
+ protected VirtualControlLoopNotification waitForFinalSuccess(ToscaPolicy policy,
+ Listener<VirtualControlLoopNotification> policyClMgt) {
+
+ return this.waitForFinal(policy, policyClMgt, ControlLoopNotificationType.FINAL_SUCCESS);
+ }
+
+ /**
+ * Waits for notifications for LOCK acquisition and GUARD Permit so that event
+ * processing may proceed.
+ */
+ protected abstract void waitForLockAndPermit(ToscaPolicy policy,
+ Listener<VirtualControlLoopNotification> policyClMgt);
+
+ /**
+ * Waits for a FINAL transaction notification.
+ *
+ * @param finalType FINAL_xxx type for which to wait
+ *
+ * @return the FINAL notification
+ */
+ protected abstract VirtualControlLoopNotification waitForFinal(ToscaPolicy policy,
+ Listener<VirtualControlLoopNotification> policyClMgt, ControlLoopNotificationType finalType);
+}
diff --git a/controlloop/common/rules-test/src/main/java/org/onap/policy/controlloop/common/rules/test/HttpClients.java b/controlloop/common/rules-test/src/main/java/org/onap/policy/controlloop/common/rules/test/HttpClients.java
new file mode 100644
index 000000000..eb729ad6d
--- /dev/null
+++ b/controlloop/common/rules-test/src/main/java/org/onap/policy/controlloop/common/rules/test/HttpClients.java
@@ -0,0 +1,67 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.controlloop.common.rules.test;
+
+import org.onap.policy.common.endpoints.http.client.HttpClientConfigException;
+import org.onap.policy.common.endpoints.http.client.HttpClientFactory;
+import org.onap.policy.common.endpoints.http.client.HttpClientFactoryInstance;
+import org.onap.policy.drools.persistence.SystemPersistenceConstants;
+
+/**
+ * Mechanism by which junit tests can manage HTTP Clients.
+ */
+public class HttpClients {
+
+ /**
+ * Constructs the object.
+ */
+ public HttpClients() {
+ super();
+ }
+
+
+ /**
+ * Adds Http Clients specified in the property file.
+ *
+ * @param propFilePrefix prefix prepended to "-http-client.properties" to yield the
+ * full name of the property file containing http client properties
+ */
+ public void addClients(String propFilePrefix) {
+ try {
+ getClientFactory().build(SystemPersistenceConstants.getManager().getHttpClientProperties(propFilePrefix));
+ } catch (HttpClientConfigException e) {
+ throw new IllegalArgumentException("cannot initialize HTTP clients", e);
+ }
+ }
+
+ /**
+ * Destroys all Http Clients.
+ */
+ public void destroy() {
+ getClientFactory().destroy();
+ }
+
+ // these methods may be overridden by junit tests
+
+ protected HttpClientFactory getClientFactory() {
+ return HttpClientFactoryInstance.getClientFactory();
+ }
+}
diff --git a/controlloop/common/rules-test/src/main/java/org/onap/policy/controlloop/common/rules/test/Listener.java b/controlloop/common/rules-test/src/main/java/org/onap/policy/controlloop/common/rules/test/Listener.java
new file mode 100644
index 000000000..5042f54c6
--- /dev/null
+++ b/controlloop/common/rules-test/src/main/java/org/onap/policy/controlloop/common/rules/test/Listener.java
@@ -0,0 +1,180 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.controlloop.common.rules.test;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure;
+import org.onap.policy.common.endpoints.event.comm.TopicEndpoint;
+import org.onap.policy.common.endpoints.event.comm.TopicEndpointManager;
+import org.onap.policy.common.endpoints.event.comm.TopicListener;
+import org.onap.policy.common.endpoints.event.comm.TopicSink;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Listener for messages published on a topic SINK.
+ *
+ * @param <T> message type
+ */
+public class Listener<T> implements TopicListener {
+ private static final Logger logger = LoggerFactory.getLogger(Listener.class);
+ public static long DEFAULT_WAIT_SEC = 5L;
+
+ private final TopicSink sink;
+ private final Function<String, T> decoder;
+ private final BlockingQueue<T> messages = new LinkedBlockingQueue<>();
+
+ /**
+ * Constructs the object.
+ *
+ * @param topicName name of the NOOP topic SINK on which to listen
+ * @param decoder function that takes a topic name and a message and decodes it into
+ * the desired type
+ */
+ public Listener(String topicName, Function<String, T> decoder) {
+ this.sink = getTopicManager().getNoopTopicSink(topicName);
+ this.decoder = decoder;
+ this.sink.register(this);
+ }
+
+ /**
+ * Determines if there are any messages waiting.
+ *
+ * @return {@code true} if there are no messages waiting, {@code false} otherwise
+ */
+ public boolean isEmpty() {
+ return messages.isEmpty();
+ }
+
+ /**
+ * Waits, for the default amount of time, for a message to be published to the topic.
+ *
+ * @return the message that was published
+ * @throws TopicException if interrupted or no message is received within the
+ * specified time
+ */
+ public T await() {
+ return await(DEFAULT_WAIT_SEC, TimeUnit.SECONDS);
+ }
+
+ /**
+ * Waits, for the specified period of time, for a message to be published to the
+ * topic.
+ *
+ * @param twait maximum time to wait
+ * @param unit time unit
+ * @return the message that was published
+ * @throws TopicException if interrupted or no message is received within the
+ * specified time
+ */
+ public T await(long twait, TimeUnit unit) {
+ return await(twait, unit, msg -> true);
+ }
+
+ /**
+ * Waits, for the default amount of time, for a message to be published to the topic.
+ *
+ * @param filter filter used to select the message of interest; preceding messages
+ * that do not pass the filter are discarded
+ * @return the message that was published
+ * @throws TopicException if interrupted or no message is received within the
+ * specified time
+ */
+ public T await(Predicate<T> filter) {
+ return await(DEFAULT_WAIT_SEC, TimeUnit.SECONDS, filter);
+ }
+
+ /**
+ * Waits, for the specified period of time, for a message to be published to the
+ * topic.
+ *
+ * @param twait maximum time to wait
+ * @param unit time unit
+ * @param filter filter used to select the message of interest; preceding messages
+ * that do not pass the filter are discarded
+ * @return the message that was published
+ * @throws TopicException if interrupted or no message is received within the
+ * specified time
+ */
+ public T await(long twait, TimeUnit unit, Predicate<T> filter) {
+ long endMs = System.currentTimeMillis() + TimeUnit.MILLISECONDS.convert(twait, unit);
+
+ for (;;) {
+ try {
+ long remainingMs = endMs - System.currentTimeMillis();
+ if (remainingMs < 0) {
+ throw new TimeoutException();
+ }
+
+ T msg = pollMessage(remainingMs);
+ if (msg == null) {
+ throw new TimeoutException();
+ }
+
+ if (filter.test(msg)) {
+ return msg;
+ }
+
+ logger.info("message discarded by the filter on topic {}", sink.getTopic());
+
+ } catch (InterruptedException e) {
+ logger.warn("'await' interrupted on topic {}", sink.getTopic());
+ Thread.currentThread().interrupt();
+ throw new TopicException(e);
+
+ } catch (TimeoutException e) {
+ logger.warn("'await' timed out on topic {}", sink.getTopic());
+ throw new TopicException(e);
+ }
+ }
+ }
+
+ /**
+ * Unregisters the listener.
+ */
+ public void unregister() {
+ sink.unregister(this);
+ }
+
+ @Override
+ public void onTopicEvent(CommInfrastructure commType, String topic, String event) {
+ try {
+ messages.add(decoder.apply(event));
+ } catch (RuntimeException e) {
+ logger.warn("cannot decode message on topic {} for event {}", topic, event, e);
+ }
+ }
+
+ // these methods may be overridden by junit tests
+
+ protected TopicEndpoint getTopicManager() {
+ return TopicEndpointManager.getManager();
+ }
+
+ protected T pollMessage(long remainingMs) throws InterruptedException {
+ return messages.poll(remainingMs, TimeUnit.MILLISECONDS);
+ }
+}
diff --git a/controlloop/common/rules-test/src/main/java/org/onap/policy/controlloop/common/rules/test/NamedRunner.java b/controlloop/common/rules-test/src/main/java/org/onap/policy/controlloop/common/rules/test/NamedRunner.java
new file mode 100644
index 000000000..1cbe5a56a
--- /dev/null
+++ b/controlloop/common/rules-test/src/main/java/org/onap/policy/controlloop/common/rules/test/NamedRunner.java
@@ -0,0 +1,85 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.controlloop.common.rules.test;
+
+import org.junit.Ignore;
+import org.junit.runner.Description;
+import org.junit.runner.notification.RunNotifier;
+import org.junit.runners.BlockJUnit4ClassRunner;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.InitializationError;
+
+/**
+ * Runs tests listed via the {@link TestNames} annotation.
+ */
+public class NamedRunner extends BlockJUnit4ClassRunner {
+
+ /**
+ * Constructs the object.
+ */
+ public NamedRunner(Class<?> testClass) throws InitializationError {
+ super(testClass);
+ }
+
+ @Override
+ protected void runChild(final FrameworkMethod method, RunNotifier notifier) {
+ Description description = describeChild(method);
+
+ if (method.getAnnotation(Ignore.class) != null) {
+ notifier.fireTestIgnored(description);
+
+ } else if (!isNamed(description.getTestClass(), method.getName())) {
+ notifier.fireTestIgnored(description);
+
+ } else {
+ runLeaf(methodBlock(method), description, notifier);
+ }
+ }
+
+ /**
+ * Determines if the test is in the list of tests to be included.
+ *
+ * @param testClass class under test
+ * @param testName name of the test of interest
+ * @return {@code true} if the test is in the list, {@code false} otherwise
+ */
+ private boolean isNamed(Class<?> testClass, String testName) {
+ TestNames annot = testClass.getAnnotation(TestNames.class);
+ if (annot == null) {
+ // no annotation - everything passes
+ return true;
+ }
+
+ for (String name : annot.names()) {
+ if (testName.equals(name)) {
+ return true;
+ }
+ }
+
+ for (String prefix : annot.prefixes()) {
+ if (testName.startsWith(prefix)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/controlloop/common/rules-test/src/main/java/org/onap/policy/controlloop/common/rules/test/Rules.java b/controlloop/common/rules-test/src/main/java/org/onap/policy/controlloop/common/rules/test/Rules.java
new file mode 100644
index 000000000..7549c6be6
--- /dev/null
+++ b/controlloop/common/rules-test/src/main/java/org/onap/policy/controlloop/common/rules/test/Rules.java
@@ -0,0 +1,413 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.controlloop.common.rules.test;
+
+import static org.awaitility.Awaitility.await;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+import java.util.Properties;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import lombok.Getter;
+import org.apache.commons.lang3.StringUtils;
+import org.kie.api.event.rule.AfterMatchFiredEvent;
+import org.kie.api.event.rule.BeforeMatchFiredEvent;
+import org.kie.api.event.rule.DefaultAgendaEventListener;
+import org.kie.api.event.rule.DefaultRuleRuntimeEventListener;
+import org.kie.api.event.rule.MatchCancelledEvent;
+import org.kie.api.event.rule.MatchCreatedEvent;
+import org.kie.api.event.rule.ObjectDeletedEvent;
+import org.kie.api.event.rule.ObjectInsertedEvent;
+import org.kie.api.event.rule.ObjectUpdatedEvent;
+import org.kie.api.event.rule.RuleRuntimeEventListener;
+import org.kie.api.runtime.KieSession;
+import org.onap.policy.common.utils.coder.CoderException;
+import org.onap.policy.common.utils.coder.StandardCoder;
+import org.onap.policy.common.utils.resources.ResourceUtils;
+import org.onap.policy.controlloop.ControlLoopEvent;
+import org.onap.policy.controlloop.drl.legacy.ControlLoopParams;
+import org.onap.policy.controlloop.eventmanager.ControlLoopEventManager;
+import org.onap.policy.controlloop.eventmanager.ControlLoopEventManager2;
+import org.onap.policy.drools.controller.DroolsController;
+import org.onap.policy.drools.persistence.SystemPersistence;
+import org.onap.policy.drools.persistence.SystemPersistenceConstants;
+import org.onap.policy.drools.system.PolicyController;
+import org.onap.policy.drools.system.PolicyControllerConstants;
+import org.onap.policy.drools.system.PolicyControllerFactory;
+import org.onap.policy.drools.system.PolicyEngine;
+import org.onap.policy.drools.system.PolicyEngineConstants;
+import org.onap.policy.drools.util.KieUtils;
+import org.onap.policy.drools.utils.logging.LoggerUtil;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Mechanism by which junit tests can manage the rule engine.
+ */
+public class Rules {
+ private static final Logger logger = LoggerFactory.getLogger(Rules.class);
+ private static final StandardCoder coder = new StandardCoder();
+
+ /**
+ * PDP-D Engine.
+ */
+ @Getter
+ private final PolicyEngine pdpd = makeEngine();
+
+ /**
+ * PDP-D Configuration Repository.
+ */
+ @Getter
+ private final SystemPersistence pdpdRepo = makePdpdRepo();
+
+
+ @Getter
+ private final String controllerName;
+
+ @Getter
+ private PolicyController controller;
+
+
+ /**
+ * Constructs the object.
+ *
+ * @param controllerName name of the controller
+ */
+ public Rules(String controllerName) {
+ this.controllerName = controllerName;
+ }
+
+ /**
+ * Configures various items, including the PDP-D Engine.
+ *
+ * @param resourceDir path to resource directory
+ */
+ public void configure(String resourceDir) {
+ pdpdRepo.setConfigurationDir("src/test/resources/config");
+
+ try {
+ File kmoduleFile = new File(resourceDir + "/META-INF/kmodule.xml");
+ File pomFile = new File("src/test/resources/" + controllerName + ".pom");
+ String resourceDir2 = resourceDir + "/org/onap/policy/controlloop/";
+ File ruleFile = new File(resourceDir + "/" + controllerName + ".drl");
+ List<File> ruleFiles = Collections.singletonList(ruleFile);
+
+ installArtifact(kmoduleFile, pomFile, resourceDir2, ruleFiles);
+ } catch (IOException e) {
+ throw new IllegalArgumentException("cannot configure KIE session for " + controllerName, e);
+ }
+
+ setupLogging();
+
+ pdpd.configure(new Properties());
+ }
+
+ /**
+ * Starts various items, including the PDP-D Engine.
+ */
+ public void start() {
+ controller = pdpd.createPolicyController(controllerName, pdpdRepo.getControllerProperties(controllerName));
+ pdpd.start();
+
+ setupDroolsLogging();
+ }
+
+ /**
+ * Stop PDP-D.
+ */
+ public void destroy() {
+ getControllerFactory().shutdown(controllerName);
+ pdpd.stop();
+ }
+
+ /**
+ * Removes various facts from working memory, including the Policy and Params, as well
+ * as any event managers and events.
+ */
+ public void resetFacts() {
+ List<Class<?>> classes = List.of(ToscaPolicy.class, ControlLoopParams.class, ControlLoopEventManager2.class,
+ ControlLoopEvent.class);
+
+ // delete all objects of the listed classes
+ DroolsController drools = controller.getDrools();
+ classes.forEach(drools::delete);
+
+ // wait for them to be deleted
+ for (Class<?> clazz : classes) {
+ await(clazz.getSimpleName()).atMost(5, TimeUnit.SECONDS)
+ .until(() -> drools.facts(controllerName, clazz).isEmpty());
+ }
+
+ /*
+ * We can't delete this class directly; we have to wait for the rules to clean it
+ * up, because the rule also cleans up a number of other associated objects.
+ */
+ Class<?> clazz = ControlLoopEventManager.class;
+ await(clazz.getSimpleName()).atMost(5, TimeUnit.SECONDS)
+ .until(() -> drools.facts(controllerName, clazz).isEmpty());
+ }
+
+ /**
+ * Installs a policy from policy/models (examples) repo.
+ */
+ public ToscaPolicy setupPolicyFromTemplate(String templatePath, String policyName) {
+ try {
+ return setupPolicy(getPolicyFromTemplate(templatePath, policyName));
+
+ } catch (InterruptedException | CoderException e) {
+ throw new IllegalArgumentException("policy " + policyName, e);
+ }
+ }
+
+ private ToscaPolicy getPolicyFromTemplate(String resourcePath, String policyName) throws CoderException {
+ String policyJson = ResourceUtils.getResourceAsString(resourcePath);
+ if (policyJson == null) {
+ throw new CoderException(new FileNotFoundException(resourcePath));
+ }
+
+ ToscaServiceTemplate serviceTemplate = coder.decode(policyJson, ToscaServiceTemplate.class);
+ ToscaPolicy policy = serviceTemplate.getToscaTopologyTemplate().getPolicies().get(0).get(policyName);
+ assertNotNull(policy);
+
+ /*
+ * name and version are used within a drl. api component and drools core will
+ * ensure that these are populated.
+ */
+ if (StringUtils.isBlank(policy.getName())) {
+ policy.setName(policyName);
+ }
+
+ if (StringUtils.isBlank(policy.getVersion())) {
+ policy.setVersion(policy.getTypeVersion());
+ }
+
+ return serviceTemplate.getToscaTopologyTemplate().getPolicies().get(0).get(policyName);
+ }
+
+ /**
+ * Installs a given policy.
+ */
+ public ToscaPolicy setupPolicyFromFile(String policyPath) {
+ try {
+ return setupPolicy(getPolicyFromFile(policyPath));
+
+ } catch (InterruptedException | IOException | CoderException e) {
+ throw new IllegalArgumentException("policy " + policyPath, e);
+ }
+ }
+
+ private ToscaPolicy getPolicyFromFile(String policyPath) throws IOException, CoderException {
+ String policyJson = ResourceUtils.getResourceAsString(policyPath);
+ if (policyJson == null) {
+ throw new CoderException(new FileNotFoundException(policyPath));
+ }
+
+ return coder.decode(policyJson, ToscaPolicy.class);
+ }
+
+ private ToscaPolicy setupPolicy(ToscaPolicy policy) throws InterruptedException {
+ final KieObjectExpectedCallback<?> policyTracker = new KieObjectInsertedExpectedCallback<>(policy);
+ final KieObjectExpectedCallback<?> paramsTracker =
+ new KieClassInsertedExpectedCallback<>(ControlLoopParams.class);
+
+ controller.getDrools().offer(policy);
+
+ assertTrue(policyTracker.isNotified());
+ assertTrue(paramsTracker.isNotified());
+
+ assertEquals(1, controller.getDrools().facts(controllerName, ToscaPolicy.class).stream()
+ .filter((anotherPolicy) -> anotherPolicy == policy).count());
+
+ assertEquals(1, controller.getDrools().facts(controllerName, ControlLoopParams.class).stream()
+ .filter((params) -> params.getToscaPolicy() == policy).count());
+ return policy;
+ }
+
+ /**
+ * Sets up overall logging.
+ */
+ private void setupLogging() {
+ LoggerUtil.setLevel(LoggerUtil.ROOT_LOGGER, "WARN");
+ LoggerUtil.setLevel("org.eclipse.jetty", "WARN");
+ LoggerUtil.setLevel("org.onap.policy.controlloop", "INFO");
+ LoggerUtil.setLevel("network", "INFO");
+ }
+
+ /**
+ * Sets up Drools Logging for events of interest.
+ */
+ private void setupDroolsLogging() {
+ KieSession session = getKieSession();
+
+ session.addEventListener(new RuleListenerLogger());
+ session.addEventListener(new AgendaListenerLogger());
+ }
+
+ /**
+ * Logs Modifications to Working Memory.
+ */
+ private static class RuleListenerLogger implements RuleRuntimeEventListener {
+ @Override
+ public void objectInserted(ObjectInsertedEvent event) {
+ String ruleName = (event.getRule() != null) ? event.getRule().getName() : "null";
+ logger.info("RULE {}: inserted {}", ruleName, event.getObject());
+ }
+
+ @Override
+ public void objectUpdated(ObjectUpdatedEvent event) {
+ String ruleName = (event.getRule() != null) ? event.getRule().getName() : "null";
+ logger.info("RULE {}: updated {}", ruleName, event.getObject());
+
+ }
+
+ @Override
+ public void objectDeleted(ObjectDeletedEvent event) {
+ String ruleName = (event.getRule() != null) ? event.getRule().getName() : "null";
+ logger.info("RULE {}: deleted {}", ruleName, event.getOldObject());
+ }
+ }
+
+ /**
+ * Logs Rule Matches.
+ */
+ private static class AgendaListenerLogger extends DefaultAgendaEventListener {
+ @Override
+ public void matchCreated(MatchCreatedEvent event) {
+ logger.info("RULE {}: match created", event.getMatch().getRule().getName());
+ }
+
+ @Override
+ public void matchCancelled(MatchCancelledEvent event) {
+ logger.info("RULE {}: match cancelled", event.getMatch().getRule().getName());
+ }
+
+ @Override
+ public void beforeMatchFired(BeforeMatchFiredEvent event) {
+ logger.info("RULE {}: before match fired", event.getMatch().getRule().getName());
+ }
+
+ @Override
+ public void afterMatchFired(AfterMatchFiredEvent event) {
+ logger.info("RULE {}: after match fired", event.getMatch().getRule().getName());
+ }
+ }
+
+ /**
+ * Base Class to track Working Memory updates for objects of type T.
+ */
+ private abstract class KieObjectExpectedCallback<T> extends DefaultRuleRuntimeEventListener {
+ protected T subject;
+
+ protected CountDownLatch countDownLatch = new CountDownLatch(1);
+
+ public KieObjectExpectedCallback(T affected) {
+ subject = affected;
+ register();
+ }
+
+ public boolean isNotified() throws InterruptedException {
+ return countDownLatch.await(9L, TimeUnit.SECONDS);
+ }
+
+ protected void callbacked() {
+ unregister();
+ countDownLatch.countDown();
+ }
+
+ public KieObjectExpectedCallback<T> register() {
+ getKieSession().addEventListener(this);
+ return this;
+ }
+
+ public KieObjectExpectedCallback<T> unregister() {
+ getKieSession().removeEventListener(this);
+ return this;
+ }
+ }
+
+ /**
+ * Tracks inserts in Working Memory for an object of type T.
+ */
+ private class KieObjectInsertedExpectedCallback<T> extends KieObjectExpectedCallback<T> {
+ public KieObjectInsertedExpectedCallback(T affected) {
+ super(affected);
+ }
+
+ @Override
+ public void objectInserted(ObjectInsertedEvent event) {
+ if (subject == event.getObject()) {
+ callbacked();
+ }
+ }
+ }
+
+ /**
+ * Tracks inserts in Working Memory for any object of class T.
+ */
+ private class KieClassInsertedExpectedCallback<T> extends KieObjectInsertedExpectedCallback<T> {
+
+ public KieClassInsertedExpectedCallback(T affected) {
+ super(affected);
+ }
+
+ public void objectInserted(ObjectInsertedEvent event) {
+ if (subject == event.getObject().getClass()) {
+ callbacked();
+ }
+ }
+ }
+
+ // these may be overridden by junit tests
+
+
+ protected PolicyEngine makeEngine() {
+ return PolicyEngineConstants.getManager();
+ }
+
+
+ protected SystemPersistence makePdpdRepo() {
+ return SystemPersistenceConstants.getManager();
+ }
+
+ protected KieSession getKieSession() {
+ return getControllerFactory().get(controllerName).getDrools().getContainer().getPolicySession(controllerName)
+ .getKieSession();
+ }
+
+ protected PolicyControllerFactory getControllerFactory() {
+ return PolicyControllerConstants.getFactory();
+ }
+
+ protected void installArtifact(File kmoduleFile, File pomFile, String resourceDir, List<File> ruleFiles)
+ throws IOException {
+
+ KieUtils.installArtifact(kmoduleFile, pomFile, resourceDir, ruleFiles);
+ }
+}
diff --git a/controlloop/common/rules-test/src/main/java/org/onap/policy/controlloop/common/rules/test/SimulatorException.java b/controlloop/common/rules-test/src/main/java/org/onap/policy/controlloop/common/rules/test/SimulatorException.java
new file mode 100644
index 000000000..f9880d07a
--- /dev/null
+++ b/controlloop/common/rules-test/src/main/java/org/onap/policy/controlloop/common/rules/test/SimulatorException.java
@@ -0,0 +1,44 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.controlloop.common.rules.test;
+
+/**
+ * Exception thrown by <i>Simulators</i>.
+ */
+public class SimulatorException extends RuntimeException {
+ private static final long serialVersionUID = 1L;
+
+ public SimulatorException() {
+ super();
+ }
+
+ public SimulatorException(String message) {
+ super(message);
+ }
+
+ public SimulatorException(Throwable cause) {
+ super(cause);
+ }
+
+ public SimulatorException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/controlloop/common/rules-test/src/main/java/org/onap/policy/controlloop/common/rules/test/Simulators.java b/controlloop/common/rules-test/src/main/java/org/onap/policy/controlloop/common/rules/test/Simulators.java
new file mode 100644
index 000000000..4a325a447
--- /dev/null
+++ b/controlloop/common/rules-test/src/main/java/org/onap/policy/controlloop/common/rules/test/Simulators.java
@@ -0,0 +1,85 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.controlloop.common.rules.test;
+
+import java.util.LinkedList;
+import java.util.List;
+import lombok.AccessLevel;
+import lombok.Getter;
+import org.onap.policy.common.endpoints.http.server.HttpServletServer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Simulator container.
+ */
+public class Simulators {
+ private static final Logger logger = LoggerFactory.getLogger(Simulators.class);
+
+ @Getter(AccessLevel.PROTECTED)
+ private final List<HttpServletServer> servers = new LinkedList<>();
+
+ /**
+ * Constructs the object.
+ */
+ public Simulators() {
+ super();
+ }
+
+ /**
+ * Invokes the given functions to start the simulators. Destroys <i>all</i> of the
+ * simulators if any fail to start.
+ *
+ * @param builders functions to invoke to build the simulators
+ */
+ public void start(SimulatorBuilder... builders) {
+ try {
+ for (SimulatorBuilder builder : builders) {
+ servers.add(builder.build());
+ }
+ } catch (InterruptedException e) {
+ logger.warn("interrupted building the simulators");
+ destroy();
+ Thread.currentThread().interrupt();
+ throw new SimulatorException(e);
+ }
+ }
+
+ /**
+ * Stops all of the simulators.
+ */
+ public void destroy() {
+ for (HttpServletServer server : servers) {
+ try {
+ server.shutdown();
+ } catch (RuntimeException e) {
+ logger.warn("error stopping simulator {}", server.getName(), e);
+ }
+ }
+
+ servers.clear();
+ }
+
+ @FunctionalInterface
+ public static interface SimulatorBuilder {
+ public HttpServletServer build() throws InterruptedException;
+ }
+}
diff --git a/controlloop/common/rules-test/src/main/java/org/onap/policy/controlloop/common/rules/test/TestNames.java b/controlloop/common/rules-test/src/main/java/org/onap/policy/controlloop/common/rules/test/TestNames.java
new file mode 100644
index 000000000..5f3d856ef
--- /dev/null
+++ b/controlloop/common/rules-test/src/main/java/org/onap/policy/controlloop/common/rules/test/TestNames.java
@@ -0,0 +1,44 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.controlloop.common.rules.test;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation for a test CLASS. Used to identify the names of the test methods to be
+ * included.
+ */
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface TestNames {
+ /**
+ * Test method names to be included.
+ */
+ String[] names() default {};
+
+ /**
+ * Prefixes of test method names to be included.
+ */
+ String[] prefixes() default {};
+}
diff --git a/controlloop/common/rules-test/src/main/java/org/onap/policy/controlloop/common/rules/test/TopicException.java b/controlloop/common/rules-test/src/main/java/org/onap/policy/controlloop/common/rules/test/TopicException.java
new file mode 100644
index 000000000..01a866966
--- /dev/null
+++ b/controlloop/common/rules-test/src/main/java/org/onap/policy/controlloop/common/rules/test/TopicException.java
@@ -0,0 +1,44 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.controlloop.common.rules.test;
+
+/**
+ * Exception thrown by <i>Topics</i>.
+ */
+public class TopicException extends RuntimeException {
+ private static final long serialVersionUID = 1L;
+
+ public TopicException() {
+ super();
+ }
+
+ public TopicException(String message) {
+ super(message);
+ }
+
+ public TopicException(Throwable cause) {
+ super(cause);
+ }
+
+ public TopicException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/controlloop/common/rules-test/src/main/java/org/onap/policy/controlloop/common/rules/test/Topics.java b/controlloop/common/rules-test/src/main/java/org/onap/policy/controlloop/common/rules/test/Topics.java
new file mode 100644
index 000000000..f71559acb
--- /dev/null
+++ b/controlloop/common/rules-test/src/main/java/org/onap/policy/controlloop/common/rules/test/Topics.java
@@ -0,0 +1,176 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.controlloop.common.rules.test;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.function.Function;
+import org.onap.policy.common.endpoints.event.comm.TopicEndpoint;
+import org.onap.policy.common.endpoints.event.comm.TopicEndpointManager;
+import org.onap.policy.common.utils.coder.Coder;
+import org.onap.policy.common.utils.coder.CoderException;
+import org.onap.policy.common.utils.resources.ResourceUtils;
+import org.onap.policy.drools.protocol.coders.EventProtocolCoder;
+import org.onap.policy.drools.protocol.coders.EventProtocolCoderConstants;
+import org.onap.policy.drools.system.PolicyController;
+
+/**
+ * Mechanism by which junit tests can manage topic messages.
+ */
+public class Topics {
+ /**
+ * Wherever this string appears within an input file, it is replaced by a value passed
+ * as a parameter to the {@link #inject(String, String, String)} method.
+ */
+ private static final String REPLACE_ME = "${replaceMe}";
+
+ /**
+ * Listeners that have been created and registered by "this" object.
+ */
+ private final List<Listener<?>> listeners = new LinkedList<>();
+
+
+ /**
+ * Constructs the object.
+ */
+ public Topics() {
+ super();
+ }
+
+ /**
+ * Unregisters all of the listeners.
+ */
+ public void destroy() {
+ listeners.forEach(Listener::unregister);
+ }
+
+ /**
+ * Injects the content of the given file onto a NOOP topic SOURCE.
+ *
+ * @param topicName topic on which to inject
+ * @param file file whose content is to be injected
+ */
+ public void inject(String topicName, String file) {
+ inject(topicName, file, REPLACE_ME);
+ }
+
+ /**
+ * Injects the content of the given file onto a NOOP topic SOURCE, with the given
+ * substitution.
+ *
+ * @param topicName topic on which to inject
+ * @param file file whose content is to be injected
+ * @param newText text to be substituted for occurrences of "${replaceMe}" in the
+ * source file
+ */
+ public void inject(String topicName, String file, String newText) {
+ try {
+ String text = ResourceUtils.getResourceAsString(file);
+ if (text == null) {
+ throw new FileNotFoundException(file);
+ }
+ text = text.replace(REPLACE_ME, newText);
+ getTopicManager().getNoopTopicSource(topicName).offer(text);
+ } catch (IOException e) {
+ throw new TopicException(e);
+ }
+ }
+
+ /**
+ * Creates a listener for messages published on a NOOP topic SINK. Messages are
+ * decoded using the coder associated with the controller.
+ *
+ * @param <T> message type
+ * @param topicName name of the topic on which to listen
+ * @param expectedClass type of message expected
+ * @param controller controller whose decoders are to be used
+ * @return a new listener
+ */
+ public <T> Listener<T> createListener(String topicName, Class<T> expectedClass, PolicyController controller) {
+ EventProtocolCoder mgr = getProtocolCoder();
+ String groupId = controller.getDrools().getGroupId();
+ String artifactId = controller.getDrools().getArtifactId();
+
+ // @formatter:off
+ return createListener(topicName,
+ event -> expectedClass.cast(mgr.decode(groupId, artifactId, topicName, event)));
+ // @formatter:on
+ }
+
+ /**
+ * Creates a listener for messages published on a NOOP topic SINK. Messages are
+ * decoded using the specified coder.
+ *
+ * @param <T> message type
+ * @param topicName name of the topic on which to listen
+ * @param expectedClass type of message expected
+ * @param coder coder to decode the messages
+ * @return a new listener
+ */
+ public <T> Listener<T> createListener(String topicName, Class<T> expectedClass, Coder coder) {
+ Function<String, T> decoder = event -> {
+ try {
+ return coder.decode(event, expectedClass);
+ } catch (CoderException e) {
+ throw new IllegalArgumentException("cannot decode message", e);
+ }
+ };
+
+ return createListener(topicName, decoder);
+ }
+
+ /**
+ * Creates a listener for messages published on a NOOP topic SINK. Messages are
+ * decoded using the specified decoder.
+ *
+ * @param <T> message type
+ * @param topicName name of the topic on which to listen
+ * @param decoder function that takes a message and decodes it into the desired type
+ * @return a new listener
+ */
+ public <T> Listener<T> createListener(String topicName, Function<String, T> decoder) {
+ Listener<T> listener = makeListener(topicName, decoder);
+ listeners.add(listener);
+
+ return listener;
+ }
+
+ // these methods may be overridden by junit tests
+
+ protected TopicEndpoint getTopicManager() {
+ return TopicEndpointManager.getManager();
+ }
+
+ protected EventProtocolCoder getProtocolCoder() {
+ return EventProtocolCoderConstants.getManager();
+ }
+
+ protected <T> Listener<T> makeListener(String topicName, Function<String, T> decoder) {
+ return new Listener<>(topicName, decoder) {
+ @Override
+ protected TopicEndpoint getTopicManager() {
+ return Topics.this.getTopicManager();
+ }
+ };
+ }
+}
diff --git a/controlloop/common/rules-test/src/main/resources/duplicates/duplicates.appc.success.json b/controlloop/common/rules-test/src/main/resources/duplicates/duplicates.appc.success.json
new file mode 100644
index 000000000..331021798
--- /dev/null
+++ b/controlloop/common/rules-test/src/main/resources/duplicates/duplicates.appc.success.json
@@ -0,0 +1,22 @@
+{
+ "body": {
+ "output": {
+ "common-header": {
+ "timestamp": "2017-08-25T21:06:23.037Z",
+ "api-ver": "5.00",
+ "originator-id": "664be3d2-6c12-4f4b-a3e7-c349acced200",
+ "request-id": "664be3d2-6c12-4f4b-a3e7-c349acced200",
+ "sub-request-id": "${replaceMe}",
+ "flags": {}
+ },
+ "status": {
+ "code": 400,
+ "message": "Restart Successful"
+ }
+ }
+ },
+ "version": "2.0",
+ "rpc-name": "restart",
+ "correlation-id": "664be3d2-6c12-4f4b-a3e7-c349acced200-1",
+ "type": "response"
+}
diff --git a/controlloop/common/rules-test/src/main/resources/duplicates/duplicates.onset.1.json b/controlloop/common/rules-test/src/main/resources/duplicates/duplicates.onset.1.json
new file mode 100644
index 000000000..70f48442f
--- /dev/null
+++ b/controlloop/common/rules-test/src/main/resources/duplicates/duplicates.onset.1.json
@@ -0,0 +1,16 @@
+{
+ "closedLoopControlName": "ControlLoop-Duplicates-48f0c2c3-a172-4192-9ae3-052274181b6e",
+ "closedLoopAlarmStart": 1463679805324,
+ "closedLoopEventClient": "DCAE_INSTANCE_ID.dcae-tca",
+ "closedLoopEventStatus": "ONSET",
+ "requestID": "${replaceMe}",
+ "target_type": "VNF",
+ "target": "generic-vnf.vnf-id",
+ "AAI": {
+ "vserver.is-closed-loop-disabled": "false",
+ "vserver.prov-status": "ACTIVE",
+ "generic-vnf.vnf-id": "duplicate-VNF"
+ },
+ "from": "DCAE",
+ "version": "1.0.2"
+}
diff --git a/controlloop/common/rules-test/src/main/resources/duplicates/duplicates.onset.2.json b/controlloop/common/rules-test/src/main/resources/duplicates/duplicates.onset.2.json
new file mode 100644
index 000000000..046243609
--- /dev/null
+++ b/controlloop/common/rules-test/src/main/resources/duplicates/duplicates.onset.2.json
@@ -0,0 +1,16 @@
+{
+ "closedLoopControlName": "ControlLoop-Duplicates-48f0c2c3-a172-4192-9ae3-052274181b6e",
+ "closedLoopAlarmStart": 1463679805324,
+ "closedLoopEventClient": "DCAE_INSTANCE_ID.dcae-tca",
+ "closedLoopEventStatus": "ONSET",
+ "requestID": "664be3d2-6c12-4f4b-a3e7-c349acced200",
+ "target_type": "VNF",
+ "target": "generic-vnf.vnf-id",
+ "AAI": {
+ "vserver.is-closed-loop-disabled": "false",
+ "vserver.prov-status": "ACTIVE",
+ "generic-vnf.vnf-id": "vCPE_Infrastructure_vGMUX_demo_app"
+ },
+ "from": "DCAE",
+ "version": "1.0.2"
+}
diff --git a/controlloop/common/rules-test/src/main/resources/duplicates/tosca-compliant-duplicates.json b/controlloop/common/rules-test/src/main/resources/duplicates/tosca-compliant-duplicates.json
new file mode 100644
index 000000000..d67472743
--- /dev/null
+++ b/controlloop/common/rules-test/src/main/resources/duplicates/tosca-compliant-duplicates.json
@@ -0,0 +1,37 @@
+{
+ "type": "onap.policies.controlloop.operational.common.Drools",
+ "type_version": "1.0.0",
+ "version": "1.0.0",
+ "name": "operational.restart",
+ "metadata": {
+ "policy-id": "operational.restart"
+ },
+ "properties": {
+ "controllerName": "usecases",
+ "id": "ControlLoop-Duplicates-48f0c2c3-a172-4192-9ae3-052274181b6e",
+ "timeout": 3600,
+ "abatement": false,
+ "trigger": "unique-policy-id-1-restart",
+ "operations": [
+ {
+ "id": "unique-policy-id-1-restart",
+ "description": "Restart the VM",
+ "operation": {
+ "actor": "APPC",
+ "operation": "Restart",
+ "target": {
+ "targetType": "VM"
+ }
+ },
+ "timeout": 1200,
+ "retries": 3,
+ "success": "final_success",
+ "failure": "final_failure",
+ "failure_timeout": "final_failure_timeout",
+ "failure_retries": "final_failure_retries",
+ "failure_exception": "final_failure_exception",
+ "failure_guard": "final_failure_guard"
+ }
+ ]
+ }
+}
diff --git a/controlloop/common/rules-test/src/main/resources/service123/service123.appc.migrate.success.json b/controlloop/common/rules-test/src/main/resources/service123/service123.appc.migrate.success.json
new file mode 100644
index 000000000..563e2c762
--- /dev/null
+++ b/controlloop/common/rules-test/src/main/resources/service123/service123.appc.migrate.success.json
@@ -0,0 +1,22 @@
+{
+ "body": {
+ "output": {
+ "common-header": {
+ "timestamp": "2017-08-25T21:06:23.037Z",
+ "api-ver": "5.00",
+ "originator-id": "664be3d2-6c12-4f4b-a3e7-c349acced200",
+ "request-id": "664be3d2-6c12-4f4b-a3e7-c349acced200",
+ "sub-request-id": "${replaceMe}",
+ "flags": {}
+ },
+ "status": {
+ "code": 400,
+ "message": "Migrate Successful"
+ }
+ }
+ },
+ "version": "2.0",
+ "rpc-name": "migrate",
+ "correlation-id": "664be3d2-6c12-4f4b-a3e7-c349acced200-1",
+ "type": "response"
+}
diff --git a/controlloop/common/rules-test/src/main/resources/service123/service123.appc.rebuild.failure.json b/controlloop/common/rules-test/src/main/resources/service123/service123.appc.rebuild.failure.json
new file mode 100644
index 000000000..88e70ef7a
--- /dev/null
+++ b/controlloop/common/rules-test/src/main/resources/service123/service123.appc.rebuild.failure.json
@@ -0,0 +1,22 @@
+{
+ "body": {
+ "output": {
+ "common-header": {
+ "timestamp": "2017-08-25T21:06:23.037Z",
+ "api-ver": "5.00",
+ "originator-id": "664be3d2-6c12-4f4b-a3e7-c349acced200",
+ "request-id": "664be3d2-6c12-4f4b-a3e7-c349acced200",
+ "sub-request-id": "${replaceMe}",
+ "flags": {}
+ },
+ "status": {
+ "code": 401,
+ "message": "Rebuild Failed"
+ }
+ }
+ },
+ "version": "2.0",
+ "rpc-name": "rebuild",
+ "correlation-id": "664be3d2-6c12-4f4b-a3e7-c349acced200-1",
+ "type": "response"
+}
diff --git a/controlloop/common/rules-test/src/main/resources/service123/service123.appc.restart.failure.json b/controlloop/common/rules-test/src/main/resources/service123/service123.appc.restart.failure.json
new file mode 100644
index 000000000..7376c8ad3
--- /dev/null
+++ b/controlloop/common/rules-test/src/main/resources/service123/service123.appc.restart.failure.json
@@ -0,0 +1,22 @@
+{
+ "body": {
+ "output": {
+ "common-header": {
+ "timestamp": "2017-08-25T21:06:23.037Z",
+ "api-ver": "5.00",
+ "originator-id": "664be3d2-6c12-4f4b-a3e7-c349acced200",
+ "request-id": "664be3d2-6c12-4f4b-a3e7-c349acced200",
+ "sub-request-id": "${replaceMe}",
+ "flags": {}
+ },
+ "status": {
+ "code": 401,
+ "message": "Restart Failed"
+ }
+ }
+ },
+ "version": "2.0",
+ "rpc-name": "restart",
+ "correlation-id": "664be3d2-6c12-4f4b-a3e7-c349acced200-1",
+ "type": "response"
+}
diff --git a/controlloop/common/rules-test/src/main/resources/service123/service123.onset.json b/controlloop/common/rules-test/src/main/resources/service123/service123.onset.json
new file mode 100644
index 000000000..a78cb5337
--- /dev/null
+++ b/controlloop/common/rules-test/src/main/resources/service123/service123.onset.json
@@ -0,0 +1,17 @@
+{
+ "closedLoopControlName": "ControlLoop-Service123-cbed919f-2212-4ef7-8051-fe6308da1bda",
+ "closedLoopAlarmStart": 1463679805324,
+ "closedLoopEventClient": "DCAE_INSTANCE_ID.dcae-tca",
+ "closedLoopEventStatus": "ONSET",
+ "requestID": "664be3d2-6c12-4f4b-a3e7-c349acced200",
+ "target_type": "VNF",
+ "target": "generic-vnf.vnf-name",
+ "AAI": {
+ "vserver.is-closed-loop-disabled": "false",
+ "vserver.prov-status": "ACTIVE",
+ "generic-vnf.vnf-name": "fw0002vm002fw002",
+ "vserver.vserver-name": "OzVServer"
+ },
+ "from": "DCAE",
+ "version": "1.0.2"
+}
diff --git a/controlloop/common/rules-test/src/main/resources/service123/tosca-compliant-service123.json b/controlloop/common/rules-test/src/main/resources/service123/tosca-compliant-service123.json
new file mode 100644
index 000000000..4eaa9e70a
--- /dev/null
+++ b/controlloop/common/rules-test/src/main/resources/service123/tosca-compliant-service123.json
@@ -0,0 +1,75 @@
+{
+ "type": "onap.policies.controlloop.operational.common.Drools",
+ "type_version": "1.0.0",
+ "version": "1.0.0",
+ "name": "operational.service123",
+ "metadata": {
+ "policy-id": "operational.service123"
+ },
+ "properties": {
+ "controllerName": "usecases",
+ "id": "ControlLoop-Service123-cbed919f-2212-4ef7-8051-fe6308da1bda",
+ "timeout": 60,
+ "abatement": true,
+ "trigger": "unique-policy-id-1-restart",
+ "operations": [
+ {
+ "id": "unique-policy-id-1-restart",
+ "description": "Restart the VM",
+ "operation": {
+ "actor": "APPC",
+ "operation": "Restart",
+ "target": {
+ "targetType": "VM"
+ }
+ },
+ "timeout": 20,
+ "retries": 3,
+ "success": "final_success",
+ "failure": "unique-policy-id-2-rebuild",
+ "failure_timeout": "unique-policy-id-2-rebuild",
+ "failure_retries": "unique-policy-id-2-rebuild",
+ "failure_guard": "unique-policy-id-2-rebuild",
+ "failure_exception": "final_failure_exception"
+ },
+ {
+ "id": "unique-policy-id-2-rebuild",
+ "name": "Rebuild Policy",
+ "operation": {
+ "actor": "APPC",
+ "operation": "Rebuild",
+ "target": {
+ "targetType": "VM"
+ }
+ },
+ "timeout": 10,
+ "retries": 0,
+ "success": "final_success",
+ "failure": "unique-policy-id-3-migrate",
+ "failure_timeout": "unique-policy-id-3-migrate",
+ "failure_retries": "unique-policy-id-3-migrate",
+ "failure_guard": "unique-policy-id-3-migrate",
+ "failure_exception": "final_failure_exception"
+ },
+ {
+ "id": "unique-policy-id-3-migrate",
+ "name": "Migrate Policy",
+ "operation": {
+ "actor": "APPC",
+ "operation": "Migrate",
+ "target": {
+ "targetType": "VM"
+ }
+ },
+ "timeout": 30,
+ "retries": 0,
+ "success": "final_success",
+ "failure": "final_failure",
+ "failure_timeout": "final_failure_timeout",
+ "failure_retries": "final_failure_retries",
+ "failure_guard": "final_failure_guard",
+ "failure_exception": "final_failure_exception"
+ }
+ ]
+ }
+}
diff --git a/controlloop/common/rules-test/src/main/resources/vcpe/tosca-compliant-vcpe.json b/controlloop/common/rules-test/src/main/resources/vcpe/tosca-compliant-vcpe.json
new file mode 100644
index 000000000..b70145b68
--- /dev/null
+++ b/controlloop/common/rules-test/src/main/resources/vcpe/tosca-compliant-vcpe.json
@@ -0,0 +1,37 @@
+{
+ "type": "onap.policies.controlloop.operational.common.Drools",
+ "type_version": "1.0.0",
+ "version": "1.0.0",
+ "name": "operational.restart",
+ "metadata": {
+ "policy-id": "operational.restart"
+ },
+ "properties": {
+ "controllerName": "usecases",
+ "id": "ControlLoop-vCPE-48f0c2c3-a172-4192-9ae3-052274181b6e",
+ "timeout": 3600,
+ "abatement": false,
+ "trigger": "unique-policy-id-1-restart",
+ "operations": [
+ {
+ "id": "unique-policy-id-1-restart",
+ "description": "Restart the VM",
+ "operation": {
+ "actor": "APPC",
+ "operation": "Restart",
+ "target": {
+ "targetType": "VM"
+ }
+ },
+ "timeout": 1200,
+ "retries": 3,
+ "success": "final_success",
+ "failure": "final_failure",
+ "failure_timeout": "final_failure_timeout",
+ "failure_retries": "final_failure_retries",
+ "failure_exception": "final_failure_exception",
+ "failure_guard": "final_failure_guard"
+ }
+ ]
+ }
+}
diff --git a/controlloop/common/rules-test/src/main/resources/vcpe/tosca-legacy-vcpe.json b/controlloop/common/rules-test/src/main/resources/vcpe/tosca-legacy-vcpe.json
new file mode 100644
index 000000000..cb0806e16
--- /dev/null
+++ b/controlloop/common/rules-test/src/main/resources/vcpe/tosca-legacy-vcpe.json
@@ -0,0 +1,9 @@
+{
+ "type": "onap.policies.controlloop.Operational",
+ "type_version": "1.0.0",
+ "properties": {
+ "content": "controlLoop%3A%0A%20%20version%3A%202.0.0%0A%20%20controlLoopName%3A%20ControlLoop-vCPE-48f0c2c3-a172-4192-9ae3-052274181b6e%0A%20%20trigger_policy%3A%20unique-policy-id-1-restart%0A%20%20timeout%3A%203600%0A%20%20abatement%3A%20false%0A%20%0Apolicies%3A%0A%20%20-%20id%3A%20unique-policy-id-1-restart%0A%20%20%20%20name%3A%20Restart%20the%20VM%0A%20%20%20%20description%3A%0A%20%20%20%20actor%3A%20APPC%0A%20%20%20%20recipe%3A%20Restart%0A%20%20%20%20target%3A%0A%20%20%20%20%20%20type%3A%20VM%0A%20%20%20%20retry%3A%203%0A%20%20%20%20timeout%3A%201200%0A%20%20%20%20success%3A%20final_success%0A%20%20%20%20failure%3A%20final_failure%0A%20%20%20%20failure_timeout%3A%20final_failure_timeout%0A%20%20%20%20failure_retries%3A%20final_failure_retries%0A%20%20%20%20failure_exception%3A%20final_failure_exception%0A%20%20%20%20failure_guard%3A%20final_failure_guard"
+ },
+ "name": "vcpe",
+ "version": "1.0.0"
+}
diff --git a/controlloop/common/rules-test/src/main/resources/vcpe/vcpe.appc.success.json b/controlloop/common/rules-test/src/main/resources/vcpe/vcpe.appc.success.json
new file mode 100644
index 000000000..331021798
--- /dev/null
+++ b/controlloop/common/rules-test/src/main/resources/vcpe/vcpe.appc.success.json
@@ -0,0 +1,22 @@
+{
+ "body": {
+ "output": {
+ "common-header": {
+ "timestamp": "2017-08-25T21:06:23.037Z",
+ "api-ver": "5.00",
+ "originator-id": "664be3d2-6c12-4f4b-a3e7-c349acced200",
+ "request-id": "664be3d2-6c12-4f4b-a3e7-c349acced200",
+ "sub-request-id": "${replaceMe}",
+ "flags": {}
+ },
+ "status": {
+ "code": 400,
+ "message": "Restart Successful"
+ }
+ }
+ },
+ "version": "2.0",
+ "rpc-name": "restart",
+ "correlation-id": "664be3d2-6c12-4f4b-a3e7-c349acced200-1",
+ "type": "response"
+}
diff --git a/controlloop/common/rules-test/src/main/resources/vcpe/vcpe.onset.1.json b/controlloop/common/rules-test/src/main/resources/vcpe/vcpe.onset.1.json
new file mode 100644
index 000000000..d08ee47cd
--- /dev/null
+++ b/controlloop/common/rules-test/src/main/resources/vcpe/vcpe.onset.1.json
@@ -0,0 +1,16 @@
+{
+ "closedLoopControlName": "ControlLoop-vCPE-48f0c2c3-a172-4192-9ae3-052274181b6e",
+ "closedLoopAlarmStart": 1463679805324,
+ "closedLoopEventClient": "DCAE_INSTANCE_ID.dcae-tca",
+ "closedLoopEventStatus": "ONSET",
+ "requestID": "664be3d2-6c12-4f4b-a3e7-c349acced200",
+ "target_type": "VNF",
+ "target": "generic-vnf.vnf-id",
+ "AAI": {
+ "vserver.is-closed-loop-disabled": "false",
+ "vserver.prov-status": "ACTIVE",
+ "generic-vnf.vnf-id": "vCPE_Infrastructure_vGMUX_demo_app"
+ },
+ "from": "DCAE",
+ "version": "1.0.2"
+} \ No newline at end of file
diff --git a/controlloop/common/rules-test/src/main/resources/vcpe/vcpe.onset.2.json b/controlloop/common/rules-test/src/main/resources/vcpe/vcpe.onset.2.json
new file mode 100644
index 000000000..b8c76514e
--- /dev/null
+++ b/controlloop/common/rules-test/src/main/resources/vcpe/vcpe.onset.2.json
@@ -0,0 +1,16 @@
+{
+ "closedLoopControlName": "ControlLoop-vCPE-48f0c2c3-a172-4192-9ae3-052274181b6e",
+ "closedLoopAlarmStart": 1463679805324,
+ "closedLoopEventClient": "DCAE_INSTANCE_ID.dcae-tca",
+ "closedLoopEventStatus": "ONSET",
+ "requestID": "8cf3cd05-1218-4224-931b-601494ffe55b",
+ "target_type": "VNF",
+ "target": "generic-vnf.vnf-id",
+ "AAI": {
+ "vserver.is-closed-loop-disabled": "false",
+ "vserver.prov-status": "ACTIVE",
+ "generic-vnf.vnf-id": "vCPE_Infrastructure_vGMUX_demo_app"
+ },
+ "from": "DCAE",
+ "version": "1.0.2"
+} \ No newline at end of file
diff --git a/controlloop/common/rules-test/src/main/resources/vcpe/vcpe.onset.3.json b/controlloop/common/rules-test/src/main/resources/vcpe/vcpe.onset.3.json
new file mode 100644
index 000000000..40f29b3cf
--- /dev/null
+++ b/controlloop/common/rules-test/src/main/resources/vcpe/vcpe.onset.3.json
@@ -0,0 +1,17 @@
+{
+ "closedLoopControlName": "ControlLoop-vCPE-48f0c2c3-a172-4192-9ae3-052274181b6e",
+ "closedLoopAlarmStart": 1570722876324905,
+ "closedLoopAlarmEnd": 1570722876324999,
+ "closedLoopEventClient": "DCAE_INSTANCE_ID.dcae-tca",
+ "closedLoopEventStatus": "ONSET",
+ "requestID": "8cf3cd05-1218-4224-931b-601494ffe55b",
+ "target_type": "VNF",
+ "target": "generic-vnf.vnf-id",
+ "AAI": {
+ "vserver.is-closed-loop-disabled": "false",
+ "vserver.prov-status": "ACTIVE",
+ "generic-vnf.vnf-id": "vCPE_Infrastructure_vGMUX_demo_app"
+ },
+ "from": "DCAE",
+ "version": "1.0.2"
+} \ No newline at end of file
diff --git a/controlloop/common/rules-test/src/main/resources/vdns/tosca-compliant-vdns.json b/controlloop/common/rules-test/src/main/resources/vdns/tosca-compliant-vdns.json
new file mode 100644
index 000000000..918e92770
--- /dev/null
+++ b/controlloop/common/rules-test/src/main/resources/vdns/tosca-compliant-vdns.json
@@ -0,0 +1,48 @@
+{
+ "type": "onap.policies.controlloop.operational.common.Drools",
+ "type_version": "1.0.0",
+ "version": "1.0.0",
+ "name": "operational.scale.up",
+ "metadata": {
+ "policy-id": "operational.scale.up"
+ },
+ "properties": {
+ "controllerName": "usecases",
+ "id": "ControlLoop-vDNS-6f37f56d-a87d-4b85-b6a9-cc953cf779b3",
+ "timeout": 60,
+ "abatement": false,
+ "trigger": "unique-policy-id-1-scale-up",
+ "operations": [
+ {
+ "id": "unique-policy-id-1-scale-up",
+ "description": "Scale up",
+ "operation": {
+ "actor": "SO",
+ "operation": "VF Module Create",
+ "target": {
+ "targetType": "VFMODULE",
+ "entityIds": {
+ "modelInvariantId": "e6130d03-56f1-4b0a-9a1d-e1b2ebc30e0e",
+ "modelVersionId": "94b18b1d-cc91-4f43-911a-e6348665f292",
+ "modelName": "VfwclVfwsnkBbefb8ce2bde..base_vfw..module-0",
+ "modelVersion": 1,
+ "modelCustomizationId": "47958575-138f-452a-8c8d-d89b595f8164"
+ }
+ },
+ "payload": {
+ "requestParameters": "{\"usePreload\":true,\"userParams\":[]}",
+ "configurationParameters": "[{\"ip-addr\":\"$.vf-module-topology.vf-module-parameters.param[9]\",\"oam-ip-addr\":\"$.vf-module-topology.vf-module-parameters.param[16]\",\"enabled\":\"$.vf-module-topology.vf-module-parameters.param[23]\"}]"
+ }
+ },
+ "timeout": 30,
+ "retries": 0,
+ "success": "final_success",
+ "failure": "final_failure",
+ "failure_timeout": "final_failure_timeout",
+ "failure_retries": "final_failure_retries",
+ "failure_exception": "final_failure_exception",
+ "failure_guard": "final_failure_guard"
+ }
+ ]
+ }
+}
diff --git a/controlloop/common/rules-test/src/main/resources/vdns/vdns.onset.json b/controlloop/common/rules-test/src/main/resources/vdns/vdns.onset.json
new file mode 100644
index 000000000..13f690952
--- /dev/null
+++ b/controlloop/common/rules-test/src/main/resources/vdns/vdns.onset.json
@@ -0,0 +1,16 @@
+{
+ "closedLoopControlName": "ControlLoop-vDNS-6f37f56d-a87d-4b85-b6a9-cc953cf779b3",
+ "closedLoopAlarmStart": 1463679805324,
+ "closedLoopEventClient": "microservice.stringmatcher",
+ "closedLoopEventStatus": "ONSET",
+ "requestID": "c7c6a4aa-bb61-4a15-b831-ba1472dd4a65",
+ "target_type": "VNF",
+ "target": "vserver.vserver-name",
+ "AAI": {
+ "vserver.is-closed-loop-disabled": "false",
+ "vserver.prov-status": "ACTIVE",
+ "vserver.vserver-name": "OzVServer"
+ },
+ "from": "DCAE",
+ "version": "1.0.2"
+}
diff --git a/controlloop/common/rules-test/src/main/resources/vfw/tosca-compliant-vfw.json b/controlloop/common/rules-test/src/main/resources/vfw/tosca-compliant-vfw.json
new file mode 100644
index 000000000..f55145658
--- /dev/null
+++ b/controlloop/common/rules-test/src/main/resources/vfw/tosca-compliant-vfw.json
@@ -0,0 +1,40 @@
+{
+ "type": "onap.policies.controlloop.operational.common.Drools",
+ "type_version": "1.0.0",
+ "name": "operational.modifyconfig",
+ "version": "1.0.0",
+ "metadata": {
+ "policy-id": "operational.modifyconfig"
+ },
+ "properties": {
+ "controllerName": "usecases",
+ "id": "ControlLoop-vFirewall-d0a1dfc6-94f5-4fd4-a5b5-4630b438850a",
+ "timeout": 60,
+ "abatement": false,
+ "trigger": "unique-policy-id-1-modifyConfig",
+ "operations": [
+ {
+ "id": "unique-policy-id-1-modifyConfig",
+ "description": "Modify the packet generator",
+ "operation": {
+ "actor": "APPC",
+ "operation": "ModifyConfig",
+ "target": {
+ "targetType": "VNF",
+ "entityIds": {
+ "resourceID": "bbb3cefd-01c8-413c-9bdd-2b92f9ca3d38"
+ }
+ }
+ },
+ "timeout": 300,
+ "retries": 0,
+ "success": "final_success",
+ "failure": "final_failure",
+ "failure_timeout": "final_failure_timeout",
+ "failure_retries": "final_failure_retries",
+ "failure_exception": "final_failure_exception",
+ "failure_guard": "final_failure_guard"
+ }
+ ]
+ }
+}
diff --git a/controlloop/common/rules-test/src/main/resources/vfw/tosca-vfw.json b/controlloop/common/rules-test/src/main/resources/vfw/tosca-vfw.json
new file mode 100644
index 000000000..35a839698
--- /dev/null
+++ b/controlloop/common/rules-test/src/main/resources/vfw/tosca-vfw.json
@@ -0,0 +1,9 @@
+{
+ "type": "onap.policies.controlloop.Operational",
+ "type_version": "1.0.0",
+ "properties": {
+ "content": "controlLoop%3A%0A%20%20version%3A%202.0.0%0A%20%20controlLoopName%3A%20ControlLoop-vFirewall-d0a1dfc6-94f5-4fd4-a5b5-4630b438850a%0A%20%20services%3A%0A%20%20%20%20-%20serviceInvariantUUID%3A%20f6937c86-584c-47ae-ad29-8d41d6f0cc7c%0A%20%20%20%20%20%20serviceUUID%3A%207be584e2-0bb2-4126-adaf-ced2c77ca0b3%0A%20%20%20%20%20%20serviceName%3A%20Service_Ete_Name7ba1fbde-6187-464a-a62d-d9dd25bdf4e8%0A%20%20trigger_policy%3A%20unique-policy-id-1-modifyConfig%0A%20%20timeout%3A%2060%0A%20%20abatement%3A%20false%0A%20%0Apolicies%3A%0A%20%20-%20id%3A%20unique-policy-id-1-modifyConfig%0A%20%20%20%20name%3A%20modify%20packet%20gen%20config%0A%20%20%20%20description%3A%0A%20%20%20%20actor%3A%20APPC%0A%20%20%20%20recipe%3A%20ModifyConfig%0A%20%20%20%20target%3A%0A%20%20%20%20%20%20resourceID%3A%20bbb3cefd-01c8-413c-9bdd-2b92f9ca3d38%0A%20%20%20%20%20%20type%3A%20VNF%0A%20%20%20%20retry%3A%200%0A%20%20%20%20timeout%3A%2030%0A%20%20%20%20success%3A%20final_success%0A%20%20%20%20failure%3A%20final_failure%0A%20%20%20%20failure_timeout%3A%20final_failure_timeout%0A%20%20%20%20failure_retries%3A%20final_failure_retries%0A%20%20%20%20failure_exception%3A%20final_failure_exception%0A%20%20%20%20failure_guard%3A%20final_failure_guard"
+ },
+ "name": "vfw",
+ "version": "1.0.0"
+}
diff --git a/controlloop/common/rules-test/src/main/resources/vfw/vfw.appc.success.json b/controlloop/common/rules-test/src/main/resources/vfw/vfw.appc.success.json
new file mode 100644
index 000000000..eb19c6832
--- /dev/null
+++ b/controlloop/common/rules-test/src/main/resources/vfw/vfw.appc.success.json
@@ -0,0 +1,17 @@
+{
+ "CommonHeader": {
+ "TimeStamp": 1506051879001,
+ "APIver": "1.01",
+ "RequestID": "c7c6a4aa-bb61-4a15-b831-ba1472dd4a65",
+ "SubRequestID": "${replaceMe}",
+ "RequestTrack": [],
+ "Flags": []
+ },
+ "Status": {
+ "Code": 400,
+ "Value": "SUCCESS"
+ },
+ "Payload": {
+ "generic-vnf.vnf-id": "jimmy-test-vnf2"
+ }
+}
diff --git a/controlloop/common/rules-test/src/main/resources/vfw/vfw.onset.json b/controlloop/common/rules-test/src/main/resources/vfw/vfw.onset.json
new file mode 100644
index 000000000..7782867a1
--- /dev/null
+++ b/controlloop/common/rules-test/src/main/resources/vfw/vfw.onset.json
@@ -0,0 +1,17 @@
+{
+ "closedLoopControlName": "ControlLoop-vFirewall-d0a1dfc6-94f5-4fd4-a5b5-4630b438850a",
+ "closedLoopAlarmStart": 1463679805324,
+ "closedLoopEventClient": "microservice.stringmatcher",
+ "closedLoopEventStatus": "ONSET",
+ "requestID": "c7c6a4aa-bb61-4a15-b831-ba1472dd4a65",
+ "target_type": "VNF",
+ "target": "generic-vnf.vnf-name",
+ "AAI": {
+ "vserver.is-closed-loop-disabled": "false",
+ "vserver.prov-status": "ACTIVE",
+ "generic-vnf.vnf-name": "fw0002vm002fw002",
+ "vserver.vserver-name": "OzVServer"
+ },
+ "from": "DCAE",
+ "version": "1.0.2"
+}
diff --git a/controlloop/common/rules-test/src/main/resources/vlb/tosca-compliant-vlb.json b/controlloop/common/rules-test/src/main/resources/vlb/tosca-compliant-vlb.json
new file mode 100644
index 000000000..8a3b64a0a
--- /dev/null
+++ b/controlloop/common/rules-test/src/main/resources/vlb/tosca-compliant-vlb.json
@@ -0,0 +1,48 @@
+{
+ "type": "onap.policies.controlloop.operational.common.Drools",
+ "type_version": "1.0.0",
+ "name": "operational.scaleout",
+ "version": "1.0.0",
+ "metadata": {
+ "policy-id": "operational.scaleout"
+ },
+ "properties": {
+ "controllerName": "usecases",
+ "id": "ControlLoop-vDNS-6f37f56d-a87d-4b85-b6a9-cc953cf779b3",
+ "timeout": 1200,
+ "abatement": false,
+ "trigger": "unique-policy-id-1-scale-up",
+ "operations": [
+ {
+ "id": "unique-policy-id-1-scale-up",
+ "description": "Create a new VF Module",
+ "operation": {
+ "actor": "SO",
+ "operation": "VF Module Create",
+ "target": {
+ "targetType": "VFMODULE",
+ "entityIds": {
+ "modelInvariantId": "e6130d03-56f1-4b0a-9a1d-e1b2ebc30e0e",
+ "modelVersionId": "94b18b1d-cc91-4f43-911a-e6348665f292",
+ "modelName": "VfwclVfwsnkBbefb8ce2bde..base_vfw..module-0",
+ "modelVersion": 1,
+ "modelCustomizationId": "47958575-138f-452a-8c8d-d89b595f8164"
+ }
+ },
+ "payload": {
+ "requestParameters": "{\"usePreload\":true,\"userParams\":[]}",
+ "configurationParameters": "[{\"ip-addr\":\"$.vf-module-topology.vf-module-parameters.param[9]\",\"oam-ip-addr\":\"$.vf-module-topology.vf-module-parameters.param[16]\",\"enabled\":\"$.vf-module-topology.vf-module-parameters.param[23]\"}]"
+ }
+ },
+ "timeout": 1200,
+ "retries": 0,
+ "success": "final_success",
+ "failure": "final_failure",
+ "failure_timeout": "final_failure_timeout",
+ "failure_retries": "final_failure_retries",
+ "failure_exception": "final_failure_exception",
+ "failure_guard": "final_failure_guard"
+ }
+ ]
+ }
+}
diff --git a/controlloop/common/rules-test/src/main/resources/vlb/tosca-vlb.json b/controlloop/common/rules-test/src/main/resources/vlb/tosca-vlb.json
new file mode 100644
index 000000000..c4f2b8179
--- /dev/null
+++ b/controlloop/common/rules-test/src/main/resources/vlb/tosca-vlb.json
@@ -0,0 +1,9 @@
+{
+ "type": "onap.policies.controlloop.Operational",
+ "type_version": "1.0.0",
+ "properties": {
+ "content": "controlLoop%3A%0A%20%20version%3A%202.0.0%0A%20%20controlLoopName%3A%20ControlLoop-vDNS-6f37f56d-a87d-4b85-b6a9-cc953cf779b3%0A%20%20services%3A%0A%20%20%20%20-%20serviceName%3A%20d4738992-6497-4dca-9db9%0A%20%20%20%20%20%20serviceInvariantUUID%3A%20dc112d6e-7e73-4777-9c6f-1a7fb5fd1b6f%0A%20%20%20%20%20%20serviceUUID%3A%202eea06c6-e1d3-4c3a-b9c4-478c506eeedf%0A%20%20trigger_policy%3A%20unique-policy-id-1-scale-up%0A%20%20timeout%3A%2060%0A%0Apolicies%3A%0A%20%20-%20id%3A%20unique-policy-id-1-scale-up%0A%20%20%20%20name%3A%20Create%20a%20new%20VF%20Module%0A%20%20%20%20description%3A%0A%20%20%20%20actor%3A%20SO%0A%20%20%20%20recipe%3A%20VF%20Module%20Create%0A%20%20%20%20target%3A%0A%20%20%20%20%20%20type%3A%20VFMODULE%0A%20%20%20%20%20%20modelInvariantId%3A%20e6130d03-56f1-4b0a-9a1d-e1b2ebc30e0e%0A%20%20%20%20%20%20modelVersionId%3A%2094b18b1d-cc91-4f43-911a-e6348665f292%0A%20%20%20%20%20%20modelName%3A%20VfwclVfwsnkBbefb8ce2bde..base_vfw..module-0%0A%20%20%20%20%20%20modelVersion%3A%201%0A%20%20%20%20%20%20modelCustomizationId%3A%2047958575-138f-452a-8c8d-d89b595f8164%0A%20%20%20%20payload%3A%0A%20%20%20%20%20%20requestParameters%3A%20%27%7B%22usePreload%22%3Atrue%2C%22userParams%22%3A%5B%5D%7D%27%0A%20%20%20%20%20%20configurationParameters%3A%20%27%5B%7B%22ip-addr%22%3A%22%24.vf-module-topology.vf-module-parameters.param%5B9%5D%22%2C%22oam-ip-addr%22%3A%22%24.vf-module-topology.vf-module-parameters.param%5B16%5D%22%2C%22enabled%22%3A%22%24.vf-module-topology.vf-module-parameters.param%5B23%5D%22%7D%5D%27%0A%20%20%20%20retry%3A%200%0A%20%20%20%20timeout%3A%2030%0A%20%20%20%20success%3A%20final_success%0A%20%20%20%20failure%3A%20final_failure%0A%20%20%20%20failure_timeout%3A%20final_failure_timeout%0A%20%20%20%20failure_retries%3A%20final_failure_retries%0A%20%20%20%20failure_exception%3A%20final_failure_exception%0A%20%20%20%20failure_guard%3A%20final_failure_guard%0A"
+ },
+ "name": "vlb",
+ "version": "1.0.0"
+}
diff --git a/controlloop/common/rules-test/src/main/resources/vlb/vlb.onset.json b/controlloop/common/rules-test/src/main/resources/vlb/vlb.onset.json
new file mode 100644
index 000000000..23ad03cbb
--- /dev/null
+++ b/controlloop/common/rules-test/src/main/resources/vlb/vlb.onset.json
@@ -0,0 +1,16 @@
+{
+ "closedLoopControlName": "ControlLoop-vDNS-6f37f56d-a87d-4b85-b6a9-cc953cf779b3",
+ "closedLoopAlarmStart": 1484677482204798,
+ "closedLoopEventClient": "DCAE_INSTANCE_ID.dcae-tca",
+ "closedLoopEventStatus": "ONSET",
+ "requestID": "e4f95e0c-a013-4530-8e59-c5c5f9e539b6",
+ "target_type": "VNF",
+ "target": "vserver.vserver-name",
+ "AAI": {
+ "vserver.is-closed-loop-disabled": "false",
+ "vserver.prov-status": "ACTIVE",
+ "vserver.vserver-name": "OzVServer"
+ },
+ "from": "DCAE",
+ "version": "1.0.2"
+}