summaryrefslogtreecommitdiffstats
path: root/controlloop/common/controller-tdjam/src/test
diff options
context:
space:
mode:
authorStraubs, Ralph (rs8887) <rs8887@att.com>2020-07-17 10:38:02 -0400
committerTaka Cho <takamune.cho@att.com>2020-08-28 17:03:19 -0400
commita6d4077e3639a0f3478f0cbf51e06ef46517a10d (patch)
tree1d34398ef3488d97c1dc6475372a1b8755373a8b /controlloop/common/controller-tdjam/src/test
parentc75e28d1c1221c37ea4fd1feed9d38c75334f4db (diff)
Add tdjam-controller
the details is on wiki: https://wiki.onap.org/display/DW/tdjam+Feature+for+Tosca-Driven+Control+Loops Fixed some eclipse warnings. Revised the interaction between a manager and its SerialWorkQueue to address some threading issues. The original code started processing the event as soon as the manager was created, WHILE it was still being added to the map. During junit tests, the event responses came back, within the same thread, which then attempted to remove the manager from the map. This resulted in a ConcurrentHashMap exception. Issue-ID: POLICY-2415 Change-Id: I94a4152637be76e5b2aea2d869afd84dfb413a0e Signed-off-by: Straubs, Ralph (rs8887) <rs8887@att.com> Signed-off-by: jhh <jorge.hernandez-herrero@att.com> Signed-off-by: Taka Cho <takamune.cho@att.com> Signed-off-by: Jim Hahn <jrh3@att.com>
Diffstat (limited to 'controlloop/common/controller-tdjam/src/test')
-rw-r--r--controlloop/common/controller-tdjam/src/test/java/org/onap/policy/controlloop/TdjamTest.java159
-rw-r--r--controlloop/common/controller-tdjam/src/test/java/org/onap/policy/controlloop/tdjam/TdjamControllerTest.java240
-rw-r--r--controlloop/common/controller-tdjam/src/test/java/org/onap/policy/extension/system/NonDroolsPolicyControllerTest.java343
-rw-r--r--controlloop/common/controller-tdjam/src/test/resources/META-INF/services/org.onap.policy.drools.features.DroolsControllerFeatureApi3
-rw-r--r--controlloop/common/controller-tdjam/src/test/resources/META-INF/services/org.onap.policy.drools.features.PolicyControllerFeatureApi2
-rw-r--r--controlloop/common/controller-tdjam/src/test/resources/config/event-manager.properties83
-rw-r--r--controlloop/common/controller-tdjam/src/test/resources/config/tdjam-controller.properties64
-rw-r--r--controlloop/common/controller-tdjam/src/test/resources/config/tdjam-http-client.properties52
-rw-r--r--controlloop/common/controller-tdjam/src/test/resources/logback-test.xml38
9 files changed, 984 insertions, 0 deletions
diff --git a/controlloop/common/controller-tdjam/src/test/java/org/onap/policy/controlloop/TdjamTest.java b/controlloop/common/controller-tdjam/src/test/java/org/onap/policy/controlloop/TdjamTest.java
new file mode 100644
index 000000000..cf40ba6d4
--- /dev/null
+++ b/controlloop/common/controller-tdjam/src/test/java/org/onap/policy/controlloop/TdjamTest.java
@@ -0,0 +1,159 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.controlloop;
+
+import java.util.Properties;
+import lombok.Getter;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.runner.RunWith;
+import org.onap.policy.common.utils.coder.CoderException;
+import org.onap.policy.controlloop.common.rules.test.BaseTest;
+import org.onap.policy.controlloop.common.rules.test.Listener;
+import org.onap.policy.controlloop.common.rules.test.NamedRunner;
+import org.onap.policy.controlloop.common.rules.test.Rules;
+import org.onap.policy.controlloop.common.rules.test.TestNames;
+import org.onap.policy.drools.persistence.SystemPersistence;
+import org.onap.policy.drools.persistence.SystemPersistenceConstants;
+import org.onap.policy.drools.system.PolicyController;
+import org.onap.policy.drools.system.PolicyControllerConstants;
+import org.onap.policy.drools.system.PolicyEngine;
+import org.onap.policy.drools.system.PolicyEngineConstants;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
+import org.onap.policy.simulators.Util;
+
+
+
+/**
+ * Tests use cases using BaseTest Set.
+ *
+ * <p/>
+ * Note: this runs ALL tests (i.e., any whose names start with "test").
+ */
+@RunWith(NamedRunner.class)
+@TestNames(prefixes = {"test"})
+
+public class TdjamTest extends BaseTest {
+ protected static final String CONTROLLER_NAME = "tdjam";
+ protected static PolicyController controller;
+
+ @Getter
+ private static final PolicyEngine pdpd = makeEngine();
+
+ @Getter
+ private static final SystemPersistence pdpdRepo = makePdpdRepo();
+
+ /**
+ * Sets up statics.
+ */
+ @BeforeClass
+ public static void setUpBeforeClass() {
+ initStatics();
+ pdpdRepo.setConfigurationDir("src/test/resources/config");
+ pdpd.configure(new Properties());
+ controller = pdpd.createPolicyController(CONTROLLER_NAME, pdpdRepo.getControllerProperties(CONTROLLER_NAME));
+ pdpd.start();
+ httpClients.addClients("tdjam");
+ simulators.start(Util::buildAaiSim, Util::buildSoSim, Util::buildVfcSim, Util::buildGuardSim,
+ Util::buildSdncSim);
+ }
+
+ /**
+ * Cleans up statics.
+ */
+ @AfterClass
+ public static void tearDownAfterClass() {
+ finishStatics();
+ PolicyControllerConstants.getFactory().shutdown(controller);
+ pdpd.stop();
+ }
+
+ /**
+ * Sets up.
+ */
+ @Before
+ public void setUp() {
+ topics = topicMaker.get();
+ }
+
+ /**
+ * Tears down.
+ */
+ @After
+ public void tearDown() {
+ topics.destroy();
+ }
+
+ protected static PolicyEngine makeEngine() {
+ return PolicyEngineConstants.getManager();
+ }
+
+ protected static SystemPersistence makePdpdRepo() {
+ return SystemPersistenceConstants.getManager();
+ }
+
+ @Override
+ protected void waitForLockAndPermit(ToscaPolicy policy, Listener<VirtualControlLoopNotification> policyClMgt) {
+ String policyName = policy.getIdentifier().getName();
+
+ policyClMgt.await(notif -> notif.getNotification() == ControlLoopNotificationType.ACTIVE
+ && (policyName + ".EVENT").equals(notif.getPolicyName()));
+
+ policyClMgt.await(notif -> notif.getNotification() == ControlLoopNotificationType.OPERATION
+ && (policyName + ".EVENT.MANAGER.PROCESSING").equals(notif.getPolicyName())
+ && notif.getMessage().startsWith("Sending guard query"));
+
+ policyClMgt.await(notif -> notif.getNotification() == ControlLoopNotificationType.OPERATION
+ && (policyName + ".EVENT.MANAGER.PROCESSING").equals(notif.getPolicyName())
+ && notif.getMessage().startsWith("Guard result") && notif.getMessage().endsWith("Permit"));
+
+ policyClMgt.await(notif -> notif.getNotification() == ControlLoopNotificationType.OPERATION
+ && (policyName + ".EVENT.MANAGER.PROCESSING").equals(notif.getPolicyName())
+ && notif.getMessage().startsWith("actor="));
+ }
+
+ @Override
+ protected VirtualControlLoopNotification waitForFinal(ToscaPolicy policy,
+ Listener<VirtualControlLoopNotification> policyClMgt, ControlLoopNotificationType finalType) {
+
+ return policyClMgt.await(notif -> notif.getNotification() == finalType
+ && (policy.getIdentifier().getName() + ".EVENT.MANAGER.FINAL").equals(notif.getPolicyName()));
+ }
+
+ @Override
+ protected ToscaPolicy checkPolicy(String fileName) {
+ try {
+ policy = Rules.getPolicyFromFile(fileName);
+ } catch (CoderException e) {
+ throw new IllegalArgumentException(fileName, e);
+ }
+ controller.getDrools().offer(policy);
+ return policy;
+ }
+
+ @Override
+ protected Listener<VirtualControlLoopNotification> createNoficationTopicListener() {
+ return topics.createListener(POLICY_CL_MGT_TOPIC,
+ VirtualControlLoopNotification.class, controller);
+ }
+}
diff --git a/controlloop/common/controller-tdjam/src/test/java/org/onap/policy/controlloop/tdjam/TdjamControllerTest.java b/controlloop/common/controller-tdjam/src/test/java/org/onap/policy/controlloop/tdjam/TdjamControllerTest.java
new file mode 100644
index 000000000..5edba8701
--- /dev/null
+++ b/controlloop/common/controller-tdjam/src/test/java/org/onap/policy/controlloop/tdjam/TdjamControllerTest.java
@@ -0,0 +1,240 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.controlloop.tdjam;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.onap.policy.drools.properties.DroolsPropertyConstants.PROPERTY_CONTROLLER_TYPE;
+
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.read.ListAppender;
+import java.util.HashSet;
+import java.util.Properties;
+import java.util.UUID;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.onap.policy.controlloop.CanonicalOnset;
+import org.onap.policy.controlloop.VirtualControlLoopNotification;
+import org.onap.policy.controlloop.common.rules.test.Listener;
+import org.onap.policy.controlloop.common.rules.test.Topics;
+import org.onap.policy.controlloop.drl.legacy.ControlLoopParams;
+import org.onap.policy.drools.controller.DroolsControllerConstants;
+import org.onap.policy.drools.system.PolicyControllerConstants;
+import org.onap.policy.drools.system.PolicyEngineConstants;
+import org.onap.policy.drools.utils.PropertyUtil;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
+import org.powermock.reflect.Whitebox;
+import org.slf4j.LoggerFactory;
+
+public class TdjamControllerTest {
+ private static Properties prop;
+ private static Logger logger = (Logger) LoggerFactory.getLogger(TdjamController.class);
+ private static ListAppender<ILoggingEvent> appender = new ListAppender<ILoggingEvent>();
+
+ /**
+ * Setup appender, and initialize properties.
+ */
+ @BeforeClass
+ public static void setupClass() throws Exception {
+ logger.setLevel(Level.DEBUG);
+ logger.addAppender(appender);
+
+ prop = PropertyUtil.getProperties("src/test/resources/config/tdjam-controller.properties");
+ prop.setProperty(PROPERTY_CONTROLLER_TYPE, "tdjam");
+
+ PolicyEngineConstants.getManager().configure(new Properties());
+ PolicyEngineConstants.getManager().start();
+
+ }
+
+ /**
+ * Remove appender.
+ */
+ @AfterClass
+ public static void cleanupClass() {
+
+ PolicyEngineConstants.getManager().stop();
+ PolicyEngineConstants.getManager().getExecutorService().shutdown();
+
+ appender.stop();
+ System.out.println("APPENDER:");
+ for (ILoggingEvent event : appender.list) {
+ System.out.println(" " + event);
+ }
+ logger.detachAppender(appender);
+ }
+
+ @Test
+ public void toscaPolicyTests() {
+ TdjamController tc = (TdjamController) PolicyControllerConstants.getFactory().build("tc", prop);
+ assertTrue(PolicyControllerConstants.getFactory().inventory().contains(tc));
+ assertTrue(DroolsControllerConstants.getFactory().inventory().contains(tc));
+
+ final HashSet<ToscaPolicy> toscaPolicies = new HashSet<>();
+ final HashSet<ControlLoopParams> controlLoopParams = new HashSet<>();
+
+ ToscaPolicy a1 = buildToscaPolicy("a", "1", tc);
+ ToscaPolicy a2 = buildToscaPolicy("a", "2", tc);
+ ToscaPolicy b1 = buildToscaPolicy("b", "1", tc);
+
+ toscaPolicies.add(a1);
+ toscaPolicies.add(a2);
+ toscaPolicies.add(b1);
+
+ assertSame(a1, tc.getToscaPolicy("a", "1"));
+ assertSame(a2, tc.getToscaPolicy("a", "2"));
+ assertSame(b1, tc.getToscaPolicy("b", "1"));
+ assertEquals(toscaPolicies, tc.getAllToscaPolicies());
+
+ // create associated ControlLoopParams
+ final ControlLoopParams clpa1 = buildControlLoopParams("a", "1", "clpa1", tc);
+ final ControlLoopParams clpa2 = buildControlLoopParams("a", "2", "clpa2", tc);
+ final ControlLoopParams clpb1 = buildControlLoopParams("b", "1", "clpb1", tc);
+ final ControlLoopParams clpb3 = buildControlLoopParams("b", "3", "clpb3", null);
+
+ // the add for 'clpb3' should fail, because there is no ToscaPolicy
+ startLog();
+ assertSame(clpb3, tc.addControlLoopParams(clpb3));
+ stopLog();
+ assertLog(".*Missing ToscaPolicy, name=b, version=3.*");
+ assertNull(tc.removeControlLoopParams("clpb3"));
+
+ controlLoopParams.add(clpa1);
+ controlLoopParams.add(clpa2);
+ controlLoopParams.add(clpb1);
+ assertEquals(controlLoopParams, new HashSet<>(tc.getAllControlLoopParams()));
+
+ // manually remove a ControlLoopParams
+ assertSame(clpa1, tc.removeControlLoopParams("clpa1"));
+ assertTrue(controlLoopParams.remove(clpa1));
+ assertEquals(controlLoopParams, new HashSet<>(tc.getAllControlLoopParams()));
+
+ // tests of nonexistent policies
+ assertNull(tc.getToscaPolicy("c", "1")); // non-existent name
+ assertNull(tc.removeToscaPolicy("c", "1"));
+ assertNull(tc.getToscaPolicy("b", "3")); // non-existent version
+ assertNull(tc.removeToscaPolicy("b", "3"));
+
+ assertSame(a1, tc.removeToscaPolicy("a", "1"));
+ assertTrue(toscaPolicies.remove(a1));
+ assertEquals(toscaPolicies, tc.getAllToscaPolicies());
+ assertSame(a2, tc.removeToscaPolicy("a", "2"));
+ assertTrue(toscaPolicies.remove(a2));
+ assertEquals(toscaPolicies, tc.getAllToscaPolicies());
+
+ // ControlLoopParams removal should be automatic
+ assertTrue(controlLoopParams.remove(clpa2));
+ assertEquals(controlLoopParams, new HashSet<>(tc.getAllControlLoopParams()));
+
+ // test reset method
+ tc.reset();
+ assertTrue(tc.getAllToscaPolicies().isEmpty());
+ assertTrue(tc.getAllControlLoopParams().isEmpty());
+ assertTrue(tc.getAllEventManagers().isEmpty());
+ assertTrue(tc.getAllOnsetToEventManager().isEmpty());
+
+ PolicyControllerConstants.getFactory().shutdown(tc);
+ assertFalse(PolicyControllerConstants.getFactory().inventory().contains(tc));
+ assertFalse(DroolsControllerConstants.getFactory().inventory().contains(tc));
+ }
+
+ @Test
+ public void onsetErrors() throws Exception {
+ TdjamController tc = (TdjamController) PolicyControllerConstants.getFactory().build("tc", prop);
+ assertTrue(PolicyControllerConstants.getFactory().inventory().contains(tc));
+ assertTrue(DroolsControllerConstants.getFactory().inventory().contains(tc));
+ tc.start();
+
+ buildToscaPolicy("a", "1", tc);
+ final ControlLoopParams clpa1 = buildControlLoopParams("a", "1", "clpa1", tc);
+ assertTrue(tc.getAllControlLoopParams().contains(clpa1));
+
+ CanonicalOnset canonicalOnset = new CanonicalOnset();
+ startLog();
+ Whitebox.invokeMethod(tc, "processEvent", canonicalOnset);
+ stopLog();
+ assertLog(".*No ControlLoopParams for event: CanonicalOnset.*");
+
+ // set Name with new canonicalOnset
+ CanonicalOnset canonicalOnset2 = new CanonicalOnset();
+ canonicalOnset2.setClosedLoopControlName("clpa1");
+ // try with a non-null requestID, but missing target
+ canonicalOnset2.setRequestId(UUID.randomUUID());
+ startLog();
+ Whitebox.invokeMethod(tc, "processEvent", canonicalOnset2);
+ stopLog();
+ assertLog(".*Exception creating ControlLoopEventManager.*");
+
+ PolicyControllerConstants.getFactory().shutdown(tc);
+ assertFalse(PolicyControllerConstants.getFactory().inventory().contains(tc));
+ }
+
+ private ToscaPolicy buildToscaPolicy(String name, String version, TdjamController tc) {
+ ToscaPolicy tp = new ToscaPolicy();
+ tp.setName(name);
+ tp.setVersion(version);
+
+ if (tc != null) {
+ tc.addToscaPolicy(tp);
+ }
+ return tp;
+ }
+
+ private ControlLoopParams buildControlLoopParams(String name, String version,
+ String closedLoopControlName, TdjamController tc) {
+
+ ControlLoopParams clp = new ControlLoopParams();
+ clp.setPolicyName(name);
+ clp.setPolicyVersion(version);
+ clp.setClosedLoopControlName(closedLoopControlName);
+
+ if (tc != null) {
+ assertTrue(tc.addControlLoopParams(clp) != clp);
+ }
+
+ return clp;
+ }
+
+ private void startLog() {
+ appender.list.clear();
+ appender.start();
+ }
+
+ private void stopLog() {
+ appender.stop();
+ }
+
+ private void assertLog(String regexp) {
+ for (ILoggingEvent event : appender.list) {
+ if (event.toString().matches(regexp)) {
+ return;
+ }
+ }
+ fail("Missing log entry: " + regexp);
+ }
+}
diff --git a/controlloop/common/controller-tdjam/src/test/java/org/onap/policy/extension/system/NonDroolsPolicyControllerTest.java b/controlloop/common/controller-tdjam/src/test/java/org/onap/policy/extension/system/NonDroolsPolicyControllerTest.java
new file mode 100644
index 000000000..ee96cb893
--- /dev/null
+++ b/controlloop/common/controller-tdjam/src/test/java/org/onap/policy/extension/system/NonDroolsPolicyControllerTest.java
@@ -0,0 +1,343 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.extension.system;
+
+import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.onap.policy.drools.properties.DroolsPropertyConstants.PROPERTY_CONTROLLER_TYPE;
+
+import java.util.List;
+import java.util.Properties;
+import java.util.function.Function;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.onap.policy.common.endpoints.event.comm.TopicSink;
+import org.onap.policy.controlloop.VirtualControlLoopNotification;
+import org.onap.policy.drools.controller.DroolsController;
+import org.onap.policy.drools.features.DroolsControllerFeatureApi;
+import org.onap.policy.drools.features.PolicyControllerFeatureApi;
+import org.onap.policy.drools.protocol.coders.TopicCoderFilterConfiguration;
+import org.onap.policy.drools.system.PolicyController;
+import org.onap.policy.drools.system.PolicyControllerConstants;
+import org.onap.policy.drools.utils.PropertyUtil;
+
+public class NonDroolsPolicyControllerTest {
+ //public static boolean loop = true;
+ private static Properties prop;
+
+ @BeforeClass
+ public static void setupClass() throws Exception {
+ prop = PropertyUtil.getProperties("src/test/resources/config/tdjam-controller.properties");
+ }
+
+ @Test
+ public void testState() {
+ NonDroolsPolicyController controller = buildController("tdjam");
+
+ assertEquals("nondrools", controller.getName());
+ assertEquals("NonDroolsPolicyController", controller.getGroupId());
+ assertEquals("nondrools", controller.getArtifactId());
+ assertEquals("1.0", controller.getVersion());
+ assertTrue(controller.isBrained());
+
+ assertFalse(controller.isAlive());
+ assertFalse(controller.isLocked());
+
+ // first 'start()'
+ controller.start();
+ assertTrue(controller.isAlive());
+ assertFalse(controller.isLocked());
+
+ // second 'start()'
+ controller.start();
+ assertTrue(controller.isAlive());
+ assertFalse(controller.isLocked());
+
+ // test a few stubbed-off methods
+ assertTrue(controller.getSessionNames().isEmpty());
+ assertTrue(controller.getCanonicalSessionNames().isEmpty());
+ assertTrue(controller.getBaseDomainNames().isEmpty());
+ assertFalse(controller.offer("topic", "event"));
+ assertFalse(controller.offer("event"));
+ assertEquals(0, controller.getRecentSourceEvents().length);
+ assertEquals(0, controller.getRecentSinkEvents().length);
+ assertNull(controller.getContainer());
+ assertThatIllegalArgumentException().isThrownBy(
+ () -> controller.fetchModelClass("NoSuchClass"));
+ assertThatIllegalStateException().isThrownBy(
+ () -> controller.updateToVersion(null, null, null, null, null));
+ assertTrue(controller.factClassNames(null).isEmpty());
+ assertEquals(0, controller.factCount(null));
+ assertTrue(controller.facts(null, null, false).isEmpty());
+ assertTrue(controller.facts("sessionName", String.class).isEmpty());
+ assertTrue(controller.factQuery(null, null, null, false).isEmpty());
+ assertFalse(controller.delete("sessionName", "fact"));
+ assertFalse(controller.delete("fact"));
+ assertFalse(controller.delete("sessionName", String.class));
+ assertFalse(controller.delete(String.class));
+
+ controller.lock();
+ assertTrue(controller.isAlive());
+ assertTrue(controller.isLocked());
+
+ controller.stop();
+ assertFalse(controller.isAlive());
+ assertTrue(controller.isLocked());
+
+ controller.unlock();
+ assertFalse(controller.isAlive());
+ assertFalse(controller.isLocked());
+
+ destroy(controller);
+ }
+
+ @Test
+ public void deliverTest() {
+ DroolsControllerFeatureHandler.resetStats();
+ final NonDroolsPolicyController controller = buildController("tdjam");
+
+ final TopicSink topicSink = mock(TopicSink.class);
+ when(topicSink.getTopic()).thenReturn("POLICY-CL-MGT");
+ when(topicSink.send(any())).thenReturn(false);
+
+ final VirtualControlLoopNotification msg = new VirtualControlLoopNotification(null);
+
+ controller.lock();
+
+ // invalid sink
+ try {
+ controller.deliver(null, null);
+ fail("Expected IllegalArgumentException did not occur");
+ } catch (IllegalArgumentException ex) {
+ assertTrue(ex.getMessage(),
+ ex.getMessage().endsWith(" invalid sink"));
+ }
+
+ // invalid event
+ try {
+ controller.deliver(topicSink, null);
+ fail("Expected IllegalArgumentException did not occur");
+ } catch (IllegalArgumentException ex) {
+ assertTrue(ex.getMessage(),
+ ex.getMessage().endsWith(" invalid event"));
+ }
+
+ // is locked
+ try {
+ controller.deliver(topicSink, "event");
+ fail("Expected IllegalStateException did not occur");
+ } catch (IllegalStateException ex) {
+ assertTrue(ex.getMessage(),
+ ex.getMessage().endsWith(" is locked"));
+ }
+ controller.unlock();
+
+ // is stopped
+ try {
+ controller.deliver(topicSink, "event");
+ fail("Expected IllegalStateException did not occur");
+ } catch (IllegalStateException ex) {
+ assertTrue(ex.getMessage(),
+ ex.getMessage().endsWith(" is stopped"));
+ }
+
+ // there should have been 4 'beforeDeliver' calls up to this point
+ assertEquals(4, DroolsControllerFeatureHandler.beforeDeliverFalse);
+
+ Function<String, Boolean> signal = (sig) -> {
+ msg.getAai().put("signal", sig);
+ return controller.deliver(topicSink, msg);
+ };
+
+ controller.start();
+
+ // 'beforeDeliver' intercepts
+ DroolsControllerFeatureHandler.resetStats();
+
+ assertTrue(signal.apply("beforeDeliverTrue"));
+ assertEquals(1, DroolsControllerFeatureHandler.beforeDeliverTrue);
+ assertEquals(0, DroolsControllerFeatureHandler.afterDeliverFalse);
+
+ assertFalse(signal.apply("beforeDeliverException"));
+ assertEquals(1, DroolsControllerFeatureHandler.beforeDeliverException);
+ assertEquals(1, DroolsControllerFeatureHandler.afterDeliverFalse);
+ // it would be nice to check the log message at this point
+
+ // 'afterDeliver' intercepts
+ DroolsControllerFeatureHandler.resetStats();
+
+ assertTrue(signal.apply("afterDeliverTrue"));
+ assertEquals(1, DroolsControllerFeatureHandler.afterDeliverTrue);
+
+ assertFalse(signal.apply("afterDeliverException"));
+ assertEquals(1, DroolsControllerFeatureHandler.afterDeliverException);
+
+ assertFalse(signal.apply("nothing in particular"));
+ assertEquals(1, DroolsControllerFeatureHandler.afterDeliverFalse);
+
+ destroy(controller);
+ }
+
+ private NonDroolsPolicyController buildController(String type) {
+ prop.setProperty(PROPERTY_CONTROLLER_TYPE, type);
+ PolicyController controller =
+ PolicyControllerConstants.getFactory().build("nondrools", prop);
+ assertTrue(controller instanceof NonDroolsPolicyController);
+ return (NonDroolsPolicyController) controller;
+ }
+
+ private void destroy(PolicyController controller) {
+ String name = controller.getName();
+ assertSame(controller, PolicyControllerConstants.getFactory().get(name));
+ PolicyControllerConstants.getFactory().destroy(controller);
+ assertThatIllegalArgumentException().isThrownBy(
+ () -> PolicyControllerConstants.getFactory().get(name));
+ }
+
+ /* ============================================================ */
+
+ /**
+ * An instance of this class is called by 'IndexedPolicyControllerFactory'.
+ * It does the build operation when the value of the 'controller.type'
+ * property matches the value of TDJAM_CONTROLLER_BUILDER_TAG.
+ */
+ public static class PolicyBuilder implements PolicyControllerFeatureApi {
+ @Override
+ public int getSequenceNumber() {
+ return 1;
+ }
+
+ @Override
+ public PolicyController beforeInstance(String name, Properties properties) {
+ if ("nondrools".equals(properties.getProperty(PROPERTY_CONTROLLER_TYPE))) {
+ return new NonDroolsPolicyController(name, properties);
+ }
+ return null;
+ }
+ }
+
+ /* ============================================================ */
+
+ /**
+ * An instance of this class is called by 'IndexedDroolsControllerFactory'.
+ * It does the build operation when the value of the 'controller.type'
+ * property matches the value of TDJAM_CONTROLLER_BUILDER_TAG.
+ */
+ public static class DroolsBuilder implements DroolsControllerFeatureApi {
+ @Override
+ public int getSequenceNumber() {
+ return 1;
+ }
+
+ @Override
+ public DroolsController beforeInstance(Properties properties,
+ String groupId, String artifactId, String version,
+ List<TopicCoderFilterConfiguration> decoderConfigurations,
+ List<TopicCoderFilterConfiguration> encoderConfigurations) throws LinkageError {
+
+ if ("nondrools".equals(properties.getProperty(PROPERTY_CONTROLLER_TYPE))) {
+ return NonDroolsPolicyController.getBuildInProgress();
+ }
+ return null;
+ }
+ }
+
+ /* ============================================================ */
+
+ public static class DroolsControllerFeatureHandler implements DroolsControllerFeatureApi {
+ static int beforeDeliverFalse = 0;
+ static int beforeDeliverTrue = 0;
+ static int beforeDeliverException = 0;
+ static int afterDeliverFalse = 0;
+ static int afterDeliverTrue = 0;
+ static int afterDeliverException = 0;
+
+ private static void resetStats() {
+ beforeDeliverFalse = 0;
+ beforeDeliverTrue = 0;
+ beforeDeliverException = 0;
+ afterDeliverFalse = 0;
+ afterDeliverTrue = 0;
+ afterDeliverException = 0;
+ }
+
+ @Override
+ public int getSequenceNumber() {
+ return 1;
+ }
+
+ @Override
+ public boolean beforeDeliver(DroolsController controller, TopicSink sink, Object fact) {
+ if (fact instanceof VirtualControlLoopNotification) {
+ String factString = ((VirtualControlLoopNotification) fact).getAai().get("signal");
+ if (factString == null) {
+ // this hook is run during 'FrankfurtTest' as well
+ return false;
+ }
+ if (factString.contains("beforeDeliverTrue")) {
+ beforeDeliverTrue += 1;
+ return true;
+ }
+ if (factString.contains("beforeDeliverException")) {
+ beforeDeliverException += 1;
+ RuntimeException ex = new RuntimeException("beforeDeliver");
+ ex.printStackTrace();
+ throw ex;
+ }
+ }
+ beforeDeliverFalse += 1;
+ return false;
+ }
+
+
+ @Override
+ public boolean afterDeliver(DroolsController controller, TopicSink sink, Object fact,
+ String json, boolean success) {
+
+ if (fact instanceof VirtualControlLoopNotification) {
+ String factString = ((VirtualControlLoopNotification) fact).getAai().get("signal");
+ if (factString == null) {
+ // this hook is run during 'FrankfurtTest' as well
+ return false;
+ }
+ if (factString.contains("afterDeliverTrue")) {
+ afterDeliverTrue += 1;
+ return true;
+ }
+ if (factString.contains("afterDeliverException")) {
+ afterDeliverException += 1;
+ throw new RuntimeException("afterDeliver");
+ }
+ }
+ afterDeliverFalse += 1;
+ return false;
+ }
+ }
+}
diff --git a/controlloop/common/controller-tdjam/src/test/resources/META-INF/services/org.onap.policy.drools.features.DroolsControllerFeatureApi b/controlloop/common/controller-tdjam/src/test/resources/META-INF/services/org.onap.policy.drools.features.DroolsControllerFeatureApi
new file mode 100644
index 000000000..bb7cf8e3f
--- /dev/null
+++ b/controlloop/common/controller-tdjam/src/test/resources/META-INF/services/org.onap.policy.drools.features.DroolsControllerFeatureApi
@@ -0,0 +1,3 @@
+org.onap.policy.extension.system.NonDroolsPolicyControllerTest$DroolsControllerFeatureHandler
+org.onap.policy.extension.system.NonDroolsPolicyControllerTest$DroolsBuilder
+org.onap.policy.controlloop.tdjam.TdjamController$DroolsBuilder
diff --git a/controlloop/common/controller-tdjam/src/test/resources/META-INF/services/org.onap.policy.drools.features.PolicyControllerFeatureApi b/controlloop/common/controller-tdjam/src/test/resources/META-INF/services/org.onap.policy.drools.features.PolicyControllerFeatureApi
new file mode 100644
index 000000000..4f2764376
--- /dev/null
+++ b/controlloop/common/controller-tdjam/src/test/resources/META-INF/services/org.onap.policy.drools.features.PolicyControllerFeatureApi
@@ -0,0 +1,2 @@
+org.onap.policy.controlloop.tdjam.TdjamController$PolicyBuilder
+org.onap.policy.extension.system.NonDroolsPolicyControllerTest$PolicyBuilder
diff --git a/controlloop/common/controller-tdjam/src/test/resources/config/event-manager.properties b/controlloop/common/controller-tdjam/src/test/resources/config/event-manager.properties
new file mode 100644
index 000000000..f5be41c35
--- /dev/null
+++ b/controlloop/common/controller-tdjam/src/test/resources/config/event-manager.properties
@@ -0,0 +1,83 @@
+#
+# ============LICENSE_START======================================================
+# ONAP
+# ===============================================================================
+# Copyright (C) 2020 AT&T Intellectual Property. All rights reserved.
+# ===============================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============LICENSE_END========================================================
+#
+
+# DB parameters
+operation.history.url=jdbc:h2:mem:Tdjam
+operation.history.userName=sa
+operation.history.password=
+
+# Actor parameters
+#
+# Note: every operation must have at least one entry, otherwise it will not be
+# configured and started. Thus some of them have a "placeholder" property.
+#
+
+#actor.service.GUARD.disabled=true
+actor.service.GUARD.clientName=GUARD
+actor.service.GUARD.onapName=my-onap-name
+actor.service.GUARD.onapComponent=my-onap-component
+actor.service.GUARD.onapInstance=my-onap-instance
+actor.service.GUARD.operations.Decision.path=decision
+
+actor.service.AAI.clientName=AAI
+actor.service.AAI.operations.CustomQuery.path=aai/v16/query
+actor.service.AAI.operations.Pnf.path=aai/v16/network/pnfs/pnf
+actor.service.AAI.operations.Tenant.path=aai/v16/search/nodes-query
+
+actor.service.APPC.sinkTopic=APPC-LCM-READ
+actor.service.APPC.sourceTopic=APPC-LCM-WRITE
+actor.service.APPC.operations.ConfigModify.placeholder=
+actor.service.APPC.operations.Migrate.placeholder=
+actor.service.APPC.operations.Restart.placeholder=
+actor.service.APPC.operations.Rebuild.placeholder=
+
+# legacy APPC - must specify sink and source for each operation
+actor.service.APPC.operations.ModifyConfig.sinkTopic=APPC-CL
+actor.service.APPC.operations.ModifyConfig.sourceTopic=APPC-CL
+
+actor.service.CDS.operations.any.host=localhost
+actor.service.CDS.operations.any.port=7878
+actor.service.CDS.operations.any.username=grpc-username
+actor.service.CDS.operations.any.password=grpc-password
+actor.service.CDS.operations.any.timeout=10
+
+actor.service.SDNC.clientName=SDNC
+actor.service.SDNC.operations.BandwidthOnDemand.path=\
+ GENERIC-RESOURCE-API:vf-module-topology-operation
+actor.service.SDNC.operations.Reroute.path=\
+ GENERIC-RESOURCE-API:network-topology-operation
+
+actor.service.SDNR.sinkTopic=SDNR-CL
+actor.service.SDNR.sourceTopic=SDNR-CL-RSP
+actor.service.SDNR.operations.any.placeholder=
+
+actor.service.SO.clientName=SO
+actor.service.SO.pollPath=orchestrationRequests/v5/
+actor.service.SO.maxPolls=20
+actor.service.SO.pollWaitSec=20
+actor.service.SO.operations.VF\ Module\ Create.path=serviceInstantiation/v7/serviceInstances
+actor.service.SO.operations.VF\ Module\ Delete.path=serviceInstances/v7
+
+actor.service.VFC.clientName=VFC
+actor.service.VFC.pollPath=jobs
+actor.service.VFC.maxPolls=20
+actor.service.VFC.pollWaitSec=20
+actor.service.VFC.operations.Restart.path=ns
+actor.service.VFC.operations.Restart.timeoutSec=60
diff --git a/controlloop/common/controller-tdjam/src/test/resources/config/tdjam-controller.properties b/controlloop/common/controller-tdjam/src/test/resources/config/tdjam-controller.properties
new file mode 100644
index 000000000..41db06c51
--- /dev/null
+++ b/controlloop/common/controller-tdjam/src/test/resources/config/tdjam-controller.properties
@@ -0,0 +1,64 @@
+#
+# ============LICENSE_START=======================================================
+# ONAP
+# ================================================================================
+# Copyright (C) 2020 AT&T Intellectual Property. All rights reserved.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============LICENSE_END=========================================================
+#
+
+controller.name=tdjam
+controller.type=tdjam
+
+rules.groupId=NonDroolsPolicyController
+rules.artifactId=tdjam
+rules.version=1.0.0
+
+noop.source.topics=DCAE_TOPIC,APPC-CL,APPC-LCM-WRITE,SDNR-CL-RSP,POLICY-CL-MGT,APPC-LCM-READ
+
+noop.source.topics.DCAE_TOPIC.events=\
+ org.onap.policy.controlloop.CanonicalOnset,org.onap.policy.controlloop.CanonicalAbated
+noop.source.topics.DCAE_TOPIC.events.org.onap.policy.controlloop.CanonicalOnset.\
+ filter=[?($.closedLoopEventStatus == 'ONSET')]
+noop.source.topics.DCAE_TOPIC.events.org.onap.policy.controlloop.CanonicalAbated.\
+ filter=[?($.closedLoopEventStatus == 'ABATED')]
+noop.source.topics.DCAE_TOPIC.events.custom.gson=org.onap.policy.controlloop.util.Serialization,gson
+
+noop.source.topics.APPC-CL.events=org.onap.policy.appc.Response,org.onap.policy.appc.Request
+noop.source.topics.APPC-CL.events.org.onap.policy.appc.Response.filter=[?($.CommonHeader && $.Status)]
+noop.source.topics.APPC-CL.events.org.onap.policy.appc.Request.filter=[?($.CommonHeader && $.Action)]
+noop.source.topics.APPC-CL.events.custom.gson=org.onap.policy.appc.util.Serialization,gsonPretty
+
+noop.source.topics.APPC-LCM-WRITE.events=org.onap.policy.appclcm.AppcLcmDmaapWrapper
+noop.source.topics.APPC-LCM-WRITE.events.org.onap.policy.appclcm.AppcLcmDmaapWrapper.filter=[?($.type == 'response')]
+noop.source.topics.APPC-LCM-WRITE.events.custom.gson=org.onap.policy.appclcm.util.Serialization,gson
+
+noop.source.topics.SDNR-CL-RSP.events=org.onap.policy.sdnr.PciResponseWrapper
+noop.source.topics.SDNR-CL-RSP.events.org.onap.policy.sdnr.PciResponseWrapper.filter=[?($.type == 'response')]
+noop.source.topics.SDNR-CL-RSP.events.custom.gson=org.onap.policy.sdnr.util.Serialization,gson
+
+noop.source.topics.POLICY-CL-MGT.events=org.onap.policy.controlloop.VirtualControlLoopNotification
+noop.source.topics.POLICY-CL-MGT.events.custom.gson=org.onap.policy.controlloop.util.Serialization,gsonPretty
+
+noop.source.topics.APPC-LCM-READ.events=org.onap.policy.appclcm.AppcLcmDmaapWrapper
+noop.source.topics.APPC-LCM-READ.events.custom.gson=org.onap.policy.appclcm.util.Serialization,gson
+
+noop.sink.topics=APPC-CL,APPC-LCM-READ,POLICY-CL-MGT,SDNR-CL,DCAE_CL_RSP
+
+noop.sink.topics.POLICY-CL-MGT.events=org.onap.policy.controlloop.VirtualControlLoopNotification
+noop.sink.topics.POLICY-CL-MGT.events.custom.gson=org.onap.policy.controlloop.util.Serialization,gsonPretty
+
+noop.sink.topics.DCAE_CL_RSP.events=org.onap.policy.controlloop.ControlLoopResponse
+noop.sink.topics.DCAE_CL_RSP.events.custom.gson=org.onap.policy.controlloop.util.Serialization,gsonPretty
+
diff --git a/controlloop/common/controller-tdjam/src/test/resources/config/tdjam-http-client.properties b/controlloop/common/controller-tdjam/src/test/resources/config/tdjam-http-client.properties
new file mode 100644
index 000000000..1e3e88cec
--- /dev/null
+++ b/controlloop/common/controller-tdjam/src/test/resources/config/tdjam-http-client.properties
@@ -0,0 +1,52 @@
+#
+# ============LICENSE_START=======================================================
+# ONAP
+# ================================================================================
+# Copyright (C) 2020 AT&T Intellectual Property. All rights reserved.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============LICENSE_END=========================================================
+#
+
+http.client.services=GUARD,AAI,SDNC,SO,VFC
+
+http.client.services.GUARD.managed=true
+http.client.services.GUARD.host=localhost
+http.client.services.GUARD.port=6669
+http.client.services.GUARD.userName=pdpx
+http.client.services.GUARD.password=pdpx
+http.client.services.GUARD.contextUriPath=policy/pdpx/v1/
+
+http.client.services.AAI.managed=true
+http.client.services.AAI.host=localhost
+http.client.services.AAI.port=6666
+http.client.services.AAI.contextUriPath=
+
+http.client.services.SDNC.managed=true
+http.client.services.SDNC.host=localhost
+http.client.services.SDNC.port=6665
+http.client.services.SDNC.userName=sdnc
+http.client.services.SDNC.password=sdnc
+http.client.services.SDNC.contextUriPath=
+
+http.client.services.SO.managed=true
+http.client.services.SO.host=localhost
+http.client.services.SO.port=6667
+http.client.services.SO.contextUriPath=
+
+http.client.services.VFC.managed=true
+http.client.services.VFC.host=localhost
+http.client.services.VFC.port=6668
+http.client.services.VFC.userName=VFC
+http.client.services.VFC.password=VFC
+http.client.services.VFC.contextUriPath=api/nslcm/v1
diff --git a/controlloop/common/controller-tdjam/src/test/resources/logback-test.xml b/controlloop/common/controller-tdjam/src/test/resources/logback-test.xml
new file mode 100644
index 000000000..656cb8136
--- /dev/null
+++ b/controlloop/common/controller-tdjam/src/test/resources/logback-test.xml
@@ -0,0 +1,38 @@
+<!--
+ ============LICENSE_START=======================================================
+ controller-tdjam
+ ================================================================================
+ Copyright (C) 2020 AT&T Intellectual Property. All rights reserved.
+ ================================================================================
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ ============LICENSE_END=========================================================
+ -->
+
+<configuration>
+ <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+ <!-- encoders are assigned the type
+ ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
+ <encoder>
+ <pattern>%d{dd-MMM-yyyy HH:mm:ss.SSS} %-5level [%thread] %logger{36} - %msg%n</pattern>
+ </encoder>
+ </appender>
+
+ <!-- the following line doesn't seem necessary, but it is needed for some reason -->
+ <logger name="org.onap.policy.controlloop.tdjam" level="debug" additivity="false">
+ <appender-ref ref="STDOUT" />
+ </logger>
+
+ <root level="debug">
+ <appender-ref ref="STDOUT" />
+ </root>
+</configuration>