aboutsummaryrefslogtreecommitdiffstats
path: root/models-interactions/model-actors/actor.sdnc
diff options
context:
space:
mode:
authorJim Hahn <jrh3@att.com>2020-02-06 21:48:12 -0500
committerJim Hahn <jrh3@att.com>2020-02-07 13:21:52 -0500
commite06578535f6afadac715c04ed03c74c05a075780 (patch)
tree1c9a0141daf15b93cb4f6452703d92cf8a6d751c /models-interactions/model-actors/actor.sdnc
parentaccad88260f99c1b5c5329285b73aa84349e623b (diff)
Clean up and enhancement of Actor re-design
Added junits for the remaining code. Enhancements to facilitate implementation of Operators: - Added allOf(), anyOf() facilities - Added AsyncResponseHandler for handling asynchronous I/O via the HttpClient - Added logRestRequest() and logRestResponse() for logging REST requests and responses - Added HttpActor and HttpOperator, which can be used as superclasses - Added doTask() - Lifted data from the event into ControlLoopEventContext Updates per previous review comments: - Changed logException() to runFunction(). - Removed the aaiCqResponse field. - Lifted fields from Policy into ControlLoopOperationParams, eliminating the need to include Policy in the class. OperatorPartial depends on the string values in the ControlLoopOperation being set to one of the string values of PolicyResult. Instead of passing ControlLoopOperation around, the operators should pass around an object that uses PolicyResult directly, rather than depending on the string values being set correctly. Created OperationOutcome for this purpose. Stop pipeline when the controller completes. Use whenComplete() where appropriate. startOperationAsync() should not block. Modified it to launch the task in the background via its own thread. Extracted CallbackManager into its own file. Replaced actor setOperators() with addOperator() Renamed add() to wrap(), and modified it to remove the future when it completes. Fixed the signature on delayedRemove() and delayedComplete(). Replaced xxxAsync() calls with just xxx() calls, where appropriate to avoid the extra overhead of submitting it to a work queue. Renamed handleFailure() to handlePreprocessorFailure(). Updates per WIP review comments Issue-ID: POLICY-1625 Signed-off-by: Jim Hahn <jrh3@att.com> Change-Id: Id4c4c7ade979bdb76cc54266837609cc69a22c58
Diffstat (limited to 'models-interactions/model-actors/actor.sdnc')
-rw-r--r--models-interactions/model-actors/actor.sdnc/src/main/java/org/onap/policy/controlloop/actor/sdnc/BandwidthOnDemandOperator.java24
-rw-r--r--models-interactions/model-actors/actor.sdnc/src/main/java/org/onap/policy/controlloop/actor/sdnc/RerouteOperator.java22
-rw-r--r--models-interactions/model-actors/actor.sdnc/src/main/java/org/onap/policy/controlloop/actor/sdnc/SdncActorServiceProvider.java27
-rw-r--r--models-interactions/model-actors/actor.sdnc/src/main/java/org/onap/policy/controlloop/actor/sdnc/SdncOperator.java132
-rw-r--r--models-interactions/model-actors/actor.sdnc/src/test/java/org/onap/policy/controlloop/actor/sdnc/BandwidthOnDemandOperatorTest.java70
-rw-r--r--models-interactions/model-actors/actor.sdnc/src/test/java/org/onap/policy/controlloop/actor/sdnc/BasicOperator.java94
-rw-r--r--models-interactions/model-actors/actor.sdnc/src/test/java/org/onap/policy/controlloop/actor/sdnc/RerouteOperatorTest.java70
-rw-r--r--models-interactions/model-actors/actor.sdnc/src/test/java/org/onap/policy/controlloop/actor/sdnc/SdncActorServiceProviderTest.java25
-rw-r--r--models-interactions/model-actors/actor.sdnc/src/test/java/org/onap/policy/controlloop/actor/sdnc/SdncOperatorTest.java326
-rw-r--r--models-interactions/model-actors/actor.sdnc/src/test/resources/bod.json32
-rw-r--r--models-interactions/model-actors/actor.sdnc/src/test/resources/reroute.json17
11 files changed, 730 insertions, 109 deletions
diff --git a/models-interactions/model-actors/actor.sdnc/src/main/java/org/onap/policy/controlloop/actor/sdnc/BandwidthOnDemandOperator.java b/models-interactions/model-actors/actor.sdnc/src/main/java/org/onap/policy/controlloop/actor/sdnc/BandwidthOnDemandOperator.java
index 0e721bf8c..2927bd85b 100644
--- a/models-interactions/model-actors/actor.sdnc/src/main/java/org/onap/policy/controlloop/actor/sdnc/BandwidthOnDemandOperator.java
+++ b/models-interactions/model-actors/actor.sdnc/src/main/java/org/onap/policy/controlloop/actor/sdnc/BandwidthOnDemandOperator.java
@@ -22,7 +22,7 @@ package org.onap.policy.controlloop.actor.sdnc;
import java.util.UUID;
import org.apache.commons.lang3.StringUtils;
-import org.onap.policy.controlloop.VirtualControlLoopEvent;
+import org.onap.policy.controlloop.actorserviceprovider.controlloop.ControlLoopEventContext;
import org.onap.policy.sdnc.SdncHealRequest;
import org.onap.policy.sdnc.SdncHealRequestHeaderInfo;
import org.onap.policy.sdnc.SdncHealRequestInfo;
@@ -37,6 +37,12 @@ import org.onap.policy.sdnc.SdncRequest;
public class BandwidthOnDemandOperator extends SdncOperator {
public static final String NAME = "BandwidthOnDemand";
+ public static final String URI = "/GENERIC-RESOURCE-API:vf-module-topology-operation";
+
+ // fields in the enrichment data
+ public static final String SERVICE_ID_KEY = "service-instance.service-instance-id";
+ public static final String VNF_ID = "vnfId";
+
/**
* Constructs the object.
*
@@ -47,19 +53,19 @@ public class BandwidthOnDemandOperator extends SdncOperator {
}
@Override
- protected SdncRequest constructRequest(VirtualControlLoopEvent onset) {
- String serviceInstance = onset.getAai().get("service-instance.service-instance-id");
+ protected SdncRequest constructRequest(ControlLoopEventContext context) {
+ String serviceInstance = context.getEnrichment().get(SERVICE_ID_KEY);
if (StringUtils.isBlank(serviceInstance)) {
- throw new IllegalArgumentException("missing enrichment data, service-instance-id");
+ throw new IllegalArgumentException("missing enrichment data, " + SERVICE_ID_KEY);
}
SdncHealVfModuleParameter bandwidth = new SdncHealVfModuleParameter();
bandwidth.setName("bandwidth");
- bandwidth.setValue(onset.getAai().get("bandwidth"));
+ bandwidth.setValue(context.getEnrichment().get("bandwidth"));
SdncHealVfModuleParameter timeStamp = new SdncHealVfModuleParameter();
timeStamp.setName("bandwidth-change-time");
- timeStamp.setValue(onset.getAai().get("bandwidth-change-time"));
+ timeStamp.setValue(context.getEnrichment().get("bandwidth-change-time"));
SdncHealVfModuleParametersInfo vfParametersInfo = new SdncHealVfModuleParametersInfo();
vfParametersInfo.addParameters(bandwidth);
@@ -80,11 +86,11 @@ public class BandwidthOnDemandOperator extends SdncOperator {
SdncRequest request = new SdncRequest();
request.setNsInstanceId(serviceInstance);
- request.setRequestId(onset.getRequestId());
- request.setUrl("/GENERIC-RESOURCE-API:vf-module-topology-operation");
+ request.setRequestId(context.getRequestId());
+ request.setUrl(URI);
SdncHealVnfInfo vnfInfo = new SdncHealVnfInfo();
- vnfInfo.setVnfId(onset.getAai().get("vnfId"));
+ vnfInfo.setVnfId(context.getEnrichment().get(VNF_ID));
SdncHealVfModuleInfo vfModuleInfo = new SdncHealVfModuleInfo();
vfModuleInfo.setVfModuleId("");
diff --git a/models-interactions/model-actors/actor.sdnc/src/main/java/org/onap/policy/controlloop/actor/sdnc/RerouteOperator.java b/models-interactions/model-actors/actor.sdnc/src/main/java/org/onap/policy/controlloop/actor/sdnc/RerouteOperator.java
index 59af31f4f..da400f8eb 100644
--- a/models-interactions/model-actors/actor.sdnc/src/main/java/org/onap/policy/controlloop/actor/sdnc/RerouteOperator.java
+++ b/models-interactions/model-actors/actor.sdnc/src/main/java/org/onap/policy/controlloop/actor/sdnc/RerouteOperator.java
@@ -22,7 +22,7 @@ package org.onap.policy.controlloop.actor.sdnc;
import java.util.UUID;
import org.apache.commons.lang3.StringUtils;
-import org.onap.policy.controlloop.VirtualControlLoopEvent;
+import org.onap.policy.controlloop.actorserviceprovider.controlloop.ControlLoopEventContext;
import org.onap.policy.sdnc.SdncHealNetworkInfo;
import org.onap.policy.sdnc.SdncHealRequest;
import org.onap.policy.sdnc.SdncHealRequestHeaderInfo;
@@ -33,6 +33,12 @@ import org.onap.policy.sdnc.SdncRequest;
public class RerouteOperator extends SdncOperator {
public static final String NAME = "Reroute";
+ public static final String URI = "/GENERIC-RESOURCE-API:network-topology-operation";
+
+ // fields in the enrichment data
+ public static final String SERVICE_ID_KEY = "service-instance.service-instance-id";
+ public static final String NETWORK_ID_KEY = "network-information.network-id";
+
/**
* Constructs the object.
*
@@ -43,17 +49,17 @@ public class RerouteOperator extends SdncOperator {
}
@Override
- protected SdncRequest constructRequest(VirtualControlLoopEvent onset) {
- String serviceInstance = onset.getAai().get("service-instance.service-instance-id");
+ protected SdncRequest constructRequest(ControlLoopEventContext context) {
+ String serviceInstance = context.getEnrichment().get(SERVICE_ID_KEY);
if (StringUtils.isBlank(serviceInstance)) {
- throw new IllegalArgumentException("missing enrichment data, service-instance-id");
+ throw new IllegalArgumentException("missing enrichment data, " + SERVICE_ID_KEY);
}
SdncHealServiceInfo serviceInfo = new SdncHealServiceInfo();
serviceInfo.setServiceInstanceId(serviceInstance);
- String networkId = onset.getAai().get("network-information.network-id");
+ String networkId = context.getEnrichment().get(NETWORK_ID_KEY);
if (StringUtils.isBlank(networkId)) {
- throw new IllegalArgumentException("missing enrichment data, network-id");
+ throw new IllegalArgumentException("missing enrichment data, " + NETWORK_ID_KEY);
}
SdncHealNetworkInfo networkInfo = new SdncHealNetworkInfo();
networkInfo.setNetworkId(networkId);
@@ -67,8 +73,8 @@ public class RerouteOperator extends SdncOperator {
SdncRequest request = new SdncRequest();
request.setNsInstanceId(serviceInstance);
- request.setRequestId(onset.getRequestId());
- request.setUrl("/GENERIC-RESOURCE-API:network-topology-operation");
+ request.setRequestId(context.getRequestId());
+ request.setUrl(URI);
SdncHealRequest healRequest = new SdncHealRequest();
healRequest.setRequestHeaderInfo(headerInfo);
diff --git a/models-interactions/model-actors/actor.sdnc/src/main/java/org/onap/policy/controlloop/actor/sdnc/SdncActorServiceProvider.java b/models-interactions/model-actors/actor.sdnc/src/main/java/org/onap/policy/controlloop/actor/sdnc/SdncActorServiceProvider.java
index 13276f929..8dc8ba50d 100644
--- a/models-interactions/model-actors/actor.sdnc/src/main/java/org/onap/policy/controlloop/actor/sdnc/SdncActorServiceProvider.java
+++ b/models-interactions/model-actors/actor.sdnc/src/main/java/org/onap/policy/controlloop/actor/sdnc/SdncActorServiceProvider.java
@@ -26,14 +26,10 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import java.util.Collections;
import java.util.List;
-import java.util.Map;
import java.util.UUID;
-import java.util.function.Function;
import org.onap.policy.controlloop.ControlLoopOperation;
import org.onap.policy.controlloop.VirtualControlLoopEvent;
-import org.onap.policy.controlloop.actorserviceprovider.Util;
-import org.onap.policy.controlloop.actorserviceprovider.impl.ActorImpl;
-import org.onap.policy.controlloop.actorserviceprovider.parameters.HttpActorParams;
+import org.onap.policy.controlloop.actorserviceprovider.impl.HttpActor;
import org.onap.policy.controlloop.policy.Policy;
import org.onap.policy.sdnc.SdncHealNetworkInfo;
import org.onap.policy.sdnc.SdncHealRequest;
@@ -49,7 +45,7 @@ import org.onap.policy.sdnc.SdncRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-public class SdncActorServiceProvider extends ActorImpl {
+public class SdncActorServiceProvider extends HttpActor {
private static final Logger logger = LoggerFactory.getLogger(SdncActorServiceProvider.class);
public static final String NAME = "SDNC";
@@ -78,23 +74,10 @@ public class SdncActorServiceProvider extends ActorImpl {
* Constructs the object.
*/
public SdncActorServiceProvider() {
- // @formatter:off
- super(NAME,
- new RerouteOperator(NAME),
- new BandwidthOnDemandOperator(NAME));
+ super(NAME);
- // @formatter:on
- }
-
- @Override
- protected Function<String, Map<String, Object>> makeOperatorParameters(Map<String, Object> actorParameters) {
- String actorName = getName();
-
- // @formatter:off
- return Util.translate(actorName, actorParameters, HttpActorParams.class)
- .doValidation(actorName)
- .makeOperationParameters(actorName);
- // @formatter:on
+ addOperator(new RerouteOperator(NAME));
+ addOperator(new BandwidthOnDemandOperator(NAME));
}
diff --git a/models-interactions/model-actors/actor.sdnc/src/main/java/org/onap/policy/controlloop/actor/sdnc/SdncOperator.java b/models-interactions/model-actors/actor.sdnc/src/main/java/org/onap/policy/controlloop/actor/sdnc/SdncOperator.java
index c2e4c8f8b..479ee908d 100644
--- a/models-interactions/model-actors/actor.sdnc/src/main/java/org/onap/policy/controlloop/actor/sdnc/SdncOperator.java
+++ b/models-interactions/model-actors/actor.sdnc/src/main/java/org/onap/policy/controlloop/actor/sdnc/SdncOperator.java
@@ -22,45 +22,31 @@ package org.onap.policy.controlloop.actor.sdnc;
import java.util.HashMap;
import java.util.Map;
+import java.util.concurrent.CompletableFuture;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
-import lombok.AccessLevel;
-import lombok.Getter;
-import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure;
import org.onap.policy.common.endpoints.http.client.HttpClient;
-import org.onap.policy.common.endpoints.http.client.HttpClientFactoryInstance;
-import org.onap.policy.common.endpoints.utils.NetLoggerUtil;
-import org.onap.policy.common.endpoints.utils.NetLoggerUtil.EventType;
-import org.onap.policy.common.parameters.ValidationResult;
-import org.onap.policy.controlloop.ControlLoopOperation;
-import org.onap.policy.controlloop.VirtualControlLoopEvent;
+import org.onap.policy.common.utils.coder.CoderException;
+import org.onap.policy.common.utils.coder.StandardCoder;
+import org.onap.policy.controlloop.actorserviceprovider.AsyncResponseHandler;
+import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
import org.onap.policy.controlloop.actorserviceprovider.Util;
-import org.onap.policy.controlloop.actorserviceprovider.impl.OperatorPartial;
+import org.onap.policy.controlloop.actorserviceprovider.controlloop.ControlLoopEventContext;
+import org.onap.policy.controlloop.actorserviceprovider.impl.HttpOperator;
import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
-import org.onap.policy.controlloop.actorserviceprovider.parameters.HttpParams;
-import org.onap.policy.controlloop.actorserviceprovider.parameters.ParameterValidationRuntimeException;
import org.onap.policy.controlloop.policy.PolicyResult;
import org.onap.policy.sdnc.SdncRequest;
import org.onap.policy.sdnc.SdncResponse;
-import org.onap.policy.sdnc.util.Serialization;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Superclass for SDNC Operators.
*/
-public abstract class SdncOperator extends OperatorPartial {
+public abstract class SdncOperator extends HttpOperator {
private static final Logger logger = LoggerFactory.getLogger(SdncOperator.class);
- @Getter(AccessLevel.PROTECTED)
- private HttpClient client;
-
- /**
- * URI path for this particular operation.
- */
- private String path;
-
/**
* Constructs the object.
*
@@ -71,74 +57,92 @@ public abstract class SdncOperator extends OperatorPartial {
super(actorName, name);
}
- // TODO add a junit for this and for plug-in via ActorService
@Override
- protected void doConfigure(Map<String, Object> parameters) {
- HttpParams params = Util.translate(getFullName(), parameters, HttpParams.class);
- ValidationResult result = params.validate(getFullName());
- if (!result.isValid()) {
- throw new ParameterValidationRuntimeException("invalid parameters", result);
- }
+ protected CompletableFuture<OperationOutcome> startOperationAsync(ControlLoopOperationParams params, int attempt,
+ OperationOutcome outcome) {
- client = HttpClientFactoryInstance.getClientFactory().get(params.getClientName());
- path = params.getPath();
- }
-
- @Override
- protected ControlLoopOperation doOperation(ControlLoopOperationParams params, int attempt,
- ControlLoopOperation operation) {
-
- SdncRequest request = constructRequest(params.getContext().getEvent());
- PolicyResult result = doRequest(request);
-
- return setOutcome(params, operation, result);
+ SdncRequest request = constructRequest(params.getContext());
+ return postRequest(params, outcome, request);
}
/**
* Constructs the request.
*
- * @param onset event for which the request should be constructed
+ * @param context associated event context
* @return a new request
*/
- protected abstract SdncRequest constructRequest(VirtualControlLoopEvent onset);
+ protected abstract SdncRequest constructRequest(ControlLoopEventContext context);
/**
- * Posts the request and retrieves the response.
+ * Posts the request and and arranges to retrieve the response.
*
+ * @param params operation parameters
+ * @param outcome updated with the response
* @param sdncRequest request to be posted
* @return the result of the request
*/
- private PolicyResult doRequest(SdncRequest sdncRequest) {
+ private CompletableFuture<OperationOutcome> postRequest(ControlLoopOperationParams params, OperationOutcome outcome,
+ SdncRequest sdncRequest) {
Map<String, Object> headers = new HashMap<>();
headers.put("Accept", "application/json");
- String sdncUrl = client.getBaseUrl();
-
- String sdncRequestJson = Serialization.gsonPretty.toJson(sdncRequest);
+ String sdncUrl = getClient().getBaseUrl();
- // TODO move this into a utility
- NetLoggerUtil.log(EventType.OUT, CommInfrastructure.REST, sdncUrl, sdncRequestJson);
- logger.info("[OUT|{}|{}|]{}{}", CommInfrastructure.REST, sdncUrl, NetLoggerUtil.SYSTEM_LS, sdncRequestJson);
+ Util.logRestRequest(sdncUrl, sdncRequest);
Entity<SdncRequest> entity = Entity.entity(sdncRequest, MediaType.APPLICATION_JSON);
- // TODO modify this to use asynchronous client operations
- Response rawResponse = client.post(path, entity, headers);
- String strResponse = HttpClient.getBody(rawResponse, String.class);
+ ResponseHandler handler = new ResponseHandler(params, outcome, sdncUrl);
+ return handler.handle(getClient().post(handler, getPath(), entity, headers));
+ }
+
+ private class ResponseHandler extends AsyncResponseHandler<Response> {
+ private final String sdncUrl;
- // TODO move this into a utility
- NetLoggerUtil.log(EventType.IN, CommInfrastructure.REST, sdncUrl, strResponse);
- logger.info("[IN|{}|{}|]{}{}", "Sdnc", sdncUrl, NetLoggerUtil.SYSTEM_LS, strResponse);
- logger.info("Response to Sdnc Heal post:");
- logger.info(strResponse);
+ public ResponseHandler(ControlLoopOperationParams params, OperationOutcome outcome, String sdncUrl) {
+ super(params, outcome);
+ this.sdncUrl = sdncUrl;
+ }
- SdncResponse response = Serialization.gsonPretty.fromJson(strResponse, SdncResponse.class);
+ /**
+ * Handles the response.
+ */
+ @Override
+ protected OperationOutcome doComplete(Response rawResponse) {
+ String strResponse = HttpClient.getBody(rawResponse, String.class);
+
+ Util.logRestResponse(sdncUrl, strResponse);
+
+ SdncResponse response;
+ try {
+ response = makeDecoder().decode(strResponse, SdncResponse.class);
+ } catch (CoderException e) {
+ logger.warn("Sdnc Heal cannot decode response with http error code {}", rawResponse.getStatus(), e);
+ return SdncOperator.this.setOutcome(getParams(), getOutcome(), PolicyResult.FAILURE_EXCEPTION);
+ }
+
+ if (response.getResponseOutput() != null && "200".equals(response.getResponseOutput().getResponseCode())) {
+ return SdncOperator.this.setOutcome(getParams(), getOutcome(), PolicyResult.SUCCESS);
+
+ } else {
+ logger.info("Sdnc Heal Restcall failed with http error code {}", rawResponse.getStatus());
+ return SdncOperator.this.setOutcome(getParams(), getOutcome(), PolicyResult.FAILURE);
+ }
+ }
- if (response.getResponseOutput() == null || !"200".equals(response.getResponseOutput().getResponseCode())) {
- logger.info("Sdnc Heal Restcall failed with http error code {}", rawResponse.getStatus());
- return PolicyResult.FAILURE;
+ /**
+ * Handles exceptions.
+ */
+ @Override
+ protected OperationOutcome doFailed(Throwable thrown) {
+ logger.info("Sdnc Heal Restcall threw an exception", thrown);
+ return SdncOperator.this.setOutcome(getParams(), getOutcome(), PolicyResult.FAILURE_EXCEPTION);
}
+ }
+
+ // these may be overridden by junit tests
- return PolicyResult.SUCCESS;
+ protected StandardCoder makeDecoder() {
+ return new StandardCoder();
}
}
diff --git a/models-interactions/model-actors/actor.sdnc/src/test/java/org/onap/policy/controlloop/actor/sdnc/BandwidthOnDemandOperatorTest.java b/models-interactions/model-actors/actor.sdnc/src/test/java/org/onap/policy/controlloop/actor/sdnc/BandwidthOnDemandOperatorTest.java
new file mode 100644
index 000000000..02931a4f1
--- /dev/null
+++ b/models-interactions/model-actors/actor.sdnc/src/test/java/org/onap/policy/controlloop/actor/sdnc/BandwidthOnDemandOperatorTest.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.controlloop.actor.sdnc;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.Map;
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.policy.common.utils.coder.CoderException;
+import org.onap.policy.sdnc.SdncRequest;
+
+public class BandwidthOnDemandOperatorTest extends BasicOperator {
+
+ private BandwidthOnDemandOperator oper;
+
+
+ /**
+ * Set up.
+ */
+ @Before
+ public void setUp() {
+ makeContext();
+ oper = new BandwidthOnDemandOperator(ACTOR);
+ }
+
+ @Test
+ public void testBandwidthOnDemandOperator() {
+ assertEquals(ACTOR, oper.getActorName());
+ assertEquals(BandwidthOnDemandOperator.NAME, oper.getName());
+ }
+
+ @Test
+ public void testConstructRequest() throws CoderException {
+ SdncRequest request = oper.constructRequest(context);
+ assertEquals("my-service", request.getNsInstanceId());
+ assertEquals(REQ_ID, request.getRequestId());
+ assertEquals(BandwidthOnDemandOperator.URI, request.getUrl());
+ assertNotNull(request.getHealRequest().getRequestHeaderInfo().getSvcRequestId());
+
+ verifyRequest("bod.json", request);
+
+ verifyMissing(oper, BandwidthOnDemandOperator.SERVICE_ID_KEY, "service");
+ }
+
+ @Override
+ protected Map<String, String> makeEnrichment() {
+ return Map.of(BandwidthOnDemandOperator.SERVICE_ID_KEY, "my-service", BandwidthOnDemandOperator.VNF_ID,
+ "my-vnf");
+ }
+}
diff --git a/models-interactions/model-actors/actor.sdnc/src/test/java/org/onap/policy/controlloop/actor/sdnc/BasicOperator.java b/models-interactions/model-actors/actor.sdnc/src/test/java/org/onap/policy/controlloop/actor/sdnc/BasicOperator.java
new file mode 100644
index 000000000..b9028d462
--- /dev/null
+++ b/models-interactions/model-actors/actor.sdnc/src/test/java/org/onap/policy/controlloop/actor/sdnc/BasicOperator.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.controlloop.actor.sdnc;
+
+import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+import static org.junit.Assert.assertEquals;
+
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.UUID;
+import org.onap.policy.common.utils.coder.CoderException;
+import org.onap.policy.common.utils.coder.StandardCoder;
+import org.onap.policy.common.utils.resources.ResourceUtils;
+import org.onap.policy.controlloop.VirtualControlLoopEvent;
+import org.onap.policy.controlloop.actorserviceprovider.controlloop.ControlLoopEventContext;
+
+/**
+ * Superclass for various operator tests.
+ */
+public abstract class BasicOperator {
+ protected static final UUID REQ_ID = UUID.randomUUID();
+ protected static final String ACTOR = "my-actor";
+
+ protected Map<String, String> enrichment;
+ protected VirtualControlLoopEvent event;
+ protected ControlLoopEventContext context;
+
+ /**
+ * Pretty-prints a request and verifies that the result matches the expected JSON.
+ *
+ * @param <T> request type
+ * @param expectedJsonFile name of the file containing the expected JSON
+ * @param request request to verify
+ * @throws CoderException if the request cannot be pretty-printed
+ */
+ protected <T> void verifyRequest(String expectedJsonFile, T request) throws CoderException {
+ String json = new StandardCoder().encode(request, true);
+ String expected = ResourceUtils.getResourceAsString(expectedJsonFile);
+
+ // strip request id, because it changes each time
+ final String stripper = "svc-request-id[^,]*";
+ json = json.replaceFirst(stripper, "").trim();
+ expected = expected.replaceFirst(stripper, "").trim();
+
+ assertEquals(expected, json);
+ }
+
+ /**
+ * Verifies that an exception is thrown if a field is missing from the enrichment
+ * data.
+ *
+ * @param oper operator to construct the request
+ * @param fieldName name of the field to be removed from the enrichment data
+ * @param expectedText text expected in the exception message
+ */
+ protected void verifyMissing(SdncOperator oper, String fieldName, String expectedText) {
+ makeContext();
+ enrichment.remove(fieldName);
+
+ assertThatIllegalArgumentException().isThrownBy(() -> oper.constructRequest(context))
+ .withMessageContaining("missing").withMessageContaining(expectedText);
+ }
+
+ protected void makeContext() {
+ // need a mutable map, so make a copy
+ enrichment = new TreeMap<>(makeEnrichment());
+
+ event = new VirtualControlLoopEvent();
+ event.setRequestId(REQ_ID);
+ event.setAai(enrichment);
+
+ context = new ControlLoopEventContext(event);
+ }
+
+ protected abstract Map<String, String> makeEnrichment();
+}
diff --git a/models-interactions/model-actors/actor.sdnc/src/test/java/org/onap/policy/controlloop/actor/sdnc/RerouteOperatorTest.java b/models-interactions/model-actors/actor.sdnc/src/test/java/org/onap/policy/controlloop/actor/sdnc/RerouteOperatorTest.java
new file mode 100644
index 000000000..0a7bcad6f
--- /dev/null
+++ b/models-interactions/model-actors/actor.sdnc/src/test/java/org/onap/policy/controlloop/actor/sdnc/RerouteOperatorTest.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.controlloop.actor.sdnc;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.Map;
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.policy.common.utils.coder.CoderException;
+import org.onap.policy.sdnc.SdncRequest;
+
+public class RerouteOperatorTest extends BasicOperator {
+
+ private RerouteOperator oper;
+
+
+ /**
+ * Set up.
+ */
+ @Before
+ public void setUp() {
+ makeContext();
+ oper = new RerouteOperator(ACTOR);
+ }
+
+ @Test
+ public void testRerouteOperator() {
+ assertEquals(ACTOR, oper.getActorName());
+ assertEquals(RerouteOperator.NAME, oper.getName());
+ }
+
+ @Test
+ public void testConstructRequest() throws CoderException {
+ SdncRequest request = oper.constructRequest(context);
+ assertEquals("my-service", request.getNsInstanceId());
+ assertEquals(REQ_ID, request.getRequestId());
+ assertEquals(RerouteOperator.URI, request.getUrl());
+ assertNotNull(request.getHealRequest().getRequestHeaderInfo().getSvcRequestId());
+
+ verifyRequest("reroute.json", request);
+
+ verifyMissing(oper, RerouteOperator.SERVICE_ID_KEY, "service");
+ verifyMissing(oper, RerouteOperator.NETWORK_ID_KEY, "network");
+ }
+
+ @Override
+ protected Map<String, String> makeEnrichment() {
+ return Map.of(RerouteOperator.SERVICE_ID_KEY, "my-service", RerouteOperator.NETWORK_ID_KEY, "my-network");
+ }
+}
diff --git a/models-interactions/model-actors/actor.sdnc/src/test/java/org/onap/policy/controlloop/actor/sdnc/SdncActorServiceProviderTest.java b/models-interactions/model-actors/actor.sdnc/src/test/java/org/onap/policy/controlloop/actor/sdnc/SdncActorServiceProviderTest.java
index 9739c7145..08655c349 100644
--- a/models-interactions/model-actors/actor.sdnc/src/test/java/org/onap/policy/controlloop/actor/sdnc/SdncActorServiceProviderTest.java
+++ b/models-interactions/model-actors/actor.sdnc/src/test/java/org/onap/policy/controlloop/actor/sdnc/SdncActorServiceProviderTest.java
@@ -3,7 +3,7 @@
* TestSdncActorServiceProvider
* ================================================================================
* Copyright (C) 2018-2019 Huawei. All rights reserved.
- * Modifications Copyright (C) 2018-2019 AT&T Corp. All rights reserved.
+ * Modifications Copyright (C) 2018-2020 AT&T Corp. All rights reserved.
* Modifications Copyright (C) 2019 Nordix Foundation.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -26,8 +26,10 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import java.util.Arrays;
import java.util.Objects;
import java.util.UUID;
+import java.util.stream.Collectors;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
@@ -36,19 +38,19 @@ import org.onap.policy.controlloop.ControlLoopOperation;
import org.onap.policy.controlloop.VirtualControlLoopEvent;
import org.onap.policy.controlloop.policy.Policy;
import org.onap.policy.sdnc.SdncRequest;
-import org.onap.policy.simulators.Util;
public class SdncActorServiceProviderTest {
- private static final String REROUTE = "Reroute";
+ private static final String REROUTE = RerouteOperator.NAME;
/**
* Set up before test class.
+ *
* @throws Exception if the A&AI simulator cannot be started
*/
@BeforeClass
public static void setUpSimulator() throws Exception {
- Util.buildAaiSim();
+ org.onap.policy.simulators.Util.buildAaiSim();
}
@AfterClass
@@ -57,6 +59,18 @@ public class SdncActorServiceProviderTest {
}
@Test
+ public void testSdncActorServiceProvider() {
+ final SdncActorServiceProvider prov = new SdncActorServiceProvider();
+
+ // verify that it has the operators we expect
+ var expected = Arrays.asList(BandwidthOnDemandOperator.NAME, RerouteOperator.NAME).stream().sorted()
+ .collect(Collectors.toList());
+ var actual = prov.getOperationNames().stream().sorted().collect(Collectors.toList());
+
+ assertEquals(expected.toString(), actual.toString());
+ }
+
+ @Test
public void testConstructRequest() {
VirtualControlLoopEvent onset = new VirtualControlLoopEvent();
ControlLoopOperation operation = new ControlLoopOperation();
@@ -84,8 +98,7 @@ public class SdncActorServiceProviderTest {
policy.setRecipe(REROUTE);
assertNotNull(provider.constructRequest(onset, operation, policy));
- SdncRequest request =
- provider.constructRequest(onset, operation, policy);
+ SdncRequest request = provider.constructRequest(onset, operation, policy);
assertEquals(requestId, Objects.requireNonNull(request).getRequestId());
assertEquals("reoptimize", request.getHealRequest().getRequestHeaderInfo().getSvcAction());
diff --git a/models-interactions/model-actors/actor.sdnc/src/test/java/org/onap/policy/controlloop/actor/sdnc/SdncOperatorTest.java b/models-interactions/model-actors/actor.sdnc/src/test/java/org/onap/policy/controlloop/actor/sdnc/SdncOperatorTest.java
new file mode 100644
index 000000000..25d383eb8
--- /dev/null
+++ b/models-interactions/model-actors/actor.sdnc/src/test/java/org/onap/policy/controlloop/actor/sdnc/SdncOperatorTest.java
@@ -0,0 +1,326 @@
+/*-
+ * ============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.sdnc;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import lombok.Setter;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.onap.policy.common.endpoints.event.comm.bus.internal.BusTopicParams;
+import org.onap.policy.common.endpoints.event.comm.bus.internal.BusTopicParams.TopicParamsBuilder;
+import org.onap.policy.common.endpoints.http.client.HttpClient;
+import org.onap.policy.common.endpoints.http.client.HttpClientFactoryInstance;
+import org.onap.policy.common.endpoints.http.server.HttpServletServer;
+import org.onap.policy.common.endpoints.http.server.HttpServletServerFactoryInstance;
+import org.onap.policy.common.endpoints.properties.PolicyEndPointProperties;
+import org.onap.policy.common.gson.GsonMessageBodyHandler;
+import org.onap.policy.common.utils.coder.CoderException;
+import org.onap.policy.common.utils.coder.StandardCoder;
+import org.onap.policy.common.utils.network.NetworkUtil;
+import org.onap.policy.controlloop.VirtualControlLoopEvent;
+import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
+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.HttpParams;
+import org.onap.policy.controlloop.policy.PolicyResult;
+import org.onap.policy.sdnc.SdncHealRequest;
+import org.onap.policy.sdnc.SdncRequest;
+import org.onap.policy.sdnc.SdncResponse;
+import org.onap.policy.sdnc.SdncResponseOutput;
+
+public class SdncOperatorTest {
+ public static final String MEDIA_TYPE_APPLICATION_JSON = "application/json";
+ private static final String EXPECTED_EXCEPTION = "expected exception";
+ public static final String HTTP_CLIENT = "my-http-client";
+ public static final String HTTP_NO_SERVER = "my-http-no-server-client";
+ private static final String ACTOR = "my-actor";
+ private static final String OPERATION = "my-operation";
+
+ /**
+ * Outcome to be added to the response.
+ */
+ @Setter
+ private static SdncResponseOutput output;
+
+
+ private VirtualControlLoopEvent event;
+ private ControlLoopEventContext context;
+ private MyOper oper;
+
+ /**
+ * Starts the SDNC simulator.
+ */
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ // allocate a port
+ int port = NetworkUtil.allocPort();
+
+ /*
+ * Start the simulator. Must use "Properties" to configure it, otherwise the
+ * server will use the wrong serialization provider.
+ */
+ Properties svrprops = getServerProperties("my-server", port);
+ HttpServletServerFactoryInstance.getServerFactory().build(svrprops).forEach(HttpServletServer::start);
+
+ /*
+ * Start the clients, one to the server, and one to a non-existent server.
+ */
+ TopicParamsBuilder builder = BusTopicParams.builder().managed(true).hostname("localhost").basePath("sdnc")
+ .serializationProvider(GsonMessageBodyHandler.class.getName());
+
+ HttpClientFactoryInstance.getClientFactory().build(builder.clientName(HTTP_CLIENT).port(port).build());
+
+ HttpClientFactoryInstance.getClientFactory()
+ .build(builder.clientName(HTTP_NO_SERVER).port(NetworkUtil.allocPort()).build());
+ }
+
+ @AfterClass
+ public static void tearDownAfterClass() {
+ HttpClientFactoryInstance.getClientFactory().destroy();
+ HttpServletServerFactoryInstance.getServerFactory().destroy();
+ }
+
+ /**
+ * Initializes {@link #oper} and sets {@link #output} to a success code.
+ */
+ @Before
+ public void setUp() {
+ event = new VirtualControlLoopEvent();
+ context = new ControlLoopEventContext(event);
+
+ initOper(HTTP_CLIENT);
+
+ output = new SdncResponseOutput();
+ output.setResponseCode("200");
+ }
+
+ @After
+ public void tearDown() {
+ oper.shutdown();
+ }
+
+ @Test
+ public void testSdncOperator() {
+ assertEquals(ACTOR, oper.getActorName());
+ assertEquals(OPERATION, oper.getName());
+ assertEquals(ACTOR + "." + OPERATION, oper.getFullName());
+ }
+
+ @Test
+ public void testGetClient() {
+ assertNotNull(oper.getTheClient());
+ }
+
+ @Test
+ public void testStartOperationAsync_testPostRequest() throws Exception {
+ OperationOutcome outcome = runOperation();
+ assertNotNull(outcome);
+ assertEquals(PolicyResult.SUCCESS, outcome.getResult());
+ }
+
+ /**
+ * Tests postRequest() when decode() throws an exception.
+ */
+ @Test
+ public void testPostRequestDecodeException() throws Exception {
+
+ oper.setDecodeFailure(true);
+
+ OperationOutcome outcome = runOperation();
+ assertNotNull(outcome);
+ assertEquals(PolicyResult.FAILURE_EXCEPTION, outcome.getResult());
+ }
+
+ /**
+ * Tests postRequest() when there is no "output" field in the response.
+ */
+ @Test
+ public void testPostRequestNoOutput() throws Exception {
+
+ setOutput(null);
+
+ OperationOutcome outcome = runOperation();
+ assertNotNull(outcome);
+ assertEquals(PolicyResult.FAILURE, outcome.getResult());
+ }
+
+ /**
+ * Tests postRequest() when the output is not a success.
+ */
+ @Test
+ public void testPostRequestOutputFailure() throws Exception {
+
+ output.setResponseCode(null);
+
+ OperationOutcome outcome = runOperation();
+ assertNotNull(outcome);
+ assertEquals(PolicyResult.FAILURE, outcome.getResult());
+ }
+
+ /**
+ * Tests postRequest() when the post() request throws an exception retrieving the
+ * response.
+ */
+ @Test
+ public void testPostRequestException() throws Exception {
+
+ // reset "oper" to point to a non-existent server
+ oper.shutdown();
+ initOper(HTTP_NO_SERVER);
+
+ OperationOutcome outcome = runOperation();
+ assertNotNull(outcome);
+ assertEquals(PolicyResult.FAILURE_EXCEPTION, outcome.getResult());
+ }
+
+ private static Properties getServerProperties(String name, int port) {
+ final Properties props = new Properties();
+ props.setProperty(PolicyEndPointProperties.PROPERTY_HTTP_SERVER_SERVICES, name);
+
+ final String svcpfx = PolicyEndPointProperties.PROPERTY_HTTP_SERVER_SERVICES + "." + name;
+
+ props.setProperty(svcpfx + PolicyEndPointProperties.PROPERTY_HTTP_REST_CLASSES_SUFFIX, Server.class.getName());
+ props.setProperty(svcpfx + PolicyEndPointProperties.PROPERTY_HTTP_HOST_SUFFIX, "localhost");
+ props.setProperty(svcpfx + PolicyEndPointProperties.PROPERTY_HTTP_PORT_SUFFIX, String.valueOf(port));
+ props.setProperty(svcpfx + PolicyEndPointProperties.PROPERTY_MANAGED_SUFFIX, "true");
+ props.setProperty(svcpfx + PolicyEndPointProperties.PROPERTY_HTTP_SWAGGER_SUFFIX, "false");
+
+ props.setProperty(svcpfx + PolicyEndPointProperties.PROPERTY_HTTP_SERIALIZATION_PROVIDER,
+ GsonMessageBodyHandler.class.getName());
+ return props;
+ }
+
+ /**
+ * Initializes {@link #oper}.
+ *
+ * @param clientName name of the client which it should use
+ */
+ private void initOper(String clientName) {
+ oper = new MyOper();
+
+ HttpParams params = HttpParams.builder().clientName(clientName).path("request").build();
+ Map<String, Object> mapParams = Util.translateToMap(OPERATION, params);
+ oper.configure(mapParams);
+ oper.start();
+ }
+
+ /**
+ * Runs the operation.
+ *
+ * @return the outcome of the operation, or {@code null} if it does not complete in
+ * time
+ */
+ private OperationOutcome runOperation() throws InterruptedException, ExecutionException, TimeoutException {
+ ControlLoopOperationParams params =
+ ControlLoopOperationParams.builder().actor(ACTOR).operation(OPERATION).context(context).build();
+
+ CompletableFuture<OperationOutcome> future = oper.startOperationAsync(params, 1, params.makeOutcome());
+
+ return future.get(5, TimeUnit.SECONDS);
+ }
+
+
+ private class MyOper extends SdncOperator {
+
+ /**
+ * Set to {@code true} to cause the decoder to throw an exception.
+ */
+ @Setter
+ private boolean decodeFailure = false;
+
+ public MyOper() {
+ super(ACTOR, OPERATION);
+ }
+
+ protected HttpClient getTheClient() {
+ return getClient();
+ }
+
+ @Override
+ protected SdncRequest constructRequest(ControlLoopEventContext context) {
+ SdncRequest request = new SdncRequest();
+
+ SdncHealRequest heal = new SdncHealRequest();
+ request.setHealRequest(heal);
+
+ return request;
+ }
+
+ @Override
+ protected StandardCoder makeDecoder() {
+ if (decodeFailure) {
+ // return a coder that throws exceptions when decode() is invoked
+ return new StandardCoder() {
+ @Override
+ public <T> T decode(String json, Class<T> clazz) throws CoderException {
+ throw new CoderException(EXPECTED_EXCEPTION);
+ }
+ };
+
+ } else {
+ return super.makeDecoder();
+ }
+ }
+ }
+
+ /**
+ * SDNC Simulator.
+ */
+ @Path("/sdnc")
+ @Produces(MEDIA_TYPE_APPLICATION_JSON)
+ public static class Server {
+
+ /**
+ * Generates a response.
+ *
+ * @param request incoming request
+ * @return resulting response
+ */
+ @POST
+ @Path("/request")
+ @Consumes(value = {MEDIA_TYPE_APPLICATION_JSON})
+ public Response postRequest(SdncRequest request) {
+
+ SdncResponse response = new SdncResponse();
+ response.setResponseOutput(output);
+
+ return Response.status(Status.OK).entity(response).build();
+ }
+ }
+}
diff --git a/models-interactions/model-actors/actor.sdnc/src/test/resources/bod.json b/models-interactions/model-actors/actor.sdnc/src/test/resources/bod.json
new file mode 100644
index 000000000..8c60bbdd8
--- /dev/null
+++ b/models-interactions/model-actors/actor.sdnc/src/test/resources/bod.json
@@ -0,0 +1,32 @@
+{
+ "input": {
+ "sdnc-request-header": {
+ "svc-request-id": "076b243e-9236-4409-973d-dd318dcab3e9",
+ "svc-action": "update"
+ },
+ "request-information": {
+ "request-action": "SdwanBandwidthChange"
+ },
+ "service-information": {
+ "service-instance-id": "my-service"
+ },
+ "vnf-information": {
+ "vnf-id": "my-vnf"
+ },
+ "vf-module-information": {
+ "vf-module-id": ""
+ },
+ "vf-module-request-input": {
+ "vf-module-input-parameters": {
+ "param": [
+ {
+ "name": "bandwidth"
+ },
+ {
+ "name": "bandwidth-change-time"
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/models-interactions/model-actors/actor.sdnc/src/test/resources/reroute.json b/models-interactions/model-actors/actor.sdnc/src/test/resources/reroute.json
new file mode 100644
index 000000000..da70a55a3
--- /dev/null
+++ b/models-interactions/model-actors/actor.sdnc/src/test/resources/reroute.json
@@ -0,0 +1,17 @@
+{
+ "input": {
+ "sdnc-request-header": {
+ "svc-request-id": "66087b39-8606-4367-9ac8-bdf64e162f29",
+ "svc-action": "reoptimize"
+ },
+ "request-information": {
+ "request-action": "ReoptimizeSOTNInstance"
+ },
+ "service-information": {
+ "service-instance-id": "my-service"
+ },
+ "network-information": {
+ "network-id": "my-network"
+ }
+ }
+}