Added vpci and vsonh tests 01/104301/22
authorpramod.jamkhedkar <pramod@research.att.com>
Tue, 24 Mar 2020 19:54:09 +0000 (15:54 -0400)
committerpramod.jamkhedkar <pramod@research.att.com>
Fri, 10 Apr 2020 17:40:25 +0000 (13:40 -0400)
Added test cases for vpci and vsonh usecases

Issue-ID: POLICY-2162
Change-Id: Ia69b16e74b82b92366b5065eeccab8d35f647742
Signed-off-by: pramod.jamkhedkar <pramod@research.att.com>
Signed-off-by: Jim Hahn <jrh3@att.com>
Signed-off-by: pramod.jamkhedkar <pramod@research.att.com>
12 files changed:
controlloop/common/controller-frankfurt/src/test/resources/config/frankfurt-controller.properties
controlloop/common/feature-controlloop-frankfurt/src/main/feature/config/frankfurt-controller.properties
controlloop/common/rules-test/src/main/java/org/onap/policy/controlloop/common/rules/test/BaseRuleTest.java
controlloop/common/rules-test/src/main/resources/vpci/tosca-compliant-vpci.json [new file with mode: 0644]
controlloop/common/rules-test/src/main/resources/vpci/tosca-vpci.json [new file with mode: 0644]
controlloop/common/rules-test/src/main/resources/vpci/vpci.onset.json [new file with mode: 0644]
controlloop/common/rules-test/src/main/resources/vpci/vpci.sdnr.success.json [new file with mode: 0644]
controlloop/common/rules-test/src/main/resources/vsonh/tosca-compliant-vsonh.json [new file with mode: 0644]
controlloop/common/rules-test/src/main/resources/vsonh/tosca-vsonh.json [new file with mode: 0644]
controlloop/common/rules-test/src/main/resources/vsonh/vsonh.onset.json [new file with mode: 0644]
controlloop/common/rules-test/src/main/resources/vsonh/vsonh.sdnr.success.json [new file with mode: 0644]
controlloop/common/rules-test/src/test/java/org/onap/policy/controlloop/common/rules/test/BaseRuleTestTest.java

index 2839e0d..af3d0eb 100644 (file)
@@ -58,8 +58,6 @@ noop.sink.topics=APPC-CL,APPC-LCM-READ,POLICY-CL-MGT,SDNR-CL,DCAE_CL_RSP
 noop.sink.topics.POLICY-CL-MGT.events=org.onap.policy.controlloop.VirtualControlLoopNotification
 noop.sink.topics.POLICY-CL-MGT.events.custom.gson=org.onap.policy.controlloop.util.Serialization,gsonPretty
 
-noop.sink.topics.SDNR-CL.events=org.onap.policy.sdnr.PciRequestWrapper
-noop.sink.topics.SDNR-CL.events.custom.gson=org.onap.policy.sdnr.util.Serialization,gson
-
 noop.sink.topics.DCAE_CL_RSP.events=org.onap.policy.controlloop.ControlLoopResponse
 noop.sink.topics.DCAE_CL_RSP.events.custom.gson=org.onap.policy.controlloop.util.Serialization,gsonPretty
+
index fb3661d..76ce48b 100644 (file)
@@ -52,9 +52,6 @@ dmaap.sink.topics.APPC-LCM-READ.events.custom.gson=org.onap.policy.appclcm.util.
 dmaap.sink.topics.POLICY-CL-MGT.events=org.onap.policy.controlloop.VirtualControlLoopNotification
 dmaap.sink.topics.POLICY-CL-MGT.events.custom.gson=org.onap.policy.controlloop.util.Serialization,gsonPretty
 
-dmaap.sink.topics.SDNR-CL.events=org.onap.policy.sdnr.PciRequestWrapper
-dmaap.sink.topics.SDNR-CL.events.custom.gson=org.onap.policy.sdnr.util.Serialization,gson
-
 dmaap.sink.topics.DCAE_CL_RSP.events=org.onap.policy.controlloop.ControlLoopResponse
 dmaap.sink.topics.DCAE_CL_RSP.events.custom.gson=org.onap.policy.controlloop.util.Serialization,gsonPretty
 
index 631b3f6..171a2ac 100644 (file)
@@ -41,6 +41,7 @@ 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;
+import org.onap.policy.sdnr.PciMessage;
 
 /**
  * Superclass used for rule tests.
@@ -57,6 +58,8 @@ public abstract class BaseRuleTest {
     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";
+    protected static final String SDNR_CL_TOPIC = "SDNR-CL";
+    protected static final String SDNR_CL_RSP_TOPIC = "SDNR-CL-RSP";
 
     /*
      * Constants for each test case.
@@ -96,12 +99,29 @@ public abstract class BaseRuleTest {
     private static final String VFW_APPC_SUCCESS = "vfw/vfw.appc.success.json";
     private static final String VFW_APPC_FAILURE = "vfw/vfw.appc.failure.json";
 
+    // VPCI
+    private static final String VPCI_TOSCA_POLICY = "vpci/tosca-vpci.json";
+    private static final String VPCI_TOSCA_COMPLIANT_POLICY = "vpci/tosca-compliant-vpci.json";
+    private static final String VPCI_ONSET = "vpci/vpci.onset.json";
+    private static final String VPCI_SDNR_SUCCESS = "vpci/vpci.sdnr.success.json";
+
+    // VSONH
+    private static final String VSONH_TOSCA_POLICY = "vsonh/tosca-vsonh.json";
+    private static final String VSONH_TOSCA_COMPLIANT_POLICY = "vsonh/tosca-compliant-vsonh.json";
+    private static final String VSONH_ONSET = "vsonh/vsonh.onset.json";
+    private static final String VSONH_SDNR_SUCCESS = "vsonh/vsonh.sdnr.success.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();
 
+    /*
+     * Coders used to decode requests and responses.
+     */
+    private static final Coder SDNR_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;
@@ -120,6 +140,7 @@ public abstract class BaseRuleTest {
     protected Listener<VirtualControlLoopNotification> policyClMgt;
     protected Listener<Request> appcClSink;
     protected Listener<AppcLcmDmaapWrapper> appcLcmRead;
+    protected Listener<PciMessage> sdnrClSink;
 
     protected PolicyController controller;
 
@@ -357,6 +378,40 @@ public abstract class BaseRuleTest {
         appcLegacyRainyDayNoResponse(VFW_TOSCA_COMPLIANT_POLICY, VFW_ONSET, APPC_MODIFY_CONFIG_OP);
     }
 
+    /**
+     * VPCI Sunny Day with Legacy Tosca Policy.
+     */
+    @Test
+    public void testVpciSunnyDayLegacy() {
+        sdnrSunnyDay(VPCI_TOSCA_POLICY, VPCI_ONSET, VPCI_SDNR_SUCCESS, "ModifyConfig");
+    }
+
+    /**
+     * VPCI Sunny Day Tosca Policy.
+     */
+    @Test
+    public void testVpciSunnyDayCompliant() {
+        sdnrSunnyDay(VPCI_TOSCA_COMPLIANT_POLICY, VPCI_ONSET, VPCI_SDNR_SUCCESS, "ModifyConfig");
+    }
+
+    // VSONH
+
+    /**
+     * VSONH Sunny Day with Legacy Tosca Policy.
+     */
+    @Test
+    public void testVsonhSunnyDayLegacy() {
+        sdnrSunnyDay(VSONH_TOSCA_POLICY, VSONH_ONSET, VSONH_SDNR_SUCCESS, "ModifyConfigANR");
+    }
+
+    /**
+     * VSONH Sunny Day with Tosca Policy.
+     */
+    @Test
+    public void testVsonhSunnyDayCompliant() {
+        sdnrSunnyDay(VSONH_TOSCA_COMPLIANT_POLICY, VSONH_ONSET, VSONH_SDNR_SUCCESS, "ModifyConfigANR");
+    }
+
     /**
      * Sunny day scenario for use cases that use APPC-LCM.
      *
@@ -526,6 +581,46 @@ public abstract class BaseRuleTest {
         waitForFinalFailure(policy, policyClMgt);
     }
 
+    /**
+     * Sunny day scenario for use cases that use SDNR.
+     *
+     * @param policyFile file containing the ToscaPolicy to be loaded
+     * @param onsetFile file containing the ONSET to be injected
+     * @param operation expected SDNR operation request
+     */
+    protected void sdnrSunnyDay(String policyFile, String onsetFile, String successFile, String operation) {
+        policyClMgt = topics.createListener(POLICY_CL_MGT_TOPIC,
+            VirtualControlLoopNotification.class, controller);
+        sdnrClSink = topics.createListener(SDNR_CL_TOPIC, PciMessage.class, SDNR_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 SDNR RESTART request was sent in response to the matching ONSET
+         */
+        PciMessage pcireq = sdnrClSink.await(req -> operation.equals(req.getBody().getInput().getAction()));
+
+        /*
+         * Inject response.
+         */
+        topics.inject(SDNR_CL_RSP_TOPIC, successFile, pcireq.getBody().getInput().getCommonHeader().getSubRequestId());
+
+        /* --- Operation Completed --- */
+
+        waitForOperationSuccess();
+
+        /* --- Transaction Completed --- */
+        waitForFinalSuccess(policy, policyClMgt);
+    }
+
     /**
      * Sunny day scenario for use cases that use an HTTP simulator.
      *
diff --git a/controlloop/common/rules-test/src/main/resources/vpci/tosca-compliant-vpci.json b/controlloop/common/rules-test/src/main/resources/vpci/tosca-compliant-vpci.json
new file mode 100644 (file)
index 0000000..692b4e7
--- /dev/null
@@ -0,0 +1,37 @@
+{
+    "type": "onap.policies.controlloop.operational.common.Drools",
+    "type_version": "1.0.0",
+    "name": "operational.modifyconfig",
+    "version": "1.0.0",
+    "metadata": {
+        "policy-id": "operational.pcihandler"
+    },
+    "properties": {
+        "controllerName": "usecases",
+        "id": "ControlLoop-vPCI-fb41f388-a5f2-11e8-98d0-529269fb1459",
+        "timeout": 1200,
+        "abatement": false,
+        "trigger": "unique-policy-id-123-modifyconfig",
+        "operations": [
+            {
+                "id": "unique-policy-id-123-modifyconfig",
+                "description": "Modify the packet generator",
+                "operation": {
+                    "actor": "SDNR",
+                    "operation": "ModifyConfig",
+                    "target": {
+                        "targetType": "PNF"
+                    }
+                },
+                "timeout": 7,
+                "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/vpci/tosca-vpci.json b/controlloop/common/rules-test/src/main/resources/vpci/tosca-vpci.json
new file mode 100644 (file)
index 0000000..84b047e
--- /dev/null
@@ -0,0 +1,11 @@
+{
+    "type": "onap.policies.controlloop.Operational",
+    "type_version": "1.0.0",
+    "properties": {
+        "policy-id": "operational.pcihandler",
+        "content": "controlLoop%3A%0A%20%20version%3A%203.0.0%0A%20%20controlLoopName%3A%20ControlLoop-vPCI-fb41f388-a5f2-11e8-98d0-529269fb1459%0A%20%20trigger_policy%3A%20unique-policy-id-123-modifyconfig%0A%20%20timeout%3A%201200%0A%20%20abatement%3A%20false%0A%20%0Apolicies%3A%0A%20%20-%20id%3A%20unique-policy-id-123-modifyconfig%0A%20%20%20%20name%3A%20modify%20PCI%20config%0A%20%20%20%20description%3A%0A%20%20%20%20actor%3A%20SDNR%0A%20%20%20%20recipe%3A%20ModifyConfig%0A%20%20%20%20target%3A%0A%20%20%20%20%20%20%23%20These%20fields%20are%20not%20used%0A%20%20%20%20%20%20resourceID%3A%20Eace933104d443b496b8.nodes.heat.vpg%0A%20%20%20%20%20%20type%3A%20PNF%0A%20%20%20%20retry%3A%200%0A%20%20%20%20timeout%3A%207000%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": "vpci",
+    "version": "1.0.0"
+
+}
diff --git a/controlloop/common/rules-test/src/main/resources/vpci/vpci.onset.json b/controlloop/common/rules-test/src/main/resources/vpci/vpci.onset.json
new file mode 100644 (file)
index 0000000..880c3cc
--- /dev/null
@@ -0,0 +1,18 @@
+{
+    "closedLoopControlName": "ControlLoop-vPCI-fb41f388-a5f2-11e8-98d0-529269fb1459",
+    "closedLoopAlarmStart": 1510187409180,
+    "closedLoopEventClient": "microservice.PCI",
+    "closedLoopEventStatus": "ONSET",
+    "requestID": "9d2d790e-a5f0-11e8-98d0-529269fb1459",
+    "target_type": "PNF",
+    "target": "pnf.pnf-name",
+    "AAI": {
+        "generic-vnf.is-closed-loop-disabled": "false",
+        "generic-vnf.prov-status": "ACTIVE",
+        "pnf.pnf-name": "OzPServer"
+    },
+    "from": "PCIMS",
+    "version": "1.0.2",
+    "Action": "ModifyConfig",
+    "payload": "{\"Configurations\":[{\"data\":{\"FAPService\":{\"alias\":\"Chn0330\",\"X0005b9Lte\":{\"phyCellIdInUse\":6,\"pnfName\":\"ncserver23\"},\"CellConfig\":{\"LTE\":{\"RAN\":{\"Common\":{\"CellIdentity\":\"Chn0330\"}}}}}}},{\"data\":{\"FAPService\":{\"alias\":\"Chn0331\",\"X0005b9Lte\":{\"phyCellIdInUse\":7,\"pnfName\":\"ncserver23\"},\"CellConfig\":{\"LTE\":{\"RAN\":{\"Common\":{\"CellIdentity\":\"Chn0331\"}}}}}}}]}"
+}
diff --git a/controlloop/common/rules-test/src/main/resources/vpci/vpci.sdnr.success.json b/controlloop/common/rules-test/src/main/resources/vpci/vpci.sdnr.success.json
new file mode 100644 (file)
index 0000000..b9137d2
--- /dev/null
@@ -0,0 +1,23 @@
+{
+    "body": {
+        "output": {
+            "CommonHeader": {
+                "TimeStamp": "2018-09-10T07:10:05.614Z",
+                "APIver": "1.0",
+                "RequestID": "9d2d790e-a5f0-11e8-98d0-529269fb1459",
+                "SubRequestID": "${replaceMe}",
+                "RequestTrack": [],
+                "Flags": []
+            },
+            "Status": {
+                "Code": 200,
+                "Value": "SUCCESS"
+            },
+            "Payload": "{ \"Configurations\":[ { \"Status\": { \"Code\": 200, \"Value\": \"SUCCESS\" }, \"data\":{\"FAPService\":{\"alias\":\"Chn0330\",\"X0005b9Lte\":{\"phyCellIdInUse\":6,\"pnfName\":\"ncserver23\"},\"CellConfig\":{\"LTE\":{\"RAN\":{\"Common\":{\"CellIdentity\":\"Chn0330\"}}}}}} } ] }"
+        }
+    },
+    "version": "1.0",
+    "rpc-name": "ModifyConfig",
+    "correlation-id": "9d2d790e-a5f0-11e8-98d0-529269fb1459-1",
+    "type": "response"
+}
diff --git a/controlloop/common/rules-test/src/main/resources/vsonh/tosca-compliant-vsonh.json b/controlloop/common/rules-test/src/main/resources/vsonh/tosca-compliant-vsonh.json
new file mode 100644 (file)
index 0000000..e01dceb
--- /dev/null
@@ -0,0 +1,37 @@
+{
+    "type": "onap.policies.controlloop.operational.common.Drools",
+    "type_version": "1.0.0",
+    "name": "operational.modifyconfig",
+    "version": "1.0.0",
+    "metadata": {
+        "policy-id": "operational.sonhandler"
+    },
+    "properties": {
+        "controllerName": "usecases",
+        "id": "ControlLoop-vSONH-7d4baf04-8875-4d1f-946d-06b874048b61",
+        "timeout": 1200,
+        "abatement": false,
+        "trigger": "unique-policy-id-123-modifyconfig",
+        "operations": [
+            {
+                "id": "unique-policy-id-123-modifyconfig",
+                "description": "Modify the packet generator",
+                "operation": {
+                    "actor": "SDNR",
+                    "operation": "ModifyConfigANR",
+                    "target": {
+                        "targetType": "PNF"
+                    }
+                },
+                "timeout": 7,
+                "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/vsonh/tosca-vsonh.json b/controlloop/common/rules-test/src/main/resources/vsonh/tosca-vsonh.json
new file mode 100644 (file)
index 0000000..4927bee
--- /dev/null
@@ -0,0 +1,10 @@
+{
+    "type": "onap.policies.controlloop.Operational",
+    "type_version": "1.0.0",
+    "properties": {
+        "policy-id": "operational.sonhandler",
+        "content": "controlLoop%3A%0A%20%20version%3A%204.0.0%0A%20%20controlLoopName%3A%20ControlLoop-vSONH-7d4baf04-8875-4d1f-946d-06b874048b61%0A%20%20trigger_policy%3A%20unique-policy-id-456-modifyconfig%0A%20%20timeout%3A%201200%0A%20%20abatement%3A%20false%0A%20%0Apolicies%3A%0A%20%20-%20id%3A%20unique-policy-id-456-modifyconfig%0A%20%20%20%20name%3A%20modify%20ANR%20config%0A%20%20%20%20description%3A%0A%20%20%20%20actor%3A%20SDNR%0A%20%20%20%20recipe%3A%20ModifyConfigANR%0A%20%20%20%20target%3A%0A%20%20%20%20%20%20%23%20These%20fields%20are%20not%20used%0A%20%20%20%20%20%20resourceID%3A%20Eace933104d443b496b8.nodes.heat.vpg%0A%20%20%20%20%20%20type%3A%20PNF%0A%20%20%20%20retry%3A%200%0A%20%20%20%20timeout%3A%20300%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": "sonh",
+    "version": "1.0.0"
+}
diff --git a/controlloop/common/rules-test/src/main/resources/vsonh/vsonh.onset.json b/controlloop/common/rules-test/src/main/resources/vsonh/vsonh.onset.json
new file mode 100644 (file)
index 0000000..4337477
--- /dev/null
@@ -0,0 +1,18 @@
+{
+    "closedLoopControlName": "ControlLoop-vSONH-7d4baf04-8875-4d1f-946d-06b874048b61",
+    "closedLoopAlarmStart": 1510187409180,
+    "closedLoopEventClient": "microservice.SONH",
+    "closedLoopEventStatus": "ONSET",
+    "requestID": "722ee65a-8afd-48df-bf57-c152ae45bacc",
+    "target_type": "PNF",
+    "target": "pnf.pnf-name",
+    "AAI": {
+        "generic-vnf.is-closed-loop-disabled": "false",
+        "generic-vnf.prov-status": "ACTIVE",
+        "pnf.pnf-name": "OzPServer"
+    },
+    "from": "SONHMS",
+    "version": "1.0.2",
+    "Action": "ModifyConfigANR",
+    "payload": "{ \"Configurations\":[ { \"data\":{ \"FAPService\":{ \"alias\":\"Cell1\", \"CellConfig\":{ \"LTE\":{ \"RAN\":{ \"Common\":{ \"CellIdentity\":\"1\" }, \"NeighborListInUse\" : { \"LTECellNumberOfEntries\" : \"1\" , \"LTECell\" : [{ \"PLMNID\" :\"plmnid1\", \"CID\":\"Chn0001\", \"PhyCellID\":\"3\", \"PNFName\":\"ncserver01\", \"Blacklisted\":\"false\"}] } } } } } } } ] }"
+}
diff --git a/controlloop/common/rules-test/src/main/resources/vsonh/vsonh.sdnr.success.json b/controlloop/common/rules-test/src/main/resources/vsonh/vsonh.sdnr.success.json
new file mode 100644 (file)
index 0000000..98211c7
--- /dev/null
@@ -0,0 +1,23 @@
+{
+    "body": {
+        "output": {
+            "CommonHeader": {
+                "TimeStamp": "2018-09-10T07:10:05.614Z",
+                "APIver": "1.0",
+                "RequestID": "722ee65a-8afd-48df-bf57-c152ae45bacc",
+                "SubRequestID": "${replaceMe}",
+                "RequestTrack": [],
+                "Flags": []
+            },
+            "Status": {
+                "Code": 200,
+                "Value": "SUCCESS"
+            },
+            "Payload": "{ \"Configurations\":[ { \"Status\": { \"Code\": 200, \"Value\": \"SUCCESS\" }, \"data\":{ \"FAPService\":{ \"alias\":\"Cell1\", \"CellConfig\":{ \"LTE\":{ \"RAN\":{ \"Common\":{ \"CellIdentity\":\"1\" }, \"NeighborListInUse\" : { \"LTECellNumberOfEntries\" : \"1\" , \"LTECell\" : [{ \"PLMNID\" :\"plmnid1\", \"CID\":\"Chn0001\", \"PhyCellID\":\"3\", \"PNFName\":\"ncserver01\", \"Blacklisted\":\"false\"}] } } } } } } } ] }"
+        }
+    },
+    "version": "1.0",
+    "rpc-name": "ModifyConfigANR",
+    "correlation-id": "722ee65a-8afd-48df-bf57-c152ae45bacc-1",
+    "type": "response"
+}
index ed3d627..0753aac 100644 (file)
@@ -56,6 +56,10 @@ import org.onap.policy.drools.controller.DroolsController;
 import org.onap.policy.drools.system.PolicyController;
 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyIdentifier;
+import org.onap.policy.sdnr.PciBody;
+import org.onap.policy.sdnr.PciCommonHeader;
+import org.onap.policy.sdnr.PciMessage;
+import org.onap.policy.sdnr.PciRequest;
 import org.powermock.reflect.Whitebox;
 
 public class BaseRuleTestTest {
@@ -72,6 +76,7 @@ public class BaseRuleTestTest {
     private LinkedList<VirtualControlLoopNotification> clMgtQueue;
     private Queue<AppcLcmDmaapWrapper> appcLcmQueue;
     private Queue<Request> appcLegacyQueue;
+    private Queue<PciMessage> sdnrQueue;
     private int permitCount;
     private int finalCount;
 
@@ -92,6 +97,8 @@ public class BaseRuleTestTest {
     @Mock
     private Listener<AppcLcmDmaapWrapper> appcLcmRead;
     @Mock
+    private Listener<PciMessage> sdnrClSink;
+    @Mock
     private DroolsController drools;
     @Mock
     private ToscaPolicy policy;
@@ -147,6 +154,8 @@ public class BaseRuleTestTest {
                         any(StandardCoder.class))).thenReturn(appcLcmRead);
         when(topics.createListener(eq(BaseRuleTest.APPC_CL_TOPIC), eq(Request.class),
                         any(StandardCoderInstantAsMillis.class))).thenReturn(appcClSink);
+        when(topics.createListener(eq(BaseRuleTest.SDNR_CL_TOPIC), eq(PciMessage.class),
+            any(StandardCoder.class))).thenReturn(sdnrClSink);
 
         Function<String, Rules> ruleMaker = this::makeRules;
         Supplier<HttpClients> httpClientMaker = this::makeHttpClients;
@@ -161,6 +170,7 @@ public class BaseRuleTestTest {
         clMgtQueue = new LinkedList<>();
         appcLcmQueue = new LinkedList<>();
         appcLegacyQueue = new LinkedList<>();
+        sdnrQueue = new LinkedList<>();
 
         when(policyClMgt.await(any())).thenAnswer(args -> {
             VirtualControlLoopNotification notif = clMgtQueue.remove();
@@ -183,6 +193,13 @@ public class BaseRuleTestTest {
             return req;
         });
 
+        when(sdnrClSink.await(any())).thenAnswer(args -> {
+            PciMessage pcireq = sdnrQueue.remove();
+            Predicate<PciMessage> pred = args.getArgument(0);
+            assertTrue(pred.test(pcireq));
+            return pcireq;
+        });
+
         permitCount = 0;
         finalCount = 0;
 
@@ -335,6 +352,26 @@ public class BaseRuleTestTest {
         checkAppcLegacyPolicyFinalFailure("ModifyConfig", base::testVfwRainyDayCompliantTimeout);
     }
 
+    @Test
+    public void testTestVpciSunnyDayLegacy() {
+        checkSdnrPolicy("ModifyConfig", base::testVpciSunnyDayLegacy);
+    }
+
+    @Test
+    public void testTestVpciSunnyDayCompliant() {
+        checkSdnrPolicy("ModifyConfig", base::testVpciSunnyDayCompliant);
+    }
+
+    @Test
+    public void testTestVsonhSunnyDayLegacy() {
+        checkSdnrPolicy("ModifyConfigANR", base::testVsonhSunnyDayLegacy);
+    }
+
+    @Test
+    public void testTestVsonhSunnyDayCompliant() {
+        checkSdnrPolicy("ModifyConfigANR", base::testVsonhSunnyDayCompliant);
+    }
+
     protected void checkAppcLcmPolicy(String operation, Runnable test) {
         enqueueAppcLcm(operation);
         enqueueClMgt(ControlLoopNotificationType.OPERATION_SUCCESS);
@@ -413,6 +450,26 @@ public class BaseRuleTestTest {
         // There were no requests sent
     }
 
+    protected void checkSdnrPolicy(String operation, Runnable test) {
+        enqueueSdnr(operation);
+        enqueueClMgt(ControlLoopNotificationType.OPERATION_SUCCESS);
+        enqueueClMgt(ControlLoopNotificationType.FINAL_SUCCESS);
+
+        test.run();
+
+        assertEquals(1, permitCount);
+        assertEquals(1, finalCount);
+
+        assertTrue(sdnrQueue.isEmpty());
+        assertTrue(clMgtQueue.isEmpty());
+
+        // initial event
+        verify(topics).inject(eq(BaseRuleTest.DCAE_TOPIC), any());
+
+        // reply to each SDNR request
+        verify(topics).inject(eq(BaseRuleTest.SDNR_CL_RSP_TOPIC), any(), any());
+    }
+
     protected void checkHttpPolicy(Runnable test) {
         enqueueClMgt(ControlLoopNotificationType.OPERATION_SUCCESS);
         enqueueClMgt(ControlLoopNotificationType.FINAL_SUCCESS);
@@ -470,6 +527,23 @@ public class BaseRuleTestTest {
         }
     }
 
+    private void enqueueSdnr(String... operationNames) {
+        for (String oper : operationNames) {
+            PciMessage pcimessage = new PciMessage();
+            PciRequest req = new PciRequest();
+            PciBody body = new PciBody();
+            body.setInput(req);
+            pcimessage.setBody(body);
+            pcimessage.getBody().getInput().setAction(oper);
+            PciCommonHeader header = new PciCommonHeader();
+            pcimessage.getBody().getInput().setCommonHeader(header);
+
+            header.setSubRequestId("my-subrequest-id");
+
+            sdnrQueue.add(pcimessage);
+        }
+    }
+
     private Rules makeRules(String controllerName) {
         return rules;
     }