From aedb286b0683e9ac24c5160e9d47f596a243697f Mon Sep 17 00:00:00 2001 From: Jim Hahn Date: Thu, 5 Mar 2020 16:41:15 -0500 Subject: [PATCH] Add other APPC-LCM operations Also added legacy ModifyConfig as an operation within APPC-LCM. Added logging to topic registration keys. Issue-ID: POLICY-2403 Signed-off-by: Jim Hahn Change-Id: Ia54a573fd6218a8afe870184b9a3baebc05b766a --- .../model-actors/actor.appclcm/pom.xml | 12 + .../actor/appclcm/AppcLcmActorServiceProvider.java | 28 +- .../actor/appclcm/AppcLcmConstants.java | 59 ++++ .../actor/appclcm/AppcLcmOperation.java | 143 ++++---- .../actor/appclcm/ConfigModifyOperation.java | 43 --- .../appclcm/AppcLcmActorServiceProviderTest.java | 46 +-- .../actor/appclcm/AppcLcmOperationTest.java | 378 ++++++++++++++------- .../actorserviceprovider/topic/Forwarder.java | 7 + .../actorserviceprovider/topic/SelectorKey.java | 6 + .../topic/SelectorKeyTest.java | 5 + 10 files changed, 451 insertions(+), 276 deletions(-) create mode 100644 models-interactions/model-actors/actor.appclcm/src/main/java/org/onap/policy/controlloop/actor/appclcm/AppcLcmConstants.java delete mode 100644 models-interactions/model-actors/actor.appclcm/src/main/java/org/onap/policy/controlloop/actor/appclcm/ConfigModifyOperation.java diff --git a/models-interactions/model-actors/actor.appclcm/pom.xml b/models-interactions/model-actors/actor.appclcm/pom.xml index 7538d6655..01cfd43e8 100644 --- a/models-interactions/model-actors/actor.appclcm/pom.xml +++ b/models-interactions/model-actors/actor.appclcm/pom.xml @@ -48,6 +48,12 @@ ${project.version} provided + + org.onap.policy.models.policy-models-interactions.model-actors + actor.appc + ${project.version} + provided + com.google.code.gson gson @@ -70,6 +76,12 @@ commons-lang3 3.8.1 + + org.onap.policy.models.policy-models-interactions.model-actors + actor.test + ${project.version} + test + org.onap.policy.models.policy-models-interactions simulators diff --git a/models-interactions/model-actors/actor.appclcm/src/main/java/org/onap/policy/controlloop/actor/appclcm/AppcLcmActorServiceProvider.java b/models-interactions/model-actors/actor.appclcm/src/main/java/org/onap/policy/controlloop/actor/appclcm/AppcLcmActorServiceProvider.java index 1d04cb5f2..704c44da7 100644 --- a/models-interactions/model-actors/actor.appclcm/src/main/java/org/onap/policy/controlloop/actor/appclcm/AppcLcmActorServiceProvider.java +++ b/models-interactions/model-actors/actor.appclcm/src/main/java/org/onap/policy/controlloop/actor/appclcm/AppcLcmActorServiceProvider.java @@ -1,11 +1,10 @@ /*- * ============LICENSE_START======================================================= - * AppcLcmActorServiceProvider + * ONAP * ================================================================================ * Copyright (C) 2017-2020 AT&T Intellectual Property. All rights reserved. * Modifications copyright (c) 2018 Nokia * Modifications Copyright (C) 2019 Nordix Foundation. - * Modifications 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. @@ -31,6 +30,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import org.onap.policy.appclcm.AppcLcmBody; import org.onap.policy.appclcm.AppcLcmCommonHeader; import org.onap.policy.appclcm.AppcLcmDmaapWrapper; @@ -39,6 +39,8 @@ import org.onap.policy.appclcm.AppcLcmOutput; import org.onap.policy.appclcm.AppcLcmResponseCode; import org.onap.policy.controlloop.ControlLoopOperation; import org.onap.policy.controlloop.VirtualControlLoopEvent; +import org.onap.policy.controlloop.actor.appc.AppcOperation; +import org.onap.policy.controlloop.actor.appc.ModifyConfigOperation; import org.onap.policy.controlloop.actorserviceprovider.impl.BidirectionalTopicActor; import org.onap.policy.controlloop.actorserviceprovider.impl.BidirectionalTopicOperator; import org.onap.policy.controlloop.actorserviceprovider.parameters.BidirectionalTopicActorParams; @@ -67,17 +69,16 @@ public class AppcLcmActorServiceProvider extends BidirectionalTopicActor recipes = - ImmutableList.of(RECIPE_RESTART, RECIPE_REBUILD, RECIPE_MIGRATE, RECIPE_MODIFY); + private static final Set recipes = AppcLcmConstants.OPERATION_NAMES; private static final ImmutableMap> targets = new ImmutableMap.Builder>() .put(RECIPE_RESTART, ImmutableList.of(TARGET_VM)).put(RECIPE_REBUILD, ImmutableList.of(TARGET_VM)) .put(RECIPE_MIGRATE, ImmutableList.of(TARGET_VM)).put(RECIPE_MODIFY, ImmutableList.of(TARGET_VNF)).build(); @@ -91,8 +92,15 @@ public class AppcLcmActorServiceProvider extends BidirectionalTopicActor OPERATION_NAMES = + Set.of(OPERATION_RESTART, OPERATION_REBUILD, OPERATION_MIGRATE, OPERATION_CONFIG_MODIFY); + + // operations from legacy APPC + public static final String LEGACY_MODIFY_CONFIG = "ModifyConfig"; + + public static final Set LEGACY_NAMES = + Set.of(LEGACY_MODIFY_CONFIG); + + public static final Set COMBINED_OPERATION_NAMES; + + static { + Set set = new HashSet<>(OPERATION_NAMES); + set.addAll(LEGACY_NAMES); + COMBINED_OPERATION_NAMES = Collections.unmodifiableSet(set); + } + + protected static final Set SUPPORTS_PAYLOAD = + Set.of(OPERATION_CONFIG_MODIFY).stream().map(String::toLowerCase).collect(Collectors.toSet()); + + private AppcLcmConstants() { + // do nothing + } +} diff --git a/models-interactions/model-actors/actor.appclcm/src/main/java/org/onap/policy/controlloop/actor/appclcm/AppcLcmOperation.java b/models-interactions/model-actors/actor.appclcm/src/main/java/org/onap/policy/controlloop/actor/appclcm/AppcLcmOperation.java index c0b83319c..749622714 100644 --- a/models-interactions/model-actors/actor.appclcm/src/main/java/org/onap/policy/controlloop/actor/appclcm/AppcLcmOperation.java +++ b/models-interactions/model-actors/actor.appclcm/src/main/java/org/onap/policy/controlloop/actor/appclcm/AppcLcmOperation.java @@ -1,6 +1,6 @@ /*- * ============LICENSE_START======================================================= - * AppcLcmOperation + * ONAP * ================================================================================ * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved. * ================================================================================ @@ -24,16 +24,15 @@ import java.util.List; import java.util.Map; import java.util.UUID; import java.util.concurrent.CompletableFuture; -import org.onap.aai.domain.yang.GenericVnf; -import org.onap.policy.aai.AaiConstants; -import org.onap.policy.aai.AaiCqResponse; +import org.apache.commons.lang3.StringUtils; import org.onap.policy.appclcm.AppcLcmBody; import org.onap.policy.appclcm.AppcLcmCommonHeader; import org.onap.policy.appclcm.AppcLcmDmaapWrapper; import org.onap.policy.appclcm.AppcLcmInput; +import org.onap.policy.appclcm.AppcLcmOutput; import org.onap.policy.appclcm.AppcLcmResponseCode; +import org.onap.policy.appclcm.AppcLcmResponseStatus; import org.onap.policy.common.utils.coder.CoderException; -import org.onap.policy.common.utils.coder.StandardCoder; import org.onap.policy.controlloop.VirtualControlLoopEvent; import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome; import org.onap.policy.controlloop.actorserviceprovider.impl.BidirectionalTopicOperation; @@ -41,23 +40,21 @@ import org.onap.policy.controlloop.actorserviceprovider.parameters.Bidirectional import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams; import org.onap.policy.controlloop.actorserviceprovider.topic.SelectorKey; import org.onap.policy.controlloop.policy.PolicyResult; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -public abstract class AppcLcmOperation extends BidirectionalTopicOperation { +public class AppcLcmOperation extends BidirectionalTopicOperation { - private static final Logger logger = LoggerFactory.getLogger(AppcLcmOperation.class); - private static final StandardCoder coder = new StandardCoder(); + private static final String MISSING_STATUS = "APPC-LCM response is missing the response status"; public static final String VNF_ID_KEY = "vnf-id"; /** * Keys used to match the response with the request listener. The sub request ID is a * UUID, so it can be used to uniquely identify the response. *

- * Note: if these change, then {@link #getExpectedKeyValues(int, Request)} must be - * updated accordingly. + * Note: if these change, then {@link #getExpectedKeyValues(int, AppcLcmDmaapWrapper)} + * must be updated accordingly. */ - public static final List SELECTOR_KEYS = List.of(new SelectorKey("common-header", "sub-request-id")); + public static final List SELECTOR_KEYS = + List.of(new SelectorKey("body", "output", "common-header", "sub-request-id")); /** * Constructs the object. @@ -67,6 +64,10 @@ public abstract class AppcLcmOperation extends BidirectionalTopicOperation startPreprocessorAsync() { - if (params != null) { - ControlLoopOperationParams cqParams = params.toBuilder().actor(AaiConstants.ACTOR_NAME) - .operation(AaiCqResponse.OPERATION).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); - } return startGuardAsync(); } @Override protected AppcLcmDmaapWrapper makeRequest(int attempt) { - AaiCqResponse cq = params.getContext().getProperty(AaiCqResponse.CONTEXT_KEY); - - GenericVnf genvnf = cq.getGenericVnfByModelInvariantId(params.getTarget().getResourceID()); - if (genvnf == null) { - logger.info("{}: target entity could not be found for {}", getFullName(), params.getRequestId()); - throw new IllegalArgumentException("target vnf-id could not be found"); - } - - return makeRequest(attempt, genvnf.getVnfId()); - } - - /** - * Makes a request, given the target VNF. This is a support function for - * {@link #makeRequest(int)}. - * - * @param attempt attempt number - * @param targetVnf target VNF - * @return a new request - */ - protected AppcLcmDmaapWrapper makeRequest(int attempt, String targetVnf) { VirtualControlLoopEvent onset = params.getContext().getEvent(); String subRequestId = UUID.randomUUID().toString(); @@ -118,22 +91,21 @@ public abstract class AppcLcmOperation extends BidirectionalTopicOperation source, AppcLcmInput request) { - String encodedPayloadString = null; + private void convertPayload(Map source, AppcLcmInput request) { try { - encodedPayloadString = coder.encode(source); + String encodedPayloadString = makeCoder().encode(source); request.setPayload(encodedPayloadString); } catch (CoderException e) { - logger.error("Cannot convert payload. Error encoding source as a string.", e); - throw new IllegalArgumentException("Cannot convert payload. Error encoding source as a string."); + throw new IllegalArgumentException("Cannot convert payload", e); } } @@ -187,16 +154,14 @@ public abstract class AppcLcmOperation extends BidirectionalTopicOperation result = - AppcLcmActorServiceProvider.processResponse(dmaapResponse); + AppcLcmActorServiceProvider.processResponse(dmaapResponse); assertEquals(PolicyResult.SUCCESS, result.getKey()); assertEquals("Restart Successful", result.getValue()); } /** - * A test to assert that a null pointer exception is thrown if the APPC response body is null. + * A test to assert that a null pointer exception is thrown if the APPC response body + * is null. */ @Test(expected = NullPointerException.class) public void processNullBodyResponseTest() { @@ -243,7 +244,8 @@ public class AppcLcmActorServiceProviderTest { } /** - * A test to assert that a null pointer exception is thrown if the APPC response output is null. + * A test to assert that a null pointer exception is thrown if the APPC response + * output is null. */ @Test(expected = NullPointerException.class) public void processNullOutputResponseTest() { @@ -364,11 +366,11 @@ public class AppcLcmActorServiceProviderTest { // when AppcLcmDmaapWrapper migrateRequest = - AppcLcmActorServiceProvider.constructRequest(onsetEvent, operation, migratePolicy, VNF01); + AppcLcmActorServiceProvider.constructRequest(onsetEvent, operation, migratePolicy, VNF01); AppcLcmDmaapWrapper rebuildRequest = - AppcLcmActorServiceProvider.constructRequest(onsetEvent, operation, rebuildPolicy, VNF01); + AppcLcmActorServiceProvider.constructRequest(onsetEvent, operation, rebuildPolicy, VNF01); AppcLcmDmaapWrapper restartRequest = - AppcLcmActorServiceProvider.constructRequest(onsetEvent, operation, restartPolicy, VNF01); + AppcLcmActorServiceProvider.constructRequest(onsetEvent, operation, restartPolicy, VNF01); // then assertNull(migrateRequest.getBody().getInput().getPayload()); @@ -384,9 +386,9 @@ public class AppcLcmActorServiceProviderTest { // when AppcLcmDmaapWrapper noPayloadRequest = - AppcLcmActorServiceProvider.constructRequest(onsetEvent, operation, noPayloadPolicy, VNF01); + AppcLcmActorServiceProvider.constructRequest(onsetEvent, operation, noPayloadPolicy, VNF01); AppcLcmDmaapWrapper emptyPayloadRequest = - AppcLcmActorServiceProvider.constructRequest(onsetEvent, operation, emptyPayloadPolicy, VNF01); + AppcLcmActorServiceProvider.constructRequest(onsetEvent, operation, emptyPayloadPolicy, VNF01); // then assertNull(noPayloadRequest.getBody().getInput().getPayload()); @@ -402,11 +404,11 @@ public class AppcLcmActorServiceProviderTest { // when AppcLcmDmaapWrapper dmaapRequest = - AppcLcmActorServiceProvider.constructRequest(onsetEvent, operation, otherPolicy, VNF01); + AppcLcmActorServiceProvider.constructRequest(onsetEvent, operation, otherPolicy, VNF01); // then assertEquals("{\"requestParameters\": {\"host-ip-address\":\"10.183.37.25\"}}", - dmaapRequest.getBody().getInput().getPayload()); + dmaapRequest.getBody().getInput().getPayload()); } @Test @@ -415,18 +417,18 @@ public class AppcLcmActorServiceProviderTest { HashMap payload = new HashMap<>(); payload.put("requestParameters", "{\"host-ip-address\":\"10.183.37.25\"}"); payload.put("configurationParameters", - "[{\"ip-addr\":\"$.vf-module-topology.vf-module-parameters.param[9]\"," - + "\"oam-ip-addr\":\"$.vf-module-topology.vf-module-parameters.param[16]\"," - + "\"enabled\":\"$.vf-module-topology.vf-module-parameters.param[23]\"}]"); + "[{\"ip-addr\":\"$.vf-module-topology.vf-module-parameters.param[9]\"," + + "\"oam-ip-addr\":\"$.vf-module-topology.vf-module-parameters.param[16]\"," + + "\"enabled\":\"$.vf-module-topology.vf-module-parameters.param[23]\"}]"); Policy otherPolicy = constructHealthCheckPolicyWithPayload(payload); // when AppcLcmDmaapWrapper dmaapRequest = - AppcLcmActorServiceProvider.constructRequest(onsetEvent, operation, otherPolicy, VNF01); + AppcLcmActorServiceProvider.constructRequest(onsetEvent, operation, otherPolicy, VNF01); // then - assertEquals(dmaapRequest.getBody().getInput().getPayload(), - "{\"requestParameters\": " + "{\"host-ip-address\":\"10.183.37.25\"}," + "\"configurationParameters\": " + assertEquals(dmaapRequest.getBody().getInput().getPayload(), "{\"requestParameters\": " + + "{\"host-ip-address\":\"10.183.37.25\"}," + "\"configurationParameters\": " + "[{\"ip-addr\":\"$.vf-module-topology.vf-module-parameters.param[9]\"," + "\"oam-ip-addr\":\"$.vf-module-topology.vf-module-parameters.param[16]\"," + "\"enabled\":\"$.vf-module-topology.vf-module-parameters.param[23]\"}]" + "}"); diff --git a/models-interactions/model-actors/actor.appclcm/src/test/java/org/onap/policy/controlloop/actor/appclcm/AppcLcmOperationTest.java b/models-interactions/model-actors/actor.appclcm/src/test/java/org/onap/policy/controlloop/actor/appclcm/AppcLcmOperationTest.java index d2af4e7e2..e94eaecd2 100644 --- a/models-interactions/model-actors/actor.appclcm/src/test/java/org/onap/policy/controlloop/actor/appclcm/AppcLcmOperationTest.java +++ b/models-interactions/model-actors/actor.appclcm/src/test/java/org/onap/policy/controlloop/actor/appclcm/AppcLcmOperationTest.java @@ -1,6 +1,6 @@ /*- * ============LICENSE_START======================================================= - * AppcLcmOperation + * ONAP * ================================================================================ * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved. * ================================================================================ @@ -22,171 +22,291 @@ package org.onap.policy.controlloop.actor.appclcm; 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.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.atLeast; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; -import java.util.List; -import java.util.UUID; +import java.util.Arrays; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Collectors; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; -import org.mockito.Mockito; import org.onap.policy.appclcm.AppcLcmBody; import org.onap.policy.appclcm.AppcLcmCommonHeader; import org.onap.policy.appclcm.AppcLcmDmaapWrapper; -import org.onap.policy.appclcm.AppcLcmInput; import org.onap.policy.appclcm.AppcLcmOutput; import org.onap.policy.appclcm.AppcLcmResponseStatus; -import org.onap.policy.controlloop.VirtualControlLoopEvent; +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.controlloop.ControlLoopOperation; +import org.onap.policy.controlloop.actor.test.BasicBidirectionalTopicOperation; import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome; import org.onap.policy.controlloop.actorserviceprovider.controlloop.ControlLoopEventContext; import org.onap.policy.controlloop.actorserviceprovider.impl.BidirectionalTopicOperation.Status; -import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams; import org.onap.policy.controlloop.policy.PolicyResult; -import org.powermock.reflect.Whitebox; - -public class AppcLcmOperationTest { - private AppcLcmInput mockInput; - private AppcLcmOutput mockOutput; - private AppcLcmBody mockBody; - private AppcLcmDmaapWrapper mockInputWrapper; - private AppcLcmDmaapWrapper mockOutputWrapper; - private OperationOutcome mockOperationOutcome; - private AppcLcmOperation operation; - private AppcLcmResponseStatus mockResponseStatus; - private AppcLcmCommonHeader mockCommonHeader; - private ControlLoopOperationParams mockParams; - private ControlLoopEventContext mockContext; - private VirtualControlLoopEvent mockEvent; +import org.onap.policy.controlloop.policy.Target; + +public class AppcLcmOperationTest extends BasicBidirectionalTopicOperation { + + private static final String EXPECTED_EXCEPTION = "expected exception"; + private static final String PAYLOAD_KEY1 = "key-A"; + private static final String PAYLOAD_VALUE1 = "value-A"; + private static final String MY_MESSAGE = "my-message"; + protected static final String MY_VNF = "my-vnf"; + protected static final String RESOURCE_ID = "my-resource"; + private static final int SUCCESS_CODE = 400; + + private AppcLcmDmaapWrapper response; + private AppcLcmOperation oper; /** - * Setup mocks for testing. + * Sets up. */ @Before - public void setup() { - mockInput = Mockito.mock(AppcLcmInput.class); - mockOutput = Mockito.mock(AppcLcmOutput.class); - mockBody = Mockito.mock(AppcLcmBody.class); - mockContext = Mockito.mock(ControlLoopEventContext.class); - mockEvent = Mockito.mock(VirtualControlLoopEvent.class); - mockInputWrapper = Mockito.mock(AppcLcmDmaapWrapper.class); - mockOutputWrapper = Mockito.mock(AppcLcmDmaapWrapper.class); - mockOperationOutcome = Mockito.mock(OperationOutcome.class); - mockResponseStatus = Mockito.mock(AppcLcmResponseStatus.class); - mockCommonHeader = Mockito.mock(AppcLcmCommonHeader.class); - mockParams = Mockito.mock(ControlLoopOperationParams.class); - operation = Mockito.mock(AppcLcmOperation.class); + public void setUp() { + super.setUpBasic(); + + response = makeResponse(); + + oper = new AppcLcmOperation(params, config); } @Test - public void testStartPreprocessorAsync() { - Mockito.doCallRealMethod().when(operation).startPreprocessorAsync(); - assertNull(operation.startPreprocessorAsync()); + public void testConstructor() { + assertEquals(DEFAULT_ACTOR, oper.getActorName()); + assertEquals(DEFAULT_OPERATION, oper.getName()); + + // missing target entity + params = params.toBuilder().targetEntity("").build(); + assertThatIllegalArgumentException().isThrownBy(() -> new AppcLcmOperation(params, config)) + .withMessage("missing targetEntity"); + } + + @Test + public void testStartPreprocessorAsync() throws Exception { + context = mock(ControlLoopEventContext.class); + when(context.getEvent()).thenReturn(event); + params = params.toBuilder().context(context).build(); + + AtomicBoolean guardStarted = new AtomicBoolean(); + + oper = new AppcLcmOperation(params, config) { + @Override + protected CompletableFuture startGuardAsync() { + guardStarted.set(true); + return super.startGuardAsync(); + } + }; + + CompletableFuture future2 = oper.startPreprocessorAsync(); + assertNotNull(future2); + assertFalse(future.isDone()); + assertTrue(guardStarted.get()); + + assertTrue(executor.runAll(100)); + assertTrue(future2.isDone()); + assertEquals(PolicyResult.SUCCESS, future2.get().getResult()); } - @Ignore @Test public void testMakeRequest() { - UUID randomId = UUID.randomUUID(); - Mockito.doCallRealMethod().when(operation).makeRequest(1, "sampleTargetVnf"); - Mockito.when(mockParams.getRequestId()).thenReturn(randomId); - Mockito.when(mockParams.getPayload()).thenReturn(null); - Mockito.when(mockParams.getContext()).thenReturn(mockContext); - Mockito.when(mockParams.getOperation()).thenReturn("Config-Modify"); - Mockito.when(mockContext.getEvent()).thenReturn(mockEvent); - Mockito.when(mockEvent.getRequestId()).thenReturn(randomId); - Whitebox.setInternalState(operation, "params", mockParams); - assertNotNull(operation.makeRequest(1, "sampleTargetVnf")); - Mockito.verify(mockParams, atLeast(1)).getRequestId(); - Mockito.verify(mockParams, atLeast(1)).getPayload(); - Mockito.verify(mockParams, atLeast(1)).getContext(); - Mockito.verify(mockContext, atLeast(1)).getEvent(); - Mockito.verify(mockEvent, atLeast(1)).getRequestId(); + AppcLcmDmaapWrapper request = oper.makeRequest(2); + assertEquals("DefaultOperation", request.getBody().getInput().getAction()); + + AppcLcmCommonHeader header = request.getBody().getInput().getCommonHeader(); + assertNotNull(header); + assertEquals(params.getRequestId(), header.getRequestId()); + + String subreq = header.getSubRequestId(); + assertNotNull(subreq); + + assertEquals("{vnf-id=my-target}", request.getBody().getInput().getActionIdentifiers().toString()); + + // a subsequent request should have a different sub-request id + assertNotEquals(subreq, oper.makeRequest(2).getBody().getInput().getCommonHeader().getSubRequestId()); + } + + @Test + public void testConvertPayload() { + // only builds a payload for ConfigModify + params = params.toBuilder().operation(AppcLcmConstants.OPERATION_CONFIG_MODIFY).build(); + oper = new AppcLcmOperation(params, config); + + AppcLcmDmaapWrapper req = oper.makeRequest(2); + assertEquals("{\"key-A\":\"value-A\"}", req.getBody().getInput().getPayload()); + + // coder exception + oper = new AppcLcmOperation(params, config) { + @Override + protected Coder makeCoder() { + return new StandardCoder() { + @Override + public String encode(Object object) throws CoderException { + throw new CoderException(EXPECTED_EXCEPTION); + } + }; + } + }; + + assertThatIllegalArgumentException().isThrownBy(() -> oper.makeRequest(2)) + .withMessage("Cannot convert payload"); } @Test public void testGetExpectedKeyValues() { - Mockito.doCallRealMethod().when(operation).getExpectedKeyValues(1, mockInputWrapper); - Mockito.when(mockInputWrapper.getBody()).thenReturn(mockBody); - Mockito.when(mockBody.getInput()).thenReturn(mockInput); - Mockito.when(mockInput.getCommonHeader()).thenReturn(mockCommonHeader); - Mockito.when(mockCommonHeader.getSubRequestId()).thenReturn("sampleSubRequestId"); - - List retList = operation.getExpectedKeyValues(1, mockInputWrapper); - assertNotNull(retList); - assertEquals(1, retList.size()); - - Mockito.verify(mockInputWrapper, atLeast(1)).getBody(); - Mockito.verify(mockBody, atLeast(1)).getInput(); - Mockito.verify(mockInput, atLeast(1)).getCommonHeader(); - Mockito.verify(mockCommonHeader, atLeast(1)).getSubRequestId(); + AppcLcmDmaapWrapper request = oper.makeRequest(2); + assertEquals(Arrays.asList(request.getBody().getInput().getCommonHeader().getSubRequestId()), + oper.getExpectedKeyValues(50, request)); } @Test public void testDetmStatus() { - Mockito.doCallRealMethod().when(operation).detmStatus("testResponse", mockOutputWrapper); - Mockito.when(mockOutputWrapper.getBody()).thenReturn(mockBody); - Mockito.when(mockBody.getOutput()).thenReturn(mockOutput); - Mockito.when(mockOutput.getStatus()).thenReturn(mockResponseStatus); - Mockito.when(mockResponseStatus.getCode()).thenReturn(100); - Status retStatus = operation.detmStatus("testResponse", mockOutputWrapper); - assertEquals(Status.STILL_WAITING, retStatus); - - Mockito.when(mockResponseStatus.getCode()).thenReturn(400); - retStatus = operation.detmStatus("testResponse", mockOutputWrapper); - assertEquals(Status.SUCCESS, retStatus); - - Mockito.when(mockResponseStatus.getCode()).thenReturn(450); - retStatus = operation.detmStatus("testResponse", mockOutputWrapper); - assertEquals(Status.FAILURE, retStatus); - - Mockito.when(mockOutput.getStatus()).thenReturn(null); - assertThatIllegalArgumentException().isThrownBy(() -> operation.detmStatus("testResponse", mockOutputWrapper)); - - Mockito.when(mockResponseStatus.getCode()).thenReturn(200); - assertThatIllegalArgumentException().isThrownBy(() -> operation.detmStatus("testResponse", mockOutputWrapper)); - - Mockito.verify(mockOutputWrapper, atLeast(1)).getBody(); - Mockito.verify(mockBody, atLeast(1)).getOutput(); - Mockito.verify(mockOutput, atLeast(1)).getStatus(); - Mockito.verify(mockResponseStatus, atLeast(1)).getCode(); + assertEquals(Status.SUCCESS, oper.detmStatus(null, response)); + + // failure + response.getBody().getOutput().getStatus().setCode(405); + assertEquals(Status.FAILURE, oper.detmStatus(null, response)); + + // error + response.getBody().getOutput().getStatus().setCode(200); + assertThatIllegalArgumentException().isThrownBy(() -> oper.detmStatus(null, response)); + + // reject + response.getBody().getOutput().getStatus().setCode(305); + assertThatIllegalArgumentException().isThrownBy(() -> oper.detmStatus(null, response)); + + // accepted + response.getBody().getOutput().getStatus().setCode(100); + assertEquals(Status.STILL_WAITING, oper.detmStatus(null, response)); + + // other + response.getBody().getOutput().getStatus().setCode(-1); + assertThatIllegalArgumentException().isThrownBy(() -> oper.detmStatus(null, response)); + + // null status + response.getBody().getOutput().setStatus(null); + assertThatIllegalArgumentException().isThrownBy(() -> oper.detmStatus(null, response)); } @Test public void testSetOutcome() { - Mockito.doCallRealMethod().when(operation).setOutcome(mockOperationOutcome, PolicyResult.SUCCESS, - mockOutputWrapper); - Mockito.doCallRealMethod().when(operation).setOutcome(mockOperationOutcome, PolicyResult.FAILURE, - mockOutputWrapper); - - Mockito.doCallRealMethod().when(mockOperationOutcome).setResult(any(PolicyResult.class)); - Mockito.doCallRealMethod().when(mockOperationOutcome).setMessage(any(String.class)); - Mockito.doCallRealMethod().when(mockOperationOutcome).getResult(); - Mockito.doCallRealMethod().when(mockOperationOutcome).getMessage(); - - Mockito.when(mockOutputWrapper.getBody()).thenReturn(mockBody); - Mockito.when(mockBody.getOutput()).thenReturn(mockOutput); - Mockito.when(mockOutput.getStatus()).thenReturn(mockResponseStatus); - Mockito.when(mockResponseStatus.getMessage()).thenReturn(null); - - OperationOutcome result = operation.setOutcome(mockOperationOutcome, PolicyResult.SUCCESS, mockOutputWrapper); - assertNull(result); - Mockito.verify(operation).setOutcome(mockOperationOutcome, PolicyResult.SUCCESS, mockOutputWrapper); - - Mockito.when(mockOutput.getStatus()).thenReturn(mockResponseStatus); - Mockito.when(mockResponseStatus.getMessage()).thenReturn("sampleMessage"); - result = operation.setOutcome(mockOperationOutcome, PolicyResult.FAILURE, mockOutputWrapper); - assertEquals(PolicyResult.FAILURE, result.getResult()); - assertNotNull(result.getMessage()); - - Mockito.verify(mockOutputWrapper, atLeast(1)).getBody(); - Mockito.verify(mockBody, atLeast(1)).getOutput(); - Mockito.verify(mockOutput, atLeast(1)).getStatus(); - Mockito.verify(mockResponseStatus, atLeast(1)).getMessage(); - Mockito.verify(operation, atLeast(1)).setOutcome(mockOperationOutcome, PolicyResult.SUCCESS, mockOutputWrapper); - Mockito.verify(operation, atLeast(1)).setOutcome(mockOperationOutcome, PolicyResult.FAILURE, mockOutputWrapper); + oper.setOutcome(outcome, PolicyResult.SUCCESS, response); + assertEquals(PolicyResult.SUCCESS, outcome.getResult()); + assertEquals(MY_MESSAGE, outcome.getMessage()); + + // failure + oper.setOutcome(outcome, PolicyResult.FAILURE, response); + assertEquals(PolicyResult.FAILURE, outcome.getResult()); + assertEquals(MY_MESSAGE, outcome.getMessage()); + + // null message + response.getBody().getOutput().getStatus().setMessage(null); + oper.setOutcome(outcome, PolicyResult.SUCCESS, response); + assertEquals(ControlLoopOperation.SUCCESS_MSG, outcome.getMessage()); + + // null status + response.getBody().getOutput().setStatus(null); + oper.setOutcome(outcome, PolicyResult.SUCCESS, response); + assertEquals(ControlLoopOperation.SUCCESS_MSG, outcome.getMessage()); + } + + @Test + public void testGetStatus() { + assertNotNull(oper.getStatus(response)); + + // null status + response.getBody().getOutput().setStatus(null); + assertNull(oper.getStatus(response)); + + // null outcome + response.getBody().setOutput(null); + assertNull(oper.getStatus(response)); + + // null body + response.setBody(null); + assertNull(oper.getStatus(response)); + + // null response + assertNull(oper.getStatus(null)); + } + + @Test + public void testOperationSupportsPayload() { + // these should support a payload + Set supported = Set.of(AppcLcmConstants.OPERATION_CONFIG_MODIFY); + + for (String name : supported) { + params = params.toBuilder().operation(name).build(); + oper = new AppcLcmOperation(params, config); + assertTrue(name, oper.operationSupportsPayload()); + } + + // these should NOT support a payload + Set unsupported = AppcLcmConstants.OPERATION_NAMES.stream().filter(name -> !supported.contains(name)) + .collect(Collectors.toSet()); + + for (String name : unsupported) { + params = params.toBuilder().operation(name).build(); + oper = new AppcLcmOperation(params, config); + assertFalse(name, oper.operationSupportsPayload()); + } + + // pick an operation that would ordinarily support payloads + String sup = supported.iterator().next(); + + // verify that it still supports payload + params = params.toBuilder().operation(sup).build(); + oper = new AppcLcmOperation(params, config); + assertTrue(oper.operationSupportsPayload()); + + // try with empty payload + params = params.toBuilder().payload(Map.of()).build(); + oper = new AppcLcmOperation(params, config); + assertFalse(oper.operationSupportsPayload()); + + // try with null payload + params = params.toBuilder().payload(null).build(); + oper = new AppcLcmOperation(params, config); + assertFalse(oper.operationSupportsPayload()); + } + + @Override + protected void makeContext() { + super.makeContext(); + + Target target = new Target(); + target.setResourceID(RESOURCE_ID); + + params = params.toBuilder().target(target).build(); } + @Override + protected Map makePayload() { + return Map.of(PAYLOAD_KEY1, PAYLOAD_VALUE1); + } + + private AppcLcmDmaapWrapper makeResponse() { + AppcLcmDmaapWrapper response = new AppcLcmDmaapWrapper(); + + AppcLcmBody body = new AppcLcmBody(); + response.setBody(body); + + AppcLcmOutput output = new AppcLcmOutput(); + body.setOutput(output); + + AppcLcmResponseStatus status = new AppcLcmResponseStatus(); + output.setStatus(status); + status.setMessage(MY_MESSAGE); + status.setCode(SUCCESS_CODE); + + return response; + } } diff --git a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/topic/Forwarder.java b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/topic/Forwarder.java index 2d98b66fc..957185e47 100644 --- a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/topic/Forwarder.java +++ b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/topic/Forwarder.java @@ -72,6 +72,8 @@ public class Forwarder { throw new IllegalArgumentException("key/value mismatch"); } + logger.info("register topic listener for key={} value={}", keys, values); + values2listeners.compute(values, (key, listeners) -> { Map, String> map = listeners; if (map == null) { @@ -90,6 +92,8 @@ public class Forwarder { * @param listener listener to unregister */ public void unregister(List values, BiConsumer listener) { + logger.info("unregister topic listener for key={} value={}", keys, values); + values2listeners.computeIfPresent(values, (key, listeners) -> { listeners.remove(listener); return (listeners.isEmpty() ? null : listeners); @@ -112,6 +116,7 @@ public class Forwarder { * No value for this field, so this message is not relevant to this * forwarder. */ + logger.info("message has no key={}", keys); return; } @@ -122,11 +127,13 @@ public class Forwarder { Map, String> listeners = values2listeners.get(values); if (listeners == null) { // no listeners for this particular list of values + logger.info("no listener registered for key={} value={}", keys, values); return; } // forward the message to each listener + logger.info("forwarding message to listeners for key={} value={}", keys, values); for (BiConsumer listener : listeners.keySet()) { try { listener.accept(textMessage, scoMessage); diff --git a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/topic/SelectorKey.java b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/topic/SelectorKey.java index fc5727395..f1ec9e91b 100644 --- a/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/topic/SelectorKey.java +++ b/models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/topic/SelectorKey.java @@ -20,6 +20,7 @@ package org.onap.policy.controlloop.actorserviceprovider.topic; +import java.util.Arrays; import lombok.EqualsAndHashCode; import org.onap.policy.common.utils.coder.StandardCoderObject; @@ -54,4 +55,9 @@ public class SelectorKey { public String extractField(StandardCoderObject object) { return object.getString(fieldIdentifiers); } + + @Override + public String toString() { + return Arrays.toString(fieldIdentifiers); + } } diff --git a/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/topic/SelectorKeyTest.java b/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/topic/SelectorKeyTest.java index 19df9c2d8..5ffcbf7dc 100644 --- a/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/topic/SelectorKeyTest.java +++ b/models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/topic/SelectorKeyTest.java @@ -83,6 +83,11 @@ public class SelectorKeyTest { assertNull(new SelectorKey().extractField(sco)); } + @Test + public void testToString() { + assertEquals("[map, abc]", key.toString()); + } + @Getter @Setter @Builder -- 2.16.6