Delay DB updates until all policies processed 08/84408/3
authorJim Hahn <jrh3@att.com>
Fri, 5 Apr 2019 21:02:06 +0000 (17:02 -0400)
committerJim Hahn <jrh3@att.com>
Fri, 5 Apr 2019 23:35:55 +0000 (19:35 -0400)
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 <jrh3@att.com>
main/src/main/java/org/onap/policy/pap/main/rest/depundep/GroupData.java [new file with mode: 0644]
main/src/main/java/org/onap/policy/pap/main/rest/depundep/ProviderBase.java
main/src/main/java/org/onap/policy/pap/main/rest/depundep/SessionData.java
main/src/test/java/org/onap/policy/pap/main/rest/depundep/ProviderSuper.java
main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestGroupData.java [new file with mode: 0644]
main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestPdpGroupDeployProvider.java
main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestProviderBase.java
main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestSessionData.java
main/src/test/resources/simpleDeploy/getGroupDao.json

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 (file)
index 0000000..9345f34
--- /dev/null
@@ -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());
+    }
+}
index 29d3b3c..b220bf8 100644 (file)
@@ -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<R extends SimpleResponse> {
                 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<R extends SimpleResponse> {
 
 
             // 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<R extends SimpleResponse> {
     private Collection<PdpGroup> getGroups(SessionData data, ToscaPolicyTypeIdentifier policyType)
                     throws PfModelException {
         // build a map containing the group with the highest version for each name
-        Map<String, GroupData> name2data = new HashMap<>();
+        Map<String, GroupVersion> 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<R extends SimpleResponse> {
                 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<R extends SimpleResponse> {
         }
 
 
-        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<R extends SimpleResponse> {
     }
 
     /**
-     * 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;
         }
index 01dc8f4..5bb96b9 100644 (file)
 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<String> newGroups;
+    private final Map<String, GroupData> 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<ToscaPolicyTypeIdentifier, List<GroupData>> type2groups = new HashMap<>();
 
     /**
      * Maps a PDP name to its most recently generated update request.
      */
-    private final Map<String, PdpUpdate> updates;
+    private final Map<String, PdpUpdate> pdpUpdates = new HashMap<>();
 
     /**
      * Maps a policy's identifier to the policy.
      */
-    private final Map<ToscaPolicyIdentifier, ToscaPolicy> policyMap;
+    private final Map<ToscaPolicyIdentifier, ToscaPolicy> 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<String, ToscaPolicy> 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<ToscaPolicy> 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<PdpUpdate> getUpdates() {
-        return updates.values();
+    public Collection<PdpUpdate> 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<ToscaPolicy> 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<PdpGroup> 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<PdpGroup> getActivePdpGroupsByPolicyType(ToscaPolicyTypeIdentifier type) throws PfModelException {
+        List<GroupData> 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<PdpGroup> 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<GroupData> 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()));
     }
 }
index 3a3673d..a1e6956 100644 (file)
@@ -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<List<PdpGroup>> getGroupCreates(int count) throws Exception {
-        verify(dao, times(count)).createPdpGroups(createCaptor.capture());
+    protected List<PdpGroup> 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<List<PdpGroup>> getGroupUpdates(int count) throws Exception {
-        verify(dao, times(count)).updatePdpGroups(updateCaptor.capture());
+    protected List<PdpGroup> 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<List<PdpGroup>> copyLists(List<List<PdpGroup>> source) {
-        List<List<PdpGroup>> target = new ArrayList<>(source.size());
-
-        for (List<PdpGroup> lst : source) {
-            target.add(new ArrayList<>(lst));
-        }
-
-        return target;
+    private List<PdpGroup> copyList(List<PdpGroup> source) {
+        List<PdpGroup> 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 (file)
index 0000000..a0d4989
--- /dev/null
@@ -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");
+    }
+}
index d3ffda8..018f117 100644 (file)
@@ -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<PdpUpdate> requests = getUpdateRequests(2);
         assertUpdate(requests, GROUP1_NAME, PDP2_TYPE, PDP2);
index f64f77d..883b3d5 100644 (file)
@@ -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<PdpUpdate> 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<List<PdpGroup>> creates = getGroupCreates(2);
-        assertGroup(creates.get(0), GROUP1_NAME, GROUP1_NEW_VERSION);
-        assertGroup(creates.get(1), GROUP2_NAME, "301.0.0");
+        // verify creates
+        List<PdpGroup> changes = getGroupCreates();
+        assertGroup(changes, GROUP1_NAME, GROUP1_NEW_VERSION);
+        assertGroup(changes, GROUP2_NAME, "301.0.0");
 
-        List<List<PdpGroup>> 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<PdpUpdate> requests = getUpdateRequests(3);
         assertUpdateIgnorePolicy(requests, GROUP1_NAME, PDP1_TYPE, PDP1);
index 6be5c8a..1c2b823 100644 (file)
 
 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<PdpUpdate> lst = sort(session.getUpdates(), this::compare);
+        List<PdpUpdate> 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<List<PdpGroup>> 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<PdpGroup> groups =
-                        Arrays.asList(makeGroup(GROUP_NAME, GROUP_VERSION), makeGroup(GROUP_NAME2, GROUP_VERSION2));
+        List<PdpGroup> 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<PdpGroup> 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<PdpGroup> 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<PdpGroup> 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) {
index 2e74d1b..65d0907 100644 (file)
@@ -2,7 +2,7 @@
     "groups": [
         {
             "name": "groupA",
-            "version": "0.0.0",
+            "version": "200.2.3",
             "pdpSubgroups": [
                 {
                     "pdpType": "pdpTypeA",