Flesh out policy deployment REST API 52/84352/2
authorJim Hahn <jrh3@att.com>
Fri, 5 Apr 2019 13:52:35 +0000 (09:52 -0400)
committerJim Hahn <jrh3@att.com>
Fri, 5 Apr 2019 15:51:26 +0000 (11:51 -0400)
Also moved the controller, the provider, and supporting classes
to their own dep_undep package.

Change-Id: Ifea1c4dd2ecbf93a8f4d45e130830cf9271103d3
Issue-ID: POLICY-1542
Signed-off-by: Jim Hahn <jrh3@att.com>
34 files changed:
main/src/main/java/org/onap/policy/pap/main/comm/msgdata/UpdateData.java
main/src/main/java/org/onap/policy/pap/main/rest/PapRestServer.java
main/src/main/java/org/onap/policy/pap/main/rest/PdpGroupDeployProvider.java [deleted file]
main/src/main/java/org/onap/policy/pap/main/rest/depundep/PdpGroupDeployControllerV1.java [moved from main/src/main/java/org/onap/policy/pap/main/rest/PdpGroupDeployControllerV1.java with 98% similarity]
main/src/main/java/org/onap/policy/pap/main/rest/depundep/PdpGroupDeployProvider.java [new file with mode: 0644]
main/src/main/java/org/onap/policy/pap/main/rest/depundep/ProviderBase.java [new file with mode: 0644]
main/src/main/java/org/onap/policy/pap/main/rest/depundep/SessionData.java [new file with mode: 0644]
main/src/test/java/org/onap/policy/pap/main/comm/PdpModifyRequestMapTest.java
main/src/test/java/org/onap/policy/pap/main/comm/msgdata/UpdateDataTest.java
main/src/test/java/org/onap/policy/pap/main/internal/TestModels.java [deleted file]
main/src/test/java/org/onap/policy/pap/main/rest/depundep/ProviderSuper.java [new file with mode: 0644]
main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestPdpGroupDeployControllerV1.java [moved from main/src/test/java/org/onap/policy/pap/main/rest/TestPdpGroupDeployControllerV1.java with 71% similarity]
main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestPdpGroupDeployProvider.java [new file with mode: 0644]
main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestProviderBase.java [new file with mode: 0644]
main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestSessionData.java [new file with mode: 0644]
main/src/test/resources/simpleDeploy/daoPolicyList.json [new file with mode: 0644]
main/src/test/resources/simpleDeploy/emptyGroups.json [new file with mode: 0644]
main/src/test/resources/simpleDeploy/emptyRequest.json [new file with mode: 0644]
main/src/test/resources/simpleDeploy/emptyRequestBase.json [new file with mode: 0644]
main/src/test/resources/simpleDeploy/getGroupDao.json [new file with mode: 0644]
main/src/test/resources/simpleDeploy/getPolicyReqNullVersion.json [new file with mode: 0644]
main/src/test/resources/simpleDeploy/groups.json [new file with mode: 0644]
main/src/test/resources/simpleDeploy/policy.json [new file with mode: 0644]
main/src/test/resources/simpleDeploy/request.json [new file with mode: 0644]
main/src/test/resources/simpleDeploy/requestBase.json [new file with mode: 0644]
main/src/test/resources/simpleDeploy/updateGroupReqMultiple.json [new file with mode: 0644]
main/src/test/resources/simpleDeploy/upgradeGroupDao.json [new file with mode: 0644]
main/src/test/resources/simpleDeploy/upgradeGroupGroup1.json [new file with mode: 0644]
main/src/test/resources/simpleDeploy/upgradeGroupGroup2.json [new file with mode: 0644]
main/src/test/resources/simpleDeploy/upgradeGroupPolicy2.json [new file with mode: 0644]
main/src/test/resources/simpleDeploy/upgradeGroupPolicy3.json [new file with mode: 0644]
main/src/test/resources/simpleDeploy/upgradeGroupPolicy4.json [new file with mode: 0644]
main/src/test/resources/simpleDeploy/upgradeGroup_NoPdpsDao.json [new file with mode: 0644]
main/src/test/resources/simpleDeploy/upgradeGroup_NothingUpdatedDao.json [new file with mode: 0644]

index 0d861e2..eca0b38 100644 (file)
@@ -20,8 +20,8 @@
 
 package org.onap.policy.pap.main.comm.msgdata;
 
-import java.util.ArrayList;
-import java.util.List;
+import java.util.HashSet;
+import java.util.Set;
 import org.onap.policy.models.pdp.concepts.PdpStatus;
 import org.onap.policy.models.pdp.concepts.PdpUpdate;
 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
@@ -62,32 +62,16 @@ public abstract class UpdateData extends MessageData {
         }
 
         // see if the other has any policies that this does not have
-        ArrayList<ToscaPolicyIdentifier> lst = new ArrayList<>(response.getPolicies());
-        List<ToscaPolicy> mypolicies = update.getPolicies();
+        Set<ToscaPolicyIdentifier> set = new HashSet<>(response.getPolicies());
 
-        if (mypolicies.size() != lst.size()) {
-            return "policies do not match";
+        for (ToscaPolicy policy : update.getPolicies()) {
+            set.remove(policy.getIdentifier());
         }
 
-        lst.removeAll(convertToscaPolicyToToscaPolicyIndentifier(update.getPolicies()));
-        if (!lst.isEmpty()) {
+        if (!set.isEmpty()) {
             return "policies do not match";
         }
 
         return null;
     }
-
-    /**
-     * Converts a ToscaPolicy list to ToscaPolicyIdentifier list.
-     *
-     * @param toscaPolicies the list of ToscaPolicy
-     * @return the ToscaPolicyIdentifier list
-     */
-    private List<ToscaPolicyIdentifier> convertToscaPolicyToToscaPolicyIndentifier(List<ToscaPolicy> toscaPolicies) {
-        final List<ToscaPolicyIdentifier> toscaPolicyIdentifiers = new ArrayList<>();
-        for (final ToscaPolicy toscaPolicy : toscaPolicies) {
-            toscaPolicyIdentifiers.add(new ToscaPolicyIdentifier(toscaPolicy.getName(), toscaPolicy.getVersion()));
-        }
-        return toscaPolicyIdentifiers;
-    }
 }
index 2858707..05ba290 100644 (file)
@@ -30,6 +30,7 @@ import org.onap.policy.common.endpoints.http.server.HttpServletServer;
 import org.onap.policy.common.endpoints.properties.PolicyEndPointProperties;
 import org.onap.policy.common.gson.GsonMessageBodyHandler;
 import org.onap.policy.pap.main.parameters.RestServerParameters;
+import org.onap.policy.pap.main.rest.depundep.PdpGroupDeployControllerV1;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
diff --git a/main/src/main/java/org/onap/policy/pap/main/rest/PdpGroupDeployProvider.java b/main/src/main/java/org/onap/policy/pap/main/rest/PdpGroupDeployProvider.java
deleted file mode 100644 (file)
index f0636fc..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * ============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;
-
-import javax.ws.rs.core.Response;
-
-import org.apache.commons.lang3.tuple.Pair;
-import org.onap.policy.models.pap.concepts.PdpDeployPolicies;
-import org.onap.policy.models.pap.concepts.PdpGroupDeployResponse;
-import org.onap.policy.models.pdp.concepts.PdpGroups;
-
-/**
- * Provider for PAP component to deploy PDP groups.
- */
-public class PdpGroupDeployProvider {
-
-    /**
-     * Deploys or updates a PDP group.
-     *
-     * @param groups PDP group configuration
-     * @return a pair containing the status and the response
-     */
-    public Pair<Response.Status, PdpGroupDeployResponse> deployGroup(PdpGroups groups) {
-
-        /*
-         * TODO Lock for updates - return error if already locked.
-         */
-
-        /*
-         * TODO Make updates - sending initial messages to PDPs and arranging for
-         * listeners to complete the deployment actions (in the background). The final
-         * step for the listener is to unlock.
-         */
-
-        /*
-         * TODO Return error if unable to send updates to all PDPs.
-         */
-
-        return Pair.of(Response.Status.OK, new PdpGroupDeployResponse());
-    }
-
-    /**
-     * Deploys or updates PDP policies.
-     *
-     * @param policies PDP policies
-     * @return a pair containing the status and the response
-     */
-    public Pair<Response.Status, PdpGroupDeployResponse> deployPolicies(PdpDeployPolicies policies) {
-
-        /*
-         * TODO Lock for updates - return error if already locked.
-         */
-
-        /*
-         * TODO Make updates - sending initial messages to PDPs and arranging for
-         * listeners to complete the deployment actions (in the background). The final
-         * step for the listener is to unlock.
-         */
-
-        /*
-         * TODO Return error if unable to send updates to all PDPs.
-         */
-
-        return Pair.of(Response.Status.OK, new PdpGroupDeployResponse());
-    }
-}
@@ -18,7 +18,7 @@
  * ============LICENSE_END=========================================================
  */
 
-package org.onap.policy.pap.main.rest;
+package org.onap.policy.pap.main.rest.depundep;
 
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiParam;
@@ -28,19 +28,17 @@ import io.swagger.annotations.Authorization;
 import io.swagger.annotations.Extension;
 import io.swagger.annotations.ExtensionProperty;
 import io.swagger.annotations.ResponseHeader;
-
 import java.util.UUID;
-
 import javax.ws.rs.HeaderParam;
 import javax.ws.rs.POST;
 import javax.ws.rs.Path;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.Status;
-
 import org.apache.commons.lang3.tuple.Pair;
 import org.onap.policy.models.pap.concepts.PdpDeployPolicies;
 import org.onap.policy.models.pap.concepts.PdpGroupDeployResponse;
 import org.onap.policy.models.pdp.concepts.PdpGroups;
+import org.onap.policy.pap.main.rest.PapRestControllerV1;
 
 /**
  * Class to provide REST end points for PAP component to deploy a PDP group.
@@ -123,7 +121,7 @@ public class PdpGroupDeployControllerV1 extends PapRestControllerV1 {
     // @formatter:on
 
     public Response deployPolicies(@HeaderParam(REQUEST_ID_NAME) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
-                    @ApiParam(value = "PDP Policies; only the name and policyVersion are required",
+                    @ApiParam(value = "PDP Policies; only the name is required",
                                     required = true) PdpDeployPolicies policies) {
 
         Pair<Status, PdpGroupDeployResponse> pair = provider.deployPolicies(policies);
diff --git a/main/src/main/java/org/onap/policy/pap/main/rest/depundep/PdpGroupDeployProvider.java b/main/src/main/java/org/onap/policy/pap/main/rest/depundep/PdpGroupDeployProvider.java
new file mode 100644 (file)
index 0000000..eef1438
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * ============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 java.util.List;
+import java.util.function.BiFunction;
+import javax.ws.rs.core.Response;
+import org.apache.commons.lang3.tuple.Pair;
+import org.onap.policy.common.utils.services.Registry;
+import org.onap.policy.models.base.PfModelException;
+import org.onap.policy.models.pap.concepts.PdpDeployPolicies;
+import org.onap.policy.models.pap.concepts.PdpGroupDeployResponse;
+import org.onap.policy.models.pdp.concepts.PdpGroup;
+import org.onap.policy.models.pdp.concepts.PdpGroups;
+import org.onap.policy.models.pdp.concepts.PdpSubGroup;
+import org.onap.policy.models.pdp.concepts.PdpUpdate;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyIdentifier;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyIdentifierOptVersion;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyTypeIdentifier;
+import org.onap.policy.pap.main.PolicyPapRuntimeException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Provider for PAP component to deploy PDP groups. The following items must be in the
+ * {@link Registry}:
+ * <ul>
+ * <li>PDP Modification Lock</li>
+ * <li>PDP Modify Request Map</li>
+ * <li>PAP DAO Factory</li>
+ * </ul>
+ */
+public class PdpGroupDeployProvider extends ProviderBase<PdpGroupDeployResponse> {
+    private static final Logger logger = LoggerFactory.getLogger(PdpGroupDeployProvider.class);
+
+
+    /**
+     * Constructs the object.
+     */
+    public PdpGroupDeployProvider() {
+        super();
+    }
+
+    /**
+     * Deploys or updates PDP groups.
+     *
+     * @param groups PDP group configurations
+     * @return a pair containing the status and the response
+     */
+    public Pair<Response.Status, PdpGroupDeployResponse> deployGroup(PdpGroups groups) {
+        return process(groups, this::deployGroups);
+    }
+
+    /**
+     * Deploys or updates PDP groups.
+     *
+     * @param data session data
+     * @param groups PDP group configurations
+     * @return a list of requests that should be sent to configure the PDPs
+     */
+    private List<PdpUpdate> deployGroups(SessionData data, PdpGroups groups) {
+        throw new PolicyPapRuntimeException("not implemented yet");
+    }
+
+    /**
+     * Deploys or updates PDP policies.
+     *
+     * @param policies PDP policies
+     * @return a pair containing the status and the response
+     */
+    public Pair<Response.Status, PdpGroupDeployResponse> deployPolicies(PdpDeployPolicies policies) {
+        return process(policies, this::deploySimplePolicies);
+    }
+
+    /**
+     * Deploys or updates PDP policies using the simple API.
+     *
+     * @param data session data
+     * @param extPolicies external PDP policies
+     * @return a list of requests that should be sent to configure the PDPs
+     */
+    private void deploySimplePolicies(SessionData data, PdpDeployPolicies policies) {
+
+        for (ToscaPolicyIdentifierOptVersion desiredPolicy : policies.getPolicies()) {
+
+            try {
+                processPolicy(data, desiredPolicy);
+
+            } catch (PfModelException e) {
+                // no need to log the error here, as it will be logged by the invoker
+                logger.warn("failed to deploy policy: {}", desiredPolicy);
+                throw new PolicyPapRuntimeException(DB_ERROR_MSG, e);
+
+            } catch (RuntimeException e) {
+                // no need to log the error here, as it will be logged by the invoker
+                logger.warn("failed to deploy policy: {}", desiredPolicy);
+                throw e;
+            }
+        }
+    }
+
+    @Override
+    protected BiFunction<PdpGroup, PdpSubGroup, Boolean> makeUpdater(ToscaPolicy policy) {
+        ToscaPolicyIdentifier desiredIdent = policy.getIdentifier();
+        ToscaPolicyTypeIdentifier desiredType = policy.getTypeIdentifier();
+
+        return (group, subgroup) -> {
+
+            if (!subgroup.getSupportedPolicyTypes().contains(desiredType)) {
+                // doesn't support the desired policy type
+                return false;
+            }
+
+            if (subgroup.getPolicies().contains(desiredIdent)) {
+                // already has the desired policy
+                return false;
+            }
+
+            if (subgroup.getPdpInstances().isEmpty()) {
+                throw new PolicyPapRuntimeException("group " + group.getName() + " subgroup " + subgroup.getPdpType()
+                                + " has no active PDPs");
+            }
+
+
+            // add the policy to the subgroup
+            subgroup.getPolicies().add(desiredIdent);
+            return true;
+        };
+    }
+
+    @Override
+    public PdpGroupDeployResponse makeResponse(String errorMsg) {
+        PdpGroupDeployResponse resp = new PdpGroupDeployResponse();
+        resp.setErrorDetails(errorMsg);
+        return resp;
+    }
+}
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
new file mode 100644 (file)
index 0000000..29d3b3c
--- /dev/null
@@ -0,0 +1,369 @@
+/*
+ * ============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 java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.stream.Collectors;
+import javax.ws.rs.core.Response;
+import org.apache.commons.lang3.tuple.Pair;
+import org.onap.policy.common.utils.services.Registry;
+import org.onap.policy.common.utils.validation.Version;
+import org.onap.policy.models.base.PfModelException;
+import org.onap.policy.models.pap.concepts.SimpleResponse;
+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;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyIdentifierOptVersion;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyTypeIdentifier;
+import org.onap.policy.pap.main.PapConstants;
+import org.onap.policy.pap.main.PolicyModelsProviderFactoryWrapper;
+import org.onap.policy.pap.main.PolicyPapRuntimeException;
+import org.onap.policy.pap.main.comm.PdpModifyRequestMap;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Super class of providers that deploy and undeploy PDP groups. The following items must
+ * be in the {@link Registry}:
+ * <ul>
+ * <li>PDP Modification Lock</li>
+ * <li>PDP Modify Request Map</li>
+ * <li>PAP DAO Factory</li>
+ * </ul>
+ *
+ * @param <R> the response type
+ */
+public abstract class ProviderBase<R extends SimpleResponse> {
+    private static final String DEPLOY_FAILED = "failed to deploy/undeploy policies";
+
+    public static final String DB_ERROR_MSG = "DB error";
+
+    private static final Logger logger = LoggerFactory.getLogger(ProviderBase.class);
+
+    /**
+     * Lock used when updating PDPs.
+     */
+    private final Object updateLock;
+
+    /**
+     * Used to send UPDATE and STATE-CHANGE requests to the PDPs.
+     */
+    private final PdpModifyRequestMap requestMap;
+
+    /**
+     * Factory for PAP DAO.
+     */
+    private final PolicyModelsProviderFactoryWrapper daoFactory;
+
+
+    /**
+     * Constructs the object.
+     */
+    public ProviderBase() {
+        this.updateLock = Registry.get(PapConstants.REG_PDP_MODIFY_LOCK, Object.class);
+        this.requestMap = Registry.get(PapConstants.REG_PDP_MODIFY_MAP, PdpModifyRequestMap.class);
+        this.daoFactory = Registry.get(PapConstants.REG_PAP_DAO_FACTORY, PolicyModelsProviderFactoryWrapper.class);
+    }
+
+    /**
+     * Processes a policy request.
+     *
+     * @param request PDP policy request
+     * @param processor function that processes the request
+     * @return a pair containing the status and the response
+     */
+    protected <T> Pair<Response.Status, R> process(T request, BiConsumer<SessionData, T> processor) {
+
+        synchronized (updateLock) {
+            // list of requests to be published to the PDPs
+            Collection<PdpUpdate> requests = Collections.emptyList();
+
+            try (PolicyModelsProvider dao = daoFactory.create()) {
+
+                SessionData data = new SessionData(dao);
+                processor.accept(data, request);
+
+                requests = data.getUpdates();
+
+            } catch (PfModelException e) {
+                logger.warn(DEPLOY_FAILED, e);
+                return Pair.of(Response.Status.INTERNAL_SERVER_ERROR, makeResponse(DB_ERROR_MSG));
+
+            } catch (PolicyPapRuntimeException e) {
+                logger.warn(DEPLOY_FAILED, e);
+                return Pair.of(Response.Status.INTERNAL_SERVER_ERROR, makeResponse(e.getMessage()));
+
+            } catch (RuntimeException e) {
+                logger.warn(DEPLOY_FAILED, e);
+                return Pair.of(Response.Status.INTERNAL_SERVER_ERROR, makeResponse("request failed"));
+            }
+
+
+            // publish the requests
+            for (PdpUpdate req : requests) {
+                requestMap.addRequest(req);
+            }
+        }
+
+        return Pair.of(Response.Status.OK, makeResponse(null));
+    }
+
+    /**
+     * Makes a response.
+     *
+     * @param errorMsg error message, or {@code null} if there was no error
+     * @return a new response
+     */
+    public abstract R makeResponse(String errorMsg);
+
+    /**
+     * Finds a Policy having the given name and version. If the specified version is
+     * {@code null}, then it finds the matching Policy with the latest version.
+     *
+     * @param data session data
+     * @param desiredPolicy the policy desired, with the "name" and optional
+     *        "policyVersion" populated
+     * @return the matching Policy type
+     * @throws PfModelException if a DAO error occurred
+     * @throws PolicyPapRuntimeException if there is no matching policy type
+     */
+    private ToscaPolicy getPolicy(SessionData data, ToscaPolicyIdentifierOptVersion desiredPolicy)
+                    throws PfModelException {
+
+        if (desiredPolicy.isNullVersion()) {
+            return data.getPolicyMaxVersion(desiredPolicy.getName());
+
+        } else {
+            return data.getPolicy(new ToscaPolicyIdentifier(desiredPolicy.getName(), desiredPolicy.getVersion()));
+        }
+    }
+
+    /**
+     * Process a single policy from the request.
+     *
+     * @param data session data
+     * @param desiredPolicy request policy
+     * @throws PolicyPapRuntimeException if an error occurs
+     * @throws PfModelException if a DAO error occurred
+     */
+    protected void processPolicy(SessionData data, ToscaPolicyIdentifierOptVersion desiredPolicy)
+                    throws PfModelException {
+
+        ToscaPolicy policy = getPolicy(data, desiredPolicy);
+
+        Collection<PdpGroup> groups = getGroups(data, policy.getTypeIdentifier());
+        if (groups.isEmpty()) {
+            throw new PolicyPapRuntimeException("policy not supported by any PDP group: " + desiredPolicy.getName()
+                            + " " + desiredPolicy.getVersion());
+        }
+
+        BiFunction<PdpGroup, PdpSubGroup, Boolean> updater = makeUpdater(policy);
+
+        for (PdpGroup group : groups) {
+            upgradeGroup(data, policy, group, updater);
+        }
+    }
+
+    /**
+     * Makes a function to update a subgroup. The function is expected to return
+     * {@code true} if the subgroup was updated, {@code false} if no update was
+     * necessary/appropriate.
+     *
+     * @param policy policy to be added to or removed from each subgroup
+     * @return a function to update a subgroup
+     */
+    protected abstract BiFunction<PdpGroup, PdpSubGroup, Boolean> makeUpdater(ToscaPolicy policy);
+
+    /**
+     * Finds the active PDP group(s) with the highest version that supports the given
+     * policy type.
+     *
+     * @param data session data
+     * @param policyType the policy type of interest
+     * @return the matching PDP group, or {@code null} if no active group supports the
+     *         given PDP types
+     * @throws PfModelException if an error occurs
+     */
+    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<>();
+
+        for (PdpGroup group : data.getActivePdpGroupsByPolicyType(policyType)) {
+            Version vers = Version.makeVersion("PdpGroup", group.getName(), group.getVersion());
+            if (vers == null) {
+                continue;
+            }
+
+            GroupData grpdata = name2data.get(group.getName());
+
+            if (grpdata == null) {
+                // not in the map yet
+                name2data.put(group.getName(), new GroupData(group, vers));
+
+            } else if (vers.compareTo(grpdata.version) >= 0) {
+                // higher version
+                grpdata.replace(group, vers);
+            }
+        }
+
+        return name2data.values().stream().map(grpdata -> grpdata.group).collect(Collectors.toList());
+    }
+
+    /**
+     * Updates a group, assigning a new version number, if it actually changes.
+     *
+     * @param data session data
+     * @param policy policy to be added to or removed from the group
+     * @param oldGroup the original group, to be updated
+     * @param updater function to update a group
+     * @throws PfModelException if a DAO error occurred
+     */
+    private void upgradeGroup(SessionData data, ToscaPolicy policy, PdpGroup oldGroup,
+                    BiFunction<PdpGroup, PdpSubGroup, Boolean> updater) throws PfModelException {
+
+        PdpGroup newGroup = new PdpGroup(oldGroup);
+        boolean updated = false;
+
+        for (PdpSubGroup subgroup : newGroup.getPdpSubgroups()) {
+
+            if (!updater.apply(newGroup, subgroup)) {
+                continue;
+            }
+
+            updated = true;
+
+            /*
+             * generate an UPDATE for each PDP instance. Since the group is active, we
+             * assume that the PDP is, too, thus no need for a STATE-CHANGE.
+             */
+            for (Pdp pdpInstance : subgroup.getPdpInstances()) {
+                data.addUpdate(makeUpdate(data, newGroup, subgroup, pdpInstance));
+            }
+        }
+
+
+        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);
+        }
+    }
+
+    /**
+     * Makes an UPDATE message for a particular PDP.
+     *
+     * @param data session data
+     * @param group group to which the PDP should belong
+     * @param subgroup subgroup to which the PDP should belong
+     * @param pdpInstance identifies the PDP of interest
+     * @return a new UPDATE message
+     */
+    private PdpUpdate makeUpdate(SessionData data, PdpGroup group, PdpSubGroup subgroup, Pdp pdpInstance) {
+
+        PdpUpdate update = new PdpUpdate();
+
+        update.setName(pdpInstance.getInstanceId());
+        update.setDescription(group.getDescription());
+        update.setPdpGroup(group.getName());
+        update.setPdpSubgroup(subgroup.getPdpType());
+        update.setPolicies(subgroup.getPolicies().stream().map(data::getPolicy).collect(Collectors.toList()));
+
+        return update;
+    }
+
+    /**
+     * 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.
+     */
+    private static class GroupData {
+        private PdpGroup group;
+        private Version version;
+
+        public GroupData(PdpGroup group, Version version) {
+            this.group = group;
+            this.version = version;
+        }
+
+        public void replace(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
new file mode 100644 (file)
index 0000000..01dc8f4
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * ============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 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 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.provider.PolicyModelsProvider;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyFilter;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyIdentifier;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyTypeIdentifier;
+import org.onap.policy.pap.main.PolicyPapRuntimeException;
+
+/**
+ * Data used during a single REST call when updating PDP policies.
+ */
+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.
+     */
+    private final Set<String> newGroups;
+
+    /**
+     * Maps a PDP name to its most recently generated update request.
+     */
+    private final Map<String, PdpUpdate> updates;
+
+    /**
+     * Maps a policy's identifier to the policy.
+     */
+    private final Map<ToscaPolicyIdentifier, ToscaPolicy> policyMap;
+
+
+    /**
+     * Constructs the object.
+     *
+     * @param dao DAO provider
+     */
+    public SessionData(PolicyModelsProvider dao) {
+        this.dao = dao;
+        this.newGroups = new HashSet<>();
+        this.updates = new HashMap<>();
+        this.policyMap = new HashMap<>();
+    }
+
+    /**
+     * Gets the policy, referenced by an identifier. Loads it from the cache, if possible.
+     * Otherwise, gets it from the DB.
+     *
+     * @param ident policy identifier
+     * @return the specified policy
+     * @throws PolicyPapRuntimeException if an error occurs
+     */
+    public ToscaPolicy getPolicy(ToscaPolicyIdentifier ident) {
+
+        return policyMap.computeIfAbsent(ident, key -> {
+
+            try {
+                List<ToscaPolicy> lst = dao.getPolicyList(ident.getName(), ident.getVersion());
+
+                if (lst.isEmpty()) {
+                    throw new PolicyPapRuntimeException(
+                                    "cannot find policy: " + ident.getName() + " " + ident.getVersion());
+                }
+
+                if (lst.size() > 1) {
+                    throw new PolicyPapRuntimeException(
+                                    "too many policies match: " + ident.getName() + " " + ident.getVersion());
+                }
+
+                return lst.get(0);
+
+            } catch (PfModelException e) {
+                throw new PolicyPapRuntimeException("cannot get policy: " + ident.getName() + " " + ident.getVersion(),
+                                e);
+            }
+        });
+    }
+
+    /**
+     * Adds an update to the set of updates, replacing any previous entry for the given
+     * PDP.
+     *
+     * @param update the update to be added
+     */
+    public void addUpdate(PdpUpdate update) {
+        updates.put(update.getName(), update);
+    }
+
+    /**
+     * Gets the accumulated UPDATE requests.
+     *
+     * @return the UPDATE requests
+     */
+    public Collection<PdpUpdate> getUpdates() {
+        return updates.values();
+    }
+
+    /**
+     * Determines if a group has been newly created as part of this REST call.
+     *
+     * @param group name to the group of interest
+     * @return {@code true} if the group has been newly created, {@code false} otherwise
+     */
+    public boolean isNewlyCreated(String group) {
+        return newGroups.contains(group);
+    }
+
+    /**
+     * Gets the policy having the given name and the maximum version.
+     *
+     * @param name name of the desired policy
+     * @return the desired policy, or {@code null} if there is no policy with given name
+     * @throws PfModelException if an error occurs
+     */
+    public ToscaPolicy getPolicyMaxVersion(String name) throws PfModelException {
+        ToscaPolicyFilter filter = ToscaPolicyFilter.builder().name(name).build();
+        // TODO setLatest, setActive?
+
+        List<ToscaPolicy> policies = dao.getFilteredPolicyList(filter);
+        if (policies.isEmpty()) {
+            throw new PolicyPapRuntimeException("cannot find policy: " + name);
+        }
+
+        return policies.get(0);
+    }
+
+    /**
+     * Gets the group having the given name and the maximum version.
+     *
+     * @param name name of the desired group
+     * @return the desired group, or {@code null} if there is no group with given name
+     * @throws PfModelException if an error occurs
+     */
+    public PdpGroup getPdpGroupMaxVersion(String name) throws PfModelException {
+        PdpGroupFilter filter = PdpGroupFilter.builder().name(name).build();
+        // TODO setLatest
+
+        List<PdpGroup> groups = dao.getFilteredPdpGroups(filter);
+        if (groups.isEmpty()) {
+            throw new PolicyPapRuntimeException("cannot find group: " + name);
+        }
+
+        return groups.get(0);
+    }
+
+    /**
+     * Gets the active groups supporting the given policy.
+     *
+     * @param type desired policy type
+     * @return the active groups supporting the given policy
+     * @throws PfModelException if an error occurs
+     */
+    public List<PdpGroup> getActivePdpGroupsByPolicyType(ToscaPolicyTypeIdentifier type) throws PfModelException {
+
+        PdpGroupFilter filter = PdpGroupFilter.builder().policyType(type).build();
+        // TODO setActive, setHasPdps
+
+        return dao.getFilteredPdpGroups(filter);
+    }
+
+    /**
+     * Creates a PDP group.
+     *
+     * @param pdpGroup the group to be created
+     * @return the created group
+     * @throws PfModelException if an error occurs
+     */
+    public PdpGroup createPdpGroup(PdpGroup pdpGroup) throws PfModelException {
+        newGroups.add(pdpGroup.getName());
+        return dao.createPdpGroups(Collections.singletonList(pdpGroup)).get(0);
+    }
+
+    /**
+     * Updates a PDP group.
+     *
+     * @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);
+    }
+}
index 8f06403..c36a7d4 100644 (file)
@@ -42,6 +42,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Queue;
 import java.util.function.Consumer;
+import java.util.stream.Collectors;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
@@ -56,7 +57,6 @@ import org.onap.policy.models.pdp.concepts.PdpStatus;
 import org.onap.policy.models.pdp.concepts.PdpUpdate;
 import org.onap.policy.models.pdp.enums.PdpState;
 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
-import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyIdentifier;
 import org.onap.policy.pap.main.PapConstants;
 import org.onap.policy.pap.main.comm.PdpModifyRequestMap.ModifyReqData;
 import org.onap.policy.pap.main.parameters.PdpModifyRequestMapParams;
@@ -133,7 +133,8 @@ public class PdpModifyRequestMapTest {
         response.setState(PdpState.SAFE);
         response.setPdpGroup(update.getPdpGroup());
         response.setPdpSubgroup(update.getPdpSubgroup());
-        response.setPolicies(convertToscaPolicyToToscaPolicyIndentifier());
+        response.setPolicies(update.getPolicies().stream().map(ToscaPolicy::getIdentifier)
+                        .collect(Collectors.toList()));
 
         map = new PdpModifyRequestMap(makeParameters()) {
 
@@ -327,10 +328,13 @@ public class PdpModifyRequestMapTest {
     public void testModifyReqDataIsActive() {
         map.addRequest(update);
 
+        ModifyReqData reqdata = getReqData(PDP1);
+        assertNotNull(reqdata);
+
+        // this should remove it from the map
         invokeProcessResponse();
 
-        // name should have been removed
-        assertNull(getReqData(PDP1));
+        assertFalse(reqdata.isActive());
     }
 
     @Test
@@ -584,18 +588,4 @@ public class PdpModifyRequestMapTest {
 
         return cng;
     }
-
-    /**
-     * Converts a ToscaPolicy list to ToscaPolicyIdentifier list.
-     *
-     * @return the ToscaPolicyIdentifier list
-     */
-    private List<ToscaPolicyIdentifier> convertToscaPolicyToToscaPolicyIndentifier() {
-        final List<ToscaPolicy> toscaPolicies = update.getPolicies();
-        final List<ToscaPolicyIdentifier> toscaPolicyIdentifiers = new ArrayList<>();
-        for (final ToscaPolicy toscaPolicy : toscaPolicies) {
-            toscaPolicyIdentifiers.add(new ToscaPolicyIdentifier(toscaPolicy.getName(), toscaPolicy.getVersion()));
-        }
-        return toscaPolicyIdentifiers;
-    }
 }
index 352b92d..bac85ed 100644 (file)
@@ -72,7 +72,7 @@ public class UpdateDataTest {
         response.setName(MY_NAME);
         response.setPdpGroup(update.getPdpGroup());
         response.setPdpSubgroup(update.getPdpSubgroup());
-        response.setPolicies(convertToscaPolicyToToscaPolicyIndentifier(update.getPolicies()));
+        response.setPolicies(policyToIdent(update.getPolicies()));
 
         data = new MyData(update);
     }
@@ -113,24 +113,26 @@ public class UpdateDataTest {
         assertEquals("subgroup does not match", data.checkResponse(response));
     }
 
-    @Test
-    public void testUpdateDataCheckResponse_MismatchedPoliciesLength() {
-        response.setPolicies(convertToscaPolicyToToscaPolicyIndentifier(Arrays.asList(update.getPolicies().get(0))));
-
-        assertEquals("policies do not match", data.checkResponse(response));
-    }
-
     @Test
     public void testUpdateDataCheckResponse_MismatchedPolicies() {
-        ArrayList<ToscaPolicyIdentifier> policies =
-                        new ArrayList<>(convertToscaPolicyToToscaPolicyIndentifier(update.getPolicies()));
-        policies.set(0, new ToscaPolicyIdentifier(DIFFERENT, "10.0.0"));
+        ArrayList<ToscaPolicy> policies = new ArrayList<>(update.getPolicies());
+        policies.set(0, makePolicy(DIFFERENT, "10.0.0"));
 
-        response.setPolicies(policies);
+        response.setPolicies(policyToIdent(policies));
 
         assertEquals("policies do not match", data.checkResponse(response));
     }
 
+    /**
+     * Converts a list of policies to their corresponding identifiers.
+     *
+     * @param policies policies to be converted
+     * @return a list of policy identifiers
+     */
+    private List<ToscaPolicyIdentifier> policyToIdent(List<ToscaPolicy> policies) {
+        return policies.stream().map(ToscaPolicy::getIdentifier).collect(Collectors.toList());
+    }
+
     /**
      * Makes an update message.
      *
@@ -184,15 +186,4 @@ public class UpdateDataTest {
             // do nothing
         }
     }
-
-    /**
-     * Converts a ToscaPolicy list to ToscaPolicyIdentifier list.
-     *
-     * @param toscaPolicies the list of ToscaPolicy
-     * @return the ToscaPolicyIdentifier list
-     */
-    private List<ToscaPolicyIdentifier> convertToscaPolicyToToscaPolicyIndentifier(List<ToscaPolicy> toscaPolicies) {
-        return toscaPolicies.stream().map(policy -> new ToscaPolicyIdentifier(policy.getName(), policy.getVersion()))
-                        .collect(Collectors.toList());
-    }
 }
diff --git a/main/src/test/java/org/onap/policy/pap/main/internal/TestModels.java b/main/src/test/java/org/onap/policy/pap/main/internal/TestModels.java
deleted file mode 100644 (file)
index 7cdd06e..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/*-
- * ============LICENSE_START=======================================================
- *  Copyright (C) 2019 Nordix Foundation.
- *  Modifications Copyright (C) 2019 AT&T Intellectual Property.
- * ================================================================================
- * 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.
- *
- * SPDX-License-Identifier: Apache-2.0
- * ============LICENSE_END=========================================================
- */
-
-package org.onap.policy.pap.main.internal;
-
-import com.openpojo.reflection.filters.FilterPackageInfo;
-import com.openpojo.validation.Validator;
-import com.openpojo.validation.ValidatorBuilder;
-import com.openpojo.validation.test.impl.GetterTester;
-import com.openpojo.validation.test.impl.SetterTester;
-
-import org.junit.Test;
-import org.onap.policy.common.utils.validation.ToStringTester;
-
-/**
- * Class to perform unit testing of models.
- *
- * @author Ram Krishna Verma (ram.krishna.verma@est.tech)
- */
-public class TestModels {
-
-    @Test
-    public void testPapModels() {
-        final Validator validator = ValidatorBuilder.create().with(new ToStringTester()).with(new SetterTester())
-                .with(new GetterTester()).build();
-        validator.validate(TestModels.class.getPackage().getName(), new FilterPackageInfo());
-    }
-}
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
new file mode 100644 (file)
index 0000000..3a3673d
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * ============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.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import org.junit.Before;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.onap.policy.common.utils.coder.Coder;
+import org.onap.policy.common.utils.coder.CoderException;
+import org.onap.policy.common.utils.coder.StandardCoder;
+import org.onap.policy.common.utils.resources.ResourceUtils;
+import org.onap.policy.common.utils.services.Registry;
+import org.onap.policy.models.pdp.concepts.PdpGroup;
+import org.onap.policy.models.pdp.concepts.PdpUpdate;
+import org.onap.policy.models.provider.PolicyModelsProvider;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
+import org.onap.policy.pap.main.PapConstants;
+import org.onap.policy.pap.main.PolicyModelsProviderFactoryWrapper;
+import org.onap.policy.pap.main.comm.PdpModifyRequestMap;
+
+/**
+ * Super class for TestPdpGroupDeployProviderXxx classes.
+ */
+public class ProviderSuper {
+    private static final Coder coder = new StandardCoder();
+
+    @Mock
+    protected PolicyModelsProvider dao;
+
+    /**
+     * Used to capture input to dao.createPdpGroups().
+     */
+    @Captor
+    private ArgumentCaptor<List<PdpGroup>> createCaptor;
+
+
+    /**
+     * Used to capture input to dao.updatePdpGroups().
+     */
+    @Captor
+    private ArgumentCaptor<List<PdpGroup>> updateCaptor;
+
+    protected Object lockit;
+    protected PdpModifyRequestMap reqmap;
+    protected PolicyModelsProviderFactoryWrapper daofact;
+    protected ToscaPolicy policy1;
+
+
+    /**
+     * Configures DAO, captors, and various mocks.
+     */
+    @Before
+    public void setUp() throws Exception {
+
+        Registry.newRegistry();
+
+        MockitoAnnotations.initMocks(this);
+
+        reqmap = mock(PdpModifyRequestMap.class);
+
+        lockit = new Object();
+        daofact = mock(PolicyModelsProviderFactoryWrapper.class);
+        policy1 = loadFile("policy.json", ToscaPolicy.class);
+
+        when(daofact.create()).thenReturn(dao);
+
+        List<PdpGroup> groups = loadGroups("groups.json");
+
+        when(dao.getFilteredPdpGroups(any())).thenReturn(groups);
+
+        when(dao.createPdpGroups(any())).thenAnswer(answer -> answer.getArgumentAt(0, List.class));
+        when(dao.updatePdpGroups(any())).thenAnswer(answer -> answer.getArgumentAt(0, List.class));
+
+        Registry.register(PapConstants.REG_PDP_MODIFY_LOCK, lockit);
+        Registry.register(PapConstants.REG_PDP_MODIFY_MAP, reqmap);
+        Registry.register(PapConstants.REG_PAP_DAO_FACTORY, daofact);
+    }
+
+    protected void assertGroup(List<PdpGroup> groups, String name, String version) {
+        PdpGroup group = groups.remove(0);
+
+        assertEquals(name, group.getName());
+        assertEquals(version, group.getVersion());
+    }
+
+    protected void assertUpdateIgnorePolicy(List<PdpUpdate> updates, String groupName, String pdpType, String pdpName) {
+
+        PdpUpdate update = updates.remove(0);
+
+        assertEquals(groupName, update.getPdpGroup());
+        assertEquals(pdpType, update.getPdpSubgroup());
+        assertEquals(pdpName, update.getName());
+    }
+
+    /**
+     * 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());
+
+        return copyLists(createCaptor.getAllValues());
+    }
+
+    /**
+     * 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());
+
+        return copyLists(updateCaptor.getAllValues());
+    }
+
+    /**
+     * Gets the updates that were added to the request map.
+     *
+     * @param count the number of times the method is expected to have been called
+     * @return the updates that were added to the request map
+     */
+    protected List<PdpUpdate> getUpdateRequests(int count) {
+        ArgumentCaptor<PdpUpdate> captor = ArgumentCaptor.forClass(PdpUpdate.class);
+
+        verify(reqmap, times(count)).addRequest(captor.capture());
+
+        return new ArrayList<>(captor.getAllValues());
+    }
+
+    /**
+     * Makes a partly deep copy of the list.
+     *
+     * @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;
+    }
+
+    /**
+     * Loads a list of groups.
+     *
+     * @param fileName name of the file from which to load
+     * @return a list of groups
+     */
+    protected List<PdpGroup> loadGroups(String fileName) {
+        return loadFile(fileName, org.onap.policy.models.pdp.concepts.PdpGroups.class).getGroups();
+    }
+
+    /**
+     * Loads a list of policies.
+     *
+     * @param fileName name of the file from which to load
+     * @return a list of policies
+     */
+    protected List<ToscaPolicy> loadPolicies(String fileName) {
+        return loadFile(fileName, PolicyList.class).policies;
+    }
+
+    /**
+     * Loads an object from a JSON file.
+     *
+     * @param fileName name of the file from which to load
+     * @param clazz the class of the object to be loaded
+     * @return the object that was loaded from the file
+     */
+    protected <T> T loadFile(String fileName, Class<T> clazz) {
+        File propFile = new File(ResourceUtils.getFilePath4Resource("simpleDeploy/" + fileName));
+        try {
+            return coder.decode(propFile, clazz);
+
+        } catch (CoderException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Wraps a list of policies. The decoder doesn't work with generic lists, so we wrap
+     * the list and decode it into the wrapper before extracting the list contents.
+     */
+    private static class PolicyList {
+        private List<ToscaPolicy> policies;
+    }
+}
@@ -1,4 +1,4 @@
-/*-
+/*
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2019 Nordix Foundation.
  *  Modifications Copyright (C) 2019 AT&T Intellectual Property.
  * ============LICENSE_END=========================================================
  */
 
-package org.onap.policy.pap.main.rest;
+package org.onap.policy.pap.main.rest.depundep;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertNotNull;
 
 import java.util.Arrays;
 import javax.ws.rs.client.Entity;
@@ -35,6 +35,7 @@ import org.onap.policy.models.pap.concepts.PdpGroupDeployResponse;
 import org.onap.policy.models.pdp.concepts.PdpGroup;
 import org.onap.policy.models.pdp.concepts.PdpSubGroup;
 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyIdentifierOptVersion;
+import org.onap.policy.pap.main.rest.CommonPapRestServer;
 
 public class TestPdpGroupDeployControllerV1 extends CommonPapRestServer {
 
@@ -49,18 +50,18 @@ public class TestPdpGroupDeployControllerV1 extends CommonPapRestServer {
 
     @Test
     public void testDeployGroup() throws Exception {
-        final Entity<PdpGroup> entgrp = makePdpGroupEntity();
+        Entity<PdpGroup> entgrp = makePdpGroupEntity();
 
-        final Invocation.Builder invocationBuilder = sendRequest(DEPLOY_GROUP_ENDPOINT);
+        Invocation.Builder invocationBuilder = sendRequest(DEPLOY_GROUP_ENDPOINT);
         Response rawresp = invocationBuilder.post(entgrp);
         PdpGroupDeployResponse resp = rawresp.readEntity(PdpGroupDeployResponse.class);
-        assertEquals(Response.Status.OK.getStatusCode(), rawresp.getStatus());
-        assertNull(resp.getErrorDetails());
+        assertEquals(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), rawresp.getStatus());
+        assertNotNull(resp.getErrorDetails());
 
         rawresp = invocationBuilder.post(entgrp);
         resp = rawresp.readEntity(PdpGroupDeployResponse.class);
-        assertEquals(Response.Status.OK.getStatusCode(), rawresp.getStatus());
-        assertNull(resp.getErrorDetails());
+        assertEquals(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), rawresp.getStatus());
+        assertNotNull(resp.getErrorDetails());
 
         // verify it fails when no authorization info is included
         checkUnauthRequest(DEPLOY_GROUP_ENDPOINT, req -> req.post(entgrp));
@@ -68,28 +69,28 @@ public class TestPdpGroupDeployControllerV1 extends CommonPapRestServer {
 
     @Test
     public void testDeployPolicies() throws Exception {
-        final Entity<PdpDeployPolicies> entgrp = makePdpPoliciesEntity();
+        Entity<PdpDeployPolicies> entgrp = makePdpPoliciesEntity();
 
-        final Invocation.Builder invocationBuilder = sendRequest(DEPLOY_POLICIES_ENDPOINT);
+        Invocation.Builder invocationBuilder = sendRequest(DEPLOY_POLICIES_ENDPOINT);
         Response rawresp = invocationBuilder.post(entgrp);
         PdpGroupDeployResponse resp = rawresp.readEntity(PdpGroupDeployResponse.class);
-        assertEquals(Response.Status.OK.getStatusCode(), rawresp.getStatus());
-        assertNull(resp.getErrorDetails());
+        assertEquals(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), rawresp.getStatus());
+        assertNotNull(resp.getErrorDetails());
 
         rawresp = invocationBuilder.post(entgrp);
         resp = rawresp.readEntity(PdpGroupDeployResponse.class);
-        assertEquals(Response.Status.OK.getStatusCode(), rawresp.getStatus());
-        assertNull(resp.getErrorDetails());
+        assertEquals(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), rawresp.getStatus());
+        assertNotNull(resp.getErrorDetails());
 
         // verify it fails when no authorization info is included
         checkUnauthRequest(DEPLOY_POLICIES_ENDPOINT, req -> req.post(entgrp));
     }
 
     private Entity<PdpGroup> makePdpGroupEntity() {
-        final PdpSubGroup subgrp = new PdpSubGroup();
+        PdpSubGroup subgrp = new PdpSubGroup();
         subgrp.setPdpType("drools");
 
-        final PdpGroup group = new PdpGroup();
+        PdpGroup group = new PdpGroup();
         group.setName("drools-group");
         group.setDescription("my description");
         group.setVersion("my-version");
@@ -99,14 +100,10 @@ public class TestPdpGroupDeployControllerV1 extends CommonPapRestServer {
     }
 
     private Entity<PdpDeployPolicies> makePdpPoliciesEntity() {
-        final ToscaPolicyIdentifierOptVersion pol1 = new ToscaPolicyIdentifierOptVersion();
-        pol1.setName("policy-a");
-        pol1.setVersion("1");
+        ToscaPolicyIdentifierOptVersion pol1 = new ToscaPolicyIdentifierOptVersion("policy-a", "1");
+        ToscaPolicyIdentifierOptVersion pol2 = new ToscaPolicyIdentifierOptVersion("policy-b", null);
 
-        final ToscaPolicyIdentifierOptVersion pol2 = new ToscaPolicyIdentifierOptVersion();
-        pol2.setName("policy-b");
-
-        final PdpDeployPolicies policies = new PdpDeployPolicies();
+        PdpDeployPolicies policies = new PdpDeployPolicies();
         policies.setPolicies(Arrays.asList(pol1, pol2));
 
         return Entity.entity(policies, MediaType.APPLICATION_JSON);
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
new file mode 100644 (file)
index 0000000..d3ffda8
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * ============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.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.onap.policy.pap.main.rest.depundep.ProviderBase.DB_ERROR_MSG;
+
+import java.util.List;
+import javax.ws.rs.core.Response.Status;
+import org.apache.commons.lang3.tuple.Pair;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.policy.common.utils.services.Registry;
+import org.onap.policy.models.base.PfModelException;
+import org.onap.policy.models.pap.concepts.PdpDeployPolicies;
+import org.onap.policy.models.pap.concepts.PdpGroupDeployResponse;
+import org.onap.policy.models.pdp.concepts.PdpGroups;
+import org.onap.policy.models.pdp.concepts.PdpUpdate;
+import org.onap.policy.pap.main.rest.depundep.PdpGroupDeployProvider;
+
+public class TestPdpGroupDeployProvider extends ProviderSuper {
+    private static final String EXPECTED_EXCEPTION = "expected exception";
+    private static final Object REQUEST_FAILED_MSG = "request failed";
+
+    private static final String POLICY1_NAME = "policyA";
+    private static final String POLICY1_VERSION = "1.2.3";
+    private static final String GROUP1_NAME = "groupA";
+    private static final String GROUP1_VERSION = "200.2.3";
+    private static final String GROUP1_NEW_VERSION = "201.0.0";
+    private static final String PDP1_TYPE = "pdpTypeA";
+    private static final String PDP2_TYPE = "pdpTypeB";
+    private static final String PDP4_TYPE = "pdpTypeD";
+    private static final String PDP2 = "pdpB";
+    private static final String PDP4 = "pdpD";
+
+    private PdpGroupDeployProvider prov;
+
+
+    @AfterClass
+    public static void tearDownAfterClass() {
+        Registry.newRegistry();
+    }
+
+    /**
+     * Configures mocks and objects.
+     *
+     * @throws Exception if an error occurs
+     */
+    @Before
+    public void setUp() throws Exception {
+
+        super.setUp();
+
+        when(dao.getPolicyList(POLICY1_NAME, POLICY1_VERSION)).thenReturn(loadPolicies("daoPolicyList.json"));
+
+        prov = new PdpGroupDeployProvider();
+    }
+
+    @Test
+    public void testDeployGroup() {
+        Pair<Status, PdpGroupDeployResponse> pair = prov.deployGroup(new PdpGroups());
+        assertEquals(Status.INTERNAL_SERVER_ERROR, pair.getLeft());
+        assertEquals("not implemented yet", pair.getRight().getErrorDetails());
+    }
+
+    @Test
+    public void testDeployPolicies() {
+        Pair<Status, PdpGroupDeployResponse> pair = prov.deployPolicies(loadEmptyRequest());
+        assertEquals(Status.OK, pair.getLeft());
+        assertNull(pair.getRight().getErrorDetails());
+    }
+
+    @Test
+    public void testDeploySimplePolicies() throws Exception {
+        Pair<Status, PdpGroupDeployResponse> pair = prov.deployPolicies(loadRequest());
+        assertEquals(Status.OK, pair.getLeft());
+        assertNull(pair.getRight().getErrorDetails());
+    }
+
+    @Test
+    public void testDeploySimplePolicies_DaoEx() throws Exception {
+        when(dao.getFilteredPdpGroups(any())).thenThrow(new PfModelException(Status.BAD_REQUEST, EXPECTED_EXCEPTION));
+
+        Pair<Status, PdpGroupDeployResponse> pair = prov.deployPolicies(loadRequest());
+        assertEquals(Status.INTERNAL_SERVER_ERROR, pair.getLeft());
+        assertEquals(DB_ERROR_MSG, pair.getRight().getErrorDetails());
+    }
+
+    @Test
+    public void testDeploySimplePolicies_RuntimeEx() throws Exception {
+        when(dao.getPolicyList(any(), any())).thenThrow(new RuntimeException(EXPECTED_EXCEPTION));
+
+        Pair<Status, PdpGroupDeployResponse> pair = prov.deployPolicies(loadRequest());
+        assertEquals(Status.INTERNAL_SERVER_ERROR, pair.getLeft());
+        assertEquals(REQUEST_FAILED_MSG, pair.getRight().getErrorDetails());
+    }
+
+    @Test
+    public void testDeploySimplePolicies_NoGroups() throws Exception {
+        when(dao.getFilteredPdpGroups(any())).thenReturn(loadGroups("emptyGroups.json"));
+
+        Pair<Status, PdpGroupDeployResponse> pair = prov.deployPolicies(loadRequest());
+        assertEquals(Status.INTERNAL_SERVER_ERROR, pair.getLeft());
+        assertEquals("policy not supported by any PDP group: policyA 1.2.3", pair.getRight().getErrorDetails());
+    }
+
+    @Test
+    public void testMakeUpdater() throws Exception {
+        /*
+         * Each subgroup has a different PDP type and name.
+         *
+         * Type is not supported by the first subgroup.
+         *
+         * Second subgroup matches.
+         *
+         * Third subgroup already contains the policy.
+         *
+         * Last subgroup matches.
+         */
+
+        when(dao.getFilteredPdpGroups(any())).thenReturn(loadGroups("upgradeGroupDao.json"));
+
+        Pair<Status, PdpGroupDeployResponse> pair = prov.deployPolicies(loadRequest());
+        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);
+
+        List<PdpUpdate> requests = getUpdateRequests(2);
+        assertUpdate(requests, GROUP1_NAME, PDP2_TYPE, PDP2);
+        assertUpdate(requests, GROUP1_NAME, PDP4_TYPE, PDP4);
+    }
+
+    @Test
+    public void testMakeUpdater_NoPdps() throws Exception {
+
+        // subgroup has no PDPs
+        when(dao.getFilteredPdpGroups(any())).thenReturn(loadGroups("upgradeGroup_NoPdpsDao.json"));
+
+        Pair<Status, PdpGroupDeployResponse> pair = prov.deployPolicies(loadRequest());
+        assertEquals(Status.INTERNAL_SERVER_ERROR, pair.getLeft());
+        assertEquals("group " + GROUP1_NAME + " subgroup " + PDP1_TYPE + " has no active PDPs",
+                        pair.getRight().getErrorDetails());
+
+        verify(dao, never()).createPdpGroups(any());
+        verify(dao, never()).updatePdpGroups(any());
+        verify(reqmap, never()).addRequest(any(PdpUpdate.class));
+    }
+
+
+    protected void assertUpdate(List<PdpUpdate> updates, String groupName, String pdpType, String pdpName) {
+
+        PdpUpdate update = updates.remove(0);
+
+        assertEquals(groupName, update.getPdpGroup());
+        assertEquals(pdpType, update.getPdpSubgroup());
+        assertEquals(pdpName, update.getName());
+        assertTrue(update.getPolicies().contains(policy1));
+    }
+
+    /**
+     * Loads a standard request.
+     *
+     * @return a standard request
+     */
+    protected PdpDeployPolicies loadRequest() {
+        return loadRequest("request.json");
+    }
+
+    /**
+     * Loads a request from a JSON file.
+     *
+     * @param fileName name of the file from which to load
+     * @return the request that was loaded
+     */
+    protected PdpDeployPolicies loadRequest(String fileName) {
+        return loadFile(fileName, PdpDeployPolicies.class);
+    }
+
+    /**
+     * Loads an empty request.
+     *
+     * @return an empty request
+     */
+    protected PdpDeployPolicies loadEmptyRequest() {
+        return loadRequest("emptyRequest.json");
+    }
+}
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
new file mode 100644 (file)
index 0000000..f64f77d
--- /dev/null
@@ -0,0 +1,421 @@
+/*
+ * ============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.assertThatThrownBy;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+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.verify;
+import static org.mockito.Mockito.when;
+import static org.onap.policy.pap.main.rest.depundep.ProviderBase.DB_ERROR_MSG;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Queue;
+import java.util.function.BiFunction;
+import javax.ws.rs.core.Response.Status;
+import org.apache.commons.lang3.tuple.Pair;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.policy.common.utils.services.Registry;
+import org.onap.policy.models.base.PfModelException;
+import org.onap.policy.models.pap.concepts.PdpDeployPolicies;
+import org.onap.policy.models.pap.concepts.SimpleResponse;
+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.tosca.authorative.concepts.ToscaPolicy;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyIdentifierOptVersion;
+import org.onap.policy.pap.main.PolicyPapRuntimeException;
+import org.powermock.reflect.Whitebox;
+
+public class TestProviderBase extends ProviderSuper {
+    private static final String EXPECTED_EXCEPTION = "expected exception";
+    private static final Object REQUEST_FAILED_MSG = "request failed";
+
+    private static final String POLICY1_NAME = "policyA";
+    private static final String POLICY1_VERSION = "1.2.3";
+    private static final String GROUP1_NAME = "groupA";
+    private static final String GROUP1_VERSION = "200.2.3";
+    private static final String GROUP1_NEW_VERSION = "201.0.0";
+    private static final String GROUP2_NAME = "groupB";
+    private static final String PDP1_TYPE = "pdpTypeA";
+    private static final String PDP2_TYPE = "pdpTypeB";
+    private static final String PDP3_TYPE = "pdpTypeC";
+    private static final String PDP4_TYPE = "pdpTypeD";
+    private static final String PDP1 = "pdpA";
+    private static final String PDP2 = "pdpB";
+    private static final String PDP3 = "pdpC";
+    private static final String PDP4 = "pdpD";
+
+    private MyProvider prov;
+
+
+    @AfterClass
+    public static void tearDownAfterClass() {
+        Registry.newRegistry();
+    }
+
+    /**
+     * Configures mocks and objects.
+     *
+     * @throws Exception if an error occurs
+     */
+    @Before
+    public void setUp() throws Exception {
+
+        super.setUp();
+
+        when(dao.getPolicyList(POLICY1_NAME, POLICY1_VERSION)).thenReturn(loadPolicies("daoPolicyList.json"));
+
+        prov = new MyProvider();
+    }
+
+    @Test
+    public void testProviderBase() {
+        assertSame(lockit, Whitebox.getInternalState(prov, "updateLock"));
+        assertSame(reqmap, Whitebox.getInternalState(prov, "requestMap"));
+        assertSame(daofact, Whitebox.getInternalState(prov, "daoFactory"));
+    }
+
+    @Test
+    public void testProcess() throws Exception {
+        Pair<Status, MyResponse> pair = prov.process(loadRequest(), this::handle);
+        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);
+
+        assertUpdate(getUpdateRequests(1), GROUP1_NAME, PDP1_TYPE, PDP1);
+    }
+
+    @Test
+    public void testProcess_CreateEx() throws Exception {
+        when(daofact.create()).thenThrow(new PfModelException(Status.BAD_REQUEST, EXPECTED_EXCEPTION));
+
+        Pair<Status, MyResponse> pair = prov.process(loadEmptyRequest(), this::handle);
+        assertEquals(Status.INTERNAL_SERVER_ERROR, pair.getLeft());
+        assertEquals(DB_ERROR_MSG, pair.getRight().getErrorDetails());
+    }
+
+    @Test
+    public void testProcess_PapEx() throws Exception {
+        when(daofact.create()).thenThrow(new PolicyPapRuntimeException(EXPECTED_EXCEPTION));
+
+        Pair<Status, MyResponse> pair = prov.process(loadEmptyRequest(), this::handle);
+        assertEquals(Status.INTERNAL_SERVER_ERROR, pair.getLeft());
+        assertEquals(EXPECTED_EXCEPTION, pair.getRight().getErrorDetails());
+    }
+
+    @Test
+    public void testProcess_RuntimeEx() throws Exception {
+        when(daofact.create()).thenThrow(new RuntimeException(EXPECTED_EXCEPTION));
+
+        Pair<Status, MyResponse> pair = prov.process(loadEmptyRequest(), this::handle);
+        assertEquals(Status.INTERNAL_SERVER_ERROR, pair.getLeft());
+        assertEquals(REQUEST_FAILED_MSG, pair.getRight().getErrorDetails());
+    }
+
+    @Test
+    public void testProcessPolicy_NoGroups() throws Exception {
+        when(dao.getFilteredPdpGroups(any())).thenReturn(Collections.emptyList());
+
+        SessionData session = new SessionData(dao);
+        ToscaPolicyIdentifierOptVersion ident = new ToscaPolicyIdentifierOptVersion(POLICY1_NAME, POLICY1_VERSION);
+        assertThatThrownBy(() -> prov.processPolicy(session, ident)).isInstanceOf(PolicyPapRuntimeException.class)
+                        .hasMessage("policy not supported by any PDP group: policyA 1.2.3");
+
+    }
+
+    @Test
+    public void testGetPolicy() throws Exception {
+        Pair<Status, MyResponse> pair = prov.process(loadRequest(), this::handle);
+        assertEquals(Status.OK, pair.getLeft());
+        assertNull(pair.getRight().getErrorDetails());
+
+        verify(dao).getPolicyList(any(), any());
+        verify(dao, never()).getFilteredPolicyList(any());
+    }
+
+    @Test
+    public void testGetPolicy_NullVersion() throws Exception {
+        // only allow this query once
+        when(dao.getPolicyList(POLICY1_NAME, POLICY1_VERSION)).thenReturn(loadPolicies("daoPolicyList.json"))
+                        .thenThrow(new RuntimeException(EXPECTED_EXCEPTION));
+
+        when(dao.getFilteredPolicyList(any())).thenReturn(loadPolicies("daoPolicyList.json"));
+
+        Pair<Status, MyResponse> pair = prov.process(loadRequest("getPolicyReqNullVersion.json"), this::handle);
+        assertEquals(Status.OK, pair.getLeft());
+        assertNull(pair.getRight().getErrorDetails());
+
+        verify(dao).getFilteredPolicyList(any());
+        verify(dao, never()).getPolicies(any(), any());
+    }
+
+    @Test
+    public void testGetPolicy_NotFound() throws Exception {
+        when(dao.getPolicyList(any(), any())).thenReturn(Collections.emptyList());
+
+        Pair<Status, MyResponse> pair = prov.process(loadRequest(), this::handle);
+        assertEquals(Status.INTERNAL_SERVER_ERROR, pair.getLeft());
+        assertEquals("cannot find policy: " + POLICY1_NAME + " " + POLICY1_VERSION, pair.getRight().getErrorDetails());
+    }
+
+    @Test
+    public void testGetGroup() throws Exception {
+        when(dao.getFilteredPdpGroups(any())).thenReturn(loadGroups("getGroupDao.json"))
+                        .thenReturn(loadGroups("groups.json"));
+
+        Pair<Status, MyResponse> pair = prov.process(loadRequest(), this::handle);
+        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);
+    }
+
+    @Test
+    public void testUpgradeGroup() throws Exception {
+        /*
+         * Each subgroup has a different PDP type and name.
+         *
+         * Type is not supported by the first subgroup.
+         *
+         * Second subgroup matches.
+         *
+         * Third subgroup already contains the policy.
+         *
+         * Last subgroup matches.
+         */
+
+        when(dao.getFilteredPdpGroups(any())).thenReturn(loadGroups("upgradeGroupDao.json"));
+
+        prov.clear();
+        prov.add(false, true, false, true);
+
+        Pair<Status, MyResponse> pair = prov.process(loadRequest(), this::handle);
+        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);
+
+        List<PdpUpdate> requests = getUpdateRequests(2);
+        assertUpdate(requests, GROUP1_NAME, PDP2_TYPE, PDP2);
+        assertUpdate(requests, GROUP1_NAME, PDP4_TYPE, PDP4);
+    }
+
+    @Test
+    public void testUpgradeGroup_Multiple() throws Exception {
+        /*
+         * Policy data in the DB: policy1=type1, policy2=type2, policy3=type3,
+         * policy4=type1
+         *
+         * Group data in the DB: group1=(type1=pdp1, type3=pdp3) group2=(type2=pdp2)
+         *
+         * Request specifies: policy1, policy2, policy3, policy4
+         *
+         * Should create new versions of group1 and group2.
+         *
+         * Should update old versions of group1 and group2. Should also update new version
+         * of group1 twice.
+         *
+         * Should generate updates to pdp1, pdp2, and pdp3.
+         */
+
+        when(dao.getPolicyList(POLICY1_NAME, POLICY1_VERSION)).thenReturn(loadPolicies("daoPolicyList.json"));
+        when(dao.getPolicyList("policyB", POLICY1_VERSION)).thenReturn(loadPolicies("upgradeGroupPolicy2.json"));
+        when(dao.getPolicyList("policyC", POLICY1_VERSION)).thenReturn(loadPolicies("upgradeGroupPolicy3.json"));
+        when(dao.getPolicyList("policyD", POLICY1_VERSION)).thenReturn(loadPolicies("upgradeGroupPolicy4.json"));
+
+        List<PdpGroup> groups1 = loadGroups("upgradeGroupGroup1.json");
+        List<PdpGroup> groups2 = loadGroups("upgradeGroupGroup2.json");
+
+        /*
+         * these are in pairs of (get-group, get-max-group) matching each policy in the
+         * request
+         */
+        // @formatter:off
+        when(dao.getFilteredPdpGroups(any()))
+            .thenReturn(groups1).thenReturn(groups1)
+            .thenReturn(groups2).thenReturn(groups2)
+            .thenReturn(groups1).thenReturn(groups1)
+            .thenReturn(groups1).thenReturn(groups1);
+        // @formatter:on
+
+        // multiple policies in the request
+        PdpDeployPolicies request = loadFile("updateGroupReqMultiple.json", PdpDeployPolicies.class);
+
+        Pair<Status, MyResponse> pair = prov.process(request, (data, deploy) -> {
+            for (ToscaPolicyIdentifierOptVersion policy : deploy.getPolicies()) {
+                handle(data, policy);
+            }
+        });
+
+        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");
+
+        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);
+
+        List<PdpUpdate> requests = getUpdateRequests(3);
+        assertUpdateIgnorePolicy(requests, GROUP1_NAME, PDP1_TYPE, PDP1);
+        assertUpdateIgnorePolicy(requests, GROUP2_NAME, PDP2_TYPE, PDP2);
+        assertUpdateIgnorePolicy(requests, GROUP1_NAME, PDP3_TYPE, PDP3);
+    }
+
+    @Test
+    public void testUpgradeGroup_NothingUpdated() throws Exception {
+        prov.clear();
+        prov.add(false);
+
+        Pair<Status, MyResponse> pair = prov.process(loadRequest(), this::handle);
+        assertEquals(Status.OK, pair.getLeft());
+        assertNull(pair.getRight().getErrorDetails());
+
+        verify(dao, never()).createPdpGroups(any());
+        verify(dao, never()).updatePdpGroups(any());
+        verify(reqmap, never()).addRequest(any(PdpUpdate.class));
+    }
+
+
+    protected void assertUpdate(List<PdpUpdate> updates, String groupName, String pdpType, String pdpName) {
+
+        PdpUpdate update = updates.remove(0);
+
+        assertEquals(groupName, update.getPdpGroup());
+        assertEquals(pdpType, update.getPdpSubgroup());
+        assertEquals(pdpName, update.getName());
+        assertTrue(update.getPolicies().contains(policy1));
+    }
+
+    /**
+     * Loads a standard request.
+     *
+     * @return a standard request
+     */
+    protected ToscaPolicyIdentifierOptVersion loadRequest() {
+        return loadRequest("requestBase.json");
+    }
+
+    /**
+     * Loads a request from a JSON file.
+     *
+     * @param fileName name of the file from which to load
+     * @return the request that was loaded
+     */
+    protected ToscaPolicyIdentifierOptVersion loadRequest(String fileName) {
+        return loadFile(fileName, ToscaPolicyIdentifierOptVersion.class);
+    }
+
+    /**
+     * Loads an empty request.
+     *
+     * @return an empty request
+     */
+    protected ToscaPolicyIdentifierOptVersion loadEmptyRequest() {
+        return loadRequest("emptyRequestBase.json");
+    }
+
+    /**
+     * Handles a request by invoking the provider's processPolicy method.
+     *
+     * @param data session data
+     * @param request request to be handled
+     */
+    private void handle(SessionData data, ToscaPolicyIdentifierOptVersion request) {
+        try {
+            prov.processPolicy(data, request);
+
+        } catch (PfModelException e) {
+            throw new PolicyPapRuntimeException(e);
+        }
+    }
+
+
+    private static class MyProvider extends ProviderBase<MyResponse> {
+        /**
+         * Used to determine whether or not to make an update when
+         * {@link #makeUpdater(ToscaPolicy)} is called. The updater function removes an
+         * item from this queue each time it is invoked.
+         */
+        private final Queue<Boolean> shouldUpdate = new LinkedList<>();
+
+        /**
+         * Constructs the object and queues up several successful updates.
+         */
+        public MyProvider() {
+            for (int x = 0; x < 10; ++x) {
+                shouldUpdate.add(true);
+            }
+        }
+
+        public void clear() {
+            shouldUpdate.clear();
+        }
+
+        public void add(Boolean... update) {
+            shouldUpdate.addAll(Arrays.asList(update));
+        }
+
+        @Override
+        public MyResponse makeResponse(String errorMsg) {
+            return new MyResponse(errorMsg);
+        }
+
+        @Override
+        protected BiFunction<PdpGroup, PdpSubGroup, Boolean> makeUpdater(ToscaPolicy policy) {
+            return (group, subgroup) -> {
+                if (shouldUpdate.remove()) {
+                    // queue indicated that the update should succeed
+                    subgroup.getPolicies().add(policy.getIdentifier());
+                    return true;
+
+                } else {
+                    // queue indicated that no update should be made this time
+                    return false;
+                }
+            };
+        }
+    }
+
+    private static class MyResponse extends SimpleResponse {
+        public MyResponse(String errorMsg) {
+            setErrorDetails(errorMsg);
+        }
+    }
+}
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
new file mode 100644 (file)
index 0000000..6be5c8a
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ * ============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.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.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import javax.ws.rs.core.Response.Status;
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.policy.models.base.PfModelException;
+import org.onap.policy.models.pdp.concepts.PdpGroup;
+import org.onap.policy.models.pdp.concepts.PdpUpdate;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyIdentifier;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyTypeIdentifier;
+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_VERSION = GROUP_VERSION_PREFIX + "7";
+    private static final String GROUP_NAME2 = "group2";
+    private static final String GROUP_VERSION2 = GROUP_VERSION_PREFIX + "6";
+    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 POLICY_VERSION_PREFIX = "1.2.";
+    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 SessionData session;
+    private ToscaPolicyIdentifier ident;
+
+    /**
+     * Initializes mocks and a session.
+     *
+     * @throws Exception if an error occurs
+     */
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+
+        ident = new ToscaPolicyIdentifier(POLICY_NAME, POLICY_VERSION);
+
+        session = new SessionData(dao);
+    }
+
+    @Test
+    public void testGetPolicy() throws Exception {
+        ToscaPolicy policy1 = makePolicy(POLICY_NAME, POLICY_VERSION);
+        when(dao.getPolicyList(POLICY_NAME, POLICY_VERSION)).thenReturn(Arrays.asList(policy1));
+
+        ToscaPolicy policy2 = makePolicy(POLICY_NAME, POLICY_VERSION2);
+        when(dao.getPolicyList(POLICY_NAME, POLICY_VERSION2)).thenReturn(Arrays.asList(policy2));
+
+        ToscaPolicyIdentifier ident2 = new ToscaPolicyIdentifier(POLICY_NAME, POLICY_VERSION2);
+
+        assertSame(policy1, session.getPolicy(ident));
+        assertSame(policy2, session.getPolicy(ident2));
+
+        // repeat
+        assertSame(policy1, session.getPolicy(ident));
+        assertSame(policy2, session.getPolicy(ident2));
+
+        assertSame(policy1, session.getPolicy(ident));
+        assertSame(policy2, session.getPolicy(ident2));
+
+        // should have only invoked this once for each policy
+        verify(dao, times(2)).getPolicyList(any(), any());
+    }
+
+    @Test
+    public void testGetPolicy_NotFound() throws Exception {
+        when(dao.getPolicyList(any(), any())).thenReturn(Collections.emptyList());
+
+        assertThatThrownBy(() -> session.getPolicy(ident)).hasMessage("cannot find policy: myPolicy 1.2.3");
+    }
+
+    @Test
+    public void testGetPolicy_TooMany() throws Exception {
+        ToscaPolicy policy = new ToscaPolicy();
+        when(dao.getPolicyList(any(), any())).thenReturn(Arrays.asList(policy, policy));
+
+        assertThatThrownBy(() -> session.getPolicy(ident)).hasMessage("too many policies match: myPolicy 1.2.3");
+    }
+
+    @Test
+    public void testGetPolicy_DaoEx() throws Exception {
+        PfModelException ex = new PfModelException(Status.INTERNAL_SERVER_ERROR, "expected exception");
+        when(dao.getPolicyList(any(), any())).thenThrow(ex);
+
+        assertThatThrownBy(() -> session.getPolicy(ident)).hasMessage("cannot get policy: myPolicy 1.2.3").hasCause(ex);
+    }
+
+    @Test
+    public void testAddUpdate() {
+        // several different updates, but one duplicate
+        PdpUpdate update1 = makeUpdate(PDP1);
+        session.addUpdate(update1);
+
+        PdpUpdate update2 = makeUpdate(PDP2);
+        session.addUpdate(update2);
+
+        PdpUpdate update3 = makeUpdate(PDP3);
+        session.addUpdate(update3);
+
+        List<PdpUpdate> lst = sort(session.getUpdates(), 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);
+        assertEquals(Arrays.asList(update1, update2, update3).toString(), lst.toString());
+    }
+
+    private ToscaPolicy makePolicy(String name, String version) {
+        ToscaPolicy policy = new ToscaPolicy();
+
+        policy.setName(name);
+        policy.setVersion(version);
+
+        return policy;
+    }
+
+    @Test
+    public void testGetPolicyMaxVersion() throws Exception {
+        ToscaPolicy policy1 = makePolicy(POLICY_NAME, POLICY_VERSION);
+
+        when(dao.getFilteredPolicyList(any())).thenReturn(Arrays.asList(policy1));
+
+        assertSame(policy1, session.getPolicyMaxVersion(POLICY_NAME));
+
+        // no matching policies - should throw an exception
+        when(dao.getFilteredPolicyList(any())).thenReturn(Collections.emptyList());
+        assertThatThrownBy(() -> session.getPolicyMaxVersion(POLICY_NAME)).hasMessage("cannot find policy: myPolicy");
+    }
+
+    @Test
+    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));
+
+        session.createPdpGroup(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);
+
+        List<List<PdpGroup>> creates = getGroupCreates(2);
+        assertEquals(group1, creates.get(0).get(0));
+        assertEquals(group2, creates.get(1).get(0));
+
+        assertTrue(session.isNewlyCreated(GROUP_NAME));
+        assertTrue(session.isNewlyCreated(GROUP_NAME2));
+    }
+
+    private PdpGroup makeGroup(String name, String version) {
+        PdpGroup group = new PdpGroup();
+
+        group.setName(name);
+        group.setVersion(version);
+
+        return group;
+    }
+
+    @Test
+    public void testGetPdpGroupMaxVersion() throws Exception {
+        PdpGroup group = makeGroup(GROUP_NAME, GROUP_VERSION);
+        when(dao.getFilteredPdpGroups(any())).thenReturn(Arrays.asList(group));
+
+        assertEquals(group, session.getPdpGroupMaxVersion(GROUP_NAME));
+
+        // try empty list
+        when(dao.getFilteredPdpGroups(any())).thenReturn(Collections.emptyList());
+        assertThatThrownBy(() -> session.getPdpGroupMaxVersion(GROUP_NAME))
+                        .isInstanceOf(PolicyPapRuntimeException.class).hasMessage("cannot find group: group");
+    }
+
+    @Test
+    public void testGetActivePdpGroupsByPolicyType() throws Exception {
+        List<PdpGroup> groups =
+                        Arrays.asList(makeGroup(GROUP_NAME, GROUP_VERSION), makeGroup(GROUP_NAME2, GROUP_VERSION2));
+        when(dao.getFilteredPdpGroups(any())).thenReturn(groups);
+
+        assertEquals(groups, session
+                        .getActivePdpGroupsByPolicyType(new ToscaPolicyTypeIdentifier(POLICY_NAME, POLICY_VERSION)));
+    }
+
+    @Test
+    public void testUpdatePdpGroup() throws Exception {
+        PdpGroup group = makeGroup(GROUP_NAME, GROUP_VERSION);
+        when(dao.updatePdpGroups(any())).thenReturn(Arrays.asList(group));
+
+        session.updatePdpGroup(group);
+
+        List<PdpGroup> updates = getGroupUpdates(1).get(0);
+        assertEquals(group, updates.get(0));
+    }
+
+    private PdpUpdate makeUpdate(String pdpName) {
+        PdpUpdate update = new PdpUpdate();
+
+        update.setName(pdpName);
+
+        return update;
+    }
+
+    private <T> List<T> sort(Collection<T> collection, Comparator<T> comparator) {
+        List<T> lst = new ArrayList<>(collection);
+        Collections.sort(lst, comparator);
+
+        return lst;
+    }
+
+    private int compare(PdpUpdate left, PdpUpdate right) {
+        return left.getName().compareTo(right.getName());
+    }
+}
diff --git a/main/src/test/resources/simpleDeploy/daoPolicyList.json b/main/src/test/resources/simpleDeploy/daoPolicyList.json
new file mode 100644 (file)
index 0000000..93ee914
--- /dev/null
@@ -0,0 +1,10 @@
+{
+    "policies":  [
+        {
+            "name": "policyA",
+            "version": "1.2.3",
+            "type": "typeA",
+            "typeVersion": "100.2.3"
+        }
+    ]
+}
diff --git a/main/src/test/resources/simpleDeploy/emptyGroups.json b/main/src/test/resources/simpleDeploy/emptyGroups.json
new file mode 100644 (file)
index 0000000..44e05c8
--- /dev/null
@@ -0,0 +1,3 @@
+{
+    "groups": []
+}
diff --git a/main/src/test/resources/simpleDeploy/emptyRequest.json b/main/src/test/resources/simpleDeploy/emptyRequest.json
new file mode 100644 (file)
index 0000000..4c458a3
--- /dev/null
@@ -0,0 +1,3 @@
+{
+    "policies": []
+}
diff --git a/main/src/test/resources/simpleDeploy/emptyRequestBase.json b/main/src/test/resources/simpleDeploy/emptyRequestBase.json
new file mode 100644 (file)
index 0000000..2c63c08
--- /dev/null
@@ -0,0 +1,2 @@
+{
+}
diff --git a/main/src/test/resources/simpleDeploy/getGroupDao.json b/main/src/test/resources/simpleDeploy/getGroupDao.json
new file mode 100644 (file)
index 0000000..2e74d1b
--- /dev/null
@@ -0,0 +1,84 @@
+{
+    "groups": [
+        {
+            "name": "groupA",
+            "version": "0.0.0",
+            "pdpSubgroups": [
+                {
+                    "pdpType": "pdpTypeA",
+                    "supportedPolicyTypes": [
+                        {
+                            "name": "typeA",
+                            "version": "100.2.3"
+                        }
+                    ],
+                    "pdpInstances": [
+                        {
+                            "instanceId": "pdpA"
+                        }
+                    ]
+                }
+            ]
+        },
+        {
+            "name": "groupA",
+            "version": "200.2.3",
+            "pdpSubgroups": [
+                {
+                    "pdpType": "pdpTypeA",
+                    "supportedPolicyTypes": [
+                        {
+                            "name": "typeA",
+                            "version": "100.2.3"
+                        }
+                    ],
+                    "pdpInstances": [
+                        {
+                            "instanceId": "pdpA"
+                        }
+                    ]
+                }
+            ]
+        },
+        {
+            "name": "groupA",
+            "version": "0.0.1",
+            "pdpSubgroups": [
+                {
+                    "pdpType": "pdpTypeA",
+                    "supportedPolicyTypes": [
+                        {
+                            "name": "typeA",
+                            "version": "100.2.3"
+                        }
+                    ],
+                    "pdpInstances": [
+                        {
+                            "instanceId": "pdpA"
+                        }
+                    ]
+                }
+            ]
+        },
+        {
+            "name": "groupA",
+            "version": "non-numeric-version",
+            "pdpSubgroups": [
+                {
+                    "pdpType": "pdpTypeA",
+                    "supportedPolicyTypes": [
+                        {
+                            "name": "typeA",
+                            "version": "100.2.3"
+                        }
+                    ],
+                    "pdpInstances": [
+                        {
+                            "instanceId": "pdpA"
+                        }
+                    ]
+                }
+            ]
+        }
+    ]
+}
diff --git a/main/src/test/resources/simpleDeploy/getPolicyReqNullVersion.json b/main/src/test/resources/simpleDeploy/getPolicyReqNullVersion.json
new file mode 100644 (file)
index 0000000..bf2d132
--- /dev/null
@@ -0,0 +1,7 @@
+{
+    "policies": [
+        {
+            "name": "policyA"
+        }
+    ]
+}
diff --git a/main/src/test/resources/simpleDeploy/groups.json b/main/src/test/resources/simpleDeploy/groups.json
new file mode 100644 (file)
index 0000000..7fd7684
--- /dev/null
@@ -0,0 +1,25 @@
+{
+    "groups": [
+        {
+            "name": "groupA",
+            "version": "200.2.3",
+            "pdpSubgroups": [
+                {
+                    "pdpType": "pdpTypeA",
+                    "supportedPolicyTypes": [
+                        {
+                            "name": "typeA",
+                            "version": "100.2.3"
+                        }
+                    ],
+                    "pdpInstances": [
+                        {
+                            "instanceId": "pdpA"
+                        }
+                    ],
+                    "policies": []
+                }
+            ]
+        }
+    ]
+}
diff --git a/main/src/test/resources/simpleDeploy/policy.json b/main/src/test/resources/simpleDeploy/policy.json
new file mode 100644 (file)
index 0000000..7786aab
--- /dev/null
@@ -0,0 +1,6 @@
+{
+    "name": "policyA",
+    "version": "1.2.3",
+    "type": "typeA",
+    "typeVersion": "100.2.3"
+}
diff --git a/main/src/test/resources/simpleDeploy/request.json b/main/src/test/resources/simpleDeploy/request.json
new file mode 100644 (file)
index 0000000..060637c
--- /dev/null
@@ -0,0 +1,8 @@
+{
+    "policies": [
+        {
+            "name": "policyA",
+            "version": "1.2.3"
+        }
+    ]
+}
diff --git a/main/src/test/resources/simpleDeploy/requestBase.json b/main/src/test/resources/simpleDeploy/requestBase.json
new file mode 100644 (file)
index 0000000..67fcdcb
--- /dev/null
@@ -0,0 +1,4 @@
+{
+    "name": "policyA",
+    "version": "1.2.3"
+}
diff --git a/main/src/test/resources/simpleDeploy/updateGroupReqMultiple.json b/main/src/test/resources/simpleDeploy/updateGroupReqMultiple.json
new file mode 100644 (file)
index 0000000..3d4684c
--- /dev/null
@@ -0,0 +1,20 @@
+{
+    "policies": [
+        {
+            "name": "policyA",
+            "version": "1.2.3"
+        },
+        {
+            "name": "policyB",
+            "version": "1.2.3"
+        },
+        {
+            "name": "policyC",
+            "version": "1.2.3"
+        },
+        {
+            "name": "policyD",
+            "version": "1.2.3"
+        }
+    ]
+}
diff --git a/main/src/test/resources/simpleDeploy/upgradeGroupDao.json b/main/src/test/resources/simpleDeploy/upgradeGroupDao.json
new file mode 100644 (file)
index 0000000..278b69a
--- /dev/null
@@ -0,0 +1,72 @@
+{
+    "groups": [
+        {
+            "name": "groupA",
+            "version": "200.2.3",
+            "pdpSubgroups": [
+                {
+                    "pdpType": "pdpTypeA",
+                    "supportedPolicyTypes": [],
+                    "pdpInstances": [
+                        {
+                            "instanceId": "pdpA"
+                        }
+                    ],
+                    "policies": []
+                },
+                {
+                    "pdpType": "pdpTypeB",
+                    "supportedPolicyTypes": [
+                        {
+                            "name": "typeA",
+                            "version": "100.2.3"
+                        }
+                    ],
+                    "pdpInstances": [
+                        {
+                            "instanceId": "pdpB"
+                        }
+                    ],
+                    "policies": []
+                },
+                {
+                    "pdpType": "pdpTypeC",
+                    "supportedPolicyTypes": [
+                        {
+                            "name": "typeA",
+                            "version": "100.2.3"
+                        }
+                    ],
+                    "pdpInstances": [
+                        {
+                            "instanceId": "pdpC"
+                        }
+                    ],
+                    "policies": [
+                        {
+                            "name": "policyA",
+                            "version": "1.2.3",
+                            "type": "typeA",
+                            "typeVersion": "100.2.3"
+                        }
+                    ]
+                },
+                {
+                    "pdpType": "pdpTypeD",
+                    "supportedPolicyTypes": [
+                        {
+                            "name": "typeA",
+                            "version": "100.2.3"
+                        }
+                    ],
+                    "pdpInstances": [
+                        {
+                            "instanceId": "pdpD"
+                        }
+                    ],
+                    "policies": []
+                }
+            ]
+        }
+    ]
+}
diff --git a/main/src/test/resources/simpleDeploy/upgradeGroupGroup1.json b/main/src/test/resources/simpleDeploy/upgradeGroupGroup1.json
new file mode 100644 (file)
index 0000000..a63eadd
--- /dev/null
@@ -0,0 +1,40 @@
+{
+    "groups": [
+        {
+            "name": "groupA",
+            "version": "200.2.3",
+            "pdpSubgroups": [
+                {
+                    "pdpType": "pdpTypeA",
+                    "supportedPolicyTypes": [
+                        {
+                            "name": "typeA",
+                            "version": "100.2.3"
+                        }
+                    ],
+                    "pdpInstances": [
+                        {
+                            "instanceId": "pdpA"
+                        }
+                    ],
+                    "policies": []
+                },
+                {
+                    "pdpType": "pdpTypeC",
+                    "supportedPolicyTypes": [
+                        {
+                            "name": "typeC",
+                            "version": "100.2.3"
+                        }
+                    ],
+                    "pdpInstances": [
+                        {
+                            "instanceId": "pdpC"
+                        }
+                    ],
+                    "policies": []
+                }
+            ]
+        }
+    ]
+}
diff --git a/main/src/test/resources/simpleDeploy/upgradeGroupGroup2.json b/main/src/test/resources/simpleDeploy/upgradeGroupGroup2.json
new file mode 100644 (file)
index 0000000..d494657
--- /dev/null
@@ -0,0 +1,25 @@
+{
+    "groups": [
+        {
+            "name": "groupB",
+            "version": "300.2.3",
+            "pdpSubgroups": [
+                {
+                    "pdpType": "pdpTypeB",
+                    "supportedPolicyTypes": [
+                        {
+                            "name": "typeB",
+                            "version": "100.2.3"
+                        }
+                    ],
+                    "pdpInstances": [
+                        {
+                            "instanceId": "pdpB"
+                        }
+                    ],
+                    "policies": []
+                }
+            ]
+        }
+    ]
+}
diff --git a/main/src/test/resources/simpleDeploy/upgradeGroupPolicy2.json b/main/src/test/resources/simpleDeploy/upgradeGroupPolicy2.json
new file mode 100644 (file)
index 0000000..3a13d0c
--- /dev/null
@@ -0,0 +1,10 @@
+{
+    "policies":  [
+        {
+            "name": "policyB",
+            "version": "1.2.3",
+            "type": "typeB",
+            "typeVersion": "100.2.3"
+        }
+    ]
+}
diff --git a/main/src/test/resources/simpleDeploy/upgradeGroupPolicy3.json b/main/src/test/resources/simpleDeploy/upgradeGroupPolicy3.json
new file mode 100644 (file)
index 0000000..bf5602e
--- /dev/null
@@ -0,0 +1,10 @@
+{
+    "policies":  [
+        {
+            "name": "policyC",
+            "version": "1.2.3",
+            "type": "typeC",
+            "typeVersion": "100.2.3"
+        }
+    ]
+}
diff --git a/main/src/test/resources/simpleDeploy/upgradeGroupPolicy4.json b/main/src/test/resources/simpleDeploy/upgradeGroupPolicy4.json
new file mode 100644 (file)
index 0000000..3c0fb72
--- /dev/null
@@ -0,0 +1,10 @@
+{
+    "policies":  [
+        {
+            "name": "policyD",
+            "version": "1.2.3",
+            "type": "typeA",
+            "typeVersion": "100.2.3"
+        }
+    ]
+}
diff --git a/main/src/test/resources/simpleDeploy/upgradeGroup_NoPdpsDao.json b/main/src/test/resources/simpleDeploy/upgradeGroup_NoPdpsDao.json
new file mode 100644 (file)
index 0000000..72563d4
--- /dev/null
@@ -0,0 +1,21 @@
+{
+    "groups": [
+        {
+            "name": "groupA",
+            "version": "200.2.3",
+            "pdpSubgroups": [
+                {
+                    "pdpType": "pdpTypeA",
+                    "supportedPolicyTypes": [
+                        {
+                            "name": "typeA",
+                            "version": "100.2.3"
+                        }
+                    ],
+                    "pdpInstances": [],
+                    "policies": []
+                }
+            ]
+        }
+    ]
+}
diff --git a/main/src/test/resources/simpleDeploy/upgradeGroup_NothingUpdatedDao.json b/main/src/test/resources/simpleDeploy/upgradeGroup_NothingUpdatedDao.json
new file mode 100644 (file)
index 0000000..60d6a68
--- /dev/null
@@ -0,0 +1,25 @@
+{
+    "groups": [
+        {
+            "name": "groupA",
+            "version": "200.2.3",
+            "pdpSubgroups": [
+                {
+                    "pdpType": "pdpTypeB",
+                    "supportedPolicyTypes": [
+                        {
+                            "name": "typeX",
+                            "version": "100.2.3"
+                        }
+                    ],
+                    "pdpInstances": [
+                        {
+                            "instanceId": "pdpB"
+                        }
+                    ],
+                    "policies": []
+                }
+            ]
+        }
+    ]
+}