From 8d554587553ab5bd5dff66db81fb45f82f46278c Mon Sep 17 00:00:00 2001 From: Jim Hahn Date: Fri, 5 Apr 2019 17:02:06 -0400 Subject: Delay DB updates until all policies processed If an exception is thrown in the middle of processing policies, it's possible for the DB to reflect a partial deployment. This change queues the DB changes so that they're all made at once, after all policies have been processed. Extracted sort() into a common place. Corrected some comments. Simplified the list retrieval in the junits since all DB creates and updates are now batched together into one operation each. Change-Id: I835175fc16d4042c741d36ec69caa8f603d46d5a Issue-ID: POLICY-1542 Signed-off-by: Jim Hahn --- .../policy/pap/main/rest/depundep/GroupData.java | 99 ++++++++++ .../pap/main/rest/depundep/ProviderBase.java | 78 ++------ .../policy/pap/main/rest/depundep/SessionData.java | 140 ++++++++++---- .../pap/main/rest/depundep/ProviderSuper.java | 29 ++- .../pap/main/rest/depundep/TestGroupData.java | 97 ++++++++++ .../rest/depundep/TestPdpGroupDeployProvider.java | 4 +- .../pap/main/rest/depundep/TestProviderBase.java | 28 +-- .../pap/main/rest/depundep/TestSessionData.java | 210 +++++++++++++++++---- .../test/resources/simpleDeploy/getGroupDao.json | 2 +- 9 files changed, 515 insertions(+), 172 deletions(-) create mode 100644 main/src/main/java/org/onap/policy/pap/main/rest/depundep/GroupData.java create mode 100644 main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestGroupData.java (limited to 'main') diff --git a/main/src/main/java/org/onap/policy/pap/main/rest/depundep/GroupData.java b/main/src/main/java/org/onap/policy/pap/main/rest/depundep/GroupData.java new file mode 100644 index 00000000..9345f341 --- /dev/null +++ b/main/src/main/java/org/onap/policy/pap/main/rest/depundep/GroupData.java @@ -0,0 +1,99 @@ +/* + * ============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.rest.depundep; + +import lombok.Getter; +import lombok.Setter; +import org.onap.policy.common.utils.validation.Version; +import org.onap.policy.models.pdp.concepts.PdpGroup; +import org.onap.policy.models.pdp.enums.PdpState; + +/** + * PdpGroup data, which includes the old group, that's in the DB, and possibly a new + * group, that must be added to the DB. + */ +@Getter +public class GroupData { + private final PdpGroup oldGroup; + + /** + * Starts out pointing to {@link #oldGroup}, but then changed to point to the new + * group, if {@link #setNewGroup(PdpGroup)} is invoked. + */ + private PdpGroup currentGroup; + + /** + * Latest version of this group. + */ + @Setter + private Version latestVersion; + + + /** + * Constructs the object. + * + * @param group the group that is in the DB + */ + public GroupData(PdpGroup group) { + this.oldGroup = group; + this.currentGroup = group; + } + + /** + * Determines if a new version of this group has been created (i.e., + * {@link #setNewGroup(PdpGroup)} has been invoked. + * + * @return {@code true} if a new version of the group has been created, {@code false} + * otherwise + */ + public boolean isNew() { + return (currentGroup != oldGroup); + } + + /** + * Updates to a new group. + * + * @param newGroup the new group + * @throws IllegalArgumentException if the new group has a different name than the old + * group + * @throws IllegalStateException if {@link #setLatestVersion(Version)} has not been + * invoked yet + */ + public void setNewGroup(PdpGroup newGroup) { + if (!currentGroup.getName().equals(newGroup.getName())) { + throw new IllegalArgumentException("attempt to change group name from " + currentGroup.getName() + " to " + + newGroup.getName()); + } + + if (currentGroup == oldGroup) { + // first time to create a new group - bump the version + if (latestVersion == null) { + throw new IllegalStateException("latestVersion not set for group: " + oldGroup.getName()); + } + + latestVersion = latestVersion.newVersion(); + oldGroup.setPdpGroupState(PdpState.PASSIVE); + } + + currentGroup = newGroup; + currentGroup.setVersion(latestVersion.toString()); + } +} diff --git a/main/src/main/java/org/onap/policy/pap/main/rest/depundep/ProviderBase.java b/main/src/main/java/org/onap/policy/pap/main/rest/depundep/ProviderBase.java index 29d3b3ca..b220bf80 100644 --- a/main/src/main/java/org/onap/policy/pap/main/rest/depundep/ProviderBase.java +++ b/main/src/main/java/org/onap/policy/pap/main/rest/depundep/ProviderBase.java @@ -37,7 +37,6 @@ import org.onap.policy.models.pdp.concepts.Pdp; import org.onap.policy.models.pdp.concepts.PdpGroup; import org.onap.policy.models.pdp.concepts.PdpSubGroup; import org.onap.policy.models.pdp.concepts.PdpUpdate; -import org.onap.policy.models.pdp.enums.PdpState; import org.onap.policy.models.provider.PolicyModelsProvider; import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy; import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyIdentifier; @@ -111,7 +110,10 @@ public abstract class ProviderBase { SessionData data = new SessionData(dao); processor.accept(data, request); - requests = data.getUpdates(); + // make all of the DB updates + data.updateDb(); + + requests = data.getPdpUpdates(); } catch (PfModelException e) { logger.warn(DEPLOY_FAILED, e); @@ -128,9 +130,7 @@ public abstract class ProviderBase { // publish the requests - for (PdpUpdate req : requests) { - requestMap.addRequest(req); - } + requests.forEach(requestMap::addRequest); } return Pair.of(Response.Status.OK, makeResponse(null)); @@ -215,7 +215,7 @@ public abstract class ProviderBase { private Collection getGroups(SessionData data, ToscaPolicyTypeIdentifier policyType) throws PfModelException { // build a map containing the group with the highest version for each name - Map name2data = new HashMap<>(); + Map name2data = new HashMap<>(); for (PdpGroup group : data.getActivePdpGroupsByPolicyType(policyType)) { Version vers = Version.makeVersion("PdpGroup", group.getName(), group.getVersion()); @@ -223,11 +223,11 @@ public abstract class ProviderBase { continue; } - GroupData grpdata = name2data.get(group.getName()); + GroupVersion grpdata = name2data.get(group.getName()); if (grpdata == null) { // not in the map yet - name2data.put(group.getName(), new GroupData(group, vers)); + name2data.put(group.getName(), new GroupVersion(group, vers)); } else if (vers.compareTo(grpdata.version) >= 0) { // higher version @@ -271,23 +271,9 @@ public abstract class ProviderBase { } - if (!updated) { - return; - } - - - // something changed - - if (data.isNewlyCreated(newGroup.getName())) { - /* - * It's already in the list of new groups - update the policies, but not the - * version. - */ - data.updatePdpGroup(newGroup); - - } else { - // haven't seen this group before - update the version - upgradeGroupVersion(data, oldGroup, newGroup); + if (updated) { + // something changed + data.setNewGroup(newGroup); } } @@ -314,49 +300,13 @@ public abstract class ProviderBase { } /** - * Upgrades a group's version. Updates the version in the new group, persists the new - * group, and deactivates the old group. - * - * @param data session data - * @param newGroup the new version of the group - * @param oldGroup the original group, to be updated - * @throws PfModelException if a DAO error occurred - */ - private void upgradeGroupVersion(SessionData data, PdpGroup newGroup, PdpGroup oldGroup) throws PfModelException { - - // change versions - newGroup.setVersion(makeNewVersion(data, oldGroup).toString()); - - // create it before we update the old group - newGroup = data.createPdpGroup(newGroup); - - // deactivate the old group - oldGroup.setPdpGroupState(PdpState.PASSIVE); - oldGroup = data.updatePdpGroup(oldGroup); - } - - /** - * Makes a new version for the PDP group. - * - * @param data session data - * @param group current group - * @return a new version - * @throws PfModelException if a DAO error occurred - */ - private Version makeNewVersion(SessionData data, PdpGroup group) throws PfModelException { - PdpGroup group2 = data.getPdpGroupMaxVersion(group.getName()); - Version vers = Version.makeVersion("PdpGroup", group2.getName(), group2.getVersion()); - return vers.newVersion(); - } - - /** - * Data associated with a group. Used to find the group with the maximum version. + * Data associated with a group. Used to find the maximum version for a given group. */ - private static class GroupData { + private static class GroupVersion { private PdpGroup group; private Version version; - public GroupData(PdpGroup group, Version version) { + public GroupVersion(PdpGroup group, Version version) { this.group = group; this.version = version; } diff --git a/main/src/main/java/org/onap/policy/pap/main/rest/depundep/SessionData.java b/main/src/main/java/org/onap/policy/pap/main/rest/depundep/SessionData.java index 01dc8f47..5bb96b9d 100644 --- a/main/src/main/java/org/onap/policy/pap/main/rest/depundep/SessionData.java +++ b/main/src/main/java/org/onap/policy/pap/main/rest/depundep/SessionData.java @@ -21,16 +21,16 @@ package org.onap.policy.pap.main.rest.depundep; import java.util.Collection; -import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Set; +import java.util.stream.Collectors; +import org.onap.policy.common.utils.validation.Version; import org.onap.policy.models.base.PfModelException; import org.onap.policy.models.pdp.concepts.PdpGroup; import org.onap.policy.models.pdp.concepts.PdpGroupFilter; import org.onap.policy.models.pdp.concepts.PdpUpdate; +import org.onap.policy.models.pdp.enums.PdpState; import org.onap.policy.models.provider.PolicyModelsProvider; import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy; import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyFilter; @@ -45,20 +45,32 @@ public class SessionData { private final PolicyModelsProvider dao; /** - * The names of newly created groups are added to this set to prevent the version - * number from being updated in case the group is re-used during the same REST call. + * Maps a group name to its group data. This accumulates the set of groups to be + * created and updated when the REST call completes. */ - private final Set newGroups; + private final Map groupCache = new HashMap<>(); + + /** + * Maps a policy type to the list of matching groups. Every group appearing within + * this map has a corresponding entry in {@link #groupCache}. + */ + private final Map> type2groups = new HashMap<>(); /** * Maps a PDP name to its most recently generated update request. */ - private final Map updates; + private final Map pdpUpdates = new HashMap<>(); /** * Maps a policy's identifier to the policy. */ - private final Map policyMap; + private final Map policyCache = new HashMap<>(); + + /** + * Maps a policy name to its latest policy. Every policy appearing within this map has + * a corresponding entry in {@link #policyCache}. + */ + private final Map latestPolicy = new HashMap<>(); /** @@ -68,9 +80,6 @@ public class SessionData { */ public SessionData(PolicyModelsProvider dao) { this.dao = dao; - this.newGroups = new HashSet<>(); - this.updates = new HashMap<>(); - this.policyMap = new HashMap<>(); } /** @@ -83,7 +92,7 @@ public class SessionData { */ public ToscaPolicy getPolicy(ToscaPolicyIdentifier ident) { - return policyMap.computeIfAbsent(ident, key -> { + return policyCache.computeIfAbsent(ident, key -> { try { List lst = dao.getPolicyList(ident.getName(), ident.getVersion()); @@ -114,7 +123,7 @@ public class SessionData { * @param update the update to be added */ public void addUpdate(PdpUpdate update) { - updates.put(update.getName(), update); + pdpUpdates.put(update.getName(), update); } /** @@ -122,8 +131,8 @@ public class SessionData { * * @return the UPDATE requests */ - public Collection getUpdates() { - return updates.values(); + public Collection getPdpUpdates() { + return pdpUpdates.values(); } /** @@ -133,7 +142,8 @@ public class SessionData { * @return {@code true} if the group has been newly created, {@code false} otherwise */ public boolean isNewlyCreated(String group) { - return newGroups.contains(group); + GroupData data = groupCache.get(group); + return (data != null && data.isNew()); } /** @@ -144,34 +154,62 @@ public class SessionData { * @throws PfModelException if an error occurs */ public ToscaPolicy getPolicyMaxVersion(String name) throws PfModelException { - ToscaPolicyFilter filter = ToscaPolicyFilter.builder().name(name).build(); - // TODO setLatest, setActive? + ToscaPolicy policy = latestPolicy.get(name); + if (policy != null) { + return policy; + } + ToscaPolicyFilter filter = + ToscaPolicyFilter.builder().name(name).version(ToscaPolicyFilter.LATEST_VERSION).build(); List policies = dao.getFilteredPolicyList(filter); if (policies.isEmpty()) { throw new PolicyPapRuntimeException("cannot find policy: " + name); } - return policies.get(0); + policy = policies.get(0); + policyCache.putIfAbsent(policy.getIdentifier(), policy); + latestPolicy.put(name, policy); + + return policy; } /** - * Gets the group having the given name and the maximum version. + * Adds a new version of a group to the cache. * - * @param name name of the desired group - * @return the desired group, or {@code null} if there is no group with given name + * @param newGroup the new group to be added + * @throws IllegalStateException if the old group has not been loaded into the cache + * yet * @throws PfModelException if an error occurs */ - public PdpGroup getPdpGroupMaxVersion(String name) throws PfModelException { - PdpGroupFilter filter = PdpGroupFilter.builder().name(name).build(); - // TODO setLatest + public void setNewGroup(PdpGroup newGroup) throws PfModelException { + String name = newGroup.getName(); + GroupData data = groupCache.get(name); + if (data == null) { + throw new IllegalStateException("group not cached: " + name); + } + if (data.getLatestVersion() != null) { + // already have the latest version + data.setNewGroup(newGroup); + return; + } + + // must determine the latest version of this group, regardless of its state + PdpGroupFilter filter = PdpGroupFilter.builder().name(name).version(PdpGroupFilter.LATEST_VERSION).build(); List groups = dao.getFilteredPdpGroups(filter); if (groups.isEmpty()) { throw new PolicyPapRuntimeException("cannot find group: " + name); } - return groups.get(0); + PdpGroup group = groups.get(0); + Version vers = Version.makeVersion("PdpGroup", group.getName(), group.getVersion()); + if (vers == null) { + // none of the versions are numeric - start with zero and increment from there + vers = new Version(0, 0, 0); + } + + data.setLatestVersion(vers); + data.setNewGroup(newGroup); } /** @@ -182,33 +220,53 @@ public class SessionData { * @throws PfModelException if an error occurs */ public List getActivePdpGroupsByPolicyType(ToscaPolicyTypeIdentifier type) throws PfModelException { + List data = type2groups.get(type); + if (data != null) { + return data.stream().map(GroupData::getCurrentGroup).collect(Collectors.toList()); + } + + PdpGroupFilter filter = PdpGroupFilter.builder().policyType(type).groupState(PdpState.ACTIVE).build(); - PdpGroupFilter filter = PdpGroupFilter.builder().policyType(type).build(); - // TODO setActive, setHasPdps + List groups = dao.getFilteredPdpGroups(filter); + + data = groups.stream().map(this::addGroup).collect(Collectors.toList()); + type2groups.put(type, data); - return dao.getFilteredPdpGroups(filter); + return groups; } /** - * Creates a PDP group. + * Adds a group to the group cache, if it isn't already in the cache. * - * @param pdpGroup the group to be created - * @return the created group - * @throws PfModelException if an error occurs + * @param group the group to be added + * @return the cache entry */ - public PdpGroup createPdpGroup(PdpGroup pdpGroup) throws PfModelException { - newGroups.add(pdpGroup.getName()); - return dao.createPdpGroups(Collections.singletonList(pdpGroup)).get(0); + private GroupData addGroup(PdpGroup group) { + GroupData data = groupCache.get(group.getName()); + if (data != null) { + return data; + } + + data = new GroupData(group); + groupCache.put(group.getName(), data); + + return data; } /** - * Updates a PDP group. + * Update the DB with the changes. * - * @param pdpGroup the group to be updated - * @return the updated group * @throws PfModelException if an error occurs */ - public PdpGroup updatePdpGroup(PdpGroup pdpGroup) throws PfModelException { - return dao.updatePdpGroups(Collections.singletonList(pdpGroup)).get(0); + public void updateDb() throws PfModelException { + List updatedGroups = + groupCache.values().stream().filter(GroupData::isNew).collect(Collectors.toList()); + if (updatedGroups.isEmpty()) { + return; + } + + // create new groups BEFORE we deactivate the old groups + dao.createPdpGroups(updatedGroups.stream().map(GroupData::getCurrentGroup).collect(Collectors.toList())); + dao.updatePdpGroups(updatedGroups.stream().map(GroupData::getOldGroup).collect(Collectors.toList())); } } diff --git a/main/src/test/java/org/onap/policy/pap/main/rest/depundep/ProviderSuper.java b/main/src/test/java/org/onap/policy/pap/main/rest/depundep/ProviderSuper.java index 3a3673d5..a1e69565 100644 --- a/main/src/test/java/org/onap/policy/pap/main/rest/depundep/ProviderSuper.java +++ b/main/src/test/java/org/onap/policy/pap/main/rest/depundep/ProviderSuper.java @@ -29,6 +29,7 @@ import static org.mockito.Mockito.when; import java.io.File; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import org.junit.Before; import org.mockito.ArgumentCaptor; @@ -125,27 +126,25 @@ public class ProviderSuper { /** * Gets the input to the method. * - * @param count the number of times the method is expected to have been called. * @return the input that was passed to the dao.createPdpGroups() method * @throws Exception if an error occurred */ - protected List> getGroupCreates(int count) throws Exception { - verify(dao, times(count)).createPdpGroups(createCaptor.capture()); + protected List getGroupCreates() throws Exception { + verify(dao).createPdpGroups(createCaptor.capture()); - return copyLists(createCaptor.getAllValues()); + return copyList(createCaptor.getValue()); } /** * Gets the input to the method. * - * @param count the number of times the method is expected to have been called * @return the input that was passed to the dao.updatePdpGroups() method * @throws Exception if an error occurred */ - protected List> getGroupUpdates(int count) throws Exception { - verify(dao, times(count)).updatePdpGroups(updateCaptor.capture()); + protected List getGroupUpdates() throws Exception { + verify(dao).updatePdpGroups(updateCaptor.capture()); - return copyLists(updateCaptor.getAllValues()); + return copyList(updateCaptor.getValue()); } /** @@ -163,19 +162,15 @@ public class ProviderSuper { } /** - * Makes a partly deep copy of the list. + * Copies a list and sorts it by group name. * * @param source source list to copy * @return a copy of the source list */ - private List> copyLists(List> source) { - List> target = new ArrayList<>(source.size()); - - for (List lst : source) { - target.add(new ArrayList<>(lst)); - } - - return target; + private List copyList(List source) { + List newlst = new ArrayList<>(source); + Collections.sort(newlst, (left, right) -> left.getName().compareTo(right.getName())); + return newlst; } /** diff --git a/main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestGroupData.java b/main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestGroupData.java new file mode 100644 index 00000000..a0d4989f --- /dev/null +++ b/main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestGroupData.java @@ -0,0 +1,97 @@ +/* + * ============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.rest.depundep; + +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.Assertions.assertThatIllegalStateException; +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 org.junit.Before; +import org.junit.Test; +import org.onap.policy.common.utils.validation.Version; +import org.onap.policy.models.pdp.concepts.PdpGroup; + +public class TestGroupData { + private static final String NEW_VERSION = "2.0.0"; + private static final String NAME = "my-name"; + + private PdpGroup oldGroup; + private PdpGroup newGroup; + private GroupData data; + private Version version; + + /** + * Sets up. + */ + @Before + public void setUp() { + oldGroup = new PdpGroup(); + oldGroup.setName(NAME); + + newGroup = new PdpGroup(oldGroup); + + version = new Version(1, 2, 3); + + data = new GroupData(oldGroup); + } + + @Test + public void test() { + assertFalse(data.isNew()); + assertSame(oldGroup, data.getOldGroup()); + assertSame(oldGroup, data.getCurrentGroup()); + + data.setLatestVersion(version); + data.setNewGroup(newGroup); + + assertTrue(data.isNew()); + assertSame(oldGroup, data.getOldGroup()); + assertSame(newGroup, data.getCurrentGroup()); + assertEquals(NEW_VERSION, data.getLatestVersion().toString()); + assertEquals(NEW_VERSION, newGroup.getVersion()); + + // repeat + newGroup = new PdpGroup(oldGroup); + data.setNewGroup(newGroup); + assertSame(oldGroup, data.getOldGroup()); + assertSame(newGroup, data.getCurrentGroup()); + assertEquals(NEW_VERSION, data.getLatestVersion().toString()); + assertEquals(NEW_VERSION, newGroup.getVersion()); + } + + @Test + public void testSetNewGroup_DifferentName() { + newGroup.setName("different-name"); + + data.setLatestVersion(version); + assertThatIllegalArgumentException().isThrownBy(() -> data.setNewGroup(newGroup)) + .withMessage("attempt to change group name from my-name to different-name"); + } + + @Test + public void testSetNewGroup_VersionNotSet() { + assertThatIllegalStateException().isThrownBy(() -> data.setNewGroup(newGroup)) + .withMessage("latestVersion not set for group: my-name"); + } +} diff --git a/main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestPdpGroupDeployProvider.java b/main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestPdpGroupDeployProvider.java index d3ffda84..018f117c 100644 --- a/main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestPdpGroupDeployProvider.java +++ b/main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestPdpGroupDeployProvider.java @@ -149,8 +149,8 @@ public class TestPdpGroupDeployProvider extends ProviderSuper { assertEquals(Status.OK, pair.getLeft()); assertNull(pair.getRight().getErrorDetails()); - assertGroup(getGroupUpdates(1).get(0), GROUP1_NAME, GROUP1_VERSION); - assertGroup(getGroupCreates(1).get(0), GROUP1_NAME, GROUP1_NEW_VERSION); + assertGroup(getGroupUpdates(), GROUP1_NAME, GROUP1_VERSION); + assertGroup(getGroupCreates(), GROUP1_NAME, GROUP1_NEW_VERSION); List requests = getUpdateRequests(2); assertUpdate(requests, GROUP1_NAME, PDP2_TYPE, PDP2); diff --git a/main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestProviderBase.java b/main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestProviderBase.java index f64f77da..883b3d55 100644 --- a/main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestProviderBase.java +++ b/main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestProviderBase.java @@ -109,8 +109,8 @@ public class TestProviderBase extends ProviderSuper { assertEquals(Status.OK, pair.getLeft()); assertNull(pair.getRight().getErrorDetails()); - assertGroup(getGroupUpdates(1).get(0), GROUP1_NAME, GROUP1_VERSION); - assertGroup(getGroupCreates(1).get(0), GROUP1_NAME, GROUP1_NEW_VERSION); + assertGroup(getGroupUpdates(), GROUP1_NAME, GROUP1_VERSION); + assertGroup(getGroupCreates(), GROUP1_NAME, GROUP1_NEW_VERSION); assertUpdate(getUpdateRequests(1), GROUP1_NAME, PDP1_TYPE, PDP1); } @@ -197,8 +197,8 @@ public class TestProviderBase extends ProviderSuper { assertEquals(Status.OK, pair.getLeft()); assertNull(pair.getRight().getErrorDetails()); - assertGroup(getGroupUpdates(1).get(0), GROUP1_NAME, GROUP1_VERSION); - assertGroup(getGroupCreates(1).get(0), GROUP1_NAME, GROUP1_NEW_VERSION); + assertGroup(getGroupUpdates(), GROUP1_NAME, GROUP1_VERSION); + assertGroup(getGroupCreates(), GROUP1_NAME, GROUP1_NEW_VERSION); } @Test @@ -224,8 +224,8 @@ public class TestProviderBase extends ProviderSuper { assertEquals(Status.OK, pair.getLeft()); assertNull(pair.getRight().getErrorDetails()); - assertGroup(getGroupUpdates(1).get(0), GROUP1_NAME, GROUP1_VERSION); - assertGroup(getGroupCreates(1).get(0), GROUP1_NAME, GROUP1_NEW_VERSION); + assertGroup(getGroupUpdates(), GROUP1_NAME, GROUP1_VERSION); + assertGroup(getGroupCreates(), GROUP1_NAME, GROUP1_NEW_VERSION); List requests = getUpdateRequests(2); assertUpdate(requests, GROUP1_NAME, PDP2_TYPE, PDP2); @@ -282,15 +282,15 @@ public class TestProviderBase extends ProviderSuper { assertEquals(Status.OK, pair.getLeft()); assertNull(pair.getRight().getErrorDetails()); - List> creates = getGroupCreates(2); - assertGroup(creates.get(0), GROUP1_NAME, GROUP1_NEW_VERSION); - assertGroup(creates.get(1), GROUP2_NAME, "301.0.0"); + // verify creates + List changes = getGroupCreates(); + assertGroup(changes, GROUP1_NAME, GROUP1_NEW_VERSION); + assertGroup(changes, GROUP2_NAME, "301.0.0"); - List> updates = getGroupUpdates(4); - assertGroup(updates.get(0), GROUP1_NAME, GROUP1_VERSION); - assertGroup(updates.get(1), GROUP2_NAME, "300.2.3"); - assertGroup(updates.get(2), GROUP1_NAME, GROUP1_NEW_VERSION); - assertGroup(updates.get(3), GROUP1_NAME, GROUP1_NEW_VERSION); + // verify updates + changes = getGroupUpdates(); + assertGroup(changes, GROUP1_NAME, GROUP1_VERSION); + assertGroup(changes, GROUP2_NAME, "300.2.3"); List requests = getUpdateRequests(3); assertUpdateIgnorePolicy(requests, GROUP1_NAME, PDP1_TYPE, PDP1); diff --git a/main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestSessionData.java b/main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestSessionData.java index 6be5c8ac..1c2b8233 100644 --- a/main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestSessionData.java +++ b/main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestSessionData.java @@ -20,12 +20,14 @@ package org.onap.policy.pap.main.rest.depundep; +import static org.assertj.core.api.Assertions.assertThatIllegalStateException; import static org.assertj.core.api.Assertions.assertThatThrownBy; 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 static org.mockito.Matchers.any; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -49,9 +51,10 @@ import org.onap.policy.pap.main.PolicyPapRuntimeException; public class TestSessionData extends ProviderSuper { private static final String GROUP_VERSION_PREFIX = "9.8."; - private static final String GROUP_NAME = "group"; + private static final String GROUP_NAME = "groupA"; private static final String GROUP_VERSION = GROUP_VERSION_PREFIX + "7"; - private static final String GROUP_NAME2 = "group2"; + private static final String GROUP_NEW_VERSION = "10.0.0"; + private static final String GROUP_NAME2 = "groupB"; private static final String GROUP_VERSION2 = GROUP_VERSION_PREFIX + "6"; private static final String PDP1 = "pdp_1"; private static final String PDP2 = "pdp_2"; @@ -60,9 +63,15 @@ public class TestSessionData extends ProviderSuper { private static final String POLICY_NAME = "myPolicy"; private static final String POLICY_VERSION = POLICY_VERSION_PREFIX + "3"; private static final String POLICY_VERSION2 = POLICY_VERSION_PREFIX + "4"; + private static final String POLICY_TYPE = "myType"; + private static final String POLICY_TYPE_VERSION = "10.20.30"; private SessionData session; private ToscaPolicyIdentifier ident; + private ToscaPolicyTypeIdentifier type; + private ToscaPolicyTypeIdentifier type2; + private PdpGroup group1; + private PdpGroup group2; /** * Initializes mocks and a session. @@ -74,6 +83,10 @@ public class TestSessionData extends ProviderSuper { super.setUp(); ident = new ToscaPolicyIdentifier(POLICY_NAME, POLICY_VERSION); + type = new ToscaPolicyTypeIdentifier(POLICY_TYPE, POLICY_TYPE_VERSION); + type2 = new ToscaPolicyTypeIdentifier(POLICY_TYPE, POLICY_TYPE_VERSION + "0"); + group1 = makeGroup(GROUP_NAME, GROUP_VERSION); + group2 = makeGroup(GROUP_NAME2, GROUP_VERSION2); session = new SessionData(dao); } @@ -126,7 +139,7 @@ public class TestSessionData extends ProviderSuper { } @Test - public void testAddUpdate() { + public void testAddUpdate_testGetPdpUpdates() { // several different updates, but one duplicate PdpUpdate update1 = makeUpdate(PDP1); session.addUpdate(update1); @@ -137,14 +150,14 @@ public class TestSessionData extends ProviderSuper { PdpUpdate update3 = makeUpdate(PDP3); session.addUpdate(update3); - List lst = sort(session.getUpdates(), this::compare); + List lst = sort(session.getPdpUpdates(), this::compare); assertEquals(Arrays.asList(update1, update2, update3).toString(), lst.toString()); // overwrite one update2 = makeUpdate(PDP2); session.addUpdate(update2); - lst = sort(session.getUpdates(), this::compare); + lst = sort(session.getPdpUpdates(), this::compare); assertEquals(Arrays.asList(update1, update2, update3).toString(), lst.toString()); } @@ -164,8 +177,15 @@ public class TestSessionData extends ProviderSuper { when(dao.getFilteredPolicyList(any())).thenReturn(Arrays.asList(policy1)); assertSame(policy1, session.getPolicyMaxVersion(POLICY_NAME)); + assertSame(policy1, session.getPolicyMaxVersion(POLICY_NAME)); + assertSame(policy1, session.getPolicyMaxVersion(POLICY_NAME)); + + // should have only invoked DAO once; used cache for other requests + verify(dao, times(1)).getFilteredPolicyList(any()); + } - // no matching policies - should throw an exception + @Test + public void testGetPolicyMaxVersion_NotFound() throws Exception { when(dao.getFilteredPolicyList(any())).thenReturn(Collections.emptyList()); assertThatThrownBy(() -> session.getPolicyMaxVersion(POLICY_NAME)).hasMessage("cannot find policy: myPolicy"); } @@ -174,24 +194,34 @@ public class TestSessionData extends ProviderSuper { public void testIsNewlyCreated_testCreatePdpGroup() throws Exception { assertFalse(session.isNewlyCreated(GROUP_NAME)); - PdpGroup group1 = makeGroup(GROUP_NAME, GROUP_VERSION); - when(dao.createPdpGroups(any())).thenReturn(Arrays.asList(group1)); + // cause the group to be loaded into the cache + when(dao.getFilteredPdpGroups(any())).thenReturn(Arrays.asList(group1)); + session.getActivePdpGroupsByPolicyType(type); - session.createPdpGroup(group1); + // not new yet + assertFalse(session.isNewlyCreated(GROUP_NAME)); + // update it + session.setNewGroup(new PdpGroup(group1)); assertTrue(session.isNewlyCreated(GROUP_NAME)); - assertFalse(session.isNewlyCreated(GROUP_NAME2)); - PdpGroup group2 = makeGroup(GROUP_NAME2, GROUP_VERSION2); - when(dao.createPdpGroups(any())).thenReturn(Arrays.asList(group2)); - session.createPdpGroup(group2); + /* + * now try group2 + */ + assertFalse(session.isNewlyCreated(GROUP_NAME2)); - List> creates = getGroupCreates(2); - assertEquals(group1, creates.get(0).get(0)); - assertEquals(group2, creates.get(1).get(0)); + // cause the group to be loaded into the cache + when(dao.getFilteredPdpGroups(any())).thenReturn(Arrays.asList(group2)); + session.getActivePdpGroupsByPolicyType(type2); + // not new yet + assertFalse(session.isNewlyCreated(GROUP_NAME2)); assertTrue(session.isNewlyCreated(GROUP_NAME)); + + // update it + session.setNewGroup(new PdpGroup(group2)); assertTrue(session.isNewlyCreated(GROUP_NAME2)); + assertTrue(session.isNewlyCreated(GROUP_NAME)); } private PdpGroup makeGroup(String name, String version) { @@ -204,37 +234,151 @@ public class TestSessionData extends ProviderSuper { } @Test - public void testGetPdpGroupMaxVersion() throws Exception { - PdpGroup group = makeGroup(GROUP_NAME, GROUP_VERSION); - when(dao.getFilteredPdpGroups(any())).thenReturn(Arrays.asList(group)); + public void testSetNewGroup() throws Exception { + // force the groups into the cache + when(dao.getFilteredPdpGroups(any())).thenReturn(Arrays.asList(group1, group2)); + session.getActivePdpGroupsByPolicyType(type); + + /* + * try group 1 + */ + when(dao.getFilteredPdpGroups(any())).thenReturn(Arrays.asList(group1)); + PdpGroup newgrp = new PdpGroup(group1); + session.setNewGroup(newgrp); + assertEquals(GROUP_NEW_VERSION, newgrp.getVersion().toString()); + + // repeat - version should be unchanged + newgrp = new PdpGroup(group1); + session.setNewGroup(newgrp); + assertEquals(GROUP_NEW_VERSION, newgrp.getVersion().toString()); + + /* + * try group 2 + */ + when(dao.getFilteredPdpGroups(any())).thenReturn(Arrays.asList(group2)); + newgrp = new PdpGroup(group2); + session.setNewGroup(newgrp); + assertEquals(GROUP_NEW_VERSION, newgrp.getVersion().toString()); + + // repeat - version should be unchanged + newgrp = new PdpGroup(group2); + session.setNewGroup(newgrp); + assertEquals(GROUP_NEW_VERSION, newgrp.getVersion().toString()); + + // should have queried the DB once by type and twice by for latest version + verify(dao, times(3)).getFilteredPdpGroups(any()); + } + + @Test + public void testSetNewGroup_NotInCache() throws Exception { + when(dao.getFilteredPdpGroups(any())).thenReturn(Arrays.asList(group1)); - assertEquals(group, session.getPdpGroupMaxVersion(GROUP_NAME)); + assertThatIllegalStateException().isThrownBy(() -> session.setNewGroup(new PdpGroup(group1))) + .withMessage("group not cached: groupA"); + } - // try empty list + @Test + public void testSetNewGroup_NotFound() throws Exception { + // force the group into the cache + when(dao.getFilteredPdpGroups(any())).thenReturn(Arrays.asList(group1)); + session.getActivePdpGroupsByPolicyType(type); + + // query for latest version will return an empty list when(dao.getFilteredPdpGroups(any())).thenReturn(Collections.emptyList()); - assertThatThrownBy(() -> session.getPdpGroupMaxVersion(GROUP_NAME)) - .isInstanceOf(PolicyPapRuntimeException.class).hasMessage("cannot find group: group"); + + assertThatThrownBy(() -> session.setNewGroup(new PdpGroup(group1))) + .isInstanceOf(PolicyPapRuntimeException.class).hasMessage("cannot find group: groupA"); + } + + @Test + public void testSetNewGroup_InvalidVersion() throws Exception { + // force the groups into the cache + group1.setVersion("invalid version"); + when(dao.getFilteredPdpGroups(any())).thenReturn(Arrays.asList(group1)); + session.getActivePdpGroupsByPolicyType(type); + + when(dao.getFilteredPdpGroups(any())).thenReturn(Arrays.asList(group1)); + PdpGroup newgrp = new PdpGroup(group1); + session.setNewGroup(newgrp); + assertEquals("1.0.0", newgrp.getVersion().toString()); } @Test public void testGetActivePdpGroupsByPolicyType() throws Exception { - List groups = - Arrays.asList(makeGroup(GROUP_NAME, GROUP_VERSION), makeGroup(GROUP_NAME2, GROUP_VERSION2)); + List groups = Arrays.asList(group1, group2); when(dao.getFilteredPdpGroups(any())).thenReturn(groups); - assertEquals(groups, session - .getActivePdpGroupsByPolicyType(new ToscaPolicyTypeIdentifier(POLICY_NAME, POLICY_VERSION))); + // repeat + assertEquals(groups, session.getActivePdpGroupsByPolicyType(type)); + assertEquals(groups, session.getActivePdpGroupsByPolicyType(type)); + assertEquals(groups, session.getActivePdpGroupsByPolicyType(type)); + + // only invoked once - should have used the cache for the rest + verify(dao, times(1)).getFilteredPdpGroups(any()); } @Test - public void testUpdatePdpGroup() throws Exception { - PdpGroup group = makeGroup(GROUP_NAME, GROUP_VERSION); - when(dao.updatePdpGroups(any())).thenReturn(Arrays.asList(group)); + public void testAddGroup() throws Exception { + List groups = Arrays.asList(group1, group2); + when(dao.getFilteredPdpGroups(any())).thenReturn(groups); - session.updatePdpGroup(group); + // query by each type + assertEquals(groups, session.getActivePdpGroupsByPolicyType(type)); + assertEquals(groups, session.getActivePdpGroupsByPolicyType(type2)); - List updates = getGroupUpdates(1).get(0); - assertEquals(group, updates.get(0)); + // invoked once for each type + verify(dao, times(2)).getFilteredPdpGroups(any()); + + // repeat - should be no more invocations + assertEquals(groups, session.getActivePdpGroupsByPolicyType(type)); + assertEquals(groups, session.getActivePdpGroupsByPolicyType(type2)); + verify(dao, times(2)).getFilteredPdpGroups(any()); + } + + @Test + public void testUpdateDb() throws Exception { + // force the groups into the cache + PdpGroup group3 = makeGroup("groupC", GROUP_VERSION2); + when(dao.getFilteredPdpGroups(any())).thenReturn(Arrays.asList(group1, group2, group3)); + session.getActivePdpGroupsByPolicyType(type); + + // update group 1 + when(dao.getFilteredPdpGroups(any())).thenReturn(Arrays.asList(group1)); + PdpGroup newgrp1 = new PdpGroup(group1); + session.setNewGroup(newgrp1); + + // another update + newgrp1 = new PdpGroup(newgrp1); + session.setNewGroup(newgrp1); + + // update group 3 + when(dao.getFilteredPdpGroups(any())).thenReturn(Arrays.asList(group3)); + PdpGroup newgrp3 = new PdpGroup(group3); + session.setNewGroup(newgrp3); + + // push the changes to the DB + session.updateDb(); + + // expect one create for groups 1 & 3 + List changes = getGroupCreates(); + assertSame(newgrp1, changes.get(0)); + assertSame(newgrp3, changes.get(1)); + + // expect one update for groups 1 & 3 + changes = getGroupUpdates(); + assertSame(group1, changes.get(0)); + assertSame(group3, changes.get(1)); + } + + @Test + public void testUpdateDb_Empty() throws Exception { + // force data into the cache + when(dao.getFilteredPdpGroups(any())).thenReturn(Arrays.asList(group1, group2)); + session.getActivePdpGroupsByPolicyType(type); + + session.updateDb(); + verify(dao, never()).createPdpGroups(any()); + verify(dao, never()).updatePdpGroups(any()); } private PdpUpdate makeUpdate(String pdpName) { diff --git a/main/src/test/resources/simpleDeploy/getGroupDao.json b/main/src/test/resources/simpleDeploy/getGroupDao.json index 2e74d1bf..65d0907a 100644 --- a/main/src/test/resources/simpleDeploy/getGroupDao.json +++ b/main/src/test/resources/simpleDeploy/getGroupDao.json @@ -2,7 +2,7 @@ "groups": [ { "name": "groupA", - "version": "0.0.0", + "version": "200.2.3", "pdpSubgroups": [ { "pdpType": "pdpTypeA", -- cgit 1.2.3-korg