From 6e96359492029ca9309ea367372ab81bf396bdde Mon Sep 17 00:00:00 2001 From: Jim Hahn Date: Tue, 3 Dec 2019 10:15:31 -0500 Subject: Move deploy/undeploy REST classes Moved classes from rest.depundep to rest, as they will no longer be specific to deploy/undeploy. Change-Id: Iea7c4e35fcd00ed83e678f7cd980e0aa9659f18e Issue-ID: POLICY-1866 Signed-off-by: Jim Hahn --- .../org/onap/policy/pap/main/rest/GroupData.java | 107 +++ .../pap/main/rest/PdpGroupDeleteControllerV1.java | 194 +++++ .../pap/main/rest/PdpGroupDeleteProvider.java | 167 ++++ .../pap/main/rest/PdpGroupDeployControllerV1.java | 152 ++++ .../pap/main/rest/PdpGroupDeployProvider.java | 710 ++++++++++++++++ .../policy/pap/main/rest/PolicyUndeployerImpl.java | 121 +++ .../onap/policy/pap/main/rest/ProviderBase.java | 287 +++++++ .../org/onap/policy/pap/main/rest/SessionData.java | 507 +++++++++++ .../policy/pap/main/rest/depundep/GroupData.java | 107 --- .../rest/depundep/PdpGroupDeleteControllerV1.java | 195 ----- .../main/rest/depundep/PdpGroupDeleteProvider.java | 167 ---- .../rest/depundep/PdpGroupDeployControllerV1.java | 153 ---- .../main/rest/depundep/PdpGroupDeployProvider.java | 710 ---------------- .../main/rest/depundep/PolicyUndeployerImpl.java | 121 --- .../pap/main/rest/depundep/ProviderBase.java | 287 ------- .../policy/pap/main/rest/depundep/SessionData.java | 507 ----------- .../policy/pap/main/startstop/PapActivator.java | 6 +- .../onap/policy/pap/main/rest/ProviderSuper.java | 276 ++++++ .../onap/policy/pap/main/rest/TestGroupData.java | 103 +++ .../main/rest/TestPdpGroupDeleteControllerV1.java | 104 +++ .../pap/main/rest/TestPdpGroupDeleteProvider.java | 297 +++++++ .../main/rest/TestPdpGroupDeployControllerV1.java | 112 +++ .../pap/main/rest/TestPdpGroupDeployProvider.java | 932 +++++++++++++++++++++ .../pap/main/rest/TestPolicyUndeployerImpl.java | 200 +++++ .../policy/pap/main/rest/TestProviderBase.java | 392 +++++++++ .../onap/policy/pap/main/rest/TestSessionData.java | 662 +++++++++++++++ .../pap/main/rest/depundep/ProviderSuper.java | 276 ------ .../pap/main/rest/depundep/TestGroupData.java | 103 --- .../depundep/TestPdpGroupDeleteControllerV1.java | 105 --- .../rest/depundep/TestPdpGroupDeleteProvider.java | 297 ------- .../depundep/TestPdpGroupDeployControllerV1.java | 113 --- .../rest/depundep/TestPdpGroupDeployProvider.java | 932 --------------------- .../rest/depundep/TestPolicyUndeployerImpl.java | 200 ----- .../pap/main/rest/depundep/TestProviderBase.java | 392 --------- .../pap/main/rest/depundep/TestSessionData.java | 662 --------------- 35 files changed, 5326 insertions(+), 5330 deletions(-) create mode 100644 main/src/main/java/org/onap/policy/pap/main/rest/GroupData.java create mode 100644 main/src/main/java/org/onap/policy/pap/main/rest/PdpGroupDeleteControllerV1.java create mode 100644 main/src/main/java/org/onap/policy/pap/main/rest/PdpGroupDeleteProvider.java create mode 100644 main/src/main/java/org/onap/policy/pap/main/rest/PdpGroupDeployControllerV1.java create mode 100644 main/src/main/java/org/onap/policy/pap/main/rest/PdpGroupDeployProvider.java create mode 100644 main/src/main/java/org/onap/policy/pap/main/rest/PolicyUndeployerImpl.java create mode 100644 main/src/main/java/org/onap/policy/pap/main/rest/ProviderBase.java create mode 100644 main/src/main/java/org/onap/policy/pap/main/rest/SessionData.java delete mode 100644 main/src/main/java/org/onap/policy/pap/main/rest/depundep/GroupData.java delete mode 100644 main/src/main/java/org/onap/policy/pap/main/rest/depundep/PdpGroupDeleteControllerV1.java delete mode 100644 main/src/main/java/org/onap/policy/pap/main/rest/depundep/PdpGroupDeleteProvider.java delete mode 100644 main/src/main/java/org/onap/policy/pap/main/rest/depundep/PdpGroupDeployControllerV1.java delete mode 100644 main/src/main/java/org/onap/policy/pap/main/rest/depundep/PdpGroupDeployProvider.java delete mode 100644 main/src/main/java/org/onap/policy/pap/main/rest/depundep/PolicyUndeployerImpl.java delete mode 100644 main/src/main/java/org/onap/policy/pap/main/rest/depundep/ProviderBase.java delete mode 100644 main/src/main/java/org/onap/policy/pap/main/rest/depundep/SessionData.java create mode 100644 main/src/test/java/org/onap/policy/pap/main/rest/ProviderSuper.java create mode 100644 main/src/test/java/org/onap/policy/pap/main/rest/TestGroupData.java create mode 100644 main/src/test/java/org/onap/policy/pap/main/rest/TestPdpGroupDeleteControllerV1.java create mode 100644 main/src/test/java/org/onap/policy/pap/main/rest/TestPdpGroupDeleteProvider.java create mode 100644 main/src/test/java/org/onap/policy/pap/main/rest/TestPdpGroupDeployControllerV1.java create mode 100644 main/src/test/java/org/onap/policy/pap/main/rest/TestPdpGroupDeployProvider.java create mode 100644 main/src/test/java/org/onap/policy/pap/main/rest/TestPolicyUndeployerImpl.java create mode 100644 main/src/test/java/org/onap/policy/pap/main/rest/TestProviderBase.java create mode 100644 main/src/test/java/org/onap/policy/pap/main/rest/TestSessionData.java delete mode 100644 main/src/test/java/org/onap/policy/pap/main/rest/depundep/ProviderSuper.java delete mode 100644 main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestGroupData.java delete mode 100644 main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestPdpGroupDeleteControllerV1.java delete mode 100644 main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestPdpGroupDeleteProvider.java delete mode 100644 main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestPdpGroupDeployControllerV1.java delete mode 100644 main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestPdpGroupDeployProvider.java delete mode 100644 main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestPolicyUndeployerImpl.java delete mode 100644 main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestProviderBase.java delete mode 100644 main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestSessionData.java (limited to 'main/src') diff --git a/main/src/main/java/org/onap/policy/pap/main/rest/GroupData.java b/main/src/main/java/org/onap/policy/pap/main/rest/GroupData.java new file mode 100644 index 00000000..511688f9 --- /dev/null +++ b/main/src/main/java/org/onap/policy/pap/main/rest/GroupData.java @@ -0,0 +1,107 @@ +/* + * ============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 lombok.Getter; +import org.onap.policy.models.pdp.concepts.PdpGroup; + +/** + * PdpGroup data, only the latest copy of the group is retained. + */ +public class GroupData { + @Getter + private PdpGroup group; + + private enum State { + UNCHANGED, CREATED, UPDATED + } + + /** + * State of the group. + */ + private State state; + + + /** + * Constructs the object, for an existing group. + * + * @param group the group that is in the DB + */ + public GroupData(PdpGroup group) { + this(group, false); + } + + /** + * Constructs the object. + * + * @param group the group that is in, or to be added to, the DB + * @param isNew {@code true} if this is a new group, {@code false} otherwise + */ + public GroupData(PdpGroup group, boolean isNew) { + this.group = group; + this.state = (isNew ? State.CREATED : State.UNCHANGED); + } + + /** + * Determines if the group is unchanged (i.e., neither new nor updated). + * + * @return {@code true} if the group is unchanged, {@code false} otherwise + */ + public boolean isUnchanged() { + return (state == State.UNCHANGED); + } + + /** + * Determines if the group is new. + * + * @return {@code true} if the group is new, {@code false} otherwise + */ + public boolean isNew() { + return (state == State.CREATED); + } + + /** + * Determines if the group has been updated. + * + * @return {@code true} if the group has been updated, {@code false} otherwise + */ + public boolean isUpdated() { + return (state == State.UPDATED); + } + + /** + * Updates the group to the new value. + * + * @param newGroup the updated group + */ + public void update(PdpGroup newGroup) { + if (!this.group.getName().equals(newGroup.getName())) { + throw new IllegalArgumentException( + "expected group " + this.group.getName() + ", but received " + newGroup.getName()); + } + + this.group = newGroup; + + if (state == State.UNCHANGED) { + state = State.UPDATED; + } + } +} diff --git a/main/src/main/java/org/onap/policy/pap/main/rest/PdpGroupDeleteControllerV1.java b/main/src/main/java/org/onap/policy/pap/main/rest/PdpGroupDeleteControllerV1.java new file mode 100644 index 00000000..80dcda35 --- /dev/null +++ b/main/src/main/java/org/onap/policy/pap/main/rest/PdpGroupDeleteControllerV1.java @@ -0,0 +1,194 @@ +/* + * ============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 io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +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.DELETE; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import org.onap.policy.models.base.PfModelException; +import org.onap.policy.models.base.PfModelRuntimeException; +import org.onap.policy.models.pap.concepts.PdpGroupDeleteResponse; +import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyIdentifierOptVersion; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Class to provide REST end points for PAP component to delete a PDP group. + */ +public class PdpGroupDeleteControllerV1 extends PapRestControllerV1 { + private static final Logger logger = LoggerFactory.getLogger(PdpGroupDeleteControllerV1.class); + + private final PdpGroupDeleteProvider provider = new PdpGroupDeleteProvider(); + + /** + * Deletes a PDP group. + * + * @param requestId request ID used in ONAP logging + * @param groupName name of the PDP group to be deleted + * @return a response + */ + // @formatter:off + @DELETE + @Path("pdps/groups/{name}") + @ApiOperation(value = "Delete PDP Group", + notes = "Deletes a PDP Group, returning optional error details", + response = PdpGroupDeleteResponse.class, + tags = {"Policy Administration (PAP) API"}, + authorizations = @Authorization(value = AUTHORIZATION_TYPE), + responseHeaders = { + @ResponseHeader(name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION, + response = String.class), + @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION, + response = String.class), + @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION, + response = String.class), + @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION, + response = UUID.class)}, + extensions = {@Extension(name = EXTENSION_NAME, + properties = {@ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION), + @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)})}) + @ApiResponses(value = {@ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE), + @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE), + @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)}) + // @formatter:on + + public Response deleteGroup(@HeaderParam(REQUEST_ID_NAME) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId, + @ApiParam(value = "PDP Group Name", required = true) @PathParam("name") String groupName) { + + return doOperation(requestId, "delete group failed", () -> provider.deleteGroup(groupName)); + } + + /** + * Undeploys the latest version of a policy from the PDPs. + * + * @param requestId request ID used in ONAP logging + * @param policyName name of the PDP Policy to be deleted + * @return a response + */ + // @formatter:off + @DELETE + @Path("pdps/policies/{name}") + @ApiOperation(value = "Undeploy a PDP Policy from PDPs", + notes = "Undeploys the latest version of a policy from the PDPs, returning optional error details", + response = PdpGroupDeleteResponse.class, + tags = {"Policy Administration (PAP) API"}, + authorizations = @Authorization(value = AUTHORIZATION_TYPE), + responseHeaders = { + @ResponseHeader(name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION, + response = String.class), + @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION, + response = String.class), + @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION, + response = String.class), + @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION, + response = UUID.class)}, + extensions = {@Extension(name = EXTENSION_NAME, + properties = {@ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION), + @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)})}) + @ApiResponses(value = {@ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE), + @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE), + @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)}) + // @formatter:on + + public Response deletePolicy(@HeaderParam(REQUEST_ID_NAME) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId, + @ApiParam(value = "PDP Policy Name", required = true) @PathParam("name") String policyName) { + + return doOperation(requestId, "undeploy policy failed", + () -> provider.undeploy(new ToscaPolicyIdentifierOptVersion(policyName, null))); + } + + /** + * Undeploys a specific version of a policy from the PDPs. + * + * @param requestId request ID used in ONAP logging + * @param policyName name of the PDP Policy to be deleted + * @param version version to be deleted + * @return a response + */ + // @formatter:off + @DELETE + @Path("pdps/policies/{name}/versions/{version}") + @ApiOperation(value = "Undeploy version of a PDP Policy from PDPs", + notes = "Undeploys a specific version of a policy from the PDPs, returning optional error details", + response = PdpGroupDeleteResponse.class, + tags = {"Policy Administration (PAP) API"}, + authorizations = @Authorization(value = AUTHORIZATION_TYPE), + responseHeaders = { + @ResponseHeader(name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION, + response = String.class), + @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION, + response = String.class), + @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION, + response = String.class), + @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION, + response = UUID.class)}, + extensions = {@Extension(name = EXTENSION_NAME, + properties = {@ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION), + @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)})}) + @ApiResponses(value = {@ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE), + @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE), + @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)}) + // @formatter:on + + public Response deletePolicyVersion( + @HeaderParam(REQUEST_ID_NAME) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId, + @ApiParam(value = "PDP Policy Name", required = true) @PathParam("name") String policyName, + @ApiParam(value = "PDP Policy Version", required = true) @PathParam("version") String version) { + + return doOperation(requestId, "undeploy policy failed", + () -> provider.undeploy(new ToscaPolicyIdentifierOptVersion(policyName, version))); + } + + /** + * Invokes an operation. + * + * @param requestId request ID + * @param errmsg error message to log if the operation throws an exception + * @param runnable operation to invoke + * @return a {@link PdpGroupDeleteResponse} response entity + */ + private Response doOperation(UUID requestId, String errmsg, RunnableWithPfEx runnable) { + try { + runnable.run(); + return addLoggingHeaders(addVersionControlHeaders(Response.status(Status.OK)), requestId) + .entity(new PdpGroupDeleteResponse()).build(); + + } catch (PfModelException | PfModelRuntimeException e) { + logger.warn(errmsg, e); + PdpGroupDeleteResponse resp = new PdpGroupDeleteResponse(); + resp.setErrorDetails(e.getErrorResponse().getErrorMessage()); + return addLoggingHeaders(addVersionControlHeaders(Response.status(e.getErrorResponse().getResponseCode())), + requestId).entity(resp).build(); + } + } +} diff --git a/main/src/main/java/org/onap/policy/pap/main/rest/PdpGroupDeleteProvider.java b/main/src/main/java/org/onap/policy/pap/main/rest/PdpGroupDeleteProvider.java new file mode 100644 index 00000000..931ad7f0 --- /dev/null +++ b/main/src/main/java/org/onap/policy/pap/main/rest/PdpGroupDeleteProvider.java @@ -0,0 +1,167 @@ +/* + * ============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 java.util.Iterator; +import java.util.Set; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import javax.ws.rs.core.Response.Status; +import org.onap.policy.models.base.PfModelException; +import org.onap.policy.models.pdp.concepts.Pdp; +import org.onap.policy.models.pdp.concepts.PdpGroup; +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.models.tosca.authorative.concepts.ToscaPolicyIdentifierOptVersion; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Provider for PAP component to delete PDP groups. + */ +public class PdpGroupDeleteProvider extends ProviderBase { + private static final Logger logger = LoggerFactory.getLogger(PdpGroupDeleteProvider.class); + + + /** + * Constructs the object. + */ + public PdpGroupDeleteProvider() { + super(); + } + + /** + * Deletes a PDP group. + * + * @param groupName name of the PDP group to be deleted + * @throws PfModelException if an error occurred + */ + public void deleteGroup(String groupName) throws PfModelException { + process(groupName, this::deleteGroup); + } + + /** + * Deletes a PDP group. + * + * @param data session data + * @param groupName name of the PDP group to be deleted + * @throws PfModelException if an error occurred + */ + private void deleteGroup(SessionData data, String groupName) throws PfModelException { + try { + PdpGroup group = data.getGroup(groupName); + if (group == null) { + throw new PfModelException(Status.NOT_FOUND, "group not found"); + } + + if (group.getPdpGroupState() == PdpState.ACTIVE) { + throw new PfModelException(Status.BAD_REQUEST, "group is still " + PdpState.ACTIVE); + } + + data.deleteGroupFromDb(group); + + } catch (PfModelException | RuntimeException e) { + // no need to log the error object here, as it will be logged by the invoker + logger.warn("failed to delete group: {}", groupName); + throw e; + } + } + + /** + * Undeploys a policy. + * + * @param policyIdent identifier of the policy to be undeployed + * @throws PfModelException if an error occurred + */ + public void undeploy(ToscaPolicyIdentifierOptVersion policyIdent) throws PfModelException { + process(policyIdent, this::undeployPolicy); + } + + /** + * Undeploys a policy from its groups. + * + * @param data session data + * @param ident identifier of the policy to be deleted + * @throws PfModelException if an error occurred + */ + private void undeployPolicy(SessionData data, ToscaPolicyIdentifierOptVersion ident) throws PfModelException { + try { + processPolicy(data, ident); + + if (data.isUnchanged()) { + throw new PfModelException(Status.BAD_REQUEST, "policy does not appear in any PDP group: " + + ident.getName() + " " + ident.getVersion()); + } + + } catch (PfModelException | RuntimeException e) { + // no need to log the error object here, as it will be logged by the invoker + logger.warn("failed to undeploy policy: {}", ident); + throw e; + } + } + + /** + * Returns a function that will remove the desired policy from a subgroup. + */ + @Override + protected Updater makeUpdater(SessionData data, ToscaPolicy policy, + ToscaPolicyIdentifierOptVersion desiredIdent) { + + // construct a matcher based on whether or not the version was specified + Predicate matcher; + + if (desiredIdent.getVersion() != null) { + // version was specified - match the whole identifier + matcher = policy.getIdentifier()::equals; + + } else { + // version was not specified - match the name only + String desnm = desiredIdent.getName(); + matcher = ident -> ident.getName().equals(desnm); + } + + + // return a function that will remove the policy from the subgroup + return (group, subgroup) -> { + + Set pdps = subgroup.getPdpInstances().stream().map(Pdp::getInstanceId).collect(Collectors.toSet()); + + boolean result = false; + + Iterator iter = subgroup.getPolicies().iterator(); + while (iter.hasNext()) { + ToscaPolicyIdentifier ident = iter.next(); + + if (matcher.test(ident)) { + result = true; + iter.remove(); + logger.info("remove policy {} {} from subgroup {} {} count={}", ident.getName(), ident.getVersion(), + group.getName(), subgroup.getPdpType(), subgroup.getPolicies().size()); + + data.trackUndeploy(ident, pdps); + } + } + + return result; + }; + } +} diff --git a/main/src/main/java/org/onap/policy/pap/main/rest/PdpGroupDeployControllerV1.java b/main/src/main/java/org/onap/policy/pap/main/rest/PdpGroupDeployControllerV1.java new file mode 100644 index 00000000..59fe38aa --- /dev/null +++ b/main/src/main/java/org/onap/policy/pap/main/rest/PdpGroupDeployControllerV1.java @@ -0,0 +1,152 @@ +/* + * ============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 io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +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.onap.policy.models.base.PfModelException; +import org.onap.policy.models.base.PfModelRuntimeException; +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.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Class to provide REST end points for PAP component to deploy a PDP group. + */ +public class PdpGroupDeployControllerV1 extends PapRestControllerV1 { + private static final Logger logger = LoggerFactory.getLogger(PdpGroupDeployControllerV1.class); + + private final PdpGroupDeployProvider provider = new PdpGroupDeployProvider(); + + /** + * Deploys or updates a PDP group. + * + * @param requestId request ID used in ONAP logging + * @param groups PDP group configuration + * @return a response + */ + // @formatter:off + @POST + @Path("pdps") + @ApiOperation(value = "Deploy or update PDP Groups", + notes = "Deploys or updates a PDP Group, returning optional error details", + response = PdpGroupDeployResponse.class, + tags = {"Policy Administration (PAP) API"}, + authorizations = @Authorization(value = AUTHORIZATION_TYPE), + responseHeaders = { + @ResponseHeader(name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION, + response = String.class), + @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION, + response = String.class), + @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION, + response = String.class), + @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION, + response = UUID.class)}, + extensions = {@Extension(name = EXTENSION_NAME, + properties = {@ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION), + @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)})}) + @ApiResponses(value = {@ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE), + @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE), + @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)}) + // @formatter:on + + public Response deployGroup(@HeaderParam(REQUEST_ID_NAME) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId, + @ApiParam(value = "List of PDP Group Configuration", required = true) PdpGroups groups) { + + return doOperation(requestId, "create groups failed", () -> provider.createOrUpdateGroups(groups)); + } + + /** + * Deploys or updates PDP policies. + * + * @param requestId request ID used in ONAP logging + * @param policies PDP policies + * @return a response + */ + // @formatter:off + @POST + @Path("pdps/policies") + @ApiOperation(value = "Deploy or update PDP Policies", + notes = "Deploys or updates PDP Policies, returning optional error details", + response = PdpGroupDeployResponse.class, + tags = {"Policy Administration (PAP) API"}, + authorizations = @Authorization(value = AUTHORIZATION_TYPE), + responseHeaders = { + @ResponseHeader(name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION, + response = String.class), + @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION, + response = String.class), + @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION, + response = String.class), + @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION, + response = UUID.class)}, + extensions = {@Extension(name = EXTENSION_NAME, + properties = {@ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION), + @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)})}) + @ApiResponses(value = {@ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE), + @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE), + @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)}) + // @formatter:on + + public Response deployPolicies(@HeaderParam(REQUEST_ID_NAME) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId, + @ApiParam(value = "PDP Policies; only the name is required", + required = true) PdpDeployPolicies policies) { + + return doOperation(requestId, "deploy policies failed", () -> provider.deployPolicies(policies)); + } + + /** + * Invokes an operation. + * + * @param requestId request ID + * @param errmsg error message to log if the operation throws an exception + * @param runnable operation to invoke + * @return a {@link PdpGroupDeployResponse} response entity + */ + private Response doOperation(UUID requestId, String errmsg, RunnableWithPfEx runnable) { + try { + runnable.run(); + return addLoggingHeaders(addVersionControlHeaders(Response.status(Status.OK)), requestId) + .entity(new PdpGroupDeployResponse()).build(); + + } catch (PfModelException | PfModelRuntimeException e) { + logger.warn(errmsg, e); + PdpGroupDeployResponse resp = new PdpGroupDeployResponse(); + resp.setErrorDetails(e.getErrorResponse().getErrorMessage()); + return addLoggingHeaders(addVersionControlHeaders(Response.status(e.getErrorResponse().getResponseCode())), + requestId).entity(resp).build(); + } + } +} 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 new file mode 100644 index 00000000..af1aab6f --- /dev/null +++ b/main/src/main/java/org/onap/policy/pap/main/rest/PdpGroupDeployProvider.java @@ -0,0 +1,710 @@ +/* + * ============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 com.att.aft.dme2.internal.apache.commons.lang.ObjectUtils; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Consumer; +import java.util.stream.Collectors; +import javax.ws.rs.core.Response.Status; +import org.onap.policy.common.parameters.BeanValidationResult; +import org.onap.policy.common.parameters.ObjectValidationResult; +import org.onap.policy.common.parameters.ValidationResult; +import org.onap.policy.common.parameters.ValidationStatus; +import org.onap.policy.common.utils.services.Registry; +import org.onap.policy.models.base.PfModelException; +import org.onap.policy.models.base.PfModelRuntimeException; +import org.onap.policy.models.pap.concepts.PdpDeployPolicies; +import org.onap.policy.models.pdp.concepts.Pdp; +import org.onap.policy.models.pdp.concepts.PdpGroup; +import org.onap.policy.models.pdp.concepts.PdpGroups; +import org.onap.policy.models.pdp.concepts.PdpStateChange; +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.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.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Provider for PAP component to deploy PDP groups. The following items must be in the + * {@link Registry}: + *
    + *
  • PDP Modification Lock
  • + *
  • PDP Modify Request Map
  • + *
  • PAP DAO Factory
  • + *
+ */ +public class PdpGroupDeployProvider extends ProviderBase { + private static final Logger logger = LoggerFactory.getLogger(PdpGroupDeployProvider.class); + + private static final String POLICY_RESULT_NAME = "policy"; + + + /** + * Constructs the object. + */ + public PdpGroupDeployProvider() { + super(); + } + + /** + * Creates or updates PDP groups. + * + * @param groups PDP group configurations to be created or updated + * @throws PfModelException if an error occurred + */ + public void createOrUpdateGroups(PdpGroups groups) throws PfModelException { + ValidationResult result = groups.validatePapRest(); + + if (!result.isValid()) { + String msg = result.getResult().trim(); + logger.warn(msg); + throw new PfModelException(Status.BAD_REQUEST, msg); + } + + process(groups, this::createOrUpdate); + } + + /** + * Creates or updates PDP groups. This is the method that does the actual work. + * + * @param data session data + * @param groups PDP group configurations + * @throws PfModelException if an error occurred + */ + private void createOrUpdate(SessionData data, PdpGroups groups) throws PfModelException { + BeanValidationResult result = new BeanValidationResult("groups", groups); + + for (PdpGroup group : groups.getGroups()) { + PdpGroup dbgroup = data.getGroup(group.getName()); + + if (dbgroup == null) { + result.addResult(addGroup(data, group)); + + } else { + result.addResult(updateGroup(data, dbgroup, group)); + } + } + + if (!result.isValid()) { + throw new PfModelException(Status.BAD_REQUEST, result.getResult().trim()); + } + } + + /** + * Adds a new group. + * + * @param data session data + * @param group the group to be added + * @return the validation result + * @throws PfModelException if an error occurred + */ + private ValidationResult addGroup(SessionData data, PdpGroup group) throws PfModelException { + BeanValidationResult result = new BeanValidationResult(group.getName(), group); + + validateGroupOnly(group, result); + if (!result.isValid()) { + return result; + } + + // default to active + if (group.getPdpGroupState() == null) { + group.setPdpGroupState(PdpState.ACTIVE); + } + + for (PdpSubGroup subgrp : group.getPdpSubgroups()) { + result.addResult(addSubGroup(data, subgrp)); + } + + if (result.isValid()) { + data.create(group); + } + + return result; + } + + /** + * Performs additional validations of a group, but does not examine the subgroups. + * + * @param group the group to be validated + * @param result the validation result + */ + private void validateGroupOnly(PdpGroup group, BeanValidationResult result) { + if (group.getPdpGroupState() == null) { + return; + } + + switch (group.getPdpGroupState()) { + case ACTIVE: + case PASSIVE: + break; + + default: + result.addResult(new ObjectValidationResult("pdpGroupState", group.getPdpGroupState(), + ValidationStatus.INVALID, "must be null, ACTIVE, or PASSIVE")); + break; + } + } + + /** + * Updates an existing group. + * + * @param data session data + * @param dbgroup the group, as it appears within the DB + * @param group the group to be added + * @return the validation result + * @throws PfModelException if an error occurred + */ + private ValidationResult updateGroup(SessionData data, PdpGroup dbgroup, PdpGroup group) throws PfModelException { + BeanValidationResult result = new BeanValidationResult(group.getName(), group); + + if (!ObjectUtils.equals(dbgroup.getProperties(), group.getProperties())) { + result.addResult(new ObjectValidationResult("properties", "", ValidationStatus.INVALID, + "cannot change properties")); + } + + boolean updated = updateField(dbgroup.getDescription(), group.getDescription(), dbgroup::setDescription); + updated = updateField(dbgroup.getPdpGroupState(), group.getPdpGroupState(), dbgroup::setPdpGroupState) + || updated; + updated = notifyPdpsDelSubGroups(data, dbgroup, group) || updated; + updated = addOrUpdateSubGroups(data, dbgroup, group, result) || updated; + + if (result.isValid() && updated) { + data.update(group); + } + + return result; + } + + /** + * Updates a field, if the new value is different than the old value. + * + * @param oldValue old value + * @param newValue new value + * @param setter function to set the field to the new value + * @return {@code true} if the field was updated, {@code false} if it already matched + * the new value + */ + private boolean updateField(T oldValue, T newValue, Consumer setter) { + if (oldValue == newValue) { + return false; + } + + if (oldValue != null && oldValue.equals(newValue)) { + return false; + } + + setter.accept(newValue); + return true; + } + + /** + * Adds or updates subgroups within the group. + * + * @param data session data + * @param dbgroup the group, as it appears within the DB + * @param group the group to be added + * @param result the validation result + * @return {@code true} if the DB group was modified, {@code false} otherwise + * @throws PfModelException if an error occurred + */ + private boolean addOrUpdateSubGroups(SessionData data, PdpGroup dbgroup, PdpGroup group, + BeanValidationResult result) throws PfModelException { + + // create a map of existing subgroups + Map type2sub = new HashMap<>(); + dbgroup.getPdpSubgroups().forEach(subgrp -> type2sub.put(subgrp.getPdpType(), subgrp)); + + boolean updated = false; + + for (PdpSubGroup subgrp : group.getPdpSubgroups()) { + PdpSubGroup dbsub = type2sub.get(subgrp.getPdpType()); + BeanValidationResult subResult = new BeanValidationResult(subgrp.getPdpType(), subgrp); + + if (dbsub == null) { + updated = true; + subResult.addResult(addSubGroup(data, subgrp)); + dbgroup.getPdpSubgroups().add(subgrp); + + } else { + updated = updateSubGroup(data, group, dbsub, subgrp, subResult) || updated; + } + + result.addResult(subResult); + } + + return updated; + } + + /** + * Notifies any PDPs whose subgroups are being removed. + * + * @param data session data + * @param dbgroup the group, as it appears within the DB + * @param group the group being updated + * @return {@code true} if a subgroup was removed, {@code false} otherwise + * @throws PfModelException if an error occurred + */ + private boolean notifyPdpsDelSubGroups(SessionData data, PdpGroup dbgroup, PdpGroup group) throws PfModelException { + boolean updated = false; + + // subgroups, as they appear within the updated group + Set subgroups = new HashSet<>(); + group.getPdpSubgroups().forEach(subgrp -> subgroups.add(subgrp.getPdpType())); + + // loop through subgroups as they appear within the DB + for (PdpSubGroup subgrp : dbgroup.getPdpSubgroups()) { + + if (!subgroups.contains(subgrp.getPdpType())) { + // this subgroup no longer appears - notify its PDPs + updated = true; + notifyPdpsDelSubGroup(data, subgrp); + trackPdpsDelSubGroup(data, subgrp); + } + } + + return updated; + } + + /** + * Notifies the PDPs that their subgroup is being removed. + * + * @param data session data + * @param subgrp subgroup that is being removed + */ + private void notifyPdpsDelSubGroup(SessionData data, PdpSubGroup subgrp) { + for (Pdp pdp : subgrp.getPdpInstances()) { + String name = pdp.getInstanceId(); + + // make it passive + PdpStateChange change = new PdpStateChange(); + change.setName(name); + change.setState(PdpState.PASSIVE); + + // remove it from subgroup and undeploy all policies + PdpUpdate update = new PdpUpdate(); + update.setName(name); + + data.addRequests(update, change); + } + } + + /** + * Tracks PDP responses when their subgroup is removed. + * + * @param data session data + * @param subgrp subgroup that is being removed + * @throws PfModelException if an error occurred + */ + private void trackPdpsDelSubGroup(SessionData data, PdpSubGroup subgrp) throws PfModelException { + Set pdps = subgrp.getPdpInstances().stream().map(Pdp::getInstanceId).collect(Collectors.toSet()); + + for (ToscaPolicyIdentifier policyId : subgrp.getPolicies()) { + data.trackUndeploy(policyId, pdps); + } + } + + /** + * Adds a new subgroup. + * + * @param data session data + * @param subgrp the subgroup to be added, updated to fully qualified versions upon + * return + * @return the validation result + * @throws PfModelException if an error occurred + */ + private ValidationResult addSubGroup(SessionData data, PdpSubGroup subgrp) throws PfModelException { + subgrp.setCurrentInstanceCount(0); + subgrp.setPdpInstances(Collections.emptyList()); + + BeanValidationResult result = new BeanValidationResult(subgrp.getPdpType(), subgrp); + + result.addResult(validateSupportedTypes(data, subgrp)); + result.addResult(validatePolicies(data, null, subgrp)); + + return result; + } + + /** + * Updates an existing subgroup. + * + * @param data session data + * @param dbgroup the group, from the DB, containing the subgroup + * @param dbsub the subgroup, from the DB + * @param subgrp the subgroup to be updated, updated to fully qualified versions upon + * return + * @param container container for additional validation results + * @return {@code true} if the subgroup content was changed, {@code false} if there + * were no changes + * @throws PfModelException if an error occurred + */ + private boolean updateSubGroup(SessionData data, PdpGroup dbgroup, PdpSubGroup dbsub, PdpSubGroup subgrp, + BeanValidationResult container) throws PfModelException { + + // perform additional validations first + if (!validateSubGroup(data, dbsub, subgrp, container)) { + return false; + } + + /* + * first, apply the changes about which the PDPs care + */ + boolean updated = updatePolicies(data, dbsub, subgrp); + + // publish any changes to the PDPs + if (updated) { + makeUpdates(data, dbgroup, dbsub); + } + + /* + * now make any remaining changes + */ + updated = updateList(dbsub.getSupportedPolicyTypes(), subgrp.getSupportedPolicyTypes(), + dbsub::setSupportedPolicyTypes) || updated; + + return updateField(dbsub.getDesiredInstanceCount(), subgrp.getDesiredInstanceCount(), + dbsub::setDesiredInstanceCount) || updated; + } + + private boolean updatePolicies(SessionData data, PdpSubGroup dbsub, PdpSubGroup subgrp) throws PfModelException { + Set undeployed = new HashSet<>(dbsub.getPolicies()); + undeployed.removeAll(subgrp.getPolicies()); + + Set deployed = new HashSet<>(subgrp.getPolicies()); + deployed.removeAll(dbsub.getPolicies()); + + if (deployed.isEmpty() && undeployed.isEmpty()) { + // lists are identical + return false; + } + + + Set pdps = subgrp.getPdpInstances().stream().map(Pdp::getInstanceId).collect(Collectors.toSet()); + + for (ToscaPolicyIdentifier policyId : deployed) { + data.trackDeploy(policyId, pdps); + } + + for (ToscaPolicyIdentifier policyId : undeployed) { + data.trackUndeploy(policyId, pdps); + } + + dbsub.setPolicies(new ArrayList<>(subgrp.getPolicies())); + return true; + } + + /** + * Performs additional validations of a subgroup. + * + * @param data session data + * @param dbsub the subgroup, from the DB + * @param subgrp the subgroup to be validated, updated to fully qualified versions + * upon return + * @param container container for additional validation results + * @return {@code true} if the subgroup is valid, {@code false} otherwise + * @throws PfModelException if an error occurred + */ + private boolean validateSubGroup(SessionData data, PdpSubGroup dbsub, PdpSubGroup subgrp, + BeanValidationResult container) throws PfModelException { + + BeanValidationResult result = new BeanValidationResult(subgrp.getPdpType(), subgrp); + + if (!ObjectUtils.equals(dbsub.getProperties(), subgrp.getProperties())) { + result.addResult(new ObjectValidationResult("properties", "", ValidationStatus.INVALID, + "cannot change properties")); + } + + result.addResult(validatePolicies(data, dbsub, subgrp)); + result.addResult(validateSupportedTypes(data, subgrp)); + container.addResult(result); + + return result.isValid(); + } + + /** + * Updates a DB list with items from a new list. + * + * @param dblist the list from the DB + * @param newList the new list + * @param setter function to set the new list + * @return {@code true} if the list changed, {@code false} if the lists were the same + */ + private boolean updateList(List dblist, List newList, Consumer> setter) { + + Set dbTypes = new HashSet<>(dblist); + Set newTypes = new HashSet<>(newList); + + if (dbTypes.equals(newTypes)) { + return false; + } + + setter.accept(new ArrayList<>(newTypes)); + + return true; + } + + /** + * Performs additional validations of the supported policy types within a subgroup. + * + * @param data session data + * @param subgrp the subgroup to be validated + * @param result the validation result + * @throws PfModelException if an error occurred + */ + private ValidationResult validateSupportedTypes(SessionData data, PdpSubGroup subgrp) throws PfModelException { + BeanValidationResult result = new BeanValidationResult(subgrp.getPdpType(), subgrp); + + for (ToscaPolicyTypeIdentifier type : subgrp.getSupportedPolicyTypes()) { + if (!type.getName().endsWith(".*") && data.getPolicyType(type) == null) { + result.addResult(new ObjectValidationResult("policy type", type, ValidationStatus.INVALID, + "unknown policy type")); + } + } + + return result; + } + + /** + * Performs additional validations of the policies within a subgroup. + * + * @param data session data + * @param dbsub subgroup from the DB, or {@code null} if this is a new subgroup + * @param subgrp the subgroup whose policies are to be validated, updated to fully + * qualified versions upon return + * @param result the validation result + * @throws PfModelException if an error occurred + */ + private ValidationResult validatePolicies(SessionData data, PdpSubGroup dbsub, PdpSubGroup subgrp) + throws PfModelException { + + // build a map of the DB data, from policy name to (fully qualified) policy + // version + Map dbname2vers = new HashMap<>(); + if (dbsub != null) { + dbsub.getPolicies().forEach(ident -> dbname2vers.put(ident.getName(), ident.getVersion())); + } + + BeanValidationResult result = new BeanValidationResult(subgrp.getPdpType(), subgrp); + + for (ToscaPolicyIdentifier ident : subgrp.getPolicies()) { + // note: "ident" may not have a fully qualified version + + String expectedVersion = dbname2vers.get(ident.getName()); + if (expectedVersion != null) { + // policy exists in the DB list - compare the versions + validateVersion(expectedVersion, ident, result); + ident.setVersion(expectedVersion); + continue; + } + + // policy doesn't appear in the DB's policy list - look it up + + ToscaPolicy policy = data.getPolicy(new ToscaPolicyIdentifierOptVersion(ident)); + if (policy == null) { + result.addResult(new ObjectValidationResult(POLICY_RESULT_NAME, ident, ValidationStatus.INVALID, + "unknown policy")); + + } else if (!isPolicySupported(subgrp.getSupportedPolicyTypes(), policy.getTypeIdentifier())) { + result.addResult(new ObjectValidationResult(POLICY_RESULT_NAME, ident, ValidationStatus.INVALID, + "not a supported policy for the subgroup")); + + } else { + // replace version with the fully qualified version from the policy + ident.setVersion(policy.getVersion()); + } + } + + return result; + } + + /** + * Determines if the new version matches the version in the DB. + * + * @param dbvers fully qualified version from the DB + * @param ident identifier whose version is to be validated; the version need not be + * fully qualified + * @param result the validation result + */ + private void validateVersion(String dbvers, ToscaPolicyIdentifier ident, BeanValidationResult result) { + String idvers = ident.getVersion(); + if (dbvers.equals(idvers)) { + return; + } + + // did not match - see if it's a prefix + + if (SessionData.isVersionPrefix(idvers) && dbvers.startsWith(idvers + ".")) { + // ident has a prefix of this version + return; + } + + result.addResult(new ObjectValidationResult(POLICY_RESULT_NAME, ident, ValidationStatus.INVALID, + "different version already deployed: " + dbvers)); + } + + /** + * Deploys or updates PDP policies using the simple API. + * + * @param policies PDP policies + * @throws PfModelException if an error occurred + */ + public void deployPolicies(PdpDeployPolicies policies) throws PfModelException { + process(policies, this::deploySimplePolicies); + } + + /** + * Deploys or updates PDP policies using the simple API. This is the method that does + * the actual work. + * + * @param data session data + * @param extPolicies external PDP policies + * @return a list of requests that should be sent to configure the PDPs + * @throws PfModelException if an error occurred + */ + private void deploySimplePolicies(SessionData data, PdpDeployPolicies policies) throws PfModelException { + + for (ToscaPolicyIdentifierOptVersion desiredPolicy : policies.getPolicies()) { + + try { + processPolicy(data, desiredPolicy); + + } catch (PfModelException | 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; + } + } + } + + /** + * Adds a policy to a subgroup, if it isn't there already. + */ + @Override + protected Updater makeUpdater(SessionData data, ToscaPolicy policy, + ToscaPolicyIdentifierOptVersion requestedIdent) { + + ToscaPolicyIdentifier desiredIdent = policy.getIdentifier(); + ToscaPolicyTypeIdentifier desiredType = policy.getTypeIdentifier(); + + return (group, subgroup) -> { + + if (!isPolicySupported(subgroup.getSupportedPolicyTypes(), desiredType)) { + // doesn't support the desired policy type + return false; + } + + if (containsPolicy(group, subgroup, desiredIdent)) { + return false; + } + + if (subgroup.getPdpInstances().isEmpty()) { + throw new PfModelRuntimeException(Status.BAD_REQUEST, "group " + group.getName() + " subgroup " + + subgroup.getPdpType() + " has no active PDPs"); + } + + + // add the policy to the subgroup + subgroup.getPolicies().add(desiredIdent); + + logger.info("add policy {} {} to subgroup {} {} count={}", desiredIdent.getName(), + desiredIdent.getVersion(), group.getName(), subgroup.getPdpType(), + subgroup.getPolicies().size()); + + Set pdps = subgroup.getPdpInstances().stream().map(Pdp::getInstanceId).collect(Collectors.toSet()); + data.trackDeploy(desiredIdent, pdps); + + return true; + }; + } + + /** + * Determines if a policy type is supported. + * + * @param supportedTypes supported policy types, any of which may end with ".*" + * @param desiredType policy type of interest + * @return {@code true} if the policy type is supported, {@code false} otherwise + */ + private boolean isPolicySupported(List supportedTypes, + ToscaPolicyTypeIdentifier desiredType) { + + if (supportedTypes.contains(desiredType)) { + return true; + } + + String desiredTypeName = desiredType.getName(); + for (ToscaPolicyTypeIdentifier type : supportedTypes) { + String supType = type.getName(); + if (supType.endsWith(".*") && desiredTypeName.startsWith(supType.substring(0, supType.length() - 1))) { + // matches everything up to, AND INCLUDING, the "." + return true; + } + } + + return false; + } + + /** + * Determines if a subgroup already contains the desired policy. + * + * @param group group that contains the subgroup + * @param subgroup subgroup of interest + * @param desiredIdent identifier of the desired policy + * @return {@code true} if the subgroup contains the desired policy, {@code false} + * otherwise + * @throws PfModelRuntimeException if the subgroup contains a different version of the + * desired policy + */ + private boolean containsPolicy(PdpGroup group, PdpSubGroup subgroup, ToscaPolicyIdentifier desiredIdent) { + String desnm = desiredIdent.getName(); + String desvers = desiredIdent.getVersion(); + + for (ToscaPolicyIdentifier actualIdent : subgroup.getPolicies()) { + if (!actualIdent.getName().equals(desnm)) { + continue; + } + + // found the policy - ensure the version matches + if (!actualIdent.getVersion().equals(desvers)) { + throw new PfModelRuntimeException(Status.BAD_REQUEST, + "group " + group.getName() + " subgroup " + subgroup.getPdpType() + " policy " + desnm + + " " + desvers + " different version already deployed: " + + actualIdent.getVersion()); + } + + // already has the desired policy & version + logger.info("subgroup {} {} already contains policy {} {}", group.getName(), subgroup.getPdpType(), desnm, + desvers); + return true; + } + + return false; + } +} diff --git a/main/src/main/java/org/onap/policy/pap/main/rest/PolicyUndeployerImpl.java b/main/src/main/java/org/onap/policy/pap/main/rest/PolicyUndeployerImpl.java new file mode 100644 index 00000000..f2812087 --- /dev/null +++ b/main/src/main/java/org/onap/policy/pap/main/rest/PolicyUndeployerImpl.java @@ -0,0 +1,121 @@ +/* + * ============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 java.util.Collection; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import org.onap.policy.models.base.PfModelException; +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.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.pap.main.comm.PolicyUndeployer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Implementation of policy undeployer. + */ +public class PolicyUndeployerImpl extends ProviderBase implements PolicyUndeployer { + private static final Logger logger = LoggerFactory.getLogger(PolicyUndeployerImpl.class); + + + /** + * Constructs the object. + */ + public PolicyUndeployerImpl() { + super(); + } + + @Override + public void undeploy(String group, String subgroup, Collection policies) + throws PfModelException { + + process(new Info(group, subgroup, policies), this::undeployPolicies); + } + + /** + * Undeploys policies from all PDPs within a subgroup. + * + * @param data session data + * @param policyInfo information about the policies to be undeployed + * @throws PfModelException if an error occurs + */ + private void undeployPolicies(SessionData data, Info policyInfo) throws PfModelException { + // get group and subgroup + PdpGroup group = data.getGroup(policyInfo.group); + if (group == null) { + return; + } + + Optional optsub = group.getPdpSubgroups().stream() + .filter(subgroup -> subgroup.getPdpType().equals(policyInfo.subgroup)).findAny(); + if (!optsub.isPresent()) { + logger.warn("subgroup {} {} not found", policyInfo.group, policyInfo.subgroup); + return; + } + + PdpSubGroup subgroup = optsub.get(); + + // remove the policies + boolean updated = false; + Set pdps = subgroup.getPdpInstances().stream().map(Pdp::getInstanceId).collect(Collectors.toSet()); + + for (ToscaPolicyIdentifier ident : policyInfo.policies) { + if (!subgroup.getPolicies().remove(ident)) { + continue; + } + + logger.info("remove policy {} {} from subgroup {} {} count={}", ident.getName(), ident.getVersion(), + group.getName(), subgroup.getPdpType(), subgroup.getPolicies().size()); + + updated = true; + data.trackUndeploy(ident, pdps); + } + + // push the updates + if (updated) { + makeUpdates(data, group, subgroup); + data.update(group); + } + } + + @Override + protected Updater makeUpdater(SessionData data, ToscaPolicy policy, ToscaPolicyIdentifierOptVersion desiredPolicy) { + throw new UnsupportedOperationException("makeUpdater should not be invoked"); + } + + private static class Info { + private String group; + private String subgroup; + private Collection policies; + + public Info(String group, String subgroup, Collection policies) { + this.group = group; + this.subgroup = subgroup; + this.policies = policies; + } + } +} diff --git a/main/src/main/java/org/onap/policy/pap/main/rest/ProviderBase.java b/main/src/main/java/org/onap/policy/pap/main/rest/ProviderBase.java new file mode 100644 index 00000000..5665e795 --- /dev/null +++ b/main/src/main/java/org/onap/policy/pap/main/rest/ProviderBase.java @@ -0,0 +1,287 @@ +/* + * ============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 java.util.Collection; +import java.util.stream.Collectors; +import javax.ws.rs.core.Response.Status; +import org.onap.policy.common.utils.services.Registry; +import org.onap.policy.models.base.PfModelException; +import org.onap.policy.models.base.PfModelRuntimeException; +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.provider.PolicyModelsProvider; +import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy; +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.comm.PdpModifyRequestMap; +import org.onap.policy.pap.main.notification.PolicyNotifier; +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}: + *
    + *
  • PDP Modification Lock
  • + *
  • PDP Modify Request Map
  • + *
  • PAP DAO Factory
  • + *
+ */ +public abstract class ProviderBase { + 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; + + /** + * Generates policy notifications based on responses from PDPs. + */ + private final PolicyNotifier notifier; + + /** + * 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); + this.notifier = Registry.get(PapConstants.REG_POLICY_NOTIFIER, PolicyNotifier.class); + } + + /** + * Processes a policy request. + * + * @param request PDP policy request + * @param processor function that processes the request + * @throws PfModelException if an error occurred + */ + protected void process(T request, BiConsumerWithEx processor) throws PfModelException { + + synchronized (updateLock) { + SessionData data; + + try (PolicyModelsProvider dao = daoFactory.create()) { + + data = new SessionData(dao); + processor.accept(data, request); + + // make all of the DB updates + data.updateDb(); + + } catch (PfModelException | PfModelRuntimeException e) { + logger.warn(DEPLOY_FAILED, e); + throw e; + + } catch (RuntimeException e) { + logger.warn(DEPLOY_FAILED, e); + throw new PfModelException(Status.INTERNAL_SERVER_ERROR, "request failed", e); + } + + // track responses for notification purposes + data.getDeployData().forEach(notifier::addDeploymentData); + data.getUndeployData().forEach(notifier::addUndeploymentData); + + // publish the requests + data.getPdpRequests().forEach(pair -> requestMap.addRequest(pair.getLeft(), pair.getRight())); + } + } + + /** + * Process a single policy from the request. + * + * @param data session data + * @param desiredPolicy request policy + * @throws PfModelException if an error occurred + */ + protected void processPolicy(SessionData data, ToscaPolicyIdentifierOptVersion desiredPolicy) + throws PfModelException { + + ToscaPolicy policy = getPolicy(data, desiredPolicy); + + Collection groups = getGroups(data, policy.getTypeIdentifier()); + if (groups.isEmpty()) { + throw new PfModelException(Status.BAD_REQUEST, "policy not supported by any PDP group: " + + desiredPolicy.getName() + " " + desiredPolicy.getVersion()); + } + + Updater updater = makeUpdater(data, policy, desiredPolicy); + + for (PdpGroup group : groups) { + upgradeGroup(data, 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 data session data + * @param policy policy to be added to or removed from each subgroup + * @param desiredPolicy request policy + * @return a function to update a subgroup + */ + protected abstract Updater makeUpdater(SessionData data, ToscaPolicy policy, + ToscaPolicyIdentifierOptVersion desiredPolicy); + + /** + * Finds the active PDP group(s) 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 occurred + */ + private Collection getGroups(SessionData data, ToscaPolicyTypeIdentifier policyType) + throws PfModelException { + + return data.getActivePdpGroupsByPolicyType(policyType); + } + + /** + * Updates a group, assigning a new version number, if it actually changes. + * + * @param data session data + * @param group the original group, to be updated + * @param updater function to update a group + * @throws PfModelException if an error occurred + */ + private void upgradeGroup(SessionData data, PdpGroup group, Updater updater) throws PfModelException { + + boolean updated = false; + + for (PdpSubGroup subgroup : group.getPdpSubgroups()) { + + if (!updater.apply(group, subgroup)) { + continue; + } + + updated = true; + + makeUpdates(data, group, subgroup); + } + + + if (updated) { + // something changed + data.update(group); + } + } + + /** + * Makes UPDATE messages for each PDP in a subgroup. + * + * @param data session data + * @param group group containing the subgroup + * @param subgroup subgroup whose PDPs should receive messages + */ + protected void makeUpdates(SessionData data, PdpGroup group, PdpSubGroup subgroup) { + for (Pdp pdp : subgroup.getPdpInstances()) { + data.addUpdate(makeUpdate(data, group, subgroup, pdp)); + } + } + + /** + * 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 pdp the PDP of interest + * @return a new UPDATE message + */ + private PdpUpdate makeUpdate(SessionData data, PdpGroup group, PdpSubGroup subgroup, Pdp pdp) { + + PdpUpdate update = new PdpUpdate(); + + update.setName(pdp.getInstanceId()); + update.setDescription(group.getDescription()); + update.setPdpGroup(group.getName()); + update.setPdpSubgroup(subgroup.getPdpType()); + update.setPolicies(subgroup.getPolicies().stream().map(ToscaPolicyIdentifierOptVersion::new) + .map(ident -> getPolicy(data, ident)).collect(Collectors.toList())); + + return update; + } + + /** + * Gets the specified policy. + * + * @param data session data + * @param ident policy identifier, with an optional version + * @return the policy of interest + * @throws PfModelRuntimeException if an error occurred or the policy was not found + */ + private ToscaPolicy getPolicy(SessionData data, ToscaPolicyIdentifierOptVersion ident) { + try { + ToscaPolicy policy = data.getPolicy(ident); + if (policy == null) { + throw new PfModelRuntimeException(Status.NOT_FOUND, + "cannot find policy: " + ident.getName() + " " + ident.getVersion()); + } + + return policy; + + } catch (PfModelException e) { + throw new PfModelRuntimeException(e.getErrorResponse().getResponseCode(), + e.getErrorResponse().getErrorMessage(), e); + } + } + + @FunctionalInterface + public static interface BiConsumerWithEx { + /** + * Performs this operation on the given arguments. + * + * @param firstArg the first input argument + * @param secondArg the second input argument + * @throws PfModelException if an error occurred + */ + void accept(F firstArg, S secondArg) throws PfModelException; + } + + @FunctionalInterface + public static interface Updater { + boolean apply(PdpGroup group, PdpSubGroup subgroup) throws PfModelException; + } +} diff --git a/main/src/main/java/org/onap/policy/pap/main/rest/SessionData.java b/main/src/main/java/org/onap/policy/pap/main/rest/SessionData.java new file mode 100644 index 00000000..22da5392 --- /dev/null +++ b/main/src/main/java/org/onap/policy/pap/main/rest/SessionData.java @@ -0,0 +1,507 @@ +/* + * ============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 java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import org.apache.commons.lang3.tuple.Pair; +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.PdpStateChange; +import org.onap.policy.models.pdp.concepts.PdpUpdate; +import org.onap.policy.models.pdp.enums.PdpState; +import org.onap.policy.models.provider.PolicyModelsProvider; +import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy; +import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyFilter; +import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyFilter.ToscaPolicyFilterBuilder; +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.ToscaPolicyType; +import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyTypeIdentifier; +import org.onap.policy.pap.main.notification.PolicyPdpNotificationData; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Data used during a single REST call when updating PDP policies. + */ +public class SessionData { + private static final Logger logger = LoggerFactory.getLogger(SessionData.class); + + /** + * If a version string matches this, then it is just a prefix (i.e., major or + * major.minor). + */ + private static final Pattern VERSION_PREFIX_PAT = Pattern.compile("[^.]+(?:[.][^.]+)?"); + + /** + * DB provider. + */ + private final PolicyModelsProvider dao; + + /** + * Maps a group name to its group data. This accumulates the set of groups to be + * created and updated when the REST call completes. + */ + private final Map groupCache = new HashMap<>(); + + /** + * Maps a policy type to the list of matching groups. Every group appearing within + * this map has a corresponding entry in {@link #groupCache}. + */ + private final Map> type2groups = new HashMap<>(); + + /** + * Maps a PDP name to its most recently generated update and state-change requests. + */ + private final Map> pdpRequests = new HashMap<>(); + + /** + * Maps a policy's identifier to the policy. + */ + private final Map policyCache = new HashMap<>(); + + /** + * Maps a policy type's identifier to the policy. + */ + private final Map typeCache = new HashMap<>(); + + /** + * Policies to be deployed. This is just used to build up the data, which is then + * passed to the notifier once the update is "committed". + */ + private final Map deploy = new HashMap<>(); + + /** + * Policies to be undeployed. This is just used to build up the data, which is then + * passed to the notifier once the update is "committed". + */ + private final Map undeploy = new HashMap<>(); + + + /** + * Constructs the object. + * + * @param dao DAO provider + */ + public SessionData(PolicyModelsProvider dao) { + this.dao = dao; + } + + /** + * Gets the policy type, referenced by an identifier. Loads it from the cache, if + * possible. Otherwise, gets it from the DB. + * + * @param desiredType policy type identifier + * @return the specified policy type + * @throws PfModelException if an error occurred + */ + public ToscaPolicyType getPolicyType(ToscaPolicyTypeIdentifier desiredType) throws PfModelException { + + ToscaPolicyType type = typeCache.get(desiredType); + if (type == null) { + + List lst = dao.getPolicyTypeList(desiredType.getName(), desiredType.getVersion()); + if (lst.isEmpty()) { + return null; + } + + type = lst.get(0); + typeCache.put(desiredType, type); + } + + return type; + } + + /** + * Gets the policy, referenced by an identifier. Loads it from the cache, if possible. + * Otherwise, gets it from the DB. + * + * @param desiredPolicy policy identifier + * @return the specified policy + * @throws PfModelException if an error occurred + */ + public ToscaPolicy getPolicy(ToscaPolicyIdentifierOptVersion desiredPolicy) throws PfModelException { + + ToscaPolicy policy = policyCache.get(desiredPolicy); + if (policy == null) { + ToscaPolicyFilterBuilder filterBuilder = ToscaPolicyFilter.builder().name(desiredPolicy.getName()); + setPolicyFilterVersion(filterBuilder, desiredPolicy.getVersion()); + + List lst = dao.getFilteredPolicyList(filterBuilder.build()); + if (lst.isEmpty()) { + return null; + } + + policy = lst.get(0); + policyCache.put(desiredPolicy, policy); + } + + // desired version may have only been a prefix - cache with full identifier, too + policyCache.putIfAbsent(new ToscaPolicyIdentifierOptVersion(policy.getIdentifier()), policy); + + return policy; + } + + /** + * Sets the "version" in a policy filter. + * + * @param filterBuilder filter builder whose version should be set + * @param desiredVersion desired version + */ + private void setPolicyFilterVersion(ToscaPolicyFilterBuilder filterBuilder, String desiredVersion) { + + if (desiredVersion == null) { + // no version specified - get the latest + filterBuilder.version(ToscaPolicyFilter.LATEST_VERSION); + + } else if (isVersionPrefix(desiredVersion)) { + // version prefix provided - match the prefix and then pick the latest + filterBuilder.versionPrefix(desiredVersion + ".").version(ToscaPolicyFilter.LATEST_VERSION); + + } else { + // must be an exact match + filterBuilder.version(desiredVersion); + } + } + + /** + * Determines if a version contains only a prefix. + * + * @param version version to inspect + * @return {@code true} if the version contains only a prefix, {@code false} if it is + * fully qualified + */ + public static boolean isVersionPrefix(String version) { + return VERSION_PREFIX_PAT.matcher(version).matches(); + } + + /** + * Adds an update and state-change to the sets, replacing any previous entries for the + * given PDP. + * + * @param update the update to be added + * @param change the state-change to be added + */ + public void addRequests(PdpUpdate update, PdpStateChange change) { + if (!update.getName().equals(change.getName())) { + throw new IllegalArgumentException("PDP name mismatch " + update.getName() + ", " + change.getName()); + } + + logger.info("add update and state-change {} {} {} policies={}", update.getName(), update.getPdpGroup(), + update.getPdpSubgroup(), update.getPolicies().size()); + pdpRequests.put(update.getName(), Pair.of(update, change)); + } + + /** + * 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) { + logger.info("add update {} {} {} policies={}", update.getName(), update.getPdpGroup(), update.getPdpSubgroup(), + update.getPolicies().size()); + pdpRequests.compute(update.getName(), (name, data) -> Pair.of(update, (data == null ? null : data.getRight()))); + } + + /** + * Adds a state-change to the set of state-change requests, replacing any previous + * entry for the given PDP. + * + * @param change the state-change to be added + */ + public void addStateChange(PdpStateChange change) { + logger.info("add state-change {}", change.getName()); + pdpRequests.compute(change.getName(), (name, data) -> Pair.of((data == null ? null : data.getLeft()), change)); + } + + /** + * Determines if any changes were made due to the REST call. + * + * @return {@code true} if nothing was changed, {@code false} if something was changed + */ + public boolean isUnchanged() { + return groupCache.values().stream().allMatch(GroupData::isUnchanged); + } + + /** + * Gets the accumulated PDP requests. + * + * @return the PDP requests + */ + public Collection> getPdpRequests() { + return pdpRequests.values(); + } + + /** + * Gets the accumulated PDP update requests. + * + * @return the PDP requests + */ + public List getPdpUpdates() { + return pdpRequests.values().stream().filter(req -> req.getLeft() != null).map(Pair::getLeft) + .collect(Collectors.toList()); + } + + /** + * Gets the accumulated PDP state-change requests. + * + * @return the PDP requests + */ + public List getPdpStateChanges() { + return pdpRequests.values().stream().filter(req -> req.getRight() != null).map(Pair::getRight) + .collect(Collectors.toList()); + } + + /** + * Creates a group. + * + * @param newGroup the new group + */ + public void create(PdpGroup newGroup) { + String name = newGroup.getName(); + + if (groupCache.put(name, new GroupData(newGroup, true)) != null) { + throw new IllegalStateException("group already cached: " + name); + } + + logger.info("create cached group {}", newGroup.getName()); + } + + /** + * Updates a group. + * + * @param newGroup the updated group + */ + public void update(PdpGroup newGroup) { + String name = newGroup.getName(); + GroupData data = groupCache.get(name); + if (data == null) { + throw new IllegalStateException("group not cached: " + name); + } + + logger.info("update cached group {}", newGroup.getName()); + data.update(newGroup); + } + + /** + * Gets the group by the given name. + * + * @param name name of the group to get + * @return the group, or {@code null} if it does not exist + * @throws PfModelException if an error occurred + */ + public PdpGroup getGroup(String name) throws PfModelException { + + GroupData data = groupCache.get(name); + if (data == null) { + List lst = dao.getPdpGroups(name); + if (lst.isEmpty()) { + logger.info("unknown group {}", name); + return null; + } + + logger.info("cache group {}", name); + data = new GroupData(lst.get(0)); + groupCache.put(name, data); + + } else { + logger.info("use cached group {}", name); + } + + return data.getGroup(); + } + + /** + * 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 occurred + */ + public List getActivePdpGroupsByPolicyType(ToscaPolicyTypeIdentifier type) throws PfModelException { + List data = type2groups.get(type); + if (data == null) { + PdpGroupFilter filter = PdpGroupFilter.builder().policyTypeList(Collections.singletonList(type)) + .groupState(PdpState.ACTIVE).build(); + + List groups = dao.getFilteredPdpGroups(filter); + + data = groups.stream().map(this::addGroup).collect(Collectors.toList()); + type2groups.put(type, data); + } + + return data.stream().map(GroupData::getGroup).collect(Collectors.toList()); + } + + /** + * Adds a group to the group cache, if it isn't already in the cache. + * + * @param group the group to be added + * @return the cache entry + */ + private GroupData addGroup(PdpGroup group) { + GroupData data = groupCache.get(group.getName()); + if (data == null) { + logger.info("cache group {}", group.getName()); + data = new GroupData(group); + groupCache.put(group.getName(), data); + + } else { + logger.info("use cached group {}", group.getName()); + } + + return data; + } + + /** + * Update the DB with the changes. + * + * @throws PfModelException if an error occurred + */ + public void updateDb() throws PfModelException { + // create new groups + List created = groupCache.values().stream().filter(GroupData::isNew).collect(Collectors.toList()); + if (!created.isEmpty()) { + if (logger.isInfoEnabled()) { + created.forEach(group -> logger.info("creating DB group {}", group.getGroup().getName())); + } + dao.createPdpGroups(created.stream().map(GroupData::getGroup).collect(Collectors.toList())); + } + + // update existing groups + List updated = + groupCache.values().stream().filter(GroupData::isUpdated).collect(Collectors.toList()); + if (!updated.isEmpty()) { + if (logger.isInfoEnabled()) { + updated.forEach(group -> logger.info("updating DB group {}", group.getGroup().getName())); + } + dao.updatePdpGroups(updated.stream().map(GroupData::getGroup).collect(Collectors.toList())); + } + } + + /** + * Deletes a group from the DB, immediately (i.e., without caching the request to be + * executed later). + * + * @param group the group to be deleted + * @throws PfModelException if an error occurred + */ + public void deleteGroupFromDb(PdpGroup group) throws PfModelException { + logger.info("deleting DB group {}", group.getName()); + dao.deletePdpGroup(group.getName()); + } + + /** + * Adds policy deployment data. + * + * @param policyId ID of the policy being deployed + * @param pdps PDPs to which the policy is being deployed + * @throws PfModelException if an error occurred + */ + protected void trackDeploy(ToscaPolicyIdentifier policyId, Collection pdps) throws PfModelException { + trackDeploy(policyId, new HashSet<>(pdps)); + } + + /** + * Adds policy deployment data. + * + * @param policyId ID of the policy being deployed + * @param pdps PDPs to which the policy is being deployed + * @throws PfModelException if an error occurred + */ + protected void trackDeploy(ToscaPolicyIdentifier policyId, Set pdps) throws PfModelException { + addData(policyId, pdps, deploy, undeploy); + } + + /** + * Adds policy undeployment data. + * + * @param policyId ID of the policy being undeployed + * @param pdps PDPs to which the policy is being undeployed + * @throws PfModelException if an error occurred + */ + protected void trackUndeploy(ToscaPolicyIdentifier policyId, Collection pdps) throws PfModelException { + trackUndeploy(policyId, new HashSet<>(pdps)); + } + + /** + * Adds policy undeployment data. + * + * @param policyId ID of the policy being undeployed + * @param pdps PDPs to which the policy is being undeployed + * @throws PfModelException if an error occurred + */ + protected void trackUndeploy(ToscaPolicyIdentifier policyId, Set pdps) throws PfModelException { + addData(policyId, pdps, undeploy, deploy); + } + + /** + * Adds policy deployment/undeployment data. + * + * @param policyId ID of the policy being deployed/undeployed + * @param pdps PDPs to which the policy is being deployed/undeployed + * @param addMap map to which it should be added + * @param removeMap map from which it should be removed + * @throws PfModelException if an error occurred + */ + private void addData(ToscaPolicyIdentifier policyId, Set pdps, + Map addMap, + Map removeMap) throws PfModelException { + + PolicyPdpNotificationData removeData = removeMap.get(policyId); + if (removeData != null) { + removeData.removeAll(pdps); + } + + ToscaPolicyIdentifierOptVersion optid = new ToscaPolicyIdentifierOptVersion(policyId); + ToscaPolicyTypeIdentifier policyType = getPolicy(optid).getTypeIdentifier(); + + addMap.computeIfAbsent(policyId, key -> new PolicyPdpNotificationData(policyId, policyType)).addAll(pdps); + } + + /** + * Gets the policies to be deployed. + * + * @return the policies to be deployed + */ + public Collection getDeployData() { + return deploy.values(); + } + + /** + * Gets the policies to be undeployed. + * + * @return the policies to be undeployed + */ + public Collection getUndeployData() { + return undeploy.values(); + } +} diff --git a/main/src/main/java/org/onap/policy/pap/main/rest/depundep/GroupData.java b/main/src/main/java/org/onap/policy/pap/main/rest/depundep/GroupData.java deleted file mode 100644 index 9ad9be28..00000000 --- a/main/src/main/java/org/onap/policy/pap/main/rest/depundep/GroupData.java +++ /dev/null @@ -1,107 +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.depundep; - -import lombok.Getter; -import org.onap.policy.models.pdp.concepts.PdpGroup; - -/** - * PdpGroup data, only the latest copy of the group is retained. - */ -public class GroupData { - @Getter - private PdpGroup group; - - private enum State { - UNCHANGED, CREATED, UPDATED - } - - /** - * State of the group. - */ - private State state; - - - /** - * Constructs the object, for an existing group. - * - * @param group the group that is in the DB - */ - public GroupData(PdpGroup group) { - this(group, false); - } - - /** - * Constructs the object. - * - * @param group the group that is in, or to be added to, the DB - * @param isNew {@code true} if this is a new group, {@code false} otherwise - */ - public GroupData(PdpGroup group, boolean isNew) { - this.group = group; - this.state = (isNew ? State.CREATED : State.UNCHANGED); - } - - /** - * Determines if the group is unchanged (i.e., neither new nor updated). - * - * @return {@code true} if the group is unchanged, {@code false} otherwise - */ - public boolean isUnchanged() { - return (state == State.UNCHANGED); - } - - /** - * Determines if the group is new. - * - * @return {@code true} if the group is new, {@code false} otherwise - */ - public boolean isNew() { - return (state == State.CREATED); - } - - /** - * Determines if the group has been updated. - * - * @return {@code true} if the group has been updated, {@code false} otherwise - */ - public boolean isUpdated() { - return (state == State.UPDATED); - } - - /** - * Updates the group to the new value. - * - * @param newGroup the updated group - */ - public void update(PdpGroup newGroup) { - if (!this.group.getName().equals(newGroup.getName())) { - throw new IllegalArgumentException( - "expected group " + this.group.getName() + ", but received " + newGroup.getName()); - } - - this.group = newGroup; - - if (state == State.UNCHANGED) { - state = State.UPDATED; - } - } -} diff --git a/main/src/main/java/org/onap/policy/pap/main/rest/depundep/PdpGroupDeleteControllerV1.java b/main/src/main/java/org/onap/policy/pap/main/rest/depundep/PdpGroupDeleteControllerV1.java deleted file mode 100644 index 47b77bdc..00000000 --- a/main/src/main/java/org/onap/policy/pap/main/rest/depundep/PdpGroupDeleteControllerV1.java +++ /dev/null @@ -1,195 +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.depundep; - -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiParam; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; -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.DELETE; -import javax.ws.rs.HeaderParam; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.Response.Status; -import org.onap.policy.models.base.PfModelException; -import org.onap.policy.models.base.PfModelRuntimeException; -import org.onap.policy.models.pap.concepts.PdpGroupDeleteResponse; -import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyIdentifierOptVersion; -import org.onap.policy.pap.main.rest.PapRestControllerV1; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Class to provide REST end points for PAP component to delete a PDP group. - */ -public class PdpGroupDeleteControllerV1 extends PapRestControllerV1 { - private static final Logger logger = LoggerFactory.getLogger(PdpGroupDeleteControllerV1.class); - - private final PdpGroupDeleteProvider provider = new PdpGroupDeleteProvider(); - - /** - * Deletes a PDP group. - * - * @param requestId request ID used in ONAP logging - * @param groupName name of the PDP group to be deleted - * @return a response - */ - // @formatter:off - @DELETE - @Path("pdps/groups/{name}") - @ApiOperation(value = "Delete PDP Group", - notes = "Deletes a PDP Group, returning optional error details", - response = PdpGroupDeleteResponse.class, - tags = {"Policy Administration (PAP) API"}, - authorizations = @Authorization(value = AUTHORIZATION_TYPE), - responseHeaders = { - @ResponseHeader(name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION, - response = String.class), - @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION, - response = String.class), - @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION, - response = String.class), - @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION, - response = UUID.class)}, - extensions = {@Extension(name = EXTENSION_NAME, - properties = {@ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION), - @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)})}) - @ApiResponses(value = {@ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE), - @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE), - @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)}) - // @formatter:on - - public Response deleteGroup(@HeaderParam(REQUEST_ID_NAME) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId, - @ApiParam(value = "PDP Group Name", required = true) @PathParam("name") String groupName) { - - return doOperation(requestId, "delete group failed", () -> provider.deleteGroup(groupName)); - } - - /** - * Undeploys the latest version of a policy from the PDPs. - * - * @param requestId request ID used in ONAP logging - * @param policyName name of the PDP Policy to be deleted - * @return a response - */ - // @formatter:off - @DELETE - @Path("pdps/policies/{name}") - @ApiOperation(value = "Undeploy a PDP Policy from PDPs", - notes = "Undeploys the latest version of a policy from the PDPs, returning optional error details", - response = PdpGroupDeleteResponse.class, - tags = {"Policy Administration (PAP) API"}, - authorizations = @Authorization(value = AUTHORIZATION_TYPE), - responseHeaders = { - @ResponseHeader(name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION, - response = String.class), - @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION, - response = String.class), - @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION, - response = String.class), - @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION, - response = UUID.class)}, - extensions = {@Extension(name = EXTENSION_NAME, - properties = {@ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION), - @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)})}) - @ApiResponses(value = {@ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE), - @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE), - @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)}) - // @formatter:on - - public Response deletePolicy(@HeaderParam(REQUEST_ID_NAME) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId, - @ApiParam(value = "PDP Policy Name", required = true) @PathParam("name") String policyName) { - - return doOperation(requestId, "undeploy policy failed", - () -> provider.undeploy(new ToscaPolicyIdentifierOptVersion(policyName, null))); - } - - /** - * Undeploys a specific version of a policy from the PDPs. - * - * @param requestId request ID used in ONAP logging - * @param policyName name of the PDP Policy to be deleted - * @param version version to be deleted - * @return a response - */ - // @formatter:off - @DELETE - @Path("pdps/policies/{name}/versions/{version}") - @ApiOperation(value = "Undeploy version of a PDP Policy from PDPs", - notes = "Undeploys a specific version of a policy from the PDPs, returning optional error details", - response = PdpGroupDeleteResponse.class, - tags = {"Policy Administration (PAP) API"}, - authorizations = @Authorization(value = AUTHORIZATION_TYPE), - responseHeaders = { - @ResponseHeader(name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION, - response = String.class), - @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION, - response = String.class), - @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION, - response = String.class), - @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION, - response = UUID.class)}, - extensions = {@Extension(name = EXTENSION_NAME, - properties = {@ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION), - @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)})}) - @ApiResponses(value = {@ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE), - @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE), - @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)}) - // @formatter:on - - public Response deletePolicyVersion( - @HeaderParam(REQUEST_ID_NAME) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId, - @ApiParam(value = "PDP Policy Name", required = true) @PathParam("name") String policyName, - @ApiParam(value = "PDP Policy Version", required = true) @PathParam("version") String version) { - - return doOperation(requestId, "undeploy policy failed", - () -> provider.undeploy(new ToscaPolicyIdentifierOptVersion(policyName, version))); - } - - /** - * Invokes an operation. - * - * @param requestId request ID - * @param errmsg error message to log if the operation throws an exception - * @param runnable operation to invoke - * @return a {@link PdpGroupDeleteResponse} response entity - */ - private Response doOperation(UUID requestId, String errmsg, RunnableWithPfEx runnable) { - try { - runnable.run(); - return addLoggingHeaders(addVersionControlHeaders(Response.status(Status.OK)), requestId) - .entity(new PdpGroupDeleteResponse()).build(); - - } catch (PfModelException | PfModelRuntimeException e) { - logger.warn(errmsg, e); - PdpGroupDeleteResponse resp = new PdpGroupDeleteResponse(); - resp.setErrorDetails(e.getErrorResponse().getErrorMessage()); - return addLoggingHeaders(addVersionControlHeaders(Response.status(e.getErrorResponse().getResponseCode())), - requestId).entity(resp).build(); - } - } -} diff --git a/main/src/main/java/org/onap/policy/pap/main/rest/depundep/PdpGroupDeleteProvider.java b/main/src/main/java/org/onap/policy/pap/main/rest/depundep/PdpGroupDeleteProvider.java deleted file mode 100644 index 09ad862b..00000000 --- a/main/src/main/java/org/onap/policy/pap/main/rest/depundep/PdpGroupDeleteProvider.java +++ /dev/null @@ -1,167 +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.depundep; - -import java.util.Iterator; -import java.util.Set; -import java.util.function.Predicate; -import java.util.stream.Collectors; -import javax.ws.rs.core.Response.Status; -import org.onap.policy.models.base.PfModelException; -import org.onap.policy.models.pdp.concepts.Pdp; -import org.onap.policy.models.pdp.concepts.PdpGroup; -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.models.tosca.authorative.concepts.ToscaPolicyIdentifierOptVersion; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Provider for PAP component to delete PDP groups. - */ -public class PdpGroupDeleteProvider extends ProviderBase { - private static final Logger logger = LoggerFactory.getLogger(PdpGroupDeleteProvider.class); - - - /** - * Constructs the object. - */ - public PdpGroupDeleteProvider() { - super(); - } - - /** - * Deletes a PDP group. - * - * @param groupName name of the PDP group to be deleted - * @throws PfModelException if an error occurred - */ - public void deleteGroup(String groupName) throws PfModelException { - process(groupName, this::deleteGroup); - } - - /** - * Deletes a PDP group. - * - * @param data session data - * @param groupName name of the PDP group to be deleted - * @throws PfModelException if an error occurred - */ - private void deleteGroup(SessionData data, String groupName) throws PfModelException { - try { - PdpGroup group = data.getGroup(groupName); - if (group == null) { - throw new PfModelException(Status.NOT_FOUND, "group not found"); - } - - if (group.getPdpGroupState() == PdpState.ACTIVE) { - throw new PfModelException(Status.BAD_REQUEST, "group is still " + PdpState.ACTIVE); - } - - data.deleteGroupFromDb(group); - - } catch (PfModelException | RuntimeException e) { - // no need to log the error object here, as it will be logged by the invoker - logger.warn("failed to delete group: {}", groupName); - throw e; - } - } - - /** - * Undeploys a policy. - * - * @param policyIdent identifier of the policy to be undeployed - * @throws PfModelException if an error occurred - */ - public void undeploy(ToscaPolicyIdentifierOptVersion policyIdent) throws PfModelException { - process(policyIdent, this::undeployPolicy); - } - - /** - * Undeploys a policy from its groups. - * - * @param data session data - * @param ident identifier of the policy to be deleted - * @throws PfModelException if an error occurred - */ - private void undeployPolicy(SessionData data, ToscaPolicyIdentifierOptVersion ident) throws PfModelException { - try { - processPolicy(data, ident); - - if (data.isUnchanged()) { - throw new PfModelException(Status.BAD_REQUEST, "policy does not appear in any PDP group: " - + ident.getName() + " " + ident.getVersion()); - } - - } catch (PfModelException | RuntimeException e) { - // no need to log the error object here, as it will be logged by the invoker - logger.warn("failed to undeploy policy: {}", ident); - throw e; - } - } - - /** - * Returns a function that will remove the desired policy from a subgroup. - */ - @Override - protected Updater makeUpdater(SessionData data, ToscaPolicy policy, - ToscaPolicyIdentifierOptVersion desiredIdent) { - - // construct a matcher based on whether or not the version was specified - Predicate matcher; - - if (desiredIdent.getVersion() != null) { - // version was specified - match the whole identifier - matcher = policy.getIdentifier()::equals; - - } else { - // version was not specified - match the name only - String desnm = desiredIdent.getName(); - matcher = ident -> ident.getName().equals(desnm); - } - - - // return a function that will remove the policy from the subgroup - return (group, subgroup) -> { - - Set pdps = subgroup.getPdpInstances().stream().map(Pdp::getInstanceId).collect(Collectors.toSet()); - - boolean result = false; - - Iterator iter = subgroup.getPolicies().iterator(); - while (iter.hasNext()) { - ToscaPolicyIdentifier ident = iter.next(); - - if (matcher.test(ident)) { - result = true; - iter.remove(); - logger.info("remove policy {} {} from subgroup {} {} count={}", ident.getName(), ident.getVersion(), - group.getName(), subgroup.getPdpType(), subgroup.getPolicies().size()); - - data.trackUndeploy(ident, pdps); - } - } - - return result; - }; - } -} diff --git a/main/src/main/java/org/onap/policy/pap/main/rest/depundep/PdpGroupDeployControllerV1.java b/main/src/main/java/org/onap/policy/pap/main/rest/depundep/PdpGroupDeployControllerV1.java deleted file mode 100644 index a9e3d5c7..00000000 --- a/main/src/main/java/org/onap/policy/pap/main/rest/depundep/PdpGroupDeployControllerV1.java +++ /dev/null @@ -1,153 +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.depundep; - -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiParam; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; -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.onap.policy.models.base.PfModelException; -import org.onap.policy.models.base.PfModelRuntimeException; -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; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Class to provide REST end points for PAP component to deploy a PDP group. - */ -public class PdpGroupDeployControllerV1 extends PapRestControllerV1 { - private static final Logger logger = LoggerFactory.getLogger(PdpGroupDeployControllerV1.class); - - private final PdpGroupDeployProvider provider = new PdpGroupDeployProvider(); - - /** - * Deploys or updates a PDP group. - * - * @param requestId request ID used in ONAP logging - * @param groups PDP group configuration - * @return a response - */ - // @formatter:off - @POST - @Path("pdps") - @ApiOperation(value = "Deploy or update PDP Groups", - notes = "Deploys or updates a PDP Group, returning optional error details", - response = PdpGroupDeployResponse.class, - tags = {"Policy Administration (PAP) API"}, - authorizations = @Authorization(value = AUTHORIZATION_TYPE), - responseHeaders = { - @ResponseHeader(name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION, - response = String.class), - @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION, - response = String.class), - @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION, - response = String.class), - @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION, - response = UUID.class)}, - extensions = {@Extension(name = EXTENSION_NAME, - properties = {@ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION), - @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)})}) - @ApiResponses(value = {@ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE), - @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE), - @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)}) - // @formatter:on - - public Response deployGroup(@HeaderParam(REQUEST_ID_NAME) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId, - @ApiParam(value = "List of PDP Group Configuration", required = true) PdpGroups groups) { - - return doOperation(requestId, "create groups failed", () -> provider.createOrUpdateGroups(groups)); - } - - /** - * Deploys or updates PDP policies. - * - * @param requestId request ID used in ONAP logging - * @param policies PDP policies - * @return a response - */ - // @formatter:off - @POST - @Path("pdps/policies") - @ApiOperation(value = "Deploy or update PDP Policies", - notes = "Deploys or updates PDP Policies, returning optional error details", - response = PdpGroupDeployResponse.class, - tags = {"Policy Administration (PAP) API"}, - authorizations = @Authorization(value = AUTHORIZATION_TYPE), - responseHeaders = { - @ResponseHeader(name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION, - response = String.class), - @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION, - response = String.class), - @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION, - response = String.class), - @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION, - response = UUID.class)}, - extensions = {@Extension(name = EXTENSION_NAME, - properties = {@ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION), - @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)})}) - @ApiResponses(value = {@ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE), - @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE), - @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)}) - // @formatter:on - - public Response deployPolicies(@HeaderParam(REQUEST_ID_NAME) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId, - @ApiParam(value = "PDP Policies; only the name is required", - required = true) PdpDeployPolicies policies) { - - return doOperation(requestId, "deploy policies failed", () -> provider.deployPolicies(policies)); - } - - /** - * Invokes an operation. - * - * @param requestId request ID - * @param errmsg error message to log if the operation throws an exception - * @param runnable operation to invoke - * @return a {@link PdpGroupDeployResponse} response entity - */ - private Response doOperation(UUID requestId, String errmsg, RunnableWithPfEx runnable) { - try { - runnable.run(); - return addLoggingHeaders(addVersionControlHeaders(Response.status(Status.OK)), requestId) - .entity(new PdpGroupDeployResponse()).build(); - - } catch (PfModelException | PfModelRuntimeException e) { - logger.warn(errmsg, e); - PdpGroupDeployResponse resp = new PdpGroupDeployResponse(); - resp.setErrorDetails(e.getErrorResponse().getErrorMessage()); - return addLoggingHeaders(addVersionControlHeaders(Response.status(e.getErrorResponse().getResponseCode())), - requestId).entity(resp).build(); - } - } -} 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 deleted file mode 100644 index 2f94d39d..00000000 --- a/main/src/main/java/org/onap/policy/pap/main/rest/depundep/PdpGroupDeployProvider.java +++ /dev/null @@ -1,710 +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.depundep; - -import com.att.aft.dme2.internal.apache.commons.lang.ObjectUtils; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Consumer; -import java.util.stream.Collectors; -import javax.ws.rs.core.Response.Status; -import org.onap.policy.common.parameters.BeanValidationResult; -import org.onap.policy.common.parameters.ObjectValidationResult; -import org.onap.policy.common.parameters.ValidationResult; -import org.onap.policy.common.parameters.ValidationStatus; -import org.onap.policy.common.utils.services.Registry; -import org.onap.policy.models.base.PfModelException; -import org.onap.policy.models.base.PfModelRuntimeException; -import org.onap.policy.models.pap.concepts.PdpDeployPolicies; -import org.onap.policy.models.pdp.concepts.Pdp; -import org.onap.policy.models.pdp.concepts.PdpGroup; -import org.onap.policy.models.pdp.concepts.PdpGroups; -import org.onap.policy.models.pdp.concepts.PdpStateChange; -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.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.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Provider for PAP component to deploy PDP groups. The following items must be in the - * {@link Registry}: - *
    - *
  • PDP Modification Lock
  • - *
  • PDP Modify Request Map
  • - *
  • PAP DAO Factory
  • - *
- */ -public class PdpGroupDeployProvider extends ProviderBase { - private static final Logger logger = LoggerFactory.getLogger(PdpGroupDeployProvider.class); - - private static final String POLICY_RESULT_NAME = "policy"; - - - /** - * Constructs the object. - */ - public PdpGroupDeployProvider() { - super(); - } - - /** - * Creates or updates PDP groups. - * - * @param groups PDP group configurations to be created or updated - * @throws PfModelException if an error occurred - */ - public void createOrUpdateGroups(PdpGroups groups) throws PfModelException { - ValidationResult result = groups.validatePapRest(); - - if (!result.isValid()) { - String msg = result.getResult().trim(); - logger.warn(msg); - throw new PfModelException(Status.BAD_REQUEST, msg); - } - - process(groups, this::createOrUpdate); - } - - /** - * Creates or updates PDP groups. This is the method that does the actual work. - * - * @param data session data - * @param groups PDP group configurations - * @throws PfModelException if an error occurred - */ - private void createOrUpdate(SessionData data, PdpGroups groups) throws PfModelException { - BeanValidationResult result = new BeanValidationResult("groups", groups); - - for (PdpGroup group : groups.getGroups()) { - PdpGroup dbgroup = data.getGroup(group.getName()); - - if (dbgroup == null) { - result.addResult(addGroup(data, group)); - - } else { - result.addResult(updateGroup(data, dbgroup, group)); - } - } - - if (!result.isValid()) { - throw new PfModelException(Status.BAD_REQUEST, result.getResult().trim()); - } - } - - /** - * Adds a new group. - * - * @param data session data - * @param group the group to be added - * @return the validation result - * @throws PfModelException if an error occurred - */ - private ValidationResult addGroup(SessionData data, PdpGroup group) throws PfModelException { - BeanValidationResult result = new BeanValidationResult(group.getName(), group); - - validateGroupOnly(group, result); - if (!result.isValid()) { - return result; - } - - // default to active - if (group.getPdpGroupState() == null) { - group.setPdpGroupState(PdpState.ACTIVE); - } - - for (PdpSubGroup subgrp : group.getPdpSubgroups()) { - result.addResult(addSubGroup(data, subgrp)); - } - - if (result.isValid()) { - data.create(group); - } - - return result; - } - - /** - * Performs additional validations of a group, but does not examine the subgroups. - * - * @param group the group to be validated - * @param result the validation result - */ - private void validateGroupOnly(PdpGroup group, BeanValidationResult result) { - if (group.getPdpGroupState() == null) { - return; - } - - switch (group.getPdpGroupState()) { - case ACTIVE: - case PASSIVE: - break; - - default: - result.addResult(new ObjectValidationResult("pdpGroupState", group.getPdpGroupState(), - ValidationStatus.INVALID, "must be null, ACTIVE, or PASSIVE")); - break; - } - } - - /** - * Updates an existing group. - * - * @param data session data - * @param dbgroup the group, as it appears within the DB - * @param group the group to be added - * @return the validation result - * @throws PfModelException if an error occurred - */ - private ValidationResult updateGroup(SessionData data, PdpGroup dbgroup, PdpGroup group) throws PfModelException { - BeanValidationResult result = new BeanValidationResult(group.getName(), group); - - if (!ObjectUtils.equals(dbgroup.getProperties(), group.getProperties())) { - result.addResult(new ObjectValidationResult("properties", "", ValidationStatus.INVALID, - "cannot change properties")); - } - - boolean updated = updateField(dbgroup.getDescription(), group.getDescription(), dbgroup::setDescription); - updated = updateField(dbgroup.getPdpGroupState(), group.getPdpGroupState(), dbgroup::setPdpGroupState) - || updated; - updated = notifyPdpsDelSubGroups(data, dbgroup, group) || updated; - updated = addOrUpdateSubGroups(data, dbgroup, group, result) || updated; - - if (result.isValid() && updated) { - data.update(group); - } - - return result; - } - - /** - * Updates a field, if the new value is different than the old value. - * - * @param oldValue old value - * @param newValue new value - * @param setter function to set the field to the new value - * @return {@code true} if the field was updated, {@code false} if it already matched - * the new value - */ - private boolean updateField(T oldValue, T newValue, Consumer setter) { - if (oldValue == newValue) { - return false; - } - - if (oldValue != null && oldValue.equals(newValue)) { - return false; - } - - setter.accept(newValue); - return true; - } - - /** - * Adds or updates subgroups within the group. - * - * @param data session data - * @param dbgroup the group, as it appears within the DB - * @param group the group to be added - * @param result the validation result - * @return {@code true} if the DB group was modified, {@code false} otherwise - * @throws PfModelException if an error occurred - */ - private boolean addOrUpdateSubGroups(SessionData data, PdpGroup dbgroup, PdpGroup group, - BeanValidationResult result) throws PfModelException { - - // create a map of existing subgroups - Map type2sub = new HashMap<>(); - dbgroup.getPdpSubgroups().forEach(subgrp -> type2sub.put(subgrp.getPdpType(), subgrp)); - - boolean updated = false; - - for (PdpSubGroup subgrp : group.getPdpSubgroups()) { - PdpSubGroup dbsub = type2sub.get(subgrp.getPdpType()); - BeanValidationResult subResult = new BeanValidationResult(subgrp.getPdpType(), subgrp); - - if (dbsub == null) { - updated = true; - subResult.addResult(addSubGroup(data, subgrp)); - dbgroup.getPdpSubgroups().add(subgrp); - - } else { - updated = updateSubGroup(data, group, dbsub, subgrp, subResult) || updated; - } - - result.addResult(subResult); - } - - return updated; - } - - /** - * Notifies any PDPs whose subgroups are being removed. - * - * @param data session data - * @param dbgroup the group, as it appears within the DB - * @param group the group being updated - * @return {@code true} if a subgroup was removed, {@code false} otherwise - * @throws PfModelException if an error occurred - */ - private boolean notifyPdpsDelSubGroups(SessionData data, PdpGroup dbgroup, PdpGroup group) throws PfModelException { - boolean updated = false; - - // subgroups, as they appear within the updated group - Set subgroups = new HashSet<>(); - group.getPdpSubgroups().forEach(subgrp -> subgroups.add(subgrp.getPdpType())); - - // loop through subgroups as they appear within the DB - for (PdpSubGroup subgrp : dbgroup.getPdpSubgroups()) { - - if (!subgroups.contains(subgrp.getPdpType())) { - // this subgroup no longer appears - notify its PDPs - updated = true; - notifyPdpsDelSubGroup(data, subgrp); - trackPdpsDelSubGroup(data, subgrp); - } - } - - return updated; - } - - /** - * Notifies the PDPs that their subgroup is being removed. - * - * @param data session data - * @param subgrp subgroup that is being removed - */ - private void notifyPdpsDelSubGroup(SessionData data, PdpSubGroup subgrp) { - for (Pdp pdp : subgrp.getPdpInstances()) { - String name = pdp.getInstanceId(); - - // make it passive - PdpStateChange change = new PdpStateChange(); - change.setName(name); - change.setState(PdpState.PASSIVE); - - // remove it from subgroup and undeploy all policies - PdpUpdate update = new PdpUpdate(); - update.setName(name); - - data.addRequests(update, change); - } - } - - /** - * Tracks PDP responses when their subgroup is removed. - * - * @param data session data - * @param subgrp subgroup that is being removed - * @throws PfModelException if an error occurred - */ - private void trackPdpsDelSubGroup(SessionData data, PdpSubGroup subgrp) throws PfModelException { - Set pdps = subgrp.getPdpInstances().stream().map(Pdp::getInstanceId).collect(Collectors.toSet()); - - for (ToscaPolicyIdentifier policyId : subgrp.getPolicies()) { - data.trackUndeploy(policyId, pdps); - } - } - - /** - * Adds a new subgroup. - * - * @param data session data - * @param subgrp the subgroup to be added, updated to fully qualified versions upon - * return - * @return the validation result - * @throws PfModelException if an error occurred - */ - private ValidationResult addSubGroup(SessionData data, PdpSubGroup subgrp) throws PfModelException { - subgrp.setCurrentInstanceCount(0); - subgrp.setPdpInstances(Collections.emptyList()); - - BeanValidationResult result = new BeanValidationResult(subgrp.getPdpType(), subgrp); - - result.addResult(validateSupportedTypes(data, subgrp)); - result.addResult(validatePolicies(data, null, subgrp)); - - return result; - } - - /** - * Updates an existing subgroup. - * - * @param data session data - * @param dbgroup the group, from the DB, containing the subgroup - * @param dbsub the subgroup, from the DB - * @param subgrp the subgroup to be updated, updated to fully qualified versions upon - * return - * @param container container for additional validation results - * @return {@code true} if the subgroup content was changed, {@code false} if there - * were no changes - * @throws PfModelException if an error occurred - */ - private boolean updateSubGroup(SessionData data, PdpGroup dbgroup, PdpSubGroup dbsub, PdpSubGroup subgrp, - BeanValidationResult container) throws PfModelException { - - // perform additional validations first - if (!validateSubGroup(data, dbsub, subgrp, container)) { - return false; - } - - /* - * first, apply the changes about which the PDPs care - */ - boolean updated = updatePolicies(data, dbsub, subgrp); - - // publish any changes to the PDPs - if (updated) { - makeUpdates(data, dbgroup, dbsub); - } - - /* - * now make any remaining changes - */ - updated = updateList(dbsub.getSupportedPolicyTypes(), subgrp.getSupportedPolicyTypes(), - dbsub::setSupportedPolicyTypes) || updated; - - return updateField(dbsub.getDesiredInstanceCount(), subgrp.getDesiredInstanceCount(), - dbsub::setDesiredInstanceCount) || updated; - } - - private boolean updatePolicies(SessionData data, PdpSubGroup dbsub, PdpSubGroup subgrp) throws PfModelException { - Set undeployed = new HashSet<>(dbsub.getPolicies()); - undeployed.removeAll(subgrp.getPolicies()); - - Set deployed = new HashSet<>(subgrp.getPolicies()); - deployed.removeAll(dbsub.getPolicies()); - - if (deployed.isEmpty() && undeployed.isEmpty()) { - // lists are identical - return false; - } - - - Set pdps = subgrp.getPdpInstances().stream().map(Pdp::getInstanceId).collect(Collectors.toSet()); - - for (ToscaPolicyIdentifier policyId : deployed) { - data.trackDeploy(policyId, pdps); - } - - for (ToscaPolicyIdentifier policyId : undeployed) { - data.trackUndeploy(policyId, pdps); - } - - dbsub.setPolicies(new ArrayList<>(subgrp.getPolicies())); - return true; - } - - /** - * Performs additional validations of a subgroup. - * - * @param data session data - * @param dbsub the subgroup, from the DB - * @param subgrp the subgroup to be validated, updated to fully qualified versions - * upon return - * @param container container for additional validation results - * @return {@code true} if the subgroup is valid, {@code false} otherwise - * @throws PfModelException if an error occurred - */ - private boolean validateSubGroup(SessionData data, PdpSubGroup dbsub, PdpSubGroup subgrp, - BeanValidationResult container) throws PfModelException { - - BeanValidationResult result = new BeanValidationResult(subgrp.getPdpType(), subgrp); - - if (!ObjectUtils.equals(dbsub.getProperties(), subgrp.getProperties())) { - result.addResult(new ObjectValidationResult("properties", "", ValidationStatus.INVALID, - "cannot change properties")); - } - - result.addResult(validatePolicies(data, dbsub, subgrp)); - result.addResult(validateSupportedTypes(data, subgrp)); - container.addResult(result); - - return result.isValid(); - } - - /** - * Updates a DB list with items from a new list. - * - * @param dblist the list from the DB - * @param newList the new list - * @param setter function to set the new list - * @return {@code true} if the list changed, {@code false} if the lists were the same - */ - private boolean updateList(List dblist, List newList, Consumer> setter) { - - Set dbTypes = new HashSet<>(dblist); - Set newTypes = new HashSet<>(newList); - - if (dbTypes.equals(newTypes)) { - return false; - } - - setter.accept(new ArrayList<>(newTypes)); - - return true; - } - - /** - * Performs additional validations of the supported policy types within a subgroup. - * - * @param data session data - * @param subgrp the subgroup to be validated - * @param result the validation result - * @throws PfModelException if an error occurred - */ - private ValidationResult validateSupportedTypes(SessionData data, PdpSubGroup subgrp) throws PfModelException { - BeanValidationResult result = new BeanValidationResult(subgrp.getPdpType(), subgrp); - - for (ToscaPolicyTypeIdentifier type : subgrp.getSupportedPolicyTypes()) { - if (!type.getName().endsWith(".*") && data.getPolicyType(type) == null) { - result.addResult(new ObjectValidationResult("policy type", type, ValidationStatus.INVALID, - "unknown policy type")); - } - } - - return result; - } - - /** - * Performs additional validations of the policies within a subgroup. - * - * @param data session data - * @param dbsub subgroup from the DB, or {@code null} if this is a new subgroup - * @param subgrp the subgroup whose policies are to be validated, updated to fully - * qualified versions upon return - * @param result the validation result - * @throws PfModelException if an error occurred - */ - private ValidationResult validatePolicies(SessionData data, PdpSubGroup dbsub, PdpSubGroup subgrp) - throws PfModelException { - - // build a map of the DB data, from policy name to (fully qualified) policy - // version - Map dbname2vers = new HashMap<>(); - if (dbsub != null) { - dbsub.getPolicies().forEach(ident -> dbname2vers.put(ident.getName(), ident.getVersion())); - } - - BeanValidationResult result = new BeanValidationResult(subgrp.getPdpType(), subgrp); - - for (ToscaPolicyIdentifier ident : subgrp.getPolicies()) { - // note: "ident" may not have a fully qualified version - - String expectedVersion = dbname2vers.get(ident.getName()); - if (expectedVersion != null) { - // policy exists in the DB list - compare the versions - validateVersion(expectedVersion, ident, result); - ident.setVersion(expectedVersion); - continue; - } - - // policy doesn't appear in the DB's policy list - look it up - - ToscaPolicy policy = data.getPolicy(new ToscaPolicyIdentifierOptVersion(ident)); - if (policy == null) { - result.addResult(new ObjectValidationResult(POLICY_RESULT_NAME, ident, ValidationStatus.INVALID, - "unknown policy")); - - } else if (!isPolicySupported(subgrp.getSupportedPolicyTypes(), policy.getTypeIdentifier())) { - result.addResult(new ObjectValidationResult(POLICY_RESULT_NAME, ident, ValidationStatus.INVALID, - "not a supported policy for the subgroup")); - - } else { - // replace version with the fully qualified version from the policy - ident.setVersion(policy.getVersion()); - } - } - - return result; - } - - /** - * Determines if the new version matches the version in the DB. - * - * @param dbvers fully qualified version from the DB - * @param ident identifier whose version is to be validated; the version need not be - * fully qualified - * @param result the validation result - */ - private void validateVersion(String dbvers, ToscaPolicyIdentifier ident, BeanValidationResult result) { - String idvers = ident.getVersion(); - if (dbvers.equals(idvers)) { - return; - } - - // did not match - see if it's a prefix - - if (SessionData.isVersionPrefix(idvers) && dbvers.startsWith(idvers + ".")) { - // ident has a prefix of this version - return; - } - - result.addResult(new ObjectValidationResult(POLICY_RESULT_NAME, ident, ValidationStatus.INVALID, - "different version already deployed: " + dbvers)); - } - - /** - * Deploys or updates PDP policies using the simple API. - * - * @param policies PDP policies - * @throws PfModelException if an error occurred - */ - public void deployPolicies(PdpDeployPolicies policies) throws PfModelException { - process(policies, this::deploySimplePolicies); - } - - /** - * Deploys or updates PDP policies using the simple API. This is the method that does - * the actual work. - * - * @param data session data - * @param extPolicies external PDP policies - * @return a list of requests that should be sent to configure the PDPs - * @throws PfModelException if an error occurred - */ - private void deploySimplePolicies(SessionData data, PdpDeployPolicies policies) throws PfModelException { - - for (ToscaPolicyIdentifierOptVersion desiredPolicy : policies.getPolicies()) { - - try { - processPolicy(data, desiredPolicy); - - } catch (PfModelException | 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; - } - } - } - - /** - * Adds a policy to a subgroup, if it isn't there already. - */ - @Override - protected Updater makeUpdater(SessionData data, ToscaPolicy policy, - ToscaPolicyIdentifierOptVersion requestedIdent) { - - ToscaPolicyIdentifier desiredIdent = policy.getIdentifier(); - ToscaPolicyTypeIdentifier desiredType = policy.getTypeIdentifier(); - - return (group, subgroup) -> { - - if (!isPolicySupported(subgroup.getSupportedPolicyTypes(), desiredType)) { - // doesn't support the desired policy type - return false; - } - - if (containsPolicy(group, subgroup, desiredIdent)) { - return false; - } - - if (subgroup.getPdpInstances().isEmpty()) { - throw new PfModelRuntimeException(Status.BAD_REQUEST, "group " + group.getName() + " subgroup " - + subgroup.getPdpType() + " has no active PDPs"); - } - - - // add the policy to the subgroup - subgroup.getPolicies().add(desiredIdent); - - logger.info("add policy {} {} to subgroup {} {} count={}", desiredIdent.getName(), - desiredIdent.getVersion(), group.getName(), subgroup.getPdpType(), - subgroup.getPolicies().size()); - - Set pdps = subgroup.getPdpInstances().stream().map(Pdp::getInstanceId).collect(Collectors.toSet()); - data.trackDeploy(desiredIdent, pdps); - - return true; - }; - } - - /** - * Determines if a policy type is supported. - * - * @param supportedTypes supported policy types, any of which may end with ".*" - * @param desiredType policy type of interest - * @return {@code true} if the policy type is supported, {@code false} otherwise - */ - private boolean isPolicySupported(List supportedTypes, - ToscaPolicyTypeIdentifier desiredType) { - - if (supportedTypes.contains(desiredType)) { - return true; - } - - String desiredTypeName = desiredType.getName(); - for (ToscaPolicyTypeIdentifier type : supportedTypes) { - String supType = type.getName(); - if (supType.endsWith(".*") && desiredTypeName.startsWith(supType.substring(0, supType.length() - 1))) { - // matches everything up to, AND INCLUDING, the "." - return true; - } - } - - return false; - } - - /** - * Determines if a subgroup already contains the desired policy. - * - * @param group group that contains the subgroup - * @param subgroup subgroup of interest - * @param desiredIdent identifier of the desired policy - * @return {@code true} if the subgroup contains the desired policy, {@code false} - * otherwise - * @throws PfModelRuntimeException if the subgroup contains a different version of the - * desired policy - */ - private boolean containsPolicy(PdpGroup group, PdpSubGroup subgroup, ToscaPolicyIdentifier desiredIdent) { - String desnm = desiredIdent.getName(); - String desvers = desiredIdent.getVersion(); - - for (ToscaPolicyIdentifier actualIdent : subgroup.getPolicies()) { - if (!actualIdent.getName().equals(desnm)) { - continue; - } - - // found the policy - ensure the version matches - if (!actualIdent.getVersion().equals(desvers)) { - throw new PfModelRuntimeException(Status.BAD_REQUEST, - "group " + group.getName() + " subgroup " + subgroup.getPdpType() + " policy " + desnm - + " " + desvers + " different version already deployed: " - + actualIdent.getVersion()); - } - - // already has the desired policy & version - logger.info("subgroup {} {} already contains policy {} {}", group.getName(), subgroup.getPdpType(), desnm, - desvers); - return true; - } - - return false; - } -} diff --git a/main/src/main/java/org/onap/policy/pap/main/rest/depundep/PolicyUndeployerImpl.java b/main/src/main/java/org/onap/policy/pap/main/rest/depundep/PolicyUndeployerImpl.java deleted file mode 100644 index f224b131..00000000 --- a/main/src/main/java/org/onap/policy/pap/main/rest/depundep/PolicyUndeployerImpl.java +++ /dev/null @@ -1,121 +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.depundep; - -import java.util.Collection; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; -import org.onap.policy.models.base.PfModelException; -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.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.pap.main.comm.PolicyUndeployer; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Implementation of policy undeployer. - */ -public class PolicyUndeployerImpl extends ProviderBase implements PolicyUndeployer { - private static final Logger logger = LoggerFactory.getLogger(PolicyUndeployerImpl.class); - - - /** - * Constructs the object. - */ - public PolicyUndeployerImpl() { - super(); - } - - @Override - public void undeploy(String group, String subgroup, Collection policies) - throws PfModelException { - - process(new Info(group, subgroup, policies), this::undeployPolicies); - } - - /** - * Undeploys policies from all PDPs within a subgroup. - * - * @param data session data - * @param policyInfo information about the policies to be undeployed - * @throws PfModelException if an error occurs - */ - private void undeployPolicies(SessionData data, Info policyInfo) throws PfModelException { - // get group and subgroup - PdpGroup group = data.getGroup(policyInfo.group); - if (group == null) { - return; - } - - Optional optsub = group.getPdpSubgroups().stream() - .filter(subgroup -> subgroup.getPdpType().equals(policyInfo.subgroup)).findAny(); - if (!optsub.isPresent()) { - logger.warn("subgroup {} {} not found", policyInfo.group, policyInfo.subgroup); - return; - } - - PdpSubGroup subgroup = optsub.get(); - - // remove the policies - boolean updated = false; - Set pdps = subgroup.getPdpInstances().stream().map(Pdp::getInstanceId).collect(Collectors.toSet()); - - for (ToscaPolicyIdentifier ident : policyInfo.policies) { - if (!subgroup.getPolicies().remove(ident)) { - continue; - } - - logger.info("remove policy {} {} from subgroup {} {} count={}", ident.getName(), ident.getVersion(), - group.getName(), subgroup.getPdpType(), subgroup.getPolicies().size()); - - updated = true; - data.trackUndeploy(ident, pdps); - } - - // push the updates - if (updated) { - makeUpdates(data, group, subgroup); - data.update(group); - } - } - - @Override - protected Updater makeUpdater(SessionData data, ToscaPolicy policy, ToscaPolicyIdentifierOptVersion desiredPolicy) { - throw new UnsupportedOperationException("makeUpdater should not be invoked"); - } - - private static class Info { - private String group; - private String subgroup; - private Collection policies; - - public Info(String group, String subgroup, Collection policies) { - this.group = group; - this.subgroup = subgroup; - this.policies = policies; - } - } -} 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 deleted file mode 100644 index fd8edf17..00000000 --- a/main/src/main/java/org/onap/policy/pap/main/rest/depundep/ProviderBase.java +++ /dev/null @@ -1,287 +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.depundep; - -import java.util.Collection; -import java.util.stream.Collectors; -import javax.ws.rs.core.Response.Status; -import org.onap.policy.common.utils.services.Registry; -import org.onap.policy.models.base.PfModelException; -import org.onap.policy.models.base.PfModelRuntimeException; -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.provider.PolicyModelsProvider; -import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy; -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.comm.PdpModifyRequestMap; -import org.onap.policy.pap.main.notification.PolicyNotifier; -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}: - *
    - *
  • PDP Modification Lock
  • - *
  • PDP Modify Request Map
  • - *
  • PAP DAO Factory
  • - *
- */ -public abstract class ProviderBase { - 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; - - /** - * Generates policy notifications based on responses from PDPs. - */ - private final PolicyNotifier notifier; - - /** - * 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); - this.notifier = Registry.get(PapConstants.REG_POLICY_NOTIFIER, PolicyNotifier.class); - } - - /** - * Processes a policy request. - * - * @param request PDP policy request - * @param processor function that processes the request - * @throws PfModelException if an error occurred - */ - protected void process(T request, BiConsumerWithEx processor) throws PfModelException { - - synchronized (updateLock) { - SessionData data; - - try (PolicyModelsProvider dao = daoFactory.create()) { - - data = new SessionData(dao); - processor.accept(data, request); - - // make all of the DB updates - data.updateDb(); - - } catch (PfModelException | PfModelRuntimeException e) { - logger.warn(DEPLOY_FAILED, e); - throw e; - - } catch (RuntimeException e) { - logger.warn(DEPLOY_FAILED, e); - throw new PfModelException(Status.INTERNAL_SERVER_ERROR, "request failed", e); - } - - // track responses for notification purposes - data.getDeployData().forEach(notifier::addDeploymentData); - data.getUndeployData().forEach(notifier::addUndeploymentData); - - // publish the requests - data.getPdpRequests().forEach(pair -> requestMap.addRequest(pair.getLeft(), pair.getRight())); - } - } - - /** - * Process a single policy from the request. - * - * @param data session data - * @param desiredPolicy request policy - * @throws PfModelException if an error occurred - */ - protected void processPolicy(SessionData data, ToscaPolicyIdentifierOptVersion desiredPolicy) - throws PfModelException { - - ToscaPolicy policy = getPolicy(data, desiredPolicy); - - Collection groups = getGroups(data, policy.getTypeIdentifier()); - if (groups.isEmpty()) { - throw new PfModelException(Status.BAD_REQUEST, "policy not supported by any PDP group: " - + desiredPolicy.getName() + " " + desiredPolicy.getVersion()); - } - - Updater updater = makeUpdater(data, policy, desiredPolicy); - - for (PdpGroup group : groups) { - upgradeGroup(data, 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 data session data - * @param policy policy to be added to or removed from each subgroup - * @param desiredPolicy request policy - * @return a function to update a subgroup - */ - protected abstract Updater makeUpdater(SessionData data, ToscaPolicy policy, - ToscaPolicyIdentifierOptVersion desiredPolicy); - - /** - * Finds the active PDP group(s) 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 occurred - */ - private Collection getGroups(SessionData data, ToscaPolicyTypeIdentifier policyType) - throws PfModelException { - - return data.getActivePdpGroupsByPolicyType(policyType); - } - - /** - * Updates a group, assigning a new version number, if it actually changes. - * - * @param data session data - * @param group the original group, to be updated - * @param updater function to update a group - * @throws PfModelException if an error occurred - */ - private void upgradeGroup(SessionData data, PdpGroup group, Updater updater) throws PfModelException { - - boolean updated = false; - - for (PdpSubGroup subgroup : group.getPdpSubgroups()) { - - if (!updater.apply(group, subgroup)) { - continue; - } - - updated = true; - - makeUpdates(data, group, subgroup); - } - - - if (updated) { - // something changed - data.update(group); - } - } - - /** - * Makes UPDATE messages for each PDP in a subgroup. - * - * @param data session data - * @param group group containing the subgroup - * @param subgroup subgroup whose PDPs should receive messages - */ - protected void makeUpdates(SessionData data, PdpGroup group, PdpSubGroup subgroup) { - for (Pdp pdp : subgroup.getPdpInstances()) { - data.addUpdate(makeUpdate(data, group, subgroup, pdp)); - } - } - - /** - * 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 pdp the PDP of interest - * @return a new UPDATE message - */ - private PdpUpdate makeUpdate(SessionData data, PdpGroup group, PdpSubGroup subgroup, Pdp pdp) { - - PdpUpdate update = new PdpUpdate(); - - update.setName(pdp.getInstanceId()); - update.setDescription(group.getDescription()); - update.setPdpGroup(group.getName()); - update.setPdpSubgroup(subgroup.getPdpType()); - update.setPolicies(subgroup.getPolicies().stream().map(ToscaPolicyIdentifierOptVersion::new) - .map(ident -> getPolicy(data, ident)).collect(Collectors.toList())); - - return update; - } - - /** - * Gets the specified policy. - * - * @param data session data - * @param ident policy identifier, with an optional version - * @return the policy of interest - * @throws PfModelRuntimeException if an error occurred or the policy was not found - */ - private ToscaPolicy getPolicy(SessionData data, ToscaPolicyIdentifierOptVersion ident) { - try { - ToscaPolicy policy = data.getPolicy(ident); - if (policy == null) { - throw new PfModelRuntimeException(Status.NOT_FOUND, - "cannot find policy: " + ident.getName() + " " + ident.getVersion()); - } - - return policy; - - } catch (PfModelException e) { - throw new PfModelRuntimeException(e.getErrorResponse().getResponseCode(), - e.getErrorResponse().getErrorMessage(), e); - } - } - - @FunctionalInterface - public static interface BiConsumerWithEx { - /** - * Performs this operation on the given arguments. - * - * @param firstArg the first input argument - * @param secondArg the second input argument - * @throws PfModelException if an error occurred - */ - void accept(F firstArg, S secondArg) throws PfModelException; - } - - @FunctionalInterface - public static interface Updater { - boolean apply(PdpGroup group, PdpSubGroup subgroup) throws PfModelException; - } -} 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 deleted file mode 100644 index 5b2a8eea..00000000 --- a/main/src/main/java/org/onap/policy/pap/main/rest/depundep/SessionData.java +++ /dev/null @@ -1,507 +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.depundep; - -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import org.apache.commons.lang3.tuple.Pair; -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.PdpStateChange; -import org.onap.policy.models.pdp.concepts.PdpUpdate; -import org.onap.policy.models.pdp.enums.PdpState; -import org.onap.policy.models.provider.PolicyModelsProvider; -import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy; -import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyFilter; -import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyFilter.ToscaPolicyFilterBuilder; -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.ToscaPolicyType; -import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyTypeIdentifier; -import org.onap.policy.pap.main.notification.PolicyPdpNotificationData; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Data used during a single REST call when updating PDP policies. - */ -public class SessionData { - private static final Logger logger = LoggerFactory.getLogger(SessionData.class); - - /** - * If a version string matches this, then it is just a prefix (i.e., major or - * major.minor). - */ - private static final Pattern VERSION_PREFIX_PAT = Pattern.compile("[^.]+(?:[.][^.]+)?"); - - /** - * DB provider. - */ - private final PolicyModelsProvider dao; - - /** - * Maps a group name to its group data. This accumulates the set of groups to be - * created and updated when the REST call completes. - */ - private final Map groupCache = new HashMap<>(); - - /** - * Maps a policy type to the list of matching groups. Every group appearing within - * this map has a corresponding entry in {@link #groupCache}. - */ - private final Map> type2groups = new HashMap<>(); - - /** - * Maps a PDP name to its most recently generated update and state-change requests. - */ - private final Map> pdpRequests = new HashMap<>(); - - /** - * Maps a policy's identifier to the policy. - */ - private final Map policyCache = new HashMap<>(); - - /** - * Maps a policy type's identifier to the policy. - */ - private final Map typeCache = new HashMap<>(); - - /** - * Policies to be deployed. This is just used to build up the data, which is then - * passed to the notifier once the update is "committed". - */ - private final Map deploy = new HashMap<>(); - - /** - * Policies to be undeployed. This is just used to build up the data, which is then - * passed to the notifier once the update is "committed". - */ - private final Map undeploy = new HashMap<>(); - - - /** - * Constructs the object. - * - * @param dao DAO provider - */ - public SessionData(PolicyModelsProvider dao) { - this.dao = dao; - } - - /** - * Gets the policy type, referenced by an identifier. Loads it from the cache, if - * possible. Otherwise, gets it from the DB. - * - * @param desiredType policy type identifier - * @return the specified policy type - * @throws PfModelException if an error occurred - */ - public ToscaPolicyType getPolicyType(ToscaPolicyTypeIdentifier desiredType) throws PfModelException { - - ToscaPolicyType type = typeCache.get(desiredType); - if (type == null) { - - List lst = dao.getPolicyTypeList(desiredType.getName(), desiredType.getVersion()); - if (lst.isEmpty()) { - return null; - } - - type = lst.get(0); - typeCache.put(desiredType, type); - } - - return type; - } - - /** - * Gets the policy, referenced by an identifier. Loads it from the cache, if possible. - * Otherwise, gets it from the DB. - * - * @param desiredPolicy policy identifier - * @return the specified policy - * @throws PfModelException if an error occurred - */ - public ToscaPolicy getPolicy(ToscaPolicyIdentifierOptVersion desiredPolicy) throws PfModelException { - - ToscaPolicy policy = policyCache.get(desiredPolicy); - if (policy == null) { - ToscaPolicyFilterBuilder filterBuilder = ToscaPolicyFilter.builder().name(desiredPolicy.getName()); - setPolicyFilterVersion(filterBuilder, desiredPolicy.getVersion()); - - List lst = dao.getFilteredPolicyList(filterBuilder.build()); - if (lst.isEmpty()) { - return null; - } - - policy = lst.get(0); - policyCache.put(desiredPolicy, policy); - } - - // desired version may have only been a prefix - cache with full identifier, too - policyCache.putIfAbsent(new ToscaPolicyIdentifierOptVersion(policy.getIdentifier()), policy); - - return policy; - } - - /** - * Sets the "version" in a policy filter. - * - * @param filterBuilder filter builder whose version should be set - * @param desiredVersion desired version - */ - private void setPolicyFilterVersion(ToscaPolicyFilterBuilder filterBuilder, String desiredVersion) { - - if (desiredVersion == null) { - // no version specified - get the latest - filterBuilder.version(ToscaPolicyFilter.LATEST_VERSION); - - } else if (isVersionPrefix(desiredVersion)) { - // version prefix provided - match the prefix and then pick the latest - filterBuilder.versionPrefix(desiredVersion + ".").version(ToscaPolicyFilter.LATEST_VERSION); - - } else { - // must be an exact match - filterBuilder.version(desiredVersion); - } - } - - /** - * Determines if a version contains only a prefix. - * - * @param version version to inspect - * @return {@code true} if the version contains only a prefix, {@code false} if it is - * fully qualified - */ - public static boolean isVersionPrefix(String version) { - return VERSION_PREFIX_PAT.matcher(version).matches(); - } - - /** - * Adds an update and state-change to the sets, replacing any previous entries for the - * given PDP. - * - * @param update the update to be added - * @param change the state-change to be added - */ - public void addRequests(PdpUpdate update, PdpStateChange change) { - if (!update.getName().equals(change.getName())) { - throw new IllegalArgumentException("PDP name mismatch " + update.getName() + ", " + change.getName()); - } - - logger.info("add update and state-change {} {} {} policies={}", update.getName(), update.getPdpGroup(), - update.getPdpSubgroup(), update.getPolicies().size()); - pdpRequests.put(update.getName(), Pair.of(update, change)); - } - - /** - * 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) { - logger.info("add update {} {} {} policies={}", update.getName(), update.getPdpGroup(), update.getPdpSubgroup(), - update.getPolicies().size()); - pdpRequests.compute(update.getName(), (name, data) -> Pair.of(update, (data == null ? null : data.getRight()))); - } - - /** - * Adds a state-change to the set of state-change requests, replacing any previous - * entry for the given PDP. - * - * @param change the state-change to be added - */ - public void addStateChange(PdpStateChange change) { - logger.info("add state-change {}", change.getName()); - pdpRequests.compute(change.getName(), (name, data) -> Pair.of((data == null ? null : data.getLeft()), change)); - } - - /** - * Determines if any changes were made due to the REST call. - * - * @return {@code true} if nothing was changed, {@code false} if something was changed - */ - public boolean isUnchanged() { - return groupCache.values().stream().allMatch(GroupData::isUnchanged); - } - - /** - * Gets the accumulated PDP requests. - * - * @return the PDP requests - */ - public Collection> getPdpRequests() { - return pdpRequests.values(); - } - - /** - * Gets the accumulated PDP update requests. - * - * @return the PDP requests - */ - public List getPdpUpdates() { - return pdpRequests.values().stream().filter(req -> req.getLeft() != null).map(Pair::getLeft) - .collect(Collectors.toList()); - } - - /** - * Gets the accumulated PDP state-change requests. - * - * @return the PDP requests - */ - public List getPdpStateChanges() { - return pdpRequests.values().stream().filter(req -> req.getRight() != null).map(Pair::getRight) - .collect(Collectors.toList()); - } - - /** - * Creates a group. - * - * @param newGroup the new group - */ - public void create(PdpGroup newGroup) { - String name = newGroup.getName(); - - if (groupCache.put(name, new GroupData(newGroup, true)) != null) { - throw new IllegalStateException("group already cached: " + name); - } - - logger.info("create cached group {}", newGroup.getName()); - } - - /** - * Updates a group. - * - * @param newGroup the updated group - */ - public void update(PdpGroup newGroup) { - String name = newGroup.getName(); - GroupData data = groupCache.get(name); - if (data == null) { - throw new IllegalStateException("group not cached: " + name); - } - - logger.info("update cached group {}", newGroup.getName()); - data.update(newGroup); - } - - /** - * Gets the group by the given name. - * - * @param name name of the group to get - * @return the group, or {@code null} if it does not exist - * @throws PfModelException if an error occurred - */ - public PdpGroup getGroup(String name) throws PfModelException { - - GroupData data = groupCache.get(name); - if (data == null) { - List lst = dao.getPdpGroups(name); - if (lst.isEmpty()) { - logger.info("unknown group {}", name); - return null; - } - - logger.info("cache group {}", name); - data = new GroupData(lst.get(0)); - groupCache.put(name, data); - - } else { - logger.info("use cached group {}", name); - } - - return data.getGroup(); - } - - /** - * 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 occurred - */ - public List getActivePdpGroupsByPolicyType(ToscaPolicyTypeIdentifier type) throws PfModelException { - List data = type2groups.get(type); - if (data == null) { - PdpGroupFilter filter = PdpGroupFilter.builder().policyTypeList(Collections.singletonList(type)) - .groupState(PdpState.ACTIVE).build(); - - List groups = dao.getFilteredPdpGroups(filter); - - data = groups.stream().map(this::addGroup).collect(Collectors.toList()); - type2groups.put(type, data); - } - - return data.stream().map(GroupData::getGroup).collect(Collectors.toList()); - } - - /** - * Adds a group to the group cache, if it isn't already in the cache. - * - * @param group the group to be added - * @return the cache entry - */ - private GroupData addGroup(PdpGroup group) { - GroupData data = groupCache.get(group.getName()); - if (data == null) { - logger.info("cache group {}", group.getName()); - data = new GroupData(group); - groupCache.put(group.getName(), data); - - } else { - logger.info("use cached group {}", group.getName()); - } - - return data; - } - - /** - * Update the DB with the changes. - * - * @throws PfModelException if an error occurred - */ - public void updateDb() throws PfModelException { - // create new groups - List created = groupCache.values().stream().filter(GroupData::isNew).collect(Collectors.toList()); - if (!created.isEmpty()) { - if (logger.isInfoEnabled()) { - created.forEach(group -> logger.info("creating DB group {}", group.getGroup().getName())); - } - dao.createPdpGroups(created.stream().map(GroupData::getGroup).collect(Collectors.toList())); - } - - // update existing groups - List updated = - groupCache.values().stream().filter(GroupData::isUpdated).collect(Collectors.toList()); - if (!updated.isEmpty()) { - if (logger.isInfoEnabled()) { - updated.forEach(group -> logger.info("updating DB group {}", group.getGroup().getName())); - } - dao.updatePdpGroups(updated.stream().map(GroupData::getGroup).collect(Collectors.toList())); - } - } - - /** - * Deletes a group from the DB, immediately (i.e., without caching the request to be - * executed later). - * - * @param group the group to be deleted - * @throws PfModelException if an error occurred - */ - public void deleteGroupFromDb(PdpGroup group) throws PfModelException { - logger.info("deleting DB group {}", group.getName()); - dao.deletePdpGroup(group.getName()); - } - - /** - * Adds policy deployment data. - * - * @param policyId ID of the policy being deployed - * @param pdps PDPs to which the policy is being deployed - * @throws PfModelException if an error occurred - */ - protected void trackDeploy(ToscaPolicyIdentifier policyId, Collection pdps) throws PfModelException { - trackDeploy(policyId, new HashSet<>(pdps)); - } - - /** - * Adds policy deployment data. - * - * @param policyId ID of the policy being deployed - * @param pdps PDPs to which the policy is being deployed - * @throws PfModelException if an error occurred - */ - protected void trackDeploy(ToscaPolicyIdentifier policyId, Set pdps) throws PfModelException { - addData(policyId, pdps, deploy, undeploy); - } - - /** - * Adds policy undeployment data. - * - * @param policyId ID of the policy being undeployed - * @param pdps PDPs to which the policy is being undeployed - * @throws PfModelException if an error occurred - */ - protected void trackUndeploy(ToscaPolicyIdentifier policyId, Collection pdps) throws PfModelException { - trackUndeploy(policyId, new HashSet<>(pdps)); - } - - /** - * Adds policy undeployment data. - * - * @param policyId ID of the policy being undeployed - * @param pdps PDPs to which the policy is being undeployed - * @throws PfModelException if an error occurred - */ - protected void trackUndeploy(ToscaPolicyIdentifier policyId, Set pdps) throws PfModelException { - addData(policyId, pdps, undeploy, deploy); - } - - /** - * Adds policy deployment/undeployment data. - * - * @param policyId ID of the policy being deployed/undeployed - * @param pdps PDPs to which the policy is being deployed/undeployed - * @param addMap map to which it should be added - * @param removeMap map from which it should be removed - * @throws PfModelException if an error occurred - */ - private void addData(ToscaPolicyIdentifier policyId, Set pdps, - Map addMap, - Map removeMap) throws PfModelException { - - PolicyPdpNotificationData removeData = removeMap.get(policyId); - if (removeData != null) { - removeData.removeAll(pdps); - } - - ToscaPolicyIdentifierOptVersion optid = new ToscaPolicyIdentifierOptVersion(policyId); - ToscaPolicyTypeIdentifier policyType = getPolicy(optid).getTypeIdentifier(); - - addMap.computeIfAbsent(policyId, key -> new PolicyPdpNotificationData(policyId, policyType)).addAll(pdps); - } - - /** - * Gets the policies to be deployed. - * - * @return the policies to be deployed - */ - public Collection getDeployData() { - return deploy.values(); - } - - /** - * Gets the policies to be undeployed. - * - * @return the policies to be undeployed - */ - public Collection getUndeployData() { - return undeploy.values(); - } -} diff --git a/main/src/main/java/org/onap/policy/pap/main/startstop/PapActivator.java b/main/src/main/java/org/onap/policy/pap/main/startstop/PapActivator.java index 8af66362..f784ed5e 100644 --- a/main/src/main/java/org/onap/policy/pap/main/startstop/PapActivator.java +++ b/main/src/main/java/org/onap/policy/pap/main/startstop/PapActivator.java @@ -50,14 +50,14 @@ import org.onap.policy.pap.main.parameters.PdpParameters; import org.onap.policy.pap.main.rest.HealthCheckRestControllerV1; import org.onap.policy.pap.main.rest.PapAafFilter; import org.onap.policy.pap.main.rest.PapStatisticsManager; +import org.onap.policy.pap.main.rest.PdpGroupDeleteControllerV1; +import org.onap.policy.pap.main.rest.PdpGroupDeployControllerV1; import org.onap.policy.pap.main.rest.PdpGroupHealthCheckControllerV1; import org.onap.policy.pap.main.rest.PdpGroupQueryControllerV1; import org.onap.policy.pap.main.rest.PdpGroupStateChangeControllerV1; import org.onap.policy.pap.main.rest.PolicyStatusControllerV1; +import org.onap.policy.pap.main.rest.PolicyUndeployerImpl; import org.onap.policy.pap.main.rest.StatisticsRestControllerV1; -import org.onap.policy.pap.main.rest.depundep.PdpGroupDeleteControllerV1; -import org.onap.policy.pap.main.rest.depundep.PdpGroupDeployControllerV1; -import org.onap.policy.pap.main.rest.depundep.PolicyUndeployerImpl; /** * This class activates Policy Administration (PAP) as a complete service together with all its controllers, listeners & diff --git a/main/src/test/java/org/onap/policy/pap/main/rest/ProviderSuper.java b/main/src/test/java/org/onap/policy/pap/main/rest/ProviderSuper.java new file mode 100644 index 00000000..852516b7 --- /dev/null +++ b/main/src/test/java/org/onap/policy/pap/main/rest/ProviderSuper.java @@ -0,0 +1,276 @@ +/*- + * ============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 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.Collections; +import java.util.List; +import java.util.stream.Collectors; +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.PdpGroups; +import org.onap.policy.models.pdp.concepts.PdpStateChange; +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.ToscaPolicyType; +import org.onap.policy.pap.main.PapConstants; +import org.onap.policy.pap.main.PolicyModelsProviderFactoryWrapper; +import org.onap.policy.pap.main.comm.PdpModifyRequestMap; +import org.onap.policy.pap.main.notification.PolicyNotifier; + +/** + * Super class for TestPdpGroupDeployProviderXxx classes. + */ +public class ProviderSuper { + private static final Coder coder = new StandardCoder(); + + @Mock + protected PolicyModelsProvider dao; + + @Mock + protected PolicyNotifier notifier; + + + /** + * Used to capture input to dao.updatePdpGroups() and dao.createPdpGroups(). + */ + @Captor + private ArgumentCaptor> 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 = loadPolicy("policy.json"); + + when(daofact.create()).thenReturn(dao); + + List 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); + Registry.register(PapConstants.REG_POLICY_NOTIFIER, notifier); + } + + protected void assertGroup(List groups, String name) { + PdpGroup group = groups.remove(0); + + assertEquals(name, group.getName()); + } + + protected void assertUpdateIgnorePolicy(List 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 create() method. + * + * @return the input that was passed to the dao.updatePdpGroups() method + * @throws Exception if an error occurred + */ + protected List getGroupCreates() throws Exception { + verify(dao).createPdpGroups(updateCaptor.capture()); + + return copyList(updateCaptor.getValue()); + } + + /** + * Gets the input to the update() method. + * + * @return the input that was passed to the dao.updatePdpGroups() method + * @throws Exception if an error occurred + */ + protected List getGroupUpdates() throws Exception { + verify(dao).updatePdpGroups(updateCaptor.capture()); + + return copyList(updateCaptor.getValue()); + } + + /** + * Gets the state-changes that were added to the request map. + * + * @param count the number of times the method is expected to have been called + * @return the state-changes that were added to the request map + */ + protected List getStateChangeRequests(int count) { + ArgumentCaptor captor = ArgumentCaptor.forClass(PdpStateChange.class); + + verify(reqmap, times(count)).addRequest(any(), captor.capture()); + + return captor.getAllValues().stream().filter(req -> req != null).collect(Collectors.toList()); + } + + /** + * 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 getUpdateRequests(int count) { + ArgumentCaptor captor = ArgumentCaptor.forClass(PdpUpdate.class); + + verify(reqmap, times(count)).addRequest(captor.capture(), any()); + + return captor.getAllValues().stream().filter(req -> req != null).collect(Collectors.toList()); + } + + /** + * Copies a list and sorts it by group name. + * + * @param source source list to copy + * @return a copy of the source list + */ + private List copyList(List source) { + List newlst = new ArrayList<>(source); + Collections.sort(newlst, (left, right) -> left.getName().compareTo(right.getName())); + return newlst; + } + + /** + * Loads a list of groups. + * + * @param fileName name of the file from which to load + * @return a list of groups + */ + protected List loadGroups(String fileName) { + return loadPdpGroups(fileName).getGroups(); + } + + /** + * Loads a PdpGroups. + * + * @param fileName name of the file from which to load + * @return a PdpGroups + */ + protected PdpGroups loadPdpGroups(String fileName) { + return loadFile(fileName, PdpGroups.class); + } + + /** + * Loads a group. + * + * @param fileName name of the file from which to load + * @return a group + */ + protected PdpGroup loadGroup(String fileName) { + return loadFile(fileName, PdpGroup.class); + } + + /** + * Loads a list of policies. + * + * @param fileName name of the file from which to load + * @return a list of policies + */ + protected List loadPolicies(String fileName) { + return loadFile(fileName, PolicyList.class).policies; + } + + /** + * Loads a policy. + * + * @param fileName name of the file from which to load + * @return a policy + */ + protected ToscaPolicy loadPolicy(String fileName) { + return loadFile(fileName, ToscaPolicy.class); + } + + /** + * Loads a policy type. + * + * @param fileName name of the file from which to load + * @return a policy type + */ + protected ToscaPolicyType loadPolicyType(String fileName) { + return loadFile(fileName, ToscaPolicyType.class); + } + + /** + * 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 loadFile(String fileName, Class 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 policies; + } +} diff --git a/main/src/test/java/org/onap/policy/pap/main/rest/TestGroupData.java b/main/src/test/java/org/onap/policy/pap/main/rest/TestGroupData.java new file mode 100644 index 00000000..5eb5611f --- /dev/null +++ b/main/src/test/java/org/onap/policy/pap/main/rest/TestGroupData.java @@ -0,0 +1,103 @@ +/* + * ============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 static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + +import org.junit.Before; +import org.junit.Test; +import org.onap.policy.models.pdp.concepts.PdpGroup; + +public class TestGroupData { + private static final String NAME = "my-name"; + + private PdpGroup oldGroup; + private PdpGroup newGroup; + private GroupData data; + + /** + * Sets up. + */ + @Before + public void setUp() { + oldGroup = new PdpGroup(); + oldGroup.setName(NAME); + + newGroup = new PdpGroup(oldGroup); + + data = new GroupData(oldGroup); + } + + @Test + public void testNew() { + data = new GroupData(oldGroup, true); + assertSame(oldGroup, data.getGroup()); + + assertFalse(data.isUnchanged()); + assertTrue(data.isNew()); + assertFalse(data.isUpdated()); + + data.update(newGroup); + assertFalse(data.isUnchanged()); + assertTrue(data.isNew()); + assertFalse(data.isUpdated()); + assertSame(newGroup, data.getGroup()); + + // repeat with a new group + newGroup = new PdpGroup(oldGroup); + data.update(newGroup); + assertFalse(data.isUnchanged()); + assertTrue(data.isNew()); + assertFalse(data.isUpdated()); + assertSame(newGroup, data.getGroup()); + } + + @Test + public void testUpdateOnly() { + assertTrue(data.isUnchanged()); + assertFalse(data.isUpdated()); + assertSame(oldGroup, data.getGroup()); + + data.update(newGroup); + + assertFalse(data.isUnchanged()); + assertTrue(data.isUpdated()); + assertFalse(data.isNew()); + assertSame(newGroup, data.getGroup()); + + // repeat + newGroup = new PdpGroup(oldGroup); + data.update(newGroup); + assertFalse(data.isUnchanged()); + assertTrue(data.isUpdated()); + assertFalse(data.isNew()); + assertSame(newGroup, data.getGroup()); + + // incorrect name + newGroup = new PdpGroup(oldGroup); + newGroup.setName("other"); + assertThatIllegalArgumentException().isThrownBy(() -> data.update(newGroup)) + .withMessage("expected group my-name, but received other"); + } +} diff --git a/main/src/test/java/org/onap/policy/pap/main/rest/TestPdpGroupDeleteControllerV1.java b/main/src/test/java/org/onap/policy/pap/main/rest/TestPdpGroupDeleteControllerV1.java new file mode 100644 index 00000000..0f1ab1f8 --- /dev/null +++ b/main/src/test/java/org/onap/policy/pap/main/rest/TestPdpGroupDeleteControllerV1.java @@ -0,0 +1,104 @@ +/* + * ============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.rest; + +import static org.junit.Assert.assertEquals; + +import javax.ws.rs.client.Invocation; +import javax.ws.rs.core.Response; +import org.junit.Test; +import org.onap.policy.models.pap.concepts.PdpGroupDeleteResponse; + +/** + * Note: this tests failure cases; success cases are tested by tests in the "e2e" package. + */ +public class TestPdpGroupDeleteControllerV1 extends CommonPapRestServer { + + private static final String GROUP_NOT_FOUND = "group not found"; + private static final String DELETE_GROUP_ENDPOINT = "pdps/groups"; + private static final String DELETE_POLICIES_ENDPOINT = "pdps/policies"; + + @Test + public void testSwagger() throws Exception { + super.testSwagger(DELETE_GROUP_ENDPOINT + "/{name}"); + + super.testSwagger(DELETE_POLICIES_ENDPOINT + "/{name}"); + super.testSwagger(DELETE_POLICIES_ENDPOINT + "/{name}/versions/{version}"); + } + + @Test + public void testDeleteGroup() throws Exception { + String uri = DELETE_GROUP_ENDPOINT + "/my-name"; + + Invocation.Builder invocationBuilder = sendRequest(uri); + Response rawresp = invocationBuilder.delete(); + PdpGroupDeleteResponse resp = rawresp.readEntity(PdpGroupDeleteResponse.class); + assertEquals(Response.Status.NOT_FOUND.getStatusCode(), rawresp.getStatus()); + assertEquals(GROUP_NOT_FOUND, resp.getErrorDetails()); + + rawresp = invocationBuilder.delete(); + resp = rawresp.readEntity(PdpGroupDeleteResponse.class); + assertEquals(Response.Status.NOT_FOUND.getStatusCode(), rawresp.getStatus()); + assertEquals(GROUP_NOT_FOUND, resp.getErrorDetails()); + + // verify it fails when no authorization info is included + checkUnauthRequest(uri, req -> req.delete()); + } + + @Test + public void testDeletePolicy() throws Exception { + String uri = DELETE_POLICIES_ENDPOINT + "/my-name"; + + Invocation.Builder invocationBuilder = sendRequest(uri); + Response rawresp = invocationBuilder.delete(); + PdpGroupDeleteResponse resp = rawresp.readEntity(PdpGroupDeleteResponse.class); + assertEquals(Response.Status.NOT_FOUND.getStatusCode(), rawresp.getStatus()); + assertEquals("cannot find policy: my-name null", resp.getErrorDetails()); + + rawresp = invocationBuilder.delete(); + resp = rawresp.readEntity(PdpGroupDeleteResponse.class); + assertEquals(Response.Status.NOT_FOUND.getStatusCode(), rawresp.getStatus()); + assertEquals("cannot find policy: my-name null", resp.getErrorDetails()); + + // verify it fails when no authorization info is included + checkUnauthRequest(uri, req -> req.delete()); + } + + @Test + public void testDeletePolicyVersion() throws Exception { + String uri = DELETE_POLICIES_ENDPOINT + "/my-name/versions/3"; + + Invocation.Builder invocationBuilder = sendRequest(uri); + Response rawresp = invocationBuilder.delete(); + PdpGroupDeleteResponse resp = rawresp.readEntity(PdpGroupDeleteResponse.class); + assertEquals(Response.Status.NOT_FOUND.getStatusCode(), rawresp.getStatus()); + assertEquals("cannot find policy: my-name 3", resp.getErrorDetails()); + + rawresp = invocationBuilder.delete(); + resp = rawresp.readEntity(PdpGroupDeleteResponse.class); + assertEquals(Response.Status.NOT_FOUND.getStatusCode(), rawresp.getStatus()); + assertEquals("cannot find policy: my-name 3", resp.getErrorDetails()); + + // verify it fails when no authorization info is included + checkUnauthRequest(uri, req -> req.delete()); + } +} diff --git a/main/src/test/java/org/onap/policy/pap/main/rest/TestPdpGroupDeleteProvider.java b/main/src/test/java/org/onap/policy/pap/main/rest/TestPdpGroupDeleteProvider.java new file mode 100644 index 00000000..ae356e83 --- /dev/null +++ b/main/src/test/java/org/onap/policy/pap/main/rest/TestPdpGroupDeleteProvider.java @@ -0,0 +1,297 @@ +/*- + * ============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 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.Matchers.eq; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.Arrays; +import java.util.List; +import java.util.Set; +import javax.ws.rs.core.Response.Status; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.onap.policy.common.utils.services.Registry; +import org.onap.policy.models.base.PfModelException; +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.tosca.authorative.concepts.ToscaPolicyIdentifier; +import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyIdentifierOptVersion; +import org.onap.policy.pap.main.rest.ProviderBase.Updater; + +public class TestPdpGroupDeleteProvider extends ProviderSuper { + private static final String EXPECTED_EXCEPTION = "expected exception"; + private static final String GROUP1_NAME = "groupA"; + + @Mock + private SessionData session; + + @Captor + private ArgumentCaptor> pdpCaptor; + + private MyProvider prov; + private ToscaPolicyIdentifierOptVersion optIdent; + private ToscaPolicyIdentifierOptVersion fullIdent; + private ToscaPolicyIdentifier ident; + private Updater updater; + + + @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(); + + ident = policy1.getIdentifier(); + optIdent = new ToscaPolicyIdentifierOptVersion(ident.getName(), null); + fullIdent = new ToscaPolicyIdentifierOptVersion(ident.getName(), ident.getVersion()); + + prov = new MyProvider(); + + updater = prov.makeUpdater(session, policy1, fullIdent); + } + + @Test + public void testDeleteGroup_Inctive() throws Exception { + PdpGroup group = loadGroup("deleteGroup.json"); + + when(session.getGroup(GROUP1_NAME)).thenReturn(group); + + prov.deleteGroup(GROUP1_NAME); + + verify(session).deleteGroupFromDb(group); + + // should be no PDP requests + verify(session, never()).addRequests(any(), any()); + } + + @Test + public void testDeleteGroup_Active() throws Exception { + PdpGroup group = loadGroup("deleteGroup.json"); + + group.setPdpGroupState(PdpState.ACTIVE); + + when(session.getGroup(GROUP1_NAME)).thenReturn(group); + + assertThatThrownBy(() -> prov.deleteGroup(GROUP1_NAME)).isInstanceOf(PfModelException.class) + .hasMessage("group is still ACTIVE"); + } + + @Test + public void testDeleteGroup_NotFound() throws Exception { + assertThatThrownBy(() -> prov.deleteGroup(GROUP1_NAME)).isInstanceOf(PfModelException.class) + .hasMessage("group not found") + .extracting(ex -> ((PfModelException) ex).getErrorResponse().getResponseCode()) + .isEqualTo(Status.NOT_FOUND); + } + + @Test + public void testDeleteGroup_Inactive() throws Exception { + PdpGroup group = loadGroup("deleteGroup.json"); + + when(session.getGroup(GROUP1_NAME)).thenReturn(group); + + prov.deleteGroup(GROUP1_NAME); + + verify(session).deleteGroupFromDb(group); + + // should done no requests for the PDPs + verify(session, never()).addRequests(any(), any()); + } + + @Test + public void testDeleteGroup_DaoEx() throws Exception { + PdpGroup group = loadGroup("deleteGroup.json"); + + when(session.getGroup(GROUP1_NAME)).thenReturn(group); + + PfModelException ex = new PfModelException(Status.BAD_REQUEST, EXPECTED_EXCEPTION); + doThrow(ex).when(session).deleteGroupFromDb(group); + + assertThatThrownBy(() -> prov.deleteGroup(GROUP1_NAME)).isSameAs(ex); + } + + @Test + public void testUndeploy_testUndeployPolicy() throws Exception { + prov.undeploy(optIdent); + } + + /** + * Tests using a real provider, just to verify end-to-end functionality. + * + * @throws Exception if an error occurs + */ + @Test + public void testUndeploy_Full() throws Exception { + when(dao.getFilteredPolicyList(any())).thenReturn(Arrays.asList(policy1)); + + PdpGroup group = loadGroup("undeploy.json"); + + when(dao.getFilteredPdpGroups(any())).thenReturn(Arrays.asList(group)); + when(dao.getFilteredPolicyList(any())).thenReturn(Arrays.asList(policy1)); + + new PdpGroupDeleteProvider().undeploy(fullIdent); + + // should have updated the old group + List updates = getGroupUpdates(); + assertEquals(1, updates.size()); + assertSame(group, updates.get(0)); + assertEquals(PdpState.ACTIVE, group.getPdpGroupState()); + + // should be one less item in the new subgroup + assertEquals(2, group.getPdpSubgroups().get(0).getPolicies().size()); + + // should have updated the PDPs + List requests = getUpdateRequests(1); + assertEquals(1, requests.size()); + PdpUpdate req = requests.get(0); + assertEquals("pdpA", req.getName()); + assertEquals(GROUP1_NAME, req.getPdpGroup()); + assertEquals("pdpTypeA", req.getPdpSubgroup()); + assertEquals(Arrays.asList(policy1, policy1), req.getPolicies()); + } + + @Test + public void testUndeployPolicy_NotFound() throws Exception { + when(session.isUnchanged()).thenReturn(true); + + assertThatThrownBy(() -> prov.undeploy(optIdent)).isInstanceOf(PfModelException.class) + .hasMessage("policy does not appear in any PDP group: policyA null"); + } + + @Test + public void testUndeployPolicy_DaoEx() throws Exception { + PfModelException exc = new PfModelException(Status.BAD_REQUEST, EXPECTED_EXCEPTION); + + prov = spy(prov); + doThrow(exc).when(prov).processPolicy(any(), any()); + + assertThatThrownBy(() -> prov.undeploy(optIdent)).isSameAs(exc); + } + + @Test + public void testUndeployPolicy_RtEx() throws Exception { + RuntimeException exc = new RuntimeException(EXPECTED_EXCEPTION); + + prov = spy(prov); + doThrow(exc).when(prov).processPolicy(any(), any()); + + assertThatThrownBy(() -> prov.undeploy(optIdent)).isSameAs(exc); + } + + @Test + public void testMakeUpdater_WithVersion() throws PfModelException { + /* + * this group has two matching policies and one policy with a different name. + */ + PdpGroup group = loadGroup("undeploy.json"); + + PdpSubGroup subgroup = group.getPdpSubgroups().get(0); + int origSize = subgroup.getPolicies().size(); + + // invoke updater - matching both name and version + assertTrue(updater.apply(group, subgroup)); + + // identified policy should have been removed + assertEquals(origSize - 1, subgroup.getPolicies().size()); + assertFalse(subgroup.getPolicies().contains(ident)); + + verify(session).trackUndeploy(eq(ident), pdpCaptor.capture()); + assertEquals("[pdpA]", pdpCaptor.getValue().toString()); + } + + @Test + public void testMakeUpdater_NullVersion() throws PfModelException { + /* + * this group has two matching policies and one policy with a different name. + */ + PdpGroup group = loadGroup("undeploy.json"); + + PdpSubGroup subgroup = group.getPdpSubgroups().get(0); + int origSize = subgroup.getPolicies().size(); + + // invoke updater - matching the name, but with a null (i.e., wild-card) version + updater = prov.makeUpdater(session, policy1, optIdent); + assertTrue(updater.apply(group, subgroup)); + + // identified policy should have been removed + assertEquals(origSize - 2, subgroup.getPolicies().size()); + assertFalse(subgroup.getPolicies().contains(ident)); + } + + @Test + public void testMakeUpdater_NotFound() throws PfModelException { + /* + * this group has one policy with a different name and one with a different + * version, but not the policy of interest. + */ + PdpGroup group = loadGroup("undeployMakeUpdaterGroupNotFound.json"); + + PdpSubGroup subgroup = group.getPdpSubgroups().get(0); + int origSize = subgroup.getPolicies().size(); + + // invoke updater + assertFalse(updater.apply(group, subgroup)); + + // should be unchanged + assertEquals(origSize, subgroup.getPolicies().size()); + } + + + private class MyProvider extends PdpGroupDeleteProvider { + + @Override + protected void process(T request, BiConsumerWithEx processor) throws PfModelException { + processor.accept(session, request); + } + + @Override + protected void processPolicy(SessionData data, ToscaPolicyIdentifierOptVersion desiredPolicy) + throws PfModelException { + // do nothing + } + } +} diff --git a/main/src/test/java/org/onap/policy/pap/main/rest/TestPdpGroupDeployControllerV1.java b/main/src/test/java/org/onap/policy/pap/main/rest/TestPdpGroupDeployControllerV1.java new file mode 100644 index 00000000..a26213d7 --- /dev/null +++ b/main/src/test/java/org/onap/policy/pap/main/rest/TestPdpGroupDeployControllerV1.java @@ -0,0 +1,112 @@ +/* + * ============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.rest; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.util.Arrays; +import javax.ws.rs.client.Entity; +import javax.ws.rs.client.Invocation; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import org.junit.Test; +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.PdpSubGroup; +import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyIdentifierOptVersion; + +/** + * Note: this tests failure cases; success cases are tested by tests in the "e2e" package. + */ +public class TestPdpGroupDeployControllerV1 extends CommonPapRestServer { + + private static final String DEPLOY_GROUP_ENDPOINT = "pdps"; + private static final String DEPLOY_POLICIES_ENDPOINT = "pdps/policies"; + + @Test + public void testSwagger() throws Exception { + super.testSwagger(DEPLOY_GROUP_ENDPOINT); + super.testSwagger(DEPLOY_POLICIES_ENDPOINT); + } + + @Test + public void testDeployGroup() throws Exception { + Entity entgrp = makePdpGroupEntity(); + + Invocation.Builder invocationBuilder = sendRequest(DEPLOY_GROUP_ENDPOINT); + Response rawresp = invocationBuilder.post(entgrp); + PdpGroupDeployResponse resp = rawresp.readEntity(PdpGroupDeployResponse.class); + assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), rawresp.getStatus()); + assertNotNull(resp.getErrorDetails()); + + rawresp = invocationBuilder.post(entgrp); + resp = rawresp.readEntity(PdpGroupDeployResponse.class); + assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), rawresp.getStatus()); + assertNotNull(resp.getErrorDetails()); + + // verify it fails when no authorization info is included + checkUnauthRequest(DEPLOY_GROUP_ENDPOINT, req -> req.post(entgrp)); + } + + @Test + public void testDeployPolicies() throws Exception { + Entity entgrp = makePdpPoliciesEntity(); + + Invocation.Builder invocationBuilder = sendRequest(DEPLOY_POLICIES_ENDPOINT); + Response rawresp = invocationBuilder.post(entgrp); + PdpGroupDeployResponse resp = rawresp.readEntity(PdpGroupDeployResponse.class); + assertEquals(Response.Status.NOT_FOUND.getStatusCode(), rawresp.getStatus()); + assertNotNull(resp.getErrorDetails()); + + rawresp = invocationBuilder.post(entgrp); + resp = rawresp.readEntity(PdpGroupDeployResponse.class); + assertEquals(Response.Status.NOT_FOUND.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 makePdpGroupEntity() { + PdpSubGroup subgrp = new PdpSubGroup(); + subgrp.setPdpType("drools"); + + PdpGroup group = new PdpGroup(); + group.setName("drools-group"); + group.setDescription("my description"); + group.setPdpSubgroups(Arrays.asList(subgrp)); + + return Entity.entity(group, MediaType.APPLICATION_JSON); + } + + private Entity makePdpPoliciesEntity() { + ToscaPolicyIdentifierOptVersion pol1 = new ToscaPolicyIdentifierOptVersion("policy-a", "1"); + ToscaPolicyIdentifierOptVersion pol2 = new ToscaPolicyIdentifierOptVersion("policy-b", null); + + 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/TestPdpGroupDeployProvider.java b/main/src/test/java/org/onap/policy/pap/main/rest/TestPdpGroupDeployProvider.java new file mode 100644 index 00000000..39a11396 --- /dev/null +++ b/main/src/test/java/org/onap/policy/pap/main/rest/TestPdpGroupDeployProvider.java @@ -0,0 +1,932 @@ +/* + * ============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 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 java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.TreeMap; +import java.util.TreeSet; +import java.util.stream.Collectors; +import javax.ws.rs.core.Response.Status; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.onap.policy.common.utils.services.Registry; +import org.onap.policy.models.base.PfModelException; +import org.onap.policy.models.base.PfModelRuntimeException; +import org.onap.policy.models.pap.concepts.PdpDeployPolicies; +import org.onap.policy.models.pdp.concepts.PdpGroup; +import org.onap.policy.models.pdp.concepts.PdpGroups; +import org.onap.policy.models.pdp.concepts.PdpStateChange; +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.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.notification.PolicyPdpNotificationData; + +public class TestPdpGroupDeployProvider extends ProviderSuper { + private static final String EXPECTED_EXCEPTION = "expected exception"; + + private static final String POLICY2_NAME = "policyB"; + private static final String POLICY1_VERSION = "1.2.3"; + private static final String GROUP1_NAME = "groupA"; + 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.getFilteredPolicyList(any())).thenReturn(loadPolicies("daoPolicyList.json")); + when(dao.getPolicyTypeList("typeA", "100.2.3")).thenReturn(Arrays.asList(loadPolicyType("daoPolicyType.json"))); + + prov = new PdpGroupDeployProvider(); + } + + @Test + public void testCreateOrUpdateGroups() throws Exception { + prov.createOrUpdateGroups(loadPdpGroups("emptyGroups.json")); + + // no groups, so no action should have been taken + assertNoGroupAction(); + } + + @Test + public void testCreateOrUpdateGroups_InvalidRequest() throws Exception { + assertThatThrownBy(() -> prov.createOrUpdateGroups(new PdpGroups())).isInstanceOf(PfModelException.class) + .hasMessageContaining("is null"); + + assertNoGroupAction(); + } + + @Test + public void testCreateOrUpdate_Invalid() throws Exception { + PdpGroups groups = loadPdpGroups("createGroups.json"); + groups.getGroups().get(0).setPdpGroupState(PdpState.TERMINATED); + + assertThatThrownBy(() -> prov.createOrUpdateGroups(groups)).isInstanceOf(PfModelException.class) + .hasMessageContaining("pdpGroupState"); + + assertNoGroupAction(); + } + + @Test + public void testAddGroup() throws Exception { + PdpGroups groups = loadPdpGroups("createGroups.json"); + PdpGroup group = groups.getGroups().get(0); + group.setPdpGroupState(PdpState.PASSIVE); + + prov.createOrUpdateGroups(groups); + + // should not have updated the state + assertEquals(PdpState.PASSIVE, group.getPdpGroupState()); + + assertSame(group, getGroupCreates().get(0)); + } + + @Test + public void testAddGroup_Invalid() throws Exception { + PdpGroups groups = loadPdpGroups("createGroups.json"); + groups.getGroups().get(0).setPdpGroupState(PdpState.TERMINATED); + + assertThatThrownBy(() -> prov.createOrUpdateGroups(groups)).isInstanceOf(PfModelException.class) + .hasMessageContaining("pdpGroupState"); + + assertNoGroupAction(); + } + + @Test + public void testAddGroup_InvalidSubGroup() throws Exception { + PdpGroups groups = loadPdpGroups("createGroups.json"); + + // policy won't match supported type + groups.getGroups().get(0).getPdpSubgroups().get(0).getSupportedPolicyTypes().get(0).setVersion("99.99.99"); + + assertThatThrownBy(() -> prov.createOrUpdateGroups(groups)).isInstanceOf(PfModelException.class) + .hasMessageContaining("supported policy"); + + assertNoGroupAction(); + } + + @Test + public void testValidateGroupOnly_NullState() throws PfModelException { + PdpGroups groups = loadPdpGroups("createGroups.json"); + groups.getGroups().get(0).setPdpGroupState(null); + prov.createOrUpdateGroups(groups); + } + + @Test + public void testValidateGroupOnly_Active() throws PfModelException { + PdpGroups groups = loadPdpGroups("createGroups.json"); + groups.getGroups().get(0).setPdpGroupState(PdpState.ACTIVE); + prov.createOrUpdateGroups(groups); + } + + @Test + public void testValidateGroupOnly_Passive() throws PfModelException { + PdpGroups groups = loadPdpGroups("createGroups.json"); + groups.getGroups().get(0).setPdpGroupState(PdpState.PASSIVE); + prov.createOrUpdateGroups(groups); + } + + @Test + public void testValidateGroupOnly_Invalid() { + PdpGroups groups = loadPdpGroups("createGroups.json"); + groups.getGroups().get(0).setPdpGroupState(PdpState.TERMINATED); + + assertThatThrownBy(() -> prov.createOrUpdateGroups(groups)).isInstanceOf(PfModelException.class) + .hasMessageContaining("pdpGroupState"); + } + + @Test + public void testUpdateGroup() throws Exception { + PdpGroups groups = loadPdpGroups("createGroups.json"); + + // DB group = new group + PdpGroup group = new PdpGroup(groups.getGroups().get(0)); + when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); + + prov.createOrUpdateGroups(groups); + + assertNoGroupAction(); + } + + @Test + public void testUpdateGroup_PropertiesChanged() throws Exception { + PdpGroups groups = loadPdpGroups("createGroups.json"); + + PdpGroup group = new PdpGroup(groups.getGroups().get(0)); + group.setProperties(new TreeMap<>()); + + when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); + + assertThatThrownBy(() -> prov.createOrUpdateGroups(groups)).isInstanceOf(PfModelException.class) + .hasMessageContaining("properties"); + + assertNoGroupAction(); + } + + @Test + public void testUpdateGroup_NewDescription() throws Exception { + PdpGroups groups = loadPdpGroups("createGroups.json"); + PdpGroup newgrp = groups.getGroups().get(0); + PdpGroup group = new PdpGroup(newgrp); + group.setDescription("old description"); + when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); + + prov.createOrUpdateGroups(groups); + + assertGroupUpdateOnly(group); + + assertEquals(group.getDescription(), "my description"); + assertEquals(newgrp.toString(), group.toString()); + } + + @Test + public void testUpdateGroup_NewState() throws Exception { + PdpGroups groups = loadPdpGroups("createGroups.json"); + PdpGroup newgrp = groups.getGroups().get(0); + PdpGroup group = new PdpGroup(newgrp); + group.setPdpGroupState(PdpState.TEST); + when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); + + prov.createOrUpdateGroups(groups); + + assertGroupUpdateOnly(group); + + assertEquals(PdpState.ACTIVE, group.getPdpGroupState()); + assertEquals(newgrp.toString(), group.toString()); + } + + @Test + public void testUpdateGroup_NewSubGroup() throws Exception { + PdpGroups groups = loadPdpGroups("createGroupsNewSub.json"); + PdpGroup group = loadPdpGroups("createGroups.json").getGroups().get(0); + when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); + + prov.createOrUpdateGroups(groups); + + PdpGroup newgrp = groups.getGroups().get(0); + assertEquals(newgrp.toString(), group.toString()); + assertGroupUpdateOnly(group); + } + + @Test + public void testUpdateGroup_UpdatedSubGroup() throws Exception { + PdpGroups groups = loadPdpGroups("createGroups.json"); + PdpGroup newgrp = groups.getGroups().get(0); + PdpGroup group = new PdpGroup(newgrp); + when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); + + // something different in this subgroup + group.getPdpSubgroups().get(0).setDesiredInstanceCount(10); + + prov.createOrUpdateGroups(groups); + + assertEquals(newgrp.toString(), group.toString()); + assertGroupUpdateOnly(group); + } + + @Test + public void testUpdateGroup_notifyPdpsDelSubGroups() throws Exception { + PdpGroup dbgroup = new PdpGroup(loadPdpGroups("createGroupsDelSub.json").getGroups().get(0)); + when(dao.getPdpGroups(dbgroup.getName())).thenReturn(Arrays.asList(dbgroup)); + + PdpGroups groups = loadPdpGroups("createGroups.json"); + + prov.createOrUpdateGroups(groups); + + // verify that DB group was updated + List updates = getGroupUpdates(); + assertEquals(1, updates.size()); + dbgroup = updates.get(0); + + PdpGroup newgrp = groups.getGroups().get(0); + + Collections.sort(newgrp.getPdpSubgroups().get(0).getPolicies()); + Collections.sort(dbgroup.getPdpSubgroups().get(0).getPolicies()); + + assertEquals(newgrp.toString(), dbgroup.toString()); + + // no deployment notifications + verify(notifier, never()).addDeploymentData(any()); + + // should have notified of deleted subgroup's policies/PDPs + ArgumentCaptor captor = ArgumentCaptor.forClass(PolicyPdpNotificationData.class); + verify(notifier).addUndeploymentData(captor.capture()); + assertDeploymentData(captor, policy1.getIdentifier(), "[pdpB, pdpD]"); + + // this requires a PDP UPDATE message + List pdpUpdates = getUpdateRequests(2); + assertEquals(2, pdpUpdates.size()); + + PdpUpdate pdpUpdate = pdpUpdates.get(0); + assertEquals(PDP2, pdpUpdate.getName()); + assertNull(pdpUpdate.getPdpGroup()); + + pdpUpdate = pdpUpdates.get(1); + assertEquals(PDP4, pdpUpdate.getName()); + assertNull(pdpUpdate.getPdpGroup()); + + // it also requires a PDP STATE-CHANGE message + List changes = getStateChangeRequests(2); + assertEquals(2, changes.size()); + + PdpStateChange change = changes.get(0); + assertEquals(PDP2, change.getName()); + assertEquals(PdpState.PASSIVE, change.getState()); + + change = changes.get(1); + assertEquals(PDP4, change.getName()); + assertEquals(PdpState.PASSIVE, change.getState()); + } + + @Test + public void testUpdateGroup_MultipleChanges() throws Exception { + PdpGroups groups = loadPdpGroups("createGroups.json"); + PdpGroup newgrp = groups.getGroups().get(0); + PdpGroup group = new PdpGroup(newgrp); + when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); + + PdpSubGroup subgrp = newgrp.getPdpSubgroups().get(0); + subgrp.setDesiredInstanceCount(30); + subgrp.getPolicies().add(new ToscaPolicyIdentifier(POLICY2_NAME, POLICY1_VERSION)); + subgrp.getSupportedPolicyTypes().add(new ToscaPolicyTypeIdentifier("typeX.*", "9.8.7")); + + when(dao.getFilteredPolicyList(any())) + .thenReturn(loadPolicies("createGroupNewPolicy.json")) + .thenReturn(loadPolicies("daoPolicyList.json")) + .thenReturn(loadPolicies("createGroupNewPolicy.json")); + + prov.createOrUpdateGroups(groups); + + Collections.sort(newgrp.getPdpSubgroups().get(0).getPolicies()); + Collections.sort(group.getPdpSubgroups().get(0).getPolicies()); + + assertEquals(newgrp.toString(), group.toString()); + + // this requires a PDP UPDATE message + assertGroupUpdate(group, subgrp); + } + + @Test + public void testUpdateField_Unchanged() throws Exception { + PdpGroups groups = loadPdpGroups("createGroups.json"); + PdpGroup newgrp = groups.getGroups().get(0); + PdpGroup group = new PdpGroup(newgrp); + when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); + + prov.createOrUpdateGroups(groups); + + assertNoGroupAction(); + } + + @Test + public void testUpdateField_WasNull() throws Exception { + PdpGroups groups = loadPdpGroups("createGroups.json"); + PdpGroup newgrp = groups.getGroups().get(0); + PdpGroup group = new PdpGroup(newgrp); + when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); + + group.setDescription(null); + + prov.createOrUpdateGroups(groups); + + assertEquals(newgrp.toString(), group.toString()); + assertGroupUpdateOnly(group); + } + + @Test + public void testUpdateField_NowNull() throws Exception { + PdpGroups groups = loadPdpGroups("createGroups.json"); + PdpGroup newgrp = groups.getGroups().get(0); + PdpGroup group = new PdpGroup(newgrp); + when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); + + newgrp.setDescription(null); + + prov.createOrUpdateGroups(groups); + + assertEquals(newgrp.toString(), group.toString()); + assertGroupUpdateOnly(group); + } + + @Test + public void testUpdateField_Changed() throws Exception { + PdpGroups groups = loadPdpGroups("createGroups.json"); + PdpGroup newgrp = groups.getGroups().get(0); + PdpGroup group = new PdpGroup(newgrp); + when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); + + newgrp.setDescription(group.getDescription() + "-changed"); + + prov.createOrUpdateGroups(groups); + + assertEquals(newgrp.toString(), group.toString()); + assertGroupUpdateOnly(group); + } + + @Test + public void testAddSubGroup() throws Exception { + PdpGroups groups = loadPdpGroups("createGroupsNewSub.json"); + PdpGroup group = loadPdpGroups("createGroups.json").getGroups().get(0); + when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); + + prov.createOrUpdateGroups(groups); + + PdpGroup newgrp = groups.getGroups().get(0); + + PdpSubGroup newsub = newgrp.getPdpSubgroups().get(1); + newsub.setCurrentInstanceCount(0); + newsub.setPdpInstances(new ArrayList<>(0)); + + assertEquals(newgrp.toString(), group.toString()); + assertGroupUpdateOnly(group); + } + + /** + * Tests addSubgroup() when the new subgroup has a wild-card policy type. + * + * @throws Exception if an error occurs + */ + @Test + public void testAddSubGroupWildCardPolicyType() throws Exception { + when(dao.getFilteredPolicyList(any())).thenReturn(loadPolicies("daoPolicyListWildCard.json")); + when(dao.getPolicyTypeList("some.*", "2.3.4")).thenReturn(Collections.emptyList()); + + PdpGroups groups = loadPdpGroups("createGroupsWildCard.json"); + PdpGroup group = loadPdpGroups("createGroups.json").getGroups().get(0); + when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); + + prov.createOrUpdateGroups(groups); + + PdpGroup newgrp = groups.getGroups().get(0); + + PdpSubGroup newsub = newgrp.getPdpSubgroups().get(1); + newsub.setCurrentInstanceCount(0); + newsub.setPdpInstances(new ArrayList<>(0)); + + assertEquals(newgrp.toString(), group.toString()); + } + + /** + * Tests addSubgroup() when the new subgroup has a wild-card policy type, but the + * policy doesn't have a matching type. + * + * @throws PfModelException if an error occurs + */ + @Test + public void testAddSubGroupWildCardPolicyTypeUnmatched() throws PfModelException { + when(dao.getFilteredPolicyList(any())).thenReturn(loadPolicies("daoPolicyListWildCardUnmatched.json")); + when(dao.getPolicyTypeList("some.*", "2.3.4")).thenReturn(Collections.emptyList()); + + PdpGroups groups = loadPdpGroups("createGroupsWildCard.json"); + PdpGroup group = loadPdpGroups("createGroups.json").getGroups().get(0); + when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); + + assertThatThrownBy(() -> prov.createOrUpdateGroups(groups)).isInstanceOf(PfModelException.class); + } + + @Test + public void testAddSubGroup_ValidationPolicyTypeNotFound() throws Exception { + PdpGroups groups = loadPdpGroups("createGroupsNewSub.json"); + PdpGroup group = loadPdpGroups("createGroups.json").getGroups().get(0); + when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); + + when(dao.getPolicyTypeList(any(), any())).thenReturn(Collections.emptyList()); + + assertThatThrownBy(() -> prov.createOrUpdateGroups(groups)).hasMessageContaining("unknown policy type"); + } + + @Test + public void testAddSubGroup_ValidationPolicyTypeDaoEx() throws Exception { + PdpGroups groups = loadPdpGroups("createGroupsNewSub.json"); + PdpGroup group = loadPdpGroups("createGroups.json").getGroups().get(0); + when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); + + PfModelException exc = new PfModelException(Status.CONFLICT, EXPECTED_EXCEPTION); + when(dao.getPolicyTypeList(any(), any())).thenThrow(exc); + + assertThatThrownBy(() -> prov.createOrUpdateGroups(groups)).isSameAs(exc); + } + + @Test + public void testAddSubGroup_ValidationPolicyNotFound() throws Exception { + PdpGroups groups = loadPdpGroups("createGroupsNewSubNotFound.json"); + PdpGroup group = loadPdpGroups("createGroups.json").getGroups().get(0); + when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); + + when(dao.getFilteredPolicyList(any())).thenReturn(Collections.emptyList()); + + assertThatThrownBy(() -> prov.createOrUpdateGroups(groups)).hasMessageContaining("unknown policy"); + } + + @Test + public void testAddSubGroup_ValidationPolicyDaoEx() throws Exception { + PdpGroups groups = loadPdpGroups("createGroupsNewSubNotFound.json"); + PdpGroup group = loadPdpGroups("createGroups.json").getGroups().get(0); + when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); + + PfModelException exc = new PfModelException(Status.CONFLICT, EXPECTED_EXCEPTION); + when(dao.getFilteredPolicyList(any())).thenThrow(exc); + + assertThatThrownBy(() -> prov.createOrUpdateGroups(groups)).isSameAs(exc); + } + + @Test + public void testAddSubGroup_ValidateVersionPrefixMatch() throws Exception { + PdpGroups groups = loadPdpGroups("createGroups.json"); + PdpGroup newgrp = groups.getGroups().get(0); + PdpGroup dbgroup = new PdpGroup(newgrp); + when(dao.getPdpGroups(dbgroup.getName())).thenReturn(Arrays.asList(dbgroup)); + + when(dao.getFilteredPolicyList(any())).thenReturn(loadPolicies("createGroupNewPolicy.json")) + .thenReturn(loadPolicies("daoPolicyList.json")) + .thenReturn(loadPolicies("createGroupNewPolicy.json")); + + PdpGroups reqgroups = loadPdpGroups("createGroupsVersPrefix.json"); + + prov.createOrUpdateGroups(reqgroups); + + Collections.sort(newgrp.getPdpSubgroups().get(0).getPolicies()); + Collections.sort(dbgroup.getPdpSubgroups().get(0).getPolicies()); + + assertEquals(newgrp.toString(), dbgroup.toString()); + } + + @Test + public void testAddSubGroup_ValidateVersionPrefixMismatch() throws Exception { + PdpGroups groups = loadPdpGroups("createGroups.json"); + PdpGroup newgrp = groups.getGroups().get(0); + PdpGroup dbgroup = new PdpGroup(newgrp); + when(dao.getPdpGroups(dbgroup.getName())).thenReturn(Arrays.asList(dbgroup)); + + when(dao.getFilteredPolicyList(any())).thenReturn(loadPolicies("daoPolicyList.json")); + + + PdpGroups reqgroups = loadPdpGroups("createGroupsVersPrefixMismatch.json"); + + assertThatThrownBy(() -> prov.createOrUpdateGroups(reqgroups)).isInstanceOf(PfModelException.class) + .hasMessageContaining("different version already deployed"); + + assertNoGroupAction(); + } + + @Test + public void testUpdateSubGroup_Invalid() throws Exception { + PdpGroups groups = loadPdpGroups("createGroups.json"); + PdpGroup newgrp = groups.getGroups().get(0); + PdpGroup group = new PdpGroup(newgrp); + when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); + + // change properties + newgrp.getPdpSubgroups().get(0).setProperties(new TreeMap<>()); + + assertThatThrownBy(() -> prov.createOrUpdateGroups(groups)).isInstanceOf(PfModelException.class) + .hasMessageContaining("properties"); + + assertNoGroupAction(); + } + + @Test + public void testUpdateSubGroup_SupportedPolicies() throws Exception { + PdpGroups groups = loadPdpGroups("createGroups.json"); + PdpGroup newgrp = groups.getGroups().get(0); + PdpGroup group = new PdpGroup(newgrp); + when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); + + newgrp.getPdpSubgroups().get(0).getSupportedPolicyTypes() + .add(new ToscaPolicyTypeIdentifier("typeX.*", "9.8.7")); + + prov.createOrUpdateGroups(groups); + + assertEquals(newgrp.toString(), group.toString()); + assertGroupUpdateOnly(group); + } + + @Test + public void testUpdateSubGroup_DesiredCount() throws Exception { + PdpGroups groups = loadPdpGroups("createGroups.json"); + PdpGroup newgrp = groups.getGroups().get(0); + PdpGroup group = new PdpGroup(newgrp); + when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); + + newgrp.getPdpSubgroups().get(0).setDesiredInstanceCount(20); + + prov.createOrUpdateGroups(groups); + + assertEquals(newgrp.toString(), group.toString()); + assertGroupUpdateOnly(group); + } + + @Test + public void testUpdateSubGroup_Policies() throws Exception { + PdpGroups groups = loadPdpGroups("createGroupsDelPolicy.json"); + PdpGroup newgrp = groups.getGroups().get(0); + PdpGroup group = new PdpGroup(newgrp); + when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); + + PdpSubGroup subgrp = newgrp.getPdpSubgroups().get(0); + + // delete second policy + subgrp.setPolicies(subgrp.getPolicies().subList(0, 1)); + + // add new policy + ToscaPolicyIdentifier policyId2 = new ToscaPolicyIdentifier(POLICY2_NAME, POLICY1_VERSION); + subgrp.getPolicies().add(policyId2); + + when(dao.getFilteredPolicyList(any())).thenReturn(loadPolicies("createGroupNewPolicy.json")) + .thenReturn(loadPolicies("daoPolicyList.json")) + .thenReturn(loadPolicies("daoPolicyListDelPolicy.json")) + .thenReturn(loadPolicies("createGroupNewPolicy.json")); + + prov.createOrUpdateGroups(groups); + + Collections.sort(newgrp.getPdpSubgroups().get(0).getPolicies()); + Collections.sort(group.getPdpSubgroups().get(0).getPolicies()); + + assertEquals(newgrp.toString(), group.toString()); + + // should have notified of added policy/PDPs + ArgumentCaptor captor = ArgumentCaptor.forClass(PolicyPdpNotificationData.class); + verify(notifier).addDeploymentData(captor.capture()); + assertDeploymentData(captor, policyId2, "[pdpA]"); + + // should have notified of deleted policy/PDPs + captor = ArgumentCaptor.forClass(PolicyPdpNotificationData.class); + verify(notifier).addUndeploymentData(captor.capture()); + assertDeploymentData(captor, new ToscaPolicyIdentifier("ToBeDeleted", POLICY1_VERSION), "[pdpA]"); + + // this requires a PDP UPDATE message + assertGroupUpdate(group, subgrp); + } + + @Test + public void testUpdateSubGroup_Unchanged() throws Exception { + PdpGroups groups = loadPdpGroups("createGroups.json"); + PdpGroup newgrp = groups.getGroups().get(0); + PdpGroup group = new PdpGroup(newgrp); + when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); + + prov.createOrUpdateGroups(groups); + + Collections.sort(newgrp.getPdpSubgroups().get(0).getPolicies()); + Collections.sort(group.getPdpSubgroups().get(0).getPolicies()); + + assertEquals(newgrp.toString(), group.toString()); + + // no notifications + verify(notifier, never()).addDeploymentData(any()); + verify(notifier, never()).addUndeploymentData(any()); + + // no group updates + assertNoGroupAction(); + } + + @Test + public void testUpdateSubGroup_PolicyVersionMismatch() throws Exception { + PdpGroups groups = loadPdpGroups("createGroups.json"); + PdpGroup newgrp = groups.getGroups().get(0); + PdpGroup dbgroup = new PdpGroup(newgrp); + when(dao.getPdpGroups(dbgroup.getName())).thenReturn(Arrays.asList(dbgroup)); + + // arrange for DB policy version to be different + PdpSubGroup dbsubgrp = dbgroup.getPdpSubgroups().get(0); + dbsubgrp.getPolicies().get(0).setVersion("9.9.9"); + + when(dao.getFilteredPolicyList(any())).thenReturn(loadPolicies("daoPolicyList.json")); + + assertThatThrownBy(() -> prov.createOrUpdateGroups(groups)).isInstanceOf(PfModelException.class) + .hasMessageContaining("different version already deployed"); + + assertNoGroupAction(); + } + + @Test + public void testValidateSubGroup_PropertiesMismatch() throws Exception { + PdpGroups groups = loadPdpGroups("createGroups.json"); + PdpGroup newgrp = groups.getGroups().get(0); + PdpGroup group = new PdpGroup(newgrp); + when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); + + newgrp.setProperties(new TreeMap<>()); + + assertThatThrownBy(() -> prov.createOrUpdateGroups(groups)).isInstanceOf(PfModelException.class) + .hasMessageContaining("properties"); + + assertNoGroupAction(); + } + + @Test + public void testDeployPolicies() throws PfModelException { + prov.deployPolicies(loadEmptyRequest()); + } + + /** + * Tests deployPolicies() when the supported policy type uses a wild-card. + * + * @throws Exception if an error occurs + */ + @Test + public void testDeployPoliciesWildCard() throws Exception { + when(dao.getFilteredPdpGroups(any())).thenReturn(loadGroups("deployPoliciesWildCard.json")); + when(dao.getFilteredPolicyList(any())).thenReturn(loadPolicies("daoPolicyListWildCard.json")); + when(dao.getPolicyTypeList(any(), any())).thenReturn(Collections.emptyList()); + + policy1.setName("policy.some"); + policy1.setVersion(POLICY1_VERSION); + policy1.setType("some.type"); + policy1.setTypeVersion("100.2.3"); + + PdpDeployPolicies depreq = loadRequest(); + depreq.getPolicies().get(0).setName("policy.some"); + + prov.deployPolicies(depreq); + + assertGroup(getGroupUpdates(), GROUP1_NAME); + + List requests = getUpdateRequests(1); + assertUpdate(requests, GROUP1_NAME, PDP2_TYPE, PDP2); + + // should have notified of added policy/PDPs + ArgumentCaptor captor = ArgumentCaptor.forClass(PolicyPdpNotificationData.class); + verify(notifier).addDeploymentData(captor.capture()); + assertDeploymentData(captor, policy1.getIdentifier(), "[pdpB]"); + + // no undeployment notifications + verify(notifier, never()).addUndeploymentData(any()); + } + + @Test + public void testDeploySimplePolicies() throws Exception { + prov.deployPolicies(loadEmptyRequest()); + } + + @Test + public void testDeploySimplePolicies_DaoEx() throws Exception { + PfModelException exc = new PfModelException(Status.BAD_REQUEST, EXPECTED_EXCEPTION); + when(dao.getFilteredPdpGroups(any())).thenThrow(exc); + + assertThatThrownBy(() -> prov.deployPolicies(loadRequest())).isSameAs(exc); + } + + @Test + public void testDeploySimplePolicies_DaoPfRtEx() throws Exception { + PfModelRuntimeException exc = new PfModelRuntimeException(Status.BAD_REQUEST, EXPECTED_EXCEPTION); + when(dao.getFilteredPdpGroups(any())).thenThrow(exc); + + assertThatThrownBy(() -> prov.deployPolicies(loadRequest())).isSameAs(exc); + } + + @Test + public void testDeploySimplePolicies_RuntimeEx() throws Exception { + RuntimeException exc = new RuntimeException(EXPECTED_EXCEPTION); + when(dao.getFilteredPolicyList(any())).thenThrow(exc); + + assertThatThrownBy(() -> prov.deployPolicies(loadRequest())).isInstanceOf(PfModelException.class).hasCause(exc); + } + + @Test + public void testDeploySimplePolicies_NoGroups() throws Exception { + when(dao.getFilteredPdpGroups(any())).thenReturn(loadGroups("emptyGroups.json")); + + assertThatThrownBy(() -> prov.deployPolicies(loadRequest())).isInstanceOf(PfModelException.class) + .hasMessage("policy not supported by any PDP group: policyA 1.2.3"); + } + + @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")); + + prov.deployPolicies(loadRequest()); + + assertGroup(getGroupUpdates(), GROUP1_NAME); + + List requests = getUpdateRequests(2); + assertUpdate(requests, GROUP1_NAME, PDP2_TYPE, PDP2); + assertUpdate(requests, GROUP1_NAME, PDP4_TYPE, PDP4); + + // should have notified of added policy/PDPs + ArgumentCaptor captor = ArgumentCaptor.forClass(PolicyPdpNotificationData.class); + verify(notifier).addDeploymentData(captor.capture()); + assertDeploymentData(captor, policy1.getIdentifier(), "[pdpB, pdpD]"); + + // no undeployment notifications + verify(notifier, never()).addUndeploymentData(any()); + } + + @Test + public void testMakeUpdater_PolicyVersionMismatch() throws Exception { + + // subgroup has a different version of the Policy + when(dao.getFilteredPdpGroups(any())).thenReturn(loadGroups("upgradeGroupDao_DiffVers.json")); + + assertThatThrownBy(() -> prov.deployPolicies(loadRequest())).isInstanceOf(PfModelRuntimeException.class) + .hasMessageContaining("pdpTypeC").hasMessageContaining("different version already deployed"); + + verify(dao, never()).createPdpGroups(any()); + verify(dao, never()).updatePdpGroups(any()); + verify(reqmap, never()).addRequest(any(PdpUpdate.class)); + } + + @Test + public void testMakeUpdater_NoPdps() throws Exception { + + // subgroup has no PDPs + when(dao.getFilteredPdpGroups(any())).thenReturn(loadGroups("upgradeGroup_NoPdpsDao.json")); + + assertThatThrownBy(() -> prov.deployPolicies(loadRequest())).isInstanceOf(PfModelRuntimeException.class) + .hasMessage("group " + GROUP1_NAME + " subgroup " + PDP1_TYPE + " has no active PDPs"); + + verify(dao, never()).createPdpGroups(any()); + verify(dao, never()).updatePdpGroups(any()); + verify(reqmap, never()).addRequest(any(PdpUpdate.class)); + } + + + protected void assertUpdate(List 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)); + } + + private void assertNoGroupAction() throws Exception { + verify(dao, never()).createPdpGroups(any()); + verify(dao, never()).updatePdpGroups(any()); + verify(reqmap, never()).addRequest(any(), any()); + } + + private void assertGroupUpdate(PdpGroup group, PdpSubGroup subgrp) throws Exception { + verify(dao, never()).createPdpGroups(any()); + + assertEquals(0, getStateChangeRequests(1).size()); + + List pdpUpdates = getUpdateRequests(1); + assertEquals(1, pdpUpdates.size()); + + PdpUpdate pdpUpdate = pdpUpdates.get(0); + assertEquals("pdpA", pdpUpdate.getName()); + assertEquals(group.getName(), pdpUpdate.getPdpGroup()); + + assertEquals(subgrp.getPdpType(), pdpUpdate.getPdpSubgroup()); + + List pdpPolicies = + pdpUpdate.getPolicies().stream().map(ToscaPolicy::getIdentifier).collect(Collectors.toList()); + Collections.sort(pdpPolicies); + + assertEquals(subgrp.getPolicies().toString(), pdpPolicies.toString()); + + List updates = getGroupUpdates(); + assertEquals(Arrays.asList(group), updates); + } + + private void assertGroupUpdateOnly(PdpGroup group) throws Exception { + verify(dao, never()).createPdpGroups(any()); + verify(reqmap, never()).addRequest(any(), any()); + + List updates = getGroupUpdates(); + assertEquals(Arrays.asList(group), updates); + } + + private void assertDeploymentData(ArgumentCaptor captor, ToscaPolicyIdentifier policyId, + String expectedPdps) { + PolicyPdpNotificationData data = captor.getValue(); + assertEquals(policyId, data.getPolicyId()); + assertEquals(policy1.getTypeIdentifier(), data.getPolicyType()); + assertEquals(expectedPdps, new TreeSet<>(data.getPdps()).toString()); + } + + /** + * 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/TestPolicyUndeployerImpl.java b/main/src/test/java/org/onap/policy/pap/main/rest/TestPolicyUndeployerImpl.java new file mode 100644 index 00000000..1a54fe5f --- /dev/null +++ b/main/src/test/java/org/onap/policy/pap/main/rest/TestPolicyUndeployerImpl.java @@ -0,0 +1,200 @@ +/*- + * ============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 static org.junit.Assert.assertEquals; +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 java.util.Arrays; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.onap.policy.common.utils.services.Registry; +import org.onap.policy.models.base.PfModelException; +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.tosca.authorative.concepts.ToscaPolicyIdentifier; + +public class TestPolicyUndeployerImpl extends ProviderSuper { + private static final String MY_GROUP = "my-group"; + private static final String MY_SUBGROUP = "my-subgroup"; + private static final String MY_SUBGROUP0 = "my-subgroup-0"; + private static final String PDP1 = "my-pdp-a"; + + @Mock + private SessionData session; + + @Captor + private ArgumentCaptor> pdpCaptor; + + private ToscaPolicyIdentifier ident1; + private ToscaPolicyIdentifier ident2; + private ToscaPolicyIdentifier ident3; + private ToscaPolicyIdentifier ident4; + private PdpGroup group; + private PdpSubGroup subgroup; + 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(); + + ident1 = new ToscaPolicyIdentifier("ident-a", "2.3.1"); + ident2 = new ToscaPolicyIdentifier("ident-b", "2.3.2"); + ident3 = new ToscaPolicyIdentifier("ident-c", "2.3.3"); + ident4 = new ToscaPolicyIdentifier("ident-d", "2.3.4"); + + group = new PdpGroup(); + group.setName(MY_GROUP); + + subgroup = new PdpSubGroup(); + subgroup.setPdpType(MY_SUBGROUP); + + Pdp pdp1 = new Pdp(); + pdp1.setInstanceId(PDP1); + + subgroup.setPdpInstances(Arrays.asList(pdp1)); + + // this subgroup should never be touched + PdpSubGroup subgroup0 = new PdpSubGroup(); + subgroup0.setPdpType(MY_SUBGROUP0); + subgroup0.setPolicies(Collections.unmodifiableList(Arrays.asList(ident1, ident2, ident3, ident4))); + subgroup.setPdpInstances(Arrays.asList(pdp1)); + + group.setPdpSubgroups(Arrays.asList(subgroup0, subgroup)); + + when(session.getGroup(MY_GROUP)).thenReturn(group); + when(session.getPolicy(any())).thenReturn(policy1); + + prov = new MyProvider(); + } + + @Test + public void testUndeployPolicies() throws PfModelException { + subgroup.setPolicies(new LinkedList<>(Arrays.asList(ident1, ident2, ident3, ident4))); + + prov.undeploy(MY_GROUP, MY_SUBGROUP, Arrays.asList(ident1, ident2)); + + // group should have been updated + verify(session).update(group); + + // subgroup should only have remaining policies + assertEquals(Arrays.asList(ident3, ident4).toString(), subgroup.getPolicies().toString()); + + // should have generated PDP-UPDATE for the PDP + verify(session).addUpdate(any()); + } + + /** + * Tests undeployPolicies() when the policies do not exist in the subgroup. + */ + @Test + public void testUndeployPoliciesUnchanged() throws PfModelException { + List origlist = Arrays.asList(ident3, ident4); + subgroup.setPolicies(new LinkedList<>(origlist)); + + prov.undeploy(MY_GROUP, MY_SUBGROUP, Arrays.asList(ident1, ident2)); + + // group NOT should have been updated + verify(session, never()).update(group); + + // subgroup's policies should be unchanged + assertEquals(origlist.toString(), subgroup.getPolicies().toString()); + + // should NOT have generated PDP-UPDATE for the PDP + verify(session, never()).addUpdate(any()); + } + + /** + * Tests undeployPolicies() when the group is not found. + */ + @Test + public void testUndeployPoliciesGroupNotFound() throws PfModelException { + // force exception to be thrown if the list is changed + subgroup.setPolicies(Collections.unmodifiableList(Arrays.asList(ident1, ident2, ident3, ident4))); + + when(session.getGroup(any())).thenReturn(null); + + prov.undeploy(MY_GROUP, MY_SUBGROUP, Arrays.asList(ident1, ident2)); + + // group should have been updated + verify(session, never()).update(group); + + // should have generated PDP-UPDATE for the PDP + verify(session, never()).addUpdate(any()); + } + + /** + * Tests undeployPolicies() when the subgroup is not found. + */ + @Test + public void testUndeployPoliciesSubGroupNotFound() throws PfModelException { + // force exception to be thrown if the list is changed + subgroup.setPolicies(Collections.unmodifiableList(Arrays.asList(ident1, ident2, ident3, ident4))); + + subgroup.setPdpType(MY_SUBGROUP + "X"); + + prov.undeploy(MY_GROUP, MY_SUBGROUP, Arrays.asList(ident1, ident2)); + + // group should have been updated + verify(session, never()).update(group); + + // should have generated PDP-UPDATE for the PDP + verify(session, never()).addUpdate(any()); + } + + @Test(expected = UnsupportedOperationException.class) + public void testMakeUpdater() { + prov.makeUpdater(null, null, null); + } + + + private class MyProvider extends PolicyUndeployerImpl { + + @Override + protected void process(T request, BiConsumerWithEx processor) throws PfModelException { + processor.accept(session, request); + } + } +} diff --git a/main/src/test/java/org/onap/policy/pap/main/rest/TestProviderBase.java b/main/src/test/java/org/onap/policy/pap/main/rest/TestProviderBase.java new file mode 100644 index 00000000..b6f56ba0 --- /dev/null +++ b/main/src/test/java/org/onap/policy/pap/main/rest/TestProviderBase.java @@ -0,0 +1,392 @@ +/* + * ============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 static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; +import java.util.TreeSet; +import javax.ws.rs.core.Response.Status; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.onap.policy.common.utils.services.Registry; +import org.onap.policy.models.base.PfModelException; +import org.onap.policy.models.base.PfModelRuntimeException; +import org.onap.policy.models.pap.concepts.PdpDeployPolicies; +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.ToscaPolicyIdentifierOptVersion; +import org.onap.policy.pap.main.notification.PolicyPdpNotificationData; +import org.powermock.reflect.Whitebox; + +public class TestProviderBase extends ProviderSuper { + private static final String EXPECTED_EXCEPTION = "expected exception"; + + 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 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.getFilteredPolicyList(any())).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 { + prov.process(loadRequest(), this::handle); + + assertGroup(getGroupUpdates(), GROUP1_NAME); + + assertUpdate(getUpdateRequests(1), GROUP1_NAME, PDP1_TYPE, PDP1); + + ArgumentCaptor captor = ArgumentCaptor.forClass(PolicyPdpNotificationData.class); + verify(notifier, times(2)).addDeploymentData(captor.capture()); + assertNotifier(captor, PDP1, PDP3); + + captor = ArgumentCaptor.forClass(PolicyPdpNotificationData.class); + verify(notifier, times(2)).addUndeploymentData(captor.capture()); + assertNotifier(captor, PDP2, PDP4); + } + + private void assertNotifier(ArgumentCaptor captor, String firstPdp, String secondPdp) { + assertEquals(1, captor.getAllValues().get(0).getPdps().size()); + assertEquals(1, captor.getAllValues().get(1).getPdps().size()); + + // ensure the order by using a TreeSet + TreeSet pdps = new TreeSet<>(captor.getAllValues().get(0).getPdps()); + pdps.addAll(captor.getAllValues().get(1).getPdps()); + assertEquals("[" + firstPdp + ", " + secondPdp + "]", pdps.toString()); + } + + @Test + public void testProcess_CreateEx() throws Exception { + PfModelException ex = new PfModelException(Status.BAD_REQUEST, EXPECTED_EXCEPTION); + when(daofact.create()).thenThrow(ex); + + assertThatThrownBy(() -> prov.process(loadEmptyRequest(), this::handle)).isSameAs(ex); + } + + @Test + public void testProcess_PfRtEx() throws Exception { + PfModelRuntimeException ex = new PfModelRuntimeException(Status.BAD_REQUEST, EXPECTED_EXCEPTION); + when(daofact.create()).thenThrow(ex); + + assertThatThrownBy(() -> prov.process(loadEmptyRequest(), this::handle)).isSameAs(ex); + } + + @Test + public void testProcess_RuntimeEx() throws Exception { + RuntimeException ex = new RuntimeException(EXPECTED_EXCEPTION); + when(daofact.create()).thenThrow(ex); + + assertThatThrownBy(() -> prov.process(loadEmptyRequest(), this::handle)).isInstanceOf(PfModelException.class) + .hasMessage("request failed").hasCause(ex); + } + + @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(PfModelException.class) + .hasMessage("policy not supported by any PDP group: policyA 1.2.3"); + + } + + @Test + public void testGetPolicy() throws Exception { + PfModelException exc = new PfModelException(Status.CONFLICT, EXPECTED_EXCEPTION); + when(dao.getFilteredPolicyList(any())).thenThrow(exc); + + assertThatThrownBy(() -> prov.process(loadRequest(), this::handle)).isInstanceOf(PfModelRuntimeException.class) + .hasCause(exc); + } + + @Test + public void testGetPolicy_NotFound() throws Exception { + when(dao.getFilteredPolicyList(any())).thenReturn(Collections.emptyList()); + + assertThatThrownBy(() -> prov.process(loadRequest(), this::handle)).isInstanceOf(PfModelRuntimeException.class) + .hasMessage("cannot find policy: policyA 1.2.3") + .extracting(ex -> ((PfModelRuntimeException) ex).getErrorResponse().getResponseCode()) + .isEqualTo(Status.NOT_FOUND); + } + + @Test + public void testGetGroup() throws Exception { + when(dao.getFilteredPdpGroups(any())).thenReturn(loadGroups("getGroupDao.json")) + .thenReturn(loadGroups("groups.json")); + + prov.process(loadRequest(), this::handle); + + assertGroup(getGroupUpdates(), GROUP1_NAME); + } + + @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); + + prov.process(loadRequest(), this::handle); + + assertGroup(getGroupUpdates(), GROUP1_NAME); + + List 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.getFilteredPolicyList(any())).thenReturn(loadPolicies("daoPolicyList.json")) + .thenReturn(loadPolicies("upgradeGroupPolicy2.json")) + .thenReturn(loadPolicies("upgradeGroupPolicy3.json")) + .thenReturn(loadPolicies("upgradeGroupPolicy4.json")); + + List groups1 = loadGroups("upgradeGroupGroup1.json"); + List 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); + + prov.process(request, (data, deploy) -> { + for (ToscaPolicyIdentifierOptVersion policy : deploy.getPolicies()) { + handle(data, policy); + } + }); + + // verify updates + List changes = getGroupUpdates(); + assertGroup(changes, GROUP1_NAME); + assertGroup(changes, GROUP2_NAME); + + List 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); + + prov.process(loadRequest(), this::handle); + + verify(dao, never()).createPdpGroups(any()); + verify(dao, never()).updatePdpGroups(any()); + verify(reqmap, never()).addRequest(any(PdpUpdate.class)); + } + + + protected void assertUpdate(List 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 + * @throws PfModelException if an error occurred + */ + private void handle(SessionData data, ToscaPolicyIdentifierOptVersion request) throws PfModelException { + prov.processPolicy(data, request); + } + + + private static class MyProvider extends ProviderBase { + /** + * 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 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 + protected Updater makeUpdater(SessionData data, ToscaPolicy policy, + ToscaPolicyIdentifierOptVersion desiredPolicy) { + + return (group, subgroup) -> { + if (shouldUpdate.remove()) { + // queue indicated that the update should succeed + subgroup.getPolicies().add(policy.getIdentifier()); + + data.trackDeploy(policy.getIdentifier(), Collections.singleton(PDP1)); + data.trackUndeploy(policy.getIdentifier(), Collections.singleton(PDP2)); + + ToscaPolicyIdentifier ident2 = new ToscaPolicyIdentifier(POLICY1_NAME, "9.9.9"); + data.trackDeploy(ident2, Collections.singleton(PDP3)); + data.trackUndeploy(ident2, Collections.singleton(PDP4)); + return true; + + } else { + // queue indicated that no update should be made this time + return false; + } + }; + } + } +} diff --git a/main/src/test/java/org/onap/policy/pap/main/rest/TestSessionData.java b/main/src/test/java/org/onap/policy/pap/main/rest/TestSessionData.java new file mode 100644 index 00000000..34b7c61f --- /dev/null +++ b/main/src/test/java/org/onap/policy/pap/main/rest/TestSessionData.java @@ -0,0 +1,662 @@ +/* + * ============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 static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.Assertions.assertThatIllegalStateException; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.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.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.Iterator; +import java.util.List; +import java.util.TreeSet; +import java.util.function.Supplier; +import javax.ws.rs.core.Response.Status; +import org.apache.commons.lang3.tuple.Pair; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.onap.policy.models.base.PfModelException; +import org.onap.policy.models.pdp.concepts.PdpGroup; +import org.onap.policy.models.pdp.concepts.PdpStateChange; +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.ToscaPolicyFilter; +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.ToscaPolicyType; +import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyTypeIdentifier; +import org.onap.policy.pap.main.notification.PolicyPdpNotificationData; + +public class TestSessionData extends ProviderSuper { + private static final String GROUP_NAME = "groupA"; + 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_TYPE = "myType"; + private static final String POLICY_TYPE_VERSION = "10.20.30"; + private static final String EXPECTED_EXCEPTION = "expected exception"; + + private SessionData session; + private ToscaPolicyIdentifierOptVersion ident; + private ToscaPolicyTypeIdentifier type; + private ToscaPolicyTypeIdentifier type2; + private PdpGroup group1; + private PdpGroup group2; + + /** + * Initializes mocks and a session. + * + * @throws Exception if an error occurs + */ + @Before + public void setUp() throws Exception { + super.setUp(); + + ident = new ToscaPolicyIdentifierOptVersion(POLICY_NAME, POLICY_VERSION); + type = new ToscaPolicyTypeIdentifier(POLICY_TYPE, POLICY_TYPE_VERSION); + type2 = new ToscaPolicyTypeIdentifier(POLICY_TYPE, POLICY_TYPE_VERSION + "0"); + group1 = loadGroup("group1.json"); + group2 = loadGroup("group2.json"); + + session = new SessionData(dao); + } + + @Test + public void testGetPolicyType() throws Exception { + ToscaPolicyType policy1 = makePolicyType(POLICY_TYPE, POLICY_TYPE_VERSION); + when(dao.getPolicyTypeList(POLICY_TYPE, POLICY_TYPE_VERSION)).thenReturn(Arrays.asList(policy1)); + + assertSame(policy1, session.getPolicyType(type)); + + // retrieve a second time - should use cache + assertSame(policy1, session.getPolicyType(type)); + } + + @Test + public void testGetPolicyType_NotFound() throws Exception { + when(dao.getPolicyTypeList(any(), any())).thenReturn(Collections.emptyList()); + + assertNull(session.getPolicyType(type)); + } + + @Test + public void testGetPolicyType_DaoEx() throws Exception { + PfModelException ex = new PfModelException(Status.INTERNAL_SERVER_ERROR, EXPECTED_EXCEPTION); + when(dao.getPolicyTypeList(POLICY_TYPE, POLICY_TYPE_VERSION)).thenThrow(ex); + + assertThatThrownBy(() -> session.getPolicyType(type)).isSameAs(ex); + } + + @Test + public void testGetPolicy_NullVersion() throws Exception { + ToscaPolicy policy1 = makePolicy(POLICY_NAME, POLICY_VERSION); + when(dao.getFilteredPolicyList(any())).thenReturn(Arrays.asList(policy1)); + + ident.setVersion(null); + assertSame(policy1, session.getPolicy(ident)); + + ToscaPolicyFilter filter = getPolicyFilter(); + assertEquals(POLICY_NAME, filter.getName()); + assertEquals(ToscaPolicyFilter.LATEST_VERSION, filter.getVersion()); + assertEquals(null, filter.getVersionPrefix()); + + // retrieve a second time using full version - should use cache + assertSame(policy1, session.getPolicy(new ToscaPolicyIdentifierOptVersion(policy1.getIdentifier()))); + verify(dao).getFilteredPolicyList(any()); + } + + @Test + public void testGetPolicy_MajorVersion() throws Exception { + ToscaPolicy policy1 = makePolicy(POLICY_NAME, POLICY_VERSION); + when(dao.getFilteredPolicyList(any())).thenReturn(Arrays.asList(policy1)); + + ident.setVersion("1"); + assertSame(policy1, session.getPolicy(ident)); + + ToscaPolicyFilter filter = getPolicyFilter(); + assertEquals(POLICY_NAME, filter.getName()); + assertEquals(ToscaPolicyFilter.LATEST_VERSION, filter.getVersion()); + assertEquals("1.", filter.getVersionPrefix()); + + // retrieve a second time using full version - should use cache + assertSame(policy1, session.getPolicy(new ToscaPolicyIdentifierOptVersion(policy1.getIdentifier()))); + verify(dao).getFilteredPolicyList(any()); + } + + @Test + public void testGetPolicy_MajorMinorVersion() throws Exception { + ToscaPolicy policy1 = makePolicy(POLICY_NAME, POLICY_VERSION); + when(dao.getFilteredPolicyList(any())).thenReturn(Arrays.asList(policy1)); + + ident.setVersion(POLICY_VERSION); + assertSame(policy1, session.getPolicy(ident)); + + ToscaPolicyFilter filter = getPolicyFilter(); + assertEquals(POLICY_NAME, filter.getName()); + assertEquals(POLICY_VERSION, filter.getVersion()); + assertEquals(null, filter.getVersionPrefix()); + + // retrieve a second time using full version - should use cache + assertSame(policy1, session.getPolicy(new ToscaPolicyIdentifierOptVersion(policy1.getIdentifier()))); + verify(dao).getFilteredPolicyList(any()); + } + + @Test + public void testGetPolicy_NotFound() throws Exception { + when(dao.getFilteredPolicyList(any())).thenReturn(Collections.emptyList()); + + assertNull(session.getPolicy(ident)); + } + + @Test + public void testGetPolicy_DaoEx() throws Exception { + PfModelException ex = new PfModelException(Status.INTERNAL_SERVER_ERROR, EXPECTED_EXCEPTION); + when(dao.getFilteredPolicyList(any())).thenThrow(ex); + + assertThatThrownBy(() -> session.getPolicy(ident)).isSameAs(ex); + } + + @Test + public void testIsVersionPrefix() { + assertTrue(SessionData.isVersionPrefix("1")); + assertTrue(SessionData.isVersionPrefix("12")); + assertTrue(SessionData.isVersionPrefix("1.2")); + assertTrue(SessionData.isVersionPrefix("1.23")); + + assertFalse(SessionData.isVersionPrefix("1.")); + assertFalse(SessionData.isVersionPrefix("1.2.")); + assertFalse(SessionData.isVersionPrefix("1.2.3")); + assertFalse(SessionData.isVersionPrefix("1.2.3.")); + assertFalse(SessionData.isVersionPrefix("1.2.3.4")); + } + + @Test + public void testAddRequests_testGetPdpStateChanges_testGetPdpUpdates() { + // pre-load with a update and state-change for other PDPs + PdpUpdate update2 = makeUpdate(PDP2); + session.addUpdate(update2); + + PdpStateChange change3 = makeStateChange(PDP3); + session.addStateChange(change3); + + // add requests + PdpUpdate update = makeUpdate(PDP1); + PdpStateChange change = makeStateChange(PDP1); + session.addRequests(update, change); + verifyRequests(update, update2, change, change3); + + /* + * repeat with a new pair + */ + update = makeUpdate(PDP1); + change = makeStateChange(PDP1); + session.addRequests(update, change); + verifyRequests(update, update2, change, change3); + + // just make an update this time + update = makeUpdate(PDP1); + session.addUpdate(update); + verifyRequests(update, update2, change, change3); + } + + private void verifyRequests(PdpUpdate update, PdpUpdate update2, PdpStateChange change, PdpStateChange change3) { + List> requests = sort(session.getPdpRequests(), this::compare); + assertEquals(3, requests.size()); + + System.out.println(requests); + System.out.println(update); + + Iterator> reqiter = requests.iterator(); + Pair pair = reqiter.next(); + assertSame(update, pair.getLeft()); + assertSame(change, pair.getRight()); + + pair = reqiter.next(); + assertSame(update2, pair.getLeft()); + assertSame(null, pair.getRight()); + + pair = reqiter.next(); + assertSame(null, pair.getLeft()); + assertSame(change3, pair.getRight()); + + // verify individual lists + List updates = Arrays.asList(update, update2); + assertEquals(sort(updates, this::compare), sort(session.getPdpUpdates(), this::compare)); + + List changes = Arrays.asList(change, change3); + assertEquals(sort(changes, this::compare), sort(session.getPdpStateChanges(), this::compare)); + } + + @Test + public void testAddRequests_MismatchedNames() { + PdpUpdate update = makeUpdate(PDP1); + PdpStateChange change = makeStateChange(PDP2); + assertThatIllegalArgumentException().isThrownBy(() -> session.addRequests(update, change)) + .withMessage("PDP name mismatch pdp_1, pdp_2"); + } + + @Test + public void testAddUpdate_testGetPdpUpdates() { + // 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 lst = sort(getUpdateRequests(), this::compare); + assertEquals(Arrays.asList(update1, update2, update3).toString(), lst.toString()); + + // overwrite one + update2 = makeUpdate(PDP2); + session.addUpdate(update2); + + lst = sort(getUpdateRequests(), this::compare); + assertEquals(Arrays.asList(update1, update2, update3).toString(), lst.toString()); + } + + @Test + public void testAddStateChange_testGetPdpStateChanges() { + // several different changes, but one duplicate + PdpStateChange change1 = makeStateChange(PDP1); + session.addStateChange(change1); + + PdpStateChange change2 = makeStateChange(PDP2); + session.addStateChange(change2); + + PdpStateChange change3 = makeStateChange(PDP3); + session.addStateChange(change3); + + List lst = sort(getStateChangeRequests(), this::compare); + assertEquals(Arrays.asList(change1, change2, change3).toString(), lst.toString()); + + // overwrite one + change2 = makeStateChange(PDP2); + session.addStateChange(change2); + + lst = sort(getStateChangeRequests(), this::compare); + assertEquals(Arrays.asList(change1, change2, change3).toString(), lst.toString()); + } + + private ToscaPolicyType makePolicyType(String name, String version) { + ToscaPolicyType type = new ToscaPolicyType(); + + type.setName(name); + type.setVersion(version); + + return type; + } + + private ToscaPolicy makePolicy(String name, String version) { + ToscaPolicy policy = new ToscaPolicy(); + + policy.setName(name); + policy.setVersion(version); + + return policy; + } + + @Test + public void testCreate() throws Exception { + assertTrue(session.isUnchanged()); + + session.create(group1); + assertSame(group1, session.getGroup(group1.getName())); + assertFalse(session.isUnchanged()); + + // can add another + session.create(group2); + assertSame(group1, session.getGroup(group1.getName())); + assertSame(group2, session.getGroup(group2.getName())); + assertFalse(session.isUnchanged()); + + // cannot overwrite + assertThatIllegalStateException().isThrownBy(() -> session.create(group1)) + .withMessage("group already cached: groupA"); + } + + @Test + public void testUpdate() throws Exception { + assertTrue(session.isUnchanged()); + + // force the groups into the cache + when(dao.getFilteredPdpGroups(any())).thenReturn(Arrays.asList(group1, group2)); + session.getActivePdpGroupsByPolicyType(type); + + /* + * try group 1 + */ + when(dao.getFilteredPdpGroups(any())).thenReturn(Arrays.asList(group1)); + PdpGroup newgrp = new PdpGroup(group1); + session.update(newgrp); + assertFalse(session.isUnchanged()); + + // repeat + newgrp = new PdpGroup(group1); + session.update(newgrp); + assertFalse(session.isUnchanged()); + + /* + * try group 2 + */ + when(dao.getFilteredPdpGroups(any())).thenReturn(Arrays.asList(group2)); + newgrp = new PdpGroup(group2); + session.update(newgrp); + assertFalse(session.isUnchanged()); + + // repeat + newgrp = new PdpGroup(group2); + session.update(newgrp); + assertFalse(session.isUnchanged()); + } + + @Test + public void testUpdate_NotInCache() throws Exception { + when(dao.getFilteredPdpGroups(any())).thenReturn(Arrays.asList(group1)); + + assertThatIllegalStateException().isThrownBy(() -> session.update(new PdpGroup(group1))) + .withMessage("group not cached: groupA"); + } + + @Test + public void testGetGroup() throws Exception { + when(dao.getPdpGroups(GROUP_NAME)).thenReturn(Arrays.asList(group1)); + + assertSame(group1, session.getGroup(GROUP_NAME)); + verify(dao).getPdpGroups(any()); + + // repeat + assertSame(group1, session.getGroup(GROUP_NAME)); + + // should not access dao again + verify(dao, times(1)).getPdpGroups(any()); + } + + @Test + public void testGetGroup_NotFound() throws Exception { + when(dao.getPdpGroups(GROUP_NAME)).thenReturn(Collections.emptyList()); + + assertNull(session.getGroup(GROUP_NAME)); + verify(dao).getPdpGroups(any()); + + // repeat + assertNull(session.getGroup(GROUP_NAME)); + + // SHOULD access dao again + verify(dao, times(2)).getPdpGroups(GROUP_NAME); + + // find it this time + when(dao.getPdpGroups(GROUP_NAME)).thenReturn(Arrays.asList(group1)); + assertSame(group1, session.getGroup(GROUP_NAME)); + verify(dao, times(3)).getPdpGroups(GROUP_NAME); + } + + @Test + public void testGetGroup_DaoEx() throws Exception { + PfModelException ex = new PfModelException(Status.BAD_REQUEST, EXPECTED_EXCEPTION); + when(dao.getPdpGroups(GROUP_NAME)).thenThrow(ex); + + assertThatThrownBy(() -> session.getGroup(GROUP_NAME)).isSameAs(ex); + } + + @Test + public void testGetActivePdpGroupsByPolicyType() throws Exception { + List groups = Arrays.asList(group1, group2); + when(dao.getFilteredPdpGroups(any())).thenReturn(groups); + + // repeat + assertEquals(groups, session.getActivePdpGroupsByPolicyType(type)); + assertEquals(groups, session.getActivePdpGroupsByPolicyType(type)); + assertEquals(groups, session.getActivePdpGroupsByPolicyType(type)); + + // only invoked once - should have used the cache for the rest + verify(dao, times(1)).getFilteredPdpGroups(any()); + } + + @Test + public void testAddGroup() throws Exception { + List groups = Arrays.asList(group1, group2); + when(dao.getFilteredPdpGroups(any())).thenReturn(groups); + + // query by each type + assertEquals(groups, session.getActivePdpGroupsByPolicyType(type)); + assertEquals(groups, session.getActivePdpGroupsByPolicyType(type2)); + + // invoked once for each type + verify(dao, times(2)).getFilteredPdpGroups(any()); + + // repeat - should be no more invocations + assertEquals(groups, session.getActivePdpGroupsByPolicyType(type)); + assertEquals(groups, session.getActivePdpGroupsByPolicyType(type2)); + verify(dao, times(2)).getFilteredPdpGroups(any()); + } + + @Test + public void testUpdateDb() throws Exception { + // force the groups into the cache + PdpGroup group3 = loadGroup("group3.json"); + when(dao.getFilteredPdpGroups(any())).thenReturn(Arrays.asList(group1, group2, group3)); + session.getActivePdpGroupsByPolicyType(type); + + // create groups 4 & 5 + PdpGroup group4 = loadGroup("group4.json"); + session.create(group4); + + PdpGroup group5 = loadGroup("group5.json"); + session.create(group5); + + // update group 1 + when(dao.getFilteredPdpGroups(any())).thenReturn(Arrays.asList(group1)); + PdpGroup newgrp1 = new PdpGroup(group1); + session.update(newgrp1); + + // another update + newgrp1 = new PdpGroup(newgrp1); + session.update(newgrp1); + + // update group 3 + when(dao.getFilteredPdpGroups(any())).thenReturn(Arrays.asList(group3)); + PdpGroup newgrp3 = new PdpGroup(group3); + session.update(newgrp3); + + // update group 5 + when(dao.getFilteredPdpGroups(any())).thenReturn(Arrays.asList(group5)); + PdpGroup newgrp5 = new PdpGroup(group5); + session.update(newgrp5); + + // push the changes to the DB + session.updateDb(); + + // expect one create for groups 4 & 5 (group5 replaced by newgrp5) + List creates = getGroupCreates(); + assertEquals(2, creates.size()); + assertSame(group4, creates.get(0)); + assertSame(newgrp5, creates.get(1)); + + // expect one update for groups 1 & 3 + List updates = getGroupUpdates(); + assertEquals(2, updates.size()); + assertSame(newgrp1, updates.get(0)); + assertSame(newgrp3, updates.get(1)); + } + + @Test + public void testUpdateDb_Empty() throws Exception { + // force data into the cache + when(dao.getFilteredPdpGroups(any())).thenReturn(Arrays.asList(group1, group2)); + session.getActivePdpGroupsByPolicyType(type); + + session.updateDb(); + verify(dao, never()).createPdpGroups(any()); + verify(dao, never()).updatePdpGroups(any()); + } + + @Test + public void testDeleteGroupFromDb() throws Exception { + session.deleteGroupFromDb(group1); + + verify(dao).deletePdpGroup(group1.getName()); + } + + @Test + public void testTrackDeploy() throws PfModelException { + testTrack(session::getDeployData, session::getUndeployData, session::trackDeploy); + } + + /** + * Tests trackDeploy() when there is something in the undeployed list. + * + * @throws PfModelException if an error occurs + */ + @Test + public void testTrackDeployRemoveUndeploy() throws PfModelException { + testTrack(session::getDeployData, session::getUndeployData, session::trackUndeploy, session::trackDeploy); + } + + @Test + public void testTrackUndeploy() throws PfModelException { + testTrack(session::getUndeployData, session::getDeployData, session::trackUndeploy); + } + + /** + * Tests trackUndeploy() when there is something in the deployed list. + * + * @throws PfModelException if an error occurs + */ + @Test + public void testTrackUndeployRemoveUndeploy() throws PfModelException { + testTrack(session::getUndeployData, session::getDeployData, session::trackDeploy, session::trackUndeploy); + } + + protected void testTrack(Supplier> expected, + Supplier> unexpected, TrackEx... trackFuncs) + throws PfModelException { + + ToscaPolicy policy = makePolicy(POLICY_NAME, POLICY_VERSION); + policy.setType(POLICY_TYPE); + policy.setTypeVersion(POLICY_TYPE_VERSION); + + when(dao.getFilteredPolicyList(any())).thenReturn(Arrays.asList(policy)); + + ToscaPolicyIdentifier policyId = new ToscaPolicyIdentifier(POLICY_NAME, POLICY_VERSION); + List pdps = Arrays.asList(PDP1, PDP2); + + for (TrackEx trackFunc : trackFuncs) { + trackFunc.accept(policyId, pdps); + } + + // "unexpected" list should be empty of any PDPs + Collection dataList = unexpected.get(); + assertTrue(dataList.size() <= 1); + if (!dataList.isEmpty()) { + PolicyPdpNotificationData data = dataList.iterator().next(); + assertTrue(data.getPdps().isEmpty()); + } + + dataList = expected.get(); + assertEquals(1, dataList.size()); + + PolicyPdpNotificationData data = dataList.iterator().next(); + assertEquals(policyId, data.getPolicyId()); + assertEquals(type, data.getPolicyType()); + assertEquals("[pdp_1, pdp_2]", new TreeSet<>(data.getPdps()).toString()); + } + + private PdpUpdate makeUpdate(String pdpName) { + PdpUpdate update = new PdpUpdate(); + + update.setName(pdpName); + + return update; + } + + private PdpStateChange makeStateChange(String pdpName) { + PdpStateChange change = new PdpStateChange(); + + change.setName(pdpName); + + return change; + } + + private ToscaPolicyFilter getPolicyFilter() throws Exception { + ArgumentCaptor captor = ArgumentCaptor.forClass(ToscaPolicyFilter.class); + verify(dao).getFilteredPolicyList(captor.capture()); + + return captor.getValue(); + } + + private List getUpdateRequests() { + return session.getPdpUpdates(); + } + + private List getStateChangeRequests() { + return session.getPdpStateChanges(); + } + + private List sort(Collection collection, Comparator comparator) { + List lst = new ArrayList<>(collection); + Collections.sort(lst, comparator); + + return lst; + } + + private int compare(Pair left, Pair right) { + return getName(left).compareTo(getName(right)); + } + + private int compare(PdpUpdate left, PdpUpdate right) { + return left.getName().compareTo(right.getName()); + } + + private int compare(PdpStateChange left, PdpStateChange right) { + return left.getName().compareTo(right.getName()); + } + + private String getName(Pair pair) { + return (pair.getKey() != null ? pair.getKey().getName() : pair.getValue().getName()); + } + + @FunctionalInterface + private static interface TrackEx { + public void accept(ToscaPolicyIdentifier policyId, Collection pdps) throws PfModelException; + } +} 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 deleted file mode 100644 index 3f29fb56..00000000 --- a/main/src/test/java/org/onap/policy/pap/main/rest/depundep/ProviderSuper.java +++ /dev/null @@ -1,276 +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.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.Collections; -import java.util.List; -import java.util.stream.Collectors; -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.PdpGroups; -import org.onap.policy.models.pdp.concepts.PdpStateChange; -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.ToscaPolicyType; -import org.onap.policy.pap.main.PapConstants; -import org.onap.policy.pap.main.PolicyModelsProviderFactoryWrapper; -import org.onap.policy.pap.main.comm.PdpModifyRequestMap; -import org.onap.policy.pap.main.notification.PolicyNotifier; - -/** - * Super class for TestPdpGroupDeployProviderXxx classes. - */ -public class ProviderSuper { - private static final Coder coder = new StandardCoder(); - - @Mock - protected PolicyModelsProvider dao; - - @Mock - protected PolicyNotifier notifier; - - - /** - * Used to capture input to dao.updatePdpGroups() and dao.createPdpGroups(). - */ - @Captor - private ArgumentCaptor> 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 = loadPolicy("policy.json"); - - when(daofact.create()).thenReturn(dao); - - List 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); - Registry.register(PapConstants.REG_POLICY_NOTIFIER, notifier); - } - - protected void assertGroup(List groups, String name) { - PdpGroup group = groups.remove(0); - - assertEquals(name, group.getName()); - } - - protected void assertUpdateIgnorePolicy(List 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 create() method. - * - * @return the input that was passed to the dao.updatePdpGroups() method - * @throws Exception if an error occurred - */ - protected List getGroupCreates() throws Exception { - verify(dao).createPdpGroups(updateCaptor.capture()); - - return copyList(updateCaptor.getValue()); - } - - /** - * Gets the input to the update() method. - * - * @return the input that was passed to the dao.updatePdpGroups() method - * @throws Exception if an error occurred - */ - protected List getGroupUpdates() throws Exception { - verify(dao).updatePdpGroups(updateCaptor.capture()); - - return copyList(updateCaptor.getValue()); - } - - /** - * Gets the state-changes that were added to the request map. - * - * @param count the number of times the method is expected to have been called - * @return the state-changes that were added to the request map - */ - protected List getStateChangeRequests(int count) { - ArgumentCaptor captor = ArgumentCaptor.forClass(PdpStateChange.class); - - verify(reqmap, times(count)).addRequest(any(), captor.capture()); - - return captor.getAllValues().stream().filter(req -> req != null).collect(Collectors.toList()); - } - - /** - * 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 getUpdateRequests(int count) { - ArgumentCaptor captor = ArgumentCaptor.forClass(PdpUpdate.class); - - verify(reqmap, times(count)).addRequest(captor.capture(), any()); - - return captor.getAllValues().stream().filter(req -> req != null).collect(Collectors.toList()); - } - - /** - * Copies a list and sorts it by group name. - * - * @param source source list to copy - * @return a copy of the source list - */ - private List copyList(List source) { - List newlst = new ArrayList<>(source); - Collections.sort(newlst, (left, right) -> left.getName().compareTo(right.getName())); - return newlst; - } - - /** - * Loads a list of groups. - * - * @param fileName name of the file from which to load - * @return a list of groups - */ - protected List loadGroups(String fileName) { - return loadPdpGroups(fileName).getGroups(); - } - - /** - * Loads a PdpGroups. - * - * @param fileName name of the file from which to load - * @return a PdpGroups - */ - protected PdpGroups loadPdpGroups(String fileName) { - return loadFile(fileName, PdpGroups.class); - } - - /** - * Loads a group. - * - * @param fileName name of the file from which to load - * @return a group - */ - protected PdpGroup loadGroup(String fileName) { - return loadFile(fileName, PdpGroup.class); - } - - /** - * Loads a list of policies. - * - * @param fileName name of the file from which to load - * @return a list of policies - */ - protected List loadPolicies(String fileName) { - return loadFile(fileName, PolicyList.class).policies; - } - - /** - * Loads a policy. - * - * @param fileName name of the file from which to load - * @return a policy - */ - protected ToscaPolicy loadPolicy(String fileName) { - return loadFile(fileName, ToscaPolicy.class); - } - - /** - * Loads a policy type. - * - * @param fileName name of the file from which to load - * @return a policy type - */ - protected ToscaPolicyType loadPolicyType(String fileName) { - return loadFile(fileName, ToscaPolicyType.class); - } - - /** - * 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 loadFile(String fileName, Class 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 policies; - } -} diff --git a/main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestGroupData.java b/main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestGroupData.java deleted file mode 100644 index 92b30b2e..00000000 --- a/main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestGroupData.java +++ /dev/null @@ -1,103 +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.depundep; - -import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; - -import org.junit.Before; -import org.junit.Test; -import org.onap.policy.models.pdp.concepts.PdpGroup; - -public class TestGroupData { - private static final String NAME = "my-name"; - - private PdpGroup oldGroup; - private PdpGroup newGroup; - private GroupData data; - - /** - * Sets up. - */ - @Before - public void setUp() { - oldGroup = new PdpGroup(); - oldGroup.setName(NAME); - - newGroup = new PdpGroup(oldGroup); - - data = new GroupData(oldGroup); - } - - @Test - public void testNew() { - data = new GroupData(oldGroup, true); - assertSame(oldGroup, data.getGroup()); - - assertFalse(data.isUnchanged()); - assertTrue(data.isNew()); - assertFalse(data.isUpdated()); - - data.update(newGroup); - assertFalse(data.isUnchanged()); - assertTrue(data.isNew()); - assertFalse(data.isUpdated()); - assertSame(newGroup, data.getGroup()); - - // repeat with a new group - newGroup = new PdpGroup(oldGroup); - data.update(newGroup); - assertFalse(data.isUnchanged()); - assertTrue(data.isNew()); - assertFalse(data.isUpdated()); - assertSame(newGroup, data.getGroup()); - } - - @Test - public void testUpdateOnly() { - assertTrue(data.isUnchanged()); - assertFalse(data.isUpdated()); - assertSame(oldGroup, data.getGroup()); - - data.update(newGroup); - - assertFalse(data.isUnchanged()); - assertTrue(data.isUpdated()); - assertFalse(data.isNew()); - assertSame(newGroup, data.getGroup()); - - // repeat - newGroup = new PdpGroup(oldGroup); - data.update(newGroup); - assertFalse(data.isUnchanged()); - assertTrue(data.isUpdated()); - assertFalse(data.isNew()); - assertSame(newGroup, data.getGroup()); - - // incorrect name - newGroup = new PdpGroup(oldGroup); - newGroup.setName("other"); - assertThatIllegalArgumentException().isThrownBy(() -> data.update(newGroup)) - .withMessage("expected group my-name, but received other"); - } -} diff --git a/main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestPdpGroupDeleteControllerV1.java b/main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestPdpGroupDeleteControllerV1.java deleted file mode 100644 index 670d1e05..00000000 --- a/main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestPdpGroupDeleteControllerV1.java +++ /dev/null @@ -1,105 +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.rest.depundep; - -import static org.junit.Assert.assertEquals; - -import javax.ws.rs.client.Invocation; -import javax.ws.rs.core.Response; -import org.junit.Test; -import org.onap.policy.models.pap.concepts.PdpGroupDeleteResponse; -import org.onap.policy.pap.main.rest.CommonPapRestServer; - -/** - * Note: this tests failure cases; success cases are tested by tests in the "e2e" package. - */ -public class TestPdpGroupDeleteControllerV1 extends CommonPapRestServer { - - private static final String GROUP_NOT_FOUND = "group not found"; - private static final String DELETE_GROUP_ENDPOINT = "pdps/groups"; - private static final String DELETE_POLICIES_ENDPOINT = "pdps/policies"; - - @Test - public void testSwagger() throws Exception { - super.testSwagger(DELETE_GROUP_ENDPOINT + "/{name}"); - - super.testSwagger(DELETE_POLICIES_ENDPOINT + "/{name}"); - super.testSwagger(DELETE_POLICIES_ENDPOINT + "/{name}/versions/{version}"); - } - - @Test - public void testDeleteGroup() throws Exception { - String uri = DELETE_GROUP_ENDPOINT + "/my-name"; - - Invocation.Builder invocationBuilder = sendRequest(uri); - Response rawresp = invocationBuilder.delete(); - PdpGroupDeleteResponse resp = rawresp.readEntity(PdpGroupDeleteResponse.class); - assertEquals(Response.Status.NOT_FOUND.getStatusCode(), rawresp.getStatus()); - assertEquals(GROUP_NOT_FOUND, resp.getErrorDetails()); - - rawresp = invocationBuilder.delete(); - resp = rawresp.readEntity(PdpGroupDeleteResponse.class); - assertEquals(Response.Status.NOT_FOUND.getStatusCode(), rawresp.getStatus()); - assertEquals(GROUP_NOT_FOUND, resp.getErrorDetails()); - - // verify it fails when no authorization info is included - checkUnauthRequest(uri, req -> req.delete()); - } - - @Test - public void testDeletePolicy() throws Exception { - String uri = DELETE_POLICIES_ENDPOINT + "/my-name"; - - Invocation.Builder invocationBuilder = sendRequest(uri); - Response rawresp = invocationBuilder.delete(); - PdpGroupDeleteResponse resp = rawresp.readEntity(PdpGroupDeleteResponse.class); - assertEquals(Response.Status.NOT_FOUND.getStatusCode(), rawresp.getStatus()); - assertEquals("cannot find policy: my-name null", resp.getErrorDetails()); - - rawresp = invocationBuilder.delete(); - resp = rawresp.readEntity(PdpGroupDeleteResponse.class); - assertEquals(Response.Status.NOT_FOUND.getStatusCode(), rawresp.getStatus()); - assertEquals("cannot find policy: my-name null", resp.getErrorDetails()); - - // verify it fails when no authorization info is included - checkUnauthRequest(uri, req -> req.delete()); - } - - @Test - public void testDeletePolicyVersion() throws Exception { - String uri = DELETE_POLICIES_ENDPOINT + "/my-name/versions/3"; - - Invocation.Builder invocationBuilder = sendRequest(uri); - Response rawresp = invocationBuilder.delete(); - PdpGroupDeleteResponse resp = rawresp.readEntity(PdpGroupDeleteResponse.class); - assertEquals(Response.Status.NOT_FOUND.getStatusCode(), rawresp.getStatus()); - assertEquals("cannot find policy: my-name 3", resp.getErrorDetails()); - - rawresp = invocationBuilder.delete(); - resp = rawresp.readEntity(PdpGroupDeleteResponse.class); - assertEquals(Response.Status.NOT_FOUND.getStatusCode(), rawresp.getStatus()); - assertEquals("cannot find policy: my-name 3", resp.getErrorDetails()); - - // verify it fails when no authorization info is included - checkUnauthRequest(uri, req -> req.delete()); - } -} diff --git a/main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestPdpGroupDeleteProvider.java b/main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestPdpGroupDeleteProvider.java deleted file mode 100644 index cac16808..00000000 --- a/main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestPdpGroupDeleteProvider.java +++ /dev/null @@ -1,297 +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.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.Matchers.eq; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.Arrays; -import java.util.List; -import java.util.Set; -import javax.ws.rs.core.Response.Status; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.Mock; -import org.onap.policy.common.utils.services.Registry; -import org.onap.policy.models.base.PfModelException; -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.tosca.authorative.concepts.ToscaPolicyIdentifier; -import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyIdentifierOptVersion; -import org.onap.policy.pap.main.rest.depundep.ProviderBase.Updater; - -public class TestPdpGroupDeleteProvider extends ProviderSuper { - private static final String EXPECTED_EXCEPTION = "expected exception"; - private static final String GROUP1_NAME = "groupA"; - - @Mock - private SessionData session; - - @Captor - private ArgumentCaptor> pdpCaptor; - - private MyProvider prov; - private ToscaPolicyIdentifierOptVersion optIdent; - private ToscaPolicyIdentifierOptVersion fullIdent; - private ToscaPolicyIdentifier ident; - private Updater updater; - - - @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(); - - ident = policy1.getIdentifier(); - optIdent = new ToscaPolicyIdentifierOptVersion(ident.getName(), null); - fullIdent = new ToscaPolicyIdentifierOptVersion(ident.getName(), ident.getVersion()); - - prov = new MyProvider(); - - updater = prov.makeUpdater(session, policy1, fullIdent); - } - - @Test - public void testDeleteGroup_Inctive() throws Exception { - PdpGroup group = loadGroup("deleteGroup.json"); - - when(session.getGroup(GROUP1_NAME)).thenReturn(group); - - prov.deleteGroup(GROUP1_NAME); - - verify(session).deleteGroupFromDb(group); - - // should be no PDP requests - verify(session, never()).addRequests(any(), any()); - } - - @Test - public void testDeleteGroup_Active() throws Exception { - PdpGroup group = loadGroup("deleteGroup.json"); - - group.setPdpGroupState(PdpState.ACTIVE); - - when(session.getGroup(GROUP1_NAME)).thenReturn(group); - - assertThatThrownBy(() -> prov.deleteGroup(GROUP1_NAME)).isInstanceOf(PfModelException.class) - .hasMessage("group is still ACTIVE"); - } - - @Test - public void testDeleteGroup_NotFound() throws Exception { - assertThatThrownBy(() -> prov.deleteGroup(GROUP1_NAME)).isInstanceOf(PfModelException.class) - .hasMessage("group not found") - .extracting(ex -> ((PfModelException) ex).getErrorResponse().getResponseCode()) - .isEqualTo(Status.NOT_FOUND); - } - - @Test - public void testDeleteGroup_Inactive() throws Exception { - PdpGroup group = loadGroup("deleteGroup.json"); - - when(session.getGroup(GROUP1_NAME)).thenReturn(group); - - prov.deleteGroup(GROUP1_NAME); - - verify(session).deleteGroupFromDb(group); - - // should done no requests for the PDPs - verify(session, never()).addRequests(any(), any()); - } - - @Test - public void testDeleteGroup_DaoEx() throws Exception { - PdpGroup group = loadGroup("deleteGroup.json"); - - when(session.getGroup(GROUP1_NAME)).thenReturn(group); - - PfModelException ex = new PfModelException(Status.BAD_REQUEST, EXPECTED_EXCEPTION); - doThrow(ex).when(session).deleteGroupFromDb(group); - - assertThatThrownBy(() -> prov.deleteGroup(GROUP1_NAME)).isSameAs(ex); - } - - @Test - public void testUndeploy_testUndeployPolicy() throws Exception { - prov.undeploy(optIdent); - } - - /** - * Tests using a real provider, just to verify end-to-end functionality. - * - * @throws Exception if an error occurs - */ - @Test - public void testUndeploy_Full() throws Exception { - when(dao.getFilteredPolicyList(any())).thenReturn(Arrays.asList(policy1)); - - PdpGroup group = loadGroup("undeploy.json"); - - when(dao.getFilteredPdpGroups(any())).thenReturn(Arrays.asList(group)); - when(dao.getFilteredPolicyList(any())).thenReturn(Arrays.asList(policy1)); - - new PdpGroupDeleteProvider().undeploy(fullIdent); - - // should have updated the old group - List updates = getGroupUpdates(); - assertEquals(1, updates.size()); - assertSame(group, updates.get(0)); - assertEquals(PdpState.ACTIVE, group.getPdpGroupState()); - - // should be one less item in the new subgroup - assertEquals(2, group.getPdpSubgroups().get(0).getPolicies().size()); - - // should have updated the PDPs - List requests = getUpdateRequests(1); - assertEquals(1, requests.size()); - PdpUpdate req = requests.get(0); - assertEquals("pdpA", req.getName()); - assertEquals(GROUP1_NAME, req.getPdpGroup()); - assertEquals("pdpTypeA", req.getPdpSubgroup()); - assertEquals(Arrays.asList(policy1, policy1), req.getPolicies()); - } - - @Test - public void testUndeployPolicy_NotFound() throws Exception { - when(session.isUnchanged()).thenReturn(true); - - assertThatThrownBy(() -> prov.undeploy(optIdent)).isInstanceOf(PfModelException.class) - .hasMessage("policy does not appear in any PDP group: policyA null"); - } - - @Test - public void testUndeployPolicy_DaoEx() throws Exception { - PfModelException exc = new PfModelException(Status.BAD_REQUEST, EXPECTED_EXCEPTION); - - prov = spy(prov); - doThrow(exc).when(prov).processPolicy(any(), any()); - - assertThatThrownBy(() -> prov.undeploy(optIdent)).isSameAs(exc); - } - - @Test - public void testUndeployPolicy_RtEx() throws Exception { - RuntimeException exc = new RuntimeException(EXPECTED_EXCEPTION); - - prov = spy(prov); - doThrow(exc).when(prov).processPolicy(any(), any()); - - assertThatThrownBy(() -> prov.undeploy(optIdent)).isSameAs(exc); - } - - @Test - public void testMakeUpdater_WithVersion() throws PfModelException { - /* - * this group has two matching policies and one policy with a different name. - */ - PdpGroup group = loadGroup("undeploy.json"); - - PdpSubGroup subgroup = group.getPdpSubgroups().get(0); - int origSize = subgroup.getPolicies().size(); - - // invoke updater - matching both name and version - assertTrue(updater.apply(group, subgroup)); - - // identified policy should have been removed - assertEquals(origSize - 1, subgroup.getPolicies().size()); - assertFalse(subgroup.getPolicies().contains(ident)); - - verify(session).trackUndeploy(eq(ident), pdpCaptor.capture()); - assertEquals("[pdpA]", pdpCaptor.getValue().toString()); - } - - @Test - public void testMakeUpdater_NullVersion() throws PfModelException { - /* - * this group has two matching policies and one policy with a different name. - */ - PdpGroup group = loadGroup("undeploy.json"); - - PdpSubGroup subgroup = group.getPdpSubgroups().get(0); - int origSize = subgroup.getPolicies().size(); - - // invoke updater - matching the name, but with a null (i.e., wild-card) version - updater = prov.makeUpdater(session, policy1, optIdent); - assertTrue(updater.apply(group, subgroup)); - - // identified policy should have been removed - assertEquals(origSize - 2, subgroup.getPolicies().size()); - assertFalse(subgroup.getPolicies().contains(ident)); - } - - @Test - public void testMakeUpdater_NotFound() throws PfModelException { - /* - * this group has one policy with a different name and one with a different - * version, but not the policy of interest. - */ - PdpGroup group = loadGroup("undeployMakeUpdaterGroupNotFound.json"); - - PdpSubGroup subgroup = group.getPdpSubgroups().get(0); - int origSize = subgroup.getPolicies().size(); - - // invoke updater - assertFalse(updater.apply(group, subgroup)); - - // should be unchanged - assertEquals(origSize, subgroup.getPolicies().size()); - } - - - private class MyProvider extends PdpGroupDeleteProvider { - - @Override - protected void process(T request, BiConsumerWithEx processor) throws PfModelException { - processor.accept(session, request); - } - - @Override - protected void processPolicy(SessionData data, ToscaPolicyIdentifierOptVersion desiredPolicy) - throws PfModelException { - // do nothing - } - } -} diff --git a/main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestPdpGroupDeployControllerV1.java b/main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestPdpGroupDeployControllerV1.java deleted file mode 100644 index 8c01e029..00000000 --- a/main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestPdpGroupDeployControllerV1.java +++ /dev/null @@ -1,113 +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.rest.depundep; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; - -import java.util.Arrays; -import javax.ws.rs.client.Entity; -import javax.ws.rs.client.Invocation; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import org.junit.Test; -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.PdpSubGroup; -import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyIdentifierOptVersion; -import org.onap.policy.pap.main.rest.CommonPapRestServer; - -/** - * Note: this tests failure cases; success cases are tested by tests in the "e2e" package. - */ -public class TestPdpGroupDeployControllerV1 extends CommonPapRestServer { - - private static final String DEPLOY_GROUP_ENDPOINT = "pdps"; - private static final String DEPLOY_POLICIES_ENDPOINT = "pdps/policies"; - - @Test - public void testSwagger() throws Exception { - super.testSwagger(DEPLOY_GROUP_ENDPOINT); - super.testSwagger(DEPLOY_POLICIES_ENDPOINT); - } - - @Test - public void testDeployGroup() throws Exception { - Entity entgrp = makePdpGroupEntity(); - - Invocation.Builder invocationBuilder = sendRequest(DEPLOY_GROUP_ENDPOINT); - Response rawresp = invocationBuilder.post(entgrp); - PdpGroupDeployResponse resp = rawresp.readEntity(PdpGroupDeployResponse.class); - assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), rawresp.getStatus()); - assertNotNull(resp.getErrorDetails()); - - rawresp = invocationBuilder.post(entgrp); - resp = rawresp.readEntity(PdpGroupDeployResponse.class); - assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), rawresp.getStatus()); - assertNotNull(resp.getErrorDetails()); - - // verify it fails when no authorization info is included - checkUnauthRequest(DEPLOY_GROUP_ENDPOINT, req -> req.post(entgrp)); - } - - @Test - public void testDeployPolicies() throws Exception { - Entity entgrp = makePdpPoliciesEntity(); - - Invocation.Builder invocationBuilder = sendRequest(DEPLOY_POLICIES_ENDPOINT); - Response rawresp = invocationBuilder.post(entgrp); - PdpGroupDeployResponse resp = rawresp.readEntity(PdpGroupDeployResponse.class); - assertEquals(Response.Status.NOT_FOUND.getStatusCode(), rawresp.getStatus()); - assertNotNull(resp.getErrorDetails()); - - rawresp = invocationBuilder.post(entgrp); - resp = rawresp.readEntity(PdpGroupDeployResponse.class); - assertEquals(Response.Status.NOT_FOUND.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 makePdpGroupEntity() { - PdpSubGroup subgrp = new PdpSubGroup(); - subgrp.setPdpType("drools"); - - PdpGroup group = new PdpGroup(); - group.setName("drools-group"); - group.setDescription("my description"); - group.setPdpSubgroups(Arrays.asList(subgrp)); - - return Entity.entity(group, MediaType.APPLICATION_JSON); - } - - private Entity makePdpPoliciesEntity() { - ToscaPolicyIdentifierOptVersion pol1 = new ToscaPolicyIdentifierOptVersion("policy-a", "1"); - ToscaPolicyIdentifierOptVersion pol2 = new ToscaPolicyIdentifierOptVersion("policy-b", null); - - 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 deleted file mode 100644 index 60f9d2e8..00000000 --- a/main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestPdpGroupDeployProvider.java +++ /dev/null @@ -1,932 +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.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 java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.TreeMap; -import java.util.TreeSet; -import java.util.stream.Collectors; -import javax.ws.rs.core.Response.Status; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.onap.policy.common.utils.services.Registry; -import org.onap.policy.models.base.PfModelException; -import org.onap.policy.models.base.PfModelRuntimeException; -import org.onap.policy.models.pap.concepts.PdpDeployPolicies; -import org.onap.policy.models.pdp.concepts.PdpGroup; -import org.onap.policy.models.pdp.concepts.PdpGroups; -import org.onap.policy.models.pdp.concepts.PdpStateChange; -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.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.notification.PolicyPdpNotificationData; - -public class TestPdpGroupDeployProvider extends ProviderSuper { - private static final String EXPECTED_EXCEPTION = "expected exception"; - - private static final String POLICY2_NAME = "policyB"; - private static final String POLICY1_VERSION = "1.2.3"; - private static final String GROUP1_NAME = "groupA"; - 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.getFilteredPolicyList(any())).thenReturn(loadPolicies("daoPolicyList.json")); - when(dao.getPolicyTypeList("typeA", "100.2.3")).thenReturn(Arrays.asList(loadPolicyType("daoPolicyType.json"))); - - prov = new PdpGroupDeployProvider(); - } - - @Test - public void testCreateOrUpdateGroups() throws Exception { - prov.createOrUpdateGroups(loadPdpGroups("emptyGroups.json")); - - // no groups, so no action should have been taken - assertNoGroupAction(); - } - - @Test - public void testCreateOrUpdateGroups_InvalidRequest() throws Exception { - assertThatThrownBy(() -> prov.createOrUpdateGroups(new PdpGroups())).isInstanceOf(PfModelException.class) - .hasMessageContaining("is null"); - - assertNoGroupAction(); - } - - @Test - public void testCreateOrUpdate_Invalid() throws Exception { - PdpGroups groups = loadPdpGroups("createGroups.json"); - groups.getGroups().get(0).setPdpGroupState(PdpState.TERMINATED); - - assertThatThrownBy(() -> prov.createOrUpdateGroups(groups)).isInstanceOf(PfModelException.class) - .hasMessageContaining("pdpGroupState"); - - assertNoGroupAction(); - } - - @Test - public void testAddGroup() throws Exception { - PdpGroups groups = loadPdpGroups("createGroups.json"); - PdpGroup group = groups.getGroups().get(0); - group.setPdpGroupState(PdpState.PASSIVE); - - prov.createOrUpdateGroups(groups); - - // should not have updated the state - assertEquals(PdpState.PASSIVE, group.getPdpGroupState()); - - assertSame(group, getGroupCreates().get(0)); - } - - @Test - public void testAddGroup_Invalid() throws Exception { - PdpGroups groups = loadPdpGroups("createGroups.json"); - groups.getGroups().get(0).setPdpGroupState(PdpState.TERMINATED); - - assertThatThrownBy(() -> prov.createOrUpdateGroups(groups)).isInstanceOf(PfModelException.class) - .hasMessageContaining("pdpGroupState"); - - assertNoGroupAction(); - } - - @Test - public void testAddGroup_InvalidSubGroup() throws Exception { - PdpGroups groups = loadPdpGroups("createGroups.json"); - - // policy won't match supported type - groups.getGroups().get(0).getPdpSubgroups().get(0).getSupportedPolicyTypes().get(0).setVersion("99.99.99"); - - assertThatThrownBy(() -> prov.createOrUpdateGroups(groups)).isInstanceOf(PfModelException.class) - .hasMessageContaining("supported policy"); - - assertNoGroupAction(); - } - - @Test - public void testValidateGroupOnly_NullState() throws PfModelException { - PdpGroups groups = loadPdpGroups("createGroups.json"); - groups.getGroups().get(0).setPdpGroupState(null); - prov.createOrUpdateGroups(groups); - } - - @Test - public void testValidateGroupOnly_Active() throws PfModelException { - PdpGroups groups = loadPdpGroups("createGroups.json"); - groups.getGroups().get(0).setPdpGroupState(PdpState.ACTIVE); - prov.createOrUpdateGroups(groups); - } - - @Test - public void testValidateGroupOnly_Passive() throws PfModelException { - PdpGroups groups = loadPdpGroups("createGroups.json"); - groups.getGroups().get(0).setPdpGroupState(PdpState.PASSIVE); - prov.createOrUpdateGroups(groups); - } - - @Test - public void testValidateGroupOnly_Invalid() { - PdpGroups groups = loadPdpGroups("createGroups.json"); - groups.getGroups().get(0).setPdpGroupState(PdpState.TERMINATED); - - assertThatThrownBy(() -> prov.createOrUpdateGroups(groups)).isInstanceOf(PfModelException.class) - .hasMessageContaining("pdpGroupState"); - } - - @Test - public void testUpdateGroup() throws Exception { - PdpGroups groups = loadPdpGroups("createGroups.json"); - - // DB group = new group - PdpGroup group = new PdpGroup(groups.getGroups().get(0)); - when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); - - prov.createOrUpdateGroups(groups); - - assertNoGroupAction(); - } - - @Test - public void testUpdateGroup_PropertiesChanged() throws Exception { - PdpGroups groups = loadPdpGroups("createGroups.json"); - - PdpGroup group = new PdpGroup(groups.getGroups().get(0)); - group.setProperties(new TreeMap<>()); - - when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); - - assertThatThrownBy(() -> prov.createOrUpdateGroups(groups)).isInstanceOf(PfModelException.class) - .hasMessageContaining("properties"); - - assertNoGroupAction(); - } - - @Test - public void testUpdateGroup_NewDescription() throws Exception { - PdpGroups groups = loadPdpGroups("createGroups.json"); - PdpGroup newgrp = groups.getGroups().get(0); - PdpGroup group = new PdpGroup(newgrp); - group.setDescription("old description"); - when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); - - prov.createOrUpdateGroups(groups); - - assertGroupUpdateOnly(group); - - assertEquals(group.getDescription(), "my description"); - assertEquals(newgrp.toString(), group.toString()); - } - - @Test - public void testUpdateGroup_NewState() throws Exception { - PdpGroups groups = loadPdpGroups("createGroups.json"); - PdpGroup newgrp = groups.getGroups().get(0); - PdpGroup group = new PdpGroup(newgrp); - group.setPdpGroupState(PdpState.TEST); - when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); - - prov.createOrUpdateGroups(groups); - - assertGroupUpdateOnly(group); - - assertEquals(PdpState.ACTIVE, group.getPdpGroupState()); - assertEquals(newgrp.toString(), group.toString()); - } - - @Test - public void testUpdateGroup_NewSubGroup() throws Exception { - PdpGroups groups = loadPdpGroups("createGroupsNewSub.json"); - PdpGroup group = loadPdpGroups("createGroups.json").getGroups().get(0); - when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); - - prov.createOrUpdateGroups(groups); - - PdpGroup newgrp = groups.getGroups().get(0); - assertEquals(newgrp.toString(), group.toString()); - assertGroupUpdateOnly(group); - } - - @Test - public void testUpdateGroup_UpdatedSubGroup() throws Exception { - PdpGroups groups = loadPdpGroups("createGroups.json"); - PdpGroup newgrp = groups.getGroups().get(0); - PdpGroup group = new PdpGroup(newgrp); - when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); - - // something different in this subgroup - group.getPdpSubgroups().get(0).setDesiredInstanceCount(10); - - prov.createOrUpdateGroups(groups); - - assertEquals(newgrp.toString(), group.toString()); - assertGroupUpdateOnly(group); - } - - @Test - public void testUpdateGroup_notifyPdpsDelSubGroups() throws Exception { - PdpGroup dbgroup = new PdpGroup(loadPdpGroups("createGroupsDelSub.json").getGroups().get(0)); - when(dao.getPdpGroups(dbgroup.getName())).thenReturn(Arrays.asList(dbgroup)); - - PdpGroups groups = loadPdpGroups("createGroups.json"); - - prov.createOrUpdateGroups(groups); - - // verify that DB group was updated - List updates = getGroupUpdates(); - assertEquals(1, updates.size()); - dbgroup = updates.get(0); - - PdpGroup newgrp = groups.getGroups().get(0); - - Collections.sort(newgrp.getPdpSubgroups().get(0).getPolicies()); - Collections.sort(dbgroup.getPdpSubgroups().get(0).getPolicies()); - - assertEquals(newgrp.toString(), dbgroup.toString()); - - // no deployment notifications - verify(notifier, never()).addDeploymentData(any()); - - // should have notified of deleted subgroup's policies/PDPs - ArgumentCaptor captor = ArgumentCaptor.forClass(PolicyPdpNotificationData.class); - verify(notifier).addUndeploymentData(captor.capture()); - assertDeploymentData(captor, policy1.getIdentifier(), "[pdpB, pdpD]"); - - // this requires a PDP UPDATE message - List pdpUpdates = getUpdateRequests(2); - assertEquals(2, pdpUpdates.size()); - - PdpUpdate pdpUpdate = pdpUpdates.get(0); - assertEquals(PDP2, pdpUpdate.getName()); - assertNull(pdpUpdate.getPdpGroup()); - - pdpUpdate = pdpUpdates.get(1); - assertEquals(PDP4, pdpUpdate.getName()); - assertNull(pdpUpdate.getPdpGroup()); - - // it also requires a PDP STATE-CHANGE message - List changes = getStateChangeRequests(2); - assertEquals(2, changes.size()); - - PdpStateChange change = changes.get(0); - assertEquals(PDP2, change.getName()); - assertEquals(PdpState.PASSIVE, change.getState()); - - change = changes.get(1); - assertEquals(PDP4, change.getName()); - assertEquals(PdpState.PASSIVE, change.getState()); - } - - @Test - public void testUpdateGroup_MultipleChanges() throws Exception { - PdpGroups groups = loadPdpGroups("createGroups.json"); - PdpGroup newgrp = groups.getGroups().get(0); - PdpGroup group = new PdpGroup(newgrp); - when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); - - PdpSubGroup subgrp = newgrp.getPdpSubgroups().get(0); - subgrp.setDesiredInstanceCount(30); - subgrp.getPolicies().add(new ToscaPolicyIdentifier(POLICY2_NAME, POLICY1_VERSION)); - subgrp.getSupportedPolicyTypes().add(new ToscaPolicyTypeIdentifier("typeX.*", "9.8.7")); - - when(dao.getFilteredPolicyList(any())) - .thenReturn(loadPolicies("createGroupNewPolicy.json")) - .thenReturn(loadPolicies("daoPolicyList.json")) - .thenReturn(loadPolicies("createGroupNewPolicy.json")); - - prov.createOrUpdateGroups(groups); - - Collections.sort(newgrp.getPdpSubgroups().get(0).getPolicies()); - Collections.sort(group.getPdpSubgroups().get(0).getPolicies()); - - assertEquals(newgrp.toString(), group.toString()); - - // this requires a PDP UPDATE message - assertGroupUpdate(group, subgrp); - } - - @Test - public void testUpdateField_Unchanged() throws Exception { - PdpGroups groups = loadPdpGroups("createGroups.json"); - PdpGroup newgrp = groups.getGroups().get(0); - PdpGroup group = new PdpGroup(newgrp); - when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); - - prov.createOrUpdateGroups(groups); - - assertNoGroupAction(); - } - - @Test - public void testUpdateField_WasNull() throws Exception { - PdpGroups groups = loadPdpGroups("createGroups.json"); - PdpGroup newgrp = groups.getGroups().get(0); - PdpGroup group = new PdpGroup(newgrp); - when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); - - group.setDescription(null); - - prov.createOrUpdateGroups(groups); - - assertEquals(newgrp.toString(), group.toString()); - assertGroupUpdateOnly(group); - } - - @Test - public void testUpdateField_NowNull() throws Exception { - PdpGroups groups = loadPdpGroups("createGroups.json"); - PdpGroup newgrp = groups.getGroups().get(0); - PdpGroup group = new PdpGroup(newgrp); - when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); - - newgrp.setDescription(null); - - prov.createOrUpdateGroups(groups); - - assertEquals(newgrp.toString(), group.toString()); - assertGroupUpdateOnly(group); - } - - @Test - public void testUpdateField_Changed() throws Exception { - PdpGroups groups = loadPdpGroups("createGroups.json"); - PdpGroup newgrp = groups.getGroups().get(0); - PdpGroup group = new PdpGroup(newgrp); - when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); - - newgrp.setDescription(group.getDescription() + "-changed"); - - prov.createOrUpdateGroups(groups); - - assertEquals(newgrp.toString(), group.toString()); - assertGroupUpdateOnly(group); - } - - @Test - public void testAddSubGroup() throws Exception { - PdpGroups groups = loadPdpGroups("createGroupsNewSub.json"); - PdpGroup group = loadPdpGroups("createGroups.json").getGroups().get(0); - when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); - - prov.createOrUpdateGroups(groups); - - PdpGroup newgrp = groups.getGroups().get(0); - - PdpSubGroup newsub = newgrp.getPdpSubgroups().get(1); - newsub.setCurrentInstanceCount(0); - newsub.setPdpInstances(new ArrayList<>(0)); - - assertEquals(newgrp.toString(), group.toString()); - assertGroupUpdateOnly(group); - } - - /** - * Tests addSubgroup() when the new subgroup has a wild-card policy type. - * - * @throws Exception if an error occurs - */ - @Test - public void testAddSubGroupWildCardPolicyType() throws Exception { - when(dao.getFilteredPolicyList(any())).thenReturn(loadPolicies("daoPolicyListWildCard.json")); - when(dao.getPolicyTypeList("some.*", "2.3.4")).thenReturn(Collections.emptyList()); - - PdpGroups groups = loadPdpGroups("createGroupsWildCard.json"); - PdpGroup group = loadPdpGroups("createGroups.json").getGroups().get(0); - when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); - - prov.createOrUpdateGroups(groups); - - PdpGroup newgrp = groups.getGroups().get(0); - - PdpSubGroup newsub = newgrp.getPdpSubgroups().get(1); - newsub.setCurrentInstanceCount(0); - newsub.setPdpInstances(new ArrayList<>(0)); - - assertEquals(newgrp.toString(), group.toString()); - } - - /** - * Tests addSubgroup() when the new subgroup has a wild-card policy type, but the - * policy doesn't have a matching type. - * - * @throws PfModelException if an error occurs - */ - @Test - public void testAddSubGroupWildCardPolicyTypeUnmatched() throws PfModelException { - when(dao.getFilteredPolicyList(any())).thenReturn(loadPolicies("daoPolicyListWildCardUnmatched.json")); - when(dao.getPolicyTypeList("some.*", "2.3.4")).thenReturn(Collections.emptyList()); - - PdpGroups groups = loadPdpGroups("createGroupsWildCard.json"); - PdpGroup group = loadPdpGroups("createGroups.json").getGroups().get(0); - when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); - - assertThatThrownBy(() -> prov.createOrUpdateGroups(groups)).isInstanceOf(PfModelException.class); - } - - @Test - public void testAddSubGroup_ValidationPolicyTypeNotFound() throws Exception { - PdpGroups groups = loadPdpGroups("createGroupsNewSub.json"); - PdpGroup group = loadPdpGroups("createGroups.json").getGroups().get(0); - when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); - - when(dao.getPolicyTypeList(any(), any())).thenReturn(Collections.emptyList()); - - assertThatThrownBy(() -> prov.createOrUpdateGroups(groups)).hasMessageContaining("unknown policy type"); - } - - @Test - public void testAddSubGroup_ValidationPolicyTypeDaoEx() throws Exception { - PdpGroups groups = loadPdpGroups("createGroupsNewSub.json"); - PdpGroup group = loadPdpGroups("createGroups.json").getGroups().get(0); - when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); - - PfModelException exc = new PfModelException(Status.CONFLICT, EXPECTED_EXCEPTION); - when(dao.getPolicyTypeList(any(), any())).thenThrow(exc); - - assertThatThrownBy(() -> prov.createOrUpdateGroups(groups)).isSameAs(exc); - } - - @Test - public void testAddSubGroup_ValidationPolicyNotFound() throws Exception { - PdpGroups groups = loadPdpGroups("createGroupsNewSubNotFound.json"); - PdpGroup group = loadPdpGroups("createGroups.json").getGroups().get(0); - when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); - - when(dao.getFilteredPolicyList(any())).thenReturn(Collections.emptyList()); - - assertThatThrownBy(() -> prov.createOrUpdateGroups(groups)).hasMessageContaining("unknown policy"); - } - - @Test - public void testAddSubGroup_ValidationPolicyDaoEx() throws Exception { - PdpGroups groups = loadPdpGroups("createGroupsNewSubNotFound.json"); - PdpGroup group = loadPdpGroups("createGroups.json").getGroups().get(0); - when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); - - PfModelException exc = new PfModelException(Status.CONFLICT, EXPECTED_EXCEPTION); - when(dao.getFilteredPolicyList(any())).thenThrow(exc); - - assertThatThrownBy(() -> prov.createOrUpdateGroups(groups)).isSameAs(exc); - } - - @Test - public void testAddSubGroup_ValidateVersionPrefixMatch() throws Exception { - PdpGroups groups = loadPdpGroups("createGroups.json"); - PdpGroup newgrp = groups.getGroups().get(0); - PdpGroup dbgroup = new PdpGroup(newgrp); - when(dao.getPdpGroups(dbgroup.getName())).thenReturn(Arrays.asList(dbgroup)); - - when(dao.getFilteredPolicyList(any())).thenReturn(loadPolicies("createGroupNewPolicy.json")) - .thenReturn(loadPolicies("daoPolicyList.json")) - .thenReturn(loadPolicies("createGroupNewPolicy.json")); - - PdpGroups reqgroups = loadPdpGroups("createGroupsVersPrefix.json"); - - prov.createOrUpdateGroups(reqgroups); - - Collections.sort(newgrp.getPdpSubgroups().get(0).getPolicies()); - Collections.sort(dbgroup.getPdpSubgroups().get(0).getPolicies()); - - assertEquals(newgrp.toString(), dbgroup.toString()); - } - - @Test - public void testAddSubGroup_ValidateVersionPrefixMismatch() throws Exception { - PdpGroups groups = loadPdpGroups("createGroups.json"); - PdpGroup newgrp = groups.getGroups().get(0); - PdpGroup dbgroup = new PdpGroup(newgrp); - when(dao.getPdpGroups(dbgroup.getName())).thenReturn(Arrays.asList(dbgroup)); - - when(dao.getFilteredPolicyList(any())).thenReturn(loadPolicies("daoPolicyList.json")); - - - PdpGroups reqgroups = loadPdpGroups("createGroupsVersPrefixMismatch.json"); - - assertThatThrownBy(() -> prov.createOrUpdateGroups(reqgroups)).isInstanceOf(PfModelException.class) - .hasMessageContaining("different version already deployed"); - - assertNoGroupAction(); - } - - @Test - public void testUpdateSubGroup_Invalid() throws Exception { - PdpGroups groups = loadPdpGroups("createGroups.json"); - PdpGroup newgrp = groups.getGroups().get(0); - PdpGroup group = new PdpGroup(newgrp); - when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); - - // change properties - newgrp.getPdpSubgroups().get(0).setProperties(new TreeMap<>()); - - assertThatThrownBy(() -> prov.createOrUpdateGroups(groups)).isInstanceOf(PfModelException.class) - .hasMessageContaining("properties"); - - assertNoGroupAction(); - } - - @Test - public void testUpdateSubGroup_SupportedPolicies() throws Exception { - PdpGroups groups = loadPdpGroups("createGroups.json"); - PdpGroup newgrp = groups.getGroups().get(0); - PdpGroup group = new PdpGroup(newgrp); - when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); - - newgrp.getPdpSubgroups().get(0).getSupportedPolicyTypes() - .add(new ToscaPolicyTypeIdentifier("typeX.*", "9.8.7")); - - prov.createOrUpdateGroups(groups); - - assertEquals(newgrp.toString(), group.toString()); - assertGroupUpdateOnly(group); - } - - @Test - public void testUpdateSubGroup_DesiredCount() throws Exception { - PdpGroups groups = loadPdpGroups("createGroups.json"); - PdpGroup newgrp = groups.getGroups().get(0); - PdpGroup group = new PdpGroup(newgrp); - when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); - - newgrp.getPdpSubgroups().get(0).setDesiredInstanceCount(20); - - prov.createOrUpdateGroups(groups); - - assertEquals(newgrp.toString(), group.toString()); - assertGroupUpdateOnly(group); - } - - @Test - public void testUpdateSubGroup_Policies() throws Exception { - PdpGroups groups = loadPdpGroups("createGroupsDelPolicy.json"); - PdpGroup newgrp = groups.getGroups().get(0); - PdpGroup group = new PdpGroup(newgrp); - when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); - - PdpSubGroup subgrp = newgrp.getPdpSubgroups().get(0); - - // delete second policy - subgrp.setPolicies(subgrp.getPolicies().subList(0, 1)); - - // add new policy - ToscaPolicyIdentifier policyId2 = new ToscaPolicyIdentifier(POLICY2_NAME, POLICY1_VERSION); - subgrp.getPolicies().add(policyId2); - - when(dao.getFilteredPolicyList(any())).thenReturn(loadPolicies("createGroupNewPolicy.json")) - .thenReturn(loadPolicies("daoPolicyList.json")) - .thenReturn(loadPolicies("daoPolicyListDelPolicy.json")) - .thenReturn(loadPolicies("createGroupNewPolicy.json")); - - prov.createOrUpdateGroups(groups); - - Collections.sort(newgrp.getPdpSubgroups().get(0).getPolicies()); - Collections.sort(group.getPdpSubgroups().get(0).getPolicies()); - - assertEquals(newgrp.toString(), group.toString()); - - // should have notified of added policy/PDPs - ArgumentCaptor captor = ArgumentCaptor.forClass(PolicyPdpNotificationData.class); - verify(notifier).addDeploymentData(captor.capture()); - assertDeploymentData(captor, policyId2, "[pdpA]"); - - // should have notified of deleted policy/PDPs - captor = ArgumentCaptor.forClass(PolicyPdpNotificationData.class); - verify(notifier).addUndeploymentData(captor.capture()); - assertDeploymentData(captor, new ToscaPolicyIdentifier("ToBeDeleted", POLICY1_VERSION), "[pdpA]"); - - // this requires a PDP UPDATE message - assertGroupUpdate(group, subgrp); - } - - @Test - public void testUpdateSubGroup_Unchanged() throws Exception { - PdpGroups groups = loadPdpGroups("createGroups.json"); - PdpGroup newgrp = groups.getGroups().get(0); - PdpGroup group = new PdpGroup(newgrp); - when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); - - prov.createOrUpdateGroups(groups); - - Collections.sort(newgrp.getPdpSubgroups().get(0).getPolicies()); - Collections.sort(group.getPdpSubgroups().get(0).getPolicies()); - - assertEquals(newgrp.toString(), group.toString()); - - // no notifications - verify(notifier, never()).addDeploymentData(any()); - verify(notifier, never()).addUndeploymentData(any()); - - // no group updates - assertNoGroupAction(); - } - - @Test - public void testUpdateSubGroup_PolicyVersionMismatch() throws Exception { - PdpGroups groups = loadPdpGroups("createGroups.json"); - PdpGroup newgrp = groups.getGroups().get(0); - PdpGroup dbgroup = new PdpGroup(newgrp); - when(dao.getPdpGroups(dbgroup.getName())).thenReturn(Arrays.asList(dbgroup)); - - // arrange for DB policy version to be different - PdpSubGroup dbsubgrp = dbgroup.getPdpSubgroups().get(0); - dbsubgrp.getPolicies().get(0).setVersion("9.9.9"); - - when(dao.getFilteredPolicyList(any())).thenReturn(loadPolicies("daoPolicyList.json")); - - assertThatThrownBy(() -> prov.createOrUpdateGroups(groups)).isInstanceOf(PfModelException.class) - .hasMessageContaining("different version already deployed"); - - assertNoGroupAction(); - } - - @Test - public void testValidateSubGroup_PropertiesMismatch() throws Exception { - PdpGroups groups = loadPdpGroups("createGroups.json"); - PdpGroup newgrp = groups.getGroups().get(0); - PdpGroup group = new PdpGroup(newgrp); - when(dao.getPdpGroups(group.getName())).thenReturn(Arrays.asList(group)); - - newgrp.setProperties(new TreeMap<>()); - - assertThatThrownBy(() -> prov.createOrUpdateGroups(groups)).isInstanceOf(PfModelException.class) - .hasMessageContaining("properties"); - - assertNoGroupAction(); - } - - @Test - public void testDeployPolicies() throws PfModelException { - prov.deployPolicies(loadEmptyRequest()); - } - - /** - * Tests deployPolicies() when the supported policy type uses a wild-card. - * - * @throws Exception if an error occurs - */ - @Test - public void testDeployPoliciesWildCard() throws Exception { - when(dao.getFilteredPdpGroups(any())).thenReturn(loadGroups("deployPoliciesWildCard.json")); - when(dao.getFilteredPolicyList(any())).thenReturn(loadPolicies("daoPolicyListWildCard.json")); - when(dao.getPolicyTypeList(any(), any())).thenReturn(Collections.emptyList()); - - policy1.setName("policy.some"); - policy1.setVersion(POLICY1_VERSION); - policy1.setType("some.type"); - policy1.setTypeVersion("100.2.3"); - - PdpDeployPolicies depreq = loadRequest(); - depreq.getPolicies().get(0).setName("policy.some"); - - prov.deployPolicies(depreq); - - assertGroup(getGroupUpdates(), GROUP1_NAME); - - List requests = getUpdateRequests(1); - assertUpdate(requests, GROUP1_NAME, PDP2_TYPE, PDP2); - - // should have notified of added policy/PDPs - ArgumentCaptor captor = ArgumentCaptor.forClass(PolicyPdpNotificationData.class); - verify(notifier).addDeploymentData(captor.capture()); - assertDeploymentData(captor, policy1.getIdentifier(), "[pdpB]"); - - // no undeployment notifications - verify(notifier, never()).addUndeploymentData(any()); - } - - @Test - public void testDeploySimplePolicies() throws Exception { - prov.deployPolicies(loadEmptyRequest()); - } - - @Test - public void testDeploySimplePolicies_DaoEx() throws Exception { - PfModelException exc = new PfModelException(Status.BAD_REQUEST, EXPECTED_EXCEPTION); - when(dao.getFilteredPdpGroups(any())).thenThrow(exc); - - assertThatThrownBy(() -> prov.deployPolicies(loadRequest())).isSameAs(exc); - } - - @Test - public void testDeploySimplePolicies_DaoPfRtEx() throws Exception { - PfModelRuntimeException exc = new PfModelRuntimeException(Status.BAD_REQUEST, EXPECTED_EXCEPTION); - when(dao.getFilteredPdpGroups(any())).thenThrow(exc); - - assertThatThrownBy(() -> prov.deployPolicies(loadRequest())).isSameAs(exc); - } - - @Test - public void testDeploySimplePolicies_RuntimeEx() throws Exception { - RuntimeException exc = new RuntimeException(EXPECTED_EXCEPTION); - when(dao.getFilteredPolicyList(any())).thenThrow(exc); - - assertThatThrownBy(() -> prov.deployPolicies(loadRequest())).isInstanceOf(PfModelException.class).hasCause(exc); - } - - @Test - public void testDeploySimplePolicies_NoGroups() throws Exception { - when(dao.getFilteredPdpGroups(any())).thenReturn(loadGroups("emptyGroups.json")); - - assertThatThrownBy(() -> prov.deployPolicies(loadRequest())).isInstanceOf(PfModelException.class) - .hasMessage("policy not supported by any PDP group: policyA 1.2.3"); - } - - @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")); - - prov.deployPolicies(loadRequest()); - - assertGroup(getGroupUpdates(), GROUP1_NAME); - - List requests = getUpdateRequests(2); - assertUpdate(requests, GROUP1_NAME, PDP2_TYPE, PDP2); - assertUpdate(requests, GROUP1_NAME, PDP4_TYPE, PDP4); - - // should have notified of added policy/PDPs - ArgumentCaptor captor = ArgumentCaptor.forClass(PolicyPdpNotificationData.class); - verify(notifier).addDeploymentData(captor.capture()); - assertDeploymentData(captor, policy1.getIdentifier(), "[pdpB, pdpD]"); - - // no undeployment notifications - verify(notifier, never()).addUndeploymentData(any()); - } - - @Test - public void testMakeUpdater_PolicyVersionMismatch() throws Exception { - - // subgroup has a different version of the Policy - when(dao.getFilteredPdpGroups(any())).thenReturn(loadGroups("upgradeGroupDao_DiffVers.json")); - - assertThatThrownBy(() -> prov.deployPolicies(loadRequest())).isInstanceOf(PfModelRuntimeException.class) - .hasMessageContaining("pdpTypeC").hasMessageContaining("different version already deployed"); - - verify(dao, never()).createPdpGroups(any()); - verify(dao, never()).updatePdpGroups(any()); - verify(reqmap, never()).addRequest(any(PdpUpdate.class)); - } - - @Test - public void testMakeUpdater_NoPdps() throws Exception { - - // subgroup has no PDPs - when(dao.getFilteredPdpGroups(any())).thenReturn(loadGroups("upgradeGroup_NoPdpsDao.json")); - - assertThatThrownBy(() -> prov.deployPolicies(loadRequest())).isInstanceOf(PfModelRuntimeException.class) - .hasMessage("group " + GROUP1_NAME + " subgroup " + PDP1_TYPE + " has no active PDPs"); - - verify(dao, never()).createPdpGroups(any()); - verify(dao, never()).updatePdpGroups(any()); - verify(reqmap, never()).addRequest(any(PdpUpdate.class)); - } - - - protected void assertUpdate(List 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)); - } - - private void assertNoGroupAction() throws Exception { - verify(dao, never()).createPdpGroups(any()); - verify(dao, never()).updatePdpGroups(any()); - verify(reqmap, never()).addRequest(any(), any()); - } - - private void assertGroupUpdate(PdpGroup group, PdpSubGroup subgrp) throws Exception { - verify(dao, never()).createPdpGroups(any()); - - assertEquals(0, getStateChangeRequests(1).size()); - - List pdpUpdates = getUpdateRequests(1); - assertEquals(1, pdpUpdates.size()); - - PdpUpdate pdpUpdate = pdpUpdates.get(0); - assertEquals("pdpA", pdpUpdate.getName()); - assertEquals(group.getName(), pdpUpdate.getPdpGroup()); - - assertEquals(subgrp.getPdpType(), pdpUpdate.getPdpSubgroup()); - - List pdpPolicies = - pdpUpdate.getPolicies().stream().map(ToscaPolicy::getIdentifier).collect(Collectors.toList()); - Collections.sort(pdpPolicies); - - assertEquals(subgrp.getPolicies().toString(), pdpPolicies.toString()); - - List updates = getGroupUpdates(); - assertEquals(Arrays.asList(group), updates); - } - - private void assertGroupUpdateOnly(PdpGroup group) throws Exception { - verify(dao, never()).createPdpGroups(any()); - verify(reqmap, never()).addRequest(any(), any()); - - List updates = getGroupUpdates(); - assertEquals(Arrays.asList(group), updates); - } - - private void assertDeploymentData(ArgumentCaptor captor, ToscaPolicyIdentifier policyId, - String expectedPdps) { - PolicyPdpNotificationData data = captor.getValue(); - assertEquals(policyId, data.getPolicyId()); - assertEquals(policy1.getTypeIdentifier(), data.getPolicyType()); - assertEquals(expectedPdps, new TreeSet<>(data.getPdps()).toString()); - } - - /** - * 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/TestPolicyUndeployerImpl.java b/main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestPolicyUndeployerImpl.java deleted file mode 100644 index 5ccb7714..00000000 --- a/main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestPolicyUndeployerImpl.java +++ /dev/null @@ -1,200 +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.depundep; - -import static org.junit.Assert.assertEquals; -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 java.util.Arrays; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; -import java.util.Set; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.Mock; -import org.onap.policy.common.utils.services.Registry; -import org.onap.policy.models.base.PfModelException; -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.tosca.authorative.concepts.ToscaPolicyIdentifier; - -public class TestPolicyUndeployerImpl extends ProviderSuper { - private static final String MY_GROUP = "my-group"; - private static final String MY_SUBGROUP = "my-subgroup"; - private static final String MY_SUBGROUP0 = "my-subgroup-0"; - private static final String PDP1 = "my-pdp-a"; - - @Mock - private SessionData session; - - @Captor - private ArgumentCaptor> pdpCaptor; - - private ToscaPolicyIdentifier ident1; - private ToscaPolicyIdentifier ident2; - private ToscaPolicyIdentifier ident3; - private ToscaPolicyIdentifier ident4; - private PdpGroup group; - private PdpSubGroup subgroup; - 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(); - - ident1 = new ToscaPolicyIdentifier("ident-a", "2.3.1"); - ident2 = new ToscaPolicyIdentifier("ident-b", "2.3.2"); - ident3 = new ToscaPolicyIdentifier("ident-c", "2.3.3"); - ident4 = new ToscaPolicyIdentifier("ident-d", "2.3.4"); - - group = new PdpGroup(); - group.setName(MY_GROUP); - - subgroup = new PdpSubGroup(); - subgroup.setPdpType(MY_SUBGROUP); - - Pdp pdp1 = new Pdp(); - pdp1.setInstanceId(PDP1); - - subgroup.setPdpInstances(Arrays.asList(pdp1)); - - // this subgroup should never be touched - PdpSubGroup subgroup0 = new PdpSubGroup(); - subgroup0.setPdpType(MY_SUBGROUP0); - subgroup0.setPolicies(Collections.unmodifiableList(Arrays.asList(ident1, ident2, ident3, ident4))); - subgroup.setPdpInstances(Arrays.asList(pdp1)); - - group.setPdpSubgroups(Arrays.asList(subgroup0, subgroup)); - - when(session.getGroup(MY_GROUP)).thenReturn(group); - when(session.getPolicy(any())).thenReturn(policy1); - - prov = new MyProvider(); - } - - @Test - public void testUndeployPolicies() throws PfModelException { - subgroup.setPolicies(new LinkedList<>(Arrays.asList(ident1, ident2, ident3, ident4))); - - prov.undeploy(MY_GROUP, MY_SUBGROUP, Arrays.asList(ident1, ident2)); - - // group should have been updated - verify(session).update(group); - - // subgroup should only have remaining policies - assertEquals(Arrays.asList(ident3, ident4).toString(), subgroup.getPolicies().toString()); - - // should have generated PDP-UPDATE for the PDP - verify(session).addUpdate(any()); - } - - /** - * Tests undeployPolicies() when the policies do not exist in the subgroup. - */ - @Test - public void testUndeployPoliciesUnchanged() throws PfModelException { - List origlist = Arrays.asList(ident3, ident4); - subgroup.setPolicies(new LinkedList<>(origlist)); - - prov.undeploy(MY_GROUP, MY_SUBGROUP, Arrays.asList(ident1, ident2)); - - // group NOT should have been updated - verify(session, never()).update(group); - - // subgroup's policies should be unchanged - assertEquals(origlist.toString(), subgroup.getPolicies().toString()); - - // should NOT have generated PDP-UPDATE for the PDP - verify(session, never()).addUpdate(any()); - } - - /** - * Tests undeployPolicies() when the group is not found. - */ - @Test - public void testUndeployPoliciesGroupNotFound() throws PfModelException { - // force exception to be thrown if the list is changed - subgroup.setPolicies(Collections.unmodifiableList(Arrays.asList(ident1, ident2, ident3, ident4))); - - when(session.getGroup(any())).thenReturn(null); - - prov.undeploy(MY_GROUP, MY_SUBGROUP, Arrays.asList(ident1, ident2)); - - // group should have been updated - verify(session, never()).update(group); - - // should have generated PDP-UPDATE for the PDP - verify(session, never()).addUpdate(any()); - } - - /** - * Tests undeployPolicies() when the subgroup is not found. - */ - @Test - public void testUndeployPoliciesSubGroupNotFound() throws PfModelException { - // force exception to be thrown if the list is changed - subgroup.setPolicies(Collections.unmodifiableList(Arrays.asList(ident1, ident2, ident3, ident4))); - - subgroup.setPdpType(MY_SUBGROUP + "X"); - - prov.undeploy(MY_GROUP, MY_SUBGROUP, Arrays.asList(ident1, ident2)); - - // group should have been updated - verify(session, never()).update(group); - - // should have generated PDP-UPDATE for the PDP - verify(session, never()).addUpdate(any()); - } - - @Test(expected = UnsupportedOperationException.class) - public void testMakeUpdater() { - prov.makeUpdater(null, null, null); - } - - - private class MyProvider extends PolicyUndeployerImpl { - - @Override - protected void process(T request, BiConsumerWithEx processor) throws PfModelException { - processor.accept(session, request); - } - } -} 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 deleted file mode 100644 index 9370a7bd..00000000 --- a/main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestProviderBase.java +++ /dev/null @@ -1,392 +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.depundep; - -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.Arrays; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; -import java.util.Queue; -import java.util.TreeSet; -import javax.ws.rs.core.Response.Status; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.onap.policy.common.utils.services.Registry; -import org.onap.policy.models.base.PfModelException; -import org.onap.policy.models.base.PfModelRuntimeException; -import org.onap.policy.models.pap.concepts.PdpDeployPolicies; -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.ToscaPolicyIdentifierOptVersion; -import org.onap.policy.pap.main.notification.PolicyPdpNotificationData; -import org.powermock.reflect.Whitebox; - -public class TestProviderBase extends ProviderSuper { - private static final String EXPECTED_EXCEPTION = "expected exception"; - - 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 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.getFilteredPolicyList(any())).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 { - prov.process(loadRequest(), this::handle); - - assertGroup(getGroupUpdates(), GROUP1_NAME); - - assertUpdate(getUpdateRequests(1), GROUP1_NAME, PDP1_TYPE, PDP1); - - ArgumentCaptor captor = ArgumentCaptor.forClass(PolicyPdpNotificationData.class); - verify(notifier, times(2)).addDeploymentData(captor.capture()); - assertNotifier(captor, PDP1, PDP3); - - captor = ArgumentCaptor.forClass(PolicyPdpNotificationData.class); - verify(notifier, times(2)).addUndeploymentData(captor.capture()); - assertNotifier(captor, PDP2, PDP4); - } - - private void assertNotifier(ArgumentCaptor captor, String firstPdp, String secondPdp) { - assertEquals(1, captor.getAllValues().get(0).getPdps().size()); - assertEquals(1, captor.getAllValues().get(1).getPdps().size()); - - // ensure the order by using a TreeSet - TreeSet pdps = new TreeSet<>(captor.getAllValues().get(0).getPdps()); - pdps.addAll(captor.getAllValues().get(1).getPdps()); - assertEquals("[" + firstPdp + ", " + secondPdp + "]", pdps.toString()); - } - - @Test - public void testProcess_CreateEx() throws Exception { - PfModelException ex = new PfModelException(Status.BAD_REQUEST, EXPECTED_EXCEPTION); - when(daofact.create()).thenThrow(ex); - - assertThatThrownBy(() -> prov.process(loadEmptyRequest(), this::handle)).isSameAs(ex); - } - - @Test - public void testProcess_PfRtEx() throws Exception { - PfModelRuntimeException ex = new PfModelRuntimeException(Status.BAD_REQUEST, EXPECTED_EXCEPTION); - when(daofact.create()).thenThrow(ex); - - assertThatThrownBy(() -> prov.process(loadEmptyRequest(), this::handle)).isSameAs(ex); - } - - @Test - public void testProcess_RuntimeEx() throws Exception { - RuntimeException ex = new RuntimeException(EXPECTED_EXCEPTION); - when(daofact.create()).thenThrow(ex); - - assertThatThrownBy(() -> prov.process(loadEmptyRequest(), this::handle)).isInstanceOf(PfModelException.class) - .hasMessage("request failed").hasCause(ex); - } - - @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(PfModelException.class) - .hasMessage("policy not supported by any PDP group: policyA 1.2.3"); - - } - - @Test - public void testGetPolicy() throws Exception { - PfModelException exc = new PfModelException(Status.CONFLICT, EXPECTED_EXCEPTION); - when(dao.getFilteredPolicyList(any())).thenThrow(exc); - - assertThatThrownBy(() -> prov.process(loadRequest(), this::handle)).isInstanceOf(PfModelRuntimeException.class) - .hasCause(exc); - } - - @Test - public void testGetPolicy_NotFound() throws Exception { - when(dao.getFilteredPolicyList(any())).thenReturn(Collections.emptyList()); - - assertThatThrownBy(() -> prov.process(loadRequest(), this::handle)).isInstanceOf(PfModelRuntimeException.class) - .hasMessage("cannot find policy: policyA 1.2.3") - .extracting(ex -> ((PfModelRuntimeException) ex).getErrorResponse().getResponseCode()) - .isEqualTo(Status.NOT_FOUND); - } - - @Test - public void testGetGroup() throws Exception { - when(dao.getFilteredPdpGroups(any())).thenReturn(loadGroups("getGroupDao.json")) - .thenReturn(loadGroups("groups.json")); - - prov.process(loadRequest(), this::handle); - - assertGroup(getGroupUpdates(), GROUP1_NAME); - } - - @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); - - prov.process(loadRequest(), this::handle); - - assertGroup(getGroupUpdates(), GROUP1_NAME); - - List 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.getFilteredPolicyList(any())).thenReturn(loadPolicies("daoPolicyList.json")) - .thenReturn(loadPolicies("upgradeGroupPolicy2.json")) - .thenReturn(loadPolicies("upgradeGroupPolicy3.json")) - .thenReturn(loadPolicies("upgradeGroupPolicy4.json")); - - List groups1 = loadGroups("upgradeGroupGroup1.json"); - List 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); - - prov.process(request, (data, deploy) -> { - for (ToscaPolicyIdentifierOptVersion policy : deploy.getPolicies()) { - handle(data, policy); - } - }); - - // verify updates - List changes = getGroupUpdates(); - assertGroup(changes, GROUP1_NAME); - assertGroup(changes, GROUP2_NAME); - - List 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); - - prov.process(loadRequest(), this::handle); - - verify(dao, never()).createPdpGroups(any()); - verify(dao, never()).updatePdpGroups(any()); - verify(reqmap, never()).addRequest(any(PdpUpdate.class)); - } - - - protected void assertUpdate(List 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 - * @throws PfModelException if an error occurred - */ - private void handle(SessionData data, ToscaPolicyIdentifierOptVersion request) throws PfModelException { - prov.processPolicy(data, request); - } - - - private static class MyProvider extends ProviderBase { - /** - * 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 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 - protected Updater makeUpdater(SessionData data, ToscaPolicy policy, - ToscaPolicyIdentifierOptVersion desiredPolicy) { - - return (group, subgroup) -> { - if (shouldUpdate.remove()) { - // queue indicated that the update should succeed - subgroup.getPolicies().add(policy.getIdentifier()); - - data.trackDeploy(policy.getIdentifier(), Collections.singleton(PDP1)); - data.trackUndeploy(policy.getIdentifier(), Collections.singleton(PDP2)); - - ToscaPolicyIdentifier ident2 = new ToscaPolicyIdentifier(POLICY1_NAME, "9.9.9"); - data.trackDeploy(ident2, Collections.singleton(PDP3)); - data.trackUndeploy(ident2, Collections.singleton(PDP4)); - return true; - - } else { - // queue indicated that no update should be made this time - return false; - } - }; - } - } -} 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 deleted file mode 100644 index 4d353a6e..00000000 --- a/main/src/test/java/org/onap/policy/pap/main/rest/depundep/TestSessionData.java +++ /dev/null @@ -1,662 +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.depundep; - -import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; -import static org.assertj.core.api.Assertions.assertThatIllegalStateException; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.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.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.Iterator; -import java.util.List; -import java.util.TreeSet; -import java.util.function.Supplier; -import javax.ws.rs.core.Response.Status; -import org.apache.commons.lang3.tuple.Pair; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.onap.policy.models.base.PfModelException; -import org.onap.policy.models.pdp.concepts.PdpGroup; -import org.onap.policy.models.pdp.concepts.PdpStateChange; -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.ToscaPolicyFilter; -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.ToscaPolicyType; -import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyTypeIdentifier; -import org.onap.policy.pap.main.notification.PolicyPdpNotificationData; - -public class TestSessionData extends ProviderSuper { - private static final String GROUP_NAME = "groupA"; - 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_TYPE = "myType"; - private static final String POLICY_TYPE_VERSION = "10.20.30"; - private static final String EXPECTED_EXCEPTION = "expected exception"; - - private SessionData session; - private ToscaPolicyIdentifierOptVersion ident; - private ToscaPolicyTypeIdentifier type; - private ToscaPolicyTypeIdentifier type2; - private PdpGroup group1; - private PdpGroup group2; - - /** - * Initializes mocks and a session. - * - * @throws Exception if an error occurs - */ - @Before - public void setUp() throws Exception { - super.setUp(); - - ident = new ToscaPolicyIdentifierOptVersion(POLICY_NAME, POLICY_VERSION); - type = new ToscaPolicyTypeIdentifier(POLICY_TYPE, POLICY_TYPE_VERSION); - type2 = new ToscaPolicyTypeIdentifier(POLICY_TYPE, POLICY_TYPE_VERSION + "0"); - group1 = loadGroup("group1.json"); - group2 = loadGroup("group2.json"); - - session = new SessionData(dao); - } - - @Test - public void testGetPolicyType() throws Exception { - ToscaPolicyType policy1 = makePolicyType(POLICY_TYPE, POLICY_TYPE_VERSION); - when(dao.getPolicyTypeList(POLICY_TYPE, POLICY_TYPE_VERSION)).thenReturn(Arrays.asList(policy1)); - - assertSame(policy1, session.getPolicyType(type)); - - // retrieve a second time - should use cache - assertSame(policy1, session.getPolicyType(type)); - } - - @Test - public void testGetPolicyType_NotFound() throws Exception { - when(dao.getPolicyTypeList(any(), any())).thenReturn(Collections.emptyList()); - - assertNull(session.getPolicyType(type)); - } - - @Test - public void testGetPolicyType_DaoEx() throws Exception { - PfModelException ex = new PfModelException(Status.INTERNAL_SERVER_ERROR, EXPECTED_EXCEPTION); - when(dao.getPolicyTypeList(POLICY_TYPE, POLICY_TYPE_VERSION)).thenThrow(ex); - - assertThatThrownBy(() -> session.getPolicyType(type)).isSameAs(ex); - } - - @Test - public void testGetPolicy_NullVersion() throws Exception { - ToscaPolicy policy1 = makePolicy(POLICY_NAME, POLICY_VERSION); - when(dao.getFilteredPolicyList(any())).thenReturn(Arrays.asList(policy1)); - - ident.setVersion(null); - assertSame(policy1, session.getPolicy(ident)); - - ToscaPolicyFilter filter = getPolicyFilter(); - assertEquals(POLICY_NAME, filter.getName()); - assertEquals(ToscaPolicyFilter.LATEST_VERSION, filter.getVersion()); - assertEquals(null, filter.getVersionPrefix()); - - // retrieve a second time using full version - should use cache - assertSame(policy1, session.getPolicy(new ToscaPolicyIdentifierOptVersion(policy1.getIdentifier()))); - verify(dao).getFilteredPolicyList(any()); - } - - @Test - public void testGetPolicy_MajorVersion() throws Exception { - ToscaPolicy policy1 = makePolicy(POLICY_NAME, POLICY_VERSION); - when(dao.getFilteredPolicyList(any())).thenReturn(Arrays.asList(policy1)); - - ident.setVersion("1"); - assertSame(policy1, session.getPolicy(ident)); - - ToscaPolicyFilter filter = getPolicyFilter(); - assertEquals(POLICY_NAME, filter.getName()); - assertEquals(ToscaPolicyFilter.LATEST_VERSION, filter.getVersion()); - assertEquals("1.", filter.getVersionPrefix()); - - // retrieve a second time using full version - should use cache - assertSame(policy1, session.getPolicy(new ToscaPolicyIdentifierOptVersion(policy1.getIdentifier()))); - verify(dao).getFilteredPolicyList(any()); - } - - @Test - public void testGetPolicy_MajorMinorVersion() throws Exception { - ToscaPolicy policy1 = makePolicy(POLICY_NAME, POLICY_VERSION); - when(dao.getFilteredPolicyList(any())).thenReturn(Arrays.asList(policy1)); - - ident.setVersion(POLICY_VERSION); - assertSame(policy1, session.getPolicy(ident)); - - ToscaPolicyFilter filter = getPolicyFilter(); - assertEquals(POLICY_NAME, filter.getName()); - assertEquals(POLICY_VERSION, filter.getVersion()); - assertEquals(null, filter.getVersionPrefix()); - - // retrieve a second time using full version - should use cache - assertSame(policy1, session.getPolicy(new ToscaPolicyIdentifierOptVersion(policy1.getIdentifier()))); - verify(dao).getFilteredPolicyList(any()); - } - - @Test - public void testGetPolicy_NotFound() throws Exception { - when(dao.getFilteredPolicyList(any())).thenReturn(Collections.emptyList()); - - assertNull(session.getPolicy(ident)); - } - - @Test - public void testGetPolicy_DaoEx() throws Exception { - PfModelException ex = new PfModelException(Status.INTERNAL_SERVER_ERROR, EXPECTED_EXCEPTION); - when(dao.getFilteredPolicyList(any())).thenThrow(ex); - - assertThatThrownBy(() -> session.getPolicy(ident)).isSameAs(ex); - } - - @Test - public void testIsVersionPrefix() { - assertTrue(SessionData.isVersionPrefix("1")); - assertTrue(SessionData.isVersionPrefix("12")); - assertTrue(SessionData.isVersionPrefix("1.2")); - assertTrue(SessionData.isVersionPrefix("1.23")); - - assertFalse(SessionData.isVersionPrefix("1.")); - assertFalse(SessionData.isVersionPrefix("1.2.")); - assertFalse(SessionData.isVersionPrefix("1.2.3")); - assertFalse(SessionData.isVersionPrefix("1.2.3.")); - assertFalse(SessionData.isVersionPrefix("1.2.3.4")); - } - - @Test - public void testAddRequests_testGetPdpStateChanges_testGetPdpUpdates() { - // pre-load with a update and state-change for other PDPs - PdpUpdate update2 = makeUpdate(PDP2); - session.addUpdate(update2); - - PdpStateChange change3 = makeStateChange(PDP3); - session.addStateChange(change3); - - // add requests - PdpUpdate update = makeUpdate(PDP1); - PdpStateChange change = makeStateChange(PDP1); - session.addRequests(update, change); - verifyRequests(update, update2, change, change3); - - /* - * repeat with a new pair - */ - update = makeUpdate(PDP1); - change = makeStateChange(PDP1); - session.addRequests(update, change); - verifyRequests(update, update2, change, change3); - - // just make an update this time - update = makeUpdate(PDP1); - session.addUpdate(update); - verifyRequests(update, update2, change, change3); - } - - private void verifyRequests(PdpUpdate update, PdpUpdate update2, PdpStateChange change, PdpStateChange change3) { - List> requests = sort(session.getPdpRequests(), this::compare); - assertEquals(3, requests.size()); - - System.out.println(requests); - System.out.println(update); - - Iterator> reqiter = requests.iterator(); - Pair pair = reqiter.next(); - assertSame(update, pair.getLeft()); - assertSame(change, pair.getRight()); - - pair = reqiter.next(); - assertSame(update2, pair.getLeft()); - assertSame(null, pair.getRight()); - - pair = reqiter.next(); - assertSame(null, pair.getLeft()); - assertSame(change3, pair.getRight()); - - // verify individual lists - List updates = Arrays.asList(update, update2); - assertEquals(sort(updates, this::compare), sort(session.getPdpUpdates(), this::compare)); - - List changes = Arrays.asList(change, change3); - assertEquals(sort(changes, this::compare), sort(session.getPdpStateChanges(), this::compare)); - } - - @Test - public void testAddRequests_MismatchedNames() { - PdpUpdate update = makeUpdate(PDP1); - PdpStateChange change = makeStateChange(PDP2); - assertThatIllegalArgumentException().isThrownBy(() -> session.addRequests(update, change)) - .withMessage("PDP name mismatch pdp_1, pdp_2"); - } - - @Test - public void testAddUpdate_testGetPdpUpdates() { - // 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 lst = sort(getUpdateRequests(), this::compare); - assertEquals(Arrays.asList(update1, update2, update3).toString(), lst.toString()); - - // overwrite one - update2 = makeUpdate(PDP2); - session.addUpdate(update2); - - lst = sort(getUpdateRequests(), this::compare); - assertEquals(Arrays.asList(update1, update2, update3).toString(), lst.toString()); - } - - @Test - public void testAddStateChange_testGetPdpStateChanges() { - // several different changes, but one duplicate - PdpStateChange change1 = makeStateChange(PDP1); - session.addStateChange(change1); - - PdpStateChange change2 = makeStateChange(PDP2); - session.addStateChange(change2); - - PdpStateChange change3 = makeStateChange(PDP3); - session.addStateChange(change3); - - List lst = sort(getStateChangeRequests(), this::compare); - assertEquals(Arrays.asList(change1, change2, change3).toString(), lst.toString()); - - // overwrite one - change2 = makeStateChange(PDP2); - session.addStateChange(change2); - - lst = sort(getStateChangeRequests(), this::compare); - assertEquals(Arrays.asList(change1, change2, change3).toString(), lst.toString()); - } - - private ToscaPolicyType makePolicyType(String name, String version) { - ToscaPolicyType type = new ToscaPolicyType(); - - type.setName(name); - type.setVersion(version); - - return type; - } - - private ToscaPolicy makePolicy(String name, String version) { - ToscaPolicy policy = new ToscaPolicy(); - - policy.setName(name); - policy.setVersion(version); - - return policy; - } - - @Test - public void testCreate() throws Exception { - assertTrue(session.isUnchanged()); - - session.create(group1); - assertSame(group1, session.getGroup(group1.getName())); - assertFalse(session.isUnchanged()); - - // can add another - session.create(group2); - assertSame(group1, session.getGroup(group1.getName())); - assertSame(group2, session.getGroup(group2.getName())); - assertFalse(session.isUnchanged()); - - // cannot overwrite - assertThatIllegalStateException().isThrownBy(() -> session.create(group1)) - .withMessage("group already cached: groupA"); - } - - @Test - public void testUpdate() throws Exception { - assertTrue(session.isUnchanged()); - - // force the groups into the cache - when(dao.getFilteredPdpGroups(any())).thenReturn(Arrays.asList(group1, group2)); - session.getActivePdpGroupsByPolicyType(type); - - /* - * try group 1 - */ - when(dao.getFilteredPdpGroups(any())).thenReturn(Arrays.asList(group1)); - PdpGroup newgrp = new PdpGroup(group1); - session.update(newgrp); - assertFalse(session.isUnchanged()); - - // repeat - newgrp = new PdpGroup(group1); - session.update(newgrp); - assertFalse(session.isUnchanged()); - - /* - * try group 2 - */ - when(dao.getFilteredPdpGroups(any())).thenReturn(Arrays.asList(group2)); - newgrp = new PdpGroup(group2); - session.update(newgrp); - assertFalse(session.isUnchanged()); - - // repeat - newgrp = new PdpGroup(group2); - session.update(newgrp); - assertFalse(session.isUnchanged()); - } - - @Test - public void testUpdate_NotInCache() throws Exception { - when(dao.getFilteredPdpGroups(any())).thenReturn(Arrays.asList(group1)); - - assertThatIllegalStateException().isThrownBy(() -> session.update(new PdpGroup(group1))) - .withMessage("group not cached: groupA"); - } - - @Test - public void testGetGroup() throws Exception { - when(dao.getPdpGroups(GROUP_NAME)).thenReturn(Arrays.asList(group1)); - - assertSame(group1, session.getGroup(GROUP_NAME)); - verify(dao).getPdpGroups(any()); - - // repeat - assertSame(group1, session.getGroup(GROUP_NAME)); - - // should not access dao again - verify(dao, times(1)).getPdpGroups(any()); - } - - @Test - public void testGetGroup_NotFound() throws Exception { - when(dao.getPdpGroups(GROUP_NAME)).thenReturn(Collections.emptyList()); - - assertNull(session.getGroup(GROUP_NAME)); - verify(dao).getPdpGroups(any()); - - // repeat - assertNull(session.getGroup(GROUP_NAME)); - - // SHOULD access dao again - verify(dao, times(2)).getPdpGroups(GROUP_NAME); - - // find it this time - when(dao.getPdpGroups(GROUP_NAME)).thenReturn(Arrays.asList(group1)); - assertSame(group1, session.getGroup(GROUP_NAME)); - verify(dao, times(3)).getPdpGroups(GROUP_NAME); - } - - @Test - public void testGetGroup_DaoEx() throws Exception { - PfModelException ex = new PfModelException(Status.BAD_REQUEST, EXPECTED_EXCEPTION); - when(dao.getPdpGroups(GROUP_NAME)).thenThrow(ex); - - assertThatThrownBy(() -> session.getGroup(GROUP_NAME)).isSameAs(ex); - } - - @Test - public void testGetActivePdpGroupsByPolicyType() throws Exception { - List groups = Arrays.asList(group1, group2); - when(dao.getFilteredPdpGroups(any())).thenReturn(groups); - - // repeat - assertEquals(groups, session.getActivePdpGroupsByPolicyType(type)); - assertEquals(groups, session.getActivePdpGroupsByPolicyType(type)); - assertEquals(groups, session.getActivePdpGroupsByPolicyType(type)); - - // only invoked once - should have used the cache for the rest - verify(dao, times(1)).getFilteredPdpGroups(any()); - } - - @Test - public void testAddGroup() throws Exception { - List groups = Arrays.asList(group1, group2); - when(dao.getFilteredPdpGroups(any())).thenReturn(groups); - - // query by each type - assertEquals(groups, session.getActivePdpGroupsByPolicyType(type)); - assertEquals(groups, session.getActivePdpGroupsByPolicyType(type2)); - - // invoked once for each type - verify(dao, times(2)).getFilteredPdpGroups(any()); - - // repeat - should be no more invocations - assertEquals(groups, session.getActivePdpGroupsByPolicyType(type)); - assertEquals(groups, session.getActivePdpGroupsByPolicyType(type2)); - verify(dao, times(2)).getFilteredPdpGroups(any()); - } - - @Test - public void testUpdateDb() throws Exception { - // force the groups into the cache - PdpGroup group3 = loadGroup("group3.json"); - when(dao.getFilteredPdpGroups(any())).thenReturn(Arrays.asList(group1, group2, group3)); - session.getActivePdpGroupsByPolicyType(type); - - // create groups 4 & 5 - PdpGroup group4 = loadGroup("group4.json"); - session.create(group4); - - PdpGroup group5 = loadGroup("group5.json"); - session.create(group5); - - // update group 1 - when(dao.getFilteredPdpGroups(any())).thenReturn(Arrays.asList(group1)); - PdpGroup newgrp1 = new PdpGroup(group1); - session.update(newgrp1); - - // another update - newgrp1 = new PdpGroup(newgrp1); - session.update(newgrp1); - - // update group 3 - when(dao.getFilteredPdpGroups(any())).thenReturn(Arrays.asList(group3)); - PdpGroup newgrp3 = new PdpGroup(group3); - session.update(newgrp3); - - // update group 5 - when(dao.getFilteredPdpGroups(any())).thenReturn(Arrays.asList(group5)); - PdpGroup newgrp5 = new PdpGroup(group5); - session.update(newgrp5); - - // push the changes to the DB - session.updateDb(); - - // expect one create for groups 4 & 5 (group5 replaced by newgrp5) - List creates = getGroupCreates(); - assertEquals(2, creates.size()); - assertSame(group4, creates.get(0)); - assertSame(newgrp5, creates.get(1)); - - // expect one update for groups 1 & 3 - List updates = getGroupUpdates(); - assertEquals(2, updates.size()); - assertSame(newgrp1, updates.get(0)); - assertSame(newgrp3, updates.get(1)); - } - - @Test - public void testUpdateDb_Empty() throws Exception { - // force data into the cache - when(dao.getFilteredPdpGroups(any())).thenReturn(Arrays.asList(group1, group2)); - session.getActivePdpGroupsByPolicyType(type); - - session.updateDb(); - verify(dao, never()).createPdpGroups(any()); - verify(dao, never()).updatePdpGroups(any()); - } - - @Test - public void testDeleteGroupFromDb() throws Exception { - session.deleteGroupFromDb(group1); - - verify(dao).deletePdpGroup(group1.getName()); - } - - @Test - public void testTrackDeploy() throws PfModelException { - testTrack(session::getDeployData, session::getUndeployData, session::trackDeploy); - } - - /** - * Tests trackDeploy() when there is something in the undeployed list. - * - * @throws PfModelException if an error occurs - */ - @Test - public void testTrackDeployRemoveUndeploy() throws PfModelException { - testTrack(session::getDeployData, session::getUndeployData, session::trackUndeploy, session::trackDeploy); - } - - @Test - public void testTrackUndeploy() throws PfModelException { - testTrack(session::getUndeployData, session::getDeployData, session::trackUndeploy); - } - - /** - * Tests trackUndeploy() when there is something in the deployed list. - * - * @throws PfModelException if an error occurs - */ - @Test - public void testTrackUndeployRemoveUndeploy() throws PfModelException { - testTrack(session::getUndeployData, session::getDeployData, session::trackDeploy, session::trackUndeploy); - } - - protected void testTrack(Supplier> expected, - Supplier> unexpected, TrackEx... trackFuncs) - throws PfModelException { - - ToscaPolicy policy = makePolicy(POLICY_NAME, POLICY_VERSION); - policy.setType(POLICY_TYPE); - policy.setTypeVersion(POLICY_TYPE_VERSION); - - when(dao.getFilteredPolicyList(any())).thenReturn(Arrays.asList(policy)); - - ToscaPolicyIdentifier policyId = new ToscaPolicyIdentifier(POLICY_NAME, POLICY_VERSION); - List pdps = Arrays.asList(PDP1, PDP2); - - for (TrackEx trackFunc : trackFuncs) { - trackFunc.accept(policyId, pdps); - } - - // "unexpected" list should be empty of any PDPs - Collection dataList = unexpected.get(); - assertTrue(dataList.size() <= 1); - if (!dataList.isEmpty()) { - PolicyPdpNotificationData data = dataList.iterator().next(); - assertTrue(data.getPdps().isEmpty()); - } - - dataList = expected.get(); - assertEquals(1, dataList.size()); - - PolicyPdpNotificationData data = dataList.iterator().next(); - assertEquals(policyId, data.getPolicyId()); - assertEquals(type, data.getPolicyType()); - assertEquals("[pdp_1, pdp_2]", new TreeSet<>(data.getPdps()).toString()); - } - - private PdpUpdate makeUpdate(String pdpName) { - PdpUpdate update = new PdpUpdate(); - - update.setName(pdpName); - - return update; - } - - private PdpStateChange makeStateChange(String pdpName) { - PdpStateChange change = new PdpStateChange(); - - change.setName(pdpName); - - return change; - } - - private ToscaPolicyFilter getPolicyFilter() throws Exception { - ArgumentCaptor captor = ArgumentCaptor.forClass(ToscaPolicyFilter.class); - verify(dao).getFilteredPolicyList(captor.capture()); - - return captor.getValue(); - } - - private List getUpdateRequests() { - return session.getPdpUpdates(); - } - - private List getStateChangeRequests() { - return session.getPdpStateChanges(); - } - - private List sort(Collection collection, Comparator comparator) { - List lst = new ArrayList<>(collection); - Collections.sort(lst, comparator); - - return lst; - } - - private int compare(Pair left, Pair right) { - return getName(left).compareTo(getName(right)); - } - - private int compare(PdpUpdate left, PdpUpdate right) { - return left.getName().compareTo(right.getName()); - } - - private int compare(PdpStateChange left, PdpStateChange right) { - return left.getName().compareTo(right.getName()); - } - - private String getName(Pair pair) { - return (pair.getKey() != null ? pair.getKey().getName() : pair.getValue().getName()); - } - - @FunctionalInterface - private static interface TrackEx { - public void accept(ToscaPolicyIdentifier policyId, Collection pdps) throws PfModelException; - } -} -- cgit 1.2.3-korg