Make Actors event-agnostic
[policy/models.git] / models-interactions / model-actors / actorServiceProvider / src / test / java / org / onap / policy / controlloop / actorserviceprovider / impl / OperationPartialTest.java
index 39564a4..b7a6a1d 100644 (file)
@@ -28,10 +28,15 @@ import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
 
 import ch.qos.logback.classic.Logger;
 import java.time.Instant;
+import java.util.ArrayDeque;
 import java.util.Arrays;
+import java.util.Collections;
+import java.util.Deque;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
@@ -44,7 +49,6 @@ import java.util.concurrent.ForkJoinPool;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.function.Consumer;
 import java.util.function.Supplier;
@@ -55,6 +59,8 @@ import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure;
 import org.onap.policy.common.endpoints.utils.NetLoggerUtil.EventType;
 import org.onap.policy.common.utils.coder.Coder;
@@ -63,13 +69,15 @@ import org.onap.policy.common.utils.coder.StandardCoder;
 import org.onap.policy.common.utils.test.log.logback.ExtractAppender;
 import org.onap.policy.common.utils.time.PseudoExecutor;
 import org.onap.policy.controlloop.ControlLoopOperation;
-import org.onap.policy.controlloop.VirtualControlLoopEvent;
+import org.onap.policy.controlloop.actorserviceprovider.ActorService;
 import org.onap.policy.controlloop.actorserviceprovider.Operation;
 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
-import org.onap.policy.controlloop.actorserviceprovider.controlloop.ControlLoopEventContext;
+import org.onap.policy.controlloop.actorserviceprovider.OperationProperties;
+import org.onap.policy.controlloop.actorserviceprovider.OperationResult;
+import org.onap.policy.controlloop.actorserviceprovider.Operator;
 import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
 import org.onap.policy.controlloop.actorserviceprovider.parameters.OperatorConfig;
-import org.onap.policy.controlloop.policy.PolicyResult;
+import org.onap.policy.controlloop.actorserviceprovider.spi.Actor;
 import org.slf4j.LoggerFactory;
 
 public class OperationPartialTest {
@@ -82,12 +90,13 @@ public class OperationPartialTest {
     private static final String OPERATION = "my-operation";
     private static final String MY_SINK = "my-sink";
     private static final String MY_SOURCE = "my-source";
+    private static final String MY_TARGET_ENTITY = "my-entity";
     private static final String TEXT = "my-text";
     private static final int TIMEOUT = 1000;
     private static final UUID REQ_ID = UUID.randomUUID();
 
-    private static final List<PolicyResult> FAILURE_RESULTS = Arrays.asList(PolicyResult.values()).stream()
-                    .filter(result -> result != PolicyResult.SUCCESS).collect(Collectors.toList());
+    private static final List<OperationResult> FAILURE_RESULTS = Arrays.asList(OperationResult.values()).stream()
+                    .filter(result -> result != OperationResult.SUCCESS).collect(Collectors.toList());
 
     /**
      * Used to attach an appender to the class' logger.
@@ -95,8 +104,17 @@ public class OperationPartialTest {
     private static final Logger logger = (Logger) LoggerFactory.getLogger(OperationPartial.class);
     private static final ExtractAppender appender = new ExtractAppender();
 
-    private VirtualControlLoopEvent event;
-    private ControlLoopEventContext context;
+    private static final List<String> PROP_NAMES = List.of("hello", "world");
+
+    @Mock
+    private ActorService service;
+    @Mock
+    private Actor guardActor;
+    @Mock
+    private Operator guardOperator;
+    @Mock
+    private Operation guardOperation;
+
     private PseudoExecutor executor;
     private ControlLoopOperationParams params;
 
@@ -110,6 +128,9 @@ public class OperationPartialTest {
     private OperationOutcome opstart;
     private OperationOutcome opend;
 
+    private Deque<OperationOutcome> starts;
+    private Deque<OperationOutcome> ends;
+
     private OperatorConfig config;
 
     /**
@@ -117,7 +138,7 @@ public class OperationPartialTest {
      */
     @BeforeClass
     public static void setUpBeforeClass() throws Exception {
-        /**
+        /*
          * Attach appender to the logger.
          */
         appender.setContext(logger.getLoggerContext());
@@ -139,15 +160,17 @@ public class OperationPartialTest {
      */
     @Before
     public void setUp() {
-        event = new VirtualControlLoopEvent();
-        event.setRequestId(REQ_ID);
-
-        context = new ControlLoopEventContext(event);
+        MockitoAnnotations.initMocks(this);
         executor = new PseudoExecutor();
 
-        params = ControlLoopOperationParams.builder().completeCallback(this::completer).context(context)
-                        .executor(executor).actor(ACTOR).operation(OPERATION).timeoutSec(TIMEOUT)
-                        .startCallback(this::starter).targetEntity(MY_SINK).build();
+        params = ControlLoopOperationParams.builder().completeCallback(this::completer).requestId(REQ_ID)
+                        .executor(executor).actorService(service).actor(ACTOR).operation(OPERATION).timeoutSec(TIMEOUT)
+                        .startCallback(this::starter).targetEntity(MY_TARGET_ENTITY).build();
+
+        when(service.getActor(OperationPartial.GUARD_ACTOR_NAME)).thenReturn(guardActor);
+        when(guardActor.getOperator(OperationPartial.GUARD_OPERATION_NAME)).thenReturn(guardOperator);
+        when(guardOperator.buildOperation(any())).thenReturn(guardOperation);
+        when(guardOperation.start()).thenReturn(CompletableFuture.completedFuture(makeSuccess()));
 
         config = new OperatorConfig(executor);
 
@@ -157,6 +180,9 @@ public class OperationPartialTest {
 
         opstart = null;
         opend = null;
+
+        starts = new ArrayDeque<>(10);
+        ends = new ArrayDeque<>(10);
     }
 
     @Test
@@ -184,27 +210,30 @@ public class OperationPartialTest {
     }
 
     @Test
-    public void testStart() {
-        verifyRun("testStart", 1, 1, PolicyResult.SUCCESS);
+    public void testGetPropertyNames() {
+        assertThat(oper.getPropertyNames()).isEqualTo(PROP_NAMES);
     }
 
-    /**
-     * Tests startOperation() when the operation has a preprocessor.
-     */
     @Test
-    public void testStartWithPreprocessor() {
-        AtomicInteger count = new AtomicInteger();
+    public void testGetProperty_testSetProperty_testGetRequiredProperty() {
+        oper.setProperty("propertyA", "valueA");
+        oper.setProperty("propertyB", "valueB");
+        oper.setProperty("propertyC", 20);
+        oper.setProperty("propertyD", "valueD");
 
-        CompletableFuture<OperationOutcome> preproc = CompletableFuture.supplyAsync(() -> {
-            count.incrementAndGet();
-            return makeSuccess();
-        }, executor);
+        assertEquals("valueA", oper.getProperty("propertyA"));
+        assertEquals("valueB", oper.getProperty("propertyB"));
+        assertEquals(Integer.valueOf(20), oper.getProperty("propertyC"));
 
-        oper.setGuard(preproc);
+        assertEquals("valueD", oper.getRequiredProperty("propertyD", "typeD"));
 
-        verifyRun("testStartWithPreprocessor_testStartPreprocessor", 1, 1, PolicyResult.SUCCESS);
+        assertThatIllegalStateException().isThrownBy(() -> oper.getRequiredProperty("propertyUnknown", "some type"))
+                        .withMessage("missing some type");
+    }
 
-        assertEquals(1, count.get());
+    @Test
+    public void testStart() {
+        verifyRun("testStart", 1, 1, OperationResult.SUCCESS);
     }
 
     /**
@@ -220,81 +249,13 @@ public class OperationPartialTest {
 
         assertNotNull(opstart);
         assertNotNull(opend);
-        assertEquals(PolicyResult.SUCCESS, opend.getResult());
+        assertEquals(OperationResult.SUCCESS, opend.getResult());
 
         assertEquals(MAX_PARALLEL, numStart);
         assertEquals(MAX_PARALLEL, oper.getCount());
         assertEquals(MAX_PARALLEL, numEnd);
     }
 
-    /**
-     * Tests startPreprocessor() when the preprocessor returns a failure.
-     */
-    @Test
-    public void testStartPreprocessorFailure() {
-        oper.setGuard(CompletableFuture.completedFuture(makeFailure()));
-
-        verifyRun("testStartPreprocessorFailure", 1, 0, PolicyResult.FAILURE_GUARD);
-    }
-
-    /**
-     * Tests startPreprocessor() when the preprocessor throws an exception.
-     */
-    @Test
-    public void testStartPreprocessorException() {
-        // arrange for the preprocessor to throw an exception
-        oper.setGuard(CompletableFuture.failedFuture(new IllegalStateException(EXPECTED_EXCEPTION)));
-
-        verifyRun("testStartPreprocessorException", 1, 0, PolicyResult.FAILURE_GUARD);
-    }
-
-    /**
-     * Tests startPreprocessor() when the pipeline is not running.
-     */
-    @Test
-    public void testStartPreprocessorNotRunning() {
-        // arrange for the preprocessor to return success, which will be ignored
-        oper.setGuard(CompletableFuture.completedFuture(makeSuccess()));
-
-        oper.start().cancel(false);
-        assertTrue(executor.runAll(MAX_REQUESTS));
-
-        assertNull(opstart);
-        assertNull(opend);
-
-        assertEquals(0, numStart);
-        assertEquals(0, oper.getCount());
-        assertEquals(0, numEnd);
-    }
-
-    /**
-     * Tests startPreprocessor() when the preprocessor <b>builder</b> throws an exception.
-     */
-    @Test
-    public void testStartPreprocessorBuilderException() {
-        oper = new MyOper() {
-            @Override
-            protected CompletableFuture<OperationOutcome> startPreprocessorAsync() {
-                throw new IllegalStateException(EXPECTED_EXCEPTION);
-            }
-        };
-
-        assertThatIllegalStateException().isThrownBy(() -> oper.start());
-
-        // should be nothing in the queue
-        assertEquals(0, executor.getQueueLength());
-    }
-
-    @Test
-    public void testStartPreprocessorAsync() {
-        assertNull(oper.startPreprocessorAsync());
-    }
-
-    @Test
-    public void testStartGuardAsync() {
-        assertNull(oper.startGuardAsync());
-    }
-
     @Test
     public void testStartOperationAsync() {
         oper.start();
@@ -305,12 +266,14 @@ public class OperationPartialTest {
 
     @Test
     public void testIsSuccess() {
+        assertFalse(oper.isSuccess(null));
+
         OperationOutcome outcome = new OperationOutcome();
 
-        outcome.setResult(PolicyResult.SUCCESS);
+        outcome.setResult(OperationResult.SUCCESS);
         assertTrue(oper.isSuccess(outcome));
 
-        for (PolicyResult failure : FAILURE_RESULTS) {
+        for (OperationResult failure : FAILURE_RESULTS) {
             outcome.setResult(failure);
             assertFalse("testIsSuccess-" + failure, oper.isSuccess(outcome));
         }
@@ -320,17 +283,17 @@ 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);
+        outcome.setResult(OperationResult.SUCCESS);
         assertFalse(oper.isActorFailed(outcome));
 
-        outcome.setResult(PolicyResult.FAILURE_RETRIES);
+        outcome.setResult(OperationResult.FAILURE_RETRIES);
         assertFalse(oper.isActorFailed(outcome));
 
         // correct outcome
-        outcome.setResult(PolicyResult.FAILURE);
+        outcome.setResult(OperationResult.FAILURE);
 
         // incorrect actor
         outcome.setActor(MY_SINK);
@@ -355,13 +318,13 @@ public class OperationPartialTest {
         /*
          * Use an operation that doesn't override doOperation().
          */
-        OperationPartial oper2 = new OperationPartial(params, config) {};
+        OperationPartial oper2 = new OperationPartial(params, config, Collections.emptyList()) {};
 
         oper2.start();
         assertTrue(executor.runAll(MAX_REQUESTS));
 
         assertNotNull(opend);
-        assertEquals(PolicyResult.FAILURE_EXCEPTION, opend.getResult());
+        assertEquals(OperationResult.FAILURE_EXCEPTION, opend.getResult());
     }
 
     @Test
@@ -380,8 +343,8 @@ public class OperationPartialTest {
             @Override
             protected CompletableFuture<OperationOutcome> startOperationAsync(int attempt, OperationOutcome outcome) {
 
-                OperationOutcome outcome2 = params.makeOutcome();
-                outcome2.setResult(PolicyResult.SUCCESS);
+                OperationOutcome outcome2 = params.makeOutcome(null);
+                outcome2.setResult(OperationResult.SUCCESS);
 
                 /*
                  * Create an incomplete future that will timeout after the operation's
@@ -396,7 +359,7 @@ public class OperationPartialTest {
             }
         };
 
-        assertEquals(PolicyResult.FAILURE_TIMEOUT, oper.start().get().getResult());
+        assertEquals(OperationResult.FAILURE_TIMEOUT, oper.start().get().getResult());
     }
 
     /**
@@ -411,7 +374,7 @@ public class OperationPartialTest {
 
         oper.setMaxFailures(10);
 
-        verifyRun("testSetRetryFlag_testRetryOnFailure_ZeroRetries", 1, 1, PolicyResult.FAILURE);
+        verifyRun("testSetRetryFlag_testRetryOnFailure_ZeroRetries", 1, 1, OperationResult.FAILURE);
     }
 
     /**
@@ -426,7 +389,7 @@ public class OperationPartialTest {
 
         oper.setMaxFailures(10);
 
-        verifyRun("testSetRetryFlag_testRetryOnFailure_NullRetries", 1, 1, PolicyResult.FAILURE);
+        verifyRun("testSetRetryFlag_testRetryOnFailure_NullRetries", 1, 1, OperationResult.FAILURE);
     }
 
     /**
@@ -443,7 +406,7 @@ public class OperationPartialTest {
         oper.setMaxFailures(10);
 
         verifyRun("testSetRetryFlag_testRetryOnFailure_RetriesExhausted", maxRetries + 1, maxRetries + 1,
-                        PolicyResult.FAILURE_RETRIES);
+                        OperationResult.FAILURE_RETRIES);
     }
 
     /**
@@ -460,7 +423,7 @@ public class OperationPartialTest {
         oper.setMaxFailures(maxFailures);
 
         verifyRun("testSetRetryFlag_testRetryOnFailure_SuccessAfterRetries", maxFailures + 1, maxFailures + 1,
-                        PolicyResult.SUCCESS);
+                        OperationResult.SUCCESS);
     }
 
     /**
@@ -472,15 +435,15 @@ public class OperationPartialTest {
         // arrange to return null from doOperation()
         oper = new MyOper() {
             @Override
-            protected OperationOutcome doOperation(int attempt, OperationOutcome operation) {
+            protected OperationOutcome doOperation(int attempt, OperationOutcome outcome) {
 
                 // update counters
-                super.doOperation(attempt, operation);
+                super.doOperation(attempt, outcome);
                 return null;
             }
         };
 
-        verifyRun("testSetRetryFlag_testRetryOnFailure_NullOutcome", 1, 1, PolicyResult.FAILURE, null, noop());
+        verifyRun("testSetRetryFlag_testRetryOnFailure_NullOutcome", 1, 1, OperationResult.FAILURE, noop());
     }
 
     @Test
@@ -517,7 +480,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);
@@ -536,41 +499,12 @@ public class OperationPartialTest {
         assertTrue(oper.isSameOperation(outcome));
     }
 
-    /**
-     * Tests handleFailure() when the outcome is a success.
-     */
-    @Test
-    public void testHandlePreprocessorFailureTrue() {
-        oper.setGuard(CompletableFuture.completedFuture(makeSuccess()));
-        verifyRun("testHandlePreprocessorFailureTrue", 1, 1, PolicyResult.SUCCESS);
-    }
-
-    /**
-     * Tests handleFailure() when the outcome is <i>not</i> a success.
-     */
-    @Test
-    public void testHandlePreprocessorFailureFalse() throws Exception {
-        oper.setGuard(CompletableFuture.completedFuture(makeFailure()));
-        verifyRun("testHandlePreprocessorFailureFalse", 1, 0, PolicyResult.FAILURE_GUARD);
-    }
-
-    /**
-     * Tests handleFailure() when the outcome is {@code null}.
-     */
-    @Test
-    public void testHandlePreprocessorFailureNull() throws Exception {
-        // arrange to return null from the preprocessor
-        oper.setGuard(CompletableFuture.completedFuture(null));
-
-        verifyRun("testHandlePreprocessorFailureNull", 1, 0, PolicyResult.FAILURE_GUARD);
-    }
-
     @Test
     public void testFromException() {
         // arrange to generate an exception when operation runs
         oper.setGenException(true);
 
-        verifyRun("testFromException", 1, 1, PolicyResult.FAILURE_EXCEPTION);
+        verifyRun("testFromException", 1, 1, OperationResult.FAILURE_EXCEPTION);
     }
 
     /**
@@ -578,7 +512,7 @@ public class OperationPartialTest {
      */
     @Test
     public void testFromExceptionNoExcept() {
-        verifyRun("testFromExceptionNoExcept", 1, 1, PolicyResult.SUCCESS);
+        verifyRun("testFromExceptionNoExcept", 1, 1, OperationResult.SUCCESS);
     }
 
     /**
@@ -589,7 +523,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<>());
@@ -654,7 +588,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<>();
@@ -685,7 +619,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<>();
@@ -764,19 +698,19 @@ public class OperationPartialTest {
     @Test
     public void testCombineOutcomes() throws Exception {
         // only one outcome
-        verifyOutcomes(0, PolicyResult.SUCCESS);
-        verifyOutcomes(0, PolicyResult.FAILURE_EXCEPTION);
+        verifyOutcomes(0, OperationResult.SUCCESS);
+        verifyOutcomes(0, OperationResult.FAILURE_EXCEPTION);
 
         // maximum is in different positions
-        verifyOutcomes(0, PolicyResult.FAILURE, PolicyResult.SUCCESS, PolicyResult.FAILURE_GUARD);
-        verifyOutcomes(1, PolicyResult.SUCCESS, PolicyResult.FAILURE, PolicyResult.FAILURE_GUARD);
-        verifyOutcomes(2, PolicyResult.SUCCESS, PolicyResult.FAILURE_GUARD, PolicyResult.FAILURE);
+        verifyOutcomes(0, OperationResult.FAILURE, OperationResult.SUCCESS, OperationResult.FAILURE_GUARD);
+        verifyOutcomes(1, OperationResult.SUCCESS, OperationResult.FAILURE, OperationResult.FAILURE_GUARD);
+        verifyOutcomes(2, OperationResult.SUCCESS, OperationResult.FAILURE_GUARD, OperationResult.FAILURE);
 
         // 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));
@@ -787,9 +721,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));
@@ -802,7 +736,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));
@@ -824,8 +758,8 @@ public class OperationPartialTest {
         assertSame(outcome, result.get());
 
         // second task fails, third should not run
-        OperationOutcome failure = params.makeOutcome();
-        failure.setResult(PolicyResult.FAILURE);
+        OperationOutcome failure = params.makeOutcome(null);
+        failure.setResult(OperationResult.FAILURE);
         tasks.clear();
         tasks.add(() -> CompletableFuture.completedFuture(outcome));
         tasks.add(() -> CompletableFuture.completedFuture(failure));
@@ -857,13 +791,13 @@ public class OperationPartialTest {
         assertSame(future1, oper.sequence(() -> future1));
     }
 
-    private void verifyOutcomes(int expected, PolicyResult... results) throws Exception {
+    private void verifyOutcomes(int expected, OperationResult... results) throws Exception {
         List<Supplier<CompletableFuture<OperationOutcome>>> tasks = new LinkedList<>();
 
         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));
 
@@ -883,13 +817,13 @@ 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,
-                        PolicyResult.FAILURE_EXCEPTION, 6);
+        Map<OperationResult, Integer> map = Map.of(OperationResult.SUCCESS, 0, OperationResult.FAILURE_GUARD, 2,
+                OperationResult.FAILURE_RETRIES, 3, OperationResult.FAILURE, 4, OperationResult.FAILURE_TIMEOUT, 5,
+                OperationResult.FAILURE_EXCEPTION, 6);
 
-        for (Entry<PolicyResult, Integer> ent : map.entrySet()) {
+        for (Entry<OperationResult, Integer> ent : map.entrySet()) {
             outcome.setResult(ent.getKey());
             assertEquals(ent.getKey().toString(), ent.getValue().intValue(), oper.detmPriority(outcome));
         }
@@ -960,12 +894,12 @@ public class OperationPartialTest {
         outcome = new OperationOutcome();
         oper.setOutcome(outcome, timex);
         assertEquals(ControlLoopOperation.FAILED_MSG, outcome.getMessage());
-        assertEquals(PolicyResult.FAILURE_TIMEOUT, outcome.getResult());
+        assertEquals(OperationResult.FAILURE_TIMEOUT, outcome.getResult());
 
         outcome = new OperationOutcome();
         oper.setOutcome(outcome, new IllegalStateException(EXPECTED_EXCEPTION));
         assertEquals(ControlLoopOperation.FAILED_MSG, outcome.getMessage());
-        assertEquals(PolicyResult.FAILURE_EXCEPTION, outcome.getResult());
+        assertEquals(OperationResult.FAILURE_EXCEPTION, outcome.getResult());
     }
 
     @Test
@@ -973,11 +907,15 @@ public class OperationPartialTest {
         OperationOutcome outcome;
 
         outcome = new OperationOutcome();
-        oper.setOutcome(outcome, PolicyResult.SUCCESS);
+        oper.setOutcome(outcome, OperationResult.SUCCESS);
         assertEquals(ControlLoopOperation.SUCCESS_MSG, outcome.getMessage());
-        assertEquals(PolicyResult.SUCCESS, outcome.getResult());
+        assertEquals(OperationResult.SUCCESS, outcome.getResult());
 
-        for (PolicyResult result : FAILURE_RESULTS) {
+        oper.setOutcome(outcome, OperationResult.SUCCESS);
+        assertEquals(ControlLoopOperation.SUCCESS_MSG, outcome.getMessage());
+        assertEquals(OperationResult.SUCCESS, outcome.getResult());
+
+        for (OperationResult result : FAILURE_RESULTS) {
             outcome = new OperationOutcome();
             oper.setOutcome(outcome, result);
             assertEquals(result.toString(), ControlLoopOperation.FAILED_MSG, outcome.getMessage());
@@ -1064,10 +1002,20 @@ public class OperationPartialTest {
     @Test
     public void testGetRetryWait() {
         // need an operator that doesn't override the retry time
-        OperationPartial oper2 = new OperationPartial(params, config) {};
+        OperationPartial oper2 = new OperationPartial(params, config, Collections.emptyList()) {};
         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()));
@@ -1084,11 +1032,13 @@ public class OperationPartialTest {
         ++numStart;
         tstart = oper.getStart();
         opstart = oper;
+        starts.add(oper);
     }
 
     private void completer(OperationOutcome oper) {
         ++numEnd;
         opend = oper;
+        ends.add(oper);
     }
 
     /**
@@ -1103,15 +1053,8 @@ public class OperationPartialTest {
     }
 
     private OperationOutcome makeSuccess() {
-        OperationOutcome outcome = params.makeOutcome();
-        outcome.setResult(PolicyResult.SUCCESS);
-
-        return outcome;
-    }
-
-    private OperationOutcome makeFailure() {
-        OperationOutcome outcome = params.makeOutcome();
-        outcome.setResult(PolicyResult.FAILURE);
+        OperationOutcome outcome = params.makeOutcome(null);
+        outcome.setResult(OperationResult.SUCCESS);
 
         return outcome;
     }
@@ -1125,12 +1068,9 @@ public class OperationPartialTest {
      * @param expectedResult expected outcome
      */
     private void verifyRun(String testName, int expectedCallbacks, int expectedOperations,
-                    PolicyResult expectedResult) {
+            OperationResult expectedResult) {
 
-        String expectedSubRequestId =
-                        (expectedResult == PolicyResult.FAILURE_EXCEPTION ? null : String.valueOf(expectedOperations));
-
-        verifyRun(testName, expectedCallbacks, expectedOperations, expectedResult, expectedSubRequestId, noop());
+        verifyRun(testName, expectedCallbacks, expectedOperations, expectedResult, noop());
     }
 
     /**
@@ -1140,13 +1080,18 @@ public class OperationPartialTest {
      * @param expectedCallbacks number of callbacks expected
      * @param expectedOperations number of operation invocations expected
      * @param expectedResult expected outcome
-     * @param expectedSubRequestId expected sub request ID
      * @param manipulator function to modify the future returned by
      *        {@link OperationPartial#start(ControlLoopOperationParams)} before the tasks
      *        in the executor are run
      */
-    private void verifyRun(String testName, int expectedCallbacks, int expectedOperations, PolicyResult expectedResult,
-                    String expectedSubRequestId, Consumer<CompletableFuture<OperationOutcome>> manipulator) {
+    private void verifyRun(String testName, int expectedCallbacks, int expectedOperations,
+            OperationResult expectedResult, Consumer<CompletableFuture<OperationOutcome>> manipulator) {
+
+        tstart = null;
+        opstart = null;
+        opend = null;
+        starts.clear();
+        ends.clear();
 
         CompletableFuture<OperationOutcome> future = oper.start();
 
@@ -1167,14 +1112,28 @@ public class OperationPartialTest {
 
             try {
                 assertTrue(future.isDone());
-                assertSame(testName, opend, future.get());
+                assertEquals(testName, opend, future.get());
+
+                // "start" is never final
+                for (OperationOutcome outcome : starts) {
+                    assertFalse(testName, outcome.isFinalOutcome());
+                }
+
+                // only the last "complete" is final
+                assertTrue(testName, ends.removeLast().isFinalOutcome());
+
+                for (OperationOutcome outcome : ends) {
+                    assertFalse(outcome.isFinalOutcome());
+                }
 
             } catch (InterruptedException | ExecutionException e) {
                 throw new IllegalStateException(e);
             }
 
             if (expectedOperations > 0) {
-                assertEquals(testName, expectedSubRequestId, opend.getSubRequestId());
+                assertNotNull(testName, oper.getSubRequestId());
+                assertEquals(testName + " op start", oper.getSubRequestId(), opstart.getSubRequestId());
+                assertEquals(testName + " op end", oper.getSubRequestId(), opend.getSubRequestId());
             }
         }
 
@@ -1187,7 +1146,7 @@ public class OperationPartialTest {
     private void setOperCoderException() {
         oper = new MyOper() {
             @Override
-            protected Coder makeCoder() {
+            protected Coder getCoder() {
                 return new StandardCoder() {
                     @Override
                     public String encode(Object object, boolean pretty) throws CoderException {
@@ -1211,16 +1170,14 @@ public class OperationPartialTest {
 
         @Setter
         private boolean genException;
-
         @Setter
         private int maxFailures = 0;
-
         @Setter
-        private CompletableFuture<OperationOutcome> guard;
+        private CompletableFuture<OperationOutcome> preProc;
 
 
         public MyOper() {
-            super(OperationPartialTest.this.params, config);
+            super(OperationPartialTest.this.params, config, PROP_NAMES);
         }
 
         @Override
@@ -1233,19 +1190,14 @@ public class OperationPartialTest {
             operation.setSubRequestId(String.valueOf(attempt));
 
             if (count > maxFailures) {
-                operation.setResult(PolicyResult.SUCCESS);
+                operation.setResult(OperationResult.SUCCESS);
             } else {
-                operation.setResult(PolicyResult.FAILURE);
+                operation.setResult(OperationResult.FAILURE);
             }
 
             return operation;
         }
 
-        @Override
-        protected CompletableFuture<OperationOutcome> startGuardAsync() {
-            return (guard != null ? guard : super.startGuardAsync());
-        }
-
         @Override
         protected long getRetryWaitMs() {
             /*