From: a.sreekumar Date: Tue, 3 Dec 2019 19:10:47 +0000 (+0000) Subject: Create PAP API to only create/update PdpGroups X-Git-Tag: 2.2.0~35^2 X-Git-Url: https://gerrit.onap.org/r/gitweb?a=commitdiff_plain;h=def5a9d47a1b512f65917babd6613e2b743ad8da;p=policy%2Fpap.git Create PAP API to only create/update PdpGroups Create an API to create/update PdpGroups. Policies are not allowed to be deployed as part of PDPGroup create/update operation. There will be a separate API as part of POLICY-2274 to deploy policies into individual group/subgroups. Change-Id: I4e2cb43fefe08b22d6f70a1db7c026e83f0ebde0 Issue-ID: POLICY-2273 Signed-off-by: a.sreekumar --- diff --git a/main/src/main/java/org/onap/policy/pap/main/rest/PdpGroupCreateOrUpdateControllerV1.java b/main/src/main/java/org/onap/policy/pap/main/rest/PdpGroupCreateOrUpdateControllerV1.java new file mode 100644 index 00000000..9f72816d --- /dev/null +++ b/main/src/main/java/org/onap/policy/pap/main/rest/PdpGroupCreateOrUpdateControllerV1.java @@ -0,0 +1,113 @@ +/* + * ============LICENSE_START======================================================= + * ONAP PAP + * ================================================================================ + * Copyright (C) 2019 Nordix Foundation. + * ================================================================================ + * 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.PdpGroupUpdateResponse; +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 create or update PDP groups. + */ +public class PdpGroupCreateOrUpdateControllerV1 extends PapRestControllerV1 { + private static final Logger logger = LoggerFactory.getLogger(PdpGroupCreateOrUpdateControllerV1.class); + + private final PdpGroupCreateOrUpdateProvider provider = new PdpGroupCreateOrUpdateProvider(); + + /** + * Creates or updates one or more PDP groups. + * + * @param requestId request ID used in ONAP logging + * @param groups PDP group configuration + * @return a response + */ + // @formatter:off + @POST + @Path("pdps/groups/batch") + @ApiOperation(value = "Create or update PDP Groups", + notes = "Create or update one or more PDP Groups, returning optional error details", + response = PdpGroupUpdateResponse.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 createOrUpdateGroups( + @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)); + } + + /** + * 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 PdpGroupUpdateResponse} response entity + */ + private Response doOperation(UUID requestId, String errmsg, RunnableWithPfEx runnable) { + try { + runnable.run(); + return addLoggingHeaders(addVersionControlHeaders(Response.status(Status.OK)), requestId) + .entity(new PdpGroupUpdateResponse()).build(); + + } catch (PfModelException | PfModelRuntimeException e) { + logger.warn(errmsg, e); + PdpGroupUpdateResponse resp = new PdpGroupUpdateResponse(); + 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/PdpGroupCreateOrUpdateProvider.java b/main/src/main/java/org/onap/policy/pap/main/rest/PdpGroupCreateOrUpdateProvider.java new file mode 100644 index 00000000..aed05172 --- /dev/null +++ b/main/src/main/java/org/onap/policy/pap/main/rest/PdpGroupCreateOrUpdateProvider.java @@ -0,0 +1,459 @@ +/* + * ============LICENSE_START======================================================= + * ONAP PAP + * ================================================================================ + * Copyright (C) 2019 Nordix Foundation. + * ================================================================================ + * 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.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 create or update PDP groups. The following items must be in the + * {@link Registry}: + * + */ +public class PdpGroupCreateOrUpdateProvider extends ProviderBase { + private static final Logger logger = LoggerFactory.getLogger(PdpGroupCreateOrUpdateProvider.class); + + /** + * Constructs the object. + */ + public PdpGroupCreateOrUpdateProvider() { + 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); + } + // During PdpGroup create/update, policies are not supposed to be deployed/undeployed into the group. + // There is a separate API for this. + List subGroupsWithPolicies = + groups.getGroups().parallelStream().flatMap(group -> group.getPdpSubgroups().parallelStream()) + .filter(subGroup -> !subGroup.getPolicies().isEmpty()).collect(Collectors.toList()); + if (!subGroupsWithPolicies.isEmpty()) { + logger.warn( + "Policies cannot be deployed during PdpGroup Create/Update operation. Ignoring the list of policies"); + subGroupsWithPolicies.forEach(subGroup -> subGroup.setPolicies(Collections.emptyList())); + } + 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, 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)); + return result; + } + + /** + * Updates an existing subgroup. + * + * @param data session data + * @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, PdpSubGroup dbsub, PdpSubGroup subgrp, + BeanValidationResult container) throws PfModelException { + + // perform additional validations first + if (!validateSubGroup(data, dbsub, subgrp, container)) { + return false; + } + + boolean updated = updateList(dbsub.getSupportedPolicyTypes(), subgrp.getSupportedPolicyTypes(), + dbsub::setSupportedPolicyTypes); + + return updateField(dbsub.getDesiredInstanceCount(), subgrp.getDesiredInstanceCount(), + dbsub::setDesiredInstanceCount) || updated; + } + + /** + * 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(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; + } + + @Override + protected Updater makeUpdater(SessionData data, ToscaPolicy policy, ToscaPolicyIdentifierOptVersion desiredPolicy) { + throw new UnsupportedOperationException("makeUpdater should not be invoked"); + } +} 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 f784ed5e..1721cb0d 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,6 +50,7 @@ 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.PdpGroupCreateOrUpdateControllerV1; import org.onap.policy.pap.main.rest.PdpGroupDeleteControllerV1; import org.onap.policy.pap.main.rest.PdpGroupDeployControllerV1; import org.onap.policy.pap.main.rest.PdpGroupHealthCheckControllerV1; @@ -239,6 +240,7 @@ public class PapActivator extends ServiceManagerContainer { RestServer server = new RestServer(papParameterGroup.getRestServerParameters(), PapAafFilter.class, HealthCheckRestControllerV1.class, StatisticsRestControllerV1.class, + PdpGroupCreateOrUpdateControllerV1.class, PdpGroupDeployControllerV1.class, PdpGroupDeleteControllerV1.class, PdpGroupStateChangeControllerV1.class, diff --git a/main/src/test/java/org/onap/policy/pap/main/rest/TestPdpGroupCreateOrUpdateControllerV1.java b/main/src/test/java/org/onap/policy/pap/main/rest/TestPdpGroupCreateOrUpdateControllerV1.java new file mode 100644 index 00000000..31246416 --- /dev/null +++ b/main/src/test/java/org/onap/policy/pap/main/rest/TestPdpGroupCreateOrUpdateControllerV1.java @@ -0,0 +1,80 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2019 Nordix Foundation. + * ================================================================================ + * 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.PdpGroupUpdateResponse; +import org.onap.policy.models.pdp.concepts.PdpGroup; +import org.onap.policy.models.pdp.concepts.PdpGroups; +import org.onap.policy.models.pdp.concepts.PdpSubGroup; + +/** + * Note: this tests failure cases; success cases are tested by tests in the "e2e" package. + */ +public class TestPdpGroupCreateOrUpdateControllerV1 extends CommonPapRestServer { + + private static final String CREATEORUPDATE_GROUPS_ENDPOINT = "pdps/groups/batch"; + + @Test + public void testSwagger() throws Exception { + super.testSwagger(CREATEORUPDATE_GROUPS_ENDPOINT); + } + + @Test + public void testCreateOrUpdateGroups() throws Exception { + Entity entgrp = makePdpGroupsEntity(); + + Invocation.Builder invocationBuilder = sendRequest(CREATEORUPDATE_GROUPS_ENDPOINT); + Response rawresp = invocationBuilder.post(entgrp); + PdpGroupUpdateResponse resp = rawresp.readEntity(PdpGroupUpdateResponse.class); + assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), rawresp.getStatus()); + assertNotNull(resp.getErrorDetails()); + + rawresp = invocationBuilder.post(entgrp); + resp = rawresp.readEntity(PdpGroupUpdateResponse.class); + assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), rawresp.getStatus()); + assertNotNull(resp.getErrorDetails()); + + // verify it fails when no authorization info is included + checkUnauthRequest(CREATEORUPDATE_GROUPS_ENDPOINT, req -> req.post(entgrp)); + } + + private Entity makePdpGroupsEntity() { + PdpSubGroup subgrp = new PdpSubGroup(); + subgrp.setPdpType("drools"); + + PdpGroup group = new PdpGroup(); + group.setName("drools-group"); + group.setDescription("my description"); + group.setPdpSubgroups(Arrays.asList(subgrp)); + PdpGroups groups = new PdpGroups(); + groups.setGroups(Arrays.asList(group)); + return Entity.entity(groups, MediaType.APPLICATION_JSON); + } +} diff --git a/main/src/test/java/org/onap/policy/pap/main/rest/TestPdpGroupCreateOrUpdateProvider.java b/main/src/test/java/org/onap/policy/pap/main/rest/TestPdpGroupCreateOrUpdateProvider.java new file mode 100644 index 00000000..1ac97c77 --- /dev/null +++ b/main/src/test/java/org/onap/policy/pap/main/rest/TestPdpGroupCreateOrUpdateProvider.java @@ -0,0 +1,563 @@ +/* + * ============LICENSE_START======================================================= + * ONAP PAP + * ================================================================================ + * Copyright (C) 2019 Nordix Foundation. + * ================================================================================ + * 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 javax.ws.rs.core.Response.Status; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.Test; +import org.onap.policy.common.utils.services.Registry; +import org.onap.policy.models.base.PfModelException; +import org.onap.policy.models.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.ToscaPolicyTypeIdentifier; + +public class TestPdpGroupCreateOrUpdateProvider extends ProviderSuper { + private static final String EXPECTED_EXCEPTION = "expected exception"; + + private static final String PDP2 = "pdpB"; + private static final String PDP4 = "pdpD"; + + private PdpGroupCreateOrUpdateProvider prov; + + @AfterClass + public static void tearDownAfterClass() { + Registry.newRegistry(); + } + + /** + * Configures mocks and objects. + * + * @throws Exception if an error occurs + */ + @Override + @Before + public void setUp() throws Exception { + + super.setUp(); + + when(dao.getPolicyTypeList("typeA", "100.2.3")).thenReturn(Arrays.asList(loadPolicyType("daoPolicyType.json"))); + + prov = new PdpGroupCreateOrUpdateProvider(); + } + + @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"); + + groups.getGroups().get(0).getPdpSubgroups().get(0).getSupportedPolicyTypes().get(0).setVersion("99.99.99"); + + assertThatThrownBy(() -> prov.createOrUpdateGroups(groups)).isInstanceOf(PfModelException.class) + .hasMessageContaining("unknown policy type"); + + 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()); + + // 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 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()); + } + + @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_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 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_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 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(); + } + + 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 assertGroupUpdateOnly(PdpGroup group) throws Exception { + verify(dao, never()).createPdpGroups(any()); + verify(reqmap, never()).addRequest(any(), any()); + + List updates = getGroupUpdates(); + assertEquals(Arrays.asList(group), updates); + } +} 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 index 39a11396..a7fc11a8 100644 --- 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 @@ -22,7 +22,6 @@ 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; @@ -48,7 +47,6 @@ 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; @@ -82,6 +80,7 @@ public class TestPdpGroupDeployProvider extends ProviderSuper { * * @throws Exception if an error occurs */ + @Override @Before public void setUp() throws Exception { @@ -145,19 +144,6 @@ public class TestPdpGroupDeployProvider extends ProviderSuper { 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"); @@ -248,19 +234,6 @@ public class TestPdpGroupDeployProvider extends ProviderSuper { 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"); @@ -277,60 +250,6 @@ public class TestPdpGroupDeployProvider extends ProviderSuper { 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"); @@ -416,24 +335,6 @@ public class TestPdpGroupDeployProvider extends ProviderSuper { 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. * @@ -523,45 +424,6 @@ public class TestPdpGroupDeployProvider extends ProviderSuper { 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"); @@ -673,25 +535,6 @@ public class TestPdpGroupDeployProvider extends ProviderSuper { 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"); diff --git a/main/src/test/java/org/onap/policy/pap/main/rest/e2e/PdpGroupCreateOrUpdateTest.java b/main/src/test/java/org/onap/policy/pap/main/rest/e2e/PdpGroupCreateOrUpdateTest.java new file mode 100644 index 00000000..dacee672 --- /dev/null +++ b/main/src/test/java/org/onap/policy/pap/main/rest/e2e/PdpGroupCreateOrUpdateTest.java @@ -0,0 +1,180 @@ +/* + * ============LICENSE_START======================================================= + * ONAP PAP + * ================================================================================ + * Copyright (C) 2019 Nordix Foundation. + * ================================================================================ + * 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.e2e; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.util.Optional; +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.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.onap.policy.models.pap.concepts.PdpGroupUpdateResponse; +import org.onap.policy.models.pdp.concepts.PdpGroup; +import org.onap.policy.models.pdp.concepts.PdpGroups; +import org.onap.policy.models.pdp.enums.PdpState; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class PdpGroupCreateOrUpdateTest extends End2EndBase { + private static final Logger logger = LoggerFactory.getLogger(PdpGroupCreateOrUpdateTest.class); + + private static final String CREATEORUPDATE_GROUPS_ENDPOINT = "pdps/groups/batch"; + private static final String DELETE_GROUP_ENDPOINT = "pdps/groups/"; + private static final String CREATE_SUBGROUP = "pdpTypeA"; + private static final String GROUP_ENDPOINT = "pdps"; + + /** + * Starts Main and adds policies to the DB. + * + * @throws Exception if an error occurs + */ + @BeforeClass + public static void setUpBeforeClass() throws Exception { + End2EndBase.setUpBeforeClass(); + + addToscaPolicyTypes("monitoring.policy-type.yaml"); + } + + /** + * Sets up. + */ + @Override + @Before + public void setUp() throws Exception { + super.setUp(); + + context = new End2EndContext(); + } + + /** + * Deletes the deployed group. + */ + @Override + @After + public void tearDown() { + // delete the group that was inserted + try { + sendRequest(DELETE_GROUP_ENDPOINT + "createGroups").delete(); + } catch (Exception e) { + logger.warn("cannot delete group: createGroups", e); + } + + super.tearDown(); + } + + @Test + public void testCreateGroups() throws Exception { + + context.addPdp("pdpAA_1", CREATE_SUBGROUP); + context.addPdp("pdpAA_2", CREATE_SUBGROUP); + context.addPdp("pdpAB_1", "pdpTypeB"); + + context.startThreads(); + + Invocation.Builder invocationBuilder = sendRequest(CREATEORUPDATE_GROUPS_ENDPOINT); + + PdpGroups groups = loadJsonFile("createGroups.json", PdpGroups.class); + Entity entity = Entity.entity(groups, MediaType.APPLICATION_JSON); + Response rawresp = invocationBuilder.post(entity); + PdpGroupUpdateResponse resp = rawresp.readEntity(PdpGroupUpdateResponse.class); + assertEquals(Response.Status.OK.getStatusCode(), rawresp.getStatus()); + assertNull(resp.getErrorDetails()); + + context.await(); + + // none of the PDPs should have handled any requests + assertEquals(context.getPdps().size(), + context.getPdps().stream().filter(pdp -> pdp.getHandled().isEmpty()).count()); + + // repeat - should be OK + rawresp = invocationBuilder.post(entity); + resp = rawresp.readEntity(PdpGroupUpdateResponse.class); + assertEquals(Response.Status.OK.getStatusCode(), rawresp.getStatus()); + assertNull(resp.getErrorDetails()); + + // repeat with different properties - should fail + groups.getGroups().get(0).setProperties(null); + rawresp = invocationBuilder.post(entity); + resp = rawresp.readEntity(PdpGroupUpdateResponse.class); + assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), rawresp.getStatus()); + assertTrue(resp.getErrorDetails().contains("cannot change properties")); + } + + @Test + public void testCreateAndUpdate_MultipleGroups() throws Exception { + + Invocation.Builder invocationBuilderForGroupUpdate = sendRequest(CREATEORUPDATE_GROUPS_ENDPOINT); + + PdpGroups groups = loadJsonFile("createGroups.json", PdpGroups.class); + Entity entity = Entity.entity(groups, MediaType.APPLICATION_JSON); + Response rawPdpGroupUpdateResponse = invocationBuilderForGroupUpdate.post(entity); + PdpGroupUpdateResponse pdpGroupUpdateResponse = + rawPdpGroupUpdateResponse.readEntity(PdpGroupUpdateResponse.class); + assertEquals(Response.Status.OK.getStatusCode(), rawPdpGroupUpdateResponse.getStatus()); + assertNull(pdpGroupUpdateResponse.getErrorDetails()); + + Invocation.Builder invocationBuilderForGroupQuery = sendRequest(GROUP_ENDPOINT); + Response pdpGroupQueryResponse = invocationBuilderForGroupQuery.get(); + assertEquals(Response.Status.OK.getStatusCode(), pdpGroupQueryResponse.getStatus()); + PdpGroups pdpGroupsInDb = pdpGroupQueryResponse.readEntity(PdpGroups.class); + assertEquals(1, pdpGroupsInDb.getGroups().size()); + assertEquals("createGroups", pdpGroupsInDb.getGroups().get(0).getName()); + assertEquals(PdpState.PASSIVE, pdpGroupsInDb.getGroups().get(0).getPdpGroupState()); + + // creating 2 new groups + PdpGroups newGroups = loadJsonFile("createNewGroups.json", PdpGroups.class); + entity = Entity.entity(newGroups, MediaType.APPLICATION_JSON); + rawPdpGroupUpdateResponse = invocationBuilderForGroupUpdate.post(entity); + pdpGroupUpdateResponse = rawPdpGroupUpdateResponse.readEntity(PdpGroupUpdateResponse.class); + assertEquals(Response.Status.OK.getStatusCode(), rawPdpGroupUpdateResponse.getStatus()); + assertNull(pdpGroupUpdateResponse.getErrorDetails()); + + invocationBuilderForGroupQuery = sendRequest(GROUP_ENDPOINT); + pdpGroupQueryResponse = invocationBuilderForGroupQuery.get(); + assertEquals(Response.Status.OK.getStatusCode(), pdpGroupQueryResponse.getStatus()); + pdpGroupsInDb = pdpGroupQueryResponse.readEntity(PdpGroups.class); + assertEquals(3, pdpGroupsInDb.getGroups().size()); + + // updating a group, changing state of old group to active + groups.getGroups().get(0).setPdpGroupState(PdpState.ACTIVE); + entity = Entity.entity(groups, MediaType.APPLICATION_JSON); + rawPdpGroupUpdateResponse = invocationBuilderForGroupUpdate.post(entity); + pdpGroupUpdateResponse = rawPdpGroupUpdateResponse.readEntity(PdpGroupUpdateResponse.class); + assertEquals(Response.Status.OK.getStatusCode(), rawPdpGroupUpdateResponse.getStatus()); + assertNull(pdpGroupUpdateResponse.getErrorDetails()); + + invocationBuilderForGroupQuery = sendRequest(GROUP_ENDPOINT); + pdpGroupQueryResponse = invocationBuilderForGroupQuery.get(); + assertEquals(Response.Status.OK.getStatusCode(), pdpGroupQueryResponse.getStatus()); + pdpGroupsInDb = pdpGroupQueryResponse.readEntity(PdpGroups.class); + assertEquals(3, pdpGroupsInDb.getGroups().size()); + Optional oldGroupInDb = + pdpGroupsInDb.getGroups().stream().filter(group -> group.getName().equals("createGroups")).findAny(); + assertEquals(PdpState.ACTIVE, oldGroupInDb.get().getPdpGroupState()); + } +} diff --git a/main/src/test/resources/e2e/createGroups.json b/main/src/test/resources/e2e/createGroups.json index 1c8774be..1630a8d5 100644 --- a/main/src/test/resources/e2e/createGroups.json +++ b/main/src/test/resources/e2e/createGroups.json @@ -29,12 +29,7 @@ "version": "1.0.0" } ], - "policies": [ - { - "name": "onap.restart.tca", - "version": "1.0.0" - } - ] + "policies": [] }, { "pdpType": "pdpTypeB", diff --git a/main/src/test/resources/e2e/createNewGroups.json b/main/src/test/resources/e2e/createNewGroups.json new file mode 100644 index 00000000..45339322 --- /dev/null +++ b/main/src/test/resources/e2e/createNewGroups.json @@ -0,0 +1,48 @@ +{ + "groups": [ + { + "name": "newGroup1", + "pdpGroupState": "ACTIVE", + "properties": { + "hello": "world" + }, + "pdpSubgroups": [ + { + "pdpType": "pdpTypeA", + "desiredInstanceCount": 2, + "properties": {}, + "pdpInstances": [], + "supportedPolicyTypes": [ + { + "name": "onap.policies.monitoring.cdap.tca.hi.lo.app", + "version": "1.0.0" + } + ], + "policies": [] + } + ] + }, + { + "name": "newGroup2", + "pdpGroupState": "ACTIVE", + "properties": { + "hello": "world" + }, + "pdpSubgroups": [ + { + "pdpType": "pdpTypeB", + "desiredInstanceCount": 2, + "properties": {}, + "pdpInstances": [], + "supportedPolicyTypes": [ + { + "name": "onap.policies.monitoring.cdap.tca.hi.lo.app", + "version": "1.0.0" + } + ], + "policies": [] + } + ] + } + ] +} diff --git a/main/src/test/resources/simpleDeploy/createGroups.json b/main/src/test/resources/simpleDeploy/createGroups.json index 59c4eb87..daef17b7 100644 --- a/main/src/test/resources/simpleDeploy/createGroups.json +++ b/main/src/test/resources/simpleDeploy/createGroups.json @@ -26,12 +26,7 @@ "instanceId": "pdpA" } ], - "policies": [ - { - "name": "policyA", - "version": "1.2.3" - } - ] + "policies": [] } ] } diff --git a/main/src/test/resources/simpleDeploy/createGroupsDelSub.json b/main/src/test/resources/simpleDeploy/createGroupsDelSub.json index cba308ec..bcaa1c1f 100644 --- a/main/src/test/resources/simpleDeploy/createGroupsDelSub.json +++ b/main/src/test/resources/simpleDeploy/createGroupsDelSub.json @@ -26,12 +26,7 @@ "instanceId": "pdpA" } ], - "policies": [ - { - "name": "policyA", - "version": "1.2.3" - } - ] + "policies": [] }, { "pdpType": "pdpTypeB", @@ -51,12 +46,7 @@ "instanceId": "pdpD" } ], - "policies": [ - { - "name": "policyA", - "version": "1.2.3" - } - ] + "policies": [] } ] }