diff options
Diffstat (limited to 'models-interactions/model-actors/actor.sdnc')
11 files changed, 1000 insertions, 16 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 new file mode 100644 index 000000000..2927bd85b --- /dev/null +++ b/models-interactions/model-actors/actor.sdnc/src/main/java/org/onap/policy/controlloop/actor/sdnc/BandwidthOnDemandOperator.java @@ -0,0 +1,108 @@ +/*- + * ============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 java.util.UUID; +import org.apache.commons.lang3.StringUtils; +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; +import org.onap.policy.sdnc.SdncHealServiceInfo; +import org.onap.policy.sdnc.SdncHealVfModuleInfo; +import org.onap.policy.sdnc.SdncHealVfModuleParameter; +import org.onap.policy.sdnc.SdncHealVfModuleParametersInfo; +import org.onap.policy.sdnc.SdncHealVfModuleRequestInput; +import org.onap.policy.sdnc.SdncHealVnfInfo; +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. + * + * @param actorName name of the actor with which this operator is associated + */ + public BandwidthOnDemandOperator(String actorName) { + super(actorName, NAME); + } + + @Override + protected SdncRequest constructRequest(ControlLoopEventContext context) { + String serviceInstance = context.getEnrichment().get(SERVICE_ID_KEY); + if (StringUtils.isBlank(serviceInstance)) { + throw new IllegalArgumentException("missing enrichment data, " + SERVICE_ID_KEY); + } + + SdncHealVfModuleParameter bandwidth = new SdncHealVfModuleParameter(); + bandwidth.setName("bandwidth"); + bandwidth.setValue(context.getEnrichment().get("bandwidth")); + + SdncHealVfModuleParameter timeStamp = new SdncHealVfModuleParameter(); + timeStamp.setName("bandwidth-change-time"); + timeStamp.setValue(context.getEnrichment().get("bandwidth-change-time")); + + SdncHealVfModuleParametersInfo vfParametersInfo = new SdncHealVfModuleParametersInfo(); + vfParametersInfo.addParameters(bandwidth); + vfParametersInfo.addParameters(timeStamp); + + SdncHealVfModuleRequestInput vfRequestInfo = new SdncHealVfModuleRequestInput(); + vfRequestInfo.setVfModuleParametersInfo(vfParametersInfo); + + SdncHealServiceInfo serviceInfo = new SdncHealServiceInfo(); + serviceInfo.setServiceInstanceId(serviceInstance); + + SdncHealRequestInfo requestInfo = new SdncHealRequestInfo(); + requestInfo.setRequestAction("SdwanBandwidthChange"); + + SdncHealRequestHeaderInfo headerInfo = new SdncHealRequestHeaderInfo(); + headerInfo.setSvcAction("update"); + headerInfo.setSvcRequestId(UUID.randomUUID().toString()); + + SdncRequest request = new SdncRequest(); + request.setNsInstanceId(serviceInstance); + request.setRequestId(context.getRequestId()); + request.setUrl(URI); + + SdncHealVnfInfo vnfInfo = new SdncHealVnfInfo(); + vnfInfo.setVnfId(context.getEnrichment().get(VNF_ID)); + + SdncHealVfModuleInfo vfModuleInfo = new SdncHealVfModuleInfo(); + vfModuleInfo.setVfModuleId(""); + + SdncHealRequest healRequest = new SdncHealRequest(); + healRequest.setVnfInfo(vnfInfo); + healRequest.setVfModuleInfo(vfModuleInfo); + healRequest.setRequestHeaderInfo(headerInfo); + healRequest.setVfModuleRequestInput(vfRequestInfo); + healRequest.setRequestInfo(requestInfo); + healRequest.setServiceInfo(serviceInfo); + request.setHealRequest(healRequest); + return request; + } +} 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 new file mode 100644 index 000000000..da400f8eb --- /dev/null +++ b/models-interactions/model-actors/actor.sdnc/src/main/java/org/onap/policy/controlloop/actor/sdnc/RerouteOperator.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.controlloop.actor.sdnc; + +import java.util.UUID; +import org.apache.commons.lang3.StringUtils; +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; +import org.onap.policy.sdnc.SdncHealRequestInfo; +import org.onap.policy.sdnc.SdncHealServiceInfo; +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. + * + * @param actorName name of the actor with which this operator is associated + */ + public RerouteOperator(String actorName) { + super(actorName, NAME); + } + + @Override + protected SdncRequest constructRequest(ControlLoopEventContext context) { + String serviceInstance = context.getEnrichment().get(SERVICE_ID_KEY); + if (StringUtils.isBlank(serviceInstance)) { + throw new IllegalArgumentException("missing enrichment data, " + SERVICE_ID_KEY); + } + SdncHealServiceInfo serviceInfo = new SdncHealServiceInfo(); + serviceInfo.setServiceInstanceId(serviceInstance); + + String networkId = context.getEnrichment().get(NETWORK_ID_KEY); + if (StringUtils.isBlank(networkId)) { + throw new IllegalArgumentException("missing enrichment data, " + NETWORK_ID_KEY); + } + SdncHealNetworkInfo networkInfo = new SdncHealNetworkInfo(); + networkInfo.setNetworkId(networkId); + + SdncHealRequestInfo requestInfo = new SdncHealRequestInfo(); + requestInfo.setRequestAction("ReoptimizeSOTNInstance"); + + SdncHealRequestHeaderInfo headerInfo = new SdncHealRequestHeaderInfo(); + headerInfo.setSvcAction("reoptimize"); + headerInfo.setSvcRequestId(UUID.randomUUID().toString()); + + SdncRequest request = new SdncRequest(); + request.setNsInstanceId(serviceInstance); + request.setRequestId(context.getRequestId()); + request.setUrl(URI); + + SdncHealRequest healRequest = new SdncHealRequest(); + healRequest.setRequestHeaderInfo(headerInfo); + healRequest.setNetworkInfo(networkInfo); + healRequest.setRequestInfo(requestInfo); + healRequest.setServiceInfo(serviceInfo); + request.setHealRequest(healRequest); + return request; + } +} 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 24d019f41..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 @@ -4,7 +4,7 @@ * ================================================================================ * Copyright (C) 2018-2019 Huawei Intellectual Property. All rights reserved. * Modifications Copyright (C) 2019 Nordix Foundation. - * Modifications Copyright (C) 2019 AT&T Intellectual Property. + * Modifications Copyright (C) 2019-2020 AT&T Intellectual Property. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,7 +29,7 @@ import java.util.List; import java.util.UUID; import org.onap.policy.controlloop.ControlLoopOperation; import org.onap.policy.controlloop.VirtualControlLoopEvent; -import org.onap.policy.controlloop.actorserviceprovider.spi.Actor; +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; @@ -45,10 +45,13 @@ import org.onap.policy.sdnc.SdncRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - -public class SdncActorServiceProvider implements Actor { +public class SdncActorServiceProvider extends HttpActor { private static final Logger logger = LoggerFactory.getLogger(SdncActorServiceProvider.class); + public static final String NAME = "SDNC"; + + // TODO old code: remove lines down to **HERE** + // Strings for Sdnc Actor private static final String SDNC_ACTOR = "SDNC"; @@ -62,8 +65,23 @@ public class SdncActorServiceProvider implements Actor { private static final String RECIPE_BW_ON_DEMAND = "BandwidthOnDemand"; private static final ImmutableList<String> recipes = ImmutableList.of(RECIPE_REROUTE); - private static final ImmutableMap<String, List<String>> targets = - new ImmutableMap.Builder<String, List<String>>().put(RECIPE_REROUTE, ImmutableList.of(TARGET_VM)).build(); + private static final ImmutableMap<String, List<String>> targets = new ImmutableMap.Builder<String, List<String>>() + .put(RECIPE_REROUTE, ImmutableList.of(TARGET_VM)).build(); + + // **HERE** + + /** + * Constructs the object. + */ + public SdncActorServiceProvider() { + super(NAME); + + addOperator(new RerouteOperator(NAME)); + addOperator(new BandwidthOnDemandOperator(NAME)); + } + + + // TODO old code: remove lines down to **HERE** @Override public String actor() { @@ -93,16 +111,15 @@ public class SdncActorServiceProvider implements Actor { * @param policy the policy * @return the constructed request */ - public SdncRequest constructRequest(VirtualControlLoopEvent onset, ControlLoopOperation operation, - Policy policy) { + public SdncRequest constructRequest(VirtualControlLoopEvent onset, ControlLoopOperation operation, Policy policy) { switch (policy.getRecipe()) { case RECIPE_REROUTE: return constructReOptimizeRequest(onset); case RECIPE_BW_ON_DEMAND: - logger.info("Construct request for receipe {}" , RECIPE_BW_ON_DEMAND); + logger.info("Construct request for receipe {}", RECIPE_BW_ON_DEMAND); return constructBwOnDemandRequest(onset); default: - logger.info("Unsupported recipe {} " + policy.getRecipe()); + logger.info("Unsupported recipe {}", policy.getRecipe()); return null; } } @@ -199,4 +216,6 @@ public class SdncActorServiceProvider implements Actor { request.setHealRequest(healRequest); return request; } + + // **HERE** } 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 new file mode 100644 index 000000000..479ee908d --- /dev/null +++ b/models-interactions/model-actors/actor.sdnc/src/main/java/org/onap/policy/controlloop/actor/sdnc/SdncOperator.java @@ -0,0 +1,148 @@ +/*- + * ============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 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 org.onap.policy.common.endpoints.http.client.HttpClient; +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.controlloop.ControlLoopEventContext; +import org.onap.policy.controlloop.actorserviceprovider.impl.HttpOperator; +import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams; +import org.onap.policy.controlloop.policy.PolicyResult; +import org.onap.policy.sdnc.SdncRequest; +import org.onap.policy.sdnc.SdncResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Superclass for SDNC Operators. + */ +public abstract class SdncOperator extends HttpOperator { + private static final Logger logger = LoggerFactory.getLogger(SdncOperator.class); + + /** + * Constructs the object. + * + * @param actorName name of the actor with which this operator is associated + * @param name operation name + */ + public SdncOperator(String actorName, String name) { + super(actorName, name); + } + + @Override + protected CompletableFuture<OperationOutcome> startOperationAsync(ControlLoopOperationParams params, int attempt, + OperationOutcome outcome) { + + SdncRequest request = constructRequest(params.getContext()); + return postRequest(params, outcome, request); + } + + /** + * Constructs the request. + * + * @param context associated event context + * @return a new request + */ + protected abstract SdncRequest constructRequest(ControlLoopEventContext context); + + /** + * 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 CompletableFuture<OperationOutcome> postRequest(ControlLoopOperationParams params, OperationOutcome outcome, + SdncRequest sdncRequest) { + Map<String, Object> headers = new HashMap<>(); + + headers.put("Accept", "application/json"); + String sdncUrl = getClient().getBaseUrl(); + + Util.logRestRequest(sdncUrl, sdncRequest); + + Entity<SdncRequest> entity = Entity.entity(sdncRequest, MediaType.APPLICATION_JSON); + + 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; + + public ResponseHandler(ControlLoopOperationParams params, OperationOutcome outcome, String sdncUrl) { + super(params, outcome); + this.sdncUrl = sdncUrl; + } + + /** + * 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); + } + } + + /** + * 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 + + 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" + } + } +} |