diff options
Diffstat (limited to 'models-interactions/model-actors/actor.appclcm/src')
6 files changed, 421 insertions, 276 deletions
diff --git a/models-interactions/model-actors/actor.appclcm/src/main/java/org/onap/policy/controlloop/actor/appclcm/AppcLcmActorServiceProvider.java b/models-interactions/model-actors/actor.appclcm/src/main/java/org/onap/policy/controlloop/actor/appclcm/AppcLcmActorServiceProvider.java index 1d04cb5f2..704c44da7 100644 --- a/models-interactions/model-actors/actor.appclcm/src/main/java/org/onap/policy/controlloop/actor/appclcm/AppcLcmActorServiceProvider.java +++ b/models-interactions/model-actors/actor.appclcm/src/main/java/org/onap/policy/controlloop/actor/appclcm/AppcLcmActorServiceProvider.java @@ -1,11 +1,10 @@ /*- * ============LICENSE_START======================================================= - * AppcLcmActorServiceProvider + * ONAP * ================================================================================ * Copyright (C) 2017-2020 AT&T Intellectual Property. All rights reserved. * Modifications copyright (c) 2018 Nokia * Modifications Copyright (C) 2019 Nordix Foundation. - * Modifications Copyright (C) 2020 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. @@ -31,6 +30,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import org.onap.policy.appclcm.AppcLcmBody; import org.onap.policy.appclcm.AppcLcmCommonHeader; import org.onap.policy.appclcm.AppcLcmDmaapWrapper; @@ -39,6 +39,8 @@ import org.onap.policy.appclcm.AppcLcmOutput; import org.onap.policy.appclcm.AppcLcmResponseCode; import org.onap.policy.controlloop.ControlLoopOperation; import org.onap.policy.controlloop.VirtualControlLoopEvent; +import org.onap.policy.controlloop.actor.appc.AppcOperation; +import org.onap.policy.controlloop.actor.appc.ModifyConfigOperation; import org.onap.policy.controlloop.actorserviceprovider.impl.BidirectionalTopicActor; import org.onap.policy.controlloop.actorserviceprovider.impl.BidirectionalTopicOperator; import org.onap.policy.controlloop.actorserviceprovider.parameters.BidirectionalTopicActorParams; @@ -67,17 +69,16 @@ public class AppcLcmActorServiceProvider extends BidirectionalTopicActor<Bidirec private static final String TARGET_VNF = "VNF"; // Strings for recipes - private static final String RECIPE_RESTART = "Restart"; - private static final String RECIPE_REBUILD = "Rebuild"; - private static final String RECIPE_MIGRATE = "Migrate"; - private static final String RECIPE_MODIFY = "ConfigModify"; + private static final String RECIPE_RESTART = AppcLcmConstants.OPERATION_RESTART; + private static final String RECIPE_REBUILD = AppcLcmConstants.OPERATION_REBUILD; + private static final String RECIPE_MIGRATE = AppcLcmConstants.OPERATION_MIGRATE; + private static final String RECIPE_MODIFY = AppcLcmConstants.OPERATION_CONFIG_MODIFY; /* To be used in future releases when LCM ConfigModify is used */ private static final String APPC_REQUEST_PARAMS = "request-parameters"; private static final String APPC_CONFIG_PARAMS = "configuration-parameters"; - private static final ImmutableList<String> recipes = - ImmutableList.of(RECIPE_RESTART, RECIPE_REBUILD, RECIPE_MIGRATE, RECIPE_MODIFY); + private static final Set<String> recipes = AppcLcmConstants.OPERATION_NAMES; private static final ImmutableMap<String, List<String>> targets = new ImmutableMap.Builder<String, List<String>>() .put(RECIPE_RESTART, ImmutableList.of(TARGET_VM)).put(RECIPE_REBUILD, ImmutableList.of(TARGET_VM)) .put(RECIPE_MIGRATE, ImmutableList.of(TARGET_VM)).put(RECIPE_MODIFY, ImmutableList.of(TARGET_VNF)).build(); @@ -91,8 +92,15 @@ public class AppcLcmActorServiceProvider extends BidirectionalTopicActor<Bidirec public AppcLcmActorServiceProvider() { super(NAME, BidirectionalTopicActorParams.class); - addOperator(new BidirectionalTopicOperator(NAME, ConfigModifyOperation.NAME, this, - AppcLcmOperation.SELECTOR_KEYS, ConfigModifyOperation::new)); + // add LCM operations first as they take precedence + for (String opname : AppcLcmConstants.OPERATION_NAMES) { + addOperator(new BidirectionalTopicOperator(NAME, opname, this, AppcLcmOperation.SELECTOR_KEYS, + AppcLcmOperation::new)); + } + + // add legacy operations + addOperator(new BidirectionalTopicOperator(NAME, ModifyConfigOperation.NAME, this, AppcOperation.SELECTOR_KEYS, + ModifyConfigOperation::new)); } /** diff --git a/models-interactions/model-actors/actor.appclcm/src/main/java/org/onap/policy/controlloop/actor/appclcm/AppcLcmConstants.java b/models-interactions/model-actors/actor.appclcm/src/main/java/org/onap/policy/controlloop/actor/appclcm/AppcLcmConstants.java new file mode 100644 index 000000000..efcbe492f --- /dev/null +++ b/models-interactions/model-actors/actor.appclcm/src/main/java/org/onap/policy/controlloop/actor/appclcm/AppcLcmConstants.java @@ -0,0 +1,59 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2020 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.controlloop.actor.appclcm; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Collectors; + +public class AppcLcmConstants { + + // Strings for OPERATIONs + public static final String OPERATION_RESTART = "Restart"; + public static final String OPERATION_REBUILD = "Rebuild"; + public static final String OPERATION_MIGRATE = "Migrate"; + public static final String OPERATION_CONFIG_MODIFY = "ConfigModify"; + + public static final Set<String> OPERATION_NAMES = + Set.of(OPERATION_RESTART, OPERATION_REBUILD, OPERATION_MIGRATE, OPERATION_CONFIG_MODIFY); + + // operations from legacy APPC + public static final String LEGACY_MODIFY_CONFIG = "ModifyConfig"; + + public static final Set<String> LEGACY_NAMES = + Set.of(LEGACY_MODIFY_CONFIG); + + public static final Set<String> COMBINED_OPERATION_NAMES; + + static { + Set<String> set = new HashSet<>(OPERATION_NAMES); + set.addAll(LEGACY_NAMES); + COMBINED_OPERATION_NAMES = Collections.unmodifiableSet(set); + } + + protected static final Set<String> SUPPORTS_PAYLOAD = + Set.of(OPERATION_CONFIG_MODIFY).stream().map(String::toLowerCase).collect(Collectors.toSet()); + + private AppcLcmConstants() { + // do nothing + } +} diff --git a/models-interactions/model-actors/actor.appclcm/src/main/java/org/onap/policy/controlloop/actor/appclcm/AppcLcmOperation.java b/models-interactions/model-actors/actor.appclcm/src/main/java/org/onap/policy/controlloop/actor/appclcm/AppcLcmOperation.java index c0b83319c..749622714 100644 --- a/models-interactions/model-actors/actor.appclcm/src/main/java/org/onap/policy/controlloop/actor/appclcm/AppcLcmOperation.java +++ b/models-interactions/model-actors/actor.appclcm/src/main/java/org/onap/policy/controlloop/actor/appclcm/AppcLcmOperation.java @@ -1,6 +1,6 @@ /*- * ============LICENSE_START======================================================= - * AppcLcmOperation + * ONAP * ================================================================================ * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved. * ================================================================================ @@ -24,16 +24,15 @@ import java.util.List; import java.util.Map; import java.util.UUID; import java.util.concurrent.CompletableFuture; -import org.onap.aai.domain.yang.GenericVnf; -import org.onap.policy.aai.AaiConstants; -import org.onap.policy.aai.AaiCqResponse; +import org.apache.commons.lang3.StringUtils; import org.onap.policy.appclcm.AppcLcmBody; import org.onap.policy.appclcm.AppcLcmCommonHeader; import org.onap.policy.appclcm.AppcLcmDmaapWrapper; import org.onap.policy.appclcm.AppcLcmInput; +import org.onap.policy.appclcm.AppcLcmOutput; import org.onap.policy.appclcm.AppcLcmResponseCode; +import org.onap.policy.appclcm.AppcLcmResponseStatus; import org.onap.policy.common.utils.coder.CoderException; -import org.onap.policy.common.utils.coder.StandardCoder; import org.onap.policy.controlloop.VirtualControlLoopEvent; import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome; import org.onap.policy.controlloop.actorserviceprovider.impl.BidirectionalTopicOperation; @@ -41,23 +40,21 @@ import org.onap.policy.controlloop.actorserviceprovider.parameters.Bidirectional import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams; import org.onap.policy.controlloop.actorserviceprovider.topic.SelectorKey; import org.onap.policy.controlloop.policy.PolicyResult; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -public abstract class AppcLcmOperation extends BidirectionalTopicOperation<AppcLcmDmaapWrapper, AppcLcmDmaapWrapper> { +public class AppcLcmOperation extends BidirectionalTopicOperation<AppcLcmDmaapWrapper, AppcLcmDmaapWrapper> { - private static final Logger logger = LoggerFactory.getLogger(AppcLcmOperation.class); - private static final StandardCoder coder = new StandardCoder(); + private static final String MISSING_STATUS = "APPC-LCM response is missing the response status"; public static final String VNF_ID_KEY = "vnf-id"; /** * Keys used to match the response with the request listener. The sub request ID is a * UUID, so it can be used to uniquely identify the response. * <p/> - * Note: if these change, then {@link #getExpectedKeyValues(int, Request)} must be - * updated accordingly. + * Note: if these change, then {@link #getExpectedKeyValues(int, AppcLcmDmaapWrapper)} + * must be updated accordingly. */ - public static final List<SelectorKey> SELECTOR_KEYS = List.of(new SelectorKey("common-header", "sub-request-id")); + public static final List<SelectorKey> SELECTOR_KEYS = + List.of(new SelectorKey("body", "output", "common-header", "sub-request-id")); /** * Constructs the object. @@ -67,6 +64,10 @@ public abstract class AppcLcmOperation extends BidirectionalTopicOperation<AppcL */ public AppcLcmOperation(ControlLoopOperationParams params, BidirectionalTopicConfig config) { super(params, config, AppcLcmDmaapWrapper.class); + + if (StringUtils.isBlank(params.getTargetEntity())) { + throw new IllegalArgumentException("missing targetEntity"); + } } /** @@ -74,40 +75,12 @@ public abstract class AppcLcmOperation extends BidirectionalTopicOperation<AppcL * Starts the GUARD using startGuardAsync. */ @Override - @SuppressWarnings("unchecked") protected CompletableFuture<OperationOutcome> startPreprocessorAsync() { - if (params != null) { - ControlLoopOperationParams cqParams = params.toBuilder().actor(AaiConstants.ACTOR_NAME) - .operation(AaiCqResponse.OPERATION).payload(null).retry(null).timeoutSec(null).build(); - - // run Custom Query and Guard, in parallel - return allOf(() -> params.getContext().obtain(AaiCqResponse.CONTEXT_KEY, cqParams), this::startGuardAsync); - } return startGuardAsync(); } @Override protected AppcLcmDmaapWrapper makeRequest(int attempt) { - AaiCqResponse cq = params.getContext().getProperty(AaiCqResponse.CONTEXT_KEY); - - GenericVnf genvnf = cq.getGenericVnfByModelInvariantId(params.getTarget().getResourceID()); - if (genvnf == null) { - logger.info("{}: target entity could not be found for {}", getFullName(), params.getRequestId()); - throw new IllegalArgumentException("target vnf-id could not be found"); - } - - return makeRequest(attempt, genvnf.getVnfId()); - } - - /** - * Makes a request, given the target VNF. This is a support function for - * {@link #makeRequest(int)}. - * - * @param attempt attempt number - * @param targetVnf target VNF - * @return a new request - */ - protected AppcLcmDmaapWrapper makeRequest(int attempt, String targetVnf) { VirtualControlLoopEvent onset = params.getContext().getEvent(); String subRequestId = UUID.randomUUID().toString(); @@ -118,22 +91,21 @@ public abstract class AppcLcmOperation extends BidirectionalTopicOperation<AppcL AppcLcmInput inputRequest = new AppcLcmInput(); inputRequest.setCommonHeader(header); - inputRequest.setAction(getName()); + + AppcLcmRecipeFormatter recipeFormatter = new AppcLcmRecipeFormatter(getName()); + inputRequest.setAction(recipeFormatter.getBodyRecipe()); /* - * Action Identifiers are required for APPC LCM requests. For R1, the recipes supported by - * Policy only require a vnf-id. + * Action Identifiers are required for APPC LCM requests. For R1, the recipes + * supported by Policy only require a vnf-id. */ - if (inputRequest.getActionIdentifiers() != null) { - inputRequest.getActionIdentifiers().put(VNF_ID_KEY, targetVnf); - } else { - inputRequest.setActionIdentifiers(Map.of(VNF_ID_KEY, targetVnf)); - } + inputRequest.setActionIdentifiers(Map.of(VNF_ID_KEY, params.getTargetEntity())); /* - * For R1, the payloads will not be required for the Restart, Rebuild, or Migrate recipes. - * APPC will populate the payload based on A&AI look up of the vnd-id provided in the action - * identifiers. The payload is set when converPayload() is called. + * For R1, the payloads will not be required for the Restart, Rebuild, or Migrate + * recipes. APPC will populate the payload based on A&AI look up of the vnd-id + * provided in the action identifiers. The payload is set when converPayload() is + * called. */ if (operationSupportsPayload()) { convertPayload(params.getPayload(), inputRequest); @@ -144,9 +116,6 @@ public abstract class AppcLcmOperation extends BidirectionalTopicOperation<AppcL AppcLcmBody body = new AppcLcmBody(); body.setInput(inputRequest); - AppcLcmRecipeFormatter recipeFormatter = new AppcLcmRecipeFormatter(getName()); - inputRequest.setAction(recipeFormatter.getBodyRecipe()); - AppcLcmDmaapWrapper dmaapRequest = new AppcLcmDmaapWrapper(); dmaapRequest.setBody(body); dmaapRequest.setVersion("2.0"); @@ -166,14 +135,12 @@ public abstract class AppcLcmOperation extends BidirectionalTopicOperation<AppcL * @param source source from which to get the values * @param map where to place the decoded values */ - private static void convertPayload(Map<String, Object> source, AppcLcmInput request) { - String encodedPayloadString = null; + private void convertPayload(Map<String, Object> source, AppcLcmInput request) { try { - encodedPayloadString = coder.encode(source); + String encodedPayloadString = makeCoder().encode(source); request.setPayload(encodedPayloadString); } catch (CoderException e) { - logger.error("Cannot convert payload. Error encoding source as a string.", e); - throw new IllegalArgumentException("Cannot convert payload. Error encoding source as a string."); + throw new IllegalArgumentException("Cannot convert payload", e); } } @@ -187,16 +154,14 @@ public abstract class AppcLcmOperation extends BidirectionalTopicOperation<AppcL @Override protected Status detmStatus(String rawResponse, AppcLcmDmaapWrapper response) { - if (response == null || response.getBody() == null || response.getBody().getOutput() == null - || response.getBody().getOutput().getStatus() == null) { - throw new IllegalArgumentException("APPC-LCM response is missing the response status"); + AppcLcmResponseStatus status = getStatus(response); + if (status == null) { + throw new IllegalArgumentException(MISSING_STATUS); } - String code = AppcLcmResponseCode.toResponseValue(response.getBody().getOutput().getStatus().getCode()); - + String code = AppcLcmResponseCode.toResponseValue(status.getCode()); if (code == null) { - throw new IllegalArgumentException( - "unknown APPC-LCM response status code: " + response.getBody().getOutput().getStatus().getCode()); + throw new IllegalArgumentException("unknown APPC-LCM response status code: " + status.getCode()); } switch (code) { @@ -218,18 +183,52 @@ public abstract class AppcLcmOperation extends BidirectionalTopicOperation<AppcL */ @Override public OperationOutcome setOutcome(OperationOutcome outcome, PolicyResult result, AppcLcmDmaapWrapper response) { - if (response == null || response.getBody() == null || response.getBody().getOutput() == null - || response.getBody().getOutput().getStatus() == null - || response.getBody().getOutput().getStatus().getMessage() == null) { + AppcLcmResponseStatus status = getStatus(response); + if (status == null) { + return setOutcome(outcome, result); + } + + String message = status.getMessage(); + if (message == null) { return setOutcome(outcome, result); } outcome.setResult(result); - outcome.setMessage(response.getBody().getOutput().getStatus().getMessage()); + outcome.setMessage(message); return outcome; } + /** + * Gets the status from the response. + * + * @param response the response from which to extract the status, or {@code null} + * @return the status, or {@code null} if it does not exist + */ + protected AppcLcmResponseStatus getStatus(AppcLcmDmaapWrapper response) { + if (response == null) { + return null; + } + + AppcLcmBody body = response.getBody(); + if (body == null) { + return null; + } + + AppcLcmOutput output = body.getOutput(); + if (output == null) { + return null; + } + + return output.getStatus(); + } + + /** + * Determines if the operation supports a payload. + * + * @return {@code true} if the operation supports a payload, {@code false} otherwise + */ protected boolean operationSupportsPayload() { - return params.getPayload() != null && !params.getPayload().isEmpty(); + return params.getPayload() != null && !params.getPayload().isEmpty() + && AppcLcmConstants.SUPPORTS_PAYLOAD.contains(params.getOperation().toLowerCase()); } } diff --git a/models-interactions/model-actors/actor.appclcm/src/main/java/org/onap/policy/controlloop/actor/appclcm/ConfigModifyOperation.java b/models-interactions/model-actors/actor.appclcm/src/main/java/org/onap/policy/controlloop/actor/appclcm/ConfigModifyOperation.java deleted file mode 100644 index 02645afd8..000000000 --- a/models-interactions/model-actors/actor.appclcm/src/main/java/org/onap/policy/controlloop/actor/appclcm/ConfigModifyOperation.java +++ /dev/null @@ -1,43 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * AppcLcmOperation - * ================================================================================ - * Copyright (C) 2020 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.controlloop.actor.appclcm; - -import org.onap.policy.controlloop.actorserviceprovider.parameters.BidirectionalTopicConfig; -import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class ConfigModifyOperation extends AppcLcmOperation { - - private static final Logger logger = LoggerFactory.getLogger(ConfigModifyOperation.class); - - public static final String NAME = "ConfigModify"; - - /** - * Constructs the object. - * - * @param params operation parameters - * @param config configuration for this operation - */ - public ConfigModifyOperation(ControlLoopOperationParams params, BidirectionalTopicConfig config) { - super(params, config); - } -} diff --git a/models-interactions/model-actors/actor.appclcm/src/test/java/org/onap/policy/controlloop/actor/appclcm/AppcLcmActorServiceProviderTest.java b/models-interactions/model-actors/actor.appclcm/src/test/java/org/onap/policy/controlloop/actor/appclcm/AppcLcmActorServiceProviderTest.java index 90fc8a59d..56ce047dd 100644 --- a/models-interactions/model-actors/actor.appclcm/src/test/java/org/onap/policy/controlloop/actor/appclcm/AppcLcmActorServiceProviderTest.java +++ b/models-interactions/model-actors/actor.appclcm/src/test/java/org/onap/policy/controlloop/actor/appclcm/AppcLcmActorServiceProviderTest.java @@ -1,8 +1,8 @@ /*- * ============LICENSE_START======================================================= - * AppcServiceProviderTest + * ONAP * ================================================================================ - * Copyright (C) 2017-2019 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2017-2020 AT&T Intellectual Property. All rights reserved. * Modifications Copyright (C) 2019 Nordix Foundation. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); @@ -27,7 +27,6 @@ import static org.junit.Assert.assertNull; import java.time.Instant; import java.util.AbstractMap; -import java.util.Arrays; import java.util.HashMap; import java.util.UUID; import java.util.stream.Collectors; @@ -77,7 +76,8 @@ public class AppcLcmActorServiceProviderTest { static { /* - * Construct an onset with an AAI subtag containing generic-vnf.vnf-id and a target type of VM. + * Construct an onset with an AAI subtag containing generic-vnf.vnf-id and a + * target type of VM. */ onsetEvent = new VirtualControlLoopEvent(); onsetEvent.setClosedLoopControlName("closedLoopControlName-Test"); @@ -181,7 +181,7 @@ public class AppcLcmActorServiceProviderTest { assertEquals(-1, prov.getSequenceNumber()); // verify that it has the operators we expect - var expected = Arrays.asList(ConfigModifyOperation.NAME).stream().sorted().collect(Collectors.toList()); + var expected = AppcLcmConstants.COMBINED_OPERATION_NAMES.stream().sorted().collect(Collectors.toList()); var actual = prov.getOperationNames().stream().sorted().collect(Collectors.toList()); assertEquals(expected.toString(), actual.toString()); @@ -194,7 +194,7 @@ public class AppcLcmActorServiceProviderTest { public void constructRestartRequestTest() { AppcLcmDmaapWrapper dmaapRequest = - AppcLcmActorServiceProvider.constructRequest(onsetEvent, operation, policy, VNF01); + AppcLcmActorServiceProvider.constructRequest(onsetEvent, operation, policy, VNF01); /* The service provider must return a non null DMAAP request wrapper */ assertNotNull(dmaapRequest); @@ -229,13 +229,14 @@ public class AppcLcmActorServiceProviderTest { @Test public void processRestartResponseSuccessTest() { AbstractMap.SimpleEntry<PolicyResult, String> result = - AppcLcmActorServiceProvider.processResponse(dmaapResponse); + AppcLcmActorServiceProvider.processResponse(dmaapResponse); assertEquals(PolicyResult.SUCCESS, result.getKey()); assertEquals("Restart Successful", result.getValue()); } /** - * A test to assert that a null pointer exception is thrown if the APPC response body is null. + * A test to assert that a null pointer exception is thrown if the APPC response body + * is null. */ @Test(expected = NullPointerException.class) public void processNullBodyResponseTest() { @@ -243,7 +244,8 @@ public class AppcLcmActorServiceProviderTest { } /** - * A test to assert that a null pointer exception is thrown if the APPC response output is null. + * A test to assert that a null pointer exception is thrown if the APPC response + * output is null. */ @Test(expected = NullPointerException.class) public void processNullOutputResponseTest() { @@ -364,11 +366,11 @@ public class AppcLcmActorServiceProviderTest { // when AppcLcmDmaapWrapper migrateRequest = - AppcLcmActorServiceProvider.constructRequest(onsetEvent, operation, migratePolicy, VNF01); + AppcLcmActorServiceProvider.constructRequest(onsetEvent, operation, migratePolicy, VNF01); AppcLcmDmaapWrapper rebuildRequest = - AppcLcmActorServiceProvider.constructRequest(onsetEvent, operation, rebuildPolicy, VNF01); + AppcLcmActorServiceProvider.constructRequest(onsetEvent, operation, rebuildPolicy, VNF01); AppcLcmDmaapWrapper restartRequest = - AppcLcmActorServiceProvider.constructRequest(onsetEvent, operation, restartPolicy, VNF01); + AppcLcmActorServiceProvider.constructRequest(onsetEvent, operation, restartPolicy, VNF01); // then assertNull(migrateRequest.getBody().getInput().getPayload()); @@ -384,9 +386,9 @@ public class AppcLcmActorServiceProviderTest { // when AppcLcmDmaapWrapper noPayloadRequest = - AppcLcmActorServiceProvider.constructRequest(onsetEvent, operation, noPayloadPolicy, VNF01); + AppcLcmActorServiceProvider.constructRequest(onsetEvent, operation, noPayloadPolicy, VNF01); AppcLcmDmaapWrapper emptyPayloadRequest = - AppcLcmActorServiceProvider.constructRequest(onsetEvent, operation, emptyPayloadPolicy, VNF01); + AppcLcmActorServiceProvider.constructRequest(onsetEvent, operation, emptyPayloadPolicy, VNF01); // then assertNull(noPayloadRequest.getBody().getInput().getPayload()); @@ -402,11 +404,11 @@ public class AppcLcmActorServiceProviderTest { // when AppcLcmDmaapWrapper dmaapRequest = - AppcLcmActorServiceProvider.constructRequest(onsetEvent, operation, otherPolicy, VNF01); + AppcLcmActorServiceProvider.constructRequest(onsetEvent, operation, otherPolicy, VNF01); // then assertEquals("{\"requestParameters\": {\"host-ip-address\":\"10.183.37.25\"}}", - dmaapRequest.getBody().getInput().getPayload()); + dmaapRequest.getBody().getInput().getPayload()); } @Test @@ -415,18 +417,18 @@ public class AppcLcmActorServiceProviderTest { HashMap<String, String> payload = new HashMap<>(); payload.put("requestParameters", "{\"host-ip-address\":\"10.183.37.25\"}"); payload.put("configurationParameters", - "[{\"ip-addr\":\"$.vf-module-topology.vf-module-parameters.param[9]\"," - + "\"oam-ip-addr\":\"$.vf-module-topology.vf-module-parameters.param[16]\"," - + "\"enabled\":\"$.vf-module-topology.vf-module-parameters.param[23]\"}]"); + "[{\"ip-addr\":\"$.vf-module-topology.vf-module-parameters.param[9]\"," + + "\"oam-ip-addr\":\"$.vf-module-topology.vf-module-parameters.param[16]\"," + + "\"enabled\":\"$.vf-module-topology.vf-module-parameters.param[23]\"}]"); Policy otherPolicy = constructHealthCheckPolicyWithPayload(payload); // when AppcLcmDmaapWrapper dmaapRequest = - AppcLcmActorServiceProvider.constructRequest(onsetEvent, operation, otherPolicy, VNF01); + AppcLcmActorServiceProvider.constructRequest(onsetEvent, operation, otherPolicy, VNF01); // then - assertEquals(dmaapRequest.getBody().getInput().getPayload(), - "{\"requestParameters\": " + "{\"host-ip-address\":\"10.183.37.25\"}," + "\"configurationParameters\": " + assertEquals(dmaapRequest.getBody().getInput().getPayload(), "{\"requestParameters\": " + + "{\"host-ip-address\":\"10.183.37.25\"}," + "\"configurationParameters\": " + "[{\"ip-addr\":\"$.vf-module-topology.vf-module-parameters.param[9]\"," + "\"oam-ip-addr\":\"$.vf-module-topology.vf-module-parameters.param[16]\"," + "\"enabled\":\"$.vf-module-topology.vf-module-parameters.param[23]\"}]" + "}"); diff --git a/models-interactions/model-actors/actor.appclcm/src/test/java/org/onap/policy/controlloop/actor/appclcm/AppcLcmOperationTest.java b/models-interactions/model-actors/actor.appclcm/src/test/java/org/onap/policy/controlloop/actor/appclcm/AppcLcmOperationTest.java index d2af4e7e2..e94eaecd2 100644 --- a/models-interactions/model-actors/actor.appclcm/src/test/java/org/onap/policy/controlloop/actor/appclcm/AppcLcmOperationTest.java +++ b/models-interactions/model-actors/actor.appclcm/src/test/java/org/onap/policy/controlloop/actor/appclcm/AppcLcmOperationTest.java @@ -1,6 +1,6 @@ /*- * ============LICENSE_START======================================================= - * AppcLcmOperation + * ONAP * ================================================================================ * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved. * ================================================================================ @@ -22,171 +22,291 @@ package org.onap.policy.controlloop.actor.appclcm; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.atLeast; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; -import java.util.List; -import java.util.UUID; +import java.util.Arrays; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Collectors; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; -import org.mockito.Mockito; import org.onap.policy.appclcm.AppcLcmBody; import org.onap.policy.appclcm.AppcLcmCommonHeader; import org.onap.policy.appclcm.AppcLcmDmaapWrapper; -import org.onap.policy.appclcm.AppcLcmInput; import org.onap.policy.appclcm.AppcLcmOutput; import org.onap.policy.appclcm.AppcLcmResponseStatus; -import org.onap.policy.controlloop.VirtualControlLoopEvent; +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.controlloop.ControlLoopOperation; +import org.onap.policy.controlloop.actor.test.BasicBidirectionalTopicOperation; import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome; import org.onap.policy.controlloop.actorserviceprovider.controlloop.ControlLoopEventContext; import org.onap.policy.controlloop.actorserviceprovider.impl.BidirectionalTopicOperation.Status; -import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams; import org.onap.policy.controlloop.policy.PolicyResult; -import org.powermock.reflect.Whitebox; - -public class AppcLcmOperationTest { - private AppcLcmInput mockInput; - private AppcLcmOutput mockOutput; - private AppcLcmBody mockBody; - private AppcLcmDmaapWrapper mockInputWrapper; - private AppcLcmDmaapWrapper mockOutputWrapper; - private OperationOutcome mockOperationOutcome; - private AppcLcmOperation operation; - private AppcLcmResponseStatus mockResponseStatus; - private AppcLcmCommonHeader mockCommonHeader; - private ControlLoopOperationParams mockParams; - private ControlLoopEventContext mockContext; - private VirtualControlLoopEvent mockEvent; +import org.onap.policy.controlloop.policy.Target; + +public class AppcLcmOperationTest extends BasicBidirectionalTopicOperation { + + private static final String EXPECTED_EXCEPTION = "expected exception"; + private static final String PAYLOAD_KEY1 = "key-A"; + private static final String PAYLOAD_VALUE1 = "value-A"; + private static final String MY_MESSAGE = "my-message"; + protected static final String MY_VNF = "my-vnf"; + protected static final String RESOURCE_ID = "my-resource"; + private static final int SUCCESS_CODE = 400; + + private AppcLcmDmaapWrapper response; + private AppcLcmOperation oper; /** - * Setup mocks for testing. + * Sets up. */ @Before - public void setup() { - mockInput = Mockito.mock(AppcLcmInput.class); - mockOutput = Mockito.mock(AppcLcmOutput.class); - mockBody = Mockito.mock(AppcLcmBody.class); - mockContext = Mockito.mock(ControlLoopEventContext.class); - mockEvent = Mockito.mock(VirtualControlLoopEvent.class); - mockInputWrapper = Mockito.mock(AppcLcmDmaapWrapper.class); - mockOutputWrapper = Mockito.mock(AppcLcmDmaapWrapper.class); - mockOperationOutcome = Mockito.mock(OperationOutcome.class); - mockResponseStatus = Mockito.mock(AppcLcmResponseStatus.class); - mockCommonHeader = Mockito.mock(AppcLcmCommonHeader.class); - mockParams = Mockito.mock(ControlLoopOperationParams.class); - operation = Mockito.mock(AppcLcmOperation.class); + public void setUp() { + super.setUpBasic(); + + response = makeResponse(); + + oper = new AppcLcmOperation(params, config); } @Test - public void testStartPreprocessorAsync() { - Mockito.doCallRealMethod().when(operation).startPreprocessorAsync(); - assertNull(operation.startPreprocessorAsync()); + public void testConstructor() { + assertEquals(DEFAULT_ACTOR, oper.getActorName()); + assertEquals(DEFAULT_OPERATION, oper.getName()); + + // missing target entity + params = params.toBuilder().targetEntity("").build(); + assertThatIllegalArgumentException().isThrownBy(() -> new AppcLcmOperation(params, config)) + .withMessage("missing targetEntity"); + } + + @Test + public void testStartPreprocessorAsync() throws Exception { + context = mock(ControlLoopEventContext.class); + when(context.getEvent()).thenReturn(event); + params = params.toBuilder().context(context).build(); + + AtomicBoolean guardStarted = new AtomicBoolean(); + + oper = new AppcLcmOperation(params, config) { + @Override + protected CompletableFuture<OperationOutcome> startGuardAsync() { + guardStarted.set(true); + return super.startGuardAsync(); + } + }; + + CompletableFuture<OperationOutcome> future2 = oper.startPreprocessorAsync(); + assertNotNull(future2); + assertFalse(future.isDone()); + assertTrue(guardStarted.get()); + + assertTrue(executor.runAll(100)); + assertTrue(future2.isDone()); + assertEquals(PolicyResult.SUCCESS, future2.get().getResult()); } - @Ignore @Test public void testMakeRequest() { - UUID randomId = UUID.randomUUID(); - Mockito.doCallRealMethod().when(operation).makeRequest(1, "sampleTargetVnf"); - Mockito.when(mockParams.getRequestId()).thenReturn(randomId); - Mockito.when(mockParams.getPayload()).thenReturn(null); - Mockito.when(mockParams.getContext()).thenReturn(mockContext); - Mockito.when(mockParams.getOperation()).thenReturn("Config-Modify"); - Mockito.when(mockContext.getEvent()).thenReturn(mockEvent); - Mockito.when(mockEvent.getRequestId()).thenReturn(randomId); - Whitebox.setInternalState(operation, "params", mockParams); - assertNotNull(operation.makeRequest(1, "sampleTargetVnf")); - Mockito.verify(mockParams, atLeast(1)).getRequestId(); - Mockito.verify(mockParams, atLeast(1)).getPayload(); - Mockito.verify(mockParams, atLeast(1)).getContext(); - Mockito.verify(mockContext, atLeast(1)).getEvent(); - Mockito.verify(mockEvent, atLeast(1)).getRequestId(); + AppcLcmDmaapWrapper request = oper.makeRequest(2); + assertEquals("DefaultOperation", request.getBody().getInput().getAction()); + + AppcLcmCommonHeader header = request.getBody().getInput().getCommonHeader(); + assertNotNull(header); + assertEquals(params.getRequestId(), header.getRequestId()); + + String subreq = header.getSubRequestId(); + assertNotNull(subreq); + + assertEquals("{vnf-id=my-target}", request.getBody().getInput().getActionIdentifiers().toString()); + + // a subsequent request should have a different sub-request id + assertNotEquals(subreq, oper.makeRequest(2).getBody().getInput().getCommonHeader().getSubRequestId()); + } + + @Test + public void testConvertPayload() { + // only builds a payload for ConfigModify + params = params.toBuilder().operation(AppcLcmConstants.OPERATION_CONFIG_MODIFY).build(); + oper = new AppcLcmOperation(params, config); + + AppcLcmDmaapWrapper req = oper.makeRequest(2); + assertEquals("{\"key-A\":\"value-A\"}", req.getBody().getInput().getPayload()); + + // coder exception + oper = new AppcLcmOperation(params, config) { + @Override + protected Coder makeCoder() { + return new StandardCoder() { + @Override + public String encode(Object object) throws CoderException { + throw new CoderException(EXPECTED_EXCEPTION); + } + }; + } + }; + + assertThatIllegalArgumentException().isThrownBy(() -> oper.makeRequest(2)) + .withMessage("Cannot convert payload"); } @Test public void testGetExpectedKeyValues() { - Mockito.doCallRealMethod().when(operation).getExpectedKeyValues(1, mockInputWrapper); - Mockito.when(mockInputWrapper.getBody()).thenReturn(mockBody); - Mockito.when(mockBody.getInput()).thenReturn(mockInput); - Mockito.when(mockInput.getCommonHeader()).thenReturn(mockCommonHeader); - Mockito.when(mockCommonHeader.getSubRequestId()).thenReturn("sampleSubRequestId"); - - List<String> retList = operation.getExpectedKeyValues(1, mockInputWrapper); - assertNotNull(retList); - assertEquals(1, retList.size()); - - Mockito.verify(mockInputWrapper, atLeast(1)).getBody(); - Mockito.verify(mockBody, atLeast(1)).getInput(); - Mockito.verify(mockInput, atLeast(1)).getCommonHeader(); - Mockito.verify(mockCommonHeader, atLeast(1)).getSubRequestId(); + AppcLcmDmaapWrapper request = oper.makeRequest(2); + assertEquals(Arrays.asList(request.getBody().getInput().getCommonHeader().getSubRequestId()), + oper.getExpectedKeyValues(50, request)); } @Test public void testDetmStatus() { - Mockito.doCallRealMethod().when(operation).detmStatus("testResponse", mockOutputWrapper); - Mockito.when(mockOutputWrapper.getBody()).thenReturn(mockBody); - Mockito.when(mockBody.getOutput()).thenReturn(mockOutput); - Mockito.when(mockOutput.getStatus()).thenReturn(mockResponseStatus); - Mockito.when(mockResponseStatus.getCode()).thenReturn(100); - Status retStatus = operation.detmStatus("testResponse", mockOutputWrapper); - assertEquals(Status.STILL_WAITING, retStatus); - - Mockito.when(mockResponseStatus.getCode()).thenReturn(400); - retStatus = operation.detmStatus("testResponse", mockOutputWrapper); - assertEquals(Status.SUCCESS, retStatus); - - Mockito.when(mockResponseStatus.getCode()).thenReturn(450); - retStatus = operation.detmStatus("testResponse", mockOutputWrapper); - assertEquals(Status.FAILURE, retStatus); - - Mockito.when(mockOutput.getStatus()).thenReturn(null); - assertThatIllegalArgumentException().isThrownBy(() -> operation.detmStatus("testResponse", mockOutputWrapper)); - - Mockito.when(mockResponseStatus.getCode()).thenReturn(200); - assertThatIllegalArgumentException().isThrownBy(() -> operation.detmStatus("testResponse", mockOutputWrapper)); - - Mockito.verify(mockOutputWrapper, atLeast(1)).getBody(); - Mockito.verify(mockBody, atLeast(1)).getOutput(); - Mockito.verify(mockOutput, atLeast(1)).getStatus(); - Mockito.verify(mockResponseStatus, atLeast(1)).getCode(); + assertEquals(Status.SUCCESS, oper.detmStatus(null, response)); + + // failure + response.getBody().getOutput().getStatus().setCode(405); + assertEquals(Status.FAILURE, oper.detmStatus(null, response)); + + // error + response.getBody().getOutput().getStatus().setCode(200); + assertThatIllegalArgumentException().isThrownBy(() -> oper.detmStatus(null, response)); + + // reject + response.getBody().getOutput().getStatus().setCode(305); + assertThatIllegalArgumentException().isThrownBy(() -> oper.detmStatus(null, response)); + + // accepted + response.getBody().getOutput().getStatus().setCode(100); + assertEquals(Status.STILL_WAITING, oper.detmStatus(null, response)); + + // other + response.getBody().getOutput().getStatus().setCode(-1); + assertThatIllegalArgumentException().isThrownBy(() -> oper.detmStatus(null, response)); + + // null status + response.getBody().getOutput().setStatus(null); + assertThatIllegalArgumentException().isThrownBy(() -> oper.detmStatus(null, response)); } @Test public void testSetOutcome() { - Mockito.doCallRealMethod().when(operation).setOutcome(mockOperationOutcome, PolicyResult.SUCCESS, - mockOutputWrapper); - Mockito.doCallRealMethod().when(operation).setOutcome(mockOperationOutcome, PolicyResult.FAILURE, - mockOutputWrapper); - - Mockito.doCallRealMethod().when(mockOperationOutcome).setResult(any(PolicyResult.class)); - Mockito.doCallRealMethod().when(mockOperationOutcome).setMessage(any(String.class)); - Mockito.doCallRealMethod().when(mockOperationOutcome).getResult(); - Mockito.doCallRealMethod().when(mockOperationOutcome).getMessage(); - - Mockito.when(mockOutputWrapper.getBody()).thenReturn(mockBody); - Mockito.when(mockBody.getOutput()).thenReturn(mockOutput); - Mockito.when(mockOutput.getStatus()).thenReturn(mockResponseStatus); - Mockito.when(mockResponseStatus.getMessage()).thenReturn(null); - - OperationOutcome result = operation.setOutcome(mockOperationOutcome, PolicyResult.SUCCESS, mockOutputWrapper); - assertNull(result); - Mockito.verify(operation).setOutcome(mockOperationOutcome, PolicyResult.SUCCESS, mockOutputWrapper); - - Mockito.when(mockOutput.getStatus()).thenReturn(mockResponseStatus); - Mockito.when(mockResponseStatus.getMessage()).thenReturn("sampleMessage"); - result = operation.setOutcome(mockOperationOutcome, PolicyResult.FAILURE, mockOutputWrapper); - assertEquals(PolicyResult.FAILURE, result.getResult()); - assertNotNull(result.getMessage()); - - Mockito.verify(mockOutputWrapper, atLeast(1)).getBody(); - Mockito.verify(mockBody, atLeast(1)).getOutput(); - Mockito.verify(mockOutput, atLeast(1)).getStatus(); - Mockito.verify(mockResponseStatus, atLeast(1)).getMessage(); - Mockito.verify(operation, atLeast(1)).setOutcome(mockOperationOutcome, PolicyResult.SUCCESS, mockOutputWrapper); - Mockito.verify(operation, atLeast(1)).setOutcome(mockOperationOutcome, PolicyResult.FAILURE, mockOutputWrapper); + oper.setOutcome(outcome, PolicyResult.SUCCESS, response); + assertEquals(PolicyResult.SUCCESS, outcome.getResult()); + assertEquals(MY_MESSAGE, outcome.getMessage()); + + // failure + oper.setOutcome(outcome, PolicyResult.FAILURE, response); + assertEquals(PolicyResult.FAILURE, outcome.getResult()); + assertEquals(MY_MESSAGE, outcome.getMessage()); + + // null message + response.getBody().getOutput().getStatus().setMessage(null); + oper.setOutcome(outcome, PolicyResult.SUCCESS, response); + assertEquals(ControlLoopOperation.SUCCESS_MSG, outcome.getMessage()); + + // null status + response.getBody().getOutput().setStatus(null); + oper.setOutcome(outcome, PolicyResult.SUCCESS, response); + assertEquals(ControlLoopOperation.SUCCESS_MSG, outcome.getMessage()); + } + + @Test + public void testGetStatus() { + assertNotNull(oper.getStatus(response)); + + // null status + response.getBody().getOutput().setStatus(null); + assertNull(oper.getStatus(response)); + + // null outcome + response.getBody().setOutput(null); + assertNull(oper.getStatus(response)); + + // null body + response.setBody(null); + assertNull(oper.getStatus(response)); + + // null response + assertNull(oper.getStatus(null)); + } + + @Test + public void testOperationSupportsPayload() { + // these should support a payload + Set<String> supported = Set.of(AppcLcmConstants.OPERATION_CONFIG_MODIFY); + + for (String name : supported) { + params = params.toBuilder().operation(name).build(); + oper = new AppcLcmOperation(params, config); + assertTrue(name, oper.operationSupportsPayload()); + } + + // these should NOT support a payload + Set<String> unsupported = AppcLcmConstants.OPERATION_NAMES.stream().filter(name -> !supported.contains(name)) + .collect(Collectors.toSet()); + + for (String name : unsupported) { + params = params.toBuilder().operation(name).build(); + oper = new AppcLcmOperation(params, config); + assertFalse(name, oper.operationSupportsPayload()); + } + + // pick an operation that would ordinarily support payloads + String sup = supported.iterator().next(); + + // verify that it still supports payload + params = params.toBuilder().operation(sup).build(); + oper = new AppcLcmOperation(params, config); + assertTrue(oper.operationSupportsPayload()); + + // try with empty payload + params = params.toBuilder().payload(Map.of()).build(); + oper = new AppcLcmOperation(params, config); + assertFalse(oper.operationSupportsPayload()); + + // try with null payload + params = params.toBuilder().payload(null).build(); + oper = new AppcLcmOperation(params, config); + assertFalse(oper.operationSupportsPayload()); + } + + @Override + protected void makeContext() { + super.makeContext(); + + Target target = new Target(); + target.setResourceID(RESOURCE_ID); + + params = params.toBuilder().target(target).build(); } + @Override + protected Map<String, Object> makePayload() { + return Map.of(PAYLOAD_KEY1, PAYLOAD_VALUE1); + } + + private AppcLcmDmaapWrapper makeResponse() { + AppcLcmDmaapWrapper response = new AppcLcmDmaapWrapper(); + + AppcLcmBody body = new AppcLcmBody(); + response.setBody(body); + + AppcLcmOutput output = new AppcLcmOutput(); + body.setOutput(output); + + AppcLcmResponseStatus status = new AppcLcmResponseStatus(); + output.setStatus(status); + status.setMessage(MY_MESSAGE); + status.setCode(SUCCESS_CODE); + + return response; + } } |