diff options
22 files changed, 451 insertions, 57 deletions
diff --git a/models-interactions/model-actors/actor.aai/src/main/java/org/onap/policy/controlloop/actor/aai/AaiCustomQueryOperation.java b/models-interactions/model-actors/actor.aai/src/main/java/org/onap/policy/controlloop/actor/aai/AaiCustomQueryOperation.java index bc2dde9d8..e32734b7d 100644 --- a/models-interactions/model-actors/actor.aai/src/main/java/org/onap/policy/controlloop/actor/aai/AaiCustomQueryOperation.java +++ b/models-interactions/model-actors/actor.aai/src/main/java/org/onap/policy/controlloop/actor/aai/AaiCustomQueryOperation.java @@ -121,9 +121,12 @@ public class AaiCustomQueryOperation extends HttpOperation<String> { * Injects the response into the context. */ @Override - protected void postProcessResponse(OperationOutcome outcome, String url, Response rawResponse, String response) { + protected CompletableFuture<OperationOutcome> postProcessResponse(OperationOutcome outcome, String url, + Response rawResponse, String response) { logger.info("{}: caching response for {}", getFullName(), params.getRequestId()); params.getContext().setProperty(AaiCqResponse.CONTEXT_KEY, new AaiCqResponse(response)); + + return super.postProcessResponse(outcome, url, rawResponse, response); } } diff --git a/models-interactions/model-actors/actor.aai/src/main/java/org/onap/policy/controlloop/actor/aai/AaiGetOperation.java b/models-interactions/model-actors/actor.aai/src/main/java/org/onap/policy/controlloop/actor/aai/AaiGetOperation.java index 60a28209b..ee1c4612d 100644 --- a/models-interactions/model-actors/actor.aai/src/main/java/org/onap/policy/controlloop/actor/aai/AaiGetOperation.java +++ b/models-interactions/model-actors/actor.aai/src/main/java/org/onap/policy/controlloop/actor/aai/AaiGetOperation.java @@ -116,13 +116,15 @@ public class AaiGetOperation extends HttpOperation<StandardCoderObject> { * Injects the response into the context. */ @Override - protected void postProcessResponse(OperationOutcome outcome, String url, Response rawResponse, - StandardCoderObject response) { + protected CompletableFuture<OperationOutcome> postProcessResponse(OperationOutcome outcome, String url, + Response rawResponse, StandardCoderObject response) { String entity = params.getTargetEntity(); logger.info("{}: caching response of {} for {}", getFullName(), entity, params.getRequestId()); params.getContext().setProperty(propertyPrefix + entity, response); + + return super.postProcessResponse(outcome, url, rawResponse, response); } /** diff --git a/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiCustomQueryOperationTest.java b/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiCustomQueryOperationTest.java index c95425e7a..a93508757 100644 --- a/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiCustomQueryOperationTest.java +++ b/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiCustomQueryOperationTest.java @@ -50,7 +50,7 @@ import org.onap.policy.controlloop.actorserviceprovider.parameters.HttpParams; import org.onap.policy.controlloop.actorserviceprovider.spi.Actor; import org.onap.policy.controlloop.policy.PolicyResult; -public class AaiCustomQueryOperationTest extends BasicAaiOperator<Map<String, String>> { +public class AaiCustomQueryOperationTest extends BasicAaiOperation<Map<String, String>> { private static final StandardCoder coder = new StandardCoder(); private static final String MY_LINK = "my-link"; diff --git a/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiGetOperatorTest.java b/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiGetOperationTest.java index ebe953570..654864246 100644 --- a/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiGetOperatorTest.java +++ b/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiGetOperationTest.java @@ -38,14 +38,14 @@ import org.onap.policy.common.utils.coder.StandardCoderObject; import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome; import org.onap.policy.controlloop.policy.PolicyResult; -public class AaiGetOperatorTest extends BasicAaiOperator<Void> { +public class AaiGetOperationTest extends BasicAaiOperation<Void> { private static final String INPUT_FIELD = "input"; private static final String TEXT = "my-text"; private AaiGetOperation oper; - public AaiGetOperatorTest() { + public AaiGetOperationTest() { super(AaiConstants.ACTOR_NAME, AaiGetOperation.TENANT); } diff --git a/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiUtilTest.java b/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiUtilTest.java index 39ed6fe88..ae38cca35 100644 --- a/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiUtilTest.java +++ b/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiUtilTest.java @@ -23,7 +23,7 @@ package org.onap.policy.controlloop.actor.aai; import java.util.Map; import org.junit.Test; -public class AaiUtilTest extends BasicAaiOperator<Void> { +public class AaiUtilTest extends BasicAaiOperation<Void> { @Test public void testMakeHeaders() { diff --git a/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/BasicAaiOperator.java b/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/BasicAaiOperation.java index 50b562afb..00485c935 100644 --- a/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/BasicAaiOperator.java +++ b/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/BasicAaiOperation.java @@ -28,12 +28,12 @@ import org.onap.policy.controlloop.actor.test.BasicHttpOperation; /** * Superclass for various operator tests. */ -public abstract class BasicAaiOperator<Q> extends BasicHttpOperation<Q> { +public abstract class BasicAaiOperation<Q> extends BasicHttpOperation<Q> { /** * Constructs the object using a default actor and operation name. */ - public BasicAaiOperator() { + public BasicAaiOperation() { super(); } @@ -43,7 +43,7 @@ public abstract class BasicAaiOperator<Q> extends BasicHttpOperation<Q> { * @param actor actor name * @param operation operation name */ - public BasicAaiOperator(String actor, String operation) { + public BasicAaiOperation(String actor, String operation) { super(actor, operation); } diff --git a/models-interactions/model-actors/actor.appc/pom.xml b/models-interactions/model-actors/actor.appc/pom.xml index 26eb7c1b7..0cc243c3f 100644 --- a/models-interactions/model-actors/actor.appc/pom.xml +++ b/models-interactions/model-actors/actor.appc/pom.xml @@ -84,5 +84,16 @@ <version>${policy.common.version}</version> <scope>provided</scope> </dependency> + <dependency> + <groupId>org.onap.policy.models.policy-models-interactions.model-actors</groupId> + <artifactId>actor.test</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.powermock</groupId> + <artifactId>powermock-api-mockito2</artifactId> + <scope>test</scope> + </dependency> </dependencies> </project> diff --git a/models-interactions/model-actors/actor.sdnc/src/test/java/org/onap/policy/controlloop/actor/sdnc/BandwidthOnDemandOperatorTest.java b/models-interactions/model-actors/actor.sdnc/src/test/java/org/onap/policy/controlloop/actor/sdnc/BandwidthOnDemandOperationTest.java index 0623df2f5..42042da67 100644 --- a/models-interactions/model-actors/actor.sdnc/src/test/java/org/onap/policy/controlloop/actor/sdnc/BandwidthOnDemandOperatorTest.java +++ b/models-interactions/model-actors/actor.sdnc/src/test/java/org/onap/policy/controlloop/actor/sdnc/BandwidthOnDemandOperationTest.java @@ -28,11 +28,11 @@ import org.junit.Before; import org.junit.Test; import org.onap.policy.sdnc.SdncRequest; -public class BandwidthOnDemandOperatorTest extends BasicSdncOperator { +public class BandwidthOnDemandOperationTest extends BasicSdncOperation { private BandwidthOnDemandOperation oper; - public BandwidthOnDemandOperatorTest() { + public BandwidthOnDemandOperationTest() { super(DEFAULT_ACTOR, BandwidthOnDemandOperation.NAME); } diff --git a/models-interactions/model-actors/actor.sdnc/src/test/java/org/onap/policy/controlloop/actor/sdnc/BasicSdncOperator.java b/models-interactions/model-actors/actor.sdnc/src/test/java/org/onap/policy/controlloop/actor/sdnc/BasicSdncOperation.java index deafc4e9d..db8751d26 100644 --- a/models-interactions/model-actors/actor.sdnc/src/test/java/org/onap/policy/controlloop/actor/sdnc/BasicSdncOperator.java +++ b/models-interactions/model-actors/actor.sdnc/src/test/java/org/onap/policy/controlloop/actor/sdnc/BasicSdncOperation.java @@ -49,14 +49,14 @@ import org.powermock.reflect.Whitebox; /** * Superclass for various operator tests. */ -public abstract class BasicSdncOperator extends BasicHttpOperation<SdncRequest> { +public abstract class BasicSdncOperation extends BasicHttpOperation<SdncRequest> { protected SdncResponse response; /** * Constructs the object using a default actor and operation name. */ - public BasicSdncOperator() { + public BasicSdncOperation() { super(); } @@ -66,7 +66,7 @@ public abstract class BasicSdncOperator extends BasicHttpOperation<SdncRequest> * @param actor actor name * @param operation operation name */ - public BasicSdncOperator(String actor, String operation) { + public BasicSdncOperation(String actor, String operation) { super(actor, operation); } @@ -94,7 +94,8 @@ public abstract class BasicSdncOperator extends BasicHttpOperation<SdncRequest> protected SdncRequest verifyOperation(SdncOperation operation) throws InterruptedException, ExecutionException, TimeoutException { - CompletableFuture<OperationOutcome> future2 = operation.startOperationAsync(1, outcome); + CompletableFuture<OperationOutcome> future2 = operation.start(); + executor.runAll(100); assertFalse(future2.isDone()); verify(client).post(callbackCaptor.capture(), any(), requestCaptor.capture(), any()); diff --git a/models-interactions/model-actors/actor.sdnc/src/test/java/org/onap/policy/controlloop/actor/sdnc/RerouteOperatorTest.java b/models-interactions/model-actors/actor.sdnc/src/test/java/org/onap/policy/controlloop/actor/sdnc/RerouteOperationTest.java index 7fc5ee7c2..a98c38180 100644 --- a/models-interactions/model-actors/actor.sdnc/src/test/java/org/onap/policy/controlloop/actor/sdnc/RerouteOperatorTest.java +++ b/models-interactions/model-actors/actor.sdnc/src/test/java/org/onap/policy/controlloop/actor/sdnc/RerouteOperationTest.java @@ -28,11 +28,11 @@ import org.junit.Before; import org.junit.Test; import org.onap.policy.sdnc.SdncRequest; -public class RerouteOperatorTest extends BasicSdncOperator { +public class RerouteOperationTest extends BasicSdncOperation { private RerouteOperation oper; - public RerouteOperatorTest() { + public RerouteOperationTest() { super(DEFAULT_ACTOR, RerouteOperation.NAME); } diff --git a/models-interactions/model-actors/actor.sdnc/src/test/java/org/onap/policy/controlloop/actor/sdnc/SdncOperatorTest.java b/models-interactions/model-actors/actor.sdnc/src/test/java/org/onap/policy/controlloop/actor/sdnc/SdncOperationTest.java index 4bc514c08..e0825e13b 100644 --- a/models-interactions/model-actors/actor.sdnc/src/test/java/org/onap/policy/controlloop/actor/sdnc/SdncOperatorTest.java +++ b/models-interactions/model-actors/actor.sdnc/src/test/java/org/onap/policy/controlloop/actor/sdnc/SdncOperationTest.java @@ -30,7 +30,7 @@ import org.junit.Before; import org.junit.Test; import org.onap.policy.sdnc.SdncRequest; -public class SdncOperatorTest extends BasicSdncOperator { +public class SdncOperationTest extends BasicSdncOperation { private SdncRequest request; private SdncOperation oper; diff --git a/models-interactions/model-actors/actor.test/src/main/java/org/onap/policy/controlloop/actor/test/BasicBidirectionalTopicOperation.java b/models-interactions/model-actors/actor.test/src/main/java/org/onap/policy/controlloop/actor/test/BasicBidirectionalTopicOperation.java new file mode 100644 index 000000000..14c7ef576 --- /dev/null +++ b/models-interactions/model-actors/actor.test/src/main/java/org/onap/policy/controlloop/actor/test/BasicBidirectionalTopicOperation.java @@ -0,0 +1,181 @@ +/*- + * ============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.mockito.Mockito.when; + +import java.util.Map; +import java.util.TreeMap; +import java.util.UUID; +import java.util.function.BiConsumer; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.onap.policy.common.utils.coder.Coder; +import org.onap.policy.common.utils.coder.CoderException; +import org.onap.policy.common.utils.coder.StandardCoder; +import org.onap.policy.common.utils.coder.StandardCoderObject; +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.OperationOutcome; +import org.onap.policy.controlloop.actorserviceprovider.controlloop.ControlLoopEventContext; +import org.onap.policy.controlloop.actorserviceprovider.impl.BidirectionalTopicOperator; +import org.onap.policy.controlloop.actorserviceprovider.parameters.BidirectionalTopicParams; +import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams; +import org.onap.policy.controlloop.actorserviceprovider.topic.BidirectionalTopicHandler; +import org.onap.policy.controlloop.actorserviceprovider.topic.Forwarder; + +/** + * Superclass for various BidirectionalTopicOperation tests. + */ +public class BasicBidirectionalTopicOperation { + protected static final UUID REQ_ID = UUID.randomUUID(); + protected static final String DEFAULT_ACTOR = "default-actor"; + protected static final String DEFAULT_OPERATION = "default-operation"; + protected static final String MY_SINK = "my-sink"; + protected static final String MY_SOURCE = "my-source"; + protected static final String TARGET_ENTITY = "my-target"; + protected static final Coder coder = new StandardCoder(); + protected static final int TIMEOUT = 10; + + protected final String actorName; + protected final String operationName; + + @Captor + protected ArgumentCaptor<BiConsumer<String, StandardCoderObject>> listenerCaptor; + + @Mock + protected ActorService service; + @Mock + protected BidirectionalTopicHandler topicHandler; + @Mock + protected Forwarder forwarder; + @Mock + protected BidirectionalTopicOperator operator; + + protected BidirectionalTopicParams topicParams; + protected ControlLoopOperationParams params; + protected Map<String, String> enrichment; + protected VirtualControlLoopEvent event; + protected ControlLoopEventContext context; + protected OperationOutcome outcome; + protected PseudoExecutor executor; + + /** + * Constructs the object using a default actor and operation name. + */ + public BasicBidirectionalTopicOperation() { + this.actorName = DEFAULT_ACTOR; + this.operationName = DEFAULT_OPERATION; + } + + /** + * Constructs the object. + * + * @param actor actor name + * @param operation operation name + */ + public BasicBidirectionalTopicOperation(String actor, String operation) { + this.actorName = actor; + this.operationName = operation; + } + + /** + * Initializes mocks and sets up. + */ + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + executor = new PseudoExecutor(); + + makeContext(); + + outcome = params.makeOutcome(); + topicParams = BidirectionalTopicParams.builder().sinkTopic(MY_SINK).sourceTopic(MY_SOURCE).timeoutSec(TIMEOUT) + .build(); + + initOperator(); + } + + /** + * Reinitializes {@link #enrichment}, {@link #event}, {@link #context}, and + * {@link #params}. + * <p/> + * Note: {@link #params} is configured to use {@link #executor}. + */ + protected void makeContext() { + enrichment = new TreeMap<>(makeEnrichment()); + + event = new VirtualControlLoopEvent(); + event.setRequestId(REQ_ID); + event.setAai(enrichment); + + context = new ControlLoopEventContext(event); + + params = ControlLoopOperationParams.builder().executor(executor).context(context).actorService(service) + .actor(actorName).operation(operationName).targetEntity(TARGET_ENTITY).payload(makePayload()) + .build(); + } + + protected Map<String, String> makePayload() { + return null; + } + + /** + * Initializes an operator so that it is "alive" and has the given names. + */ + protected void initOperator() { + when(operator.isAlive()).thenReturn(true); + when(operator.getFullName()).thenReturn(actorName + "." + operationName); + when(operator.getActorName()).thenReturn(actorName); + when(operator.getName()).thenReturn(operationName); + when(operator.getTopicHandler()).thenReturn(topicHandler); + when(operator.getForwarder()).thenReturn(forwarder); + when(operator.getParams()).thenReturn(topicParams); + } + + /** + * Makes enrichment data. + * + * @return enrichment data + */ + protected Map<String, String> makeEnrichment() { + return new TreeMap<>(); + } + + /** + * Provides a response to the topic {@link #listenerCaptor}. + * + * @param listener listener to which to provide the response + * @param response response to be provided + */ + protected void provideResponse(BiConsumer<String, StandardCoderObject> listener, String response) { + try { + StandardCoderObject sco = coder.decode(response, StandardCoderObject.class); + listener.accept(response, sco); + + } catch (CoderException e) { + throw new IllegalArgumentException("response is not a Map", e); + } + } +} diff --git a/models-interactions/model-actors/actor.test/src/main/java/org/onap/policy/controlloop/actor/test/BasicHttpOperation.java b/models-interactions/model-actors/actor.test/src/main/java/org/onap/policy/controlloop/actor/test/BasicHttpOperation.java index e160479b3..492929296 100644 --- a/models-interactions/model-actors/actor.test/src/main/java/org/onap/policy/controlloop/actor/test/BasicHttpOperation.java +++ b/models-interactions/model-actors/actor.test/src/main/java/org/onap/policy/controlloop/actor/test/BasicHttpOperation.java @@ -45,7 +45,7 @@ import org.onap.policy.controlloop.actorserviceprovider.impl.HttpOperator; import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams; /** - * Superclass for various operator tests. + * Superclass for various HttpOperation tests. * * @param <Q> request type */ diff --git a/models-interactions/model-actors/actor.test/src/test/java/org/onap/policy/controlloop/actor/test/BasicBidirectionalTopicOperationTest.java b/models-interactions/model-actors/actor.test/src/test/java/org/onap/policy/controlloop/actor/test/BasicBidirectionalTopicOperationTest.java new file mode 100644 index 000000000..4fd559101 --- /dev/null +++ b/models-interactions/model-actors/actor.test/src/test/java/org/onap/policy/controlloop/actor/test/BasicBidirectionalTopicOperationTest.java @@ -0,0 +1,140 @@ +/*- + * ============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.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; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.verify; + +import java.util.function.BiConsumer; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.onap.policy.common.utils.coder.StandardCoderObject; + +public class BasicBidirectionalTopicOperationTest { + private static final String ACTOR = "my-actor"; + private static final String OPERATION = "my-operation"; + + @Mock + private BiConsumer<String, StandardCoderObject> listener; + + private BasicBidirectionalTopicOperation oper; + + + /** + * Sets up. + */ + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + oper = new BasicBidirectionalTopicOperation(ACTOR, OPERATION); + oper.setUp(); + } + + @Test + public void testBasicBidirectionalTopicOperation() { + oper = new BasicBidirectionalTopicOperation(); + assertEquals(BasicHttpOperation.DEFAULT_ACTOR, oper.actorName); + assertEquals(BasicHttpOperation.DEFAULT_OPERATION, oper.operationName); + } + + @Test + public void testBasicBidirectionalTopicOperationStringString() { + assertEquals(ACTOR, oper.actorName); + assertEquals(OPERATION, oper.operationName); + } + + @Test + public void testSetUp() { + assertNotNull(oper.topicParams); + assertNotNull(oper.context); + assertNotNull(oper.outcome); + assertNotNull(oper.executor); + assertTrue(oper.operator.isAlive()); + } + + @Test + public void testMakeContext() { + oper.makeContext(); + + assertTrue(oper.enrichment.isEmpty()); + + assertSame(BasicBidirectionalTopicOperation.REQ_ID, oper.event.getRequestId()); + assertSame(oper.enrichment, oper.event.getAai()); + + assertSame(oper.event, oper.context.getEvent()); + + assertSame(oper.context, oper.params.getContext()); + assertSame(oper.service, oper.params.getActorService()); + assertSame(oper.executor, oper.params.getExecutor()); + assertEquals(ACTOR, oper.params.getActor()); + assertEquals(OPERATION, oper.params.getOperation()); + assertEquals(BasicBidirectionalTopicOperation.TARGET_ENTITY, oper.params.getTargetEntity()); + } + + @Test + public void testMakePayload() { + assertNull(oper.makePayload()); + } + + @Test + public void testInitOperator() { + oper.initOperator(); + + assertTrue(oper.operator.isAlive()); + assertEquals(ACTOR + "." + OPERATION, oper.operator.getFullName()); + assertEquals(ACTOR, oper.operator.getActorName()); + assertEquals(OPERATION, oper.operator.getName()); + assertSame(oper.topicHandler, oper.operator.getTopicHandler()); + assertSame(oper.forwarder, oper.operator.getForwarder()); + assertSame(oper.topicParams, oper.operator.getParams()); + } + + @Test + public void testMakeEnrichment() { + assertTrue(oper.makeEnrichment().isEmpty()); + } + + @Test + public void testProvideResponse() { + String response = "{\"input\": 10}"; + + oper.provideResponse(listener, response); + + ArgumentCaptor<StandardCoderObject> scoCaptor = ArgumentCaptor.forClass(StandardCoderObject.class); + verify(listener).accept(eq(response), scoCaptor.capture()); + + assertEquals("10", scoCaptor.getValue().getString("input")); + + // try with an invalid response + assertThatIllegalArgumentException().isThrownBy(() -> oper.provideResponse(listener, "{invalid json")) + .withMessage("response is not a Map"); + } +} diff --git a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/Util.java b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/Util.java index b885b5c25..ba4785922 100644 --- a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/Util.java +++ b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/Util.java @@ -34,6 +34,7 @@ import org.slf4j.LoggerFactory; */ public class Util { private static final Logger logger = LoggerFactory.getLogger(Util.class); + private static final Coder coder = new StandardCoder(); private Util() { // do nothing @@ -84,11 +85,8 @@ public class Util { * @return the translated object */ public static <T> T translate(String identifier, Object source, Class<T> clazz) { - Coder coder = new StandardCoder(); - try { - String json = coder.encode(source); - return coder.decode(json, clazz); + return coder.convert(source, clazz); } catch (CoderException | RuntimeException e) { throw new IllegalArgumentException("cannot translate parameters for " + identifier, e); @@ -105,10 +103,6 @@ public class Util { */ @SuppressWarnings("unchecked") public static Map<String, Object> translateToMap(String identifier, Object source) { - if (source == null) { - return null; - } - return translate(identifier, source, LinkedHashMap.class); } } 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 1c37a8e0d..3e02da611 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 @@ -130,15 +130,27 @@ public class ControlLoopEventContext implements Serializable { return null; } - CompletableFuture<OperationOutcome> future = retrievers.get(name); - if (future != null) { - return future; - } + /* + * Return any existing future, if it wasn't canceled. Otherwise, start a new + * request. + */ - future = params.start(); + // @formatter:off + CompletableFuture<OperationOutcome> oldFuture = + retrievers.compute(name, (key, future) -> (future == null || future.isCancelled() ? null : future)); + // @formatter:on - CompletableFuture<OperationOutcome> oldFuture = retrievers.putIfAbsent(name, future); if (oldFuture != null) { + return oldFuture; + } + + /* + * Note: must NOT invoke params.start() within retrievers.compute(), as start() + * may invoke obtain() which would cause a recursive update to the retrievers map. + */ + CompletableFuture<OperationOutcome> future = params.start(); + + if ((oldFuture = retrievers.putIfAbsent(name, future)) != null) { future.cancel(false); return oldFuture; } diff --git a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/impl/BidirectionalTopicOperation.java b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/impl/BidirectionalTopicOperation.java index f82015d6b..d1e21f8fd 100644 --- a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/impl/BidirectionalTopicOperation.java +++ b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/impl/BidirectionalTopicOperation.java @@ -214,14 +214,14 @@ public abstract class BidirectionalTopicOperation<Q, S> extends OperationPartial case SUCCESS: logger.info("{}.{} request succeeded for {}", params.getActor(), params.getOperation(), params.getRequestId()); - setOutcome(outcome, PolicyResult.SUCCESS); + setOutcome(outcome, PolicyResult.SUCCESS, response); postProcessResponse(outcome, rawResponse, response); return outcome; case FAILURE: logger.info("{}.{} request failed for {}", params.getActor(), params.getOperation(), params.getRequestId()); - return setOutcome(outcome, PolicyResult.FAILURE); + return setOutcome(outcome, PolicyResult.FAILURE, response); case STILL_WAITING: default: @@ -232,6 +232,18 @@ public abstract class BidirectionalTopicOperation<Q, S> extends OperationPartial } /** + * Sets an operation's outcome and default message based on the result. + * + * @param outcome operation to be updated + * @param result result of the operation + * @param response response used to populate the outcome + * @return the updated operation + */ + public OperationOutcome setOutcome(OperationOutcome outcome, PolicyResult result, S response) { + return setOutcome(outcome, result); + } + + /** * Processes a successful response. * * @param outcome outcome to be populated diff --git a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/impl/HttpOperation.java b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/impl/HttpOperation.java index f1829d79a..c3c0f6dc2 100644 --- a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/impl/HttpOperation.java +++ b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/impl/HttpOperation.java @@ -148,21 +148,23 @@ public abstract class HttpOperation<T> extends OperationPartial { controller.add(requester.apply(callback)); // once "future" completes, process the response, and then complete the controller - future.thenApplyAsync(response -> processResponse(outcome, url, response), executor) + future.thenComposeAsync(response -> processResponse(outcome, url, response), executor) .whenCompleteAsync(controller.delayedComplete(), executor); return controller; } /** - * Processes a response. This method simply sets the outcome to SUCCESS. + * Processes a response. This method decodes the response, sets the outcome based on + * the response, and then returns a completed future. * * @param outcome outcome to be populate * @param url URL to which to request was sent * @param response raw response to process - * @return the outcome + * @return a future to cancel or await the outcome */ - protected OperationOutcome processResponse(OperationOutcome outcome, String url, Response rawResponse) { + protected CompletableFuture<OperationOutcome> processResponse(OperationOutcome outcome, String url, + Response rawResponse) { logger.info("{}.{}: response received for {}", params.getActor(), params.getOperation(), params.getRequestId()); @@ -173,7 +175,6 @@ public abstract class HttpOperation<T> extends OperationPartial { T response; if (responseClass == String.class) { response = responseClass.cast(strResponse); - } else { try { response = makeCoder().decode(strResponse, responseClass); @@ -187,26 +188,40 @@ public abstract class HttpOperation<T> extends OperationPartial { if (!isSuccess(rawResponse, response)) { logger.info("{}.{} request failed with http error code {} for {}", params.getActor(), params.getOperation(), rawResponse.getStatus(), params.getRequestId()); - return setOutcome(outcome, PolicyResult.FAILURE); + return CompletableFuture.completedFuture(setOutcome(outcome, PolicyResult.FAILURE, response)); } logger.info("{}.{} request succeeded for {}", params.getActor(), params.getOperation(), params.getRequestId()); - setOutcome(outcome, PolicyResult.SUCCESS); - postProcessResponse(outcome, url, rawResponse, response); + setOutcome(outcome, PolicyResult.SUCCESS, response); + return postProcessResponse(outcome, url, rawResponse, response); + } - return outcome; + /** + * Sets an operation's outcome and default message based on the result. + * + * @param outcome operation to be updated + * @param result result of the operation + * @param response response used to populate the outcome + * @return the updated operation + */ + public OperationOutcome setOutcome(OperationOutcome outcome, PolicyResult result, T response) { + return setOutcome(outcome, result); } /** - * Processes a successful response. + * Processes a successful response. This method simply returns the outcome wrapped in + * a completed future. * * @param outcome outcome to be populate * @param url URL to which to request was sent * @param rawResponse raw response * @param response decoded response + * @return a future to cancel or await the outcome */ - protected void postProcessResponse(OperationOutcome outcome, String url, Response rawResponse, T response) { - // do nothing + protected CompletableFuture<OperationOutcome> postProcessResponse(OperationOutcome outcome, String url, + Response rawResponse, T response) { + + return CompletableFuture.completedFuture(outcome); } /** 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 0b3497197..680a56f89 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 @@ -68,6 +68,7 @@ import org.slf4j.LoggerFactory; 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 long DEFAULT_RETRY_WAIT_MS = 1000L; // values extracted from the operator diff --git a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/topic/TopicListenerImpl.java b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/topic/TopicListenerImpl.java index fcb463518..93beab1cb 100644 --- a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/topic/TopicListenerImpl.java +++ b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/topic/TopicListenerImpl.java @@ -45,7 +45,7 @@ import org.slf4j.LoggerFactory; */ public class TopicListenerImpl implements TopicListener { private static final Logger logger = LoggerFactory.getLogger(TopicListenerImpl.class); - private static StandardCoder coder = new StandardCoder(); + private static final StandardCoder coder = new StandardCoder(); /** * Maps selector to a forwarder. 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 b462043d5..cf2426214 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 @@ -42,6 +42,7 @@ import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOp public class ControlLoopEventContextTest { private static final UUID REQ_ID = UUID.randomUUID(); + private static final String ITEM_KEY = "obtain-C"; private Map<String, String> enrichment; private VirtualControlLoopEvent event; @@ -118,13 +119,28 @@ public class ControlLoopEventContextTest { ControlLoopOperationParams params2 = mock(ControlLoopOperationParams.class); when(params2.start()).thenReturn(future2); - assertSame(future2, context.obtain("obtain-C", params2)); + assertSame(future2, context.obtain(ITEM_KEY, params2)); return future; }); - assertSame(future2, context.obtain("obtain-C", params)); + assertSame(future2, context.obtain(ITEM_KEY, params)); // should have canceled the interrupted future assertTrue(future.isCancelled()); + + // return a new future next time start() is called + CompletableFuture<OperationOutcome> future3 = new CompletableFuture<>(); + when(params.start()).thenReturn(future3); + + // repeat - should get the same future + assertSame(future2, context.obtain(ITEM_KEY, params)); + assertSame(future2, context.obtain(ITEM_KEY, params)); + + // future2 should still be active + assertFalse(future2.isCancelled()); + + // cancel it - now we should get the new future + future2.cancel(false); + assertSame(future3, context.obtain(ITEM_KEY, params)); } } diff --git a/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/impl/HttpOperationTest.java b/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/impl/HttpOperationTest.java index 50cb8fa8f..8189c74fe 100644 --- a/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/impl/HttpOperationTest.java +++ b/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/impl/HttpOperationTest.java @@ -302,8 +302,10 @@ public class HttpOperationTest { * Tests processResponse() when it's a success and the response type is a String. */ @Test - public void testProcessResponseSuccessString() { - assertSame(outcome, oper.processResponse(outcome, PATH, response)); + public void testProcessResponseSuccessString() throws Exception { + CompletableFuture<OperationOutcome> result = oper.processResponse(outcome, PATH, response); + assertTrue(result.isDone()); + assertSame(outcome, result.get()); assertEquals(PolicyResult.SUCCESS, outcome.getResult()); } @@ -311,9 +313,11 @@ public class HttpOperationTest { * Tests processResponse() when it's a failure. */ @Test - public void testProcessResponseFailure() { + public void testProcessResponseFailure() throws Exception { when(response.getStatus()).thenReturn(555); - assertSame(outcome, oper.processResponse(outcome, PATH, response)); + CompletableFuture<OperationOutcome> result = oper.processResponse(outcome, PATH, response); + assertTrue(result.isDone()); + assertSame(outcome, result.get()); assertEquals(PolicyResult.FAILURE, outcome.getResult()); } @@ -321,12 +325,14 @@ public class HttpOperationTest { * Tests processResponse() when the decoder succeeds. */ @Test - public void testProcessResponseDecodeOk() throws CoderException { + public void testProcessResponseDecodeOk() throws Exception { when(response.readEntity(String.class)).thenReturn("10"); MyGetOperation<Integer> oper2 = new MyGetOperation<>(Integer.class); - assertSame(outcome, oper2.processResponse(outcome, PATH, response)); + CompletableFuture<OperationOutcome> result = oper2.processResponse(outcome, PATH, response); + assertTrue(result.isDone()); + assertSame(outcome, result.get()); assertEquals(PolicyResult.SUCCESS, outcome.getResult()); } |