diff options
author | Jim Hahn <jrh3@att.com> | 2020-02-18 12:25:37 -0500 |
---|---|---|
committer | Jim Hahn <jrh3@att.com> | 2020-02-19 12:45:30 -0500 |
commit | cbbc4a71ce71f22439b083107c65c22cc63bc9cc (patch) | |
tree | 5123d1b22ddd887d693b5007060cb3bdc7f0bad6 /models-interactions/model-actors | |
parent | 4ccc26577b51545b4b4db6823c6d926bc0ffc5a4 (diff) |
Add SO actor
Issue-ID: POLICY-2371
Signed-off-by: Jim Hahn <jrh3@att.com>
Change-Id: I3faf0276e8039dc43a976d18ff8e704fdbec3d49
Diffstat (limited to 'models-interactions/model-actors')
20 files changed, 1930 insertions, 57 deletions
diff --git a/models-interactions/model-actors/actor.so/pom.xml b/models-interactions/model-actors/actor.so/pom.xml index dd7bddc24..6d11c1367 100644 --- a/models-interactions/model-actors/actor.so/pom.xml +++ b/models-interactions/model-actors/actor.so/pom.xml @@ -18,63 +18,82 @@ ============LICENSE_END========================================================= --> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <modelVersion>4.0.0</modelVersion> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> - <parent> - <groupId>org.onap.policy.models.policy-models-interactions.model-actors</groupId> - <artifactId>model-actors</artifactId> - <version>2.2.1-SNAPSHOT</version> - </parent> + <parent> + <groupId>org.onap.policy.models.policy-models-interactions.model-actors</groupId> + <artifactId>model-actors</artifactId> + <version>2.2.1-SNAPSHOT</version> + </parent> - <artifactId>actor.so</artifactId> + <artifactId>actor.so</artifactId> - <dependencies> - <dependency> - <groupId>org.onap.policy.models.policy-models-interactions.model-actors</groupId> - <artifactId>actorServiceProvider</artifactId> - <version>${project.version}</version> - <scope>provided</scope> - </dependency> - <dependency> - <groupId>org.onap.policy.models.policy-models-interactions.model-impl</groupId> - <artifactId>aai</artifactId> - <version>${project.version}</version> - <scope>provided</scope> - </dependency> - <dependency> - <groupId>org.onap.policy.models.policy-models-interactions.model-impl</groupId> - <artifactId>events</artifactId> - <version>${project.version}</version> - <scope>provided</scope> - </dependency> - <dependency> - <groupId>org.onap.policy.models.policy-models-interactions.model-impl</groupId> - <artifactId>so</artifactId> - <version>${project.version}</version> - <scope>provided</scope> - </dependency> - <dependency> - <groupId>com.google.code.gson</groupId> - <artifactId>gson</artifactId> - <scope>provided</scope> - </dependency> - <dependency> - <groupId>org.onap.policy.common</groupId> - <artifactId>policy-endpoints</artifactId> - <version>${policy.common.version}</version> - <scope>provided</scope> - </dependency> - <dependency> - <groupId>junit</groupId> - <artifactId>junit</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.onap.policy.models.policy-models-interactions</groupId> - <artifactId>simulators</artifactId> - <version>${project.version}</version> - <scope>test</scope> - </dependency> - </dependencies> + <dependencies> + <dependency> + <groupId>org.onap.policy.models.policy-models-interactions.model-actors</groupId> + <artifactId>actorServiceProvider</artifactId> + <version>${project.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.onap.policy.models.policy-models-interactions.model-impl</groupId> + <artifactId>aai</artifactId> + <version>${project.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.onap.policy.models.policy-models-interactions.model-impl</groupId> + <artifactId>events</artifactId> + <version>${project.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.onap.policy.models.policy-models-interactions.model-impl</groupId> + <artifactId>so</artifactId> + <version>${project.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.onap.policy.models.policy-models-interactions.model-actors</groupId> + <artifactId>actor.aai</artifactId> + <version>${project.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>com.google.code.gson</groupId> + <artifactId>gson</artifactId> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.onap.policy.common</groupId> + <artifactId>policy-endpoints</artifactId> + <version>${policy.common.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.onap.policy.models.policy-models-interactions.model-actors</groupId> + <artifactId>actor.test</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.onap.policy.models.policy-models-interactions</groupId> + <artifactId>simulators</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.powermock</groupId> + <artifactId>powermock-api-mockito2</artifactId> + <scope>test</scope> + </dependency> + </dependencies> </project> diff --git a/models-interactions/model-actors/actor.so/src/main/java/org/onap/policy/controlloop/actor/so/SoActorParams.java b/models-interactions/model-actors/actor.so/src/main/java/org/onap/policy/controlloop/actor/so/SoActorParams.java new file mode 100644 index 000000000..3e82fe1a6 --- /dev/null +++ b/models-interactions/model-actors/actor.so/src/main/java/org/onap/policy/controlloop/actor/so/SoActorParams.java @@ -0,0 +1,56 @@ +/*- + * ============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.so; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; +import org.onap.policy.common.parameters.annotations.Min; +import org.onap.policy.controlloop.actorserviceprovider.parameters.HttpActorParams; + +@Getter +@Setter +@EqualsAndHashCode(callSuper = true) +public class SoActorParams extends HttpActorParams { + + /* + * Optional, default values that are used if missing from the operation-specific + * parameters. + */ + + /** + * Path to use for the "get" request. + */ + private String pathGet = "/orchestrationRequests/v5/"; + + /** + * Maximum number of "get" requests permitted, after the initial request, to retrieve + * the response. + */ + @Min(0) + private int maxGets = 20; + + /** + * Time, in seconds, to wait between issuing "get" requests. + */ + @Min(1) + private int waitSecGet = 20; +} diff --git a/models-interactions/model-actors/actor.so/src/main/java/org/onap/policy/controlloop/actor/so/SoActorServiceProvider.java b/models-interactions/model-actors/actor.so/src/main/java/org/onap/policy/controlloop/actor/so/SoActorServiceProvider.java index 51d14a2c0..c7c6b00e9 100644 --- a/models-interactions/model-actors/actor.so/src/main/java/org/onap/policy/controlloop/actor/so/SoActorServiceProvider.java +++ b/models-interactions/model-actors/actor.so/src/main/java/org/onap/policy/controlloop/actor/so/SoActorServiceProvider.java @@ -92,8 +92,13 @@ public class SoActorServiceProvider extends ActorImpl { // **HERE** + /** + * Constructs the object. + */ public SoActorServiceProvider() { super(NAME); + + addOperator(SoOperator.makeSoOperator(NAME, VfModuleCreate.NAME, VfModuleCreate::new)); } // TODO old code: remove lines down to **HERE** diff --git a/models-interactions/model-actors/actor.so/src/main/java/org/onap/policy/controlloop/actor/so/SoOperation.java b/models-interactions/model-actors/actor.so/src/main/java/org/onap/policy/controlloop/actor/so/SoOperation.java new file mode 100644 index 000000000..510a737a6 --- /dev/null +++ b/models-interactions/model-actors/actor.so/src/main/java/org/onap/policy/controlloop/actor/so/SoOperation.java @@ -0,0 +1,340 @@ +/*- + * ============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.so; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import java.util.function.Function; +import javax.ws.rs.core.Response; +import lombok.Getter; +import org.onap.aai.domain.yang.CloudRegion; +import org.onap.aai.domain.yang.GenericVnf; +import org.onap.aai.domain.yang.ServiceInstance; +import org.onap.aai.domain.yang.Tenant; +import org.onap.policy.aai.AaiCqResponse; +import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure; +import org.onap.policy.common.endpoints.utils.NetLoggerUtil.EventType; +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.actorserviceprovider.OperationOutcome; +import org.onap.policy.controlloop.actorserviceprovider.impl.HttpOperation; +import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams; +import org.onap.policy.controlloop.policy.PolicyResult; +import org.onap.policy.controlloop.policy.Target; +import org.onap.policy.so.SoModelInfo; +import org.onap.policy.so.SoRequest; +import org.onap.policy.so.SoRequestInfo; +import org.onap.policy.so.SoRequestParameters; +import org.onap.policy.so.SoRequestStatus; +import org.onap.policy.so.SoResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Superclass for SDNC Operators. Note: subclasses should invoke {@link #resetGetCount()} + * each time they issue an HTTP request. + */ +public abstract class SoOperation extends HttpOperation<SoResponse> { + private static final Logger logger = LoggerFactory.getLogger(SoOperation.class); + private static final Coder coder = new StandardCoder(); + + public static final String FAILED = "FAILED"; + public static final String COMPLETE = "COMPLETE"; + public static final int SO_RESPONSE_CODE = 999; + + // fields within the policy payload + public static final String REQ_PARAM_NM = "requestParameters"; + public static final String CONFIG_PARAM_NM = "configurationParameters"; + + @Getter + private final SoOperator operator; + + /** + * Number of "get" requests issued so far, on the current operation attempt. + */ + @Getter + private int getCount; + + + /** + * Constructs the object. + * + * @param params operation parameters + * @param operator operator that created this operation + */ + public SoOperation(ControlLoopOperationParams params, SoOperator operator) { + super(params, operator, SoResponse.class); + this.operator = operator; + } + + /** + * Subclasses should invoke this before issuing their first HTTP request. + */ + protected void resetGetCount() { + getCount = 0; + } + + /** + * Starts the GUARD. + */ + @Override + protected CompletableFuture<OperationOutcome> startPreprocessorAsync() { + return startGuardAsync(); + } + + /** + * If the response does not indicate that the request has been completed, then sleep a + * bit and issue a "get". + */ + @Override + protected CompletableFuture<OperationOutcome> postProcessResponse(OperationOutcome outcome, String url, + Response rawResponse, SoResponse response) { + + // see if the request has "completed", whether or not it was successful + if (rawResponse.getStatus() == 200) { + String requestState = getRequestState(response); + if (COMPLETE.equalsIgnoreCase(requestState)) { + return CompletableFuture + .completedFuture(setOutcome(outcome, PolicyResult.SUCCESS, rawResponse, response)); + } + + if (FAILED.equalsIgnoreCase(requestState)) { + return CompletableFuture + .completedFuture(setOutcome(outcome, PolicyResult.FAILURE, rawResponse, response)); + } + } + + // still incomplete + + // need a request ID with which to query + if (response.getRequestReferences() == null || response.getRequestReferences().getRequestId() == null) { + throw new IllegalArgumentException("missing request ID in response"); + } + + // see if the limit for the number of "gets" has been reached + if (getCount++ >= operator.getMaxGets()) { + logger.warn("{}: execeeded 'get' limit {} for {}", getFullName(), operator.getMaxGets(), + params.getRequestId()); + setOutcome(outcome, PolicyResult.FAILURE_TIMEOUT); + outcome.setMessage(SO_RESPONSE_CODE + " " + outcome.getMessage()); + return CompletableFuture.completedFuture(outcome); + } + + // sleep and then perform a "get" operation + Function<Void, CompletableFuture<OperationOutcome>> doGet = unused -> issueGet(outcome, response); + return sleep(getWaitMsGet(), TimeUnit.MILLISECONDS).thenComposeAsync(doGet); + } + + /** + * Issues a "get" request to see if the original request is complete yet. + * + * @param outcome outcome to be populated with the response + * @param response previous response + * @return a future that can be used to cancel the "get" request or await its response + */ + private CompletableFuture<OperationOutcome> issueGet(OperationOutcome outcome, SoResponse response) { + String path = operator.getPathGet() + response.getRequestReferences().getRequestId(); + String url = operator.getClient().getBaseUrl() + path; + + logger.debug("{}: 'get' count {} for {}", getFullName(), getCount, params.getRequestId()); + + logMessage(EventType.OUT, CommInfrastructure.REST, url, null); + + // TODO should this use "path" or the full "url"? + return handleResponse(outcome, url, callback -> operator.getClient().get(callback, path, null)); + } + + /** + * Gets the request state of a response. + * + * @param response response from which to get the state + * @return the request state of the response, or {@code null} if it does not exist + */ + protected String getRequestState(SoResponse response) { + SoRequest request = response.getRequest(); + if (request == null) { + return null; + } + + SoRequestStatus status = request.getRequestStatus(); + if (status == null) { + return null; + } + + return status.getRequestState(); + } + + /** + * Treats everything as a success, so we always go into + * {@link #postProcessResponse(OperationOutcome, String, Response, SoResponse)}. + */ + @Override + protected boolean isSuccess(Response rawResponse, SoResponse response) { + return true; + } + + /** + * Prepends the message with the http status code. + */ + @Override + public OperationOutcome setOutcome(OperationOutcome outcome, PolicyResult result, Response rawResponse, + SoResponse response) { + + // set default result and message + setOutcome(outcome, result); + + outcome.setMessage(rawResponse.getStatus() + " " + outcome.getMessage()); + return outcome; + } + + protected SoModelInfo prepareSoModelInfo() { + Target target = params.getTarget(); + if (target == null) { + throw new IllegalArgumentException("missing Target"); + } + + if (target.getModelCustomizationId() == null || target.getModelInvariantId() == null + || target.getModelName() == null || target.getModelVersion() == null + || target.getModelVersionId() == null) { + throw new IllegalArgumentException("missing VF Module model"); + } + + SoModelInfo soModelInfo = new SoModelInfo(); + soModelInfo.setModelCustomizationId(target.getModelCustomizationId()); + soModelInfo.setModelInvariantId(target.getModelInvariantId()); + soModelInfo.setModelName(target.getModelName()); + soModelInfo.setModelVersion(target.getModelVersion()); + soModelInfo.setModelVersionId(target.getModelVersionId()); + soModelInfo.setModelType("vfModule"); + return soModelInfo; + } + + /** + * Construct requestInfo for the SO requestDetails. + * + * @return SO request information + */ + protected SoRequestInfo constructRequestInfo() { + SoRequestInfo soRequestInfo = new SoRequestInfo(); + soRequestInfo.setSource("POLICY"); + soRequestInfo.setSuppressRollback(false); + soRequestInfo.setRequestorId("policy"); + return soRequestInfo; + } + + /** + * Builds the request parameters from the policy payload. + */ + protected SoRequestParameters buildRequestParameters() { + if (params.getPayload() == null) { + return null; + } + + String json = params.getPayload().get(REQ_PARAM_NM); + if (json == null) { + return null; + } + + try { + return coder.decode(json, SoRequestParameters.class); + } catch (CoderException e) { + throw new IllegalArgumentException("invalid payload value: " + REQ_PARAM_NM); + } + } + + /** + * Builds the configuration parameters from the policy payload. + */ + protected List<Map<String, String>> buildConfigurationParameters() { + if (params.getPayload() == null) { + return null; + } + + String json = params.getPayload().get(CONFIG_PARAM_NM); + if (json == null) { + return null; + } + + try { + @SuppressWarnings("unchecked") + List<Map<String, String>> result = coder.decode(json, ArrayList.class); + return result; + } catch (CoderException | RuntimeException e) { + throw new IllegalArgumentException("invalid payload value: " + CONFIG_PARAM_NM); + } + } + + /* + * These methods extract data from the Custom Query and throw an + * IllegalArgumentException if the desired data item is not found. + */ + + protected GenericVnf getVnfItem(AaiCqResponse aaiCqResponse, SoModelInfo soModelInfo) { + GenericVnf vnf = aaiCqResponse.getGenericVnfByVfModuleModelInvariantId(soModelInfo.getModelInvariantId()); + if (vnf == null) { + throw new IllegalArgumentException("missing generic VNF"); + } + + return vnf; + } + + protected ServiceInstance getServiceInstance(AaiCqResponse aaiCqResponse) { + ServiceInstance vnfService = aaiCqResponse.getServiceInstance(); + if (vnfService == null) { + throw new IllegalArgumentException("missing VNF Service Item"); + } + + return vnfService; + } + + protected Tenant getDefaultTenant(AaiCqResponse aaiCqResponse) { + Tenant tenant = aaiCqResponse.getDefaultTenant(); + if (tenant == null) { + throw new IllegalArgumentException("missing Tenant Item"); + } + + return tenant; + } + + protected CloudRegion getDefaultCloudRegion(AaiCqResponse aaiCqResponse) { + CloudRegion cloudRegion = aaiCqResponse.getDefaultCloudRegion(); + if (cloudRegion == null) { + throw new IllegalArgumentException("missing Cloud Region"); + } + + return cloudRegion; + } + + // these may be overridden by junit tests + + /** + * Gets the wait time, in milliseconds, between "get" requests. + * + * @return the wait time, in milliseconds, between "get" requests + */ + public long getWaitMsGet() { + return TimeUnit.MILLISECONDS.convert(operator.getWaitSecGet(), TimeUnit.SECONDS); + } +} diff --git a/models-interactions/model-actors/actor.so/src/main/java/org/onap/policy/controlloop/actor/so/SoOperator.java b/models-interactions/model-actors/actor.so/src/main/java/org/onap/policy/controlloop/actor/so/SoOperator.java new file mode 100644 index 000000000..011201f23 --- /dev/null +++ b/models-interactions/model-actors/actor.so/src/main/java/org/onap/policy/controlloop/actor/so/SoOperator.java @@ -0,0 +1,90 @@ +/*- + * ============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.so; + +import java.util.Map; +import java.util.function.BiFunction; +import lombok.Getter; +import org.onap.policy.common.parameters.ValidationResult; +import org.onap.policy.controlloop.actorserviceprovider.Operation; +import org.onap.policy.controlloop.actorserviceprovider.Util; +import org.onap.policy.controlloop.actorserviceprovider.impl.HttpOperator; +import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams; +import org.onap.policy.controlloop.actorserviceprovider.parameters.ParameterValidationRuntimeException; + +@Getter +public abstract class SoOperator extends HttpOperator { + + /** + * Path to use for the "get" request. A trailing "/" is added, if it is missing. + */ + private String pathGet; + + /** + * Maximum number of "get" requests permitted, after the initial request, to retrieve + * the response. + */ + private int maxGets; + + /** + * Time, in seconds, to wait between issuing "get" requests. + */ + private int waitSecGet; + + + public SoOperator(String actorName, String name) { + super(actorName, name); + } + + @Override + protected void doConfigure(Map<String, Object> parameters) { + SoParams params = Util.translate(getFullName(), parameters, SoParams.class); + ValidationResult result = params.validate(getFullName()); + if (!result.isValid()) { + throw new ParameterValidationRuntimeException("invalid parameters", result); + } + + this.pathGet = params.getPathGet() + (params.getPathGet().endsWith("/") ? "" : "/"); + this.maxGets = params.getMaxGets(); + this.waitSecGet = params.getWaitSecGet(); + + super.doConfigure(params); + } + + /** + * Makes an operator that will construct operations. + * + * @param actorName actor name + * @param operation operation name + * @param operationMaker function to make an operation + * @return a new operator + */ + public static SoOperator makeSoOperator(String actorName, String operation, + BiFunction<ControlLoopOperationParams, SoOperator, SoOperation> operationMaker) { + + return new SoOperator(actorName, operation) { + @Override + public Operation buildOperation(ControlLoopOperationParams params) { + return operationMaker.apply(params, this); + } + }; + } +} diff --git a/models-interactions/model-actors/actor.so/src/main/java/org/onap/policy/controlloop/actor/so/SoParams.java b/models-interactions/model-actors/actor.so/src/main/java/org/onap/policy/controlloop/actor/so/SoParams.java new file mode 100644 index 000000000..53f6e932f --- /dev/null +++ b/models-interactions/model-actors/actor.so/src/main/java/org/onap/policy/controlloop/actor/so/SoParams.java @@ -0,0 +1,55 @@ +/*- + * ============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.so; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.SuperBuilder; +import org.onap.policy.common.parameters.annotations.Min; +import org.onap.policy.common.parameters.annotations.NotBlank; +import org.onap.policy.common.parameters.annotations.NotNull; +import org.onap.policy.controlloop.actorserviceprovider.parameters.HttpParams; + +@NotNull +@NotBlank +@Data +@EqualsAndHashCode(callSuper = true) +@SuperBuilder(toBuilder = true) +public class SoParams extends HttpParams { + + /** + * Path to use for the "get" request. + */ + private String pathGet; + + /** + * Maximum number of "get" requests permitted, after the initial request, to retrieve + * the response. + */ + @Min(0) + private int maxGets; + + /** + * Time, in seconds, to wait between issuing "get" requests. + */ + @Min(1) + private int waitSecGet; +} diff --git a/models-interactions/model-actors/actor.so/src/main/java/org/onap/policy/controlloop/actor/so/VfModuleCreate.java b/models-interactions/model-actors/actor.so/src/main/java/org/onap/policy/controlloop/actor/so/VfModuleCreate.java new file mode 100644 index 000000000..f356dcefc --- /dev/null +++ b/models-interactions/model-actors/actor.so/src/main/java/org/onap/policy/controlloop/actor/so/VfModuleCreate.java @@ -0,0 +1,186 @@ +/*- + * ============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.so; + +import java.util.concurrent.CompletableFuture; +import javax.ws.rs.client.Entity; +import javax.ws.rs.core.MediaType; +import org.apache.commons.lang3.tuple.Pair; +import org.onap.aai.domain.yang.CloudRegion; +import org.onap.aai.domain.yang.GenericVnf; +import org.onap.aai.domain.yang.ServiceInstance; +import org.onap.aai.domain.yang.Tenant; +import org.onap.policy.aai.AaiConstants; +import org.onap.policy.aai.AaiCqResponse; +import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure; +import org.onap.policy.common.endpoints.utils.NetLoggerUtil.EventType; +import org.onap.policy.controlloop.actor.aai.AaiCustomQueryOperation; +import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome; +import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams; +import org.onap.policy.so.SoCloudConfiguration; +import org.onap.policy.so.SoModelInfo; +import org.onap.policy.so.SoOperationType; +import org.onap.policy.so.SoRelatedInstance; +import org.onap.policy.so.SoRelatedInstanceListElement; +import org.onap.policy.so.SoRequest; +import org.onap.policy.so.SoRequestDetails; +import org.onap.policy.so.SoRequestParameters; + +public class VfModuleCreate extends SoOperation { + public static final String NAME = "VF Module Create"; + + public VfModuleCreate(ControlLoopOperationParams params, SoOperator operator) { + super(params, operator); + } + + /** + * Ensures that A&AI customer query has been performed, and then runs the guard query. + */ + @Override + @SuppressWarnings("unchecked") + protected CompletableFuture<OperationOutcome> startPreprocessorAsync() { + ControlLoopOperationParams cqParams = params.toBuilder().actor(AaiConstants.ACTOR_NAME) + .operation(AaiCustomQueryOperation.NAME).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); + } + + @Override + protected CompletableFuture<OperationOutcome> startOperationAsync(int attempt, OperationOutcome outcome) { + + // starting a whole new attempt - reset the count + resetGetCount(); + + Pair<String, SoRequest> pair = makeRequest(); + String path = pair.getLeft(); + SoRequest request = pair.getRight(); + + Entity<SoRequest> entity = Entity.entity(request, MediaType.APPLICATION_JSON); + String url = getOperator().getClient().getBaseUrl() + path; + + logMessage(EventType.OUT, CommInfrastructure.REST, url, request); + + // TODO should this use "path" or the full "url"? + + return handleResponse(outcome, url, callback -> getOperator().getClient().post(callback, path, entity, null)); + } + + /** + * Makes a request. + * + * @return a pair containing the request URL and the new request + */ + protected Pair<String, SoRequest> makeRequest() { + final AaiCqResponse aaiCqResponse = params.getContext().getProperty(AaiCqResponse.CONTEXT_KEY); + final SoModelInfo soModelInfo = prepareSoModelInfo(); + final GenericVnf vnfItem = getVnfItem(aaiCqResponse, soModelInfo); + final ServiceInstance vnfServiceItem = getServiceInstance(aaiCqResponse); + final Tenant tenantItem = getDefaultTenant(aaiCqResponse); + final CloudRegion cloudRegionItem = getDefaultCloudRegion(aaiCqResponse); + + SoRequest request = new SoRequest(); + request.setOperationType(SoOperationType.SCALE_OUT); + + // + // + // Do NOT send SO the requestId, they do not support this field + // + request.setRequestDetails(new SoRequestDetails()); + request.getRequestDetails().setRequestParameters(new SoRequestParameters()); + request.getRequestDetails().getRequestParameters().setUserParams(null); + + // cloudConfiguration + request.getRequestDetails().setCloudConfiguration(constructCloudConfigurationCq(tenantItem, cloudRegionItem)); + + // modelInfo + request.getRequestDetails().setModelInfo(soModelInfo); + + // requestInfo + request.getRequestDetails().setRequestInfo(constructRequestInfo()); + request.getRequestDetails().getRequestInfo().setInstanceName("vfModuleName"); + + // relatedInstanceList + SoRelatedInstanceListElement relatedInstanceListElement1 = new SoRelatedInstanceListElement(); + SoRelatedInstanceListElement relatedInstanceListElement2 = new SoRelatedInstanceListElement(); + relatedInstanceListElement1.setRelatedInstance(new SoRelatedInstance()); + relatedInstanceListElement2.setRelatedInstance(new SoRelatedInstance()); + + // Service Item + relatedInstanceListElement1.getRelatedInstance().setInstanceId(vnfServiceItem.getServiceInstanceId()); + relatedInstanceListElement1.getRelatedInstance().setModelInfo(new SoModelInfo()); + relatedInstanceListElement1.getRelatedInstance().getModelInfo().setModelType("service"); + relatedInstanceListElement1.getRelatedInstance().getModelInfo() + .setModelInvariantId(vnfServiceItem.getModelInvariantId()); + relatedInstanceListElement1.getRelatedInstance().getModelInfo() + .setModelVersionId(vnfServiceItem.getModelVersionId()); + relatedInstanceListElement1.getRelatedInstance().getModelInfo().setModelName( + aaiCqResponse.getModelVerByVersionId(vnfServiceItem.getModelVersionId()).getModelName()); + relatedInstanceListElement1.getRelatedInstance().getModelInfo().setModelVersion( + aaiCqResponse.getModelVerByVersionId(vnfServiceItem.getModelVersionId()).getModelVersion()); + + // VNF Item + relatedInstanceListElement2.getRelatedInstance().setInstanceId(vnfItem.getVnfId()); + relatedInstanceListElement2.getRelatedInstance().setModelInfo(new SoModelInfo()); + relatedInstanceListElement2.getRelatedInstance().getModelInfo().setModelType("vnf"); + relatedInstanceListElement2.getRelatedInstance().getModelInfo() + .setModelInvariantId(vnfItem.getModelInvariantId()); + relatedInstanceListElement2.getRelatedInstance().getModelInfo().setModelVersionId(vnfItem.getModelVersionId()); + + relatedInstanceListElement2.getRelatedInstance().getModelInfo() + .setModelName(aaiCqResponse.getModelVerByVersionId(vnfItem.getModelVersionId()).getModelName()); + relatedInstanceListElement2.getRelatedInstance().getModelInfo().setModelVersion( + aaiCqResponse.getModelVerByVersionId(vnfItem.getModelVersionId()).getModelVersion()); + + relatedInstanceListElement2.getRelatedInstance().getModelInfo() + .setModelCustomizationId(vnfItem.getModelCustomizationId()); + + // Insert the Service Item and VNF Item + request.getRequestDetails().getRelatedInstanceList().add(relatedInstanceListElement1); + request.getRequestDetails().getRelatedInstanceList().add(relatedInstanceListElement2); + + // Request Parameters + request.getRequestDetails().setRequestParameters(buildRequestParameters()); + + // Configuration Parameters + request.getRequestDetails().setConfigurationParameters(buildConfigurationParameters()); + + // compute the path + String path = "/serviceInstantiation/v7/serviceInstances/" + vnfServiceItem.getServiceInstanceId() + "/vnfs/" + + vnfItem.getVnfId() + "/vfModules/scaleOut"; + + return Pair.of(path, request); + } + + /** + * Construct cloudConfiguration for the SO requestDetails. Overridden for custom + * query. + * + * @param tenantItem tenant item from A&AI named-query response + * @return SO cloud configuration + */ + private SoCloudConfiguration constructCloudConfigurationCq(Tenant tenantItem, CloudRegion cloudRegionItem) { + SoCloudConfiguration cloudConfiguration = new SoCloudConfiguration(); + cloudConfiguration.setTenantId(tenantItem.getTenantId()); + cloudConfiguration.setLcpCloudRegionId(cloudRegionItem.getCloudRegionId()); + return cloudConfiguration; + } +} diff --git a/models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/BasicSoOperation.java b/models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/BasicSoOperation.java new file mode 100644 index 000000000..089470420 --- /dev/null +++ b/models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/BasicSoOperation.java @@ -0,0 +1,144 @@ +/*- + * ============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.so; + +import static org.mockito.Mockito.when; + +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import org.mockito.Mock; +import org.onap.policy.controlloop.actor.test.BasicHttpOperation; +import org.onap.policy.controlloop.actorserviceprovider.Util; +import org.onap.policy.controlloop.policy.Target; +import org.onap.policy.so.SoRequest; +import org.onap.policy.so.SoRequestParameters; +import org.onap.policy.so.SoRequestReferences; +import org.onap.policy.so.SoRequestStatus; +import org.onap.policy.so.SoResponse; + +/** + * Superclass for various operator tests. + */ +public abstract class BasicSoOperation extends BasicHttpOperation<SoRequest> { + protected static final String[] IGNORE_FIELDS = {"RequestID", "subRequestID", "seconds", "nanos"}; + + public static final String MODEL_CUSTOM_ID = "my-model-customization-id"; + public static final String MODEL_INVAR_ID = "my-model-invariant-id"; + public static final String MODEL_NAME = "my-model-name"; + public static final String MODEL_VERSION = "my-model-version"; + public static final String MODEL_VERS_ID = "my-model-version-id"; + public static final String SUBSCRIPTION_SVC_TYPE = "my-subscription-service-type"; + public static final String PATH_GET = "my-path-get/"; + public static final int MAX_GETS = 3; + public static final int WAIT_SEC_GETS = 20; + + @Mock + protected SoOperator soOperator; + + protected Target target; + protected SoResponse response; + + /** + * Constructs the object using a default actor and operation name. + */ + public BasicSoOperation() { + super(); + } + + /** + * Constructs the object. + * + * @param actor actor name + * @param operation operation name + */ + public BasicSoOperation(String actor, String operation) { + super(actor, operation); + } + + /** + * Initializes mocks and sets up. + */ + public void setUp() throws Exception { + super.setUp(); + + response = new SoResponse(); + + SoRequest request = new SoRequest(); + response.setRequest(request); + + SoRequestStatus status = new SoRequestStatus(); + request.setRequestStatus(status); + status.setRequestState(SoOperation.COMPLETE); + + SoRequestReferences ref = new SoRequestReferences(); + response.setRequestReferences(ref); + ref.setRequestId(REQ_ID.toString()); + + when(rawResponse.getStatus()).thenReturn(200); + when(rawResponse.readEntity(String.class)).thenReturn(coder.encode(response)); + + operator = soOperator; + + initOperator(); + } + + @Override + protected void initOperator() { + super.initOperator(); + when(soOperator.getMaxGets()).thenReturn(MAX_GETS); + when(soOperator.getPathGet()).thenReturn(PATH_GET); + when(soOperator.getWaitSecGet()).thenReturn(WAIT_SEC_GETS); + } + + @Override + protected void makeContext() { + super.makeContext(); + + target = new Target(); + target.setModelCustomizationId(MODEL_CUSTOM_ID); + target.setModelInvariantId(MODEL_INVAR_ID); + target.setModelName(MODEL_NAME); + target.setModelVersion(MODEL_VERSION); + target.setModelVersionId(MODEL_VERS_ID); + + params = params.toBuilder().target(target).build(); + } + + @Override + protected Map<String, String> makePayload() { + Map<String, String> payload = new HashMap<>(); + + // request parameters + SoRequestParameters reqParams = new SoRequestParameters(); + reqParams.setSubscriptionServiceType(SUBSCRIPTION_SVC_TYPE); + payload.put(SoOperation.REQ_PARAM_NM, Util.translate("", reqParams, String.class)); + + // config parameters + List<Map<String, String>> config = new LinkedList<>(); + config.add(Collections.emptyMap()); + payload.put(SoOperation.CONFIG_PARAM_NM, Util.translate("", config, String.class)); + + return payload; + } +} diff --git a/models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/SoActorParamsTest.java b/models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/SoActorParamsTest.java new file mode 100644 index 000000000..f463fcb94 --- /dev/null +++ b/models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/SoActorParamsTest.java @@ -0,0 +1,116 @@ +/*- + * ============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.so; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.Map; +import java.util.TreeMap; +import java.util.function.Consumer; +import org.junit.Before; +import org.junit.Test; +import org.onap.policy.common.parameters.ValidationResult; +import org.onap.policy.controlloop.actorserviceprovider.Util; + + +public class SoActorParamsTest { + private static final String CONTAINER = "my-container"; + private static final String CLIENT = "my-client"; + private static final String PATH_GET = "my-path-get"; + private static final int MAX_GETS = 3; + private static final int WAIT_SEC_GETS = 20; + private static final int TIMEOUT = 10; + + private static final String PATH1 = "path #1"; + private static final String PATH2 = "path #2"; + private static final String URI1 = "uri #1"; + private static final String URI2 = "uri #2"; + + private Map<String, Map<String, Object>> operations; + private SoActorParams params; + + /** + * Initializes {@link #operations} with two items and {@link params} with a fully + * populated object. + */ + @Before + public void setUp() { + operations = new TreeMap<>(); + operations.put(PATH1, Map.of("path", URI1)); + operations.put(PATH2, Map.of("path", URI2)); + + params = makeSoActorParams(); + } + + @Test + public void testValidate() { + assertTrue(params.validate(CONTAINER).isValid()); + + // only a few fields are required + SoActorParams sparse = Util.translate(CONTAINER, Map.of("operation", operations), SoActorParams.class); + assertTrue(sparse.validate(CONTAINER).isValid()); + + testValidateField("maxGets", "minimum", params2 -> params2.setMaxGets(-1)); + testValidateField("waitSecGet", "minimum", params2 -> params2.setWaitSecGet(0)); + + // check fields from superclass + testValidateField("operation", "null", params2 -> params2.setOperation(null)); + testValidateField("timeoutSec", "minimum", params2 -> params2.setTimeoutSec(-1)); + + // check edge cases + params.setMaxGets(0); + assertTrue(params.validate(CONTAINER).isValid()); + params.setMaxGets(MAX_GETS); + + params.setWaitSecGet(1); + assertTrue(params.validate(CONTAINER).isValid()); + params.setWaitSecGet(WAIT_SEC_GETS); + } + + private void testValidateField(String fieldName, String expected, Consumer<SoActorParams> makeInvalid) { + + // original params should be valid + ValidationResult result = params.validate(CONTAINER); + assertTrue(fieldName, result.isValid()); + + // make invalid params + SoActorParams params2 = makeSoActorParams(); + makeInvalid.accept(params2); + result = params2.validate(CONTAINER); + assertFalse(fieldName, result.isValid()); + assertThat(result.getResult()).contains(CONTAINER).contains(fieldName).contains(expected); + } + + private SoActorParams makeSoActorParams() { + SoActorParams params2 = new SoActorParams(); + params2.setClientName(CLIENT); + params2.setTimeoutSec(TIMEOUT); + params2.setOperation(operations); + + params2.setWaitSecGet(WAIT_SEC_GETS); + params2.setMaxGets(MAX_GETS); + params2.setPathGet(PATH_GET); + + return params2; + } +} diff --git a/models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/SoActorServiceProviderTest.java b/models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/SoActorServiceProviderTest.java index b46ac52fb..a9d5b8192 100644 --- a/models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/SoActorServiceProviderTest.java +++ b/models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/SoActorServiceProviderTest.java @@ -29,11 +29,13 @@ import static org.junit.Assert.assertNull; import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.util.Arrays; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.TreeMap; import java.util.UUID; +import java.util.stream.Collectors; import org.apache.commons.io.IOUtils; import org.junit.Test; import org.onap.policy.aai.AaiCqResponse; @@ -66,6 +68,17 @@ public class SoActorServiceProviderTest { } @Test + public void testConstructor() { + SoActorServiceProvider prov = new SoActorServiceProvider(); + + // verify that it has the operators we expect + var expected = Arrays.asList(VfModuleCreate.NAME).stream().sorted().collect(Collectors.toList()); + var actual = prov.getOperationNames().stream().sorted().collect(Collectors.toList()); + + assertEquals(expected.toString(), actual.toString()); + } + + @Test public void testSendRequest() { SoActorServiceProvider.sendRequest(UUID.randomUUID().toString(), null, null, null, null, null); } diff --git a/models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/SoOperationTest.java b/models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/SoOperationTest.java new file mode 100644 index 000000000..e70413876 --- /dev/null +++ b/models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/SoOperationTest.java @@ -0,0 +1,353 @@ +/*- + * ============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.so; + +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +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.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Consumer; +import java.util.function.Supplier; +import org.junit.Before; +import org.junit.Test; +import org.onap.aai.domain.yang.CloudRegion; +import org.onap.aai.domain.yang.GenericVnf; +import org.onap.aai.domain.yang.ServiceInstance; +import org.onap.aai.domain.yang.Tenant; +import org.onap.policy.aai.AaiCqResponse; +import org.onap.policy.common.utils.coder.CoderException; +import org.onap.policy.controlloop.ControlLoopOperation; +import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome; +import org.onap.policy.controlloop.policy.PolicyResult; +import org.onap.policy.so.SoModelInfo; +import org.onap.policy.so.SoRequest; +import org.onap.policy.so.SoRequestInfo; +import org.onap.policy.so.SoRequestParameters; +import org.onap.policy.so.SoRequestReferences; +import org.onap.policy.so.SoRequestStatus; +import org.onap.policy.so.SoResponse; + +public class SoOperationTest extends BasicSoOperation { + + private SoOperation oper; + + /** + * Sets up. + */ + @Before + public void setUp() throws Exception { + super.setUp(); + + initOperator(); + + oper = new SoOperation(params, soOperator) {}; + } + + @Test + public void testConstructor_testGetWaitMsGet() { + assertEquals(DEFAULT_ACTOR, oper.getActorName()); + assertEquals(DEFAULT_OPERATION, oper.getName()); + assertSame(soOperator, oper.getOperator()); + assertEquals(1000 * WAIT_SEC_GETS, oper.getWaitMsGet()); + } + + @Test + public void testStartPreprocessorAsync() { + AtomicBoolean guardStarted = new AtomicBoolean(); + + oper = new SoOperation(params, soOperator) { + @Override + protected CompletableFuture<OperationOutcome> startGuardAsync() { + guardStarted.set(true); + return super.startGuardAsync(); + } + }; + + assertNull(oper.startPreprocessorAsync()); + assertTrue(guardStarted.get()); + } + + @Test + public void testPostProcess() throws Exception { + // completed + CompletableFuture<OperationOutcome> future2 = oper.postProcessResponse(outcome, PATH, rawResponse, response); + assertTrue(future2.isDone()); + assertSame(outcome, future2.get()); + assertEquals(PolicyResult.SUCCESS, outcome.getResult()); + + // failed + response.getRequest().getRequestStatus().setRequestState(SoOperation.FAILED); + future2 = oper.postProcessResponse(outcome, PATH, rawResponse, response); + assertTrue(future2.isDone()); + assertSame(outcome, future2.get()); + assertEquals(PolicyResult.FAILURE, outcome.getResult()); + + // no request id in the response + response.getRequestReferences().setRequestId(null); + response.getRequest().getRequestStatus().setRequestState("unknown"); + assertThatIllegalArgumentException() + .isThrownBy(() -> oper.postProcessResponse(outcome, PATH, rawResponse, response)) + .withMessage("missing request ID in response"); + response.getRequestReferences().setRequestId(REQ_ID.toString()); + + // status = 500 + when(rawResponse.getStatus()).thenReturn(500); + + // null request reference + SoRequestReferences ref = response.getRequestReferences(); + response.setRequestReferences(null); + assertThatIllegalArgumentException() + .isThrownBy(() -> oper.postProcessResponse(outcome, PATH, rawResponse, response)) + .withMessage("missing request ID in response"); + response.setRequestReferences(ref); + } + + /** + * Tests postProcess() when the "get" is repeated a couple of times. + */ + @Test + public void testPostProcessRepeated_testResetGetCount() throws Exception { + /* + * Two failures and then a success - should result in two "get" calls. + * + * Note: getStatus() is invoked twice during each call, so have to double up the + * return values. + */ + when(rawResponse.getStatus()).thenReturn(500, 500, 500, 500, 200, 200); + + when(client.get(any(), any(), any())).thenAnswer(provideResponse(rawResponse)); + + // use a real executor + params = params.toBuilder().executor(ForkJoinPool.commonPool()).build(); + + oper = new SoOperation(params, soOperator) { + @Override + public long getWaitMsGet() { + return 1; + } + }; + + CompletableFuture<OperationOutcome> future2 = oper.postProcessResponse(outcome, PATH, rawResponse, response); + + assertSame(outcome, future2.get(5, TimeUnit.SECONDS)); + assertEquals(PolicyResult.SUCCESS, outcome.getResult()); + assertEquals(2, oper.getGetCount()); + + /* + * repeat - this time, the "get" operations will be exhausted, so it should fail + */ + when(rawResponse.getStatus()).thenReturn(500); + + future2 = oper.postProcessResponse(outcome, PATH, rawResponse, response); + + assertSame(outcome, future2.get(5, TimeUnit.SECONDS)); + assertEquals(PolicyResult.FAILURE_TIMEOUT, outcome.getResult()); + assertEquals(MAX_GETS + 1, oper.getGetCount()); + + oper.resetGetCount(); + assertEquals(0, oper.getGetCount()); + } + + @Test + public void testGetRequestState() { + SoResponse resp = new SoResponse(); + assertNull(oper.getRequestState(resp)); + + SoRequest req = new SoRequest(); + resp.setRequest(req); + assertNull(oper.getRequestState(resp)); + + SoRequestStatus status = new SoRequestStatus(); + req.setRequestStatus(status); + assertNull(oper.getRequestState(resp)); + + status.setRequestState("my-state"); + assertEquals("my-state", oper.getRequestState(resp)); + } + + @Test + public void testIsSuccess() { + // always true + + assertTrue(oper.isSuccess(rawResponse, response)); + + when(rawResponse.getStatus()).thenReturn(500); + assertTrue(oper.isSuccess(rawResponse, response)); + } + + @Test + public void testSetOutcome() { + // success case + when(rawResponse.getStatus()).thenReturn(200); + assertSame(outcome, oper.setOutcome(outcome, PolicyResult.SUCCESS, rawResponse, response)); + + assertEquals(PolicyResult.SUCCESS, outcome.getResult()); + assertEquals("200 " + ControlLoopOperation.SUCCESS_MSG, outcome.getMessage()); + + // failure case + when(rawResponse.getStatus()).thenReturn(500); + assertSame(outcome, oper.setOutcome(outcome, PolicyResult.FAILURE, rawResponse, response)); + + assertEquals(PolicyResult.FAILURE, outcome.getResult()); + assertEquals("500 " + ControlLoopOperation.FAILED_MSG, outcome.getMessage()); + } + + @Test + public void testPrepareSoModelInfo() throws CoderException { + verifyMissingModelInfo(target::getModelCustomizationId, target::setModelCustomizationId); + verifyMissingModelInfo(target::getModelInvariantId, target::setModelInvariantId); + verifyMissingModelInfo(target::getModelName, target::setModelName); + verifyMissingModelInfo(target::getModelVersion, target::setModelVersion); + verifyMissingModelInfo(target::getModelVersionId, target::setModelVersionId); + + // valid data + SoModelInfo info = oper.prepareSoModelInfo(); + verifyRequest("model.json", info); + + // try with null target + params = params.toBuilder().target(null).build(); + oper = new SoOperation(params, soOperator) {}; + + assertThatIllegalArgumentException().isThrownBy(() -> oper.prepareSoModelInfo()).withMessage("missing Target"); + } + + private void verifyMissingModelInfo(Supplier<String> getter, Consumer<String> setter) { + String original = getter.get(); + + setter.accept(null); + assertThatIllegalArgumentException().isThrownBy(() -> oper.prepareSoModelInfo()) + .withMessage("missing VF Module model"); + + setter.accept(original); + } + + @Test + public void testConstructRequestInfo() throws CoderException { + SoRequestInfo info = oper.constructRequestInfo(); + verifyRequest("reqinfo.json", info); + } + + @Test + public void testBuildRequestParameters() throws CoderException { + // valid data + SoRequestParameters reqParams = oper.buildRequestParameters(); + verifyRequest("reqparams.json", reqParams); + + // invalid json + params.getPayload().put(SoOperation.REQ_PARAM_NM, "{invalid json"); + assertThatIllegalArgumentException().isThrownBy(() -> oper.buildRequestParameters()) + .withMessage("invalid payload value: " + SoOperation.REQ_PARAM_NM); + + // missing data + params.getPayload().remove(SoOperation.REQ_PARAM_NM); + assertNull(oper.buildRequestParameters()); + + // null payload + params = params.toBuilder().payload(null).build(); + oper = new SoOperation(params, soOperator) {}; + assertNull(oper.buildRequestParameters()); + } + + @Test + public void testBuildConfigurationParameters() { + // valid data + List<Map<String, String>> result = oper.buildConfigurationParameters(); + assertEquals(List.of(Collections.emptyMap()), result); + + // invalid json + params.getPayload().put(SoOperation.CONFIG_PARAM_NM, "{invalid json"); + assertThatIllegalArgumentException().isThrownBy(() -> oper.buildConfigurationParameters()) + .withMessage("invalid payload value: " + SoOperation.CONFIG_PARAM_NM); + + // missing data + params.getPayload().remove(SoOperation.CONFIG_PARAM_NM); + assertNull(oper.buildConfigurationParameters()); + + // null payload + params = params.toBuilder().payload(null).build(); + oper = new SoOperation(params, soOperator) {}; + assertNull(oper.buildConfigurationParameters()); + } + + @Test + public void testGetVnfItem() { + // missing data + AaiCqResponse cq = mock(AaiCqResponse.class); + assertThatIllegalArgumentException().isThrownBy(() -> oper.getVnfItem(cq, oper.prepareSoModelInfo())) + .withMessage("missing generic VNF"); + + // valid data + GenericVnf vnf = new GenericVnf(); + when(cq.getGenericVnfByVfModuleModelInvariantId(MODEL_INVAR_ID)).thenReturn(vnf); + assertSame(vnf, oper.getVnfItem(cq, oper.prepareSoModelInfo())); + } + + @Test + public void testGetServiceInstance() { + // missing data + AaiCqResponse cq = mock(AaiCqResponse.class); + assertThatIllegalArgumentException().isThrownBy(() -> oper.getServiceInstance(cq)) + .withMessage("missing VNF Service Item"); + + // valid data + ServiceInstance instance = new ServiceInstance(); + when(cq.getServiceInstance()).thenReturn(instance); + assertSame(instance, oper.getServiceInstance(cq)); + } + + @Test + public void testGetDefaultTenant() { + // missing data + AaiCqResponse cq = mock(AaiCqResponse.class); + assertThatIllegalArgumentException().isThrownBy(() -> oper.getDefaultTenant(cq)) + .withMessage("missing Tenant Item"); + + // valid data + Tenant tenant = new Tenant(); + when(cq.getDefaultTenant()).thenReturn(tenant); + assertSame(tenant, oper.getDefaultTenant(cq)); + } + + @Test + public void testGetDefaultCloudRegion() { + // missing data + AaiCqResponse cq = mock(AaiCqResponse.class); + assertThatIllegalArgumentException().isThrownBy(() -> oper.getDefaultCloudRegion(cq)) + .withMessage("missing Cloud Region"); + + // valid data + CloudRegion region = new CloudRegion(); + when(cq.getDefaultCloudRegion()).thenReturn(region); + assertSame(region, oper.getDefaultCloudRegion(cq)); + } +} diff --git a/models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/SoOperatorTest.java b/models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/SoOperatorTest.java new file mode 100644 index 000000000..16bbdea2a --- /dev/null +++ b/models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/SoOperatorTest.java @@ -0,0 +1,146 @@ +/*- + * ============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.so; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertSame; +import static org.mockito.Mockito.when; + +import java.util.Map; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.onap.policy.common.endpoints.http.client.HttpClient; +import org.onap.policy.common.endpoints.http.client.HttpClientFactory; +import org.onap.policy.controlloop.VirtualControlLoopEvent; +import org.onap.policy.controlloop.actorserviceprovider.Operation; +import org.onap.policy.controlloop.actorserviceprovider.Util; +import org.onap.policy.controlloop.actorserviceprovider.controlloop.ControlLoopEventContext; +import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams; +import org.onap.policy.controlloop.actorserviceprovider.parameters.ParameterValidationRuntimeException; + +public class SoOperatorTest { + private static final String ACTOR = "my-actor"; + private static final String OPERATION = "my-name"; + private static final String CLIENT = "my-client"; + private static final String PATH = "/my-path"; + private static final String PATH_GET = "my-path-get/"; + private static final int MAX_GETS = 3; + private static final int WAIT_SEC_GETS = 20; + private static final int TIMEOUT = 100; + + @Mock + private HttpClient client; + + @Mock + private HttpClientFactory factory; + + + private SoOperator oper; + + /** + * Initializes fields, including {@link #oper}, and resets the static fields used by + * the REST server. + */ + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + when(factory.get(CLIENT)).thenReturn(client); + + oper = new MyOperator(); + + SoParams params = SoParams.builder().pathGet(PATH_GET).maxGets(MAX_GETS).waitSecGet(WAIT_SEC_GETS) + .clientName(CLIENT).path(PATH).timeoutSec(TIMEOUT).build(); + Map<String, Object> paramMap = Util.translateToMap(OPERATION, params); + oper.configure(paramMap); + } + + @Test + public void testConstructor() { + assertEquals(ACTOR, oper.getActorName()); + assertEquals(OPERATION, oper.getName()); + assertEquals(ACTOR + "." + OPERATION, oper.getFullName()); + } + + @Test + public void testMakeSoOperator() { + oper = SoOperator.makeSoOperator(ACTOR, OPERATION, MyOperation::new); + + VirtualControlLoopEvent event = new VirtualControlLoopEvent(); + ControlLoopEventContext context = new ControlLoopEventContext(event); + ControlLoopOperationParams params = + ControlLoopOperationParams.builder().actor(ACTOR).operation(OPERATION).context(context).build(); + + Operation operation1 = oper.buildOperation(params); + assertNotNull(operation1); + + Operation operation2 = oper.buildOperation(params); + assertNotNull(operation2); + assertNotSame(operation1, operation2); + } + + @Test + public void testDoConfigure_testGetters() { + // should use given values + assertSame(client, oper.getClient()); + assertEquals(PATH_GET, oper.getPathGet()); + assertEquals(MAX_GETS, oper.getMaxGets()); + assertEquals(WAIT_SEC_GETS, oper.getWaitSecGet()); + + SoParams params = SoParams.builder().pathGet("unslashed").maxGets(MAX_GETS).waitSecGet(WAIT_SEC_GETS) + .clientName(CLIENT).path(PATH).timeoutSec(TIMEOUT).build(); + Map<String, Object> paramMap = Util.translateToMap(OPERATION, params); + oper.configure(paramMap); + assertEquals("unslashed/", oper.getPathGet()); + + // test invalid parameters + Map<String, Object> paramMap2 = Util.translateToMap(OPERATION, SoParams.builder().build()); + assertThatThrownBy(() -> oper.configure(paramMap2)).isInstanceOf(ParameterValidationRuntimeException.class); + } + + + private class MyOperator extends SoOperator { + public MyOperator() { + super(ACTOR, OPERATION); + } + + @Override + public Operation buildOperation(ControlLoopOperationParams params) { + return null; + } + + @Override + protected HttpClientFactory getClientFactory() { + return factory; + } + } + + private class MyOperation extends SoOperation { + public MyOperation(ControlLoopOperationParams params, SoOperator operator) { + super(params, operator); + } + } +} diff --git a/models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/SoParamsTest.java b/models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/SoParamsTest.java new file mode 100644 index 000000000..2b02ad8ff --- /dev/null +++ b/models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/SoParamsTest.java @@ -0,0 +1,92 @@ +/*- + * ============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.so; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.function.Function; +import org.junit.Before; +import org.junit.Test; +import org.onap.policy.common.parameters.ValidationResult; +import org.onap.policy.controlloop.actor.so.SoParams.SoParamsBuilder; +import org.onap.policy.controlloop.actorserviceprovider.parameters.HttpParams.HttpParamsBuilder; + +public class SoParamsTest { + private static final String CONTAINER = "my-container"; + private static final String CLIENT = "my-client"; + private static final String PATH = "my-path"; + private static final String PATH_GET = "my-path-get"; + private static final int MAX_GETS = 3; + private static final int WAIT_SEC_GETS = 20; + private static final int TIMEOUT = 10; + + private SoParams params; + + @Before + public void setUp() { + params = SoParams.builder().pathGet(PATH_GET).maxGets(MAX_GETS).waitSecGet(WAIT_SEC_GETS).clientName(CLIENT) + .path(PATH).timeoutSec(TIMEOUT).build(); + } + + @Test + public void testValidate() { + assertTrue(params.validate(CONTAINER).isValid()); + + testValidateField("pathGet", "null", bldr -> bldr.pathGet(null)); + testValidateField("maxGets", "minimum", bldr -> bldr.maxGets(-1)); + testValidateField("waitSecGet", "minimum", bldr -> bldr.waitSecGet(-1)); + + // validate one of the superclass fields + testValidateField("clientName", "null", bldr -> bldr.clientName(null)); + + // check edge cases + assertTrue(params.toBuilder().maxGets(0).build().validate(CONTAINER).isValid()); + assertFalse(params.toBuilder().waitSecGet(0).build().validate(CONTAINER).isValid()); + assertTrue(params.toBuilder().waitSecGet(1).build().validate(CONTAINER).isValid()); + } + + @Test + public void testBuilder_testToBuilder() { + assertEquals(CLIENT, params.getClientName()); + + assertEquals(PATH_GET, params.getPathGet()); + assertEquals(MAX_GETS, params.getMaxGets()); + assertEquals(WAIT_SEC_GETS, params.getWaitSecGet()); + + assertEquals(params, params.toBuilder().build()); + } + + private void testValidateField(String fieldName, String expected, + @SuppressWarnings("rawtypes") Function<SoParamsBuilder, HttpParamsBuilder> makeInvalid) { + + // original params should be valid + ValidationResult result = params.validate(CONTAINER); + assertTrue(fieldName, result.isValid()); + + // make invalid params + result = makeInvalid.apply(params.toBuilder()).build().validate(CONTAINER); + assertFalse(fieldName, result.isValid()); + assertThat(result.getResult()).contains(fieldName).contains(expected); + } +} diff --git a/models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/VfModuleCreateTest.java b/models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/VfModuleCreateTest.java new file mode 100644 index 000000000..40efdc880 --- /dev/null +++ b/models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/VfModuleCreateTest.java @@ -0,0 +1,182 @@ +/*- + * ============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.so; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import org.apache.commons.lang3.tuple.Pair; +import org.junit.Before; +import org.junit.Test; +import org.onap.aai.domain.yang.CloudRegion; +import org.onap.aai.domain.yang.GenericVnf; +import org.onap.aai.domain.yang.ModelVer; +import org.onap.aai.domain.yang.ServiceInstance; +import org.onap.aai.domain.yang.Tenant; +import org.onap.policy.aai.AaiCqResponse; +import org.onap.policy.common.utils.coder.CoderException; +import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome; +import org.onap.policy.controlloop.actorserviceprovider.controlloop.ControlLoopEventContext; +import org.onap.policy.controlloop.policy.PolicyResult; +import org.onap.policy.so.SoRequest; + +public class VfModuleCreateTest extends BasicSoOperation { + private static final String MODEL_NAME2 = "my-model-name-B"; + private static final String MODEL_VERS2 = "my-model-version-B"; + private static final String SVC_INSTANCE_ID = "my-service-instance-id"; + private static final String VNF_ID = "my-vnf-id"; + + private VfModuleCreate oper; + + public VfModuleCreateTest() { + super(DEFAULT_ACTOR, VfModuleCreate.NAME); + } + + + @Before + public void setUp() throws Exception { + super.setUp(); + oper = new VfModuleCreate(params, soOperator); + } + + @Test + public void testConstructor() { + assertEquals(DEFAULT_ACTOR, oper.getActorName()); + assertEquals(VfModuleCreate.NAME, oper.getName()); + } + + @Test + public void testStartPreprocessorAsync() { + CompletableFuture<OperationOutcome> future = new CompletableFuture<>(); + context = mock(ControlLoopEventContext.class); + when(context.obtain(eq(AaiCqResponse.CONTEXT_KEY), any())).thenReturn(future); + params = params.toBuilder().context(context).build(); + + AtomicBoolean guardStarted = new AtomicBoolean(); + + oper = new VfModuleCreate(params, soOperator) { + @Override + protected CompletableFuture<OperationOutcome> startGuardAsync() { + guardStarted.set(true); + return super.startGuardAsync(); + } + }; + + assertSame(future, oper.startPreprocessorAsync()); + assertFalse(future.isDone()); + assertTrue(guardStarted.get()); + } + + @Test + public void testStartOperationAsync() throws Exception { + when(client.post(any(), any(), any(), any())).thenAnswer(provideResponse(rawResponse)); + + // use a real executor + params = params.toBuilder().executor(ForkJoinPool.commonPool()).build(); + + oper = new VfModuleCreate(params, soOperator) { + @Override + public long getWaitMsGet() { + return 1; + } + }; + + CompletableFuture<OperationOutcome> future2 = oper.start(); + + outcome = future2.get(500, TimeUnit.SECONDS); + assertEquals(PolicyResult.SUCCESS, outcome.getResult()); + } + + /** + * Tests startOperationAsync() when "get" operations are required. + */ + @Test + public void testStartOperationAsyncWithGets() throws Exception { + when(rawResponse.getStatus()).thenReturn(500, 500, 500, 500, 200, 200); + + when(client.post(any(), any(), any(), any())).thenAnswer(provideResponse(rawResponse)); + when(client.get(any(), any(), any())).thenAnswer(provideResponse(rawResponse)); + + // use a real executor + params = params.toBuilder().executor(ForkJoinPool.commonPool()).build(); + + oper = new VfModuleCreate(params, soOperator) { + @Override + public long getWaitMsGet() { + return 1; + } + }; + + CompletableFuture<OperationOutcome> future2 = oper.start(); + + outcome = future2.get(500, TimeUnit.SECONDS); + assertEquals(PolicyResult.SUCCESS, outcome.getResult()); + } + + @Test + public void testMakeRequest() throws CoderException { + Pair<String, SoRequest> pair = oper.makeRequest(); + + // @formatter:off + assertEquals( + "/serviceInstantiation/v7/serviceInstances/my-service-instance-id/vnfs/my-vnf-id/vfModules/scaleOut", + pair.getLeft()); + // @formatter:on + + verifyRequest("vfModuleCreate.json", pair.getRight()); + } + + + @Override + protected void makeContext() { + super.makeContext(); + + AaiCqResponse cq = mock(AaiCqResponse.class); + + GenericVnf vnf = new GenericVnf(); + when(cq.getGenericVnfByVfModuleModelInvariantId(MODEL_INVAR_ID)).thenReturn(vnf); + vnf.setVnfId(VNF_ID); + + ServiceInstance instance = new ServiceInstance(); + when(cq.getServiceInstance()).thenReturn(instance); + instance.setServiceInstanceId(SVC_INSTANCE_ID); + + when(cq.getDefaultTenant()).thenReturn(new Tenant()); + when(cq.getDefaultCloudRegion()).thenReturn(new CloudRegion()); + + ModelVer modelVers = new ModelVer(); + when(cq.getModelVerByVersionId(any())).thenReturn(modelVers); + modelVers.setModelName(MODEL_NAME2); + modelVers.setModelVersion(MODEL_VERS2); + + params.getContext().setProperty(AaiCqResponse.CONTEXT_KEY, cq); + } +} diff --git a/models-interactions/model-actors/actor.so/src/test/resources/model.json b/models-interactions/model-actors/actor.so/src/test/resources/model.json new file mode 100644 index 000000000..133b0fe91 --- /dev/null +++ b/models-interactions/model-actors/actor.so/src/test/resources/model.json @@ -0,0 +1,8 @@ +{ + "modelType": "vfModule", + "modelInvariantId": "my-model-invariant-id", + "modelVersionId": "my-model-version-id", + "modelName": "my-model-name", + "modelVersion": "my-model-version", + "modelCustomizationId": "my-model-customization-id" +}
\ No newline at end of file diff --git a/models-interactions/model-actors/actor.so/src/test/resources/reqinfo.json b/models-interactions/model-actors/actor.so/src/test/resources/reqinfo.json new file mode 100644 index 000000000..62d6eb1e6 --- /dev/null +++ b/models-interactions/model-actors/actor.so/src/test/resources/reqinfo.json @@ -0,0 +1,5 @@ +{ + "source": "POLICY", + "suppressRollback": false, + "requestorId": "policy" +}
\ No newline at end of file diff --git a/models-interactions/model-actors/actor.so/src/test/resources/reqparams.json b/models-interactions/model-actors/actor.so/src/test/resources/reqparams.json new file mode 100644 index 000000000..44598ac81 --- /dev/null +++ b/models-interactions/model-actors/actor.so/src/test/resources/reqparams.json @@ -0,0 +1,5 @@ +{ + "subscriptionServiceType": "my-subscription-service-type", + "usePreload": false, + "userParams": [] +}
\ No newline at end of file diff --git a/models-interactions/model-actors/actor.so/src/test/resources/vfModuleCreate.json b/models-interactions/model-actors/actor.so/src/test/resources/vfModuleCreate.json new file mode 100644 index 000000000..06258f3f3 --- /dev/null +++ b/models-interactions/model-actors/actor.so/src/test/resources/vfModuleCreate.json @@ -0,0 +1,49 @@ +{ + "requestDetails": { + "modelInfo": { + "modelType": "vfModule", + "modelInvariantId": "my-model-invariant-id", + "modelVersionId": "my-model-version-id", + "modelName": "my-model-name", + "modelVersion": "my-model-version", + "modelCustomizationId": "my-model-customization-id" + }, + "cloudConfiguration": {}, + "requestInfo": { + "instanceName": "vfModuleName", + "source": "POLICY", + "suppressRollback": false, + "requestorId": "policy" + }, + "relatedInstanceList": [ + { + "relatedInstance": { + "instanceId": "my-service-instance-id", + "modelInfo": { + "modelType": "service", + "modelName": "my-model-name-B", + "modelVersion": "my-model-version-B" + } + } + }, + { + "relatedInstance": { + "instanceId": "my-vnf-id", + "modelInfo": { + "modelType": "vnf", + "modelName": "my-model-name-B", + "modelVersion": "my-model-version-B" + } + } + } + ], + "requestParameters": { + "subscriptionServiceType": "my-subscription-service-type", + "usePreload": false, + "userParams": [] + }, + "configurationParameters": [ + {} + ] + } +}
\ No newline at end of file diff --git a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/controlloop/ControlLoopEventContext.java b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/controlloop/ControlLoopEventContext.java index 3e02da611..8099ea7c2 100644 --- a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/controlloop/ControlLoopEventContext.java +++ b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/controlloop/ControlLoopEventContext.java @@ -137,7 +137,7 @@ public class ControlLoopEventContext implements Serializable { // @formatter:off CompletableFuture<OperationOutcome> oldFuture = - retrievers.compute(name, (key, future) -> (future == null || future.isCancelled() ? null : future)); + retrievers.computeIfPresent(name, (key, future) -> future.isCancelled() ? null : future); // @formatter:on if (oldFuture != null) { diff --git a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/impl/HttpOperator.java b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/impl/HttpOperator.java index add74aa42..b4a3318e7 100644 --- a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/impl/HttpOperator.java +++ b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/impl/HttpOperator.java @@ -95,6 +95,15 @@ public abstract class HttpOperator extends OperatorPartial { throw new ParameterValidationRuntimeException("invalid parameters", result); } + doConfigure(params); + } + + /** + * Configures the operator using the specified parameters. + * + * @param params operator parameters + */ + protected void doConfigure(HttpParams params) { client = getClientFactory().get(params.getClientName()); path = params.getPath(); timeoutMs = TimeUnit.MILLISECONDS.convert(params.getTimeoutSec(), TimeUnit.SECONDS); |