Merge "Adding Tosca compliant operational policy type to defaultGroup for apex-pdp"
diff --git a/main/src/main/java/org/onap/policy/pap/main/comm/msgdata/UpdateReq.java b/main/src/main/java/org/onap/policy/pap/main/comm/msgdata/UpdateReq.java
index 69a4e3a..753735d 100644
--- a/main/src/main/java/org/onap/policy/pap/main/comm/msgdata/UpdateReq.java
+++ b/main/src/main/java/org/onap/policy/pap/main/comm/msgdata/UpdateReq.java
@@ -2,7 +2,7 @@
  * ============LICENSE_START=======================================================
  * ONAP PAP
  * ================================================================================
- * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2019-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.
@@ -77,7 +77,7 @@
         }
 
         Set<ToscaPolicyIdentifier> actualSet = new HashSet<>(alwaysList(response.getPolicies()));
-        getNotifier().processResponse(getName(), actualSet);
+        getNotifier().processResponse(response.getName(), actualSet);
 
         PdpUpdate message = getMessage();
 
diff --git a/main/src/main/java/org/onap/policy/pap/main/notification/PolicyTrackerData.java b/main/src/main/java/org/onap/policy/pap/main/notification/PolicyTrackerData.java
index 530e107..29e7b14 100644
--- a/main/src/main/java/org/onap/policy/pap/main/notification/PolicyTrackerData.java
+++ b/main/src/main/java/org/onap/policy/pap/main/notification/PolicyTrackerData.java
@@ -2,7 +2,7 @@
  * ============LICENSE_START=======================================================
  * ONAP PAP
  * ================================================================================
- * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2019-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.
@@ -76,6 +76,16 @@
     }
 
     /**
+     * Determines if everything has succeeded.
+     *
+     * @return {@code true} if this is complete <i>and</i> nothing has failed,
+     *         {@code false} otherwise
+     */
+    public boolean allSucceeded() {
+        return (failPdps.isEmpty() && incompletePdps.isEmpty());
+    }
+
+    /**
      * Determines if all of the sets within the data are empty (i.e., contain no PDPs).
      *
      * @return {@code true} if the data is completely empty, {@code false} otherwise
@@ -112,26 +122,28 @@
      * Removes PDPs from the sets.
      *
      * @param pdps PDPs to be removed
-     * @return {@code true} if the policy is now complete, {@code false} otherwise
+     * @return {@code true} if anything changed and the policy is now complete, {@code false} otherwise
      */
     public boolean removePdps(Collection<String> pdps) {
-        successPdps.removeAll(pdps);
-        failPdps.removeAll(pdps);
+        boolean changed = successPdps.removeAll(pdps);
+        changed = failPdps.removeAll(pdps) || changed;
+        changed = incompletePdps.removeAll(pdps) || changed;
 
-        return (incompletePdps.removeAll(pdps) && incompletePdps.isEmpty());
+        return (changed && incompletePdps.isEmpty());
     }
 
     /**
      * Removes a PDP from all sets.
      *
      * @param pdp PDP to be removed
-     * @return {@code true} if the policy is now complete, {@code false} otherwise
+     * @return {@code true} if anything changed and the policy is now complete, {@code false} otherwise
      */
     public boolean removePdp(String pdp) {
-        successPdps.remove(pdp);
-        failPdps.remove(pdp);
+        boolean changed = successPdps.remove(pdp);
+        changed = failPdps.remove(pdp) || changed;
+        changed = incompletePdps.remove(pdp) || changed;
 
-        return (incompletePdps.remove(pdp) && incompletePdps.isEmpty());
+        return (changed && incompletePdps.isEmpty());
     }
 
     /**
diff --git a/main/src/main/java/org/onap/policy/pap/main/notification/PolicyUndeployTracker.java b/main/src/main/java/org/onap/policy/pap/main/notification/PolicyUndeployTracker.java
index 964ff44..af2f0b6 100644
--- a/main/src/main/java/org/onap/policy/pap/main/notification/PolicyUndeployTracker.java
+++ b/main/src/main/java/org/onap/policy/pap/main/notification/PolicyUndeployTracker.java
@@ -2,7 +2,7 @@
  * ============LICENSE_START=======================================================
  * ONAP PAP
  * ================================================================================
- * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2019-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.
@@ -43,11 +43,10 @@
     }
 
     /**
-     * Returns {@code true} only when the data is "complete" (i.e., not awaiting responses
-     * from any other PDPs).
+     * Returns {@code true} only when the data is all successful.
      */
     @Override
     protected boolean shouldRemove(PolicyTrackerData data) {
-        return data.isComplete();
+        return data.allSucceeded();
     }
 }
diff --git a/main/src/test/java/org/onap/policy/pap/main/notification/PolicyDeployTrackerTest.java b/main/src/test/java/org/onap/policy/pap/main/notification/PolicyDeployTrackerTest.java
index 832fddc..742d87d 100644
--- a/main/src/test/java/org/onap/policy/pap/main/notification/PolicyDeployTrackerTest.java
+++ b/main/src/test/java/org/onap/policy/pap/main/notification/PolicyDeployTrackerTest.java
@@ -2,7 +2,7 @@
  * ============LICENSE_START=======================================================
  * ONAP PAP
  * ================================================================================
- * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2019-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.
@@ -58,12 +58,12 @@
         tracker = new PolicyDeployTracker();
     }
 
+    /**
+     * Simple test with one PDP that immediately responds with success.
+     */
     @Test
-    public void test() {
-        tracker.addData(makeData(policy1, PDP1, PDP2));
-
-        // indicate that PDP2 has succeeded
-        tracker.processResponse(PDP2, Arrays.asList(policy1), new ArrayList<>(0));
+    public void testSimpleImmediateSuccess() {
+        tracker.addData(makeData(policy1, PDP1));
 
         // indicate that PDP1 has succeeded
         List<PolicyStatus> statusList = new ArrayList<>();
@@ -72,15 +72,143 @@
         assertEquals(1, statusList.size());
         assertEquals(policy1, statusList.get(0).getPolicy());
         assertEquals(type, statusList.get(0).getPolicyType());
+        assertEquals("[1, 0, 0]", getCounts(statusList.get(0)).toString());
+
+        // indicate that PDP1 has succeeded again - should be no output
+        statusList.clear();
+        tracker.processResponse(PDP1, Arrays.asList(policy1), statusList);
+        assertEquals(0, statusList.size());
+
+        // indicate failure
+        statusList.clear();
+        tracker.processResponse(PDP1, Arrays.asList(), statusList);
+        assertEquals(1, statusList.size());
+        assertEquals("[0, 1, 0]", getCounts(statusList.get(0)).toString());
+
+        // indicate that PDP1 has failed again - should be no output
+        statusList.clear();
+        tracker.processResponse(PDP1, Arrays.asList(), statusList);
+        assertEquals(0, statusList.size());
+
+        // indicate that PDP1 has succeeded again
+        statusList.clear();
+        tracker.processResponse(PDP1, Arrays.asList(policy1), statusList);
+        assertEquals("[1, 0, 0]", getCounts(statusList.get(0)).toString());
+    }
+
+    /**
+     * Simple test with one PDP that immediately responds with success.
+     */
+    @Test
+    public void testSimpleImmediateFail() {
+        tracker.addData(makeData(policy1, PDP1));
+
+        // indicate that PDP1 has failed
+        List<PolicyStatus> statusList = new ArrayList<>();
+        tracker.processResponse(PDP1, Arrays.asList(), statusList);
+        assertEquals(1, statusList.size());
+        assertEquals("[0, 1, 0]", getCounts(statusList.get(0)).toString());
+
+        // indicate that PDP1 has failed again - should be no output
+        statusList.clear();
+        tracker.processResponse(PDP1, Arrays.asList(), statusList);
+        assertEquals(0, statusList.size());
+
+        // indicate success
+        tracker.processResponse(PDP1, Arrays.asList(policy1), statusList);
+
+        assertEquals(1, statusList.size());
+        assertEquals(policy1, statusList.get(0).getPolicy());
+        assertEquals(type, statusList.get(0).getPolicyType());
+        assertEquals("[1, 0, 0]", getCounts(statusList.get(0)).toString());
+
+        // indicate that PDP1 has succeeded again - should be no output
+        statusList.clear();
+        tracker.processResponse(PDP1, Arrays.asList(policy1), statusList);
+        assertEquals(0, statusList.size());
+    }
+
+    /**
+     * Simple test where PDP is removed and then it responds.
+     */
+    @Test
+    public void testSimpleRemove() {
+        tracker.addData(makeData(policy1, PDP1));
+
+        // remove the PDP
+        List<PolicyStatus> statusList = new ArrayList<>();
+        tracker.removePdp(PDP1, statusList);
+        assertEquals(1, statusList.size());
+        assertEquals(policy1, statusList.get(0).getPolicy());
+        assertEquals(type, statusList.get(0).getPolicyType());
+        assertEquals("[0, 0, 0]", getCounts(statusList.get(0)).toString());
+
+        /*
+         * indicate that PDP1 has succeeded - should be no message since PDP was removed
+         * from the policy
+         */
+        statusList.clear();
+        tracker.processResponse(PDP1, Arrays.asList(policy1), statusList);
+        assertEquals(0, statusList.size());
+
+        /*
+         * indicate that PDP1 has failed - should be no message since PDP was removed
+         * from the policy
+         */
+        statusList.clear();
+        tracker.processResponse(PDP1, Arrays.asList(), statusList);
+        assertEquals(0, statusList.size());
+    }
+
+    /**
+     * Test with multiple PDPs.
+     */
+    @Test
+    public void testMulti() {
+        tracker.addData(makeData(policy1, PDP1, PDP2));
+
+        // indicate that PDP2 has succeeded
+        List<PolicyStatus> statusList = new ArrayList<>();
+        tracker.processResponse(PDP2, Arrays.asList(policy1), statusList);
+        assertEquals(0, statusList.size());
+
+        // indicate that PDP1 has succeeded
+        statusList.clear();
+        tracker.processResponse(PDP1, Arrays.asList(policy1), statusList);
+
+        assertEquals(1, statusList.size());
+        assertEquals(policy1, statusList.get(0).getPolicy());
+        assertEquals(type, statusList.get(0).getPolicyType());
         assertEquals("[2, 0, 0]", getCounts(statusList.get(0)).toString());
 
-        // indicate that PDP1 has failed - should get a notification, if still in the map
+        // indicate that PDP1 has failed - should get a notification
         statusList.clear();
         tracker.processResponse(PDP1, Collections.emptyList(), statusList);
         assertEquals(1, statusList.size());
         assertEquals(policy1, statusList.get(0).getPolicy());
         assertEquals(type, statusList.get(0).getPolicyType());
         assertEquals("[1, 1, 0]", getCounts(statusList.get(0)).toString());
+
+        // indicate that PDP1 has succeeded
+        statusList.clear();
+        tracker.processResponse(PDP1, Arrays.asList(policy1), statusList);
+        assertEquals(1, statusList.size());
+        assertEquals("[2, 0, 0]", getCounts(statusList.get(0)).toString());
+
+        // remove PDP2 - expect message
+        statusList.clear();
+        tracker.removePdp(PDP2, statusList);
+        assertEquals(1, statusList.size());
+        assertEquals("[1, 0, 0]", getCounts(statusList.get(0)).toString());
+
+        // re-add PDP2
+        tracker.addData(makeData(policy1, PDP2));
+
+        // indicate that PDP2 has succeeded; PDP1 should still be ok
+        statusList.clear();
+        tracker.processResponse(PDP2, Arrays.asList(policy1), statusList);
+        assertEquals(1, statusList.size());
+        assertEquals("[2, 0, 0]", getCounts(statusList.get(0)).toString());
     }
 
     @Test
diff --git a/main/src/test/java/org/onap/policy/pap/main/notification/PolicyTrackerDataTest.java b/main/src/test/java/org/onap/policy/pap/main/notification/PolicyTrackerDataTest.java
index a727e05..ff79780 100644
--- a/main/src/test/java/org/onap/policy/pap/main/notification/PolicyTrackerDataTest.java
+++ b/main/src/test/java/org/onap/policy/pap/main/notification/PolicyTrackerDataTest.java
@@ -2,7 +2,7 @@
  * ============LICENSE_START=======================================================
  * ONAP PAP
  * ================================================================================
- * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2019-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.
@@ -72,6 +72,29 @@
     }
 
     @Test
+    public void testAllSucceeded() {
+        assertTrue(data.allSucceeded());
+
+        data.addPdps(Arrays.asList(PDP1, PDP2));
+        assertFalse(data.allSucceeded());
+
+        data.success(PDP1);
+        assertFalse(data.allSucceeded());
+
+        data.fail(PDP2);
+        assertFalse(data.allSucceeded());
+
+        data.success(PDP2);
+        assertTrue(data.allSucceeded());
+
+        data.fail(PDP2);
+        assertFalse(data.allSucceeded());
+
+        data.success(PDP2);
+        assertTrue(data.allSucceeded());
+    }
+
+    @Test
     public void testIsEmpty() {
         assertTrue(data.isEmpty());
 
@@ -143,6 +166,9 @@
         data.fail(PDP4);
         assertFalse(data.removePdps(Arrays.asList(PDP1, PDP3, PDP5)));
         assertEquals("[1, 1, 1]", getCounts().toString());
+
+        assertTrue(data.removePdps(Arrays.asList(PDP6)));
+        assertEquals("[1, 1, 0]", getCounts().toString());
     }
 
     /**
@@ -167,6 +193,48 @@
         assertTrue(data.removePdps(Arrays.asList(PDP2, PDP3)));
     }
 
+    /**
+     * Tests removePdps() with more variations.
+     */
+    @Test
+    public void testRemovePdpsVariations() {
+        data.addPdps(Arrays.asList(PDP1, PDP2, PDP3));
+        data.success(PDP1);
+        data.fail(PDP2);
+        assertEquals("[1, 1, 1]", getCounts().toString());
+
+        // remove PDP1, which checks removal from "success" set, while incomplete
+        assertFalse(data.removePdps(Arrays.asList(PDP1)));
+        assertEquals("[0, 1, 1]", getCounts().toString());
+
+        // remove PDP2, which checks removal from "failure" set, while incomplete
+        assertFalse(data.removePdps(Arrays.asList(PDP2)));
+        assertEquals("[0, 0, 1]", getCounts().toString());
+
+        // re-add 1 & 2
+        data.addPdps(Arrays.asList(PDP1, PDP2));
+        data.success(PDP1);
+        data.fail(PDP2);
+        assertEquals("[1, 1, 1]", getCounts().toString());
+
+        // remove PDP3, which checks removal from "incomplete" set
+        assertTrue(data.removePdps(Arrays.asList(PDP3)));
+        assertEquals("[1, 1, 0]", getCounts().toString());
+
+        // remove PDP1, which checks removal from "success" set, while complete
+        assertTrue(data.removePdps(Arrays.asList(PDP1)));
+        assertEquals("[0, 1, 0]", getCounts().toString());
+
+        // remove PDP2, which checks removal from "failure" set, while complete
+        assertTrue(data.removePdps(Arrays.asList(PDP2)));
+        assertEquals("[0, 0, 0]", getCounts().toString());
+
+        // re-add 1 and then remove it again
+        data.addPdps(Arrays.asList(PDP1));
+        assertTrue(data.removePdps(Arrays.asList(PDP1)));
+        assertEquals("[0, 0, 0]", getCounts().toString());
+    }
+
     @Test
     public void testRemovePdp() {
         data.addPdps(Arrays.asList(PDP1, PDP2, PDP3, PDP4, PDP5, PDP6));
@@ -214,6 +282,48 @@
         assertTrue(data.removePdp(PDP2));
     }
 
+    /**
+     * Tests removePdp() with more variations.
+     */
+    @Test
+    public void testRemovePdpVariations() {
+        data.addPdps(Arrays.asList(PDP1, PDP2, PDP3));
+        data.success(PDP1);
+        data.fail(PDP2);
+        assertEquals("[1, 1, 1]", getCounts().toString());
+
+        // remove PDP1, which checks removal from "success" set, while incomplete
+        assertFalse(data.removePdp(PDP1));
+        assertEquals("[0, 1, 1]", getCounts().toString());
+
+        // remove PDP2, which checks removal from "failure" set, while incomplete
+        assertFalse(data.removePdp(PDP2));
+        assertEquals("[0, 0, 1]", getCounts().toString());
+
+        // re-add 1 & 2
+        data.addPdps(Arrays.asList(PDP1, PDP2));
+        data.success(PDP1);
+        data.fail(PDP2);
+        assertEquals("[1, 1, 1]", getCounts().toString());
+
+        // remove PDP3, which checks removal from "incomplete" set
+        assertTrue(data.removePdp(PDP3));
+        assertEquals("[1, 1, 0]", getCounts().toString());
+
+        // remove PDP1, which checks removal from "success" set, while complete
+        assertTrue(data.removePdp(PDP1));
+        assertEquals("[0, 1, 0]", getCounts().toString());
+
+        // remove PDP2, which checks removal from "failure" set, while complete
+        assertTrue(data.removePdp(PDP2));
+        assertEquals("[0, 0, 0]", getCounts().toString());
+
+        // re-add 1 and then remove it again
+        data.addPdps(Arrays.asList(PDP1));
+        assertTrue(data.removePdp(PDP1));
+        assertEquals("[0, 0, 0]", getCounts().toString());
+    }
+
     @Test
     public void testComplete() {
         // attempt to remove a PDP that isn't in the data
diff --git a/main/src/test/java/org/onap/policy/pap/main/notification/PolicyUndeployTrackerTest.java b/main/src/test/java/org/onap/policy/pap/main/notification/PolicyUndeployTrackerTest.java
index ba85c48..7d3f54f 100644
--- a/main/src/test/java/org/onap/policy/pap/main/notification/PolicyUndeployTrackerTest.java
+++ b/main/src/test/java/org/onap/policy/pap/main/notification/PolicyUndeployTrackerTest.java
@@ -2,7 +2,7 @@
  * ============LICENSE_START=======================================================
  * ONAP PAP
  * ================================================================================
- * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2019-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.
@@ -58,8 +58,117 @@
         tracker = new PolicyUndeployTracker();
     }
 
+    /**
+     * Simple test with one PDP that immediately responds with success.
+     */
     @Test
-    public void test() {
+    public void testSimpleImmediateSuccess() {
+        tracker.addData(makeData(policy1, PDP1));
+
+        // indicate that PDP1 has succeeded (i.e., undeployed)
+        List<PolicyStatus> statusList = new ArrayList<>();
+        tracker.processResponse(PDP1, Arrays.asList(), statusList);
+
+        assertEquals(1, statusList.size());
+        assertEquals(policy1, statusList.get(0).getPolicy());
+        assertEquals(type, statusList.get(0).getPolicyType());
+        assertEquals("[1, 0, 0]", getCounts(statusList.get(0)).toString());
+
+        // indicate that PDP1 has succeeded again - should be no output
+        statusList.clear();
+        tracker.processResponse(PDP1, Arrays.asList(), statusList);
+        assertEquals(0, statusList.size());
+
+        // indicate failure (i.e., still deployed) - no output, because no longer tracked
+        statusList.clear();
+        tracker.processResponse(PDP1, Arrays.asList(policy1), statusList);
+        assertEquals(0, statusList.size());
+
+        // indicate that PDP1 has failed again - still no output
+        statusList.clear();
+        tracker.processResponse(PDP1, Arrays.asList(policy1), statusList);
+        assertEquals(0, statusList.size());
+
+        // indicate that PDP1 has succeeded again - still no output
+        statusList.clear();
+        tracker.processResponse(PDP1, Arrays.asList(), statusList);
+        assertEquals(0, statusList.size());
+    }
+
+    /**
+     * Simple test with one PDP that immediately responds with success.
+     */
+    @Test
+    public void testSimpleImmediateFail() {
+        tracker.addData(makeData(policy1, PDP1));
+
+        // indicate that PDP1 has failed (i.e., still deployed)
+        List<PolicyStatus> statusList = new ArrayList<>();
+        tracker.processResponse(PDP1, Arrays.asList(policy1), statusList);
+        assertEquals(1, statusList.size());
+        assertEquals("[0, 1, 0]", getCounts(statusList.get(0)).toString());
+
+        // indicate that PDP1 has failed again - should be no output
+        statusList.clear();
+        tracker.processResponse(PDP1, Arrays.asList(policy1), statusList);
+        assertEquals(0, statusList.size());
+
+        // indicate success (i.e., undeployed)
+        tracker.processResponse(PDP1, Arrays.asList(), statusList);
+
+        assertEquals(1, statusList.size());
+        assertEquals(policy1, statusList.get(0).getPolicy());
+        assertEquals(type, statusList.get(0).getPolicyType());
+        assertEquals("[1, 0, 0]", getCounts(statusList.get(0)).toString());
+
+        // indicate that PDP1 has succeeded again - should be no output
+        statusList.clear();
+        tracker.processResponse(PDP1, Arrays.asList(), statusList);
+        assertEquals(0, statusList.size());
+
+        // indicate that PDP1 has failed again - still no output
+        statusList.clear();
+        tracker.processResponse(PDP1, Arrays.asList(policy1), statusList);
+        assertEquals(0, statusList.size());
+    }
+
+    /**
+     * Simple test where PDP is removed and then it responds.
+     */
+    @Test
+    public void testSimpleRemove() {
+        tracker.addData(makeData(policy1, PDP1));
+
+        // remove the PDP
+        List<PolicyStatus> statusList = new ArrayList<>();
+        tracker.removePdp(PDP1, statusList);
+        assertEquals(1, statusList.size());
+        assertEquals(policy1, statusList.get(0).getPolicy());
+        assertEquals(type, statusList.get(0).getPolicyType());
+        assertEquals("[0, 0, 0]", getCounts(statusList.get(0)).toString());
+
+        /*
+         * indicate that PDP1 has succeeded (i.e., undeployed) - should be no message
+         * since PDP was removed from the policy
+         */
+        statusList.clear();
+        tracker.processResponse(PDP1, Arrays.asList(), statusList);
+        assertEquals(0, statusList.size());
+
+        /*
+         * indicate that PDP1 has failed (i.e., still deployed) - should be no message
+         * since PDP was removed from the policy
+         */
+        statusList.clear();
+        tracker.processResponse(PDP1, Arrays.asList(policy1), statusList);
+        assertEquals(0, statusList.size());
+    }
+
+    /**
+     * Test with multiple PDPs.
+     */
+    @Test
+    public void testMulti() {
         tracker.addData(makeData(policy1, PDP1, PDP2));
 
         // indicate that PDP2 has been undeployed
@@ -74,14 +183,50 @@
         assertEquals(type, statusList.get(0).getPolicyType());
         assertEquals("[2, 0, 0]", getCounts(statusList.get(0)).toString());
 
-        // indicate that PDP1 has been re-deployed - should not get a notification,
-        // because policy
-        // is gone
+        /*
+         * indicate that PDP1 has been re-deployed - should not get a notification,
+         * because policy is gone
+         */
         statusList.clear();
         tracker.processResponse(PDP1, Arrays.asList(policy1), statusList);
         assertTrue(statusList.isEmpty());
     }
 
+    /**
+     * Test with multiple PDPs, and one is removed while it is in a failure state.
+     */
+    @Test
+    public void testMultiRemove() {
+        tracker.addData(makeData(policy1, PDP1, PDP2));
+
+        // indicate that PDP2 has been undeployed
+        tracker.processResponse(PDP2, Collections.emptyList(), new ArrayList<>(0));
+
+        // indicate that PDP1 has failed (i.e., still deployed)
+        List<PolicyStatus> statusList = new ArrayList<>();
+        tracker.processResponse(PDP1, Arrays.asList(policy1), statusList);
+
+        assertEquals(1, statusList.size());
+        assertEquals(policy1, statusList.get(0).getPolicy());
+        assertEquals(type, statusList.get(0).getPolicyType());
+        assertEquals("[1, 1, 0]", getCounts(statusList.get(0)).toString());
+
+        // remove PDP1 - expect message AND policy should be removed
+        statusList.clear();
+        tracker.removePdp(PDP1, statusList);
+        assertEquals(1, statusList.size());
+        assertEquals("[1, 0, 0]", getCounts(statusList.get(0)).toString());
+
+        // re-add PDP1
+        tracker.addData(makeData(policy1, PDP1));
+
+        // indicate that PDP1 has succeeded; policy is now new, so doesn't include PDP2
+        statusList.clear();
+        tracker.processResponse(PDP1, Arrays.asList(), statusList);
+        assertEquals(1, statusList.size());
+        assertEquals("[1, 0, 0]", getCounts(statusList.get(0)).toString());
+    }
+
     @Test
     public void testUpdateData() {
         // when success returns false
@@ -112,8 +257,8 @@
         // when data is not complete
         assertFalse(tracker.shouldRemove(data));
 
-        // when data is complete
-        when(data.isComplete()).thenReturn(true);
+        // when data has succeeded
+        when(data.allSucceeded()).thenReturn(true);
         assertTrue(tracker.shouldRemove(data));
     }
 }
diff --git a/main/src/test/java/org/onap/policy/pap/main/rest/e2e/PdpGroupDeleteTest.java b/main/src/test/java/org/onap/policy/pap/main/rest/e2e/PdpGroupDeleteTest.java
index 68e7028..d9fc66a 100644
--- a/main/src/test/java/org/onap/policy/pap/main/rest/e2e/PdpGroupDeleteTest.java
+++ b/main/src/test/java/org/onap/policy/pap/main/rest/e2e/PdpGroupDeleteTest.java
@@ -2,7 +2,7 @@
  * ============LICENSE_START=======================================================
  * ONAP PAP
  * ================================================================================
- * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2019-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.
@@ -21,16 +21,27 @@
 package org.onap.policy.pap.main.rest.e2e;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 
 import java.util.Collections;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
 import javax.ws.rs.client.Invocation;
 import javax.ws.rs.core.Response;
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
+import org.onap.policy.common.endpoints.event.comm.bus.NoopTopicFactories;
+import org.onap.policy.common.endpoints.event.comm.bus.NoopTopicSink;
+import org.onap.policy.common.utils.coder.StandardCoder;
 import org.onap.policy.models.pap.concepts.PdpGroupDeleteResponse;
+import org.onap.policy.models.pap.concepts.PolicyNotification;
+import org.onap.policy.models.pap.concepts.PolicyStatus;
 import org.onap.policy.models.pdp.concepts.PdpStatus;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyIdentifier;
+import org.onap.policy.pap.main.PapConstants;
 
 public class PdpGroupDeleteTest extends End2EndBase {
     private static final String DELETE_GROUP_ENDPOINT = "pdps/groups";
@@ -112,6 +123,13 @@
 
         context.startThreads();
 
+        // arrange to catch notifications
+        LinkedBlockingQueue<String> notifications = new LinkedBlockingQueue<>();
+        NoopTopicSink notifier = NoopTopicFactories.getSinkFactory().get(PapConstants.TOPIC_POLICY_NOTIFICATION);
+        notifier.register((infra, topic, msg) -> {
+            notifications.add(msg);
+        });
+
         String uri = DELETE_POLICIES_ENDPOINT + "/onap.restart.tcaB";
 
         Invocation.Builder invocationBuilder = sendRequest(uri);
@@ -122,6 +140,20 @@
 
         context.await();
 
+        // wait for the notification
+        String json = notifications.poll(5, TimeUnit.SECONDS);
+        PolicyNotification notify = new StandardCoder().decode(json, PolicyNotification.class);
+        assertNotNull(notify.getAdded());
+        assertNotNull(notify.getDeleted());
+        assertTrue(notify.getAdded().isEmpty());
+        assertEquals(1, notify.getDeleted().size());
+
+        PolicyStatus deleted = notify.getDeleted().get(0);
+        assertEquals(2, deleted.getSuccessCount());
+        assertEquals(0, deleted.getFailureCount());
+        assertEquals(0, deleted.getIncompleteCount());
+        assertEquals(new ToscaPolicyIdentifier("onap.restart.tcaB", "1.0.0"), deleted.getPolicy());
+
         rawresp = invocationBuilder.delete();
         resp = rawresp.readEntity(PdpGroupDeleteResponse.class);
         assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), rawresp.getStatus());
diff --git a/main/src/test/java/org/onap/policy/pap/main/rest/e2e/PdpGroupDeployTest.java b/main/src/test/java/org/onap/policy/pap/main/rest/e2e/PdpGroupDeployTest.java
index 1f04970..549ae20 100644
--- a/main/src/test/java/org/onap/policy/pap/main/rest/e2e/PdpGroupDeployTest.java
+++ b/main/src/test/java/org/onap/policy/pap/main/rest/e2e/PdpGroupDeployTest.java
@@ -2,7 +2,7 @@
  * ============LICENSE_START=======================================================
  * ONAP PAP
  * ================================================================================
- * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2019-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.
@@ -21,35 +21,38 @@
 package org.onap.policy.pap.main.rest.e2e;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
 import java.util.Arrays;
 import java.util.List;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
 import javax.ws.rs.client.Entity;
 import javax.ws.rs.client.Invocation;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
-import org.junit.After;
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
+import org.onap.policy.common.endpoints.event.comm.bus.NoopTopicFactories;
+import org.onap.policy.common.endpoints.event.comm.bus.NoopTopicSink;
+import org.onap.policy.common.utils.coder.StandardCoder;
 import org.onap.policy.models.pap.concepts.PdpDeployPolicies;
 import org.onap.policy.models.pap.concepts.PdpGroupDeployResponse;
+import org.onap.policy.models.pap.concepts.PolicyNotification;
+import org.onap.policy.models.pap.concepts.PolicyStatus;
 import org.onap.policy.models.pdp.concepts.DeploymentGroup;
 import org.onap.policy.models.pdp.concepts.DeploymentGroups;
 import org.onap.policy.models.pdp.concepts.PdpStatus;
 import org.onap.policy.models.pdp.enums.PdpState;
 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyIdentifier;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.onap.policy.pap.main.PapConstants;
 
 public class PdpGroupDeployTest extends End2EndBase {
-    private static final Logger logger = LoggerFactory.getLogger(PdpGroupDeployTest.class);
-
     private static final String DEPLOY_GROUP_ENDPOINT = "pdps/deployments/batch";
     private static final String DEPLOY_POLICIES_ENDPOINT = "pdps/policies";
-    private static final String DELETE_GROUP_ENDPOINT = "pdps/groups";
     private static final String DEPLOY_SUBGROUP = "pdpTypeA";
 
     /**
@@ -75,21 +78,6 @@
         context = new End2EndContext();
     }
 
-    /**
-     * Deletes the deployed group.
-     */
-    @After
-    public void tearDown() {
-        // delete the group that was inserted
-        try {
-            sendRequest(DELETE_GROUP_ENDPOINT + "/deployGroups").delete();
-        } catch (Exception e) {
-            logger.warn("cannot delete group: deployGroups", e);
-        }
-
-        super.tearDown();
-    }
-
     @Test
     public void testUpdateGroupPolicies() throws Exception {
 
@@ -98,7 +86,7 @@
         PdpStatus status11 = new PdpStatus();
         status11.setName("pdpAA_1");
         status11.setState(PdpState.ACTIVE);
-        status11.setPdpGroup("deployPolicies");
+        status11.setPdpGroup("deployGroups");
         status11.setPdpType(DEPLOY_SUBGROUP);
         status11.setPdpSubgroup(DEPLOY_SUBGROUP);
 
@@ -108,7 +96,7 @@
         PdpStatus status12 = new PdpStatus();
         status12.setName("pdpAA_2");
         status12.setState(PdpState.ACTIVE);
-        status12.setPdpGroup("deployPolicies");
+        status12.setPdpGroup("deployGroups");
         status12.setPdpType(DEPLOY_SUBGROUP);
         status12.setPdpSubgroup(DEPLOY_SUBGROUP);
         status12.setPolicies(idents);
@@ -159,7 +147,9 @@
         status11.setPdpType(DEPLOY_SUBGROUP);
         status11.setPdpSubgroup(DEPLOY_SUBGROUP);
 
-        List<ToscaPolicyIdentifier> idents = Arrays.asList(new ToscaPolicyIdentifier("onap.restart.tca", "1.0.0"));
+        final ToscaPolicyIdentifier ident = new ToscaPolicyIdentifier("onap.restart.tcaB", "1.0.0");
+
+        List<ToscaPolicyIdentifier> idents = Arrays.asList(ident);
         status11.setPolicies(idents);
 
         PdpStatus status12 = new PdpStatus();
@@ -176,9 +166,16 @@
 
         context.startThreads();
 
+        // arrange to catch notifications
+        LinkedBlockingQueue<String> notifications = new LinkedBlockingQueue<>();
+        NoopTopicSink notifier = NoopTopicFactories.getSinkFactory().get(PapConstants.TOPIC_POLICY_NOTIFICATION);
+        notifier.register((infra, topic, msg) -> {
+            notifications.add(msg);
+        });
+
         Invocation.Builder invocationBuilder = sendRequest(DEPLOY_POLICIES_ENDPOINT);
 
-        PdpDeployPolicies policies = loadJsonFile("deployPoliciesReq.json", PdpDeployPolicies.class);
+        PdpDeployPolicies policies = loadJsonFile("deployPoliciesReq2.json", PdpDeployPolicies.class);
         Entity<PdpDeployPolicies> entity = Entity.entity(policies, MediaType.APPLICATION_JSON);
         Response rawresp = invocationBuilder.post(entity);
         PdpGroupDeployResponse resp = rawresp.readEntity(PdpGroupDeployResponse.class);
@@ -188,6 +185,20 @@
 
         context.await();
 
+        // wait for the notification
+        String json = notifications.poll(5, TimeUnit.SECONDS);
+        PolicyNotification notify = new StandardCoder().decode(json, PolicyNotification.class);
+        assertNotNull(notify.getAdded());
+        assertNotNull(notify.getDeleted());
+        assertTrue(notify.getDeleted().isEmpty());
+        assertEquals(1, notify.getAdded().size());
+
+        PolicyStatus added = notify.getAdded().get(0);
+        assertEquals(2, added.getSuccessCount());
+        assertEquals(0, added.getFailureCount());
+        assertEquals(0, added.getIncompleteCount());
+        assertEquals(ident, added.getPolicy());
+
         // one of the PDPs should not have handled any requests
         assertEquals(1, context.getPdps().stream().filter(pdp -> pdp.getHandled().isEmpty()).count());
 
diff --git a/main/src/test/resources/e2e/deployPolicies.json b/main/src/test/resources/e2e/deployPolicies.json
index 90363ee..d9cdfe8 100644
--- a/main/src/test/resources/e2e/deployPolicies.json
+++ b/main/src/test/resources/e2e/deployPolicies.json
@@ -1,7 +1,7 @@
 {
     "groups": [
         {
-            "name": "deployGroups",
+            "name": "deployPolicies",
             "pdpGroupState": "ACTIVE",
             "pdpSubgroups": [
                 {
@@ -45,7 +45,7 @@
                     ],
                     "policies": [
                         {
-                            "name": "onap.restart.tca",
+                            "name": "onap.restart.tcaB",
                             "version": "1.0.0"
                         }
                     ]
diff --git a/main/src/test/resources/e2e/deployPoliciesReq2.json b/main/src/test/resources/e2e/deployPoliciesReq2.json
new file mode 100644
index 0000000..cd6ed4f
--- /dev/null
+++ b/main/src/test/resources/e2e/deployPoliciesReq2.json
@@ -0,0 +1,7 @@
+{
+    "policies": [
+        {
+            "policy-id": "onap.restart.tcaB"
+        }
+    ]
+}
\ No newline at end of file