aboutsummaryrefslogtreecommitdiffstats
path: root/controlloop/common
diff options
context:
space:
mode:
authorJim Hahn <jrh3@att.com>2020-07-30 18:05:02 -0400
committerJim Hahn <jrh3@att.com>2020-08-24 14:31:13 -0400
commitdd1fd8d3f4f30766a82f7c5200400bedec683354 (patch)
treeb7116031341230ba3226d3ba053803c8d688f9b7 /controlloop/common
parent3d2058a63eb8996d9af6f9f6142a9f882895d682 (diff)
Add Step classes for usecases controller
Add usecases-specific classes for managing preprocessor steps. Issue-ID: POLICY-2748 Change-Id: I62a2bf8fbeb656a5017531a3f3de6a6dbad5a004 Signed-off-by: Jim Hahn <jrh3@att.com>
Diffstat (limited to 'controlloop/common')
-rw-r--r--controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/AaiCqStep2.java66
-rw-r--r--controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/AaiGetPnfStep2.java70
-rw-r--r--controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/AaiGetTenantStep2.java94
-rw-r--r--controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/GetTargetEntityStep2.java60
-rw-r--r--controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/GuardStep2.java115
-rw-r--r--controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/LockStep2.java71
-rw-r--r--controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/Step2.java433
-rw-r--r--controlloop/common/controller-usecases/src/test/java/org/onap/policy/drools/apps/controller/usecases/step/AaiCqStep2Test.java131
-rw-r--r--controlloop/common/controller-usecases/src/test/java/org/onap/policy/drools/apps/controller/usecases/step/AaiGetPnfStep2Test.java133
-rw-r--r--controlloop/common/controller-usecases/src/test/java/org/onap/policy/drools/apps/controller/usecases/step/AaiGetTenantStep2Test.java161
-rw-r--r--controlloop/common/controller-usecases/src/test/java/org/onap/policy/drools/apps/controller/usecases/step/GetTargetEntityStep2Test.java87
-rw-r--r--controlloop/common/controller-usecases/src/test/java/org/onap/policy/drools/apps/controller/usecases/step/GuardStep2Test.java166
-rw-r--r--controlloop/common/controller-usecases/src/test/java/org/onap/policy/drools/apps/controller/usecases/step/LockStep2Test.java134
-rw-r--r--controlloop/common/controller-usecases/src/test/java/org/onap/policy/drools/apps/controller/usecases/step/Step2Test.java514
14 files changed, 2235 insertions, 0 deletions
diff --git a/controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/AaiCqStep2.java b/controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/AaiCqStep2.java
new file mode 100644
index 000000000..9ae1d7fb0
--- /dev/null
+++ b/controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/AaiCqStep2.java
@@ -0,0 +1,66 @@
+/*-
+ * ============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.drools.apps.controller.usecases.step;
+
+import org.onap.policy.aai.AaiCqResponse;
+import org.onap.policy.controlloop.actor.aai.AaiActor;
+import org.onap.policy.controlloop.actor.aai.AaiCustomQueryOperation;
+import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
+
+/**
+ * Wrapper for {@link AaiCustomQueryOperation}. The {@link #success(OperationOutcome)}
+ * method stores the resultant "tenant" object in the step's context.
+ */
+public class AaiCqStep2 extends Step2 {
+
+ /**
+ * Constructs the object using information from another step.
+ *
+ * @param otherStep step whose information should be used
+ */
+ public AaiCqStep2(Step2 otherStep) {
+ super(otherStep, AaiActor.NAME, AaiCustomQueryOperation.NAME);
+ }
+
+ /**
+ * Skips the operation if we already have the data.
+ */
+ @Override
+ public boolean start(long remainingMs) {
+ if (stepContext.contains(AaiCqResponse.CONTEXT_KEY)) {
+ // already have the data
+ return false;
+ }
+
+ return super.start(remainingMs);
+ }
+
+ /**
+ * Saves the response for later use.
+ */
+ @Override
+ public void success(OperationOutcome outcome) {
+ AaiCqResponse resp = outcome.getResponse();
+ stepContext.setProperty(AaiCqResponse.CONTEXT_KEY, resp);
+
+ super.success(outcome);
+ }
+}
diff --git a/controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/AaiGetPnfStep2.java b/controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/AaiGetPnfStep2.java
new file mode 100644
index 000000000..131daef9d
--- /dev/null
+++ b/controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/AaiGetPnfStep2.java
@@ -0,0 +1,70 @@
+/*-
+ * ============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.drools.apps.controller.usecases.step;
+
+import org.onap.policy.common.utils.coder.StandardCoderObject;
+import org.onap.policy.controlloop.actor.aai.AaiActor;
+import org.onap.policy.controlloop.actor.aai.AaiGetPnfOperation;
+import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
+
+/**
+ * Wrapper for {@link AaiGetPnfOperation}. The {@link #success(OperationOutcome)} method
+ * stores the resultant PNF object in the step's context.
+ * <p/>
+ * Note: this assumes that the target entity is one of the properties returned by
+ * {@link AaiGetPnfOperation#getPropertyNames()}.
+ */
+public class AaiGetPnfStep2 extends Step2 {
+
+
+ /**
+ * Constructs the object using information from another step.
+ *
+ * @param otherStep step whose information should be used
+ */
+ public AaiGetPnfStep2(Step2 otherStep) {
+ super(otherStep, AaiActor.NAME, AaiGetPnfOperation.NAME);
+ }
+
+ /**
+ * Skips the operation if we already have the data.
+ */
+ @Override
+ public boolean start(long remainingMs) {
+ if (stepContext.contains(AaiGetPnfOperation.getKey(getTargetEntity()))) {
+ // already have the data
+ return false;
+ }
+
+ return super.start(remainingMs);
+ }
+
+ /**
+ * Saves the response for later use.
+ */
+ @Override
+ public void success(OperationOutcome outcome) {
+ StandardCoderObject resp = outcome.getResponse();
+ stepContext.setProperty(AaiGetPnfOperation.getKey(getTargetEntity()), resp);
+
+ super.success(outcome);
+ }
+}
diff --git a/controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/AaiGetTenantStep2.java b/controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/AaiGetTenantStep2.java
new file mode 100644
index 000000000..d1851dd42
--- /dev/null
+++ b/controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/AaiGetTenantStep2.java
@@ -0,0 +1,94 @@
+/*-
+ * ============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.drools.apps.controller.usecases.step;
+
+import java.util.Collections;
+import java.util.List;
+import org.apache.commons.lang3.StringUtils;
+import org.onap.policy.common.utils.coder.StandardCoderObject;
+import org.onap.policy.controlloop.actor.aai.AaiActor;
+import org.onap.policy.controlloop.actor.aai.AaiGetTenantOperation;
+import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
+import org.onap.policy.controlloop.actorserviceprovider.OperationProperties;
+
+/**
+ * Wrapper for {@link AaiGetTenantOperation}. The vserver name is extracted from the
+ * enrichment data and passed as the target entity for the operation. The
+ * {@link #success(OperationOutcome)} method stores the resultant "tenant" object in the
+ * step's context.
+ */
+public class AaiGetTenantStep2 extends Step2 {
+
+ private final String vserver;
+
+
+ /**
+ * Constructs the object using information from another step.
+ *
+ * @param otherStep step whose information should be used
+ */
+ public AaiGetTenantStep2(Step2 otherStep) {
+ super(otherStep, AaiActor.NAME, AaiGetTenantOperation.NAME);
+
+ vserver = event.getAai().get(VSERVER_VSERVER_NAME);
+ if (StringUtils.isBlank(vserver)) {
+ throw new IllegalArgumentException("missing " + VSERVER_VSERVER_NAME + " in enrichment data");
+ }
+ }
+
+ /**
+ * The vserver is passed as the target entity, thus we don't need to include the
+ * target entity in the property list.
+ */
+ @Override
+ public List<String> getPropertyNames() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public void setProperties() {
+ getOperation().setProperty(OperationProperties.AAI_TARGET_ENTITY, vserver);
+ }
+
+ /**
+ * Skips the operation if we already have the data.
+ */
+ @Override
+ public boolean start(long remainingMs) {
+ if (stepContext.contains(AaiGetTenantOperation.getKey(vserver))) {
+ // already have the data
+ return false;
+ }
+
+ return super.start(remainingMs);
+ }
+
+ /**
+ * Saves the response for later use.
+ */
+ @Override
+ public void success(OperationOutcome outcome) {
+ StandardCoderObject resp = outcome.getResponse();
+ stepContext.setProperty(AaiGetTenantOperation.getKey(vserver), resp);
+
+ super.success(outcome);
+ }
+}
diff --git a/controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/GetTargetEntityStep2.java b/controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/GetTargetEntityStep2.java
new file mode 100644
index 000000000..06201b13c
--- /dev/null
+++ b/controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/GetTargetEntityStep2.java
@@ -0,0 +1,60 @@
+/*-
+ * ============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.drools.apps.controller.usecases.step;
+
+import org.onap.policy.controlloop.actorserviceprovider.Operation;
+import org.onap.policy.drools.apps.controller.usecases.GetTargetEntityOperation2;
+import org.onap.policy.drools.apps.controller.usecases.UsecasesConstants;
+
+/**
+ * Wrapper for {@link GetTargetEntityOperation2}. The {@link #start(long)} method always
+ * returns {@code false}, as the Operation should never actually be started.
+ */
+public class GetTargetEntityStep2 extends Step2 {
+
+
+ /**
+ * Constructs the object using information from another step.
+ *
+ * @param otherStep step whose information should be used
+ */
+ public GetTargetEntityStep2(Step2 otherStep) {
+ super(otherStep, UsecasesConstants.GET_TARGET_ENTITY_ACTOR, UsecasesConstants.GET_TARGET_ENTITY_OPERATION);
+ }
+
+ @Override
+ protected Operation buildOperation() {
+ return new GetTargetEntityOperation2(stepContext, event, params);
+ }
+
+ /**
+ * The operation does not actually have to be executed, as it populates the target
+ * entity as soon as {@link Operation#setProperty(String, Object)} is invoked.
+ */
+ @Override
+ public boolean start(long remainingMs) {
+ if (!isInitialized()) {
+ throw new IllegalStateException("step has not been initialized");
+ }
+
+ return false;
+ }
+}
diff --git a/controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/GuardStep2.java b/controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/GuardStep2.java
new file mode 100644
index 000000000..b7247ce69
--- /dev/null
+++ b/controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/GuardStep2.java
@@ -0,0 +1,115 @@
+/*-
+ * ============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.drools.apps.controller.usecases.step;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import org.onap.policy.controlloop.actor.guard.DecisionOperation;
+import org.onap.policy.controlloop.actor.guard.GuardActor;
+import org.onap.policy.controlloop.actor.so.VfModuleCreate;
+import org.onap.policy.controlloop.actorserviceprovider.Operation;
+import org.onap.policy.controlloop.actorserviceprovider.OperationProperties;
+
+/**
+ * Wrapper for a Guard operation. Note: this makes a clone of the operation parameters,
+ * replacing the payload. It overrides the operation's property names with that are
+ * relevant for guards. In addition, it overrides the relevant loadXxx() methods to load
+ * the data into the payload instead of into the operation's properties. It also
+ * increments or decrements the VF Count, depending whether the operation is a "VF Module
+ * Create" or not.
+ */
+public class GuardStep2 extends Step2 {
+ public static final String PAYLOAD_KEY_TARGET_ENTITY = "target";
+ public static final String PAYLOAD_KEY_VF_COUNT = "vfCount";
+
+ private final Operation policyOper;
+
+
+ /**
+ * Constructs the object using information from another step.
+ *
+ * @param otherStep step whose information should be used
+ */
+ public GuardStep2(Step2 otherStep, String closedLoopControlName) {
+ super(otherStep, GuardActor.NAME, DecisionOperation.NAME);
+
+ if (!otherStep.isInitialized()) {
+ throw new IllegalStateException("policy operation must be initialized before the guard operation");
+ }
+
+ this.policyOper = otherStep.getOperation();
+
+ Map<String, Object> payload = new LinkedHashMap<>();
+ payload.put("actor", otherStep.getActorName());
+ payload.put("operation", otherStep.getOperationName());
+ payload.put("requestId", params.getRequestId());
+ payload.put("clname", closedLoopControlName);
+
+ params = params.toBuilder().payload(payload).build();
+ }
+
+ @Override
+ public boolean acceptsEvent() {
+ return true;
+ }
+
+ /**
+ * Builds the list of properties on the policy's actual operation.
+ */
+ @Override
+ public List<String> getPropertyNames() {
+ List<String> names = new ArrayList<>(1);
+
+ // include VF Count if the policy's operation needs it
+ if (policyOper.getPropertyNames().contains(OperationProperties.DATA_VF_COUNT)) {
+ names.add(OperationProperties.DATA_VF_COUNT);
+ }
+
+ return names;
+ }
+
+ /**
+ * Load the target entity into the payload instead of the operation's properties.
+ */
+ @Override
+ protected void loadTargetEntity(String propName) {
+ params.getPayload().put(PAYLOAD_KEY_TARGET_ENTITY, getTargetEntity());
+ }
+
+ /**
+ * Load the VF Count into the payload instead of the operation's properties.
+ * Increments the count for "VF Module Create". Decrements it otherwise.
+ */
+ @Override
+ protected void loadVfCount(String propName) {
+ // run guard with the proposed VF count
+ int count = getVfCount();
+ if (VfModuleCreate.NAME.equals(policyOper.getName())) {
+ ++count;
+ } else {
+ --count;
+ }
+
+ params.getPayload().put(PAYLOAD_KEY_VF_COUNT, count);
+ }
+}
diff --git a/controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/LockStep2.java b/controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/LockStep2.java
new file mode 100644
index 000000000..507a08116
--- /dev/null
+++ b/controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/LockStep2.java
@@ -0,0 +1,71 @@
+/*-
+ * ============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.drools.apps.controller.usecases.step;
+
+import org.onap.policy.controlloop.actorserviceprovider.Operation;
+import org.onap.policy.controlloop.eventmanager.ActorConstants;
+import org.onap.policy.drools.apps.controller.usecases.LockOperation2;
+
+/**
+ * Wrapper for the LOCK pseudo operation. Arranges for the lock's future to generate an
+ * outcome.
+ */
+public class LockStep2 extends Step2 {
+
+ /**
+ * Constructs the object using information from another step.
+ *
+ * @param otherStep step whose information should be used
+ */
+ public LockStep2(Step2 otherStep) {
+ super(otherStep, ActorConstants.LOCK_ACTOR, ActorConstants.LOCK_OPERATION);
+ }
+
+ @Override
+ public boolean acceptsEvent() {
+ return true;
+ }
+
+ @Override
+ public boolean start(long remainingMs) {
+ super.start(remainingMs);
+
+ if (future != null) {
+ future.whenComplete((outcome, thrown) -> {
+ outcome.setFinalOutcome(true);
+ params.getCompleteCallback().accept(outcome);
+ });
+ }
+
+ /*
+ * ELSE: The operation must have thrown an exception. Nothing more to do as
+ * super.start() will have already propagated the exception to the completion
+ * handler.
+ */
+
+ return true;
+ }
+
+ @Override
+ protected Operation buildOperation() {
+ return new LockOperation2(stepContext, params);
+ }
+}
diff --git a/controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/Step2.java b/controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/Step2.java
new file mode 100644
index 000000000..9275f791d
--- /dev/null
+++ b/controlloop/common/controller-usecases/src/main/java/org/onap/policy/drools/apps/controller/usecases/step/Step2.java
@@ -0,0 +1,433 @@
+/*-
+ * ============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.drools.apps.controller.usecases.step;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+import lombok.Getter;
+import lombok.Setter;
+import org.apache.commons.lang3.StringUtils;
+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.StandardCoderObject;
+import org.onap.policy.controlloop.VirtualControlLoopEvent;
+import org.onap.policy.controlloop.actor.aai.AaiGetPnfOperation;
+import org.onap.policy.controlloop.actor.aai.AaiGetTenantOperation;
+import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
+import org.onap.policy.controlloop.actorserviceprovider.OperationProperties;
+import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
+import org.onap.policy.controlloop.eventmanager.Step;
+import org.onap.policy.controlloop.eventmanager.StepContext;
+import org.onap.policy.drools.apps.controller.usecases.UsecasesConstants;
+
+/**
+ * Steps specific to the usecases controller. The {@link #setProperties()} method is used
+ * to load the various properties into the operation, extracting enrichment data where
+ * appropriate, and extracting other data from the step's context. For each property,
+ * there is a getXxx() method for extracting the value and a loadXxx() method for loading
+ * the extracted value into the operation. In addition, the
+ * {@link #success(OperationOutcome)} method is responsible for extracting responses from
+ * an operation outcome and recording the data in the step's context for use by subsequent
+ * steps.
+ */
+public class Step2 extends Step {
+ public static final String TARGET_INFO_MSG = "Target information";
+ public static final String ENRICHMENT_PREFIX = "enrichment/";
+ public static final String VSERVER_VSERVER_NAME = "vserver.vserver-name";
+ public static final String RESOURCE_LINK = "resource-link";
+ public static final String RESULT_DATA = "result-data";
+
+ private static final Map<String, BiConsumer<Step2, String>> PROPERTY_LOADER;
+ private static final Map<String, Consumer<Step2>> PROPERTY_SAVER;
+
+ static {
+ /*
+ * Populate map for PROPERTY_LOADER.
+ */
+ Map<String, BiConsumer<Step2, String>> map = new HashMap<>();
+
+ map.put(OperationProperties.AAI_DEFAULT_CLOUD_REGION, Step2::loadCloudRegion);
+ map.put(OperationProperties.AAI_DEFAULT_TENANT, Step2::loadTenant);
+ map.put(OperationProperties.AAI_PNF, Step2::loadPnf);
+ map.put(OperationProperties.AAI_RESOURCE_VNF, Step2::loadResourceVnf);
+ map.put(OperationProperties.AAI_SERVICE, Step2::loadService);
+ map.put(OperationProperties.AAI_SERVICE_MODEL, Step2::loadServiceModel);
+ map.put(OperationProperties.AAI_TARGET_ENTITY, Step2::loadTargetEntity);
+ map.put(OperationProperties.AAI_VNF, Step2::loadVnf);
+ map.put(OperationProperties.AAI_VNF_MODEL, Step2::loadVnfModel);
+ map.put(OperationProperties.AAI_VSERVER_LINK, Step2::loadVserverLink);
+ map.put(OperationProperties.DATA_VF_COUNT, Step2::loadVfCount);
+ map.put(OperationProperties.EVENT_ADDITIONAL_PARAMS, Step2::loadAdditionalEventParams);
+ map.put(OperationProperties.EVENT_PAYLOAD, Step2::loadEventPayload);
+ map.put(OperationProperties.OPT_CDS_GRPC_AAI_PROPERTIES, Step2::loadOptCdsGrpcAaiProperties);
+
+ map.put(UsecasesConstants.AAI_DEFAULT_GENERIC_VNF, Step2::loadDefaultGenericVnf);
+
+ PROPERTY_LOADER = Collections.unmodifiableMap(map);
+
+
+ /*
+ * Populate map for PROPERTY_SAVER.
+ */
+ Map<String, Consumer<Step2>> map2 = new HashMap<>();
+
+ map2.put(OperationProperties.DATA_VF_COUNT, Step2::storeVfCount);
+
+ PROPERTY_SAVER = Collections.unmodifiableMap(map2);
+ }
+
+
+ protected final StepContext stepContext;
+ protected final VirtualControlLoopEvent event;
+
+ /**
+ * {@code True} if the associated preprocessing steps have been loaded, {@code false}
+ * otherwise.
+ */
+ @Getter
+ @Setter
+ private boolean preprocessed;
+
+ /**
+ * Actions to take to store the Operation's properties back into the context.
+ */
+ private List<Consumer<Step2>> postProcessors = new LinkedList<>();
+
+
+ /**
+ * Constructs the object. This is used when constructing the step for the policy's
+ * actual operation.
+ *
+ * @param stepContext the step's context
+ * @param params operation parameters
+ * @param event the event being processed
+ */
+ public Step2(StepContext stepContext, ControlLoopOperationParams params, VirtualControlLoopEvent event) {
+ super(params, new AtomicReference<>());
+ this.stepContext = stepContext;
+ this.event = event;
+ }
+
+ /**
+ * Constructs the object using information from another step. This is used when
+ * constructing a preprocessing step.
+ *
+ * @param otherStep step whose information should be used
+ * @param actor actor name
+ * @param operation operation name
+ */
+ public Step2(Step2 otherStep, String actor, String operation) {
+ super(otherStep, actor, operation);
+ this.stepContext = otherStep.stepContext;
+ this.event = otherStep.event;
+ }
+
+ /**
+ * Determines if starting this step indicates acceptance of the event. The default
+ * method simply invokes {@link #isPolicyStep()}.
+ *
+ * @return {@code true} if this step accepts the event, {@code false} if it is still
+ * indeterminate
+ */
+ public boolean acceptsEvent() {
+ return isPolicyStep();
+ }
+
+ /**
+ * Indicates that the step succeeded with the given outcome. Invoked by the rules. The
+ * default method invokes the post processors.
+ *
+ * @param outcome operation's outcome
+ */
+ public void success(OperationOutcome outcome) {
+ for (Consumer<Step2> proc : postProcessors) {
+ proc.accept(this);
+ }
+ }
+
+ /**
+ * Gets the names of the properties required by the operation. The default method just
+ * delegates to the operation to identify the properties.
+ *
+ * @return the names of the properties required by the operation
+ */
+ public List<String> getPropertyNames() {
+ return getOperation().getPropertyNames();
+ }
+
+ /**
+ * Sets the operation's properties. This is invoked <i>after</i> any preprocessor
+ * steps have been performed. It also adds items to {@link #postProcessors}.
+ */
+ public void setProperties() {
+ postProcessors.clear();
+
+ for (String propName : getPropertyNames()) {
+ // identify the saver, if any
+ Consumer<Step2> saver = PROPERTY_SAVER.get(propName);
+ if (saver != null) {
+ postProcessors.add(saver);
+ }
+
+
+ // load data
+ if (propName.startsWith(ENRICHMENT_PREFIX)) {
+ loadEnrichment(propName);
+ continue;
+ }
+
+ BiConsumer<Step2, String> loader = PROPERTY_LOADER.get(propName);
+ if (loader == null) {
+ throw new IllegalArgumentException("unknown property " + propName + " needed by " + getActorName() + "."
+ + getOperationName());
+ }
+
+ loader.accept(this, propName);
+ }
+ }
+
+ protected void loadCloudRegion(String propName) {
+ getOperation().setProperty(propName, getCloudRegion());
+ }
+
+ protected void loadTenant(String propName) {
+ getOperation().setProperty(propName, getTenant());
+ }
+
+ protected void loadPnf(String propName) {
+ getOperation().setProperty(propName, getPnf());
+ }
+
+ protected void loadResourceVnf(String propName) {
+ getOperation().setProperty(propName, getResourceVnf());
+ }
+
+ protected void loadService(String propName) {
+ getOperation().setProperty(propName, getService());
+ }
+
+ protected void loadServiceModel(String propName) {
+ getOperation().setProperty(propName, getServiceModel());
+ }
+
+ protected void loadTargetEntity(String propName) {
+ getOperation().setProperty(propName, getTargetEntity());
+ }
+
+ protected void loadVnf(String propName) {
+ getOperation().setProperty(propName, getVnf());
+ }
+
+ protected void loadVnfModel(String propName) {
+ getOperation().setProperty(propName, getVnfModel());
+ }
+
+ protected void loadVserverLink(String propName) {
+ getOperation().setProperty(propName, getVserverLink());
+ }
+
+ protected void loadVfCount(String propName) {
+ getOperation().setProperty(propName, getVfCount());
+ }
+
+ protected void loadEnrichment(String propName) {
+ getOperation().setProperty(propName, getEnrichment(propName));
+ }
+
+ protected void loadAdditionalEventParams(String propName) {
+ getOperation().setProperty(propName, getAdditionalEventParams());
+ }
+
+ protected void loadEventPayload(String propName) {
+ getOperation().setProperty(propName, getEventPayload());
+ }
+
+ protected void loadOptCdsGrpcAaiProperties(String propName) {
+ // do nothing
+ }
+
+ protected void loadDefaultGenericVnf(String propName) {
+ getOperation().setProperty(propName, getDefaultGenericVnf());
+ }
+
+ protected CloudRegion getCloudRegion() {
+ AaiCqResponse aaicq = getCustomQueryData();
+ return aaicq.getDefaultCloudRegion();
+ }
+
+ protected Tenant getTenant() {
+ AaiCqResponse aaicq = getCustomQueryData();
+ return aaicq.getDefaultTenant();
+ }
+
+ protected StandardCoderObject getPnf() {
+ return stepContext.getProperty(AaiGetPnfOperation.getKey(getTargetEntity()));
+ }
+
+ protected GenericVnf getResourceVnf() {
+ verifyNotNull(TARGET_INFO_MSG, params.getTarget());
+
+ String resourceId = params.getTarget().getResourceID();
+
+ verifyNotNull("Target resource ID", resourceId);
+
+ AaiCqResponse aaicq = getCustomQueryData();
+ return aaicq.getGenericVnfByModelInvariantId(resourceId);
+ }
+
+ protected ServiceInstance getService() {
+ AaiCqResponse aaicq = getCustomQueryData();
+ return aaicq.getServiceInstance();
+ }
+
+ protected ModelVer getServiceModel() {
+ AaiCqResponse aaicq = getCustomQueryData();
+ ServiceInstance service = aaicq.getServiceInstance();
+ return aaicq.getModelVerByVersionId(service.getModelVersionId());
+ }
+
+ /**
+ * The default method assumes there is only one target entity and that it's stored
+ * within the step's context.
+ */
+ protected String getTargetEntity() {
+ return stepContext.getProperty(OperationProperties.AAI_TARGET_ENTITY);
+ }
+
+ protected GenericVnf getVnf() {
+ verifyNotNull(TARGET_INFO_MSG, params.getTarget());
+
+ String modelInvariantId = params.getTarget().getModelInvariantId();
+
+ verifyNotNull("modelInvariantId", modelInvariantId);
+
+ AaiCqResponse aaicq = getCustomQueryData();
+ return aaicq.getGenericVnfByVfModuleModelInvariantId(modelInvariantId);
+ }
+
+ protected ModelVer getVnfModel() {
+ GenericVnf vnf = getVnf();
+ AaiCqResponse aaicq = getCustomQueryData();
+ return aaicq.getModelVerByVersionId(vnf.getModelVersionId());
+ }
+
+ protected String getVserverLink() {
+ String vserver = event.getAai().get(VSERVER_VSERVER_NAME);
+ if (StringUtils.isBlank(vserver)) {
+ throw new IllegalArgumentException("missing " + VSERVER_VSERVER_NAME + " in enrichment data");
+ }
+
+ StandardCoderObject tenant = stepContext.getProperty(AaiGetTenantOperation.getKey(vserver));
+ verifyNotNull("tenant data", tenant);
+
+ String resourceLink = tenant.getString(RESULT_DATA, 0, RESOURCE_LINK);
+ verifyNotNull("tenant data resource-link", resourceLink);
+
+ return stripPrefix(resourceLink, 3);
+ }
+
+ protected Integer getVfCount() {
+ if (stepContext.contains(OperationProperties.DATA_VF_COUNT)) {
+ return stepContext.getProperty(OperationProperties.DATA_VF_COUNT);
+ }
+
+ verifyNotNull(TARGET_INFO_MSG, params.getTarget());
+
+ String modelCustomizationId = params.getTarget().getModelCustomizationId();
+ String modelInvariantId = params.getTarget().getModelInvariantId();
+ String modelVersionId = params.getTarget().getModelVersionId();
+
+ verifyNotNull("target modelCustomizationId", modelCustomizationId);
+ verifyNotNull("target modelInvariantId", modelInvariantId);
+ verifyNotNull("target modelVersionId", modelVersionId);
+
+ AaiCqResponse aaicq = getCustomQueryData();
+ return aaicq.getVfModuleCount(modelCustomizationId, modelInvariantId, modelVersionId);
+ }
+
+ protected String getEnrichment(String propName) {
+ String enrichmentKey = propName.substring(ENRICHMENT_PREFIX.length());
+ String value = event.getAai().get(enrichmentKey);
+ verifyNotNull(propName, value);
+
+ return value;
+ }
+
+ protected Map<String, String> getAdditionalEventParams() {
+ return event.getAdditionalEventParams();
+ }
+
+ protected String getEventPayload() {
+ return event.getPayload();
+ }
+
+ protected GenericVnf getDefaultGenericVnf() {
+ AaiCqResponse aaicq = getCustomQueryData();
+ return aaicq.getDefaultGenericVnf();
+ }
+
+ protected AaiCqResponse getCustomQueryData() {
+ AaiCqResponse aaicq = stepContext.getProperty(AaiCqResponse.CONTEXT_KEY);
+ verifyNotNull("custom query data", aaicq);
+
+ return aaicq;
+ }
+
+ protected void storeVfCount() {
+ if (!getOperation().containsProperty(OperationProperties.DATA_VF_COUNT)) {
+ return;
+ }
+
+ int vfcount = getOperation().getProperty(OperationProperties.DATA_VF_COUNT);
+ stepContext.setProperty(OperationProperties.DATA_VF_COUNT, vfcount);
+ }
+
+ protected void verifyNotNull(String propName, Object value) {
+ if (value == null) {
+ throw new IllegalArgumentException(
+ "missing " + propName + " for " + getActorName() + "." + getOperationName());
+ }
+ }
+
+ protected static String stripPrefix(String resourceLink, int ncomponents) {
+ int previdx = -1;
+ for (int nslashes = 0; nslashes < ncomponents; ++nslashes) {
+ int idx = resourceLink.indexOf('/', previdx + 1);
+ if (idx < 0) {
+ break;
+ }
+
+ previdx = idx;
+ }
+
+ return resourceLink.substring(Math.max(0, previdx));
+ }
+}
diff --git a/controlloop/common/controller-usecases/src/test/java/org/onap/policy/drools/apps/controller/usecases/step/AaiCqStep2Test.java b/controlloop/common/controller-usecases/src/test/java/org/onap/policy/drools/apps/controller/usecases/step/AaiCqStep2Test.java
new file mode 100644
index 000000000..9869c2182
--- /dev/null
+++ b/controlloop/common/controller-usecases/src/test/java/org/onap/policy/drools/apps/controller/usecases/step/AaiCqStep2Test.java
@@ -0,0 +1,131 @@
+/*-
+ * ============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.drools.apps.controller.usecases.step;
+
+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.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.UUID;
+import java.util.concurrent.CompletableFuture;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.onap.policy.aai.AaiCqResponse;
+import org.onap.policy.controlloop.VirtualControlLoopEvent;
+import org.onap.policy.controlloop.actor.aai.AaiActor;
+import org.onap.policy.controlloop.actor.aai.AaiCustomQueryOperation;
+import org.onap.policy.controlloop.actorserviceprovider.ActorService;
+import org.onap.policy.controlloop.actorserviceprovider.Operation;
+import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
+import org.onap.policy.controlloop.actorserviceprovider.Operator;
+import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
+import org.onap.policy.controlloop.actorserviceprovider.spi.Actor;
+import org.onap.policy.controlloop.eventmanager.StepContext;
+
+public class AaiCqStep2Test {
+ private static final String MY_TARGET = "my-target";
+ private static final UUID REQ_ID = UUID.randomUUID();
+
+ @Mock
+ private Operator policyOperator;
+ @Mock
+ private Operation policyOperation;
+ @Mock
+ private Actor policyActor;
+ @Mock
+ private ActorService actors;
+ @Mock
+ private ControlLoopOperationParams params;
+ @Mock
+ private StepContext stepContext;
+ @Mock
+ private VirtualControlLoopEvent event;
+
+ private CompletableFuture<OperationOutcome> future;
+ private Step2 master;
+ private AaiCqStep2 step;
+
+ /**
+ * Sets up.
+ */
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ future = new CompletableFuture<>();
+
+ when(params.toBuilder()).thenReturn(ControlLoopOperationParams.builder().actorService(actors)
+ .targetEntity(MY_TARGET).requestId(REQ_ID));
+
+ // configure policy operation
+ when(actors.getActor(AaiActor.NAME)).thenReturn(policyActor);
+ when(policyActor.getOperator(AaiCustomQueryOperation.NAME)).thenReturn(policyOperator);
+ when(policyOperator.buildOperation(any())).thenReturn(policyOperation);
+ when(policyOperation.start()).thenReturn(future);
+
+ master = new Step2(stepContext, params, event);
+ step = new AaiCqStep2(master);
+ }
+
+ @Test
+ public void testConstructor() {
+ assertEquals(AaiActor.NAME, step.getActorName());
+ assertEquals(AaiCustomQueryOperation.NAME, step.getOperationName());
+ assertSame(stepContext, step.stepContext);
+ assertSame(event, step.event);
+ }
+
+ @Test
+ public void testStart() {
+ step.init();
+ assertTrue(step.start(100));
+ verify(policyOperation).start();
+ }
+
+ /**
+ * Tests start() when the data has already been retrieved.
+ */
+ @Test
+ public void testStartAlreadyHaveData() {
+ when(stepContext.contains(AaiCqResponse.CONTEXT_KEY)).thenReturn(true);
+
+ step.init();
+ assertFalse(step.start(200));
+ verify(policyOperation, never()).start();
+ }
+
+ @Test
+ public void testSuccess() {
+ AaiCqResponse data = new AaiCqResponse("{}");
+ OperationOutcome outcome = new OperationOutcome();
+ outcome.setResponse(data);
+
+ step.success(outcome);
+ verify(stepContext).setProperty(AaiCqResponse.CONTEXT_KEY, data);
+ }
+}
diff --git a/controlloop/common/controller-usecases/src/test/java/org/onap/policy/drools/apps/controller/usecases/step/AaiGetPnfStep2Test.java b/controlloop/common/controller-usecases/src/test/java/org/onap/policy/drools/apps/controller/usecases/step/AaiGetPnfStep2Test.java
new file mode 100644
index 000000000..7580c2c0c
--- /dev/null
+++ b/controlloop/common/controller-usecases/src/test/java/org/onap/policy/drools/apps/controller/usecases/step/AaiGetPnfStep2Test.java
@@ -0,0 +1,133 @@
+/*-
+ * ============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.drools.apps.controller.usecases.step;
+
+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.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.UUID;
+import java.util.concurrent.CompletableFuture;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.onap.policy.common.utils.coder.StandardCoderObject;
+import org.onap.policy.controlloop.VirtualControlLoopEvent;
+import org.onap.policy.controlloop.actor.aai.AaiActor;
+import org.onap.policy.controlloop.actor.aai.AaiGetPnfOperation;
+import org.onap.policy.controlloop.actorserviceprovider.ActorService;
+import org.onap.policy.controlloop.actorserviceprovider.Operation;
+import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
+import org.onap.policy.controlloop.actorserviceprovider.OperationProperties;
+import org.onap.policy.controlloop.actorserviceprovider.Operator;
+import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
+import org.onap.policy.controlloop.actorserviceprovider.spi.Actor;
+import org.onap.policy.controlloop.eventmanager.StepContext;
+
+public class AaiGetPnfStep2Test {
+ private static final String MY_TARGET = "my-target";
+ private static final UUID REQ_ID = UUID.randomUUID();
+
+ @Mock
+ private Operator policyOperator;
+ @Mock
+ private Operation policyOperation;
+ @Mock
+ private Actor policyActor;
+ @Mock
+ private ActorService actors;
+ @Mock
+ private ControlLoopOperationParams params;
+ @Mock
+ private StepContext stepContext;
+ @Mock
+ private VirtualControlLoopEvent event;
+
+ private CompletableFuture<OperationOutcome> future;
+ private Step2 master;
+ private AaiGetPnfStep2 step;
+
+ /**
+ * Sets up.
+ */
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ future = new CompletableFuture<>();
+
+ when(params.toBuilder()).thenReturn(ControlLoopOperationParams.builder().actorService(actors)
+ .requestId(REQ_ID));
+
+ // configure policy operation
+ when(actors.getActor(AaiActor.NAME)).thenReturn(policyActor);
+ when(policyActor.getOperator(AaiGetPnfOperation.NAME)).thenReturn(policyOperator);
+ when(policyOperator.buildOperation(any())).thenReturn(policyOperation);
+ when(policyOperation.start()).thenReturn(future);
+ when(stepContext.getProperty(OperationProperties.AAI_TARGET_ENTITY)).thenReturn(MY_TARGET);
+
+ master = new Step2(stepContext, params, event);
+ step = new AaiGetPnfStep2(master);
+ }
+
+ @Test
+ public void testConstructor() {
+ assertEquals(AaiActor.NAME, step.getActorName());
+ assertEquals(AaiGetPnfOperation.NAME, step.getOperationName());
+ assertSame(stepContext, step.stepContext);
+ assertSame(event, step.event);
+ }
+
+ @Test
+ public void testStart() {
+ step.init();
+ assertTrue(step.start(100));
+ verify(policyOperation).start();
+ }
+
+ /**
+ * Tests start() when the data has already been retrieved.
+ */
+ @Test
+ public void testStartAlreadyHaveData() {
+ when(stepContext.contains(AaiGetPnfOperation.getKey(MY_TARGET))).thenReturn(true);
+
+ step.init();
+ assertFalse(step.start(200));
+ verify(policyOperation, never()).start();
+ }
+
+ @Test
+ public void testSuccess() {
+ StandardCoderObject data = new StandardCoderObject();
+ OperationOutcome outcome = new OperationOutcome();
+ outcome.setResponse(data);
+
+ step.success(outcome);
+ verify(stepContext).setProperty(AaiGetPnfOperation.getKey(MY_TARGET), data);
+ }
+}
diff --git a/controlloop/common/controller-usecases/src/test/java/org/onap/policy/drools/apps/controller/usecases/step/AaiGetTenantStep2Test.java b/controlloop/common/controller-usecases/src/test/java/org/onap/policy/drools/apps/controller/usecases/step/AaiGetTenantStep2Test.java
new file mode 100644
index 000000000..65c27b45f
--- /dev/null
+++ b/controlloop/common/controller-usecases/src/test/java/org/onap/policy/drools/apps/controller/usecases/step/AaiGetTenantStep2Test.java
@@ -0,0 +1,161 @@
+/*-
+ * ============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.drools.apps.controller.usecases.step;
+
+import static org.assertj.core.api.Assertions.assertThat;
+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.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.CompletableFuture;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.onap.policy.common.utils.coder.StandardCoderObject;
+import org.onap.policy.controlloop.VirtualControlLoopEvent;
+import org.onap.policy.controlloop.actor.aai.AaiActor;
+import org.onap.policy.controlloop.actor.aai.AaiGetTenantOperation;
+import org.onap.policy.controlloop.actorserviceprovider.ActorService;
+import org.onap.policy.controlloop.actorserviceprovider.Operation;
+import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
+import org.onap.policy.controlloop.actorserviceprovider.OperationProperties;
+import org.onap.policy.controlloop.actorserviceprovider.Operator;
+import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
+import org.onap.policy.controlloop.actorserviceprovider.spi.Actor;
+import org.onap.policy.controlloop.eventmanager.StepContext;
+
+public class AaiGetTenantStep2Test {
+ private static final String MY_VSERVER = "my-vserver";
+ private static final UUID REQ_ID = UUID.randomUUID();
+
+ @Mock
+ private Operator policyOperator;
+ @Mock
+ private Operation policyOperation;
+ @Mock
+ private Actor policyActor;
+ @Mock
+ private ActorService actors;
+ @Mock
+ private ControlLoopOperationParams params;
+ @Mock
+ private StepContext stepContext;
+ @Mock
+ private VirtualControlLoopEvent event;
+
+ private CompletableFuture<OperationOutcome> future;
+ private Step2 master;
+ private AaiGetTenantStep2 step;
+
+ /**
+ * Sets up.
+ */
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ future = new CompletableFuture<>();
+
+ when(params.toBuilder()).thenReturn(ControlLoopOperationParams.builder().actorService(actors)
+ .targetEntity("my-target").requestId(REQ_ID));
+
+ // configure policy operation
+ when(actors.getActor(AaiActor.NAME)).thenReturn(policyActor);
+ when(policyActor.getOperator(AaiGetTenantOperation.NAME)).thenReturn(policyOperator);
+ when(policyOperator.buildOperation(any())).thenReturn(policyOperation);
+ when(policyOperation.start()).thenReturn(future);
+
+ when(event.getAai()).thenReturn(Map.of(Step2.VSERVER_VSERVER_NAME, MY_VSERVER));
+
+ master = new Step2(stepContext, params, event);
+ step = new AaiGetTenantStep2(master);
+ }
+
+ @Test
+ public void testConstructor() {
+ assertEquals(AaiActor.NAME, step.getActorName());
+ assertEquals(AaiGetTenantOperation.NAME, step.getOperationName());
+ assertSame(stepContext, step.stepContext);
+ assertSame(event, step.event);
+
+ // empty vserver name
+ when(event.getAai()).thenReturn(Map.of(Step2.VSERVER_VSERVER_NAME, ""));
+ assertThatIllegalArgumentException().isThrownBy(() -> new AaiGetTenantStep2(master))
+ .withMessage("missing " + Step2.VSERVER_VSERVER_NAME + " in enrichment data");
+
+ // missing vserver name
+ when(event.getAai()).thenReturn(Map.of());
+ assertThatIllegalArgumentException().isThrownBy(() -> new AaiGetTenantStep2(master))
+ .withMessage("missing " + Step2.VSERVER_VSERVER_NAME + " in enrichment data");
+ }
+
+ @Test
+ public void testGetPropertyNames() {
+ assertThat(step.getPropertyNames()).isEmpty();
+ }
+
+ @Test
+ public void testSetProperties() {
+ step.init();
+
+ step.setProperties();
+
+ verify(policyOperation).setProperty(OperationProperties.AAI_TARGET_ENTITY, MY_VSERVER);
+ }
+
+ @Test
+ public void testStart() {
+ step.init();
+ assertTrue(step.start(100));
+ verify(policyOperation).start();
+ }
+
+ /**
+ * Tests start() when the data has already been retrieved.
+ */
+ @Test
+ public void testStartAlreadyHaveData() {
+ when(stepContext.contains(AaiGetTenantOperation.getKey(MY_VSERVER))).thenReturn(true);
+
+ step.init();
+ assertFalse(step.start(200));
+ verify(policyOperation, never()).start();
+ }
+
+ @Test
+ public void testSuccess() {
+ StandardCoderObject data = new StandardCoderObject();
+ OperationOutcome outcome = new OperationOutcome();
+ outcome.setResponse(data);
+
+ step.success(outcome);
+ verify(stepContext).setProperty(AaiGetTenantOperation.getKey(MY_VSERVER), data);
+ }
+}
diff --git a/controlloop/common/controller-usecases/src/test/java/org/onap/policy/drools/apps/controller/usecases/step/GetTargetEntityStep2Test.java b/controlloop/common/controller-usecases/src/test/java/org/onap/policy/drools/apps/controller/usecases/step/GetTargetEntityStep2Test.java
new file mode 100644
index 000000000..965d04d7f
--- /dev/null
+++ b/controlloop/common/controller-usecases/src/test/java/org/onap/policy/drools/apps/controller/usecases/step/GetTargetEntityStep2Test.java
@@ -0,0 +1,87 @@
+/*-
+ * ============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.drools.apps.controller.usecases.step;
+
+import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
+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.Mockito.when;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.onap.policy.controlloop.VirtualControlLoopEvent;
+import org.onap.policy.controlloop.actorserviceprovider.Operation;
+import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
+import org.onap.policy.controlloop.eventmanager.StepContext;
+import org.onap.policy.drools.apps.controller.usecases.GetTargetEntityOperation2;
+import org.onap.policy.drools.apps.controller.usecases.UsecasesConstants;
+
+public class GetTargetEntityStep2Test {
+ @Mock
+ private ControlLoopOperationParams params;
+ @Mock
+ private StepContext stepContext;
+ @Mock
+ private VirtualControlLoopEvent event;
+
+ private Step2 master;
+ private GetTargetEntityStep2 step;
+
+ /**
+ * Sets up.
+ */
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ when(params.toBuilder()).thenReturn(ControlLoopOperationParams.builder());
+
+ master = new Step2(stepContext, params, event);
+ step = new GetTargetEntityStep2(master);
+ }
+
+ @Test
+ public void testConstructor() {
+ assertEquals(UsecasesConstants.GET_TARGET_ENTITY_ACTOR, step.getActorName());
+ assertEquals(UsecasesConstants.GET_TARGET_ENTITY_OPERATION, step.getOperationName());
+ assertSame(stepContext, step.stepContext);
+ assertSame(event, step.event);
+ }
+
+ @Test
+ public void testBuildOperation() {
+ Operation oper = step.buildOperation();
+ assertTrue(oper instanceof GetTargetEntityOperation2);
+ }
+
+ @Test
+ public void testStart() {
+ assertThatIllegalStateException().isThrownBy(() -> step.start(200))
+ .withMessage("step has not been initialized");
+
+ step.init();
+ assertFalse(step.start(100));
+ }
+}
diff --git a/controlloop/common/controller-usecases/src/test/java/org/onap/policy/drools/apps/controller/usecases/step/GuardStep2Test.java b/controlloop/common/controller-usecases/src/test/java/org/onap/policy/drools/apps/controller/usecases/step/GuardStep2Test.java
new file mode 100644
index 000000000..43319efb3
--- /dev/null
+++ b/controlloop/common/controller-usecases/src/test/java/org/onap/policy/drools/apps/controller/usecases/step/GuardStep2Test.java
@@ -0,0 +1,166 @@
+/*-
+ * ============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.drools.apps.controller.usecases.step;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.when;
+
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.onap.policy.controlloop.VirtualControlLoopEvent;
+import org.onap.policy.controlloop.actor.guard.DecisionOperation;
+import org.onap.policy.controlloop.actor.guard.GuardActor;
+import org.onap.policy.controlloop.actor.so.VfModuleCreate;
+import org.onap.policy.controlloop.actorserviceprovider.Operation;
+import org.onap.policy.controlloop.actorserviceprovider.OperationProperties;
+import org.onap.policy.controlloop.actorserviceprovider.controlloop.ControlLoopEventContext;
+import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
+import org.onap.policy.controlloop.eventmanager.StepContext;
+
+public class GuardStep2Test {
+ private static final String CL_NAME = "my-closed-loop";
+ private static final String MASTER_ACTOR = "master-actor";
+ private static final String MASTER_OPERATION = "master-operation";
+ private static final String MY_TARGET = "my-target";
+ private static final UUID REQ_ID = UUID.randomUUID();
+ private static final int VF_COUNT = 10;
+
+ @Mock
+ private ControlLoopEventContext context;
+ @Mock
+ private StepContext stepContext;
+ @Mock
+ private VirtualControlLoopEvent event;
+ @Mock
+ private Operation policyOper;
+
+ private ControlLoopOperationParams params;
+ private Step2 master;
+ private GuardStep2 step;
+
+ /**
+ * Sets up.
+ */
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ when(event.getRequestId()).thenReturn(REQ_ID);
+
+ when(context.getEvent()).thenReturn(event);
+
+ when(stepContext.getProperty(OperationProperties.AAI_TARGET_ENTITY)).thenReturn(MY_TARGET);
+ when(stepContext.contains(OperationProperties.DATA_VF_COUNT)).thenReturn(true);
+ when(stepContext.getProperty(OperationProperties.DATA_VF_COUNT)).thenReturn(VF_COUNT);
+
+
+ params = ControlLoopOperationParams.builder().actor(MASTER_ACTOR).operation(MASTER_OPERATION)
+ .targetEntity(MY_TARGET).context(context).build();
+
+ master = new Step2(stepContext, params, event) {
+ @Override
+ protected Operation buildOperation() {
+ return policyOper;
+ }
+ };
+
+ // force it to build the operation
+ master.init();
+
+ step = new GuardStep2(master, CL_NAME);
+ }
+
+ @Test
+ public void testConstructor() {
+ assertEquals(GuardActor.NAME, step.getActorName());
+ assertEquals(DecisionOperation.NAME, step.getOperationName());
+ assertSame(stepContext, step.stepContext);
+ assertSame(event, step.event);
+
+ // test when master is uninitialized
+ master = new Step2(stepContext, params, event);
+ assertThatIllegalStateException().isThrownBy(() -> new GuardStep2(master, CL_NAME));
+
+ ControlLoopOperationParams params2 = step.getParams();
+
+ // @formatter:off
+ assertThat(params2.getPayload()).isEqualTo(Map.of(
+ "actor", MASTER_ACTOR,
+ "operation", MASTER_OPERATION,
+ "requestId", REQ_ID,
+ "clname", CL_NAME));
+ // @formatter:on
+ }
+
+ @Test
+ public void testAcceptsEvent() {
+ // it should always accept events
+ assertTrue(step.acceptsEvent());
+ }
+
+ @Test
+ public void testGetPropertyNames() {
+ // unmatching property names
+ when(policyOper.getPropertyNames()).thenReturn(List.of("propA", "propB"));
+ assertThat(step.getPropertyNames()).isEmpty();
+
+ // matching property names
+ when(policyOper.getPropertyNames()).thenReturn(List.of("propA", OperationProperties.DATA_VF_COUNT, "propB"));
+ assertThat(step.getPropertyNames()).isEqualTo(List.of(OperationProperties.DATA_VF_COUNT));
+ }
+
+ @Test
+ public void testLoadTargetEntity() {
+ step.loadTargetEntity(OperationProperties.AAI_TARGET_ENTITY);
+ assertThat(step.getParams().getPayload().get(GuardStep2.PAYLOAD_KEY_TARGET_ENTITY)).isEqualTo(MY_TARGET);
+ }
+
+ /**
+ * Tests loadVfCount() when the policy operation is NOT "VF Module Create".
+ */
+ @Test
+ public void testLoadVfCountNotVfModuleCreate() {
+ // should decrement the count
+ step.loadVfCount("");
+ assertThat(step.getParams().getPayload().get(GuardStep2.PAYLOAD_KEY_VF_COUNT)).isEqualTo(VF_COUNT - 1);
+ }
+
+ /**
+ * Tests loadVfCount() when the policy operation is "VF Module Create".
+ */
+ @Test
+ public void testLoadVfCountVfModuleCreate() {
+ when(policyOper.getName()).thenReturn(VfModuleCreate.NAME);
+
+ // should increment the count
+ step.loadVfCount("");
+ assertThat(step.getParams().getPayload().get(GuardStep2.PAYLOAD_KEY_VF_COUNT)).isEqualTo(VF_COUNT + 1);
+ }
+}
diff --git a/controlloop/common/controller-usecases/src/test/java/org/onap/policy/drools/apps/controller/usecases/step/LockStep2Test.java b/controlloop/common/controller-usecases/src/test/java/org/onap/policy/drools/apps/controller/usecases/step/LockStep2Test.java
new file mode 100644
index 000000000..2afd39547
--- /dev/null
+++ b/controlloop/common/controller-usecases/src/test/java/org/onap/policy/drools/apps/controller/usecases/step/LockStep2Test.java
@@ -0,0 +1,134 @@
+/*-
+ * ============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.drools.apps.controller.usecases.step;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Consumer;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.onap.policy.controlloop.VirtualControlLoopEvent;
+import org.onap.policy.controlloop.actorserviceprovider.Operation;
+import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
+import org.onap.policy.controlloop.actorserviceprovider.OperationProperties;
+import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
+import org.onap.policy.controlloop.eventmanager.ActorConstants;
+import org.onap.policy.controlloop.eventmanager.StepContext;
+
+public class LockStep2Test {
+ private static final String MY_TARGET = "my-target";
+
+ @Mock
+ private StepContext stepContext;
+ @Mock
+ private Operation policyOper;
+ @Mock
+ private VirtualControlLoopEvent event;
+ @Mock
+ private Consumer<OperationOutcome> callback;
+
+ private ControlLoopOperationParams params;
+ private CompletableFuture<OperationOutcome> future;
+ private Step2 master;
+ private LockStep2 step;
+
+ /**
+ * Sets up.
+ */
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ future = new CompletableFuture<>();
+
+ when(stepContext.requestLock(MY_TARGET)).thenReturn(future);
+ when(stepContext.getProperty(OperationProperties.AAI_TARGET_ENTITY)).thenReturn(MY_TARGET);
+
+ params = ControlLoopOperationParams.builder().completeCallback(callback).build();
+
+ master = new Step2(stepContext, params, event) {
+ @Override
+ protected Operation buildOperation() {
+ return policyOper;
+ }
+ };
+
+ // force it to build the operation
+ master.init();
+
+ step = new LockStep2(master);
+ }
+
+ @Test
+ public void testConstructor() {
+ assertEquals(ActorConstants.LOCK_ACTOR, step.getActorName());
+ assertEquals(ActorConstants.LOCK_OPERATION, step.getOperationName());
+ assertSame(stepContext, step.stepContext);
+ assertSame(event, step.event);
+ }
+
+ @Test
+ public void testAcceptsEvent() {
+ // it should always accept events
+ assertTrue(step.acceptsEvent());
+ }
+
+ @Test
+ public void testStart() {
+ // start the operation
+ step.init();
+ step.setProperties();
+ assertTrue(step.start(100));
+
+ // complete the operation's future
+ OperationOutcome outcome = params.makeOutcome();
+ outcome.setTarget(MY_TARGET);
+
+ future.complete(outcome);
+
+ // ensure it invoked the callback
+ verify(callback).accept(outcome);
+ }
+
+ /**
+ * Tests start when the operation throws an exception.
+ */
+ @Test
+ public void testStartNoFuture() {
+ // start the operation
+ step.init();
+
+ // force an exception by NOT invoking setProperties()
+
+ assertTrue(step.start(100));
+
+ // should have already invoked the callback
+ verify(callback).accept(any());
+ }
+}
diff --git a/controlloop/common/controller-usecases/src/test/java/org/onap/policy/drools/apps/controller/usecases/step/Step2Test.java b/controlloop/common/controller-usecases/src/test/java/org/onap/policy/drools/apps/controller/usecases/step/Step2Test.java
new file mode 100644
index 000000000..75fe486ed
--- /dev/null
+++ b/controlloop/common/controller-usecases/src/test/java/org/onap/policy/drools/apps/controller/usecases/step/Step2Test.java
@@ -0,0 +1,514 @@
+/*-
+ * ============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.drools.apps.controller.usecases.step;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatCode;
+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.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.UUID;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ForkJoinPool;
+import java.util.concurrent.LinkedBlockingQueue;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+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.StandardCoderObject;
+import org.onap.policy.controlloop.VirtualControlLoopEvent;
+import org.onap.policy.controlloop.actor.aai.AaiGetPnfOperation;
+import org.onap.policy.controlloop.actor.aai.AaiGetTenantOperation;
+import org.onap.policy.controlloop.actorserviceprovider.ActorService;
+import org.onap.policy.controlloop.actorserviceprovider.Operation;
+import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
+import org.onap.policy.controlloop.actorserviceprovider.OperationProperties;
+import org.onap.policy.controlloop.actorserviceprovider.Operator;
+import org.onap.policy.controlloop.actorserviceprovider.controlloop.ControlLoopEventContext;
+import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
+import org.onap.policy.controlloop.actorserviceprovider.spi.Actor;
+import org.onap.policy.controlloop.eventmanager.ControlLoopOperationManager2;
+import org.onap.policy.controlloop.eventmanager.StepContext;
+import org.onap.policy.controlloop.policy.Policy;
+import org.onap.policy.controlloop.policy.Target;
+import org.onap.policy.controlloop.policy.TargetType;
+import org.onap.policy.drools.apps.controller.usecases.UsecasesConstants;
+
+public class Step2Test {
+ private static final UUID REQ_ID = UUID.randomUUID();
+ private static final String POLICY_ID = "my-policy";
+ private static final String POLICY_ACTOR = "my-actor";
+ private static final String POLICY_OPERATION = "my-operation";
+ private static final String MY_TARGET = "my-target";
+ private static final String PAYLOAD_KEY = "payload-key";
+ private static final String PAYLOAD_VALUE = "payload-value";
+ private static final Integer POLICY_RETRY = 3;
+ private static final Integer POLICY_TIMEOUT = 20;
+ private static final String NO_SLASH = "noslash";
+ private static final String ONE_SLASH = "/one";
+
+ @Mock
+ private Operator policyOperator;
+ @Mock
+ private Operation policyOperation;
+ @Mock
+ private Actor policyActor;
+ @Mock
+ private ActorService actors;
+ @Mock
+ private StepContext stepContext;
+ @Mock
+ private AaiCqResponse aaicq;
+
+ private CompletableFuture<OperationOutcome> future;
+ private Target target;
+ private Map<String, String> payload;
+ private Policy policy;
+ private VirtualControlLoopEvent event;
+ private ControlLoopEventContext context;
+ private BlockingQueue<OperationOutcome> starts;
+ private BlockingQueue<OperationOutcome> completions;
+ private ControlLoopOperationParams params;
+ private Step2 step;
+
+ /**
+ * Sets up.
+ */
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ future = new CompletableFuture<>();
+
+ // configure policy operation
+ when(actors.getActor(POLICY_ACTOR)).thenReturn(policyActor);
+ when(policyActor.getOperator(POLICY_OPERATION)).thenReturn(policyOperator);
+ when(policyOperator.buildOperation(any())).thenReturn(policyOperation);
+ when(policyOperation.start()).thenReturn(future);
+
+ when(policyOperation.getPropertyNames()).thenReturn(List.of());
+
+ when(stepContext.getProperty(AaiCqResponse.CONTEXT_KEY)).thenReturn(aaicq);
+
+ target = new Target();
+ target.setType(TargetType.VM);
+
+ payload = Map.of(PAYLOAD_KEY, PAYLOAD_VALUE);
+
+ policy = new Policy();
+ policy.setId(POLICY_ID);
+ policy.setActor(POLICY_ACTOR);
+ policy.setRecipe(POLICY_OPERATION);
+ policy.setTarget(target);
+ policy.setPayload(payload);
+ policy.setRetry(POLICY_RETRY);
+ policy.setTimeout(POLICY_TIMEOUT);
+
+ event = new VirtualControlLoopEvent();
+ event.setRequestId(REQ_ID);
+ event.setTarget(ControlLoopOperationManager2.VSERVER_VSERVER_NAME);
+ event.setAai(new TreeMap<>(Map.of(ControlLoopOperationManager2.VSERVER_VSERVER_NAME, MY_TARGET)));
+
+ context = new ControlLoopEventContext(event);
+
+ starts = new LinkedBlockingQueue<>();
+ completions = new LinkedBlockingQueue<>();
+
+ params = ControlLoopOperationParams.builder().actor(POLICY_ACTOR).actorService(actors)
+ .completeCallback(completions::add).context(context).executor(ForkJoinPool.commonPool())
+ .operation(POLICY_OPERATION).payload(new TreeMap<>(payload)).startCallback(starts::add)
+ .target(target).targetEntity(MY_TARGET).build();
+
+ step = new Step2(stepContext, params, event);
+ step.init();
+ }
+
+ @Test
+ public void testConstructor() {
+ assertSame(stepContext, step.stepContext);
+ assertSame(event, step.event);
+ assertSame(actors, step.getParams().getActorService());
+ }
+
+ @Test
+ public void testConstructorStep2() {
+ step = new Step2(step, "actorB", "operationB");
+ assertSame(stepContext, step.stepContext);
+ assertSame(event, step.event);
+
+ assertEquals("actorB", step.getActorName());
+ assertEquals("operationB", step.getOperationName());
+ assertSame(actors, step.getParams().getActorService());
+ }
+
+ @Test
+ public void testAcceptsEvent() {
+ // it's a policy step, thus it accepts events
+ assertTrue(step.acceptsEvent());
+
+ step = new Step2(step, "actorB", "operationB");
+
+ // it's not a policy step, thus it does not accept events
+ assertFalse(step.acceptsEvent());
+ }
+
+ @Test
+ public void testSuccess() {
+ assertThatCode(() -> step.success(null)).doesNotThrowAnyException();
+ }
+
+ @Test
+ public void testGetPropertyNames() {
+ // empty property list
+ assertThat(step.getPropertyNames()).isEmpty();
+
+ // try with non-empty list
+ when(policyOperation.getPropertyNames()).thenReturn(List.of("propA", "propB"));
+ assertThat(step.getPropertyNames()).isEqualTo(List.of("propA", "propB"));
+ }
+
+ @Test
+ public void testSetProperties() {
+ CloudRegion cloudRegion = new CloudRegion();
+ when(aaicq.getDefaultCloudRegion()).thenReturn(cloudRegion);
+
+ Tenant tenant = new Tenant();
+ when(aaicq.getDefaultTenant()).thenReturn(tenant);
+
+ when(policyOperation.getPropertyNames()).thenReturn(
+ List.of(OperationProperties.AAI_DEFAULT_CLOUD_REGION, OperationProperties.AAI_DEFAULT_TENANT));
+
+ step.setProperties();
+
+ // should have been exactly two properties set
+ verify(policyOperation, times(2)).setProperty(any(), any());
+ verify(policyOperation).setProperty(OperationProperties.AAI_DEFAULT_CLOUD_REGION, cloudRegion);
+ verify(policyOperation).setProperty(OperationProperties.AAI_DEFAULT_TENANT, tenant);
+ }
+
+ /**
+ * Tests setProperties() when the property is unknown.
+ */
+ @Test
+ public void testSetPropertiesUnknown() {
+ when(policyOperation.getPropertyNames()).thenReturn(List.of("unknown-property"));
+
+ assertThatIllegalArgumentException().isThrownBy(() -> step.setProperties())
+ .withMessage("unknown property unknown-property needed by my-actor.my-operation");
+ }
+
+ @Test
+ public void testLoadCloudRegion_testGetCloudRegion() {
+ CloudRegion data = new CloudRegion();
+ when(aaicq.getDefaultCloudRegion()).thenReturn(data);
+ when(policyOperation.getPropertyNames()).thenReturn(List.of(OperationProperties.AAI_DEFAULT_CLOUD_REGION));
+
+ step.setProperties();
+ verify(policyOperation).setProperty(OperationProperties.AAI_DEFAULT_CLOUD_REGION, data);
+ }
+
+ @Test
+ public void testLoadTenant_testGetTenant() {
+ Tenant data = new Tenant();
+ when(aaicq.getDefaultTenant()).thenReturn(data);
+ when(policyOperation.getPropertyNames()).thenReturn(List.of(OperationProperties.AAI_DEFAULT_TENANT));
+
+ step.setProperties();
+ verify(policyOperation).setProperty(OperationProperties.AAI_DEFAULT_TENANT, data);
+ }
+
+ @Test
+ public void testLoadPnf_testGetPnf() {
+ StandardCoderObject data = new StandardCoderObject();
+ when(stepContext.getProperty(OperationProperties.AAI_TARGET_ENTITY)).thenReturn(MY_TARGET);
+ when(stepContext.getProperty(AaiGetPnfOperation.getKey(MY_TARGET))).thenReturn(data);
+ when(policyOperation.getPropertyNames()).thenReturn(List.of(OperationProperties.AAI_PNF));
+
+ step.setProperties();
+ verify(policyOperation).setProperty(OperationProperties.AAI_PNF, data);
+ }
+
+ @Test
+ public void testLoadResourceVnf_testGetResourceVnf() {
+ target.setResourceID("my-resource");
+ GenericVnf data = new GenericVnf();
+ when(aaicq.getGenericVnfByModelInvariantId("my-resource")).thenReturn(data);
+ when(policyOperation.getPropertyNames()).thenReturn(List.of(OperationProperties.AAI_RESOURCE_VNF));
+
+ step.setProperties();
+ verify(policyOperation).setProperty(OperationProperties.AAI_RESOURCE_VNF, data);
+
+ // missing resource ID
+ target.setResourceID(null);
+ assertThatIllegalArgumentException().isThrownBy(() -> step.setProperties())
+ .withMessageContaining("missing Target resource ID");
+
+ // missing target
+ params = params.toBuilder().target(null).build();
+ step = new Step2(stepContext, params, event);
+ step.init();
+ assertThatIllegalArgumentException().isThrownBy(() -> step.setProperties())
+ .withMessageContaining(Step2.TARGET_INFO_MSG);
+ }
+
+ @Test
+ public void testLoadService_testGetService() {
+ ServiceInstance data = new ServiceInstance();
+ when(aaicq.getServiceInstance()).thenReturn(data);
+ when(policyOperation.getPropertyNames()).thenReturn(List.of(OperationProperties.AAI_SERVICE));
+
+ step.setProperties();
+ verify(policyOperation).setProperty(OperationProperties.AAI_SERVICE, data);
+ }
+
+ @Test
+ public void testLoadServiceModel_testGetServiceModel() {
+ ServiceInstance service = new ServiceInstance();
+ service.setModelVersionId("my-service-version");
+ when(aaicq.getServiceInstance()).thenReturn(service);
+
+ ModelVer data = new ModelVer();
+ when(aaicq.getModelVerByVersionId("my-service-version")).thenReturn(data);
+ when(policyOperation.getPropertyNames()).thenReturn(List.of(OperationProperties.AAI_SERVICE_MODEL));
+
+ step.setProperties();
+ verify(policyOperation).setProperty(OperationProperties.AAI_SERVICE_MODEL, data);
+ }
+
+ @Test
+ public void testLoadVnf_testGetVnf() {
+ target.setModelInvariantId("my-model-invariant");
+ GenericVnf data = new GenericVnf();
+ when(aaicq.getGenericVnfByVfModuleModelInvariantId("my-model-invariant")).thenReturn(data);
+ when(policyOperation.getPropertyNames()).thenReturn(List.of(OperationProperties.AAI_VNF));
+
+ step.setProperties();
+ verify(policyOperation).setProperty(OperationProperties.AAI_VNF, data);
+
+ // missing model invariant ID
+ target.setModelInvariantId(null);
+ assertThatIllegalArgumentException().isThrownBy(() -> step.setProperties())
+ .withMessageContaining("missing modelInvariantId");
+
+ // missing target
+ params = params.toBuilder().target(null).build();
+ step = new Step2(stepContext, params, event);
+ step.init();
+ assertThatIllegalArgumentException().isThrownBy(() -> step.setProperties())
+ .withMessageContaining(Step2.TARGET_INFO_MSG);
+ }
+
+ @Test
+ public void testLoadVnfModel_testGetVnfModel() {
+ target.setModelInvariantId("my-model-invariant");
+ GenericVnf vnf = new GenericVnf();
+ when(aaicq.getGenericVnfByVfModuleModelInvariantId("my-model-invariant")).thenReturn(vnf);
+
+ vnf.setModelVersionId("my-vnf-model-version-id");
+ ModelVer data = new ModelVer();
+ when(aaicq.getModelVerByVersionId("my-vnf-model-version-id")).thenReturn(data);
+ when(policyOperation.getPropertyNames()).thenReturn(List.of(OperationProperties.AAI_VNF_MODEL));
+
+ step.setProperties();
+ verify(policyOperation).setProperty(OperationProperties.AAI_VNF_MODEL, data);
+ }
+
+ @Test
+ public void testLoadVserverLink_testGetVserverLink() {
+ event.setAai(Map.of(Step2.VSERVER_VSERVER_NAME, "vserverB"));
+
+ StandardCoderObject tenant = mock(StandardCoderObject.class);
+ when(stepContext.getProperty(AaiGetTenantOperation.getKey("vserverB"))).thenReturn(tenant);
+
+ when(tenant.getString("result-data", 0, "resource-link")).thenReturn("/aai/v7/some/link/bbb");
+
+ when(policyOperation.getPropertyNames()).thenReturn(List.of(OperationProperties.AAI_VSERVER_LINK));
+
+ step.setProperties();
+ verify(policyOperation).setProperty(OperationProperties.AAI_VSERVER_LINK, "/some/link/bbb");
+
+ // missing resource link
+ when(tenant.getString("result-data", 0, "resource-link")).thenReturn(null);
+ assertThatIllegalArgumentException().isThrownBy(() -> step.setProperties())
+ .withMessageContaining("missing tenant data resource-link");
+
+ // missing tenant data
+ when(stepContext.getProperty(AaiGetTenantOperation.getKey("vserverB"))).thenReturn(null);
+ assertThatIllegalArgumentException().isThrownBy(() -> step.setProperties())
+ .withMessageContaining("missing tenant data for");
+
+ // empty vserver name
+ event.setAai(Map.of(Step2.VSERVER_VSERVER_NAME, ""));
+ assertThatIllegalArgumentException().isThrownBy(() -> step.setProperties())
+ .withMessageContaining("missing vserver.vserver-name");
+
+ // missing vserver name
+ event.setAai(Map.of());
+ assertThatIllegalArgumentException().isThrownBy(() -> step.setProperties())
+ .withMessageContaining("missing vserver.vserver-name");
+ }
+
+ @Test
+ public void testLoadVfCount_testGetVfCount() {
+ target.setModelCustomizationId("vf-count-customization");
+ target.setModelInvariantId("vf-count-invariant");
+ target.setModelVersionId("vf-count-version");
+ when(aaicq.getVfModuleCount("vf-count-customization", "vf-count-invariant", "vf-count-version")).thenReturn(11);
+ when(policyOperation.getPropertyNames()).thenReturn(List.of(OperationProperties.DATA_VF_COUNT));
+
+ step.setProperties();
+ verify(policyOperation).setProperty(OperationProperties.DATA_VF_COUNT, 11);
+
+ // missing model version id
+ target.setModelVersionId(null);
+ assertThatIllegalArgumentException().isThrownBy(() -> step.setProperties())
+ .withMessageContaining("missing target modelVersionId");
+
+ // missing model invariant id
+ target.setModelInvariantId(null);
+ assertThatIllegalArgumentException().isThrownBy(() -> step.setProperties())
+ .withMessageContaining("missing target modelInvariantId");
+
+ // missing model customization id
+ target.setModelCustomizationId(null);
+ assertThatIllegalArgumentException().isThrownBy(() -> step.setProperties())
+ .withMessageContaining("missing target modelCustomizationId");
+
+ // missing target
+ params = params.toBuilder().target(null).build();
+ step = new Step2(stepContext, params, event);
+ step.init();
+ assertThatIllegalArgumentException().isThrownBy(() -> step.setProperties())
+ .withMessageContaining(Step2.TARGET_INFO_MSG);
+
+ // get it from the step context
+ when(stepContext.contains(OperationProperties.DATA_VF_COUNT)).thenReturn(true);
+ when(stepContext.getProperty(OperationProperties.DATA_VF_COUNT)).thenReturn(22);
+ step.setProperties();
+ verify(policyOperation).setProperty(OperationProperties.DATA_VF_COUNT, 22);
+ }
+
+ @Test
+ public void testLoadEnrichment_testGetEnrichment() {
+ event.setAai(Map.of("bandwidth", "bandwidth-value"));
+ when(policyOperation.getPropertyNames()).thenReturn(List.of(OperationProperties.ENRICHMENT_BANDWIDTH));
+
+ step.setProperties();
+ verify(policyOperation).setProperty(OperationProperties.ENRICHMENT_BANDWIDTH, "bandwidth-value");
+
+ // missing enrichment data
+ event.setAai(Map.of());
+ assertThatIllegalArgumentException().isThrownBy(() -> step.setProperties());
+ }
+
+ @Test
+ public void testLoadAdditionalEventParams_testGetAdditionalEventParams() {
+ Map<String, String> data = Map.of("addA", "add-valueA", "addB", "add-valueB");
+ event.setAdditionalEventParams(data);
+ when(policyOperation.getPropertyNames()).thenReturn(List.of(OperationProperties.EVENT_ADDITIONAL_PARAMS));
+
+ step.setProperties();
+ verify(policyOperation).setProperty(OperationProperties.EVENT_ADDITIONAL_PARAMS, data);
+ }
+
+ @Test
+ public void testLoadEventPayload_testGetEventPayload() {
+ event.setPayload("some-event-payload");
+ when(policyOperation.getPropertyNames()).thenReturn(List.of(OperationProperties.EVENT_PAYLOAD));
+
+ step.setProperties();
+ verify(policyOperation).setProperty(OperationProperties.EVENT_PAYLOAD, "some-event-payload");
+ }
+
+ @Test
+ public void testLoadOptCdsGrpcAaiProperties() {
+ when(policyOperation.getPropertyNames()).thenReturn(List.of(OperationProperties.OPT_CDS_GRPC_AAI_PROPERTIES));
+
+ step.setProperties();
+ verify(policyOperation, never()).setProperty(any(), anyString());
+ }
+
+ @Test
+ public void testLoadDefaultGenericVnf_testGetDefaultGenericVnf() {
+ GenericVnf data = new GenericVnf();
+ when(aaicq.getDefaultGenericVnf()).thenReturn(data);
+ when(policyOperation.getPropertyNames()).thenReturn(List.of(UsecasesConstants.AAI_DEFAULT_GENERIC_VNF));
+
+ step.setProperties();
+ verify(policyOperation).setProperty(UsecasesConstants.AAI_DEFAULT_GENERIC_VNF, data);
+ }
+
+ @Test
+ public void testGetCustomQueryData() {
+ assertSame(aaicq, step.getCustomQueryData());
+
+ when(stepContext.getProperty(AaiCqResponse.CONTEXT_KEY)).thenReturn(null);
+
+ assertThatIllegalArgumentException().isThrownBy(() -> step.getCustomQueryData())
+ .withMessage("missing custom query data for my-actor.my-operation");
+ }
+
+ @Test
+ public void testVerifyNotNull() {
+ assertThatCode(() -> step.verifyNotNull("verifyA", "verify-value-A")).doesNotThrowAnyException();
+
+ assertThatIllegalArgumentException().isThrownBy(() -> step.verifyNotNull("verifyB", null))
+ .withMessage("missing verifyB for my-actor.my-operation");
+ }
+
+ @Test
+ public void testStripPrefix() {
+ assertEquals(NO_SLASH, Step2.stripPrefix(NO_SLASH, 0));
+ assertEquals(NO_SLASH, Step2.stripPrefix(NO_SLASH, 1));
+ assertEquals(NO_SLASH, Step2.stripPrefix(NO_SLASH, 2));
+
+ assertEquals(ONE_SLASH, Step2.stripPrefix(ONE_SLASH, 1));
+ assertEquals(ONE_SLASH, Step2.stripPrefix(ONE_SLASH, 2));
+
+ assertEquals("/slashes", Step2.stripPrefix("/two/slashes", 2));
+ assertEquals("/slashes", Step2.stripPrefix("/two/slashes", 3));
+
+ assertEquals("/and/more", Step2.stripPrefix("/three/slashes/and/more", 3));
+
+ assertEquals("/and/more", Step2.stripPrefix("prefix/three/slashes/and/more", 3));
+ }
+
+}