From dbb701d2aae428e27c0590a42e2d371bb9bca59d Mon Sep 17 00:00:00 2001 From: Parshad Patel Date: Fri, 23 Nov 2018 15:21:20 +0900 Subject: Rename test classes in drools-pdp Make test classes name consistence Issue-ID: POLICY-1281 Change-Id: I9632831dd36b1d362aeadfb53fda600762c835ca Signed-off-by: Parshad Patel --- .../policy/drools/pooling/EndToEndFeatureTest.java | 786 +++++++++++++++++++++ .../onap/policy/drools/pooling/FeatureTest2.java | 786 --------------------- .../drools/pooling/message/BasicMessageTester.java | 244 ------- .../policy/drools/pooling/message/ForwardTest.java | 2 +- .../drools/pooling/message/HeartbeatTest.java | 2 +- .../drools/pooling/message/IdentificationTest.java | 2 +- .../policy/drools/pooling/message/LeaderTest.java | 2 +- .../policy/drools/pooling/message/MessageTest.java | 2 +- .../message/MessageWithAssignmentsTester.java | 112 --- .../policy/drools/pooling/message/OfflineTest.java | 2 +- .../policy/drools/pooling/message/QueryTest.java | 2 +- .../pooling/message/SupportBasicMessageTester.java | 244 +++++++ .../SupportMessageWithAssignmentsTester.java | 113 +++ .../drools/pooling/state/ActiveStateTest.java | 2 +- .../drools/pooling/state/BasicStateTester.java | 287 -------- .../policy/drools/pooling/state/IdleStateTest.java | 2 +- .../drools/pooling/state/InactiveStateTest.java | 2 +- .../drools/pooling/state/ProcessingStateTest.java | 2 +- .../drools/pooling/state/QueryStateTest.java | 2 +- .../drools/pooling/state/StartStateTest.java | 2 +- .../policy/drools/pooling/state/StateTest.java | 2 +- .../pooling/state/SupportBasicStateTester.java | 287 ++++++++ 22 files changed, 1444 insertions(+), 1443 deletions(-) create mode 100644 feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/EndToEndFeatureTest.java delete mode 100644 feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/FeatureTest2.java delete mode 100644 feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/BasicMessageTester.java delete mode 100644 feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/MessageWithAssignmentsTester.java create mode 100644 feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/SupportBasicMessageTester.java create mode 100644 feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/SupportMessageWithAssignmentsTester.java delete mode 100644 feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/state/BasicStateTester.java create mode 100644 feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/state/SupportBasicStateTester.java (limited to 'feature-pooling-dmaap') diff --git a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/EndToEndFeatureTest.java b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/EndToEndFeatureTest.java new file mode 100644 index 00000000..616d95fe --- /dev/null +++ b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/EndToEndFeatureTest.java @@ -0,0 +1,786 @@ +/* + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2018 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.drools.pooling; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.onap.policy.drools.pooling.PoolingProperties.PREFIX; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Deque; +import java.util.IdentityHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Properties; +import java.util.TreeMap; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure; +import org.onap.policy.common.endpoints.event.comm.TopicEndpoint; +import org.onap.policy.common.endpoints.event.comm.TopicListener; +import org.onap.policy.common.endpoints.event.comm.TopicSink; +import org.onap.policy.common.endpoints.event.comm.TopicSource; +import org.onap.policy.common.endpoints.properties.PolicyEndPointProperties; +import org.onap.policy.drools.controller.DroolsController; +import org.onap.policy.drools.system.PolicyController; +import org.onap.policy.drools.system.PolicyEngine; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * End-to-end tests of the pooling feature. Launches one or more "hosts", each one having its own + * feature object. Uses real feature objects, as well as real DMaaP sources and sinks. However, the + * following are not:
PolicyEngine, PolicyController, DroolsController
mocked
+ *
+ * + *

The following fields must be set before executing this:

+ */ +public class EndToEndFeatureTest { + + private static final Logger logger = LoggerFactory.getLogger(EndToEndFeatureTest.class); + + /** + * UEB servers for both internal & external topics. + */ + private static final String UEB_SERVERS = ""; + + /** + * Name of the topic used for inter-host communication. + */ + private static final String INTERNAL_TOPIC = ""; + + /** + * Name of the topic from which "external" events "arrive". + */ + private static final String EXTERNAL_TOPIC = ""; + + /** + * Consumer group to use when polling the external topic. + */ + private static final String EXTERNAL_GROUP = EndToEndFeatureTest.class.getName(); + + /** + * Name of the controller. + */ + private static final String CONTROLLER1 = "controller.one"; + + /** + * Maximum number of items to fetch from DMaaP in a single poll. + */ + private static final String FETCH_LIMIT = "5"; + + private static final long STD_REACTIVATE_WAIT_MS = 10000; + private static final long STD_IDENTIFICATION_MS = 10000; + private static final long STD_START_HEARTBEAT_MS = 15000; + private static final long STD_ACTIVE_HEARTBEAT_MS = 12000; + private static final long STD_INTER_HEARTBEAT_MS = 5000; + private static final long STD_OFFLINE_PUB_WAIT_MS = 2; + private static final long EVENT_WAIT_SEC = 15; + + // these are saved and restored on exit from this test class + private static PoolingFeature.Factory saveFeatureFactory; + private static PoolingManagerImpl.Factory saveManagerFactory; + private static DmaapManager.Factory saveDmaapFactory; + + /** + * Sink for external DMaaP topic. + */ + private static TopicSink externalSink; + + /** + * Sink for internal DMaaP topic. + */ + private static TopicSink internalSink; + + /** + * Context for the current test case. + */ + private Context ctx; + + /** + * Setup before class. + * + */ + @BeforeClass + public static void setUpBeforeClass() { + saveFeatureFactory = PoolingFeature.getFactory(); + saveManagerFactory = PoolingManagerImpl.getFactory(); + saveDmaapFactory = DmaapManager.getFactory(); + + externalSink = TopicEndpoint.manager.addTopicSinks(makeSinkProperties(EXTERNAL_TOPIC)).get(0); + externalSink.start(); + + internalSink = TopicEndpoint.manager.addTopicSinks(makeSinkProperties(INTERNAL_TOPIC)).get(0); + internalSink.start(); + } + + /** + * Tear down after class. + * + */ + @AfterClass + public static void tearDownAfterClass() { + PoolingFeature.setFactory(saveFeatureFactory); + PoolingManagerImpl.setFactory(saveManagerFactory); + DmaapManager.setFactory(saveDmaapFactory); + + externalSink.stop(); + internalSink.stop(); + } + + /** + * Setup. + */ + @Before + public void setUp() { + ctx = null; + } + + /** + * Tear down. + */ + @After + public void tearDown() { + if (ctx != null) { + ctx.destroy(); + } + } + + @Ignore + @Test + public void test_SingleHost() throws Exception { + run(70, 1); + } + + @Ignore + @Test + public void test_TwoHosts() throws Exception { + run(200, 2); + } + + @Ignore + @Test + public void test_ThreeHosts() throws Exception { + run(200, 3); + } + + private void run(int nmessages, int nhosts) throws Exception { + ctx = new Context(nmessages); + + for (int x = 0; x < nhosts; ++x) { + ctx.addHost(); + } + + ctx.startHosts(); + ctx.awaitAllActive(STD_IDENTIFICATION_MS * 2); + + for (int x = 0; x < nmessages; ++x) { + ctx.offerExternal(makeMessage(x)); + } + + ctx.awaitEvents(EVENT_WAIT_SEC, TimeUnit.SECONDS); + + assertEquals(0, ctx.getDecodeErrors()); + assertEquals(0, ctx.getRemainingEvents()); + ctx.checkAllSawAMsg(); + } + + private String makeMessage(int reqnum) { + return "{\"reqid\":\"req" + reqnum + "\", \"data\":\"hello " + reqnum + "\"}"; + } + + private static Properties makeSinkProperties(String topic) { + Properties props = new Properties(); + + props.setProperty(PolicyEndPointProperties.PROPERTY_UEB_SINK_TOPICS, topic); + + props.setProperty(PolicyEndPointProperties.PROPERTY_UEB_SINK_TOPICS + "." + topic + + PolicyEndPointProperties.PROPERTY_TOPIC_SERVERS_SUFFIX, UEB_SERVERS); + props.setProperty(PolicyEndPointProperties.PROPERTY_UEB_SINK_TOPICS + "." + topic + + PolicyEndPointProperties.PROPERTY_TOPIC_SINK_PARTITION_KEY_SUFFIX, "0"); + props.setProperty(PolicyEndPointProperties.PROPERTY_UEB_SINK_TOPICS + "." + topic + + PolicyEndPointProperties.PROPERTY_MANAGED_SUFFIX, "false"); + + return props; + } + + private static Properties makeSourceProperties(String topic) { + Properties props = new Properties(); + + props.setProperty(PolicyEndPointProperties.PROPERTY_UEB_SOURCE_TOPICS, topic); + + props.setProperty(PolicyEndPointProperties.PROPERTY_UEB_SOURCE_TOPICS + "." + topic + + PolicyEndPointProperties.PROPERTY_TOPIC_SERVERS_SUFFIX, UEB_SERVERS); + props.setProperty(PolicyEndPointProperties.PROPERTY_UEB_SOURCE_TOPICS + "." + topic + + PolicyEndPointProperties.PROPERTY_TOPIC_SOURCE_FETCH_LIMIT_SUFFIX, FETCH_LIMIT); + props.setProperty(PolicyEndPointProperties.PROPERTY_UEB_SOURCE_TOPICS + "." + topic + + PolicyEndPointProperties.PROPERTY_MANAGED_SUFFIX, "false"); + + if (EXTERNAL_TOPIC.equals(topic)) { + // consumer group is a constant + props.setProperty(PolicyEndPointProperties.PROPERTY_UEB_SOURCE_TOPICS + "." + topic + + PolicyEndPointProperties.PROPERTY_TOPIC_SOURCE_CONSUMER_GROUP_SUFFIX, EXTERNAL_GROUP); + + // consumer instance is generated by the BusConsumer code + } + + // else internal topic: feature populates info for internal topic + + return props; + } + + /** + * Context used for a single test case. + */ + private static class Context { + + private final FeatureFactory featureFactory; + private final ManagerFactory managerFactory; + + /** + * Hosts that have been added to this context. + */ + private final Deque hosts = new LinkedList<>(); + + /** + * Maps a drools controller to its policy controller. + */ + private final IdentityHashMap drools2policy = new IdentityHashMap<>(); + + /** + * Counts the number of decode errors. + */ + private final AtomicInteger decodeErrors = new AtomicInteger(0); + + /** + * Number of events we're still waiting to receive. + */ + private final CountDownLatch eventCounter; + + /** + * Constructor. + * + * @param nEvents number of events to be processed + */ + public Context(int events) { + featureFactory = new FeatureFactory(this); + managerFactory = new ManagerFactory(this); + eventCounter = new CountDownLatch(events); + + PoolingFeature.setFactory(featureFactory); + PoolingManagerImpl.setFactory(managerFactory); + } + + /** + * Destroys the context, stopping any hosts that remain. + */ + public void destroy() { + stopHosts(); + hosts.clear(); + } + + /** + * Creates and adds a new host to the context. + * + * @return the new Host + */ + public Host addHost() { + Host host = new Host(this); + hosts.add(host); + + return host; + } + + /** + * Starts the hosts. + */ + public void startHosts() { + hosts.forEach(host -> host.start()); + } + + /** + * Stops the hosts. + */ + public void stopHosts() { + hosts.forEach(host -> host.stop()); + } + + /** + * Verifies that all hosts processed at least one message. + */ + public void checkAllSawAMsg() { + int msgs = 0; + for (Host host : hosts) { + assertTrue("msgs=" + msgs, host.messageSeen()); + ++msgs; + } + } + + /** + * Offers an event to the external topic. + * + * @param event event + */ + public void offerExternal(String event) { + externalSink.send(event); + } + + /** + * Decodes an event. + * + * @param event event + * @return the decoded event, or {@code null} if it cannot be decoded + */ + public Object decodeEvent(String event) { + return managerFactory.decodeEvent(null, null, event); + } + + /** + * Associates a controller with its drools controller. + * + * @param controller controller + * @param droolsController drools controller + */ + public void addController(PolicyController controller, DroolsController droolsController) { + drools2policy.put(droolsController, controller); + } + + /** + * Get controller. + * + * @param droolsController drools controller + * @return the controller associated with a drools controller, or {@code null} if it has no + * associated controller + */ + public PolicyController getController(DroolsController droolsController) { + return drools2policy.get(droolsController); + } + + /** + * Get decode errors. + * + * @return the number of decode errors so far + */ + public int getDecodeErrors() { + return decodeErrors.get(); + } + + /** + * Increments the count of decode errors. + */ + public void bumpDecodeErrors() { + decodeErrors.incrementAndGet(); + } + + /** + * Get remaining events. + * + * @return the number of events that haven't been processed + */ + public long getRemainingEvents() { + return eventCounter.getCount(); + } + + /** + * Adds an event to the counter. + */ + public void addEvent() { + eventCounter.countDown(); + } + + /** + * Waits, for a period of time, for all events to be processed. + * + * @param time time + * @param units units + * @return {@code true} if all events have been processed, {@code false} otherwise + * @throws InterruptedException throws interrupted exception + */ + public boolean awaitEvents(long time, TimeUnit units) throws InterruptedException { + return eventCounter.await(time, units); + } + + /** + * Waits, for a period of time, for all hosts to enter the Active state. + * + * @param timeMs maximum time to wait, in milliseconds + * @throws InterruptedException throws interrupted exception + */ + public void awaitAllActive(long timeMs) throws InterruptedException { + long tend = timeMs + System.currentTimeMillis(); + + for (Host host : hosts) { + long tremain = Math.max(0, tend - System.currentTimeMillis()); + assertTrue(host.awaitActive(tremain)); + } + } + } + + /** + * Simulates a single "host". + */ + private static class Host { + + private final PoolingFeature feature = new PoolingFeature(); + + /** + * {@code True} if this host has processed a message, {@code false} otherwise. + */ + private final AtomicBoolean sawMsg = new AtomicBoolean(false); + + private final TopicSource externalSource; + private final TopicSource internalSource; + + // mock objects + private final PolicyEngine engine = mock(PolicyEngine.class); + private final ListenerController controller = mock(ListenerController.class); + private final DroolsController drools = mock(DroolsController.class); + + /** + * Constructor. + * + * @param context context + */ + public Host(Context context) { + + when(controller.getName()).thenReturn(CONTROLLER1); + when(controller.getDrools()).thenReturn(drools); + + externalSource = TopicEndpoint.manager.addTopicSources(makeSourceProperties(EXTERNAL_TOPIC)).get(0); + internalSource = TopicEndpoint.manager.addTopicSources(makeSourceProperties(INTERNAL_TOPIC)).get(0); + + // stop consuming events if the controller stops + when(controller.stop()).thenAnswer(args -> { + externalSource.unregister(controller); + return true; + }); + + doAnswer(new MyExternalTopicListener(context, this)).when(controller).onTopicEvent(any(), any(), any()); + + context.addController(controller, drools); + } + + /** + * Waits, for a period of time, for the host to enter the Active state. + * + * @param timeMs time to wait, in milliseconds + * @return {@code true} if the host entered the Active state within the given amount of + * time, {@code false} otherwise + * @throws InterruptedException throws interrupted exception + */ + public boolean awaitActive(long timeMs) throws InterruptedException { + return feature.getActiveLatch().await(timeMs, TimeUnit.MILLISECONDS); + } + + /** + * Starts threads for the host so that it begins consuming from both the external "DMaaP" + * topic and its own internal "DMaaP" topic. + */ + public void start() { + DmaapManager.setFactory(new DmaapManager.Factory() { + @Override + public List getTopicSources() { + return Arrays.asList(internalSource, externalSource); + } + + @Override + public List getTopicSinks() { + return Arrays.asList(internalSink, externalSink); + } + }); + + feature.beforeStart(engine); + feature.afterCreate(controller); + + feature.beforeStart(controller); + + // start consuming events from the external topic + externalSource.register(controller); + + feature.afterStart(controller); + } + + /** + * Stops the host's threads. + */ + public void stop() { + feature.beforeStop(controller); + externalSource.unregister(controller); + feature.afterStop(controller); + } + + /** + * Offers an event to the feature, before the policy controller handles it. + * + * @param protocol protocol + * @param topic2 topic + * @param event event + * @return {@code true} if the event was handled, {@code false} otherwise + */ + public boolean beforeOffer(CommInfrastructure protocol, String topic2, String event) { + return feature.beforeOffer(controller, protocol, topic2, event); + } + + /** + * Offers an event to the feature, after the policy controller handles it. + * + * @param protocol protocol + * @param topic topic + * @param event event + * @param success success + * @return {@code true} if the event was handled, {@code false} otherwise + */ + public boolean afterOffer(CommInfrastructure protocol, String topic, String event, boolean success) { + + return feature.afterOffer(controller, protocol, topic, event, success); + } + + /** + * Offers an event to the feature, before the drools controller handles it. + * + * @param fact fact + * @return {@code true} if the event was handled, {@code false} otherwise + */ + public boolean beforeInsert(Object fact) { + return feature.beforeInsert(drools, fact); + } + + /** + * Offers an event to the feature, after the drools controller handles it. + * + * @param fact fact + * @param successInsert {@code true} if it was successfully inserted by the drools + * controller, {@code false} otherwise + * @return {@code true} if the event was handled, {@code false} otherwise + */ + public boolean afterInsert(Object fact, boolean successInsert) { + return feature.afterInsert(drools, fact, successInsert); + } + + /** + * Indicates that a message was seen for this host. + */ + public void sawMessage() { + sawMsg.set(true); + } + + /** + * Message seen. + * + * @return {@code true} if a message was seen for this host, {@code false} otherwise + */ + public boolean messageSeen() { + return sawMsg.get(); + } + } + + /** + * Listener for the external topic. Simulates the actions taken by + * AggregatedPolicyController.onTopicEvent. + */ + private static class MyExternalTopicListener implements Answer { + + private final Context context; + private final Host host; + + public MyExternalTopicListener(Context context, Host host) { + this.context = context; + this.host = host; + } + + @Override + public Void answer(InvocationOnMock args) throws Throwable { + int index = 0; + CommInfrastructure commType = args.getArgument(index++); + String topic = args.getArgument(index++); + String event = args.getArgument(index++); + + if (host.beforeOffer(commType, topic, event)) { + return null; + } + + boolean result; + Object fact = context.decodeEvent(event); + + if (fact == null) { + result = false; + context.bumpDecodeErrors(); + + } else { + result = true; + + if (!host.beforeInsert(fact)) { + // feature did not handle it so we handle it here + host.afterInsert(fact, result); + + host.sawMessage(); + context.addEvent(); + } + } + + host.afterOffer(commType, topic, event, result); + return null; + } + } + + /** + * Simulator for the feature-level factory. + */ + private static class FeatureFactory extends PoolingFeature.Factory { + + private final Context context; + + /** + * Constructor. + * + * @param context context + */ + public FeatureFactory(Context context) { + this.context = context; + + /* + * Note: do NOT extract anything from "context" at this point, because it hasn't been + * fully initialized yet + */ + } + + @Override + public Properties getProperties(String featName) { + Properties props = new Properties(); + + props.setProperty(PoolingProperties.PROP_EXTRACTOR_PREFIX + ".java.util.Map", "${reqid}"); + + props.setProperty(specialize(PoolingProperties.FEATURE_ENABLED, CONTROLLER1), "true"); + props.setProperty(specialize(PoolingProperties.POOLING_TOPIC, CONTROLLER1), INTERNAL_TOPIC); + props.setProperty(specialize(PoolingProperties.OFFLINE_LIMIT, CONTROLLER1), "10000"); + props.setProperty(specialize(PoolingProperties.OFFLINE_AGE_MS, CONTROLLER1), "1000000"); + props.setProperty(specialize(PoolingProperties.OFFLINE_PUB_WAIT_MS, CONTROLLER1), + "" + STD_OFFLINE_PUB_WAIT_MS); + props.setProperty(specialize(PoolingProperties.START_HEARTBEAT_MS, CONTROLLER1), + "" + STD_START_HEARTBEAT_MS); + props.setProperty(specialize(PoolingProperties.REACTIVATE_MS, CONTROLLER1), "" + STD_REACTIVATE_WAIT_MS); + props.setProperty(specialize(PoolingProperties.IDENTIFICATION_MS, CONTROLLER1), "" + STD_IDENTIFICATION_MS); + props.setProperty(specialize(PoolingProperties.ACTIVE_HEARTBEAT_MS, CONTROLLER1), + "" + STD_ACTIVE_HEARTBEAT_MS); + props.setProperty(specialize(PoolingProperties.INTER_HEARTBEAT_MS, CONTROLLER1), + "" + STD_INTER_HEARTBEAT_MS); + + props.putAll(makeSinkProperties(INTERNAL_TOPIC)); + props.putAll(makeSourceProperties(INTERNAL_TOPIC)); + + return props; + } + + @Override + public PolicyController getController(DroolsController droolsController) { + return context.getController(droolsController); + } + + /** + * Embeds a specializer within a property name, after the prefix. + * + * @param propnm property name into which it should be embedded + * @param spec specializer to be embedded + * @return the property name, with the specializer embedded within it + */ + private String specialize(String propnm, String spec) { + String suffix = propnm.substring(PREFIX.length()); + return PREFIX + spec + "." + suffix; + } + } + + /** + * Simulator for the pooling manager factory. + */ + private static class ManagerFactory extends PoolingManagerImpl.Factory { + + /** + * Used to decode events from the external topic. + */ + private final ThreadLocal mapper = new ThreadLocal() { + @Override + protected ObjectMapper initialValue() { + return new ObjectMapper(); + } + }; + + /** + * Used to decode events into a Map. + */ + private final TypeReference> typeRef = new TypeReference>() {}; + + /** + * Constructor. + * + * @param context context + */ + public ManagerFactory(Context context) { + + /* + * Note: do NOT extract anything from "context" at this point, because it hasn't been + * fully initialized yet + */ + } + + @Override + public boolean canDecodeEvent(DroolsController drools, String topic) { + return true; + } + + @Override + public Object decodeEvent(DroolsController drools, String topic, String event) { + try { + return mapper.get().readValue(event, typeRef); + + } catch (IOException e) { + logger.warn("cannot decode external event", e); + return null; + } + } + } + + /** + * Controller that also implements the {@link TopicListener} interface. + */ + private static interface ListenerController extends PolicyController, TopicListener { + + } +} diff --git a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/FeatureTest2.java b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/FeatureTest2.java deleted file mode 100644 index 050ca612..00000000 --- a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/FeatureTest2.java +++ /dev/null @@ -1,786 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * ONAP - * ================================================================================ - * Copyright (C) 2018 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.drools.pooling; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import static org.onap.policy.drools.pooling.PoolingProperties.PREFIX; - -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; - -import java.io.IOException; -import java.util.Arrays; -import java.util.Deque; -import java.util.IdentityHashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Properties; -import java.util.TreeMap; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; - -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Ignore; -import org.junit.Test; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; -import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure; -import org.onap.policy.common.endpoints.event.comm.TopicEndpoint; -import org.onap.policy.common.endpoints.event.comm.TopicListener; -import org.onap.policy.common.endpoints.event.comm.TopicSink; -import org.onap.policy.common.endpoints.event.comm.TopicSource; -import org.onap.policy.common.endpoints.properties.PolicyEndPointProperties; -import org.onap.policy.drools.controller.DroolsController; -import org.onap.policy.drools.system.PolicyController; -import org.onap.policy.drools.system.PolicyEngine; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * End-to-end tests of the pooling feature. Launches one or more "hosts", each one having its own - * feature object. Uses real feature objects, as well as real DMaaP sources and sinks. However, the - * following are not:
PolicyEngine, PolicyController, DroolsController
mocked
- *
- * - *

The following fields must be set before executing this:

  • UEB_SERVERS
  • - *
  • INTERNAL_TOPIC
  • EXTERNAL_TOPIC
- */ -public class FeatureTest2 { - - private static final Logger logger = LoggerFactory.getLogger(FeatureTest2.class); - - /** - * UEB servers for both internal & external topics. - */ - private static final String UEB_SERVERS = ""; - - /** - * Name of the topic used for inter-host communication. - */ - private static final String INTERNAL_TOPIC = ""; - - /** - * Name of the topic from which "external" events "arrive". - */ - private static final String EXTERNAL_TOPIC = ""; - - /** - * Consumer group to use when polling the external topic. - */ - private static final String EXTERNAL_GROUP = FeatureTest2.class.getName(); - - /** - * Name of the controller. - */ - private static final String CONTROLLER1 = "controller.one"; - - /** - * Maximum number of items to fetch from DMaaP in a single poll. - */ - private static final String FETCH_LIMIT = "5"; - - private static final long STD_REACTIVATE_WAIT_MS = 10000; - private static final long STD_IDENTIFICATION_MS = 10000; - private static final long STD_START_HEARTBEAT_MS = 15000; - private static final long STD_ACTIVE_HEARTBEAT_MS = 12000; - private static final long STD_INTER_HEARTBEAT_MS = 5000; - private static final long STD_OFFLINE_PUB_WAIT_MS = 2; - private static final long EVENT_WAIT_SEC = 15; - - // these are saved and restored on exit from this test class - private static PoolingFeature.Factory saveFeatureFactory; - private static PoolingManagerImpl.Factory saveManagerFactory; - private static DmaapManager.Factory saveDmaapFactory; - - /** - * Sink for external DMaaP topic. - */ - private static TopicSink externalSink; - - /** - * Sink for internal DMaaP topic. - */ - private static TopicSink internalSink; - - /** - * Context for the current test case. - */ - private Context ctx; - - /** - * Setup before class. - * - */ - @BeforeClass - public static void setUpBeforeClass() { - saveFeatureFactory = PoolingFeature.getFactory(); - saveManagerFactory = PoolingManagerImpl.getFactory(); - saveDmaapFactory = DmaapManager.getFactory(); - - externalSink = TopicEndpoint.manager.addTopicSinks(makeSinkProperties(EXTERNAL_TOPIC)).get(0); - externalSink.start(); - - internalSink = TopicEndpoint.manager.addTopicSinks(makeSinkProperties(INTERNAL_TOPIC)).get(0); - internalSink.start(); - } - - /** - * Tear down after class. - * - */ - @AfterClass - public static void tearDownAfterClass() { - PoolingFeature.setFactory(saveFeatureFactory); - PoolingManagerImpl.setFactory(saveManagerFactory); - DmaapManager.setFactory(saveDmaapFactory); - - externalSink.stop(); - internalSink.stop(); - } - - /** - * Setup. - */ - @Before - public void setUp() { - ctx = null; - } - - /** - * Tear down. - */ - @After - public void tearDown() { - if (ctx != null) { - ctx.destroy(); - } - } - - @Ignore - @Test - public void test_SingleHost() throws Exception { - run(70, 1); - } - - @Ignore - @Test - public void test_TwoHosts() throws Exception { - run(200, 2); - } - - @Ignore - @Test - public void test_ThreeHosts() throws Exception { - run(200, 3); - } - - private void run(int nmessages, int nhosts) throws Exception { - ctx = new Context(nmessages); - - for (int x = 0; x < nhosts; ++x) { - ctx.addHost(); - } - - ctx.startHosts(); - ctx.awaitAllActive(STD_IDENTIFICATION_MS * 2); - - for (int x = 0; x < nmessages; ++x) { - ctx.offerExternal(makeMessage(x)); - } - - ctx.awaitEvents(EVENT_WAIT_SEC, TimeUnit.SECONDS); - - assertEquals(0, ctx.getDecodeErrors()); - assertEquals(0, ctx.getRemainingEvents()); - ctx.checkAllSawAMsg(); - } - - private String makeMessage(int reqnum) { - return "{\"reqid\":\"req" + reqnum + "\", \"data\":\"hello " + reqnum + "\"}"; - } - - private static Properties makeSinkProperties(String topic) { - Properties props = new Properties(); - - props.setProperty(PolicyEndPointProperties.PROPERTY_UEB_SINK_TOPICS, topic); - - props.setProperty(PolicyEndPointProperties.PROPERTY_UEB_SINK_TOPICS + "." + topic - + PolicyEndPointProperties.PROPERTY_TOPIC_SERVERS_SUFFIX, UEB_SERVERS); - props.setProperty(PolicyEndPointProperties.PROPERTY_UEB_SINK_TOPICS + "." + topic - + PolicyEndPointProperties.PROPERTY_TOPIC_SINK_PARTITION_KEY_SUFFIX, "0"); - props.setProperty(PolicyEndPointProperties.PROPERTY_UEB_SINK_TOPICS + "." + topic - + PolicyEndPointProperties.PROPERTY_MANAGED_SUFFIX, "false"); - - return props; - } - - private static Properties makeSourceProperties(String topic) { - Properties props = new Properties(); - - props.setProperty(PolicyEndPointProperties.PROPERTY_UEB_SOURCE_TOPICS, topic); - - props.setProperty(PolicyEndPointProperties.PROPERTY_UEB_SOURCE_TOPICS + "." + topic - + PolicyEndPointProperties.PROPERTY_TOPIC_SERVERS_SUFFIX, UEB_SERVERS); - props.setProperty(PolicyEndPointProperties.PROPERTY_UEB_SOURCE_TOPICS + "." + topic - + PolicyEndPointProperties.PROPERTY_TOPIC_SOURCE_FETCH_LIMIT_SUFFIX, FETCH_LIMIT); - props.setProperty(PolicyEndPointProperties.PROPERTY_UEB_SOURCE_TOPICS + "." + topic - + PolicyEndPointProperties.PROPERTY_MANAGED_SUFFIX, "false"); - - if (EXTERNAL_TOPIC.equals(topic)) { - // consumer group is a constant - props.setProperty(PolicyEndPointProperties.PROPERTY_UEB_SOURCE_TOPICS + "." + topic - + PolicyEndPointProperties.PROPERTY_TOPIC_SOURCE_CONSUMER_GROUP_SUFFIX, EXTERNAL_GROUP); - - // consumer instance is generated by the BusConsumer code - } - - // else internal topic: feature populates info for internal topic - - return props; - } - - /** - * Context used for a single test case. - */ - private static class Context { - - private final FeatureFactory featureFactory; - private final ManagerFactory managerFactory; - - /** - * Hosts that have been added to this context. - */ - private final Deque hosts = new LinkedList<>(); - - /** - * Maps a drools controller to its policy controller. - */ - private final IdentityHashMap drools2policy = new IdentityHashMap<>(); - - /** - * Counts the number of decode errors. - */ - private final AtomicInteger decodeErrors = new AtomicInteger(0); - - /** - * Number of events we're still waiting to receive. - */ - private final CountDownLatch eventCounter; - - /** - * Constructor. - * - * @param nEvents number of events to be processed - */ - public Context(int events) { - featureFactory = new FeatureFactory(this); - managerFactory = new ManagerFactory(this); - eventCounter = new CountDownLatch(events); - - PoolingFeature.setFactory(featureFactory); - PoolingManagerImpl.setFactory(managerFactory); - } - - /** - * Destroys the context, stopping any hosts that remain. - */ - public void destroy() { - stopHosts(); - hosts.clear(); - } - - /** - * Creates and adds a new host to the context. - * - * @return the new Host - */ - public Host addHost() { - Host host = new Host(this); - hosts.add(host); - - return host; - } - - /** - * Starts the hosts. - */ - public void startHosts() { - hosts.forEach(host -> host.start()); - } - - /** - * Stops the hosts. - */ - public void stopHosts() { - hosts.forEach(host -> host.stop()); - } - - /** - * Verifies that all hosts processed at least one message. - */ - public void checkAllSawAMsg() { - int msgs = 0; - for (Host host : hosts) { - assertTrue("msgs=" + msgs, host.messageSeen()); - ++msgs; - } - } - - /** - * Offers an event to the external topic. - * - * @param event event - */ - public void offerExternal(String event) { - externalSink.send(event); - } - - /** - * Decodes an event. - * - * @param event event - * @return the decoded event, or {@code null} if it cannot be decoded - */ - public Object decodeEvent(String event) { - return managerFactory.decodeEvent(null, null, event); - } - - /** - * Associates a controller with its drools controller. - * - * @param controller controller - * @param droolsController drools controller - */ - public void addController(PolicyController controller, DroolsController droolsController) { - drools2policy.put(droolsController, controller); - } - - /** - * Get controller. - * - * @param droolsController drools controller - * @return the controller associated with a drools controller, or {@code null} if it has no - * associated controller - */ - public PolicyController getController(DroolsController droolsController) { - return drools2policy.get(droolsController); - } - - /** - * Get decode errors. - * - * @return the number of decode errors so far - */ - public int getDecodeErrors() { - return decodeErrors.get(); - } - - /** - * Increments the count of decode errors. - */ - public void bumpDecodeErrors() { - decodeErrors.incrementAndGet(); - } - - /** - * Get remaining events. - * - * @return the number of events that haven't been processed - */ - public long getRemainingEvents() { - return eventCounter.getCount(); - } - - /** - * Adds an event to the counter. - */ - public void addEvent() { - eventCounter.countDown(); - } - - /** - * Waits, for a period of time, for all events to be processed. - * - * @param time time - * @param units units - * @return {@code true} if all events have been processed, {@code false} otherwise - * @throws InterruptedException throws interrupted exception - */ - public boolean awaitEvents(long time, TimeUnit units) throws InterruptedException { - return eventCounter.await(time, units); - } - - /** - * Waits, for a period of time, for all hosts to enter the Active state. - * - * @param timeMs maximum time to wait, in milliseconds - * @throws InterruptedException throws interrupted exception - */ - public void awaitAllActive(long timeMs) throws InterruptedException { - long tend = timeMs + System.currentTimeMillis(); - - for (Host host : hosts) { - long tremain = Math.max(0, tend - System.currentTimeMillis()); - assertTrue(host.awaitActive(tremain)); - } - } - } - - /** - * Simulates a single "host". - */ - private static class Host { - - private final PoolingFeature feature = new PoolingFeature(); - - /** - * {@code True} if this host has processed a message, {@code false} otherwise. - */ - private final AtomicBoolean sawMsg = new AtomicBoolean(false); - - private final TopicSource externalSource; - private final TopicSource internalSource; - - // mock objects - private final PolicyEngine engine = mock(PolicyEngine.class); - private final ListenerController controller = mock(ListenerController.class); - private final DroolsController drools = mock(DroolsController.class); - - /** - * Constructor. - * - * @param context context - */ - public Host(Context context) { - - when(controller.getName()).thenReturn(CONTROLLER1); - when(controller.getDrools()).thenReturn(drools); - - externalSource = TopicEndpoint.manager.addTopicSources(makeSourceProperties(EXTERNAL_TOPIC)).get(0); - internalSource = TopicEndpoint.manager.addTopicSources(makeSourceProperties(INTERNAL_TOPIC)).get(0); - - // stop consuming events if the controller stops - when(controller.stop()).thenAnswer(args -> { - externalSource.unregister(controller); - return true; - }); - - doAnswer(new MyExternalTopicListener(context, this)).when(controller).onTopicEvent(any(), any(), any()); - - context.addController(controller, drools); - } - - /** - * Waits, for a period of time, for the host to enter the Active state. - * - * @param timeMs time to wait, in milliseconds - * @return {@code true} if the host entered the Active state within the given amount of - * time, {@code false} otherwise - * @throws InterruptedException throws interrupted exception - */ - public boolean awaitActive(long timeMs) throws InterruptedException { - return feature.getActiveLatch().await(timeMs, TimeUnit.MILLISECONDS); - } - - /** - * Starts threads for the host so that it begins consuming from both the external "DMaaP" - * topic and its own internal "DMaaP" topic. - */ - public void start() { - DmaapManager.setFactory(new DmaapManager.Factory() { - @Override - public List getTopicSources() { - return Arrays.asList(internalSource, externalSource); - } - - @Override - public List getTopicSinks() { - return Arrays.asList(internalSink, externalSink); - } - }); - - feature.beforeStart(engine); - feature.afterCreate(controller); - - feature.beforeStart(controller); - - // start consuming events from the external topic - externalSource.register(controller); - - feature.afterStart(controller); - } - - /** - * Stops the host's threads. - */ - public void stop() { - feature.beforeStop(controller); - externalSource.unregister(controller); - feature.afterStop(controller); - } - - /** - * Offers an event to the feature, before the policy controller handles it. - * - * @param protocol protocol - * @param topic2 topic - * @param event event - * @return {@code true} if the event was handled, {@code false} otherwise - */ - public boolean beforeOffer(CommInfrastructure protocol, String topic2, String event) { - return feature.beforeOffer(controller, protocol, topic2, event); - } - - /** - * Offers an event to the feature, after the policy controller handles it. - * - * @param protocol protocol - * @param topic topic - * @param event event - * @param success success - * @return {@code true} if the event was handled, {@code false} otherwise - */ - public boolean afterOffer(CommInfrastructure protocol, String topic, String event, boolean success) { - - return feature.afterOffer(controller, protocol, topic, event, success); - } - - /** - * Offers an event to the feature, before the drools controller handles it. - * - * @param fact fact - * @return {@code true} if the event was handled, {@code false} otherwise - */ - public boolean beforeInsert(Object fact) { - return feature.beforeInsert(drools, fact); - } - - /** - * Offers an event to the feature, after the drools controller handles it. - * - * @param fact fact - * @param successInsert {@code true} if it was successfully inserted by the drools - * controller, {@code false} otherwise - * @return {@code true} if the event was handled, {@code false} otherwise - */ - public boolean afterInsert(Object fact, boolean successInsert) { - return feature.afterInsert(drools, fact, successInsert); - } - - /** - * Indicates that a message was seen for this host. - */ - public void sawMessage() { - sawMsg.set(true); - } - - /** - * Message seen. - * - * @return {@code true} if a message was seen for this host, {@code false} otherwise - */ - public boolean messageSeen() { - return sawMsg.get(); - } - } - - /** - * Listener for the external topic. Simulates the actions taken by - * AggregatedPolicyController.onTopicEvent. - */ - private static class MyExternalTopicListener implements Answer { - - private final Context context; - private final Host host; - - public MyExternalTopicListener(Context context, Host host) { - this.context = context; - this.host = host; - } - - @Override - public Void answer(InvocationOnMock args) throws Throwable { - int index = 0; - CommInfrastructure commType = args.getArgument(index++); - String topic = args.getArgument(index++); - String event = args.getArgument(index++); - - if (host.beforeOffer(commType, topic, event)) { - return null; - } - - boolean result; - Object fact = context.decodeEvent(event); - - if (fact == null) { - result = false; - context.bumpDecodeErrors(); - - } else { - result = true; - - if (!host.beforeInsert(fact)) { - // feature did not handle it so we handle it here - host.afterInsert(fact, result); - - host.sawMessage(); - context.addEvent(); - } - } - - host.afterOffer(commType, topic, event, result); - return null; - } - } - - /** - * Simulator for the feature-level factory. - */ - private static class FeatureFactory extends PoolingFeature.Factory { - - private final Context context; - - /** - * Constructor. - * - * @param context context - */ - public FeatureFactory(Context context) { - this.context = context; - - /* - * Note: do NOT extract anything from "context" at this point, because it hasn't been - * fully initialized yet - */ - } - - @Override - public Properties getProperties(String featName) { - Properties props = new Properties(); - - props.setProperty(PoolingProperties.PROP_EXTRACTOR_PREFIX + ".java.util.Map", "${reqid}"); - - props.setProperty(specialize(PoolingProperties.FEATURE_ENABLED, CONTROLLER1), "true"); - props.setProperty(specialize(PoolingProperties.POOLING_TOPIC, CONTROLLER1), INTERNAL_TOPIC); - props.setProperty(specialize(PoolingProperties.OFFLINE_LIMIT, CONTROLLER1), "10000"); - props.setProperty(specialize(PoolingProperties.OFFLINE_AGE_MS, CONTROLLER1), "1000000"); - props.setProperty(specialize(PoolingProperties.OFFLINE_PUB_WAIT_MS, CONTROLLER1), - "" + STD_OFFLINE_PUB_WAIT_MS); - props.setProperty(specialize(PoolingProperties.START_HEARTBEAT_MS, CONTROLLER1), - "" + STD_START_HEARTBEAT_MS); - props.setProperty(specialize(PoolingProperties.REACTIVATE_MS, CONTROLLER1), "" + STD_REACTIVATE_WAIT_MS); - props.setProperty(specialize(PoolingProperties.IDENTIFICATION_MS, CONTROLLER1), "" + STD_IDENTIFICATION_MS); - props.setProperty(specialize(PoolingProperties.ACTIVE_HEARTBEAT_MS, CONTROLLER1), - "" + STD_ACTIVE_HEARTBEAT_MS); - props.setProperty(specialize(PoolingProperties.INTER_HEARTBEAT_MS, CONTROLLER1), - "" + STD_INTER_HEARTBEAT_MS); - - props.putAll(makeSinkProperties(INTERNAL_TOPIC)); - props.putAll(makeSourceProperties(INTERNAL_TOPIC)); - - return props; - } - - @Override - public PolicyController getController(DroolsController droolsController) { - return context.getController(droolsController); - } - - /** - * Embeds a specializer within a property name, after the prefix. - * - * @param propnm property name into which it should be embedded - * @param spec specializer to be embedded - * @return the property name, with the specializer embedded within it - */ - private String specialize(String propnm, String spec) { - String suffix = propnm.substring(PREFIX.length()); - return PREFIX + spec + "." + suffix; - } - } - - /** - * Simulator for the pooling manager factory. - */ - private static class ManagerFactory extends PoolingManagerImpl.Factory { - - /** - * Used to decode events from the external topic. - */ - private final ThreadLocal mapper = new ThreadLocal() { - @Override - protected ObjectMapper initialValue() { - return new ObjectMapper(); - } - }; - - /** - * Used to decode events into a Map. - */ - private final TypeReference> typeRef = new TypeReference>() {}; - - /** - * Constructor. - * - * @param context context - */ - public ManagerFactory(Context context) { - - /* - * Note: do NOT extract anything from "context" at this point, because it hasn't been - * fully initialized yet - */ - } - - @Override - public boolean canDecodeEvent(DroolsController drools, String topic) { - return true; - } - - @Override - public Object decodeEvent(DroolsController drools, String topic, String event) { - try { - return mapper.get().readValue(event, typeRef); - - } catch (IOException e) { - logger.warn("cannot decode external event", e); - return null; - } - } - } - - /** - * Controller that also implements the {@link TopicListener} interface. - */ - private static interface ListenerController extends PolicyController, TopicListener { - - } -} diff --git a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/BasicMessageTester.java b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/BasicMessageTester.java deleted file mode 100644 index 2dab38d1..00000000 --- a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/BasicMessageTester.java +++ /dev/null @@ -1,244 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * ONAP - * ================================================================================ - * Copyright (C) 2018 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.drools.pooling.message; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; -import org.onap.policy.drools.pooling.PoolingFeatureException; - -/** - * Superclass used to test subclasses of {@link Message}. - * - * @param type of {@link Message} subclass that this tests - */ -public abstract class BasicMessageTester { - // values set by makeValidMessage() - public static final String VALID_HOST_PREDECESSOR = "hostA"; - public static final String VALID_HOST = "hostB"; - public static final String VALID_CHANNEL = "channelC"; - - /** - * Used to perform JSON serialization and de-serialization. - */ - public final ObjectMapper mapper = new ObjectMapper(); - - /** - * The subclass of the type of Message being tested. - */ - private final Class subclazz; - - /** - * Constructor. - * - * @param subclazz subclass of {@link Message} being tested - */ - public BasicMessageTester(Class subclazz) { - this.subclazz = subclazz; - } - - /** - * Creates a default Message and verifies that the source and channel are - * {@code null}. - * - */ - @Test - public final void testDefaultConstructor() { - testDefaultConstructorFields(makeDefaultMessage()); - } - - /** - * Tests that the Message has the correct source, and that the channel is - * {@code null}. - * - */ - @Test - public final void testConstructorWithArgs() { - testValidFields(makeValidMessage()); - } - - /** - * Makes a valid message and then verifies that it can be serialized and - * de-serialized. Verifies that the de-serialized message is of the same - * type, and has the same content, as the original. - * - * @throws Exception if an error occurs - */ - @Test - public final void testJsonEncodeDecode() throws Exception { - T originalMsg = makeValidMessage(); - - Message msg = mapper.readValue(mapper.writeValueAsString(originalMsg), Message.class); - assertEquals(subclazz, msg.getClass()); - - msg.checkValidity(); - - testValidFields(subclazz.cast(msg)); - } - - /** - * Creates a valid Message and verifies that checkValidity() passes. - * - * @throws PoolingFeatureException if an error occurs - */ - @Test - public final void testCheckValidity_Ok() throws PoolingFeatureException { - T msg = makeValidMessage(); - msg.checkValidity(); - - testValidFields(subclazz.cast(msg)); - } - - /** - * Creates a default Message and verifies that checkValidity() fails. Does - * not throw an exception. - */ - @Test - public final void testCheckValidity_DefaultConstructor() { - try { - makeDefaultMessage().checkValidity(); - fail("missing exception"); - - } catch (PoolingFeatureException expected) { - // success - } - } - - /** - * Creates a message via {@link #makeValidMessage()}, updates it via the - * given function, and then invokes the checkValidity() method on it. It is - * expected that the checkValidity() will throw an exception. - * - * @param func function to update the message prior to invoking - * checkValidity() - */ - public void expectCheckValidityFailure(MessageUpdateFunction func) { - try { - T msg = makeValidMessage(); - func.update(msg); - - msg.checkValidity(); - - fail("missing exception"); - - } catch (PoolingFeatureException expected) { - // success - } - } - - /** - * Creates a message via {@link #makeValidMessage()}, updates one of its - * fields via the given function, and then invokes the checkValidity() - * method on it. It is expected that the checkValidity() will throw an - * exception. It checks both the case when the message's field is set to - * {@code null}, and when it is set to empty (i.e., ""). - * - * @param func function to update the message's field prior to invoking - * checkValidity() - */ - public void expectCheckValidityFailure_NullOrEmpty(MessageFieldUpdateFunction func) { - expectCheckValidityFailure(msg -> func.update(msg, null)); - expectCheckValidityFailure(msg -> func.update(msg, "")); - } - - /** - * Makes a message using the default constructor. - * - * @return a new Message - */ - public final T makeDefaultMessage() { - try { - return subclazz.getConstructor().newInstance(); - - } catch (Exception e) { - throw new AssertionError(e); - } - } - - - // the remaining methods will typically be overridden - - /** - * Makes a message that will pass the validity check. Note: this should use - * the non-default constructor, and the source and channel should be set to - * {@link VALID_HOST} and {@link VALID_CHANNEL}, respectively. - * - * @return a valid Message - */ - public abstract T makeValidMessage(); - - /** - * Verifies that fields are set as expected by - * {@link #makeDefaultMessage()}. - * - * @param msg the default Message - */ - public void testDefaultConstructorFields(T msg) { - assertNull(msg.getSource()); - assertNull(msg.getChannel()); - } - - /** - * Verifies that fields are set as expected by {@link #makeValidMessage()}. - * - * @param msg message whose fields are to be validated - */ - public void testValidFields(T msg) { - assertEquals(VALID_HOST, msg.getSource()); - assertEquals(VALID_CHANNEL, msg.getChannel()); - } - - /** - * Function that updates a message. - * - * @param type of Message the function updates - */ - @FunctionalInterface - public static interface MessageUpdateFunction { - - /** - * Updates a message. - * - * @param msg message to be updated - */ - public void update(T msg); - } - - /** - * Function that updates a single field within a message. - * - * @param type of Message the function updates - */ - @FunctionalInterface - public static interface MessageFieldUpdateFunction { - - /** - * Updates a field within a message. - * - * @param msg message to be updated - * @param newValue new field value - */ - public void update(T msg, String newValue); - } -} diff --git a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/ForwardTest.java b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/ForwardTest.java index c51cafed..99df69ec 100644 --- a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/ForwardTest.java +++ b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/ForwardTest.java @@ -28,7 +28,7 @@ import static org.junit.Assert.assertTrue; import org.junit.Test; import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure; -public class ForwardTest extends BasicMessageTester { +public class ForwardTest extends SupportBasicMessageTester { // values set by makeValidMessage() public static final CommInfrastructure VALID_PROTOCOL = CommInfrastructure.UEB; public static final int VALID_HOPS = 0; diff --git a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/HeartbeatTest.java b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/HeartbeatTest.java index 43f1afd4..d1a82f4f 100644 --- a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/HeartbeatTest.java +++ b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/HeartbeatTest.java @@ -22,7 +22,7 @@ package org.onap.policy.drools.pooling.message; import static org.junit.Assert.assertEquals; -public class HeartbeatTest extends BasicMessageTester { +public class HeartbeatTest extends SupportBasicMessageTester { /** * Sequence number to validate time stamps within the heart beat. diff --git a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/IdentificationTest.java b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/IdentificationTest.java index 7b28afc0..06336b3e 100644 --- a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/IdentificationTest.java +++ b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/IdentificationTest.java @@ -23,7 +23,7 @@ package org.onap.policy.drools.pooling.message; import org.junit.Before; import org.junit.Test; -public class IdentificationTest extends MessageWithAssignmentsTester { +public class IdentificationTest extends SupportMessageWithAssignmentsTester { public IdentificationTest() { super(Identification.class); diff --git a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/LeaderTest.java b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/LeaderTest.java index e30d7d09..eefd45d4 100644 --- a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/LeaderTest.java +++ b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/LeaderTest.java @@ -23,7 +23,7 @@ package org.onap.policy.drools.pooling.message; import org.junit.Before; import org.junit.Test; -public class LeaderTest extends MessageWithAssignmentsTester { +public class LeaderTest extends SupportMessageWithAssignmentsTester { public LeaderTest() { super(Leader.class); diff --git a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/MessageTest.java b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/MessageTest.java index 4e683ff9..db8cd9f9 100644 --- a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/MessageTest.java +++ b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/MessageTest.java @@ -25,7 +25,7 @@ import static org.junit.Assert.assertNull; import org.junit.Test; -public class MessageTest extends BasicMessageTester { +public class MessageTest extends SupportBasicMessageTester { public MessageTest() { super(Message.class); diff --git a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/MessageWithAssignmentsTester.java b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/MessageWithAssignmentsTester.java deleted file mode 100644 index e5dfae9b..00000000 --- a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/MessageWithAssignmentsTester.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * ONAP - * ================================================================================ - * Copyright (C) 2018 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.drools.pooling.message; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; - -import org.junit.Test; - -/** - * Superclass used to test subclasses of {@link MessageWithAssignments}. - * - * @param type of {@link MessageWithAssignments} subclass that this tests - */ -public abstract class MessageWithAssignmentsTester extends BasicMessageTester { - // values set by makeValidMessage() - public static final String[] VALID_ARRAY = {VALID_HOST, VALID_HOST + "_xxx"}; - public static final BucketAssignments VALID_ASGN = new BucketAssignments(VALID_ARRAY); - - /** - * {@code True} if {@code null} assignments are allowed, {@code false} - * otherwise. - */ - private boolean nullAssignments; - - /** - * Constructor. - * - * @param subclazz subclass of {@link MessageWithAssignments} being tested - */ - public MessageWithAssignmentsTester(Class subclazz) { - super(subclazz); - } - - /** - * Indicates whether or not {@code null} assignments should be used for the - * remaining tests. - * - * @param nullAssignments {@code true} to use {@code null} assignments, - * {@code false} otherwise - */ - public void setNullAssignments(boolean nullAssignments) { - this.nullAssignments = nullAssignments; - } - - public boolean isNullAssignments() { - return nullAssignments; - } - - @Test - public void testCheckValidity_InvalidFields() throws Exception { - // null source (i.e., superclass field) - expectCheckValidityFailure(msg -> msg.setSource(null)); - - // empty assignments - expectCheckValidityFailure(msg -> msg.setAssignments(new BucketAssignments(new String[0]))); - - // invalid assignment - String[] invalidAssignment = {"abc", null}; - expectCheckValidityFailure(msg -> msg.setAssignments(new BucketAssignments(invalidAssignment))); - } - - @Test - public void testGetAssignments_testSetAssignments() { - MessageWithAssignments msg = makeValidMessage(); - - // from constructor - assertEquals(VALID_ASGN, msg.getAssignments()); - - BucketAssignments asgn = new BucketAssignments(); - msg.setAssignments(asgn); - assertEquals(asgn, msg.getAssignments()); - } - - @Override - public void testDefaultConstructorFields(T msg) { - super.testDefaultConstructorFields(msg); - - assertNull(msg.getAssignments()); - } - - @Override - public void testValidFields(T msg) { - super.testValidFields(msg); - - if (nullAssignments) { - assertNull(msg.getAssignments()); - - } else { - assertEquals(VALID_ASGN, msg.getAssignments()); - } - } - -} diff --git a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/OfflineTest.java b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/OfflineTest.java index 4fe37366..906733e9 100644 --- a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/OfflineTest.java +++ b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/OfflineTest.java @@ -20,7 +20,7 @@ package org.onap.policy.drools.pooling.message; -public class OfflineTest extends BasicMessageTester { +public class OfflineTest extends SupportBasicMessageTester { public OfflineTest() { super(Offline.class); diff --git a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/QueryTest.java b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/QueryTest.java index e0ab016a..933dddfd 100644 --- a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/QueryTest.java +++ b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/QueryTest.java @@ -20,7 +20,7 @@ package org.onap.policy.drools.pooling.message; -public class QueryTest extends BasicMessageTester { +public class QueryTest extends SupportBasicMessageTester { public QueryTest() { super(Query.class); diff --git a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/SupportBasicMessageTester.java b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/SupportBasicMessageTester.java new file mode 100644 index 00000000..e30d78d4 --- /dev/null +++ b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/SupportBasicMessageTester.java @@ -0,0 +1,244 @@ +/* + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2018 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.drools.pooling.message; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.Test; +import org.onap.policy.drools.pooling.PoolingFeatureException; + +/** + * Superclass used to test subclasses of {@link Message}. + * + * @param type of {@link Message} subclass that this tests + */ +public abstract class SupportBasicMessageTester { + // values set by makeValidMessage() + public static final String VALID_HOST_PREDECESSOR = "hostA"; + public static final String VALID_HOST = "hostB"; + public static final String VALID_CHANNEL = "channelC"; + + /** + * Used to perform JSON serialization and de-serialization. + */ + public final ObjectMapper mapper = new ObjectMapper(); + + /** + * The subclass of the type of Message being tested. + */ + private final Class subclazz; + + /** + * Constructor. + * + * @param subclazz subclass of {@link Message} being tested + */ + public SupportBasicMessageTester(Class subclazz) { + this.subclazz = subclazz; + } + + /** + * Creates a default Message and verifies that the source and channel are + * {@code null}. + * + */ + @Test + public final void testDefaultConstructor() { + testDefaultConstructorFields(makeDefaultMessage()); + } + + /** + * Tests that the Message has the correct source, and that the channel is + * {@code null}. + * + */ + @Test + public final void testConstructorWithArgs() { + testValidFields(makeValidMessage()); + } + + /** + * Makes a valid message and then verifies that it can be serialized and + * de-serialized. Verifies that the de-serialized message is of the same + * type, and has the same content, as the original. + * + * @throws Exception if an error occurs + */ + @Test + public final void testJsonEncodeDecode() throws Exception { + T originalMsg = makeValidMessage(); + + Message msg = mapper.readValue(mapper.writeValueAsString(originalMsg), Message.class); + assertEquals(subclazz, msg.getClass()); + + msg.checkValidity(); + + testValidFields(subclazz.cast(msg)); + } + + /** + * Creates a valid Message and verifies that checkValidity() passes. + * + * @throws PoolingFeatureException if an error occurs + */ + @Test + public final void testCheckValidity_Ok() throws PoolingFeatureException { + T msg = makeValidMessage(); + msg.checkValidity(); + + testValidFields(subclazz.cast(msg)); + } + + /** + * Creates a default Message and verifies that checkValidity() fails. Does + * not throw an exception. + */ + @Test + public final void testCheckValidity_DefaultConstructor() { + try { + makeDefaultMessage().checkValidity(); + fail("missing exception"); + + } catch (PoolingFeatureException expected) { + // success + } + } + + /** + * Creates a message via {@link #makeValidMessage()}, updates it via the + * given function, and then invokes the checkValidity() method on it. It is + * expected that the checkValidity() will throw an exception. + * + * @param func function to update the message prior to invoking + * checkValidity() + */ + public void expectCheckValidityFailure(MessageUpdateFunction func) { + try { + T msg = makeValidMessage(); + func.update(msg); + + msg.checkValidity(); + + fail("missing exception"); + + } catch (PoolingFeatureException expected) { + // success + } + } + + /** + * Creates a message via {@link #makeValidMessage()}, updates one of its + * fields via the given function, and then invokes the checkValidity() + * method on it. It is expected that the checkValidity() will throw an + * exception. It checks both the case when the message's field is set to + * {@code null}, and when it is set to empty (i.e., ""). + * + * @param func function to update the message's field prior to invoking + * checkValidity() + */ + public void expectCheckValidityFailure_NullOrEmpty(MessageFieldUpdateFunction func) { + expectCheckValidityFailure(msg -> func.update(msg, null)); + expectCheckValidityFailure(msg -> func.update(msg, "")); + } + + /** + * Makes a message using the default constructor. + * + * @return a new Message + */ + public final T makeDefaultMessage() { + try { + return subclazz.getConstructor().newInstance(); + + } catch (Exception e) { + throw new AssertionError(e); + } + } + + + // the remaining methods will typically be overridden + + /** + * Makes a message that will pass the validity check. Note: this should use + * the non-default constructor, and the source and channel should be set to + * {@link VALID_HOST} and {@link VALID_CHANNEL}, respectively. + * + * @return a valid Message + */ + public abstract T makeValidMessage(); + + /** + * Verifies that fields are set as expected by + * {@link #makeDefaultMessage()}. + * + * @param msg the default Message + */ + public void testDefaultConstructorFields(T msg) { + assertNull(msg.getSource()); + assertNull(msg.getChannel()); + } + + /** + * Verifies that fields are set as expected by {@link #makeValidMessage()}. + * + * @param msg message whose fields are to be validated + */ + public void testValidFields(T msg) { + assertEquals(VALID_HOST, msg.getSource()); + assertEquals(VALID_CHANNEL, msg.getChannel()); + } + + /** + * Function that updates a message. + * + * @param type of Message the function updates + */ + @FunctionalInterface + public static interface MessageUpdateFunction { + + /** + * Updates a message. + * + * @param msg message to be updated + */ + public void update(T msg); + } + + /** + * Function that updates a single field within a message. + * + * @param type of Message the function updates + */ + @FunctionalInterface + public static interface MessageFieldUpdateFunction { + + /** + * Updates a field within a message. + * + * @param msg message to be updated + * @param newValue new field value + */ + public void update(T msg, String newValue); + } +} diff --git a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/SupportMessageWithAssignmentsTester.java b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/SupportMessageWithAssignmentsTester.java new file mode 100644 index 00000000..bf245feb --- /dev/null +++ b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/SupportMessageWithAssignmentsTester.java @@ -0,0 +1,113 @@ +/* + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2018 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.drools.pooling.message; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import org.junit.Test; + +/** + * Superclass used to test subclasses of {@link MessageWithAssignments}. + * + * @param type of {@link MessageWithAssignments} subclass that this tests + */ +public abstract class SupportMessageWithAssignmentsTester + extends SupportBasicMessageTester { + // values set by makeValidMessage() + public static final String[] VALID_ARRAY = {VALID_HOST, VALID_HOST + "_xxx"}; + public static final BucketAssignments VALID_ASGN = new BucketAssignments(VALID_ARRAY); + + /** + * {@code True} if {@code null} assignments are allowed, {@code false} + * otherwise. + */ + private boolean nullAssignments; + + /** + * Constructor. + * + * @param subclazz subclass of {@link MessageWithAssignments} being tested + */ + public SupportMessageWithAssignmentsTester(Class subclazz) { + super(subclazz); + } + + /** + * Indicates whether or not {@code null} assignments should be used for the + * remaining tests. + * + * @param nullAssignments {@code true} to use {@code null} assignments, + * {@code false} otherwise + */ + public void setNullAssignments(boolean nullAssignments) { + this.nullAssignments = nullAssignments; + } + + public boolean isNullAssignments() { + return nullAssignments; + } + + @Test + public void testCheckValidity_InvalidFields() throws Exception { + // null source (i.e., superclass field) + expectCheckValidityFailure(msg -> msg.setSource(null)); + + // empty assignments + expectCheckValidityFailure(msg -> msg.setAssignments(new BucketAssignments(new String[0]))); + + // invalid assignment + String[] invalidAssignment = {"abc", null}; + expectCheckValidityFailure(msg -> msg.setAssignments(new BucketAssignments(invalidAssignment))); + } + + @Test + public void testGetAssignments_testSetAssignments() { + MessageWithAssignments msg = makeValidMessage(); + + // from constructor + assertEquals(VALID_ASGN, msg.getAssignments()); + + BucketAssignments asgn = new BucketAssignments(); + msg.setAssignments(asgn); + assertEquals(asgn, msg.getAssignments()); + } + + @Override + public void testDefaultConstructorFields(T msg) { + super.testDefaultConstructorFields(msg); + + assertNull(msg.getAssignments()); + } + + @Override + public void testValidFields(T msg) { + super.testValidFields(msg); + + if (nullAssignments) { + assertNull(msg.getAssignments()); + + } else { + assertEquals(VALID_ASGN, msg.getAssignments()); + } + } + +} diff --git a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/state/ActiveStateTest.java b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/state/ActiveStateTest.java index 9cb835c9..c8cbdbb5 100644 --- a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/state/ActiveStateTest.java +++ b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/state/ActiveStateTest.java @@ -47,7 +47,7 @@ import org.onap.policy.drools.pooling.message.Query; import org.onap.policy.drools.utils.Pair; import org.onap.policy.drools.utils.Triple; -public class ActiveStateTest extends BasicStateTester { +public class ActiveStateTest extends SupportBasicStateTester { private ActiveState state; diff --git a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/state/BasicStateTester.java b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/state/BasicStateTester.java deleted file mode 100644 index 20f49a0e..00000000 --- a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/state/BasicStateTester.java +++ /dev/null @@ -1,287 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * ONAP - * ================================================================================ - * Copyright (C) 2018 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.drools.pooling.state; - -import static org.junit.Assert.assertNotNull; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.SortedSet; -import java.util.TreeSet; -import java.util.concurrent.atomic.AtomicReference; -import org.onap.policy.drools.pooling.CancellableScheduledTask; -import org.onap.policy.drools.pooling.PoolingManager; -import org.onap.policy.drools.pooling.PoolingProperties; -import org.onap.policy.drools.pooling.message.BucketAssignments; -import org.onap.policy.drools.pooling.message.Leader; -import org.onap.policy.drools.pooling.message.Message; -import org.onap.policy.drools.utils.Pair; -import org.onap.policy.drools.utils.Triple; - -/** - * Superclass used to test subclasses of {@link State}. - */ -public class BasicStateTester { - - protected static final long STD_HEARTBEAT_WAIT_MS = 10; - protected static final long STD_REACTIVATE_WAIT_MS = STD_HEARTBEAT_WAIT_MS + 1; - protected static final long STD_IDENTIFICATION_MS = STD_REACTIVATE_WAIT_MS + 1; - protected static final long STD_ACTIVE_HEARTBEAT_MS = STD_IDENTIFICATION_MS + 1; - protected static final long STD_INTER_HEARTBEAT_MS = STD_ACTIVE_HEARTBEAT_MS + 1; - - protected static final String MY_TOPIC = "myTopic"; - - protected static final String PREV_HOST = "prevHost"; - protected static final String PREV_HOST2 = PREV_HOST + "A"; - - // this follows PREV_HOST, alphabetically - protected static final String MY_HOST = PREV_HOST + "X"; - - // these follow MY_HOST, alphabetically - protected static final String HOST1 = MY_HOST + "1"; - protected static final String HOST2 = MY_HOST + "2"; - protected static final String HOST3 = MY_HOST + "3"; - protected static final String HOST4 = MY_HOST + "4"; - - protected static final String LEADER = HOST1; - - protected static final String[] HOST_ARR3 = {HOST1, MY_HOST, HOST2}; - - protected static final BucketAssignments EMPTY_ASGN = new BucketAssignments(); - protected static final BucketAssignments ASGN3 = new BucketAssignments(HOST_ARR3); - - /** - * Scheduled tasks returned by schedule(). - */ - protected LinkedList onceSchedules; - - /** - * Tasks captured via schedule(). - */ - protected LinkedList> onceTasks; - - /** - * Scheduled tasks returned by scheduleWithFixedDelay(). - */ - protected LinkedList repeatedSchedules; - - /** - * Tasks captured via scheduleWithFixedDelay(). - */ - protected LinkedList> repeatedTasks; - - /** - * Messages captured via publish(). - */ - protected LinkedList> published; - - /** - * Messages captured via publishAdmin(). - */ - protected LinkedList admin; - - protected PoolingManager mgr; - protected PoolingProperties props; - protected State prevState; - - public BasicStateTester() { - super(); - } - - /** - * Setup. - * - * @throws Exception throws exception - */ - public void setUp() throws Exception { - onceSchedules = new LinkedList<>(); - onceTasks = new LinkedList<>(); - - repeatedSchedules = new LinkedList<>(); - repeatedTasks = new LinkedList<>(); - - published = new LinkedList<>(); - admin = new LinkedList<>(); - - mgr = mock(PoolingManager.class); - props = mock(PoolingProperties.class); - - when(mgr.getHost()).thenReturn(MY_HOST); - when(mgr.getTopic()).thenReturn(MY_TOPIC); - when(mgr.getProperties()).thenReturn(props); - - when(props.getStartHeartbeatMs()).thenReturn(STD_HEARTBEAT_WAIT_MS); - when(props.getReactivateMs()).thenReturn(STD_REACTIVATE_WAIT_MS); - when(props.getIdentificationMs()).thenReturn(STD_IDENTIFICATION_MS); - when(props.getActiveHeartbeatMs()).thenReturn(STD_ACTIVE_HEARTBEAT_MS); - when(props.getInterHeartbeatMs()).thenReturn(STD_INTER_HEARTBEAT_MS); - - prevState = new State(mgr) { - @Override - public Map getFilter() { - throw new UnsupportedOperationException("cannot filter"); - } - }; - - // capture publish() arguments - doAnswer(invocation -> { - Object[] args = invocation.getArguments(); - published.add(new Pair<>((String) args[0], (Message) args[1])); - - return null; - }).when(mgr).publish(anyString(), any(Message.class)); - - // capture publishAdmin() arguments - doAnswer(invocation -> { - Object[] args = invocation.getArguments(); - admin.add((Message) args[0]); - - return null; - }).when(mgr).publishAdmin(any(Message.class)); - - // capture schedule() arguments, and return a new future - when(mgr.schedule(anyLong(), any(StateTimerTask.class))).thenAnswer(invocation -> { - Object[] args = invocation.getArguments(); - onceTasks.add(new Pair<>((Long) args[0], (StateTimerTask) args[1])); - - CancellableScheduledTask sched = mock(CancellableScheduledTask.class); - onceSchedules.add(sched); - return sched; - }); - - // capture scheduleWithFixedDelay() arguments, and return a new future - when(mgr.scheduleWithFixedDelay(anyLong(), anyLong(), any(StateTimerTask.class))).thenAnswer(invocation -> { - Object[] args = invocation.getArguments(); - repeatedTasks.add(new Triple<>((Long) args[0], (Long) args[1], (StateTimerTask) args[2])); - - CancellableScheduledTask sched = mock(CancellableScheduledTask.class); - repeatedSchedules.add(sched); - return sched; - }); - - // get/set assignments in the manager - AtomicReference asgn = new AtomicReference<>(ASGN3); - - when(mgr.getAssignments()).thenAnswer(args -> asgn.get()); - - doAnswer(args -> { - asgn.set(args.getArgument(0)); - return null; - }).when(mgr).startDistributing(any()); - } - - /** - * Makes a sorted set of hosts. - * - * @param hosts the hosts to be sorted - * @return the set of hosts, sorted - */ - protected SortedSet sortHosts(String... hosts) { - return new TreeSet<>(Arrays.asList(hosts)); - } - - /** - * Captures the host array from the Leader message published to the admin channel. - * - * @return the host array, as a list - */ - protected List captureHostList() { - return Arrays.asList(captureHostArray()); - } - - /** - * Captures the host array from the Leader message published to the admin channel. - * - * @return the host array - */ - protected String[] captureHostArray() { - BucketAssignments asgn = captureAssignments(); - - String[] arr = asgn.getHostArray(); - assertNotNull(arr); - - return arr; - } - - /** - * Captures the assignments from the Leader message published to the admin channel. - * - * @return the bucket assignments - */ - protected BucketAssignments captureAssignments() { - Leader msg = captureAdminMessage(Leader.class); - - BucketAssignments asgn = msg.getAssignments(); - assertNotNull(asgn); - return asgn; - } - - /** - * Captures the message published to the admin channel. - * - * @param clazz type of {@link Message} to capture - * @return the message that was published - */ - protected T captureAdminMessage(Class clazz) { - return captureAdminMessage(clazz, 0); - } - - /** - * Captures the message published to the admin channel. - * - * @param clazz type of {@link Message} to capture - * @param index index of the item to be captured - * @return the message that was published - */ - protected T captureAdminMessage(Class clazz, int index) { - return clazz.cast(admin.get(index)); - } - - /** - * Captures the message published to the non-admin channels. - * - * @param clazz type of {@link Message} to capture - * @return the (channel,message) pair that was published - */ - protected Pair capturePublishedMessage(Class clazz) { - return capturePublishedMessage(clazz, 0); - } - - /** - * Captures the message published to the non-admin channels. - * - * @param clazz type of {@link Message} to capture - * @param index index of the item to be captured - * @return the (channel,message) pair that was published - */ - protected Pair capturePublishedMessage(Class clazz, int index) { - Pair msg = published.get(index); - return new Pair<>(msg.first(), clazz.cast(msg.second())); - } -} diff --git a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/state/IdleStateTest.java b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/state/IdleStateTest.java index cf2c9c7c..9e3ddcf9 100644 --- a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/state/IdleStateTest.java +++ b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/state/IdleStateTest.java @@ -39,7 +39,7 @@ import org.onap.policy.drools.pooling.message.Message; import org.onap.policy.drools.pooling.message.Offline; import org.onap.policy.drools.pooling.message.Query; -public class IdleStateTest extends BasicStateTester { +public class IdleStateTest extends SupportBasicStateTester { private IdleState state; diff --git a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/state/InactiveStateTest.java b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/state/InactiveStateTest.java index ee7fd5e5..77491616 100644 --- a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/state/InactiveStateTest.java +++ b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/state/InactiveStateTest.java @@ -38,7 +38,7 @@ import org.onap.policy.drools.pooling.message.Message; import org.onap.policy.drools.pooling.message.Query; import org.onap.policy.drools.utils.Pair; -public class InactiveStateTest extends BasicStateTester { +public class InactiveStateTest extends SupportBasicStateTester { private InactiveState state; diff --git a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/state/ProcessingStateTest.java b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/state/ProcessingStateTest.java index 4f634516..14784fc2 100644 --- a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/state/ProcessingStateTest.java +++ b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/state/ProcessingStateTest.java @@ -41,7 +41,7 @@ import org.onap.policy.drools.pooling.message.Message; import org.onap.policy.drools.pooling.message.Query; import org.onap.policy.drools.pooling.state.ProcessingState.HostBucket; -public class ProcessingStateTest extends BasicStateTester { +public class ProcessingStateTest extends SupportBasicStateTester { private ProcessingState state; private HostBucket hostBucket; diff --git a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/state/QueryStateTest.java b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/state/QueryStateTest.java index 5601932e..97c9c95a 100644 --- a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/state/QueryStateTest.java +++ b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/state/QueryStateTest.java @@ -41,7 +41,7 @@ import org.onap.policy.drools.pooling.message.Message; import org.onap.policy.drools.pooling.message.Offline; import org.onap.policy.drools.utils.Pair; -public class QueryStateTest extends BasicStateTester { +public class QueryStateTest extends SupportBasicStateTester { private QueryState state; diff --git a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/state/StartStateTest.java b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/state/StartStateTest.java index faafb8cb..092657e5 100644 --- a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/state/StartStateTest.java +++ b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/state/StartStateTest.java @@ -43,7 +43,7 @@ import org.onap.policy.drools.pooling.message.Query; import org.onap.policy.drools.utils.Pair; import org.onap.policy.drools.utils.Triple; -public class StartStateTest extends BasicStateTester { +public class StartStateTest extends SupportBasicStateTester { private StartState state; diff --git a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/state/StateTest.java b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/state/StateTest.java index 42bb35f2..65d9ee31 100644 --- a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/state/StateTest.java +++ b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/state/StateTest.java @@ -44,7 +44,7 @@ import org.onap.policy.drools.pooling.message.Message; import org.onap.policy.drools.pooling.message.Offline; import org.onap.policy.drools.pooling.message.Query; -public class StateTest extends BasicStateTester { +public class StateTest extends SupportBasicStateTester { private State state; diff --git a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/state/SupportBasicStateTester.java b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/state/SupportBasicStateTester.java new file mode 100644 index 00000000..4727652a --- /dev/null +++ b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/state/SupportBasicStateTester.java @@ -0,0 +1,287 @@ +/* + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2018 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.drools.pooling.state; + +import static org.junit.Assert.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.SortedSet; +import java.util.TreeSet; +import java.util.concurrent.atomic.AtomicReference; +import org.onap.policy.drools.pooling.CancellableScheduledTask; +import org.onap.policy.drools.pooling.PoolingManager; +import org.onap.policy.drools.pooling.PoolingProperties; +import org.onap.policy.drools.pooling.message.BucketAssignments; +import org.onap.policy.drools.pooling.message.Leader; +import org.onap.policy.drools.pooling.message.Message; +import org.onap.policy.drools.utils.Pair; +import org.onap.policy.drools.utils.Triple; + +/** + * Superclass used to test subclasses of {@link State}. + */ +public class SupportBasicStateTester { + + protected static final long STD_HEARTBEAT_WAIT_MS = 10; + protected static final long STD_REACTIVATE_WAIT_MS = STD_HEARTBEAT_WAIT_MS + 1; + protected static final long STD_IDENTIFICATION_MS = STD_REACTIVATE_WAIT_MS + 1; + protected static final long STD_ACTIVE_HEARTBEAT_MS = STD_IDENTIFICATION_MS + 1; + protected static final long STD_INTER_HEARTBEAT_MS = STD_ACTIVE_HEARTBEAT_MS + 1; + + protected static final String MY_TOPIC = "myTopic"; + + protected static final String PREV_HOST = "prevHost"; + protected static final String PREV_HOST2 = PREV_HOST + "A"; + + // this follows PREV_HOST, alphabetically + protected static final String MY_HOST = PREV_HOST + "X"; + + // these follow MY_HOST, alphabetically + protected static final String HOST1 = MY_HOST + "1"; + protected static final String HOST2 = MY_HOST + "2"; + protected static final String HOST3 = MY_HOST + "3"; + protected static final String HOST4 = MY_HOST + "4"; + + protected static final String LEADER = HOST1; + + protected static final String[] HOST_ARR3 = {HOST1, MY_HOST, HOST2}; + + protected static final BucketAssignments EMPTY_ASGN = new BucketAssignments(); + protected static final BucketAssignments ASGN3 = new BucketAssignments(HOST_ARR3); + + /** + * Scheduled tasks returned by schedule(). + */ + protected LinkedList onceSchedules; + + /** + * Tasks captured via schedule(). + */ + protected LinkedList> onceTasks; + + /** + * Scheduled tasks returned by scheduleWithFixedDelay(). + */ + protected LinkedList repeatedSchedules; + + /** + * Tasks captured via scheduleWithFixedDelay(). + */ + protected LinkedList> repeatedTasks; + + /** + * Messages captured via publish(). + */ + protected LinkedList> published; + + /** + * Messages captured via publishAdmin(). + */ + protected LinkedList admin; + + protected PoolingManager mgr; + protected PoolingProperties props; + protected State prevState; + + public SupportBasicStateTester() { + super(); + } + + /** + * Setup. + * + * @throws Exception throws exception + */ + public void setUp() throws Exception { + onceSchedules = new LinkedList<>(); + onceTasks = new LinkedList<>(); + + repeatedSchedules = new LinkedList<>(); + repeatedTasks = new LinkedList<>(); + + published = new LinkedList<>(); + admin = new LinkedList<>(); + + mgr = mock(PoolingManager.class); + props = mock(PoolingProperties.class); + + when(mgr.getHost()).thenReturn(MY_HOST); + when(mgr.getTopic()).thenReturn(MY_TOPIC); + when(mgr.getProperties()).thenReturn(props); + + when(props.getStartHeartbeatMs()).thenReturn(STD_HEARTBEAT_WAIT_MS); + when(props.getReactivateMs()).thenReturn(STD_REACTIVATE_WAIT_MS); + when(props.getIdentificationMs()).thenReturn(STD_IDENTIFICATION_MS); + when(props.getActiveHeartbeatMs()).thenReturn(STD_ACTIVE_HEARTBEAT_MS); + when(props.getInterHeartbeatMs()).thenReturn(STD_INTER_HEARTBEAT_MS); + + prevState = new State(mgr) { + @Override + public Map getFilter() { + throw new UnsupportedOperationException("cannot filter"); + } + }; + + // capture publish() arguments + doAnswer(invocation -> { + Object[] args = invocation.getArguments(); + published.add(new Pair<>((String) args[0], (Message) args[1])); + + return null; + }).when(mgr).publish(anyString(), any(Message.class)); + + // capture publishAdmin() arguments + doAnswer(invocation -> { + Object[] args = invocation.getArguments(); + admin.add((Message) args[0]); + + return null; + }).when(mgr).publishAdmin(any(Message.class)); + + // capture schedule() arguments, and return a new future + when(mgr.schedule(anyLong(), any(StateTimerTask.class))).thenAnswer(invocation -> { + Object[] args = invocation.getArguments(); + onceTasks.add(new Pair<>((Long) args[0], (StateTimerTask) args[1])); + + CancellableScheduledTask sched = mock(CancellableScheduledTask.class); + onceSchedules.add(sched); + return sched; + }); + + // capture scheduleWithFixedDelay() arguments, and return a new future + when(mgr.scheduleWithFixedDelay(anyLong(), anyLong(), any(StateTimerTask.class))).thenAnswer(invocation -> { + Object[] args = invocation.getArguments(); + repeatedTasks.add(new Triple<>((Long) args[0], (Long) args[1], (StateTimerTask) args[2])); + + CancellableScheduledTask sched = mock(CancellableScheduledTask.class); + repeatedSchedules.add(sched); + return sched; + }); + + // get/set assignments in the manager + AtomicReference asgn = new AtomicReference<>(ASGN3); + + when(mgr.getAssignments()).thenAnswer(args -> asgn.get()); + + doAnswer(args -> { + asgn.set(args.getArgument(0)); + return null; + }).when(mgr).startDistributing(any()); + } + + /** + * Makes a sorted set of hosts. + * + * @param hosts the hosts to be sorted + * @return the set of hosts, sorted + */ + protected SortedSet sortHosts(String... hosts) { + return new TreeSet<>(Arrays.asList(hosts)); + } + + /** + * Captures the host array from the Leader message published to the admin channel. + * + * @return the host array, as a list + */ + protected List captureHostList() { + return Arrays.asList(captureHostArray()); + } + + /** + * Captures the host array from the Leader message published to the admin channel. + * + * @return the host array + */ + protected String[] captureHostArray() { + BucketAssignments asgn = captureAssignments(); + + String[] arr = asgn.getHostArray(); + assertNotNull(arr); + + return arr; + } + + /** + * Captures the assignments from the Leader message published to the admin channel. + * + * @return the bucket assignments + */ + protected BucketAssignments captureAssignments() { + Leader msg = captureAdminMessage(Leader.class); + + BucketAssignments asgn = msg.getAssignments(); + assertNotNull(asgn); + return asgn; + } + + /** + * Captures the message published to the admin channel. + * + * @param clazz type of {@link Message} to capture + * @return the message that was published + */ + protected T captureAdminMessage(Class clazz) { + return captureAdminMessage(clazz, 0); + } + + /** + * Captures the message published to the admin channel. + * + * @param clazz type of {@link Message} to capture + * @param index index of the item to be captured + * @return the message that was published + */ + protected T captureAdminMessage(Class clazz, int index) { + return clazz.cast(admin.get(index)); + } + + /** + * Captures the message published to the non-admin channels. + * + * @param clazz type of {@link Message} to capture + * @return the (channel,message) pair that was published + */ + protected Pair capturePublishedMessage(Class clazz) { + return capturePublishedMessage(clazz, 0); + } + + /** + * Captures the message published to the non-admin channels. + * + * @param clazz type of {@link Message} to capture + * @param index index of the item to be captured + * @return the (channel,message) pair that was published + */ + protected Pair capturePublishedMessage(Class clazz, int index) { + Pair msg = published.get(index); + return new Pair<>(msg.first(), clazz.cast(msg.second())); + } +} -- cgit 1.2.3-korg