Make targetEntity a property 84/111384/2
authorJim Hahn <jrh3@att.com>
Tue, 18 Aug 2020 13:39:19 +0000 (09:39 -0400)
committerJim Hahn <jrh3@att.com>
Tue, 18 Aug 2020 21:11:52 +0000 (17:11 -0400)
The target entity is not always known when an Operation is first
constructed, thus it should be treated as an Operation property instead
of being included within the ControlLoopParams.  Started the process of
moving it from the Params to the properties.
Also fixed a bug in custom query - it was setting the outcome response
to the String response instead of setting it to the AaiCqResponse
object.
Also added logging when an Operation's properties are set.

Issue-ID: POLICY-2746
Change-Id: I56c0cd90985f6140363548b0b8d031471b586e88
Signed-off-by: Jim Hahn <jrh3@att.com>
23 files changed:
models-interactions/model-actors/actor.aai/src/main/java/org/onap/policy/controlloop/actor/aai/AaiCustomQueryOperation.java
models-interactions/model-actors/actor.aai/src/main/java/org/onap/policy/controlloop/actor/aai/AaiGetOperation.java
models-interactions/model-actors/actor.aai/src/main/java/org/onap/policy/controlloop/actor/aai/AaiGetPnfOperation.java
models-interactions/model-actors/actor.aai/src/main/java/org/onap/policy/controlloop/actor/aai/AaiGetTenantOperation.java
models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiCustomQueryOperationTest.java
models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiGetPnfOperationTest.java
models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiGetTenantOperationTest.java
models-interactions/model-actors/actor.appc/src/test/java/org/onap/policy/controlloop/actor/appc/ModifyConfigOperationTest.java
models-interactions/model-actors/actor.appclcm/src/main/java/org/onap/policy/controlloop/actor/appclcm/AppcLcmOperation.java
models-interactions/model-actors/actor.appclcm/src/test/java/org/onap/policy/controlloop/actor/appclcm/AppcLcmOperationTest.java
models-interactions/model-actors/actor.cds/src/test/java/org/onap/policy/controlloop/actor/cds/GrpcOperationTest.java
models-interactions/model-actors/actor.guard/src/main/java/org/onap/policy/controlloop/actor/guard/DecisionOperation.java
models-interactions/model-actors/actor.sdnr/src/test/java/org/onap/policy/controlloop/actor/sdnr/SdnrOperationTest.java
models-interactions/model-actors/actor.test/src/main/java/org/onap/policy/controlloop/actor/test/BasicOperation.java
models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/Operation.java
models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/OperationProperties.java
models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/impl/OperationPartial.java
models-interactions/model-actors/actorServiceProvider/src/main/java/org/onap/policy/controlloop/actorserviceprovider/parameters/ControlLoopOperationParams.java
models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/impl/BidirectionalTopicOperationTest.java
models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/impl/HttpOperationTest.java
models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/impl/HttpPollingOperationTest.java
models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/impl/OperationPartialTest.java
models-interactions/model-actors/actorServiceProvider/src/test/java/org/onap/policy/controlloop/actorserviceprovider/parameters/ControlLoopOperationParamsTest.java

index 388959d..5480135 100644 (file)
@@ -40,6 +40,7 @@ import org.onap.policy.controlloop.actorserviceprovider.OperationProperties;
 import org.onap.policy.controlloop.actorserviceprovider.impl.HttpOperation;
 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.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -186,6 +187,19 @@ public class AaiCustomQueryOperation extends HttpOperation<String> {
         return AaiUtil.makeHeaders(params);
     }
 
+    @Override
+    public OperationOutcome setOutcome(OperationOutcome outcome, PolicyResult result, Response rawResponse,
+                    String response) {
+
+        super.setOutcome(outcome, result, rawResponse, response);
+
+        if (response != null) {
+            outcome.setResponse(new AaiCqResponse(response));
+        }
+
+        return outcome;
+    }
+
     /**
      * Injects the response into the context.
      */
index c91e2a0..3fb978d 100644 (file)
@@ -20,7 +20,7 @@
 
 package org.onap.policy.controlloop.actor.aai;
 
-import java.util.Collections;
+import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.concurrent.CompletableFuture;
@@ -29,6 +29,7 @@ import javax.ws.rs.client.WebTarget;
 import javax.ws.rs.core.Response;
 import org.onap.policy.common.utils.coder.StandardCoderObject;
 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
+import org.onap.policy.controlloop.actorserviceprovider.OperationProperties;
 import org.onap.policy.controlloop.actorserviceprovider.impl.HttpOperation;
 import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
 import org.onap.policy.controlloop.actorserviceprovider.parameters.HttpConfig;
@@ -45,6 +46,8 @@ public class AaiGetOperation extends HttpOperation<StandardCoderObject> {
 
     public static final int DEFAULT_RETRY = 3;
 
+    private static final List<String> PROPERTY_NAMES = List.of(OperationProperties.AAI_TARGET_ENTITY);
+
 
     /**
      * Responses that are retrieved from A&AI are placed in the operation context under
@@ -59,7 +62,7 @@ public class AaiGetOperation extends HttpOperation<StandardCoderObject> {
      * @param config configuration for this operation
      */
     public AaiGetOperation(ControlLoopOperationParams params, HttpConfig config) {
-        super(params, config, StandardCoderObject.class, Collections.emptyList());
+        super(params, config, StandardCoderObject.class, PROPERTY_NAMES);
         this.propertyPrefix = getFullName() + ".";
     }
 
@@ -110,9 +113,9 @@ public class AaiGetOperation extends HttpOperation<StandardCoderObject> {
     @Override
     protected CompletableFuture<OperationOutcome> postProcessResponse(OperationOutcome outcome, String url,
                     Response rawResponse, StandardCoderObject response) {
-        String entity = params.getTargetEntity();
 
         if (params.getContext() != null) {
+            String entity = getTargetEntity();
             logger.info("{}: caching response of {} for {}", getFullName(), entity, params.getRequestId());
             params.getContext().setProperty(propertyPrefix + entity, response);
         }
index fbf4096..d89d835 100644 (file)
@@ -74,7 +74,7 @@ public class AaiGetPnfOperation extends AaiGetOperation {
 
         StringBuilder str = new StringBuilder(getClient().getBaseUrl());
 
-        String path = getPath() + URI_SEP + URLEncoder.encode(params.getTargetEntity(), StandardCharsets.UTF_8);
+        String path = getPath() + URI_SEP + URLEncoder.encode(getTargetEntity(), StandardCharsets.UTF_8);
         WebTarget web = getClient().getWebTarget().path(path);
         str.append(path);
 
index cbd1791..fe11798 100644 (file)
@@ -76,7 +76,7 @@ public class AaiGetTenantOperation extends AaiGetOperation {
         str.append(path);
 
         web = addQuery(web, str, "?", "search-node-type", "vserver");
-        web = addQuery(web, str, "&", "filter", "vserver-name:EQUALS:" + params.getTargetEntity());
+        web = addQuery(web, str, "&", "filter", "vserver-name:EQUALS:" + getTargetEntity());
 
         Builder webldr = web.request();
         addHeaders(webldr, headers);
index f122537..8e8b8f1 100644 (file)
@@ -21,7 +21,6 @@
 package org.onap.policy.controlloop.actor.aai;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatCode;
 import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
 import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
 import static org.junit.Assert.assertEquals;
@@ -114,27 +113,22 @@ public class AaiCustomQueryOperationTest extends BasicAaiOperation {
         HttpParams opParams = HttpParams.builder().clientName(MY_CLIENT).path("v16/query").build();
         config = new HttpConfig(blockingExecutor, opParams, HttpClientFactoryInstance.getClientFactory());
 
-        params = params.toBuilder().targetEntity(SIM_VSERVER).retry(0).timeoutSec(5).executor(blockingExecutor)
-                        .preprocessed(true).build();
+        params = params.toBuilder().retry(0).timeoutSec(5).executor(blockingExecutor).preprocessed(true).build();
         oper = new AaiCustomQueryOperation(params, config);
+        oper.setProperty(OperationProperties.AAI_TARGET_ENTITY, SIM_VSERVER);
 
         oper.setProperty(OperationProperties.AAI_VSERVER_LINK, MY_LINK);
 
         outcome = oper.start().get();
         assertEquals(PolicyResult.SUCCESS, outcome.getResult());
 
-        String resp = outcome.getResponse();
-        assertThat(resp).isNotNull().contains("relationship-list");
+        assertNotNull(outcome.getResponse());
     }
 
     @Test
     public void testConstructor() {
         assertEquals(AaiConstants.ACTOR_NAME, oper.getActorName());
         assertEquals(AaiCustomQueryOperation.NAME, oper.getName());
-
-        // verify that it works with an empty target entity
-        params = params.toBuilder().targetEntity("").build();
-        assertThatCode(() -> new AaiCustomQueryOperation(params, config)).doesNotThrowAnyException();
     }
 
     @Test
@@ -263,6 +257,15 @@ public class AaiCustomQueryOperationTest extends BasicAaiOperation {
                         .withMessage("cannot perform custom query - no resource-link");
     }
 
+    @Test
+    public void testSetOutcome() {
+        outcome = oper.setOutcome(params.makeOutcome(null), PolicyResult.SUCCESS, null, null);
+        assertNull(outcome.getResponse());
+
+        outcome = oper.setOutcome(params.makeOutcome(null), PolicyResult.SUCCESS, null, "{}");
+        assertTrue(outcome.getResponse() instanceof AaiCqResponse);
+    }
+
     private String makeTenantReply() throws Exception {
         Map<String, String> links = Map.of(AaiCustomQueryOperation.RESOURCE_LINK, MY_LINK);
         List<Map<String, String>> data = Arrays.asList(links);
index b211db2..13b5b59 100644 (file)
@@ -29,6 +29,7 @@ import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.when;
 
+import java.util.List;
 import java.util.Map;
 import java.util.concurrent.CompletableFuture;
 import javax.ws.rs.client.InvocationCallback;
@@ -41,6 +42,7 @@ import org.onap.policy.common.endpoints.http.client.HttpClientFactoryInstance;
 import org.onap.policy.common.utils.coder.StandardCoder;
 import org.onap.policy.common.utils.coder.StandardCoderObject;
 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
+import org.onap.policy.controlloop.actorserviceprovider.OperationProperties;
 import org.onap.policy.controlloop.actorserviceprovider.parameters.HttpConfig;
 import org.onap.policy.controlloop.actorserviceprovider.parameters.HttpParams;
 import org.onap.policy.controlloop.policy.PolicyResult;
@@ -82,7 +84,7 @@ public class AaiGetPnfOperationTest extends BasicAaiOperation {
 
     @Test
     public void testGetPropertyNames() {
-        assertThat(oper.getPropertyNames()).isEmpty();
+        assertThat(oper.getPropertyNames()).isEqualTo(List.of(OperationProperties.AAI_TARGET_ENTITY));
     }
 
     /**
@@ -93,8 +95,9 @@ public class AaiGetPnfOperationTest extends BasicAaiOperation {
         HttpParams opParams = HttpParams.builder().clientName(MY_CLIENT).path("v16/network/pnfs/pnf").build();
         config = new HttpConfig(blockingExecutor, opParams, HttpClientFactoryInstance.getClientFactory());
 
-        params = params.toBuilder().targetEntity("OzVServer").retry(0).timeoutSec(5).executor(blockingExecutor).build();
+        params = params.toBuilder().retry(0).timeoutSec(5).executor(blockingExecutor).build();
         oper = new AaiGetPnfOperation(params, config);
+        oper.setProperty(OperationProperties.AAI_TARGET_ENTITY, "OzVServer");
 
         outcome = oper.start().get();
         assertEquals(PolicyResult.SUCCESS, outcome.getResult());
@@ -109,8 +112,9 @@ public class AaiGetPnfOperationTest extends BasicAaiOperation {
         HttpParams opParams = HttpParams.builder().clientName(MY_CLIENT).path("v16/network/pnfs/pnf").build();
         config = new HttpConfig(blockingExecutor, opParams, HttpClientFactoryInstance.getClientFactory());
 
-        params = params.toBuilder().targetEntity("getFail").retry(0).timeoutSec(5).executor(blockingExecutor).build();
+        params = params.toBuilder().retry(0).timeoutSec(5).executor(blockingExecutor).build();
         oper = new AaiGetPnfOperation(params, config);
+        oper.setProperty(OperationProperties.AAI_TARGET_ENTITY, "getFail");
 
         outcome = oper.start().get();
         assertEquals(PolicyResult.FAILURE, outcome.getResult());
index fe0327c..11604cd 100644 (file)
@@ -29,6 +29,7 @@ import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.when;
 
+import java.util.List;
 import java.util.Map;
 import java.util.concurrent.CompletableFuture;
 import javax.ws.rs.client.InvocationCallback;
@@ -41,6 +42,7 @@ import org.onap.policy.common.endpoints.http.client.HttpClientFactoryInstance;
 import org.onap.policy.common.utils.coder.StandardCoder;
 import org.onap.policy.common.utils.coder.StandardCoderObject;
 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
+import org.onap.policy.controlloop.actorserviceprovider.OperationProperties;
 import org.onap.policy.controlloop.actorserviceprovider.parameters.HttpConfig;
 import org.onap.policy.controlloop.actorserviceprovider.parameters.HttpParams;
 import org.onap.policy.controlloop.policy.PolicyResult;
@@ -82,7 +84,7 @@ public class AaiGetTenantOperationTest extends BasicAaiOperation {
 
     @Test
     public void testGetPropertyNames() {
-        assertThat(oper.getPropertyNames()).isEmpty();
+        assertThat(oper.getPropertyNames()).isEqualTo(List.of(OperationProperties.AAI_TARGET_ENTITY));
     }
 
     /**
@@ -93,8 +95,9 @@ public class AaiGetTenantOperationTest extends BasicAaiOperation {
         HttpParams opParams = HttpParams.builder().clientName(MY_CLIENT).path("v16/search/nodes-query").build();
         config = new HttpConfig(blockingExecutor, opParams, HttpClientFactoryInstance.getClientFactory());
 
-        params = params.toBuilder().targetEntity("OzVServer").retry(0).timeoutSec(5).executor(blockingExecutor).build();
+        params = params.toBuilder().retry(0).timeoutSec(5).executor(blockingExecutor).build();
         oper = new AaiGetTenantOperation(params, config);
+        oper.setProperty(OperationProperties.AAI_TARGET_ENTITY, "OzVServer");
 
         outcome = oper.start().get();
         assertEquals(PolicyResult.SUCCESS, outcome.getResult());
@@ -109,9 +112,9 @@ public class AaiGetTenantOperationTest extends BasicAaiOperation {
         HttpParams opParams = HttpParams.builder().clientName(MY_CLIENT).path("v16/search/nodes-query").build();
         config = new HttpConfig(blockingExecutor, opParams, HttpClientFactoryInstance.getClientFactory());
 
-        params = params.toBuilder().targetEntity("failedVserver").retry(0).timeoutSec(5).executor(blockingExecutor)
-                        .build();
+        params = params.toBuilder().retry(0).timeoutSec(5).executor(blockingExecutor).build();
         oper = new AaiGetTenantOperation(params, config);
+        oper.setProperty(OperationProperties.AAI_TARGET_ENTITY, "failedVserver");
 
         outcome = oper.start().get();
         assertEquals(PolicyResult.FAILURE, outcome.getResult());
index 3b63514..2177dfa 100644 (file)
@@ -159,7 +159,7 @@ public class ModifyConfigOperationTest extends BasicAppcOperation {
         assertTrue(guardStarted.get());
         verify(context).obtain(eq(AaiCqResponse.CONTEXT_KEY), any());
 
-        future2.complete(params.makeOutcome());
+        future2.complete(params.makeOutcome(null));
         assertTrue(executor.runAll(100));
         assertTrue(future3.isDone());
         assertEquals(PolicyResult.SUCCESS, future3.get().getResult());
index 590bf19..dc74825 100644 (file)
 
 package org.onap.policy.controlloop.actor.appclcm;
 
-import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.CompletableFuture;
-import org.apache.commons.lang3.StringUtils;
 import org.onap.policy.appclcm.AppcLcmBody;
 import org.onap.policy.appclcm.AppcLcmCommonHeader;
 import org.onap.policy.appclcm.AppcLcmDmaapWrapper;
@@ -34,6 +32,7 @@ import org.onap.policy.appclcm.AppcLcmResponseCode;
 import org.onap.policy.appclcm.AppcLcmResponseStatus;
 import org.onap.policy.common.utils.coder.CoderException;
 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
+import org.onap.policy.controlloop.actorserviceprovider.OperationProperties;
 import org.onap.policy.controlloop.actorserviceprovider.impl.BidirectionalTopicOperation;
 import org.onap.policy.controlloop.actorserviceprovider.parameters.BidirectionalTopicConfig;
 import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
@@ -45,6 +44,8 @@ public class AppcLcmOperation extends BidirectionalTopicOperation<AppcLcmDmaapWr
     private static final String MISSING_STATUS = "APPC-LCM response is missing the response status";
     public static final String VNF_ID_KEY = "vnf-id";
 
+    private static final List<String> PROPERTY_NAMES = List.of(OperationProperties.AAI_TARGET_ENTITY);
+
     /**
      * 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.
@@ -62,11 +63,7 @@ public class AppcLcmOperation extends BidirectionalTopicOperation<AppcLcmDmaapWr
      * @param config configuration for this operation
      */
     public AppcLcmOperation(ControlLoopOperationParams params, BidirectionalTopicConfig config) {
-        super(params, config, AppcLcmDmaapWrapper.class, Collections.emptyList());
-
-        if (StringUtils.isBlank(params.getTargetEntity())) {
-            throw new IllegalArgumentException("missing targetEntity");
-        }
+        super(params, config, AppcLcmDmaapWrapper.class, PROPERTY_NAMES);
     }
 
     /**
@@ -97,7 +94,7 @@ public class AppcLcmOperation extends BidirectionalTopicOperation<AppcLcmDmaapWr
          * Action Identifiers are required for APPC LCM requests. For R1, the recipes
          * supported by Policy only require a vnf-id.
          */
-        inputRequest.setActionIdentifiers(Map.of(VNF_ID_KEY, params.getTargetEntity()));
+        inputRequest.setActionIdentifiers(Map.of(VNF_ID_KEY, getTargetEntity()));
 
         /*
          * For R1, the payloads will not be required for the Restart, Rebuild, or Migrate
index 705fd10..f3b3cc2 100644 (file)
@@ -32,6 +32,7 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 import java.util.Arrays;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.CompletableFuture;
@@ -55,6 +56,7 @@ 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.OperationProperties;
 import org.onap.policy.controlloop.actorserviceprovider.controlloop.ControlLoopEventContext;
 import org.onap.policy.controlloop.actorserviceprovider.impl.BidirectionalTopicOperation.Status;
 import org.onap.policy.controlloop.actorserviceprovider.parameters.BidirectionalTopicConfig;
@@ -135,16 +137,11 @@ public class AppcLcmOperationTest extends BasicBidirectionalTopicOperation<AppcL
     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 testGetPropertyNames() {
-        assertThat(oper.getPropertyNames()).isEmpty();
+        assertThat(oper.getPropertyNames()).isEqualTo(List.of(OperationProperties.AAI_TARGET_ENTITY));
     }
 
     @Test
index 2e9935f..5123495 100644 (file)
@@ -151,9 +151,9 @@ public class GrpcOperationTest {
         when(context.obtain(eq(AaiCqResponse.CONTEXT_KEY), any())).thenReturn(cqFuture);
         when(context.getEvent()).thenReturn(onset);
 
-        params = ControlLoopOperationParams.builder().actor(CdsActorConstants.CDS_ACTOR)
-                        .operation(GrpcOperation.NAME).context(context).actorService(new ActorService())
-                        .targetEntity(TARGET_ENTITY).target(target).build();
+        params = ControlLoopOperationParams.builder().actor(CdsActorConstants.CDS_ACTOR).operation(GrpcOperation.NAME)
+                        .context(context).actorService(new ActorService()).targetEntity(TARGET_ENTITY).target(target)
+                        .build();
     }
 
     /**
@@ -166,10 +166,9 @@ public class GrpcOperationTest {
 
         Map<String, Object> payload = Map.of("artifact_name", "my_artifact", "artifact_version", "1.0");
 
-        params = ControlLoopOperationParams.builder()
-                        .actor(CdsActorConstants.CDS_ACTOR).operation("subscribe").context(context)
-                        .actorService(new ActorService()).targetEntity(TARGET_ENTITY).target(target).retry(0)
-                        .timeoutSec(5).executor(blockingExecutor).payload(payload).build();
+        params = ControlLoopOperationParams.builder().actor(CdsActorConstants.CDS_ACTOR).operation("subscribe")
+                        .context(context).actorService(new ActorService()).targetEntity(TARGET_ENTITY).target(target)
+                        .retry(0).timeoutSec(5).executor(blockingExecutor).payload(payload).build();
 
         cdsProps.setHost("localhost");
         cdsProps.setPort(sim.getPort());
@@ -181,7 +180,7 @@ public class GrpcOperationTest {
             @Override
             protected CompletableFuture<OperationOutcome> startGuardAsync() {
                 // indicate that guard completed successfully
-                return CompletableFuture.completedFuture(params.makeOutcome());
+                return CompletableFuture.completedFuture(params.makeOutcome(null));
             }
         };
 
@@ -200,10 +199,9 @@ public class GrpcOperationTest {
 
         Map<String, Object> payload = Map.of("artifact_name", "my_artifact", "artifact_version", "1.0");
 
-        params = ControlLoopOperationParams.builder()
-                        .actor(CdsActorConstants.CDS_ACTOR).operation("subscribe").context(context)
-                        .actorService(new ActorService()).targetEntity(TARGET_ENTITY).target(target).retry(0)
-                        .timeoutSec(5).executor(blockingExecutor).payload(payload).preprocessed(true).build();
+        params = ControlLoopOperationParams.builder().actor(CdsActorConstants.CDS_ACTOR).operation("subscribe")
+                        .context(context).actorService(new ActorService()).targetEntity(TARGET_ENTITY).target(target)
+                        .retry(0).timeoutSec(5).executor(blockingExecutor).payload(payload).preprocessed(true).build();
 
         cdsProps.setHost("localhost");
         cdsProps.setPort(sim.getPort());
@@ -260,8 +258,7 @@ public class GrpcOperationTest {
         operation = new GrpcOperation(params, config);
 
         // in neither property nor context
-        assertThatIllegalArgumentException().isThrownBy(() -> operation.getPnfData())
-                        .withMessage("missing PNF data");
+        assertThatIllegalArgumentException().isThrownBy(() -> operation.getPnfData()).withMessage("missing PNF data");
 
         // only in context
         Pnf pnf = new Pnf();
@@ -335,7 +332,7 @@ public class GrpcOperationTest {
         assertTrue(guardStarted.get());
         verify(context).obtain(eq(AaiCqResponse.CONTEXT_KEY), any());
 
-        cqFuture.complete(params.makeOutcome());
+        cqFuture.complete(params.makeOutcome(null));
         assertTrue(executor.runAll(100));
         assertEquals(PolicyResult.SUCCESS, future3.get(2, TimeUnit.SECONDS).getResult());
         assertTrue(future3.isDone());
@@ -363,7 +360,7 @@ public class GrpcOperationTest {
         assertTrue(guardStarted.get());
         verify(context).obtain(eq(AaiGetPnfOperation.getKey(TARGET_ENTITY)), any());
 
-        cqFuture.complete(params.makeOutcome());
+        cqFuture.complete(params.makeOutcome(null));
         assertTrue(executor.runAll(100));
         assertEquals(PolicyResult.SUCCESS, future3.get(2, TimeUnit.SECONDS).getResult());
         assertTrue(future3.isDone());
@@ -415,7 +412,8 @@ public class GrpcOperationTest {
     @Test
     public void testStartOperationAsyncError() throws Exception {
         operation = new GrpcOperation(params, config);
-        assertThatIllegalArgumentException().isThrownBy(() -> operation.startOperationAsync(1, params.makeOutcome()));
+        assertThatIllegalArgumentException()
+                        .isThrownBy(() -> operation.startOperationAsync(1, params.makeOutcome(null)));
     }
 
     @Test
@@ -457,7 +455,7 @@ public class GrpcOperationTest {
         assertEquals(1000, operation.getTimeoutMs(0));
         assertEquals(2000, operation.getTimeoutMs(2));
         operation.generateSubRequestId(1);
-        CompletableFuture<OperationOutcome> future3 = operation.startOperationAsync(1, params.makeOutcome());
+        CompletableFuture<OperationOutcome> future3 = operation.startOperationAsync(1, params.makeOutcome(null));
         assertNotNull(future3);
     }
 
index bd4f0e3..032a0c1 100644 (file)
@@ -99,7 +99,7 @@ public class DecisionOperation extends HttpOperation<DecisionResponse> {
         final Executor executor = params.getExecutor();
         final CallbackManager callbacks = new CallbackManager();
 
-        return CompletableFuture.completedFuture(params.makeOutcome())
+        return CompletableFuture.completedFuture(params.makeOutcome(getTargetEntity()))
                         .whenCompleteAsync(callbackStarted(callbacks), executor)
                         .whenCompleteAsync(callbackCompleted(callbacks), executor);
     }
index abce210..7537fa2 100644 (file)
@@ -168,7 +168,7 @@ public class SdnrOperationTest extends BasicSdnrOperation {
         assertFalse(future.isDone());
         assertTrue(guardStarted.get());
 
-        future2.complete(params.makeOutcome());
+        future2.complete(params.makeOutcome(null));
         assertTrue(executor.runAll(100));
         assertTrue(future3.isDone());
         assertEquals(PolicyResult.SUCCESS, future3.get().getResult());
index c0ea447..a0bb58e 100644 (file)
@@ -136,7 +136,7 @@ public class BasicOperation {
         when(guardActor.getOperator(OperationPartial.GUARD_OPERATION_NAME)).thenReturn(guardOperator);
         when(guardOperator.buildOperation(any())).thenReturn(guardOperation);
 
-        outcome = params.makeOutcome();
+        outcome = params.makeOutcome(TARGET_ENTITY);
         outcome.setResult(PolicyResult.SUCCESS);
         when(guardOperation.start()).thenReturn(CompletableFuture.completedFuture(outcome));
 
@@ -147,7 +147,7 @@ public class BasicOperation {
         when(cqOperation.start()).thenReturn(cqFuture);
 
         // get a fresh outcome
-        outcome = params.makeOutcome();
+        outcome = params.makeOutcome(TARGET_ENTITY);
     }
 
     /**
@@ -226,7 +226,7 @@ public class BasicOperation {
      */
     protected void provideCqResponse(AaiCqResponse cq) {
         context.setProperty(AaiCqResponse.CONTEXT_KEY, cq);
-        OperationOutcome outcome2 = params.makeOutcome();
+        OperationOutcome outcome2 = params.makeOutcome(TARGET_ENTITY);
         outcome2.setResult(PolicyResult.SUCCESS);
         cqFuture.complete(outcome2);
     }
index dfa0865..2c63e98 100644 (file)
@@ -50,6 +50,15 @@ public interface Operation {
      */
     List<String> getPropertyNames();
 
+    /**
+     * Determines if a property has been assigned for the operation.
+     *
+     * @param name property name
+     * @return {@code true} if the given property has been assigned for the operation,
+     *         {@code false} otherwise
+     */
+    public boolean containsProperty(String name);
+
     /**
      * Sets a property.
      *
@@ -58,6 +67,14 @@ public interface Operation {
      */
     public void setProperty(String name, Object value);
 
+    /**
+     * Gets a property's value.
+     *
+     * @param name name of the property of interest
+     * @return the property's value, or {@code null} if it has no value
+     */
+    public <T> T getProperty(String name);
+
     /**
      * Called by enforcement PDP engine to start the operation. As part of the operation,
      * it invokes the "start" and "complete" call-backs found within the parameters.
index c36b61e..718daed 100644 (file)
@@ -23,6 +23,9 @@ package org.onap.policy.controlloop.actorserviceprovider;
 /**
  * Names of properties needed by the Actors defined within this repo. Note: this is not
  * exhaustive, as additional property names may be returned by company-defined Actors.
+ * <p/>
+ * Note: any time a property is added, applications using the actors must be updated to
+ * provide the property's value when requested.
  */
 public class OperationProperties {
 
@@ -42,6 +45,23 @@ public class OperationProperties {
      */
     public static final String AAI_DEFAULT_TENANT = "AAI/defaultTenant";
 
+    /**
+     * A&AI PNF. Obtained as follows:
+     * <ol>
+     * <li>using the target entity, invoke AaiGetPnfOperation</li>
+     * </ol>
+     */
+    public static final String AAI_PNF = "AAI/pnf";
+
+    /**
+     * A&AI VNF id for the target resource ID. Obtained as follows:
+     * <ol>
+     * <li>using the target resource ID, invoke the custom query
+     * getGenericVnfByModelInvariantId() method to get the generic VNF</li>
+     * </ol>
+     */
+    public static final String AAI_RESOURCE_VNF = "AAI/resourceId/vnf";
+
     /**
      * A&AI Service instance. Obtained as follows:
      * <ol>
@@ -59,6 +79,13 @@ public class OperationProperties {
      */
     public static final String AAI_SERVICE_MODEL = "AAI/service/model";
 
+    /**
+     * A&AI Target Entity. This is a String that can typically be found in the enrichment
+     * data, depending on the Target type. Sometimes, however, it must be retrieved via an
+     * A&AI query.
+     */
+    public static final String AAI_TARGET_ENTITY = "AAI/targetEntity";
+
     /**
      * A&AI VNF. Obtained as follows:
      * <ol>
@@ -82,23 +109,6 @@ public class OperationProperties {
      */
     public static final String AAI_VNF_MODEL = "AAI/vnf/model";
 
-    /**
-     * A&AI VNF id for the target resource ID. Obtained as follows:
-     * <ol>
-     * <li>using the target resource ID, invoke the custom query
-     * getGenericVnfByModelInvariantId() method to get the generic VNF</li>
-     * </ol>
-     */
-    public static final String AAI_RESOURCE_VNF = "AAI/resourceId/vnf";
-
-    /**
-     * A&AI PNF. Obtained as follows:
-     * <ol>
-     * <li>using the target entity, invoke AaiGetPnfOperation</li>
-     * </ol>
-     */
-    public static final String AAI_PNF = "AAI/pnf";
-
     /**
      * A&AI link to the vserver. Obtained as follows:
      * <ol>
index 0aa1122..b5cc15e 100644 (file)
@@ -53,6 +53,7 @@ import org.onap.policy.controlloop.ControlLoopOperation;
 import org.onap.policy.controlloop.actorserviceprovider.CallbackManager;
 import org.onap.policy.controlloop.actorserviceprovider.Operation;
 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
+import org.onap.policy.controlloop.actorserviceprovider.OperationProperties;
 import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
 import org.onap.policy.controlloop.actorserviceprovider.parameters.OperatorConfig;
 import org.onap.policy.controlloop.actorserviceprovider.pipeline.PipelineControllerFuture;
@@ -139,34 +140,19 @@ public abstract class OperationPartial implements Operation {
         return params.getOperation();
     }
 
-    /**
-     * Determines if a property has been assigned for the operation.
-     *
-     * @param name property name
-     * @return {@code true} if the given property has been assigned for the operation,
-     *         {@code false} otherwise
-     */
+    @Override
     public boolean containsProperty(String name) {
         return properties.containsKey(name);
     }
 
-    /**
-     * Sets a property.
-     *
-     * @param name property name
-     * @param value new value
-     */
+    @Override
     public void setProperty(String name, Object value) {
+        logger.info("{}: set property {}={}", getFullName(), name, value);
         properties.put(name, value);
     }
 
-    /**
-     * Gets a property's value.
-     *
-     * @param name name of the property of interest
-     * @return the property's value, or {@code null} if it has no value
-     */
     @SuppressWarnings("unchecked")
+    @Override
     public <T> T getProperty(String name) {
         return (T) properties.get(name);
     }
@@ -230,7 +216,7 @@ public abstract class OperationPartial implements Operation {
             // propagate "stop" to the callbacks
             controller.add(callbacks);
 
-            final OperationOutcome outcome2 = params.makeOutcome();
+            final OperationOutcome outcome2 = params.makeOutcome(getTargetEntity());
 
             // TODO need a FAILURE_MISSING_DATA (e.g., A&AI)
 
@@ -304,7 +290,7 @@ public abstract class OperationPartial implements Operation {
         Map<String, Object> guard = new LinkedHashMap<>();
         guard.put("actor", params.getActor());
         guard.put("operation", params.getOperation());
-        guard.put("target", params.getTargetEntity());
+        guard.put("target", getTargetEntity());
         guard.put("requestId", params.getRequestId());
 
         String clname = params.getContext().getEvent().getClosedLoopControlName();
@@ -358,7 +344,7 @@ public abstract class OperationPartial implements Operation {
         logger.info("{}: start operation attempt {} for {}", getFullName(), attempt, params.getRequestId());
 
         final Executor executor = params.getExecutor();
-        final OperationOutcome outcome = params.makeOutcome();
+        final OperationOutcome outcome = params.makeOutcome(getTargetEntity());
         final CallbackManager callbacks = new CallbackManager();
 
         // this operation attempt gets its own controller
@@ -489,7 +475,7 @@ public abstract class OperationPartial implements Operation {
                 outcome = origOutcome;
             } else {
                 logger.warn("{}: null outcome; treating as a failure for {}", getFullName(), params.getRequestId());
-                outcome = this.setOutcome(params.makeOutcome(), PolicyResult.FAILURE);
+                outcome = this.setOutcome(params.makeOutcome(getTargetEntity()), PolicyResult.FAILURE);
             }
 
             // ensure correct actor/operation
@@ -588,7 +574,7 @@ public abstract class OperationPartial implements Operation {
     private Function<Throwable, OperationOutcome> fromException(String type) {
 
         return thrown -> {
-            OperationOutcome outcome = params.makeOutcome();
+            OperationOutcome outcome = params.makeOutcome(getTargetEntity());
 
             if (thrown instanceof CancellationException || thrown.getCause() instanceof CancellationException) {
                 // do not include exception in the message, as it just clutters the log
@@ -1106,6 +1092,16 @@ public abstract class OperationPartial implements Operation {
         return DEFAULT_RETRY_WAIT_MS;
     }
 
+    /**
+     * Gets the target entity, first trying the properties and then the parameters.
+     *
+     * @return the target entity
+     */
+    protected String getTargetEntity() {
+        String targetEntity = getProperty(OperationProperties.AAI_TARGET_ENTITY);
+        return (targetEntity != null ? targetEntity : params.getTargetEntity());
+    }
+
     /**
      * Gets the operation timeout.
      *
index d0b7c26..66573f3 100644 (file)
@@ -69,6 +69,7 @@ public class ControlLoopOperationParams {
     /**
      * Event for which the operation applies.
      */
+    // TODO to be removed
     private ControlLoopEventContext context;
 
     /**
@@ -106,15 +107,15 @@ public class ControlLoopOperationParams {
     private Integer retry;
 
     /**
-     * The entity's target information. May be {@code null}, depending on the requirement
-     * of the operation to be invoked.
+     * The Target information, extracted from the Policy. May be {@code null}, depending
+     * on the requirement of the operation to be invoked.
      */
     private Target target;
 
     /**
      * Target entity.
      */
-    @NotNull
+    // TODO to be removed
     private String targetEntity;
 
     /**
@@ -193,7 +194,19 @@ public class ControlLoopOperationParams {
      *
      * @return a new operation outcome
      */
+    // TODO to be removed
     public OperationOutcome makeOutcome() {
+        return makeOutcome(getTargetEntity());
+    }
+
+    /**
+     * Makes an operation outcome, populating it from the parameters.
+     *
+     * @param targetEntity the target entity
+     *
+     * @return a new operation outcome
+     */
+    public OperationOutcome makeOutcome(String targetEntity) {
         OperationOutcome outcome = new OperationOutcome();
         outcome.setActor(getActor());
         outcome.setOperation(getOperation());
index e28ddeb..f63e07e 100644 (file)
@@ -110,7 +110,7 @@ public class BidirectionalTopicOperationTest {
         executor = new PseudoExecutor();
 
         params = ControlLoopOperationParams.builder().actor(ACTOR).operation(OPERATION).executor(executor).build();
-        outcome = params.makeOutcome();
+        outcome = params.makeOutcome(null);
 
         response = new MyResponse();
         response.setRequestId(REQ_ID);
index 33e5303..daabaa2 100644 (file)
@@ -190,7 +190,7 @@ public class HttpOperationTest {
         context = new ControlLoopEventContext(event);
         params = ControlLoopOperationParams.builder().actor(ACTOR).operation(OPERATION).context(context).build();
 
-        outcome = params.makeOutcome();
+        outcome = params.makeOutcome(null);
 
         callback = new AtomicReference<>();
         future = new CompletableFuture<>();
index 7809646..ede2b79 100644 (file)
@@ -100,7 +100,7 @@ public class HttpPollingOperationTest {
         when(rawResponse.readEntity(String.class)).thenReturn(response);
 
         params = ControlLoopOperationParams.builder().actor(MY_ACTOR).operation(MY_OPERATION).build();
-        outcome = params.makeOutcome();
+        outcome = params.makeOutcome(null);
 
         oper = new MyOper(params, config);
     }
index 6d54358..6db824f 100644 (file)
@@ -75,6 +75,7 @@ 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.OperationProperties;
 import org.onap.policy.controlloop.actorserviceprovider.Operator;
 import org.onap.policy.controlloop.actorserviceprovider.controlloop.ControlLoopEventContext;
 import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
@@ -399,7 +400,7 @@ public class OperationPartialTest {
     public void testIsActorFailed() {
         assertFalse(oper.isActorFailed(null));
 
-        OperationOutcome outcome = params.makeOutcome();
+        OperationOutcome outcome = params.makeOutcome(null);
 
         // incorrect outcome
         outcome.setResult(PolicyResult.SUCCESS);
@@ -459,7 +460,7 @@ public class OperationPartialTest {
             @Override
             protected CompletableFuture<OperationOutcome> startOperationAsync(int attempt, OperationOutcome outcome) {
 
-                OperationOutcome outcome2 = params.makeOutcome();
+                OperationOutcome outcome2 = params.makeOutcome(null);
                 outcome2.setResult(PolicyResult.SUCCESS);
 
                 /*
@@ -596,7 +597,7 @@ public class OperationPartialTest {
     public void testIsSameOperation() {
         assertFalse(oper.isSameOperation(null));
 
-        OperationOutcome outcome = params.makeOutcome();
+        OperationOutcome outcome = params.makeOutcome(null);
 
         // wrong actor - should be false
         outcome.setActor(null);
@@ -667,7 +668,7 @@ public class OperationPartialTest {
         // first task completes, others do not
         List<Supplier<CompletableFuture<OperationOutcome>>> tasks = new LinkedList<>();
 
-        final OperationOutcome outcome = params.makeOutcome();
+        final OperationOutcome outcome = params.makeOutcome(null);
 
         tasks.add(() -> CompletableFuture.completedFuture(outcome));
         tasks.add(() -> new CompletableFuture<>());
@@ -732,7 +733,7 @@ public class OperationPartialTest {
 
     @Test
     public void testAllOfArray() throws Exception {
-        final OperationOutcome outcome = params.makeOutcome();
+        final OperationOutcome outcome = params.makeOutcome(null);
 
         CompletableFuture<OperationOutcome> future1 = new CompletableFuture<>();
         CompletableFuture<OperationOutcome> future2 = new CompletableFuture<>();
@@ -763,7 +764,7 @@ public class OperationPartialTest {
 
     @Test
     public void testAllOfList() throws Exception {
-        final OperationOutcome outcome = params.makeOutcome();
+        final OperationOutcome outcome = params.makeOutcome(null);
 
         CompletableFuture<OperationOutcome> future1 = new CompletableFuture<>();
         CompletableFuture<OperationOutcome> future2 = new CompletableFuture<>();
@@ -852,9 +853,9 @@ public class OperationPartialTest {
 
         // null outcome - takes precedence over a success
         List<Supplier<CompletableFuture<OperationOutcome>>> tasks = new LinkedList<>();
-        tasks.add(() -> CompletableFuture.completedFuture(params.makeOutcome()));
+        tasks.add(() -> CompletableFuture.completedFuture(params.makeOutcome(null)));
         tasks.add(() -> CompletableFuture.completedFuture(null));
-        tasks.add(() -> CompletableFuture.completedFuture(params.makeOutcome()));
+        tasks.add(() -> CompletableFuture.completedFuture(params.makeOutcome(null)));
         CompletableFuture<OperationOutcome> result = oper.allOf(tasks);
 
         assertTrue(executor.runAll(MAX_REQUESTS));
@@ -865,9 +866,9 @@ public class OperationPartialTest {
         IllegalStateException except = new IllegalStateException(EXPECTED_EXCEPTION);
 
         tasks.clear();
-        tasks.add(() -> CompletableFuture.completedFuture(params.makeOutcome()));
+        tasks.add(() -> CompletableFuture.completedFuture(params.makeOutcome(null)));
         tasks.add(() -> CompletableFuture.failedFuture(except));
-        tasks.add(() -> CompletableFuture.completedFuture(params.makeOutcome()));
+        tasks.add(() -> CompletableFuture.completedFuture(params.makeOutcome(null)));
         result = oper.allOf(tasks);
 
         assertTrue(executor.runAll(MAX_REQUESTS));
@@ -880,7 +881,7 @@ public class OperationPartialTest {
      */
     @Test
     public void testSequence() throws Exception {
-        final OperationOutcome outcome = params.makeOutcome();
+        final OperationOutcome outcome = params.makeOutcome(null);
 
         List<Supplier<CompletableFuture<OperationOutcome>>> tasks = new LinkedList<>();
         tasks.add(() -> CompletableFuture.completedFuture(outcome));
@@ -902,7 +903,7 @@ public class OperationPartialTest {
         assertSame(outcome, result.get());
 
         // second task fails, third should not run
-        OperationOutcome failure = params.makeOutcome();
+        OperationOutcome failure = params.makeOutcome(null);
         failure.setResult(PolicyResult.FAILURE);
         tasks.clear();
         tasks.add(() -> CompletableFuture.completedFuture(outcome));
@@ -941,7 +942,7 @@ public class OperationPartialTest {
         OperationOutcome expectedOutcome = null;
 
         for (int count = 0; count < results.length; ++count) {
-            OperationOutcome outcome = params.makeOutcome();
+            OperationOutcome outcome = params.makeOutcome(null);
             outcome.setResult(results[count]);
             tasks.add(() -> CompletableFuture.completedFuture(outcome));
 
@@ -961,7 +962,7 @@ public class OperationPartialTest {
     public void testDetmPriority() throws CoderException {
         assertEquals(1, oper.detmPriority(null));
 
-        OperationOutcome outcome = params.makeOutcome();
+        OperationOutcome outcome = params.makeOutcome(null);
 
         Map<PolicyResult, Integer> map = Map.of(PolicyResult.SUCCESS, 0, PolicyResult.FAILURE_GUARD, 2,
                         PolicyResult.FAILURE_RETRIES, 3, PolicyResult.FAILURE, 4, PolicyResult.FAILURE_TIMEOUT, 5,
@@ -1150,6 +1151,16 @@ public class OperationPartialTest {
         assertEquals(OperationPartial.DEFAULT_RETRY_WAIT_MS, oper2.getRetryWaitMs());
     }
 
+    @Test
+    public void testGetTargetEntity() {
+        // get it from the params
+        assertEquals(MY_TARGET_ENTITY, oper.getTargetEntity());
+
+        // now get it from the properties
+        oper.setProperty(OperationProperties.AAI_TARGET_ENTITY, "entityX");
+        assertEquals("entityX", oper.getTargetEntity());
+    }
+
     @Test
     public void testGetTimeOutMs() {
         assertEquals(TIMEOUT * 1000, oper.getTimeoutMs(params.getTimeoutSec()));
@@ -1187,14 +1198,14 @@ public class OperationPartialTest {
     }
 
     private OperationOutcome makeSuccess() {
-        OperationOutcome outcome = params.makeOutcome();
+        OperationOutcome outcome = params.makeOutcome(null);
         outcome.setResult(PolicyResult.SUCCESS);
 
         return outcome;
     }
 
     private OperationOutcome makeFailure() {
-        OperationOutcome outcome = params.makeOutcome();
+        OperationOutcome outcome = params.makeOutcome(null);
         outcome.setResult(PolicyResult.FAILURE);
 
         return outcome;
index 634d7b1..5e79247 100644 (file)
@@ -131,7 +131,7 @@ public class ControlLoopOperationParamsTest {
                         .retry(RETRY).target(TARGET).targetEntity(TARGET_ENTITY).timeoutSec(TIMEOUT)
                         .startCallback(starter).preprocessed(true).build();
 
-        outcome = params.makeOutcome();
+        outcome = params.makeOutcome(TARGET_ENTITY);
     }
 
     @Test
@@ -245,7 +245,10 @@ public class ControlLoopOperationParamsTest {
         testValidate("actorService", NULL_MSG, bldr -> bldr.actorService(null));
         testValidate("executor", NULL_MSG, bldr -> bldr.executor(null));
         testValidate("operation", NULL_MSG, bldr -> bldr.operation(null));
-        testValidate("target", NULL_MSG, bldr -> bldr.targetEntity(null));
+
+        // has no target entity
+        BeanValidationResult result = params.toBuilder().targetEntity(null).build().validate();
+        assertTrue(result.isValid());
 
         // note: if context is null, then it will ACTUALLY complain about the request ID
         testValidate(REQUEST_ID_NAME, NULL_MSG, bldr -> bldr.context(null));
@@ -263,7 +266,7 @@ public class ControlLoopOperationParamsTest {
 
         // test when event has no request ID
         when(event.getRequestId()).thenReturn(null);
-        BeanValidationResult result = params.validate();
+        result = params.validate();
         assertFalse(result.isValid());
         assertThat(result.getResult()).contains("event").contains(REQUEST_ID_NAME).contains(NULL_MSG);