diff options
Diffstat (limited to 'models-interactions')
63 files changed, 1267 insertions, 184 deletions
diff --git a/models-interactions/model-actors/actor.aai/src/main/resources/META-INF/services/org.onap.policy.controlloop.actorServiceProvider.spi.Actor b/models-interactions/model-actors/actor.aai/src/main/resources/META-INF/services/org.onap.policy.controlloop.actorserviceprovider.spi.Actor index 6a52e3f17..6a52e3f17 100644 --- a/models-interactions/model-actors/actor.aai/src/main/resources/META-INF/services/org.onap.policy.controlloop.actorServiceProvider.spi.Actor +++ b/models-interactions/model-actors/actor.aai/src/main/resources/META-INF/services/org.onap.policy.controlloop.actorserviceprovider.spi.Actor diff --git a/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiActorServiceProviderTest.java b/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiActorServiceProviderTest.java index 513f339fb..12b6ca44c 100644 --- a/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiActorServiceProviderTest.java +++ b/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiActorServiceProviderTest.java @@ -27,8 +27,9 @@ import java.util.LinkedList; import java.util.List; import java.util.stream.Collectors; import org.junit.Test; +import org.onap.policy.controlloop.actor.test.BasicActor; -public class AaiActorServiceProviderTest { +public class AaiActorServiceProviderTest extends BasicActor { @Test public void testAaiActorServiceProvider() { @@ -44,5 +45,8 @@ public class AaiActorServiceProviderTest { var actual = prov.getOperationNames().stream().sorted().collect(Collectors.toList()); assertEquals(expected.toString(), actual.toString()); + + // verify that it all plugs into the ActorService + verifyActorService(AaiActorServiceProvider.NAME, "service.yaml"); } } diff --git a/models-interactions/model-actors/actor.aai/src/test/resources/service.yaml b/models-interactions/model-actors/actor.aai/src/test/resources/service.yaml new file mode 100644 index 000000000..9f6561de0 --- /dev/null +++ b/models-interactions/model-actors/actor.aai/src/test/resources/service.yaml @@ -0,0 +1,33 @@ +# +# ============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======================================================== +# +httpClients: +- clientName: my-client + hostname: localhost + port: 80 + basePath: base-url + managed: true +actors: + AAI: + clientName: my-client + operations: + CustomQuery: + path: cq + Tenant: + path: tenant
\ No newline at end of file diff --git a/models-interactions/model-actors/actor.appc/src/main/java/org/onap/policy/controlloop/actor/appc/AppcActorServiceProvider.java b/models-interactions/model-actors/actor.appc/src/main/java/org/onap/policy/controlloop/actor/appc/AppcActorServiceProvider.java index f6a204540..76aa828c1 100644 --- a/models-interactions/model-actors/actor.appc/src/main/java/org/onap/policy/controlloop/actor/appc/AppcActorServiceProvider.java +++ b/models-interactions/model-actors/actor.appc/src/main/java/org/onap/policy/controlloop/actor/appc/AppcActorServiceProvider.java @@ -42,7 +42,7 @@ import org.slf4j.LoggerFactory; public class AppcActorServiceProvider extends BidirectionalTopicActor<BidirectionalTopicActorParams> { - private static final String NAME = "APPC"; + public static final String NAME = "APPC"; private static final Logger logger = LoggerFactory.getLogger(AppcActorServiceProvider.class); diff --git a/models-interactions/model-actors/actor.appc/src/main/java/org/onap/policy/controlloop/actor/appc/AppcOperation.java b/models-interactions/model-actors/actor.appc/src/main/java/org/onap/policy/controlloop/actor/appc/AppcOperation.java index 7d4af80ad..dc46f1253 100644 --- a/models-interactions/model-actors/actor.appc/src/main/java/org/onap/policy/controlloop/actor/appc/AppcOperation.java +++ b/models-interactions/model-actors/actor.appc/src/main/java/org/onap/policy/controlloop/actor/appc/AppcOperation.java @@ -24,6 +24,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.UUID; +import java.util.concurrent.CompletableFuture; import org.onap.policy.appc.CommonHeader; import org.onap.policy.appc.Request; import org.onap.policy.appc.Response; @@ -67,6 +68,14 @@ public abstract class AppcOperation extends BidirectionalTopicOperation<Request, } /** + * Starts the GUARD. + */ + @Override + protected CompletableFuture<OperationOutcome> startPreprocessorAsync() { + return startGuardAsync(); + } + + /** * Makes a request, given the target VNF. This is a support function for * {@link #makeRequest(int)}. * @@ -104,10 +113,16 @@ public abstract class AppcOperation extends BidirectionalTopicOperation<Request, * @param source source from which to get the values * @param target where to place the decoded values */ - private static void convertPayload(Map<String, String> source, Map<String, Object> target) { - for (Entry<String, String> ent : source.entrySet()) { + private static void convertPayload(Map<String, Object> source, Map<String, Object> target) { + for (Entry<String, Object> ent : source.entrySet()) { + Object value = ent.getValue(); + if (value == null) { + target.put(ent.getKey(), null); + continue; + } + try { - target.put(ent.getKey(), coder.decode(ent.getValue(), Object.class)); + target.put(ent.getKey(), coder.decode(value.toString(), Object.class)); } catch (CoderException e) { logger.warn("cannot decode JSON value {}: {}", ent.getKey(), ent.getValue(), e); diff --git a/models-interactions/model-actors/actor.appc/src/main/resources/META-INF/services/org.onap.policy.controlloop.actorServiceProvider.spi.Actor b/models-interactions/model-actors/actor.appc/src/main/resources/META-INF/services/org.onap.policy.controlloop.actorserviceprovider.spi.Actor index f1002a301..f1002a301 100644 --- a/models-interactions/model-actors/actor.appc/src/main/resources/META-INF/services/org.onap.policy.controlloop.actorServiceProvider.spi.Actor +++ b/models-interactions/model-actors/actor.appc/src/main/resources/META-INF/services/org.onap.policy.controlloop.actorserviceprovider.spi.Actor diff --git a/models-interactions/model-actors/actor.appc/src/test/java/org/onap/policy/controlloop/actor/appc/AppcOperationTest.java b/models-interactions/model-actors/actor.appc/src/test/java/org/onap/policy/controlloop/actor/appc/AppcOperationTest.java index 218a4e532..8b71b614d 100644 --- a/models-interactions/model-actors/actor.appc/src/test/java/org/onap/policy/controlloop/actor/appc/AppcOperationTest.java +++ b/models-interactions/model-actors/actor.appc/src/test/java/org/onap/policy/controlloop/actor/appc/AppcOperationTest.java @@ -63,6 +63,11 @@ public class AppcOperationTest extends BasicAppcOperation { } @Test + public void testStartPreprocessorAsync() { + assertNotNull(oper.startPreprocessorAsync()); + } + + @Test public void testMakeRequest() { Request request = oper.makeRequest(2, MY_VNF); assertEquals(DEFAULT_OPERATION, request.getAction()); @@ -106,7 +111,7 @@ public class AppcOperationTest extends BasicAppcOperation { /* * insert invalid json text into the payload. */ - Map<String, String> payload = new TreeMap<>(params.getPayload()); + Map<String, Object> payload = new TreeMap<>(params.getPayload()); payload.put("invalid-key", "{invalid json"); params = params.toBuilder().payload(payload).build(); @@ -126,6 +131,31 @@ public class AppcOperationTest extends BasicAppcOperation { KEY2, Map.of("output", "world")), request.getPayload()); // @formatter:on + + + /* + * insert null item into the payload. + */ + payload = new TreeMap<>(); + payload.put(KEY1, "abc"); + payload.put(KEY2, null); + payload.put(KEY3, "def"); + params = params.toBuilder().payload(payload).build(); + + oper = new AppcOperation(params, config) { + @Override + protected Request makeRequest(int attempt) { + return oper.makeRequest(attempt, MY_VNF); + } + }; + request = oper.makeRequest(2, MY_VNF); + + payload.put(AppcOperation.VNF_ID_KEY, MY_VNF); + payload.put(KEY1, "abc"); + payload.put(KEY2, null); + payload.put(KEY3, "def"); + + assertEquals(payload, request.getPayload()); } @Test diff --git a/models-interactions/model-actors/actor.appc/src/test/java/org/onap/policy/controlloop/actor/appc/AppcServiceProviderTest.java b/models-interactions/model-actors/actor.appc/src/test/java/org/onap/policy/controlloop/actor/appc/AppcServiceProviderTest.java index 305c6d7cd..99e9d824a 100644 --- a/models-interactions/model-actors/actor.appc/src/test/java/org/onap/policy/controlloop/actor/appc/AppcServiceProviderTest.java +++ b/models-interactions/model-actors/actor.appc/src/test/java/org/onap/policy/controlloop/actor/appc/AppcServiceProviderTest.java @@ -43,6 +43,7 @@ import org.onap.policy.controlloop.ControlLoopEventStatus; import org.onap.policy.controlloop.ControlLoopOperation; import org.onap.policy.controlloop.ControlLoopTargetType; import org.onap.policy.controlloop.VirtualControlLoopEvent; +import org.onap.policy.controlloop.actor.test.BasicActor; import org.onap.policy.controlloop.policy.Policy; import org.onap.policy.controlloop.policy.Target; import org.onap.policy.controlloop.policy.TargetType; @@ -50,7 +51,7 @@ import org.onap.policy.simulators.Util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class AppcServiceProviderTest { +public class AppcServiceProviderTest extends BasicActor { private static final String GENERIC_VNF_ID = "generic-vnf.vnf-id"; @@ -74,7 +75,8 @@ public class AppcServiceProviderTest { static { /* - * Construct an onset with an AAI subtag containing generic-vnf.vnf-id and a target type of VM. + * Construct an onset with an AAI subtag containing generic-vnf.vnf-id and a + * target type of VM. */ onsetEvent = new VirtualControlLoopEvent(); onsetEvent.setClosedLoopControlName("closedLoopControlName-Test"); @@ -140,6 +142,12 @@ public class AppcServiceProviderTest { } @Test + public void testActorService() { + // verify that it all plugs into the ActorService + verifyActorService(AppcActorServiceProvider.NAME, "service.yaml"); + } + + @Test public void testConstructModifyConfigRequest() { policy.setPayload(new HashMap<>()); policy.getPayload().put(KEY1, VALUE1); diff --git a/models-interactions/model-actors/actor.appc/src/test/java/org/onap/policy/controlloop/actor/appc/BasicAppcOperation.java b/models-interactions/model-actors/actor.appc/src/test/java/org/onap/policy/controlloop/actor/appc/BasicAppcOperation.java index ed3e7a7ee..ecba91996 100644 --- a/models-interactions/model-actors/actor.appc/src/test/java/org/onap/policy/controlloop/actor/appc/BasicAppcOperation.java +++ b/models-interactions/model-actors/actor.appc/src/test/java/org/onap/policy/controlloop/actor/appc/BasicAppcOperation.java @@ -54,6 +54,7 @@ public abstract class BasicAppcOperation extends BasicBidirectionalTopicOperatio protected static final String MY_VNF = "my-vnf"; protected static final String KEY1 = "my-key-A"; protected static final String KEY2 = "my-key-B"; + protected static final String KEY3 = "my-key-C"; protected static final String VALUE1 = "{\"input\":\"hello\"}"; protected static final String VALUE2 = "{\"output\":\"world\"}"; protected static final String RESOURCE_ID = "my-resource"; @@ -162,7 +163,7 @@ public abstract class BasicAppcOperation extends BasicBidirectionalTopicOperatio } @Override - protected Map<String, String> makePayload() { + protected Map<String, Object> makePayload() { return Map.of(KEY1, VALUE1, KEY2, VALUE2); } } diff --git a/models-interactions/model-actors/actor.appc/src/test/java/org/onap/policy/controlloop/actor/appc/ModifyConfigOperationTest.java b/models-interactions/model-actors/actor.appc/src/test/java/org/onap/policy/controlloop/actor/appc/ModifyConfigOperationTest.java index 5ff789715..460f2c9f0 100644 --- a/models-interactions/model-actors/actor.appc/src/test/java/org/onap/policy/controlloop/actor/appc/ModifyConfigOperationTest.java +++ b/models-interactions/model-actors/actor.appc/src/test/java/org/onap/policy/controlloop/actor/appc/ModifyConfigOperationTest.java @@ -24,11 +24,11 @@ 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.assertNotNull; -import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.util.Arrays; @@ -42,6 +42,7 @@ import org.onap.policy.appc.Request; import org.onap.policy.common.utils.coder.CoderException; import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome; import org.onap.policy.controlloop.actorserviceprovider.controlloop.ControlLoopEventContext; +import org.onap.policy.controlloop.policy.PolicyResult; public class ModifyConfigOperationTest extends BasicAppcOperation { @@ -64,10 +65,11 @@ public class ModifyConfigOperationTest extends BasicAppcOperation { } @Test - public void testStartPreprocessorAsync() { - CompletableFuture<OperationOutcome> future = new CompletableFuture<>(); + public void testStartPreprocessorAsync() throws Exception { + CompletableFuture<OperationOutcome> future2 = new CompletableFuture<>(); context = mock(ControlLoopEventContext.class); - when(context.obtain(eq(AaiCqResponse.CONTEXT_KEY), any())).thenReturn(future); + when(context.obtain(eq(AaiCqResponse.CONTEXT_KEY), any())).thenReturn(future2); + when(context.getEvent()).thenReturn(event); params = params.toBuilder().context(context).build(); AtomicBoolean guardStarted = new AtomicBoolean(); @@ -80,9 +82,16 @@ public class ModifyConfigOperationTest extends BasicAppcOperation { } }; - assertSame(future, oper.startPreprocessorAsync()); + CompletableFuture<OperationOutcome> future3 = oper.startPreprocessorAsync(); + assertNotNull(future3); assertFalse(future.isDone()); assertTrue(guardStarted.get()); + verify(context).obtain(eq(AaiCqResponse.CONTEXT_KEY), any()); + + future2.complete(params.makeOutcome()); + assertTrue(executor.runAll(100)); + assertTrue(future3.isDone()); + assertEquals(PolicyResult.SUCCESS, future3.get().getResult()); } @Test diff --git a/models-interactions/model-actors/actor.appc/src/test/resources/service.yaml b/models-interactions/model-actors/actor.appc/src/test/resources/service.yaml new file mode 100644 index 000000000..ab9ad98b5 --- /dev/null +++ b/models-interactions/model-actors/actor.appc/src/test/resources/service.yaml @@ -0,0 +1,38 @@ +# +# ============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======================================================== +# +topics: + topicSources: + - topicCommInfrastructure: NOOP + topic: my-source + servers: + - localhost + managed: true + topicSinks: + - topicCommInfrastructure: NOOP + topic: my-sink + servers: + - localhost + managed: true +actors: + APPC: + sinkTopic: my-sink + sourceTopic: my-source + operations: + ModifyConfig: {}
\ No newline at end of file diff --git a/models-interactions/model-actors/actor.appclcm/src/main/resources/META-INF/services/org.onap.policy.controlloop.actorServiceProvider.spi.Actor b/models-interactions/model-actors/actor.appclcm/src/main/resources/META-INF/services/org.onap.policy.controlloop.actorserviceprovider.spi.Actor index 403ad9859..403ad9859 100644 --- a/models-interactions/model-actors/actor.appclcm/src/main/resources/META-INF/services/org.onap.policy.controlloop.actorServiceProvider.spi.Actor +++ b/models-interactions/model-actors/actor.appclcm/src/main/resources/META-INF/services/org.onap.policy.controlloop.actorserviceprovider.spi.Actor diff --git a/models-interactions/model-actors/actor.guard/src/main/java/org/onap/policy/controlloop/actor/guard/GuardActorServiceProvider.java b/models-interactions/model-actors/actor.guard/src/main/java/org/onap/policy/controlloop/actor/guard/GuardActorServiceProvider.java index ea08d13da..e37de57bb 100644 --- a/models-interactions/model-actors/actor.guard/src/main/java/org/onap/policy/controlloop/actor/guard/GuardActorServiceProvider.java +++ b/models-interactions/model-actors/actor.guard/src/main/java/org/onap/policy/controlloop/actor/guard/GuardActorServiceProvider.java @@ -24,10 +24,11 @@ package org.onap.policy.controlloop.actor.guard; import org.onap.policy.controlloop.actorserviceprovider.impl.HttpActor; import org.onap.policy.controlloop.actorserviceprovider.impl.HttpOperator; +import org.onap.policy.controlloop.actorserviceprovider.impl.OperationPartial; public class GuardActorServiceProvider extends HttpActor<GuardActorParams> { // actor name - public static final String NAME = "GUARD"; + public static final String NAME = OperationPartial.GUARD_ACTOR_NAME; /** * Constructs the object. diff --git a/models-interactions/model-actors/actor.guard/src/main/java/org/onap/policy/controlloop/actor/guard/GuardOperation.java b/models-interactions/model-actors/actor.guard/src/main/java/org/onap/policy/controlloop/actor/guard/GuardOperation.java index 453a3e377..a5459f660 100644 --- a/models-interactions/model-actors/actor.guard/src/main/java/org/onap/policy/controlloop/actor/guard/GuardOperation.java +++ b/models-interactions/model-actors/actor.guard/src/main/java/org/onap/policy/controlloop/actor/guard/GuardOperation.java @@ -20,9 +20,7 @@ package org.onap.policy.controlloop.actor.guard; -import java.util.LinkedHashMap; import java.util.Map; -import java.util.Map.Entry; import java.util.UUID; import java.util.concurrent.CompletableFuture; import javax.ws.rs.client.Entity; @@ -33,13 +31,12 @@ import org.onap.policy.common.endpoints.utils.NetLoggerUtil.EventType; import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome; import org.onap.policy.controlloop.actorserviceprovider.Util; import org.onap.policy.controlloop.actorserviceprovider.impl.HttpOperation; +import org.onap.policy.controlloop.actorserviceprovider.impl.OperationPartial; import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams; import org.onap.policy.controlloop.actorserviceprovider.parameters.HttpConfig; import org.onap.policy.controlloop.policy.PolicyResult; import org.onap.policy.models.decisions.concepts.DecisionRequest; import org.onap.policy.models.decisions.concepts.DecisionResponse; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * Guard Operation. The outcome message is set to the guard response. If the guard is @@ -57,17 +54,14 @@ import org.slf4j.LoggerFactory; * </dl> */ public class GuardOperation extends HttpOperation<DecisionResponse> { - private static final Logger logger = LoggerFactory.getLogger(GuardOperation.class); // operation name - public static final String NAME = "Decision"; + public static final String NAME = OperationPartial.GUARD_OPERATION_NAME; public static final String PERMIT = "Permit"; public static final String DENY = "Deny"; public static final String INDETERMINATE = "Indeterminate"; - private static final String RESOURCE = "resource"; - /** * Prefix for properties in the payload that should be copied to the "resource" field * of the request. @@ -118,34 +112,9 @@ public class GuardOperation extends HttpOperation<DecisionResponse> { throw new IllegalArgumentException("missing payload"); } - /* - * This code could be easily modified to allow the context and/or resource to be - * an encoded JSON string, that is decoded into a Map and stuffed into the - * appropriate field. - */ - Map<String, Object> req = config.makeRequest(); - Map<String, Object> resource = new LinkedHashMap<>(); - - for (Entry<String, String> ent : params.getPayload().entrySet()) { - String key = ent.getKey(); - - if (key.startsWith(RESOURCE_PREFIX)) { - // it's a resource property - put into the resource map - key = key.substring(RESOURCE_PREFIX.length()); - resource.put(key, ent.getValue()); - - } else if (key.indexOf('.') < 0) { - // it's a normal property - put into the request map - req.put(key, ent.getValue()); - - } else { - logger.warn("{}: unused key {} in payload for {}", getFullName(), key, params.getRequestId()); - } - } - + req.putAll(params.getPayload()); req.computeIfAbsent("requestId", key -> UUID.randomUUID().toString()); - req.put(RESOURCE, resource); return req; } diff --git a/models-interactions/model-actors/actor.guard/src/main/resources/META-INF/services/org.onap.policy.controlloop.actorServiceProvider.spi.Actor b/models-interactions/model-actors/actor.guard/src/main/resources/META-INF/services/org.onap.policy.controlloop.actorserviceprovider.spi.Actor index dd4368504..dd4368504 100644 --- a/models-interactions/model-actors/actor.guard/src/main/resources/META-INF/services/org.onap.policy.controlloop.actorServiceProvider.spi.Actor +++ b/models-interactions/model-actors/actor.guard/src/main/resources/META-INF/services/org.onap.policy.controlloop.actorserviceprovider.spi.Actor diff --git a/models-interactions/model-actors/actor.guard/src/test/java/org/onap/policy/controlloop/actor/guard/GuardActorParamsTest.java b/models-interactions/model-actors/actor.guard/src/test/java/org/onap/policy/controlloop/actor/guard/GuardActorParamsTest.java index cd9f4e316..1c256090e 100644 --- a/models-interactions/model-actors/actor.guard/src/test/java/org/onap/policy/controlloop/actor/guard/GuardActorParamsTest.java +++ b/models-interactions/model-actors/actor.guard/src/test/java/org/onap/policy/controlloop/actor/guard/GuardActorParamsTest.java @@ -32,6 +32,7 @@ import org.junit.Before; import org.junit.Test; import org.onap.policy.common.parameters.ValidationResult; import org.onap.policy.controlloop.actorserviceprovider.Util; +import org.onap.policy.controlloop.actorserviceprovider.parameters.CommonActorParams; public class GuardActorParamsTest { private static final String CONTAINER = "my-container"; @@ -68,13 +69,14 @@ public class GuardActorParamsTest { assertTrue(params.validate(CONTAINER).isValid()); // only a few fields are required - GuardActorParams sparse = Util.translate(CONTAINER, Map.of("operation", operations), GuardActorParams.class); + GuardActorParams sparse = Util.translate(CONTAINER, Map.of(CommonActorParams.OPERATIONS_FIELD, operations), + GuardActorParams.class); assertTrue(sparse.validate(CONTAINER).isValid()); assertEquals(GuardActorParams.DEFAULT_ACTION, sparse.getAction()); // check fields from superclass - testValidateField("operation", "null", params2 -> params2.setOperation(null)); + testValidateField(CommonActorParams.OPERATIONS_FIELD, "null", params2 -> params2.setOperations(null)); testValidateField("timeoutSec", "minimum", params2 -> params2.setTimeoutSec(-1)); } @@ -96,7 +98,7 @@ public class GuardActorParamsTest { GuardActorParams params2 = new GuardActorParams(); params2.setClientName(CLIENT); params2.setTimeoutSec(TIMEOUT); - params2.setOperation(operations); + params2.setOperations(operations); params2.setOnapName(ONAP_NAME); params2.setOnapComponent(ONAP_COMP); diff --git a/models-interactions/model-actors/actor.guard/src/test/java/org/onap/policy/controlloop/actor/guard/GuardActorServiceProviderTest.java b/models-interactions/model-actors/actor.guard/src/test/java/org/onap/policy/controlloop/actor/guard/GuardActorServiceProviderTest.java index f4ab6061e..bb5d4ddf8 100644 --- a/models-interactions/model-actors/actor.guard/src/test/java/org/onap/policy/controlloop/actor/guard/GuardActorServiceProviderTest.java +++ b/models-interactions/model-actors/actor.guard/src/test/java/org/onap/policy/controlloop/actor/guard/GuardActorServiceProviderTest.java @@ -25,8 +25,9 @@ import static org.junit.Assert.assertEquals; import java.util.Arrays; import java.util.stream.Collectors; import org.junit.Test; +import org.onap.policy.controlloop.actor.test.BasicActor; -public class GuardActorServiceProviderTest { +public class GuardActorServiceProviderTest extends BasicActor { @Test public void test() { @@ -37,5 +38,8 @@ public class GuardActorServiceProviderTest { var actual = prov.getOperationNames().stream().sorted().collect(Collectors.toList()); assertEquals(expected.toString(), actual.toString()); + + // verify that it all plugs into the ActorService + verifyActorService(GuardActorServiceProvider.NAME, "service.yaml"); } } diff --git a/models-interactions/model-actors/actor.guard/src/test/java/org/onap/policy/controlloop/actor/guard/GuardOperationTest.java b/models-interactions/model-actors/actor.guard/src/test/java/org/onap/policy/controlloop/actor/guard/GuardOperationTest.java index 406cdd05d..bd23a818b 100644 --- a/models-interactions/model-actors/actor.guard/src/test/java/org/onap/policy/controlloop/actor/guard/GuardOperationTest.java +++ b/models-interactions/model-actors/actor.guard/src/test/java/org/onap/policy/controlloop/actor/guard/GuardOperationTest.java @@ -92,14 +92,16 @@ public class GuardOperationTest extends BasicHttpOperation<DecisionRequest> { verifyPayload("makeReqStd.json", makePayload()); verifyPayload("makeReqDefault.json", new TreeMap<>()); - Map<String, String> payload = new TreeMap<>(); + Map<String, Object> payload = new TreeMap<>(); payload.put("action", "some action"); payload.put("hello", "world"); payload.put("r u there?", "yes"); payload.put("requestId", "some request id"); - payload.put("resource.abc", "def"); - payload.put("resource.ghi", "jkl"); - payload.put("some.other", "unused"); + + Map<String, Object> resource = new TreeMap<>(); + payload.put("resource", resource); + resource.put("abc", "def"); + resource.put("ghi", "jkl"); verifyPayload("makeReq.json", payload); @@ -109,7 +111,7 @@ public class GuardOperationTest extends BasicHttpOperation<DecisionRequest> { assertThatIllegalArgumentException().isThrownBy(() -> oper.makeRequest()); } - private void verifyPayload(String expectedJsonFile, Map<String, String> payload) throws CoderException { + private void verifyPayload(String expectedJsonFile, Map<String, Object> payload) throws CoderException { params.getPayload().clear(); params.getPayload().putAll(payload); @@ -150,7 +152,7 @@ public class GuardOperationTest extends BasicHttpOperation<DecisionRequest> { } @Override - protected Map<String, String> makePayload() { + protected Map<String, Object> makePayload() { DecisionRequest req = new DecisionRequest(); req.setAction("my-action"); req.setOnapComponent("my-onap-component"); @@ -158,12 +160,14 @@ public class GuardOperationTest extends BasicHttpOperation<DecisionRequest> { req.setOnapName("my-onap-name"); req.setRequestId("my-request-id"); - @SuppressWarnings("unchecked") - Map<String, String> map = Util.translate("", req, TreeMap.class); - // add resources - map.put(GuardOperation.RESOURCE_PREFIX + "actor", "resource-actor"); - map.put(GuardOperation.RESOURCE_PREFIX + "operation", "resource-operation"); + Map<String, Object> resource = new TreeMap<>(); + req.setResource(resource); + resource.put("actor", "resource-actor"); + resource.put("operation", "resource-operation"); + + @SuppressWarnings("unchecked") + Map<String, Object> map = Util.translate("", req, TreeMap.class); return map; } diff --git a/models-interactions/model-actors/actor.guard/src/test/resources/makeReqDefault.json b/models-interactions/model-actors/actor.guard/src/test/resources/makeReqDefault.json index 9e9df7b22..d757eb993 100644 --- a/models-interactions/model-actors/actor.guard/src/test/resources/makeReqDefault.json +++ b/models-interactions/model-actors/actor.guard/src/test/resources/makeReqDefault.json @@ -1,5 +1,4 @@ { "action": "guard", - "requestId": "abcdefghi", - "resource": {} + "requestId": "abcdefghi" } diff --git a/models-interactions/model-actors/actor.guard/src/test/resources/service.yaml b/models-interactions/model-actors/actor.guard/src/test/resources/service.yaml new file mode 100644 index 000000000..131cf785b --- /dev/null +++ b/models-interactions/model-actors/actor.guard/src/test/resources/service.yaml @@ -0,0 +1,31 @@ +# +# ============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======================================================== +# +httpClients: +- clientName: my-client + hostname: localhost + port: 80 + basePath: base-url + managed: true +actors: + GUARD: + clientName: my-client + operations: + Decision: + path: decide
\ No newline at end of file diff --git a/models-interactions/model-actors/actor.sdnc/src/main/resources/META-INF/services/org.onap.policy.controlloop.actorServiceProvider.spi.Actor b/models-interactions/model-actors/actor.sdnc/src/main/resources/META-INF/services/org.onap.policy.controlloop.actorserviceprovider.spi.Actor index f4d1e975e..f4d1e975e 100644 --- a/models-interactions/model-actors/actor.sdnc/src/main/resources/META-INF/services/org.onap.policy.controlloop.actorServiceProvider.spi.Actor +++ b/models-interactions/model-actors/actor.sdnc/src/main/resources/META-INF/services/org.onap.policy.controlloop.actorserviceprovider.spi.Actor 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 ac81d49c9..752cb9125 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 @@ -36,10 +36,11 @@ import org.junit.Test; import org.onap.policy.common.endpoints.http.server.HttpServletServerFactoryInstance; import org.onap.policy.controlloop.ControlLoopOperation; import org.onap.policy.controlloop.VirtualControlLoopEvent; +import org.onap.policy.controlloop.actor.test.BasicActor; import org.onap.policy.controlloop.policy.Policy; import org.onap.policy.sdnc.SdncRequest; -public class SdncActorServiceProviderTest { +public class SdncActorServiceProviderTest extends BasicActor { private static final String REROUTE = RerouteOperation.NAME; @@ -68,6 +69,9 @@ public class SdncActorServiceProviderTest { var actual = prov.getOperationNames().stream().sorted().collect(Collectors.toList()); assertEquals(expected.toString(), actual.toString()); + + // verify that it all plugs into the ActorService + verifyActorService(SdncActorServiceProvider.NAME, "service.yaml"); } @Test diff --git a/models-interactions/model-actors/actor.sdnc/src/test/java/org/onap/policy/controlloop/actor/sdnc/SdncOperationTest.java b/models-interactions/model-actors/actor.sdnc/src/test/java/org/onap/policy/controlloop/actor/sdnc/SdncOperationTest.java index b87ed2c80..b7f71715c 100644 --- a/models-interactions/model-actors/actor.sdnc/src/test/java/org/onap/policy/controlloop/actor/sdnc/SdncOperationTest.java +++ b/models-interactions/model-actors/actor.sdnc/src/test/java/org/onap/policy/controlloop/actor/sdnc/SdncOperationTest.java @@ -22,6 +22,7 @@ package org.onap.policy.controlloop.actor.sdnc; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.util.Map; @@ -57,6 +58,11 @@ public class SdncOperationTest extends BasicSdncOperation { } @Test + public void testStartPreprocessorAsync() { + assertNotNull(oper.startPreprocessorAsync()); + } + + @Test public void testStartOperationAsync_testStartRequestAsync() throws Exception { verifyOperation(oper); } diff --git a/models-interactions/model-actors/actor.sdnc/src/test/resources/service.yaml b/models-interactions/model-actors/actor.sdnc/src/test/resources/service.yaml new file mode 100644 index 000000000..71d9dae79 --- /dev/null +++ b/models-interactions/model-actors/actor.sdnc/src/test/resources/service.yaml @@ -0,0 +1,33 @@ +# +# ============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======================================================== +# +httpClients: +- clientName: my-client + hostname: localhost + port: 80 + basePath: base-url + managed: true +actors: + SDNC: + clientName: my-client + operations: + BandwidthOnDemand: + path: bod + Reroute: + path: reroute
\ No newline at end of file diff --git a/models-interactions/model-actors/actor.sdnr/src/main/resources/META-INF/services/org.onap.policy.controlloop.actorServiceProvider.spi.Actor b/models-interactions/model-actors/actor.sdnr/src/main/resources/META-INF/services/org.onap.policy.controlloop.actorserviceprovider.spi.Actor index c8d5e4c41..c8d5e4c41 100644 --- a/models-interactions/model-actors/actor.sdnr/src/main/resources/META-INF/services/org.onap.policy.controlloop.actorServiceProvider.spi.Actor +++ b/models-interactions/model-actors/actor.sdnr/src/main/resources/META-INF/services/org.onap.policy.controlloop.actorserviceprovider.spi.Actor diff --git a/models-interactions/model-actors/actor.so/src/main/java/org/onap/policy/controlloop/actor/so/SoActorServiceProvider.java b/models-interactions/model-actors/actor.so/src/main/java/org/onap/policy/controlloop/actor/so/SoActorServiceProvider.java index 1dbad623b..9c9e6dc62 100644 --- a/models-interactions/model-actors/actor.so/src/main/java/org/onap/policy/controlloop/actor/so/SoActorServiceProvider.java +++ b/models-interactions/model-actors/actor.so/src/main/java/org/onap/policy/controlloop/actor/so/SoActorServiceProvider.java @@ -35,7 +35,7 @@ import org.onap.aai.domain.yang.Tenant; import org.onap.policy.aai.AaiCqResponse; import org.onap.policy.controlloop.ControlLoopOperation; import org.onap.policy.controlloop.VirtualControlLoopEvent; -import org.onap.policy.controlloop.actorserviceprovider.impl.ActorImpl; +import org.onap.policy.controlloop.actorserviceprovider.impl.HttpActor; import org.onap.policy.controlloop.policy.Policy; import org.onap.policy.so.SoCloudConfiguration; import org.onap.policy.so.SoManager; @@ -51,7 +51,7 @@ import org.onap.policy.so.util.Serialization; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class SoActorServiceProvider extends ActorImpl { +public class SoActorServiceProvider extends HttpActor<SoActorParams> { private static final Logger logger = LoggerFactory.getLogger(SoActorServiceProvider.class); public static final String NAME = "SO"; @@ -96,7 +96,7 @@ public class SoActorServiceProvider extends ActorImpl { * Constructs the object. */ public SoActorServiceProvider() { - super(NAME); + super(NAME, SoActorParams.class); addOperator(new SoOperator(NAME, VfModuleCreate.NAME, VfModuleCreate::new)); } diff --git a/models-interactions/model-actors/actor.so/src/main/java/org/onap/policy/controlloop/actor/so/SoConstants.java b/models-interactions/model-actors/actor.so/src/main/java/org/onap/policy/controlloop/actor/so/SoConstants.java new file mode 100644 index 000000000..faafb43a6 --- /dev/null +++ b/models-interactions/model-actors/actor.so/src/main/java/org/onap/policy/controlloop/actor/so/SoConstants.java @@ -0,0 +1,29 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.controlloop.actor.so; + +public class SoConstants { + public static final String CONTEXT_KEY_VF_COUNT = "SO.VFCount"; + + private SoConstants() { + // do nothing + } +} diff --git a/models-interactions/model-actors/actor.so/src/main/java/org/onap/policy/controlloop/actor/so/SoOperation.java b/models-interactions/model-actors/actor.so/src/main/java/org/onap/policy/controlloop/actor/so/SoOperation.java index d8d960e54..53fb973a5 100644 --- a/models-interactions/model-actors/actor.so/src/main/java/org/onap/policy/controlloop/actor/so/SoOperation.java +++ b/models-interactions/model-actors/actor.so/src/main/java/org/onap/policy/controlloop/actor/so/SoOperation.java @@ -97,6 +97,23 @@ public abstract class SoOperation extends HttpOperation<SoResponse> { } /** + * Validates that the parameters contain the required target information to extract + * the VF count from the custom query. + */ + protected void validateTarget() { + verifyNotNull("Target information", params.getTarget()); + verifyNotNull("model-customization-id", params.getTarget().getModelCustomizationId()); + verifyNotNull("model-invariant-id", params.getTarget().getModelInvariantId()); + verifyNotNull("model-version-id", params.getTarget().getModelVersionId()); + } + + private void verifyNotNull(String type, Object value) { + if (value == null) { + throw new IllegalArgumentException("missing " + type + " for guard payload"); + } + } + + /** * Starts the GUARD. */ @Override @@ -105,6 +122,24 @@ public abstract class SoOperation extends HttpOperation<SoResponse> { } /** + * Stores the VF count and then runs the guard. + * + * @return a future to cancel or await the guard response + */ + protected CompletableFuture<OperationOutcome> storeVfCountRunGuard() { + String custId = params.getTarget().getModelCustomizationId(); + String invId = params.getTarget().getModelInvariantId(); + String verId = params.getTarget().getModelVersionId(); + + AaiCqResponse cq = params.getContext().getProperty(AaiCqResponse.CONTEXT_KEY); + int vfcount = cq.getVfModuleCount(custId, invId, verId); + + params.getContext().setProperty(SoConstants.CONTEXT_KEY_VF_COUNT, vfcount); + + return startGuardAsync(); + } + + /** * If the response does not indicate that the request has been completed, then sleep a * bit and issue a "get". */ @@ -116,6 +151,7 @@ public abstract class SoOperation extends HttpOperation<SoResponse> { if (rawResponse.getStatus() == 200) { String requestState = getRequestState(response); if (COMPLETE.equalsIgnoreCase(requestState)) { + successfulCompletion(); return CompletableFuture .completedFuture(setOutcome(outcome, PolicyResult.SUCCESS, rawResponse, response)); } @@ -147,6 +183,13 @@ public abstract class SoOperation extends HttpOperation<SoResponse> { } /** + * Invoked when a request completes successfully. + */ + protected void successfulCompletion() { + // do nothing + } + + /** * Issues a "get" request to see if the original request is complete yet. * * @param outcome outcome to be populated with the response @@ -251,13 +294,13 @@ public abstract class SoOperation extends HttpOperation<SoResponse> { return null; } - String json = params.getPayload().get(REQ_PARAM_NM); - if (json == null) { + Object data = params.getPayload().get(REQ_PARAM_NM); + if (data == null) { return null; } try { - return coder.decode(json, SoRequestParameters.class); + return coder.decode(data.toString(), SoRequestParameters.class); } catch (CoderException e) { throw new IllegalArgumentException("invalid payload value: " + REQ_PARAM_NM); } @@ -271,14 +314,14 @@ public abstract class SoOperation extends HttpOperation<SoResponse> { return null; } - String json = params.getPayload().get(CONFIG_PARAM_NM); - if (json == null) { + Object data = params.getPayload().get(CONFIG_PARAM_NM); + if (data == null) { return null; } try { @SuppressWarnings("unchecked") - List<Map<String, String>> result = coder.decode(json, ArrayList.class); + List<Map<String, String>> result = coder.decode(data.toString(), ArrayList.class); return result; } catch (CoderException | RuntimeException e) { throw new IllegalArgumentException("invalid payload value: " + CONFIG_PARAM_NM); diff --git a/models-interactions/model-actors/actor.so/src/main/java/org/onap/policy/controlloop/actor/so/VfModuleCreate.java b/models-interactions/model-actors/actor.so/src/main/java/org/onap/policy/controlloop/actor/so/VfModuleCreate.java index c17d25211..e88a10cff 100644 --- a/models-interactions/model-actors/actor.so/src/main/java/org/onap/policy/controlloop/actor/so/VfModuleCreate.java +++ b/models-interactions/model-actors/actor.so/src/main/java/org/onap/policy/controlloop/actor/so/VfModuleCreate.java @@ -20,6 +20,7 @@ package org.onap.policy.controlloop.actor.so; +import java.util.Map; import java.util.concurrent.CompletableFuture; import javax.ws.rs.client.Entity; import javax.ws.rs.core.MediaType; @@ -45,24 +46,61 @@ import org.onap.policy.so.SoRequest; import org.onap.policy.so.SoRequestDetails; import org.onap.policy.so.SoRequestParameters; +/** + * Operation to create a VF Module. This gets the VF count from the A&AI Custom Query + * response and stores it in the context. It also passes the count+1 to the guard. Once + * the "create" completes successfully, it bumps the VF count that's stored in the + * context. + * <p/> + * Note: currently, this only supports storing the count for a single target VF. + */ public class VfModuleCreate extends SoOperation { public static final String NAME = "VF Module Create"; + public static final String PAYLOAD_KEY_VF_COUNT = "vfCount"; + + /** + * Constructs the object. + * + * @param params operation parameters + * @param config configuration for this operation + */ public VfModuleCreate(ControlLoopOperationParams params, HttpConfig config) { super(params, config); + + // ensure we have the necessary parameters + validateTarget(); } /** - * Ensures that A&AI customer query has been performed, and then runs the guard query. + * Ensures that A&AI customer query has been performed, and then runs the guard. */ @Override @SuppressWarnings("unchecked") protected CompletableFuture<OperationOutcome> startPreprocessorAsync() { + if (params.getContext().contains(SoConstants.CONTEXT_KEY_VF_COUNT)) { + return startGuardAsync(); + } + + // need the VF count ControlLoopOperationParams cqParams = params.toBuilder().actor(AaiConstants.ACTOR_NAME) .operation(AaiCustomQueryOperation.NAME).payload(null).retry(null).timeoutSec(null).build(); - // run Custom Query and Guard, in parallel - return allOf(() -> params.getContext().obtain(AaiCqResponse.CONTEXT_KEY, cqParams), this::startGuardAsync); + // run Custom Query, extract the VF count, and then run the Guard + return sequence(() -> params.getContext().obtain(AaiCqResponse.CONTEXT_KEY, cqParams), + this::storeVfCountRunGuard); + } + + @Override + protected Map<String, Object> makeGuardPayload() { + Map<String, Object> payload = super.makeGuardPayload(); + + int vfcount = params.getContext().getProperty(SoConstants.CONTEXT_KEY_VF_COUNT); + + // run guard with the proposed vf count + payload.put(PAYLOAD_KEY_VF_COUNT, vfcount + 1); + + return payload; } @Override @@ -86,6 +124,15 @@ public class VfModuleCreate extends SoOperation { } /** + * Increments the VF count that's stored in the context. + */ + @Override + protected void successfulCompletion() { + int vfcount = params.getContext().getProperty(SoConstants.CONTEXT_KEY_VF_COUNT); + params.getContext().setProperty(SoConstants.CONTEXT_KEY_VF_COUNT, vfcount + 1); + } + + /** * Makes a request. * * @return a pair containing the request URL and the new request diff --git a/models-interactions/model-actors/actor.so/src/main/resources/META-INF/services/org.onap.policy.controlloop.actorServiceProvider.spi.Actor b/models-interactions/model-actors/actor.so/src/main/resources/META-INF/services/org.onap.policy.controlloop.actorserviceprovider.spi.Actor index a955eb71c..a955eb71c 100644 --- a/models-interactions/model-actors/actor.so/src/main/resources/META-INF/services/org.onap.policy.controlloop.actorServiceProvider.spi.Actor +++ b/models-interactions/model-actors/actor.so/src/main/resources/META-INF/services/org.onap.policy.controlloop.actorserviceprovider.spi.Actor diff --git a/models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/BasicSoOperation.java b/models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/BasicSoOperation.java index 3a2aaf849..35f1ef823 100644 --- a/models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/BasicSoOperation.java +++ b/models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/BasicSoOperation.java @@ -20,6 +20,7 @@ package org.onap.policy.controlloop.actor.so; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; import java.util.Collections; @@ -28,6 +29,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; import org.mockito.Mock; +import org.onap.policy.aai.AaiCqResponse; import org.onap.policy.controlloop.actor.test.BasicHttpOperation; import org.onap.policy.controlloop.actorserviceprovider.Util; import org.onap.policy.controlloop.policy.Target; @@ -52,6 +54,7 @@ public abstract class BasicSoOperation extends BasicHttpOperation<SoRequest> { public static final String PATH_GET = "my-path-get/"; public static final int MAX_GETS = 3; public static final int WAIT_SEC_GETS = 20; + public static final Integer VF_COUNT = 10; @Mock protected SoConfig config; @@ -125,8 +128,8 @@ public abstract class BasicSoOperation extends BasicHttpOperation<SoRequest> { } @Override - protected Map<String, String> makePayload() { - Map<String, String> payload = new HashMap<>(); + protected Map<String, Object> makePayload() { + Map<String, Object> payload = new HashMap<>(); // request parameters SoRequestParameters reqParams = new SoRequestParameters(); @@ -140,4 +143,9 @@ public abstract class BasicSoOperation extends BasicHttpOperation<SoRequest> { return payload; } + + protected AaiCqResponse makeCqResponse() { + when(cqResponse.getVfModuleCount(any(), any(), any())).thenReturn(VF_COUNT); + return cqResponse; + } } diff --git a/models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/SoActorParamsTest.java b/models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/SoActorParamsTest.java index f463fcb94..5fb647253 100644 --- a/models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/SoActorParamsTest.java +++ b/models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/SoActorParamsTest.java @@ -31,6 +31,7 @@ import org.junit.Before; import org.junit.Test; import org.onap.policy.common.parameters.ValidationResult; import org.onap.policy.controlloop.actorserviceprovider.Util; +import org.onap.policy.controlloop.actorserviceprovider.parameters.CommonActorParams; public class SoActorParamsTest { @@ -67,14 +68,15 @@ public class SoActorParamsTest { assertTrue(params.validate(CONTAINER).isValid()); // only a few fields are required - SoActorParams sparse = Util.translate(CONTAINER, Map.of("operation", operations), SoActorParams.class); + SoActorParams sparse = Util.translate(CONTAINER, Map.of(CommonActorParams.OPERATIONS_FIELD, operations), + SoActorParams.class); assertTrue(sparse.validate(CONTAINER).isValid()); testValidateField("maxGets", "minimum", params2 -> params2.setMaxGets(-1)); testValidateField("waitSecGet", "minimum", params2 -> params2.setWaitSecGet(0)); // check fields from superclass - testValidateField("operation", "null", params2 -> params2.setOperation(null)); + testValidateField(CommonActorParams.OPERATIONS_FIELD, "null", params2 -> params2.setOperations(null)); testValidateField("timeoutSec", "minimum", params2 -> params2.setTimeoutSec(-1)); // check edge cases @@ -105,7 +107,7 @@ public class SoActorParamsTest { SoActorParams params2 = new SoActorParams(); params2.setClientName(CLIENT); params2.setTimeoutSec(TIMEOUT); - params2.setOperation(operations); + params2.setOperations(operations); params2.setWaitSecGet(WAIT_SEC_GETS); params2.setMaxGets(MAX_GETS); diff --git a/models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/SoActorServiceProviderTest.java b/models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/SoActorServiceProviderTest.java index a9d5b8192..b73a65e44 100644 --- a/models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/SoActorServiceProviderTest.java +++ b/models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/SoActorServiceProviderTest.java @@ -23,6 +23,7 @@ package org.onap.policy.controlloop.actor.so; +import static org.assertj.core.api.Assertions.assertThatCode; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; @@ -41,6 +42,7 @@ import org.junit.Test; import org.onap.policy.aai.AaiCqResponse; import org.onap.policy.controlloop.ControlLoopOperation; import org.onap.policy.controlloop.VirtualControlLoopEvent; +import org.onap.policy.controlloop.actor.test.BasicActor; import org.onap.policy.controlloop.policy.Policy; import org.onap.policy.controlloop.policy.Target; import org.onap.policy.so.SoOperationType; @@ -48,7 +50,7 @@ import org.onap.policy.so.SoRequest; import org.onap.policy.so.SoRequestParameters; import org.onap.policy.so.util.Serialization; -public class SoActorServiceProviderTest { +public class SoActorServiceProviderTest extends BasicActor { private static final String C_VALUE = "cvalue"; private static final String A_VALUE = "avalue"; @@ -79,8 +81,15 @@ public class SoActorServiceProviderTest { } @Test + public void testActorService() { + // verify that it all plugs into the ActorService + verifyActorService(SoActorServiceProvider.NAME, "service.yaml"); + } + + @Test public void testSendRequest() { - SoActorServiceProvider.sendRequest(UUID.randomUUID().toString(), null, null, null, null, null); + assertThatCode(() -> SoActorServiceProvider.sendRequest(UUID.randomUUID().toString(), null, null, null, null, + null)).doesNotThrowAnyException(); } @Test diff --git a/models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/SoOperationTest.java b/models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/SoOperationTest.java index 871d37032..b2ae5727b 100644 --- a/models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/SoOperationTest.java +++ b/models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/SoOperationTest.java @@ -20,8 +20,10 @@ package org.onap.policy.controlloop.actor.so; +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.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; @@ -35,7 +37,6 @@ import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; import java.util.function.Supplier; import org.junit.Before; @@ -82,19 +83,55 @@ public class SoOperationTest extends BasicSoOperation { } @Test + public void testValidateTarget() { + // check when various fields are null + verifyNotNull("model-customization-id", target::getModelCustomizationId, target::setModelCustomizationId); + verifyNotNull("model-invariant-id", target::getModelInvariantId, target::setModelInvariantId); + verifyNotNull("model-version-id", target::getModelVersionId, target::setModelVersionId); + + // verify it's still valid + assertThatCode(() -> new VfModuleCreate(params, config)).doesNotThrowAnyException(); + + // check when Target, itself, is null + params = params.toBuilder().target(null).build(); + assertThatIllegalArgumentException().isThrownBy(() -> new VfModuleCreate(params, config)) + .withMessageContaining("Target information"); + } + + private void verifyNotNull(String expectedText, Supplier<String> getter, Consumer<String> setter) { + String originalValue = getter.get(); + + // try with null + setter.accept(null); + assertThatIllegalArgumentException().isThrownBy(() -> new VfModuleCreate(params, config)) + .withMessageContaining(expectedText); + + setter.accept(originalValue); + } + + @Test public void testStartPreprocessorAsync() { - AtomicBoolean guardStarted = new AtomicBoolean(); + assertNotNull(oper.startPreprocessorAsync()); + } - oper = new SoOperation(params, config) { - @Override - protected CompletableFuture<OperationOutcome> startGuardAsync() { - guardStarted.set(true); - return super.startGuardAsync(); - } - }; + @Test + public void testStoreVfCountRunGuard() throws Exception { + // insert CQ data so it's there for the guard + context.setProperty(AaiCqResponse.CONTEXT_KEY, makeCqResponse()); + + // cause guard to fail + OperationOutcome outcome2 = params.makeOutcome(); + outcome2.setResult(PolicyResult.FAILURE); + when(guardOperation.start()).thenReturn(CompletableFuture.completedFuture(outcome2)); + + CompletableFuture<OperationOutcome> future2 = oper.storeVfCountRunGuard(); + assertTrue(executor.runAll(100)); + assertTrue(future2.isDone()); + assertEquals(PolicyResult.FAILURE, future2.get().getResult()); - assertNull(oper.startPreprocessorAsync()); - assertTrue(guardStarted.get()); + // verify that the count was stored + Integer vfcount = context.getProperty(SoConstants.CONTEXT_KEY_VF_COUNT); + assertEquals(VF_COUNT, vfcount); } @Test diff --git a/models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/VfModuleCreateTest.java b/models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/VfModuleCreateTest.java index 6c3cfbf66..63cf744c1 100644 --- a/models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/VfModuleCreateTest.java +++ b/models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/VfModuleCreateTest.java @@ -20,15 +20,17 @@ package org.onap.policy.controlloop.actor.so; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.TimeUnit; @@ -36,6 +38,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import org.apache.commons.lang3.tuple.Pair; import org.junit.Before; import org.junit.Test; +import org.mockito.ArgumentCaptor; import org.onap.aai.domain.yang.CloudRegion; import org.onap.aai.domain.yang.GenericVnf; import org.onap.aai.domain.yang.ModelVer; @@ -44,7 +47,7 @@ import org.onap.aai.domain.yang.Tenant; import org.onap.policy.aai.AaiCqResponse; import org.onap.policy.common.utils.coder.CoderException; import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome; -import org.onap.policy.controlloop.actorserviceprovider.controlloop.ControlLoopEventContext; +import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams; import org.onap.policy.controlloop.policy.PolicyResult; import org.onap.policy.so.SoRequest; @@ -71,14 +74,17 @@ public class VfModuleCreateTest extends BasicSoOperation { public void testConstructor() { assertEquals(DEFAULT_ACTOR, oper.getActorName()); assertEquals(VfModuleCreate.NAME, oper.getName()); + + // verify that target validation is done + params = params.toBuilder().target(null).build(); + assertThatIllegalArgumentException().isThrownBy(() -> new VfModuleCreate(params, config)) + .withMessageContaining("Target information"); } @Test - public void testStartPreprocessorAsync() { - CompletableFuture<OperationOutcome> future = new CompletableFuture<>(); - context = mock(ControlLoopEventContext.class); - when(context.obtain(eq(AaiCqResponse.CONTEXT_KEY), any())).thenReturn(future); - params = params.toBuilder().context(context).build(); + public void testStartPreprocessorAsync() throws Exception { + // put the count in the context so that it will skip the custom query + params.getContext().setProperty(SoConstants.CONTEXT_KEY_VF_COUNT, 20); AtomicBoolean guardStarted = new AtomicBoolean(); @@ -90,13 +96,60 @@ public class VfModuleCreateTest extends BasicSoOperation { } }; - assertSame(future, oper.startPreprocessorAsync()); - assertFalse(future.isDone()); + CompletableFuture<OperationOutcome> future3 = oper.startPreprocessorAsync(); + assertNotNull(future3); assertTrue(guardStarted.get()); } @Test - public void testStartOperationAsync() throws Exception { + public void testStartGuardAsync() throws Exception { + // remove CQ data so it's forced to query + context.removeProperty(AaiCqResponse.CONTEXT_KEY); + + CompletableFuture<OperationOutcome> future2 = oper.startPreprocessorAsync(); + assertTrue(executor.runAll(100)); + assertFalse(future2.isDone()); + + provideCqResponse(makeCqResponse()); + assertTrue(executor.runAll(100)); + assertTrue(future2.isDone()); + assertEquals(PolicyResult.SUCCESS, future2.get().getResult()); + } + + @Test + public void testMakeGuardPayload() { + final int origCount = 30; + params.getContext().setProperty(SoConstants.CONTEXT_KEY_VF_COUNT, origCount); + + CompletableFuture<OperationOutcome> future2 = oper.startPreprocessorAsync(); + assertTrue(executor.runAll(100)); + assertTrue(future2.isDone()); + + // get the payload from the request + ArgumentCaptor<ControlLoopOperationParams> captor = ArgumentCaptor.forClass(ControlLoopOperationParams.class); + verify(guardOperator).buildOperation(captor.capture()); + + Map<String, Object> payload = captor.getValue().getPayload(); + assertNotNull(payload); + + @SuppressWarnings("unchecked") + Map<String, Object> resource = (Map<String, Object>) payload.get("resource"); + assertNotNull(resource); + + @SuppressWarnings("unchecked") + Map<String, Object> guard = (Map<String, Object>) resource.get("guard"); + assertNotNull(guard); + + Integer newCount = (Integer) guard.get(VfModuleCreate.PAYLOAD_KEY_VF_COUNT); + assertNotNull(newCount); + assertEquals(origCount + 1, newCount.intValue()); + } + + @Test + public void testStartOperationAsync_testSuccessfulCompletion() throws Exception { + final int origCount = 30; + params.getContext().setProperty(SoConstants.CONTEXT_KEY_VF_COUNT, origCount); + when(client.post(any(), any(), any(), any())).thenAnswer(provideResponse(rawResponse)); // use a real executor @@ -113,6 +166,9 @@ public class VfModuleCreateTest extends BasicSoOperation { outcome = future2.get(500, TimeUnit.SECONDS); assertEquals(PolicyResult.SUCCESS, outcome.getResult()); + + Integer newCount = (Integer) params.getContext().getProperty(SoConstants.CONTEXT_KEY_VF_COUNT); + assertEquals(origCount + 1, newCount.intValue()); } /** diff --git a/models-interactions/model-actors/actor.so/src/test/resources/service.yaml b/models-interactions/model-actors/actor.so/src/test/resources/service.yaml new file mode 100644 index 000000000..b1ac162a4 --- /dev/null +++ b/models-interactions/model-actors/actor.so/src/test/resources/service.yaml @@ -0,0 +1,31 @@ +# +# ============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======================================================== +# +httpClients: +- clientName: my-client + hostname: localhost + port: 80 + basePath: base-url + managed: true +actors: + SO: + clientName: my-client + operations: + VF Module Create: + path: create
\ No newline at end of file diff --git a/models-interactions/model-actors/actor.test/pom.xml b/models-interactions/model-actors/actor.test/pom.xml index 3df35c355..86e34fa8c 100644 --- a/models-interactions/model-actors/actor.test/pom.xml +++ b/models-interactions/model-actors/actor.test/pom.xml @@ -34,6 +34,11 @@ <dependencies> <dependency> <groupId>org.onap.policy.models.policy-models-interactions.model-impl</groupId> + <artifactId>aai</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.onap.policy.models.policy-models-interactions.model-impl</groupId> <artifactId>events</artifactId> <version>${project.version}</version> </dependency> @@ -69,4 +74,18 @@ <scope>compile</scope> </dependency> </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-jar-plugin</artifactId> + <configuration> + <excludes> + <exclude>src/test/**</exclude> + </excludes> + </configuration> + </plugin> + </plugins> + </build> </project> diff --git a/models-interactions/model-actors/actor.test/src/main/java/org/onap/policy/controlloop/actor/test/BasicActor.java b/models-interactions/model-actors/actor.test/src/main/java/org/onap/policy/controlloop/actor/test/BasicActor.java new file mode 100644 index 000000000..1b11d0d32 --- /dev/null +++ b/models-interactions/model-actors/actor.test/src/main/java/org/onap/policy/controlloop/actor/test/BasicActor.java @@ -0,0 +1,182 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.controlloop.actor.test; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.FileNotFoundException; +import java.util.Map; +import lombok.Getter; +import org.onap.policy.common.endpoints.event.comm.TopicEndpointManager; +import org.onap.policy.common.endpoints.event.comm.bus.internal.BusTopicParams; +import org.onap.policy.common.endpoints.http.client.HttpClientConfigException; +import org.onap.policy.common.endpoints.http.client.HttpClientFactory; +import org.onap.policy.common.endpoints.http.client.HttpClientFactoryInstance; +import org.onap.policy.common.endpoints.parameters.TopicParameterGroup; +import org.onap.policy.common.parameters.BeanValidationResult; +import org.onap.policy.common.parameters.BeanValidator; +import org.onap.policy.common.parameters.annotations.NotNull; +import org.onap.policy.common.utils.coder.Coder; +import org.onap.policy.common.utils.coder.CoderException; +import org.onap.policy.common.utils.coder.StandardYamlCoder; +import org.onap.policy.common.utils.resources.ResourceUtils; +import org.onap.policy.controlloop.actorserviceprovider.ActorService; +import org.onap.policy.controlloop.actorserviceprovider.Operator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Superclass for various Actor tests. + */ +public class BasicActor { + private static final Logger logger = LoggerFactory.getLogger(BasicActor.class); + private static final Coder yamlCoder = new StandardYamlCoder(); + + /** + * Reads a YAML configuration file, configures the specified topics and HTTP clients, + * and then runs the specified actor through its paces: configure(), start(), stop(), + * and shutdown(). Finally, it destroys the topics and HTTP clients. + * + * @param actorName name of the actor to be tested. + * @param yamlConfigFile YAML configuration file name + * @throws IllegalArgumentException if an error occurs + */ + protected void verifyActorService(String actorName, String yamlConfigFile) { + ActorService service = new ActorService() {}; + + // ensure the actor was loaded + assertNotNull(service.getActor(actorName)); + + try { + MyConfig config = readConfig(yamlConfigFile); + config.validate(); + + startOtherServices(config); + + // configure and verify + service.configure(config.getActors()); + for (Operator operator : service.getActor(actorName).getOperators()) { + assertTrue(operator.isConfigured()); + } + + // start and verify + service.start(); + for (Operator operator : service.getActor(actorName).getOperators()) { + assertTrue(operator.isAlive()); + } + + // stop and verify + service.stop(); + for (Operator operator : service.getActor(actorName).getOperators()) { + assertFalse(operator.isAlive()); + } + + // shut down and verify + service.shutdown(); + for (Operator operator : service.getActor(actorName).getOperators()) { + assertFalse(operator.isAlive()); + } + + } catch (HttpClientConfigException e) { + logger.error("failed to configure HTTP client(s) for actor: {}", actorName); + throw new IllegalArgumentException(e); + + } finally { + stopOtherServices(); + } + } + + /** + * Reads a YAML configuration from a file. + * + * @param yamlConfigFile YAML configuration file name + * @return the configuration that was read from the file + * @throws AssertionError if an error occurs + * @throws CoderException if an error occurs + */ + private MyConfig readConfig(String yamlConfigFile) { + try { + String yaml = ResourceUtils.getResourceAsString(yamlConfigFile); + if (yaml == null) { + throw new FileNotFoundException(yamlConfigFile); + } + + return yamlCoder.decode(yaml, MyConfig.class); + + } catch (CoderException | FileNotFoundException e) { + logger.error("cannot decode YAML file {}", yamlConfigFile); + throw new IllegalArgumentException(e); + } + } + + /** + * Starts the Topic and HTTP clients. + * + * @param config configuration + * @throws HttpClientConfigException if an error occurs + */ + private void startOtherServices(MyConfig config) throws HttpClientConfigException { + stopOtherServices(); + + if (config.getHttpClients() != null) { + HttpClientFactory factory = HttpClientFactoryInstance.getClientFactory(); + for (BusTopicParams params : config.getHttpClients()) { + factory.build(params); + } + } + + if (config.getTopics() != null) { + TopicEndpointManager.getManager().addTopics(config.getTopics()); + } + } + + /** + * Stops the Topic and HTTP clients. + */ + private void stopOtherServices() { + TopicEndpointManager.getManager().shutdown(); + HttpClientFactoryInstance.getClientFactory().destroy(); + } + + @Getter + public static class MyConfig { + private BusTopicParams[] httpClients; + private TopicParameterGroup topics; + + @NotNull + private Map<String, Map<String, Object>> actors; + + /** + * Validates the config. + */ + public void validate() { + BeanValidationResult result = new BeanValidator().validateTop(BasicActor.class.getSimpleName(), this); + if (topics != null) { + result.addResult(topics.validate()); + } + if (!result.isValid()) { + throw new IllegalArgumentException(result.getResult()); + } + } + } +} diff --git a/models-interactions/model-actors/actor.test/src/main/java/org/onap/policy/controlloop/actor/test/BasicOperation.java b/models-interactions/model-actors/actor.test/src/main/java/org/onap/policy/controlloop/actor/test/BasicOperation.java index f027c1c18..989f6a7c3 100644 --- a/models-interactions/model-actors/actor.test/src/main/java/org/onap/policy/controlloop/actor/test/BasicOperation.java +++ b/models-interactions/model-actors/actor.test/src/main/java/org/onap/policy/controlloop/actor/test/BasicOperation.java @@ -21,6 +21,8 @@ package org.onap.policy.controlloop.actor.test; import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; import java.util.Map; import java.util.TreeMap; @@ -29,6 +31,8 @@ import java.util.concurrent.CompletableFuture; import javax.ws.rs.core.Response; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.onap.policy.aai.AaiConstants; +import org.onap.policy.aai.AaiCqResponse; import org.onap.policy.common.utils.coder.Coder; import org.onap.policy.common.utils.coder.CoderException; import org.onap.policy.common.utils.coder.StandardCoder; @@ -36,9 +40,14 @@ import org.onap.policy.common.utils.resources.ResourceUtils; import org.onap.policy.common.utils.time.PseudoExecutor; import org.onap.policy.controlloop.VirtualControlLoopEvent; 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.controlloop.ControlLoopEventContext; +import org.onap.policy.controlloop.actorserviceprovider.impl.OperationPartial; import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams; +import org.onap.policy.controlloop.actorserviceprovider.spi.Actor; +import org.onap.policy.controlloop.policy.PolicyResult; /** * Superclass for various Operation tests. @@ -55,7 +64,22 @@ public class BasicOperation { @Mock protected ActorService service; + @Mock + protected Actor guardActor; + @Mock + protected Operator guardOperator; + @Mock + protected Operation guardOperation; + @Mock + protected Actor cqActor; + @Mock + protected Operator cqOperator; + @Mock + protected Operation cqOperation; + @Mock + protected AaiCqResponse cqResponse; + protected CompletableFuture<OperationOutcome> cqFuture; protected CompletableFuture<Response> future; protected ControlLoopOperationParams params; protected Map<String, String> enrichment; @@ -89,12 +113,28 @@ public class BasicOperation { public void setUpBasic() { MockitoAnnotations.initMocks(this); + cqFuture = new CompletableFuture<>(); future = new CompletableFuture<>(); executor = new PseudoExecutor(); makeContext(); + when(service.getActor(OperationPartial.GUARD_ACTOR_NAME)).thenReturn(guardActor); + when(guardActor.getOperator(OperationPartial.GUARD_OPERATION_NAME)).thenReturn(guardOperator); + when(guardOperator.buildOperation(any())).thenReturn(guardOperation); + + outcome = params.makeOutcome(); + outcome.setResult(PolicyResult.SUCCESS); + when(guardOperation.start()).thenReturn(CompletableFuture.completedFuture(outcome)); + + when(service.getActor(AaiConstants.ACTOR_NAME)).thenReturn(cqActor); + when(cqActor.getOperator("CustomQuery")).thenReturn(cqOperator); + when(cqOperator.buildOperation(any())).thenReturn(cqOperation); + + when(cqOperation.start()).thenReturn(cqFuture); + + // get a fresh outcome outcome = params.makeOutcome(); } @@ -133,7 +173,7 @@ public class BasicOperation { * * @return payload data */ - protected Map<String, String> makePayload() { + protected Map<String, Object> makePayload() { return null; } @@ -162,4 +202,16 @@ public class BasicOperation { assertEquals(expected, json); } + + /** + * Provides a response to a custom query. + * + * @param cq response to provide + */ + protected void provideCqResponse(AaiCqResponse cq) { + context.setProperty(AaiCqResponse.CONTEXT_KEY, cq); + OperationOutcome outcome2 = params.makeOutcome(); + outcome2.setResult(PolicyResult.SUCCESS); + cqFuture.complete(outcome2); + } } diff --git a/models-interactions/model-actors/actor.test/src/test/java/org/onap/policy/controlloop/actor/test/BasicActorTest.java b/models-interactions/model-actors/actor.test/src/test/java/org/onap/policy/controlloop/actor/test/BasicActorTest.java new file mode 100644 index 000000000..ef9b37ba6 --- /dev/null +++ b/models-interactions/model-actors/actor.test/src/test/java/org/onap/policy/controlloop/actor/test/BasicActorTest.java @@ -0,0 +1,47 @@ +/*- + * ============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.test; + +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import org.junit.Test; + +public class BasicActorTest extends BasicActor { + + @Test + public void testVerifyActorService_testStartOtherServices_testStopOtherServices() { + // mostly empty service + verifyActorService(DummyActor.NAME, "service.yaml"); + + // service with Topics and HTTP Clients + verifyActorService(DummyActor.NAME, "serviceFull.yaml"); + + assertThatIllegalArgumentException() + .isThrownBy(() -> verifyActorService(DummyActor.NAME, "serviceInvalidHttp.yaml")); + + assertThatIllegalArgumentException() + .isThrownBy(() -> verifyActorService(DummyActor.NAME, "serviceMissingActors.yaml")); + + // config file not found + assertThatThrownBy(() -> verifyActorService(DummyActor.NAME, "file-not-found.yaml")); + } +} diff --git a/models-interactions/model-actors/actor.test/src/test/java/org/onap/policy/controlloop/actor/test/BasicOperationTest.java b/models-interactions/model-actors/actor.test/src/test/java/org/onap/policy/controlloop/actor/test/BasicOperationTest.java index 60bb00892..5eb35e9d0 100644 --- a/models-interactions/model-actors/actor.test/src/test/java/org/onap/policy/controlloop/actor/test/BasicOperationTest.java +++ b/models-interactions/model-actors/actor.test/src/test/java/org/onap/policy/controlloop/actor/test/BasicOperationTest.java @@ -27,11 +27,16 @@ import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import java.util.Map; +import java.util.concurrent.CompletableFuture; import org.junit.Before; import org.junit.Test; +import org.onap.policy.aai.AaiCqResponse; import org.onap.policy.common.utils.coder.CoderException; import org.onap.policy.common.utils.resources.ResourceUtils; +import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome; import org.onap.policy.controlloop.actorserviceprovider.Util; +import org.onap.policy.controlloop.actorserviceprovider.impl.OperationPartial; +import org.onap.policy.controlloop.policy.PolicyResult; public class BasicOperationTest { private static final String ACTOR = "my-actor"; @@ -65,6 +70,12 @@ public class BasicOperationTest { assertNotNull(oper.context); assertNotNull(oper.outcome); assertNotNull(oper.executor); + assertNotNull(oper.guardOperation); + + CompletableFuture<OperationOutcome> future = oper.service.getActor(OperationPartial.GUARD_ACTOR_NAME) + .getOperator(OperationPartial.GUARD_OPERATION_NAME).buildOperation(null).start(); + assertTrue(future.isDone()); + assertEquals(PolicyResult.SUCCESS, future.get().getResult()); } @Test @@ -97,4 +108,14 @@ public class BasicOperationTest { Map<String, Object> map = Util.translateToMap("", ResourceUtils.getResourceAsString("actual.json")); oper.verifyRequest("expected.json", map, "svc-request-id", "vnf-id"); } + + @Test + public void testProvideCqResponse() throws Exception { + AaiCqResponse cq = new AaiCqResponse("{}"); + oper.provideCqResponse(cq); + + assertSame(cq, oper.context.getProperty(AaiCqResponse.CONTEXT_KEY)); + assertTrue(oper.cqFuture.isDone()); + assertEquals(PolicyResult.SUCCESS, oper.cqFuture.get().getResult()); + } } diff --git a/models-interactions/model-actors/actor.test/src/test/java/org/onap/policy/controlloop/actor/test/DummyActor.java b/models-interactions/model-actors/actor.test/src/test/java/org/onap/policy/controlloop/actor/test/DummyActor.java new file mode 100644 index 000000000..c862a18b7 --- /dev/null +++ b/models-interactions/model-actors/actor.test/src/test/java/org/onap/policy/controlloop/actor/test/DummyActor.java @@ -0,0 +1,39 @@ +/*- + * ============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.test; + +import org.onap.policy.controlloop.actorserviceprovider.impl.ActorImpl; + +public class DummyActor extends ActorImpl { + public static final String NAME = "MyActor"; + public static final String MY_OPERATION1 = "MyOperationA"; + public static final String MY_OPERATION2 = "MyOperationB"; + + /** + * Constructs the object. + */ + public DummyActor() { + super(NAME); + + addOperator(new DummyOperator(NAME, MY_OPERATION1)); + addOperator(new DummyOperator(NAME, MY_OPERATION2)); + } +} diff --git a/models-interactions/model-actors/actor.test/src/test/java/org/onap/policy/controlloop/actor/test/DummyOperator.java b/models-interactions/model-actors/actor.test/src/test/java/org/onap/policy/controlloop/actor/test/DummyOperator.java new file mode 100644 index 000000000..efd3b6500 --- /dev/null +++ b/models-interactions/model-actors/actor.test/src/test/java/org/onap/policy/controlloop/actor/test/DummyOperator.java @@ -0,0 +1,37 @@ +/*- + * ============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.test; + +import org.onap.policy.controlloop.actorserviceprovider.Operation; +import org.onap.policy.controlloop.actorserviceprovider.impl.OperatorPartial; +import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams; + +public class DummyOperator extends OperatorPartial { + + public DummyOperator(String actorName, String name) { + super(actorName, name); + } + + @Override + public Operation buildOperation(ControlLoopOperationParams params) { + return null; + } +} diff --git a/models-interactions/model-actors/actor.test/src/test/resources/META-INF/services/org.onap.policy.controlloop.actorserviceprovider.spi.Actor b/models-interactions/model-actors/actor.test/src/test/resources/META-INF/services/org.onap.policy.controlloop.actorserviceprovider.spi.Actor new file mode 100644 index 000000000..f9c3bddfd --- /dev/null +++ b/models-interactions/model-actors/actor.test/src/test/resources/META-INF/services/org.onap.policy.controlloop.actorserviceprovider.spi.Actor @@ -0,0 +1 @@ +org.onap.policy.controlloop.actor.test.DummyActor
\ No newline at end of file diff --git a/models-interactions/model-actors/actor.test/src/test/resources/service.yaml b/models-interactions/model-actors/actor.test/src/test/resources/service.yaml new file mode 100644 index 000000000..49de7da51 --- /dev/null +++ b/models-interactions/model-actors/actor.test/src/test/resources/service.yaml @@ -0,0 +1,23 @@ +# +# ============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======================================================== +# +actors: + MyActor: + MyOperationA: {} + MyOperationB: {}
\ No newline at end of file diff --git a/models-interactions/model-actors/actor.test/src/test/resources/serviceFull.yaml b/models-interactions/model-actors/actor.test/src/test/resources/serviceFull.yaml new file mode 100644 index 000000000..9818215be --- /dev/null +++ b/models-interactions/model-actors/actor.test/src/test/resources/serviceFull.yaml @@ -0,0 +1,42 @@ +# +# ============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======================================================== +# +httpClients: +- clientName: my-client + hostname: localhost + port: 80 + basePath: base-url + managed: true +topics: + topicSources: + - topicCommInfrastructure: NOOP + topic: my-source + servers: + - localhost + managed: true + topicSinks: + - topicCommInfrastructure: NOOP + topic: my-sink + servers: + - localhost + managed: true +actors: + MyActor: + MyOperationA: {} + MyOperationB: {}
\ No newline at end of file diff --git a/models-interactions/model-actors/actor.test/src/test/resources/serviceInvalidHttp.yaml b/models-interactions/model-actors/actor.test/src/test/resources/serviceInvalidHttp.yaml new file mode 100644 index 000000000..b31e8e81e --- /dev/null +++ b/models-interactions/model-actors/actor.test/src/test/resources/serviceInvalidHttp.yaml @@ -0,0 +1,29 @@ +# +# ============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======================================================== +# +httpClients: +- clientName: my-client + hostname: localhost + port: 80 + serializationProvider: unknown.class.name + managed: true +actors: + MyActor: + MyOperationA: {} + MyOperationB: {}
\ No newline at end of file diff --git a/models-interactions/model-actors/actor.test/src/test/resources/serviceMissingActors.yaml b/models-interactions/model-actors/actor.test/src/test/resources/serviceMissingActors.yaml new file mode 100644 index 000000000..0eec84ea4 --- /dev/null +++ b/models-interactions/model-actors/actor.test/src/test/resources/serviceMissingActors.yaml @@ -0,0 +1,25 @@ +# +# ============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======================================================== +# +httpClients: +- clientName: my-client + hostname: localhost + port: 80 + basePath: base-url + managed: true
\ No newline at end of file diff --git a/models-interactions/model-actors/actor.vfc/src/main/resources/META-INF/services/org.onap.policy.controlloop.actorServiceProvider.spi.Actor b/models-interactions/model-actors/actor.vfc/src/main/resources/META-INF/services/org.onap.policy.controlloop.actorserviceprovider.spi.Actor index e43c726cf..e43c726cf 100644 --- a/models-interactions/model-actors/actor.vfc/src/main/resources/META-INF/services/org.onap.policy.controlloop.actorServiceProvider.spi.Actor +++ b/models-interactions/model-actors/actor.vfc/src/main/resources/META-INF/services/org.onap.policy.controlloop.actorserviceprovider.spi.Actor diff --git a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/ActorService.java b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/ActorService.java index 24c2cfc23..22c7d3365 100644 --- a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/ActorService.java +++ b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/ActorService.java @@ -24,7 +24,9 @@ package org.onap.policy.controlloop.actorserviceprovider; import com.google.common.collect.ImmutableMap; import java.util.Collection; import java.util.HashMap; +import java.util.Iterator; import java.util.Map; +import java.util.ServiceConfigurationError; import java.util.ServiceLoader; import java.util.Set; import org.onap.policy.common.parameters.BeanValidationResult; @@ -57,7 +59,17 @@ public class ActorService extends StartConfigPartial<Map<String, Map<String, Obj Map<String, Actor> map = new HashMap<>(); - for (Actor newActor : loadActors()) { + Iterator<Actor> iter = loadActors().iterator(); + while (iter.hasNext()) { + + Actor newActor; + try { + newActor = iter.next(); + } catch (ServiceConfigurationError e) { + logger.warn("unable to load actor", e); + continue; + } + map.compute(newActor.getName(), (name, existingActor) -> { if (existingActor == null) { return newActor; @@ -168,8 +180,7 @@ public class ActorService extends StartConfigPartial<Map<String, Map<String, Obj @Override protected void doStop() { logger.info("stopping actors"); - name2actor.values() - .forEach(actor -> Util.runFunction(actor::stop, "failed to stop actor {}", actor.getName())); + name2actor.values().forEach(actor -> Util.runFunction(actor::stop, "failed to stop actor {}", actor.getName())); } @Override diff --git a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/controlloop/ControlLoopEventContext.java b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/controlloop/ControlLoopEventContext.java index 8099ea7c2..f7b58c11e 100644 --- a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/controlloop/ControlLoopEventContext.java +++ b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/controlloop/ControlLoopEventContext.java @@ -117,6 +117,14 @@ public class ControlLoopEventContext implements Serializable { } /** + * Removes a property. + * @param name property name + */ + public void removeProperty(String name) { + properties.remove(name); + } + + /** * Obtains the given property. * * @param name name of the desired property diff --git a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/impl/OperationPartial.java b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/impl/OperationPartial.java index e636228f6..c998209bc 100644 --- a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/impl/OperationPartial.java +++ b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/impl/OperationPartial.java @@ -23,8 +23,10 @@ package org.onap.policy.controlloop.actorserviceprovider.impl; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; +import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; +import java.util.Map; import java.util.Queue; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; @@ -71,6 +73,8 @@ public abstract class OperationPartial implements Operation { private static final Logger logger = LoggerFactory.getLogger(OperationPartial.class); private static final Coder coder = new StandardCoder(); + public static final String GUARD_ACTOR_NAME = "GUARD"; + public static final String GUARD_OPERATION_NAME = "Decision"; public static final long DEFAULT_RETRY_WAIT_MS = 1000L; private final OperatorConfig config; @@ -187,7 +191,7 @@ public abstract class OperationPartial implements Operation { /** * Invokes the operation's preprocessor step(s) as a "future". This method simply - * invokes {@link #startGuardAsync()}. + * returns {@code null}. * <p/> * This method assumes the following: * <ul> @@ -199,12 +203,11 @@ public abstract class OperationPartial implements Operation { * {@code null} if this operation needs no preprocessor */ protected CompletableFuture<OperationOutcome> startPreprocessorAsync() { - return startGuardAsync(); + return null; } /** - * Invokes the operation's guard step(s) as a "future". This method simply returns - * {@code null}. + * Invokes the operation's guard step(s) as a "future". * <p/> * This method assumes the following: * <ul> @@ -216,7 +219,42 @@ public abstract class OperationPartial implements Operation { * {@code null} if this operation has no guard */ protected CompletableFuture<OperationOutcome> startGuardAsync() { - return null; + // get the guard payload + Map<String,Object> guardPayload = makeGuardPayload(); + + // wrap it in a "resource" + Map<String,Object> resource = new LinkedHashMap<>(); + resource.put("guard", guardPayload); + + Map<String,Object> payload = new LinkedHashMap<>(); + payload.put("resource", resource); + + /* + * Note: can't use constants from actor.guard, because that would create a + * circular dependency. + */ + return params.toBuilder().actor(GUARD_ACTOR_NAME).operation(GUARD_OPERATION_NAME).retry(null).timeoutSec(null) + .payload(payload).build().start(); + } + + /** + * Creates a payload to execute a guard operation. + * + * @return a new guard payload + */ + protected Map<String, Object> makeGuardPayload() { + Map<String, Object> guard = new LinkedHashMap<>(); + guard.put("actor", params.getActor()); + guard.put("recipe", params.getOperation()); + guard.put("target", params.getTargetEntity()); + guard.put("requestId", params.getRequestId()); + + String clname = params.getContext().getEvent().getClosedLoopControlName(); + if (clname != null) { + guard.put("clname", clname); + } + + return guard; } /** diff --git a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/parameters/CommonActorParams.java b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/parameters/CommonActorParams.java index dc6f2b657..b8218e53b 100644 --- a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/parameters/CommonActorParams.java +++ b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/parameters/CommonActorParams.java @@ -33,18 +33,22 @@ import org.onap.policy.controlloop.actorserviceprovider.Util; /** * Superclass for Actor parameters that have default values in "this" object, and - * operation-specific values in {@link #operation}. + * operation-specific values in {@link #operations}. */ @Getter @Setter @EqualsAndHashCode public class CommonActorParams { + /** + * Name of the "operations" field contained within actor parameters. + */ + public static final String OPERATIONS_FIELD = "operations"; /** * Maps the operation name to its parameters. */ @NotNull - protected Map<String, Map<String, Object>> operation; + protected Map<String, Map<String, Object>> operations; /** @@ -57,10 +61,10 @@ public class CommonActorParams { public Function<String, Map<String, Object>> makeOperationParameters(String name) { Map<String, Object> defaultParams = Util.translateToMap(name, this); - defaultParams.remove("operation"); + defaultParams.remove(OPERATIONS_FIELD); return operationName -> { - Map<String, Object> specificParams = operation.get(operationName); + Map<String, Object> specificParams = operations.get(operationName); if (specificParams == null) { return null; } diff --git a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/parameters/ControlLoopOperationParams.java b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/parameters/ControlLoopOperationParams.java index 925916097..7fc15c97b 100644 --- a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/parameters/ControlLoopOperationParams.java +++ b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/parameters/ControlLoopOperationParams.java @@ -86,7 +86,7 @@ public class ControlLoopOperationParams { /** * Payload data for the request. */ - private Map<String, String> payload; + private Map<String, Object> payload; /** * Number of retries allowed, or {@code null} if no retries. diff --git a/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/controlloop/ControlLoopEventContextTest.java b/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/controlloop/ControlLoopEventContextTest.java index cf2426214..0f44f4f36 100644 --- a/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/controlloop/ControlLoopEventContextTest.java +++ b/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/controlloop/ControlLoopEventContextTest.java @@ -41,6 +41,7 @@ import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome; import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams; public class ControlLoopEventContextTest { + private static final String MY_KEY = "def"; private static final UUID REQ_ID = UUID.randomUUID(); private static final String ITEM_KEY = "obtain-C"; @@ -53,7 +54,7 @@ public class ControlLoopEventContextTest { */ @Before public void setUp() { - enrichment = Map.of("abc", "one", "def", "two"); + enrichment = Map.of("abc", "one", MY_KEY, "two"); event = new VirtualControlLoopEvent(); event.setRequestId(REQ_ID); @@ -81,17 +82,21 @@ public class ControlLoopEventContextTest { } @Test - public void testContains_testGetProperty_testSetProperty() { + public void testContains_testGetProperty_testSetProperty_testRemoveProperty() { context.setProperty("abc", "a string"); - context.setProperty("def", 100); + context.setProperty(MY_KEY, 100); + assertTrue(context.contains(MY_KEY)); assertFalse(context.contains("ghi")); String strValue = context.getProperty("abc"); assertEquals("a string", strValue); - int intValue = context.getProperty("def"); + int intValue = context.getProperty(MY_KEY); assertEquals(100, intValue); + + context.removeProperty(MY_KEY); + assertFalse(context.contains(MY_KEY)); } @Test diff --git a/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/impl/BidirectionalTopicActorTest.java b/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/impl/BidirectionalTopicActorTest.java index 4a4354195..dfd3f8bc6 100644 --- a/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/impl/BidirectionalTopicActorTest.java +++ b/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/impl/BidirectionalTopicActorTest.java @@ -172,7 +172,7 @@ public class BidirectionalTopicActorTest { new TreeMap<>(maker.apply("operB")).toString()); // with invalid actor parameters - params.setOperation(null); + params.setOperations(null); assertThatThrownBy(() -> prov.makeOperatorParameters(Util.translateToMap(prov.getName(), params))) .isInstanceOf(ParameterValidationRuntimeException.class); } @@ -212,7 +212,7 @@ public class BidirectionalTopicActorTest { params.setTimeoutSec(TIMEOUT); // @formatter:off - params.setOperation(Map.of( + params.setOperations(Map.of( "operA", Map.of(), "operB", Map.of("sourceTopic", "topicB"))); // @formatter:on diff --git a/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/impl/HttpActorTest.java b/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/impl/HttpActorTest.java index dacd3a529..a28b98c81 100644 --- a/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/impl/HttpActorTest.java +++ b/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/impl/HttpActorTest.java @@ -54,7 +54,7 @@ public class HttpActorTest { params.setTimeoutSec(TIMEOUT); // @formatter:off - params.setOperation(Map.of( + params.setOperations(Map.of( "operA", Map.of("path", "urlA"), "operB", Map.of("path", "urlB"))); // @formatter:on @@ -73,7 +73,7 @@ public class HttpActorTest { new TreeMap<>(maker.apply("operB")).toString()); // with invalid actor parameters - params.setOperation(null); + params.setOperations(null); assertThatThrownBy(() -> prov.makeOperatorParameters(Util.translateToMap(prov.getName(), params))) .isInstanceOf(ParameterValidationRuntimeException.class); } diff --git a/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/impl/OperationPartialTest.java b/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/impl/OperationPartialTest.java index 39564a443..2893cb627 100644 --- a/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/impl/OperationPartialTest.java +++ b/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/impl/OperationPartialTest.java @@ -28,6 +28,9 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import ch.qos.logback.classic.Logger; import java.time.Instant; @@ -44,7 +47,6 @@ import java.util.concurrent.ForkJoinPool; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import java.util.function.Supplier; @@ -55,6 +57,9 @@ import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure; import org.onap.policy.common.endpoints.utils.NetLoggerUtil.EventType; import org.onap.policy.common.utils.coder.Coder; @@ -64,11 +69,14 @@ import org.onap.policy.common.utils.test.log.logback.ExtractAppender; import org.onap.policy.common.utils.time.PseudoExecutor; import org.onap.policy.controlloop.ControlLoopOperation; import org.onap.policy.controlloop.VirtualControlLoopEvent; +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.controlloop.ControlLoopEventContext; import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams; import org.onap.policy.controlloop.actorserviceprovider.parameters.OperatorConfig; +import org.onap.policy.controlloop.actorserviceprovider.spi.Actor; import org.onap.policy.controlloop.policy.PolicyResult; import org.slf4j.LoggerFactory; @@ -82,6 +90,7 @@ public class OperationPartialTest { private static final String OPERATION = "my-operation"; private static final String MY_SINK = "my-sink"; private static final String MY_SOURCE = "my-source"; + private static final String MY_TARGET_ENTITY = "my-entity"; private static final String TEXT = "my-text"; private static final int TIMEOUT = 1000; private static final UUID REQ_ID = UUID.randomUUID(); @@ -95,6 +104,15 @@ public class OperationPartialTest { private static final Logger logger = (Logger) LoggerFactory.getLogger(OperationPartial.class); private static final ExtractAppender appender = new ExtractAppender(); + @Mock + private ActorService service; + @Mock + private Actor guardActor; + @Mock + private Operator guardOperator; + @Mock + private Operation guardOperation; + private VirtualControlLoopEvent event; private ControlLoopEventContext context; private PseudoExecutor executor; @@ -139,6 +157,8 @@ public class OperationPartialTest { */ @Before public void setUp() { + MockitoAnnotations.initMocks(this); + event = new VirtualControlLoopEvent(); event.setRequestId(REQ_ID); @@ -146,8 +166,13 @@ public class OperationPartialTest { executor = new PseudoExecutor(); params = ControlLoopOperationParams.builder().completeCallback(this::completer).context(context) - .executor(executor).actor(ACTOR).operation(OPERATION).timeoutSec(TIMEOUT) - .startCallback(this::starter).targetEntity(MY_SINK).build(); + .executor(executor).actorService(service).actor(ACTOR).operation(OPERATION).timeoutSec(TIMEOUT) + .startCallback(this::starter).targetEntity(MY_TARGET_ENTITY).build(); + + when(service.getActor(OperationPartial.GUARD_ACTOR_NAME)).thenReturn(guardActor); + when(guardActor.getOperator(OperationPartial.GUARD_OPERATION_NAME)).thenReturn(guardOperator); + when(guardOperator.buildOperation(any())).thenReturn(guardOperation); + when(guardOperation.start()).thenReturn(CompletableFuture.completedFuture(makeSuccess())); config = new OperatorConfig(executor); @@ -189,25 +214,6 @@ public class OperationPartialTest { } /** - * Tests startOperation() when the operation has a preprocessor. - */ - @Test - public void testStartWithPreprocessor() { - AtomicInteger count = new AtomicInteger(); - - CompletableFuture<OperationOutcome> preproc = CompletableFuture.supplyAsync(() -> { - count.incrementAndGet(); - return makeSuccess(); - }, executor); - - oper.setGuard(preproc); - - verifyRun("testStartWithPreprocessor_testStartPreprocessor", 1, 1, PolicyResult.SUCCESS); - - assertEquals(1, count.get()); - } - - /** * Tests start() with multiple running requests. */ @Test @@ -232,7 +238,7 @@ public class OperationPartialTest { */ @Test public void testStartPreprocessorFailure() { - oper.setGuard(CompletableFuture.completedFuture(makeFailure())); + oper.setPreProc(CompletableFuture.completedFuture(makeFailure())); verifyRun("testStartPreprocessorFailure", 1, 0, PolicyResult.FAILURE_GUARD); } @@ -243,7 +249,7 @@ public class OperationPartialTest { @Test public void testStartPreprocessorException() { // arrange for the preprocessor to throw an exception - oper.setGuard(CompletableFuture.failedFuture(new IllegalStateException(EXPECTED_EXCEPTION))); + oper.setPreProc(CompletableFuture.failedFuture(new IllegalStateException(EXPECTED_EXCEPTION))); verifyRun("testStartPreprocessorException", 1, 0, PolicyResult.FAILURE_GUARD); } @@ -254,7 +260,7 @@ public class OperationPartialTest { @Test public void testStartPreprocessorNotRunning() { // arrange for the preprocessor to return success, which will be ignored - oper.setGuard(CompletableFuture.completedFuture(makeSuccess())); + // oper.setGuard(CompletableFuture.completedFuture(makeSuccess())); oper.start().cancel(false); assertTrue(executor.runAll(MAX_REQUESTS)); @@ -291,8 +297,49 @@ public class OperationPartialTest { } @Test - public void testStartGuardAsync() { - assertNull(oper.startGuardAsync()); + public void testStartGuardAsync() throws Exception { + CompletableFuture<OperationOutcome> future = oper.startGuardAsync(); + assertTrue(future.isDone()); + assertEquals(PolicyResult.SUCCESS, future.get().getResult()); + + // verify the parameters that were passed + ArgumentCaptor<ControlLoopOperationParams> paramsCaptor = + ArgumentCaptor.forClass(ControlLoopOperationParams.class); + verify(guardOperator).buildOperation(paramsCaptor.capture()); + + params = paramsCaptor.getValue(); + assertEquals(OperationPartial.GUARD_ACTOR_NAME, params.getActor()); + assertEquals(OperationPartial.GUARD_OPERATION_NAME, params.getOperation()); + assertNull(params.getRetry()); + assertNull(params.getTimeoutSec()); + + Map<String, Object> payload = params.getPayload(); + assertNotNull(payload); + + @SuppressWarnings("unchecked") + Map<String, Object> resource = (Map<String, Object>) payload.get("resource"); + assertNotNull(resource); + + @SuppressWarnings("unchecked") + Map<String, Object> guard = (Map<String, Object>) resource.get("guard"); + assertEquals(oper.makeGuardPayload(), guard); + } + + @Test + public void testMakeGuardPayload() { + Map<String, Object> payload = oper.makeGuardPayload(); + assertSame(REQ_ID, payload.get("requestId")); + + // request id changes, so remove it + payload.remove("requestId"); + + assertEquals("{actor=my-actor, recipe=my-operation, target=my-entity}", payload.toString()); + + // repeat, but with closed loop name + event.setClosedLoopControlName("my-loop"); + payload = oper.makeGuardPayload(); + payload.remove("requestId"); + assertEquals("{actor=my-actor, recipe=my-operation, target=my-entity, clname=my-loop}", payload.toString()); } @Test @@ -541,7 +588,7 @@ public class OperationPartialTest { */ @Test public void testHandlePreprocessorFailureTrue() { - oper.setGuard(CompletableFuture.completedFuture(makeSuccess())); + oper.setPreProc(CompletableFuture.completedFuture(makeSuccess())); verifyRun("testHandlePreprocessorFailureTrue", 1, 1, PolicyResult.SUCCESS); } @@ -550,7 +597,7 @@ public class OperationPartialTest { */ @Test public void testHandlePreprocessorFailureFalse() throws Exception { - oper.setGuard(CompletableFuture.completedFuture(makeFailure())); + oper.setPreProc(CompletableFuture.completedFuture(makeFailure())); verifyRun("testHandlePreprocessorFailureFalse", 1, 0, PolicyResult.FAILURE_GUARD); } @@ -559,9 +606,8 @@ public class OperationPartialTest { */ @Test public void testHandlePreprocessorFailureNull() throws Exception { - // arrange to return null from the preprocessor - oper.setGuard(CompletableFuture.completedFuture(null)); - + // arrange to return a null outcome from the preprocessor + oper.setPreProc(CompletableFuture.completedFuture(null)); verifyRun("testHandlePreprocessorFailureNull", 1, 0, PolicyResult.FAILURE_GUARD); } @@ -1211,12 +1257,10 @@ public class OperationPartialTest { @Setter private boolean genException; - @Setter private int maxFailures = 0; - @Setter - private CompletableFuture<OperationOutcome> guard; + private CompletableFuture<OperationOutcome> preProc; public MyOper() { @@ -1242,11 +1286,6 @@ public class OperationPartialTest { } @Override - protected CompletableFuture<OperationOutcome> startGuardAsync() { - return (guard != null ? guard : super.startGuardAsync()); - } - - @Override protected long getRetryWaitMs() { /* * Sleep timers run in the background, but we want to control things via the @@ -1254,5 +1293,10 @@ public class OperationPartialTest { */ return 0L; } + + @Override + protected CompletableFuture<OperationOutcome> startPreprocessorAsync() { + return (preProc != null ? preProc : super.startPreprocessorAsync()); + } } } diff --git a/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/parameters/BidirectionalTopicActorParamsTest.java b/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/parameters/BidirectionalTopicActorParamsTest.java index 1f38ad371..1276950a5 100644 --- a/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/parameters/BidirectionalTopicActorParamsTest.java +++ b/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/parameters/BidirectionalTopicActorParamsTest.java @@ -76,11 +76,12 @@ public class BidirectionalTopicActorParamsTest { assertTrue(params.validate(CONTAINER).isValid()); // only a few fields are required - BidirectionalTopicActorParams sparse = Util.translate(CONTAINER, Map.of("operation", operMap, "timeoutSec", 1), - BidirectionalTopicActorParams.class); + BidirectionalTopicActorParams sparse = + Util.translate(CONTAINER, Map.of(CommonActorParams.OPERATIONS_FIELD, operMap, "timeoutSec", 1), + BidirectionalTopicActorParams.class); assertTrue(sparse.validate(CONTAINER).isValid()); - testValidateField("operation", "null", params2 -> params2.setOperation(null)); + testValidateField(CommonActorParams.OPERATIONS_FIELD, "null", params2 -> params2.setOperations(null)); testValidateField("timeoutSec", "minimum", params2 -> params2.setTimeoutSec(-1)); // check edge cases @@ -111,7 +112,7 @@ public class BidirectionalTopicActorParamsTest { params2.setSinkTopic(DFLT_SINK); params2.setSourceTopic(DFLT_SOURCE); params2.setTimeoutSec(DFLT_TIMEOUT); - params2.setOperation(operMap); + params2.setOperations(operMap); return params2; } diff --git a/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/parameters/CommonActorParamsTest.java b/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/parameters/CommonActorParamsTest.java index 901420346..99b441064 100644 --- a/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/parameters/CommonActorParamsTest.java +++ b/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/parameters/CommonActorParamsTest.java @@ -86,7 +86,7 @@ public class CommonActorParamsTest { assertThatCode(() -> params.doValidation(CONTAINER)).doesNotThrowAnyException(); // invalid param - params.setOperation(null); + params.setOperations(null); assertThatThrownBy(() -> params.doValidation(CONTAINER)) .isInstanceOf(ParameterValidationRuntimeException.class); } @@ -96,11 +96,12 @@ public class CommonActorParamsTest { assertTrue(params.validate(CONTAINER).isValid()); // only a few fields are required - CommonActorParams sparse = Util.translate(CONTAINER, Map.of("operation", operations, "timeoutSec", 1), + CommonActorParams sparse = Util.translate(CONTAINER, + Map.of(CommonActorParams.OPERATIONS_FIELD, operations, "timeoutSec", 1), CommonActorParams.class); assertTrue(sparse.validate(CONTAINER).isValid()); - testValidateField("operation", "null", params2 -> params2.setOperation(null)); + testValidateField(CommonActorParams.OPERATIONS_FIELD, "null", params2 -> params2.setOperations(null)); } private void testValidateField(String fieldName, String expected, Consumer<CommonActorParams> makeInvalid) { @@ -119,7 +120,7 @@ public class CommonActorParamsTest { private CommonActorParams makeCommonActorParams() { MyParams params2 = new MyParams(); - params2.setOperation(operations); + params2.setOperations(operations); params2.setText1(TEXT1); params2.setText2(TEXT2); diff --git a/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/parameters/ControlLoopOperationParamsTest.java b/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/parameters/ControlLoopOperationParamsTest.java index a5215a48f..e4c83049b 100644 --- a/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/parameters/ControlLoopOperationParamsTest.java +++ b/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/parameters/ControlLoopOperationParamsTest.java @@ -99,7 +99,7 @@ public class ControlLoopOperationParamsTest { @Mock private Consumer<OperationOutcome> starter; - private Map<String, String> payload; + private Map<String, Object> payload; private ControlLoopOperationParams params; private OperationOutcome outcome; diff --git a/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/parameters/HttpActorParamsTest.java b/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/parameters/HttpActorParamsTest.java index 9e708535f..99bf63305 100644 --- a/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/parameters/HttpActorParamsTest.java +++ b/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/parameters/HttpActorParamsTest.java @@ -64,11 +64,11 @@ public class HttpActorParamsTest { assertTrue(params.validate(CONTAINER).isValid()); // only a few fields are required - HttpActorParams sparse = Util.translate(CONTAINER, Map.of("operation", operations, "timeoutSec", 1), - HttpActorParams.class); + HttpActorParams sparse = Util.translate(CONTAINER, + Map.of(CommonActorParams.OPERATIONS_FIELD, operations, "timeoutSec", 1), HttpActorParams.class); assertTrue(sparse.validate(CONTAINER).isValid()); - testValidateField("operation", "null", params2 -> params2.setOperation(null)); + testValidateField(CommonActorParams.OPERATIONS_FIELD, "null", params2 -> params2.setOperations(null)); testValidateField("timeoutSec", "minimum", params2 -> params2.setTimeoutSec(-1)); // check edge cases @@ -97,7 +97,7 @@ public class HttpActorParamsTest { HttpActorParams params2 = new HttpActorParams(); params2.setClientName(CLIENT); params2.setTimeoutSec(TIMEOUT); - params2.setOperation(operations); + params2.setOperations(operations); return params2; } diff --git a/models-interactions/model-actors/actorServiceProvider/src/test/resources/META-INF/services/org.onap.policy.controlloop.actorserviceprovider.spi.Actor b/models-interactions/model-actors/actorServiceProvider/src/test/resources/META-INF/services/org.onap.policy.controlloop.actorserviceprovider.spi.Actor index 2a4bb5749..5f28cf4f2 100644 --- a/models-interactions/model-actors/actorServiceProvider/src/test/resources/META-INF/services/org.onap.policy.controlloop.actorserviceprovider.spi.Actor +++ b/models-interactions/model-actors/actorServiceProvider/src/test/resources/META-INF/services/org.onap.policy.controlloop.actorserviceprovider.spi.Actor @@ -1 +1,2 @@ -org.onap.policy.controlloop.actorserviceprovider.DummyActor
\ No newline at end of file +org.onap.policy.controlloop.actorserviceprovider.DummyActor +org.onap.policy.controlloop.actorserviceprovider.InvalidActor
\ No newline at end of file |