From 633e52e39cc6ff05f6a72603de36109bfdfa636d Mon Sep 17 00:00:00 2001 From: Jim Hahn Date: Tue, 22 Oct 2019 18:05:42 -0400 Subject: Add PolicyTrackerData for generating notifications Change-Id: Ife3ab77c0664101bbf32def5fb4d1a5ac194f459 Issue-ID: POLICY-1841 Signed-off-by: Jim Hahn --- .../pap/main/notification/PolicyTrackerData.java | 180 ++++++++++++++++ .../main/notification/PolicyTrackerDataTest.java | 239 +++++++++++++++++++++ 2 files changed, 419 insertions(+) create mode 100644 main/src/main/java/org/onap/policy/pap/main/notification/PolicyTrackerData.java create mode 100644 main/src/test/java/org/onap/policy/pap/main/notification/PolicyTrackerDataTest.java (limited to 'main') 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 new file mode 100644 index 00000000..530e1079 --- /dev/null +++ b/main/src/main/java/org/onap/policy/pap/main/notification/PolicyTrackerData.java @@ -0,0 +1,180 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP PAP + * ================================================================================ + * Copyright (C) 2019 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.pap.main.notification; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; +import lombok.Getter; +import org.onap.policy.models.pap.concepts.PolicyStatus; +import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyTypeIdentifier; + +/** + * Data associated with a policy, used by PolicyTracker. PDPs start in + * {@link #incompletePdps} and are moved to either {@link #successPdps} or + * {@link #failPdps}, depending on their response. Objects of this type are not + * multi-thread safe. + */ +public class PolicyTrackerData { + /** + * The policy type associated with the policy. + */ + @Getter + private final ToscaPolicyTypeIdentifier policyType; + + /** + * PDPs that have successfully completed an update of the policy. + */ + private final Set successPdps = new HashSet<>(); + + /** + * PDPs that have failed to complete an update of the policy. + */ + private final Set failPdps = new HashSet<>(); + + /** + * PDPs for which we're still awaiting a response. + */ + private final Set incompletePdps = new HashSet<>(); + + + /** + * Constructs the object. + * + * @param policyType policy type + */ + public PolicyTrackerData(ToscaPolicyTypeIdentifier policyType) { + this.policyType = policyType; + } + + /** + * Determines if this is complete (i.e., it is not waiting for responses from any + * other PDPs). + * + * @return {@code true} if this is complete, {@code false} otherwise + */ + public boolean isComplete() { + return 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 + */ + public boolean isEmpty() { + return (successPdps.isEmpty() && failPdps.isEmpty() && incompletePdps.isEmpty()); + } + + /** + * Puts the values from this data into the given status object. + * + * @param status object whose values are to be set + */ + public void putValuesInto(PolicyStatus status) { + status.setFailureCount(failPdps.size()); + status.setIncompleteCount(incompletePdps.size()); + status.setSuccessCount(successPdps.size()); + } + + /** + * Adds PDPs to {@link #incompletePdps}, removing them from any other sets in which + * they appear. + * + * @param pdps PDPs to be added + */ + public void addPdps(Collection pdps) { + successPdps.removeAll(pdps); + failPdps.removeAll(pdps); + + incompletePdps.addAll(pdps); + } + + /** + * Removes PDPs from the sets. + * + * @param pdps PDPs to be removed + * @return {@code true} if the policy is now complete, {@code false} otherwise + */ + public boolean removePdps(Collection pdps) { + successPdps.removeAll(pdps); + failPdps.removeAll(pdps); + + return (incompletePdps.removeAll(pdps) && 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 + */ + public boolean removePdp(String pdp) { + successPdps.remove(pdp); + failPdps.remove(pdp); + + return (incompletePdps.remove(pdp) && incompletePdps.isEmpty()); + } + + /** + * Indicates that a PDP has successfully processed this policy. + * + * @param pdp the PDP of interest + * @return {@code true} if the policy is now complete, {@code false} otherwise + */ + public boolean success(String pdp) { + return complete(pdp, successPdps, failPdps); + } + + /** + * Indicates that a PDP has processed this policy, but was unsuccessful. + * + * @param pdp the PDP of interest + * @return {@code true} if the policy is now complete, {@code false} otherwise + */ + public boolean fail(String pdp) { + return complete(pdp, failPdps, successPdps); + } + + /** + * Indicates that a PDP has processed this policy, either successfully or + * unsuccessfully. + * + * @param pdp the PDP of interest + * @param addSet set to which the PDP should be added + * @param removeSet set from which the PDP should be removed + * @return {@code true} if the policy is now complete, {@code false} otherwise + */ + private boolean complete(String pdp, Set addSet, Set removeSet) { + if (incompletePdps.remove(pdp) || removeSet.remove(pdp)) { + // successfully removed from one of the sets + addSet.add(pdp); + return incompletePdps.isEmpty(); + } + + /* + * Else: wasn't in either set, thus it's already in the "addSet" or it isn't + * relevant to this policy. Either way, just discard it without triggering any new + * notification. + */ + return false; + } +} 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 new file mode 100644 index 00000000..a727e057 --- /dev/null +++ b/main/src/test/java/org/onap/policy/pap/main/notification/PolicyTrackerDataTest.java @@ -0,0 +1,239 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP PAP + * ================================================================================ + * Copyright (C) 2019 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.pap.main.notification; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import org.junit.Before; +import org.junit.Test; +import org.onap.policy.models.pap.concepts.PolicyStatus; +import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyTypeIdentifier; + +public class PolicyTrackerDataTest { + + private static final ToscaPolicyTypeIdentifier TYPE = new ToscaPolicyTypeIdentifier("my-type", "1.2.3"); + private static final String PDP1 = "pdp-1"; + private static final String PDP2 = "pdp-2"; + private static final String PDP3 = "pdp-3"; + private static final String PDP4 = "pdp-4"; + private static final String PDP5 = "pdp-5"; + private static final String PDP6 = "pdp-6"; + + private Collection fullSet; + private PolicyTrackerData data; + + @Before + public void setUp() { + fullSet = Arrays.asList(PDP1, PDP2, PDP3, PDP4, PDP5, PDP6); + data = new PolicyTrackerData(TYPE); + } + + @Test + public void testPolicyTrackerData_testGetPolicyType() { + assertSame(TYPE, data.getPolicyType()); + } + + @Test + public void testIsComplete() { + assertTrue(data.isComplete()); + + data.addPdps(Arrays.asList(PDP1, PDP2)); + assertFalse(data.isComplete()); + + data.success(PDP1); + assertFalse(data.isComplete()); + + data.fail(PDP2); + assertTrue(data.isComplete()); + } + + @Test + public void testIsEmpty() { + assertTrue(data.isEmpty()); + + data.addPdps(Arrays.asList(PDP1, PDP2)); + assertFalse(data.isEmpty()); + + data.success(PDP1); + assertFalse(data.isEmpty()); + + data.fail(PDP2); + assertFalse(data.isEmpty()); + + data.removePdp(PDP1); + assertFalse(data.isEmpty()); + + data.removePdp(PDP2); + assertTrue(data.isEmpty()); + } + + @Test + public void testPutValuesInto() { + data.addPdps(fullSet); + data.success(PDP1); + data.fail(PDP2); + data.fail(PDP3); + + PolicyStatus status = new PolicyStatus(); + data.putValuesInto(status); + + assertEquals(1, status.getSuccessCount()); + assertEquals(2, status.getFailureCount()); + assertEquals(3, status.getIncompleteCount()); + } + + @Test + public void testAddPdps_testSuccess_testFail() { + data.addPdps(Arrays.asList(PDP1, PDP2, PDP3, PDP4)); + assertEquals("[0, 0, 4]", getCounts().toString()); + + data.success(PDP1); + assertEquals("[1, 0, 3]", getCounts().toString()); + + data.success(PDP2); + assertEquals("[2, 0, 2]", getCounts().toString()); + + // repeat + data.success(PDP2); + assertEquals("[2, 0, 2]", getCounts().toString()); + + data.fail(PDP3); + assertEquals("[2, 1, 1]", getCounts().toString()); + + // repeat + data.fail(PDP3); + assertEquals("[2, 1, 1]", getCounts().toString()); + + data.addPdps(Arrays.asList(PDP2, PDP3, PDP4, PDP5)); + + // PDP1 is still success + assertEquals("[1, 0, 4]", getCounts().toString()); + } + + @Test + public void testRemovePdps() { + data.addPdps(Arrays.asList(PDP1, PDP2, PDP3, PDP4, PDP5, PDP6)); + data.success(PDP1); + data.success(PDP2); + data.fail(PDP3); + data.fail(PDP4); + assertFalse(data.removePdps(Arrays.asList(PDP1, PDP3, PDP5))); + assertEquals("[1, 1, 1]", getCounts().toString()); + } + + /** + * Tests removePdps(), where nothing is removed from the "incomplete" set. + */ + @Test + public void testRemovePdpsNoIncompleteRemove() { + assertFalse(data.removePdps(Arrays.asList(PDP1, PDP2))); + assertEquals("[0, 0, 0]", getCounts().toString()); + } + + /** + * Tests removePdps(), where remaining incomplete items are removed. + */ + @Test + public void testRemovePdpsAllComplete() { + data.addPdps(Arrays.asList(PDP1)); + assertTrue(data.removePdps(Arrays.asList(PDP1))); + + data.addPdps(Arrays.asList(PDP1, PDP2, PDP3)); + assertFalse(data.removePdps(Arrays.asList(PDP1))); + assertTrue(data.removePdps(Arrays.asList(PDP2, PDP3))); + } + + @Test + public void testRemovePdp() { + data.addPdps(Arrays.asList(PDP1, PDP2, PDP3, PDP4, PDP5, PDP6)); + data.success(PDP1); + data.success(PDP2); + data.fail(PDP3); + data.fail(PDP4); + + assertFalse(data.removePdp(PDP1)); + assertEquals("[1, 2, 2]", getCounts().toString()); + + assertFalse(data.removePdp(PDP2)); + assertEquals("[0, 2, 2]", getCounts().toString()); + + assertFalse(data.removePdp(PDP3)); + assertEquals("[0, 1, 2]", getCounts().toString()); + + assertFalse(data.removePdp(PDP4)); + assertEquals("[0, 0, 2]", getCounts().toString()); + + assertFalse(data.removePdp(PDP5)); + assertEquals("[0, 0, 1]", getCounts().toString()); + + assertTrue(data.removePdp(PDP6)); + assertEquals("[0, 0, 0]", getCounts().toString()); + } + + /** + * Tests removePdps(), where nothing is removed from the "incomplete" set. + */ + @Test + public void testRemovePdpNoIncompleteRemove() { + assertFalse(data.removePdp(PDP1)); + assertEquals("[0, 0, 0]", getCounts().toString()); + } + + /** + * Tests removePdps(), where remaining incomplete items are removed. + */ + @Test + public void testRemovePdpAllComplete() { + data.addPdps(Arrays.asList(PDP1, PDP2)); + assertFalse(data.removePdp(PDP1)); + + assertTrue(data.removePdp(PDP2)); + } + + @Test + public void testComplete() { + // attempt to remove a PDP that isn't in the data + assertFalse(data.success(PDP1)); + + // remove one that was incomplete + data.addPdps(Arrays.asList(PDP1)); + assertTrue(data.success(PDP1)); + + // move from one set to the other + assertTrue(data.fail(PDP1)); + + // already in the correct set + assertFalse(data.fail(PDP1)); + } + + private List getCounts() { + PolicyStatus status = new PolicyStatus(); + data.putValuesInto(status); + + return Arrays.asList(status.getSuccessCount(), status.getFailureCount(), status.getIncompleteCount()); + } +} -- cgit 1.2.3-korg