Do not require context in ControlLoopOperationParams 49/111249/1
authorJim Hahn <jrh3@att.com>
Thu, 13 Aug 2020 15:15:29 +0000 (11:15 -0400)
committerJim Hahn <jrh3@att.com>
Thu, 13 Aug 2020 16:27:43 +0000 (12:27 -0400)
Modified ControlLoopOperationParams so that the request ID can
be provided instead of the context.  However, if the request ID
is not provided, then it still requires a context.  (This requirement
should be lifted in a subsequent review).

Issue-ID: POLICY-2746
Change-Id: Ib00f46f2fe56430d700ee2edfba12f2c1a106a3f
Signed-off-by: Jim Hahn <jrh3@att.com>
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/parameters/ControlLoopOperationParamsTest.java

index f5dd498..d0b7c26 100644 (file)
@@ -33,6 +33,7 @@ import lombok.Getter;
 import org.onap.policy.common.parameters.BeanValidationResult;
 import org.onap.policy.common.parameters.BeanValidator;
 import org.onap.policy.common.parameters.annotations.NotNull;
+import org.onap.policy.controlloop.VirtualControlLoopEvent;
 import org.onap.policy.controlloop.actorserviceprovider.ActorService;
 import org.onap.policy.controlloop.actorserviceprovider.Operation;
 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
@@ -68,9 +69,13 @@ public class ControlLoopOperationParams {
     /**
      * Event for which the operation applies.
      */
-    @NotNull
     private ControlLoopEventContext context;
 
+    /**
+     * If {@code null}, this value is extracted from the context.
+     */
+    private UUID requestId;
+
     /**
      * Executor to use to run the operation.
      */
@@ -175,7 +180,12 @@ public class ControlLoopOperationParams {
      * @return the event's request ID, or {@code null} if no request ID is available
      */
     public UUID getRequestId() {
-        return (context == null || context.getEvent() == null ? null : context.getEvent().getRequestId());
+        if (requestId == null && context != null && context.getEvent() != null) {
+            // cache the request ID
+            requestId = context.getEvent().getRequestId();
+        }
+
+        return requestId;
     }
 
     /**
@@ -230,6 +240,34 @@ public class ControlLoopOperationParams {
      * @return the validation result
      */
     public BeanValidationResult validate() {
-        return new BeanValidator().validateTop(ControlLoopOperationParams.class.getSimpleName(), this);
+        BeanValidationResult result =
+                        new BeanValidator().validateTop(ControlLoopOperationParams.class.getSimpleName(), this);
+
+        // validate that we have a request ID, or that we can get it from the context's
+        // event
+
+        if (context == null) {
+            // no context specified - invoker must provide a request ID then
+            result.validateNotNull("requestId", requestId);
+
+        } else if (requestId == null) {
+            // have a context, but no request ID - check the context's event for the
+            // request ID
+            BeanValidationResult contextResult = new BeanValidationResult("context", context);
+            VirtualControlLoopEvent event = context.getEvent();
+            contextResult.validateNotNull("event", event);
+
+            if (event != null) {
+                // cache the request id for later use
+                BeanValidationResult eventResult = new BeanValidationResult("event", event);
+                eventResult.validateNotNull("requestId", event.getRequestId());
+
+                contextResult.addResult(eventResult);
+            }
+
+            result.addResult(contextResult);
+        }
+
+        return result;
     }
 }
index 98ca673..634d7b1 100644 (file)
@@ -60,6 +60,8 @@ import org.onap.policy.controlloop.actorserviceprovider.spi.Actor;
 import org.onap.policy.controlloop.policy.Target;
 
 public class ControlLoopOperationParamsTest {
+    private static final String NULL_MSG = "null";
+    private static final String REQUEST_ID_NAME = "requestId";
     private static final String EXPECTED_EXCEPTION = "expected exception";
     private static final String ACTOR = "my-actor";
     private static final String OPERATION = "my-operation";
@@ -68,6 +70,7 @@ public class ControlLoopOperationParamsTest {
     private static final Integer RETRY = 3;
     private static final Integer TIMEOUT = 100;
     private static final UUID REQ_ID = UUID.randomUUID();
+    private static final UUID REQ_ID2 = UUID.randomUUID();
 
     @Mock
     private Actor actor;
@@ -133,28 +136,41 @@ public class ControlLoopOperationParamsTest {
 
     @Test
     public void testStart() {
-        assertSame(operFuture, params.start());
-
         assertThatIllegalArgumentException().isThrownBy(() -> params.toBuilder().context(null).build().start());
+
+        assertSame(operFuture, params.start());
     }
 
     @Test
     public void testBuild() {
-        assertSame(operation, params.build());
-
         assertThatIllegalArgumentException().isThrownBy(() -> params.toBuilder().context(null).build().build());
+
+        assertSame(operation, params.build());
     }
 
     @Test
     public void testGetRequestId() {
         assertSame(REQ_ID, params.getRequestId());
 
+        // when both request ID and event request ID are set - should use request ID
+        // parameter
+        assertSame(REQ_ID2, params.toBuilder().requestId(REQ_ID2).build().getRequestId());
+    }
+
+    /**
+     * Tests getRequestId() when the request ID is not available in the context.
+     */
+    @Test
+    public void testGetRequestIdNotFromContext() {
         // try with null context
         assertNull(params.toBuilder().context(null).build().getRequestId());
 
         // try with null event
         when(context.getEvent()).thenReturn(null);
         assertNull(params.getRequestId());
+
+        // set request ID directly
+        assertSame(REQ_ID2, params.toBuilder().requestId(REQ_ID2).build().getRequestId());
     }
 
     @Test
@@ -225,12 +241,14 @@ public class ControlLoopOperationParamsTest {
 
     @Test
     public void testValidateFields() {
-        testValidate("actor", "null", bldr -> bldr.actor(null));
-        testValidate("actorService", "null", bldr -> bldr.actorService(null));
-        testValidate("context", "null", bldr -> bldr.context(null));
-        testValidate("executor", "null", bldr -> bldr.executor(null));
-        testValidate("operation", "null", bldr -> bldr.operation(null));
-        testValidate("target", "null", bldr -> bldr.targetEntity(null));
+        testValidate("actor", NULL_MSG, bldr -> bldr.actor(null));
+        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));
+
+        // note: if context is null, then it will ACTUALLY complain about the request ID
+        testValidate(REQUEST_ID_NAME, NULL_MSG, bldr -> bldr.context(null));
 
         // check edge cases
         assertTrue(params.toBuilder().build().validate().isValid());
@@ -242,6 +260,26 @@ public class ControlLoopOperationParamsTest {
         // test with minimal fields
         assertTrue(ControlLoopOperationParams.builder().actorService(actorService).context(context).actor(ACTOR)
                         .operation(OPERATION).targetEntity(TARGET_ENTITY).build().validate().isValid());
+
+        // test when event has no request ID
+        when(event.getRequestId()).thenReturn(null);
+        BeanValidationResult result = params.validate();
+        assertFalse(result.isValid());
+        assertThat(result.getResult()).contains("event").contains(REQUEST_ID_NAME).contains(NULL_MSG);
+
+        // try when context has no event
+        when(context.getEvent()).thenReturn(null);
+        result = params.validate();
+        assertFalse(result.isValid());
+        assertThat(result.getResult()).contains("event").doesNotContain(REQUEST_ID_NAME).contains(NULL_MSG);
+
+        // has both request ID and context, but no event
+        result = params.toBuilder().requestId(REQ_ID2).build().validate();
+        assertTrue(result.isValid());
+
+        // has request ID, but not context
+        result = params.toBuilder().requestId(REQ_ID2).context(null).build().validate();
+        assertTrue(result.isValid());
     }
 
     private void testValidate(String fieldName, String expected,