diff options
Diffstat (limited to 'feature-pooling-dmaap/src')
58 files changed, 0 insertions, 11730 deletions
diff --git a/feature-pooling-dmaap/src/assembly/assemble_zip.xml b/feature-pooling-dmaap/src/assembly/assemble_zip.xml deleted file mode 100644 index 9908a2b9..00000000 --- a/feature-pooling-dmaap/src/assembly/assemble_zip.xml +++ /dev/null @@ -1,76 +0,0 @@ -<!-- - ============LICENSE_START======================================================= - feature-pooling-dmaap - ================================================================================ - 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========================================================= - --> - -<!-- Defines how we build the .zip file which is our distribution. --> - -<assembly - xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd"> - <id>feature-pooling-dmaap</id> - <formats> - <format>zip</format> - </formats> - - <!-- we want "system" and related files right at the root level as this - file is suppose to be unzip on top of a karaf distro. --> - <includeBaseDirectory>false</includeBaseDirectory> - - <fileSets> - <fileSet> - <directory>target</directory> - <outputDirectory>lib/feature</outputDirectory> - <includes> - <include>feature-pooling-dmaap-${project.version}.jar</include> - </includes> - </fileSet> - <fileSet> - <directory>target/assembly/lib</directory> - <outputDirectory>lib/dependencies</outputDirectory> - <includes> - <include>*.jar</include> - </includes> - </fileSet> - <fileSet> - <directory>src/main/feature/config</directory> - <outputDirectory>config</outputDirectory> - <fileMode>0644</fileMode> - <excludes/> - </fileSet> - <fileSet> - <directory>src/main/feature/bin</directory> - <outputDirectory>bin</outputDirectory> - <fileMode>0744</fileMode> - <excludes/> - </fileSet> - <fileSet> - <directory>src/main/feature/db</directory> - <outputDirectory>db</outputDirectory> - <fileMode>0744</fileMode> - <excludes/> - </fileSet> - <fileSet> - <directory>src/main/feature/install</directory> - <outputDirectory>install</outputDirectory> - <fileMode>0744</fileMode> - <excludes/> - </fileSet> - </fileSets> -</assembly> diff --git a/feature-pooling-dmaap/src/main/feature/config/feature-pooling-dmaap.properties b/feature-pooling-dmaap/src/main/feature/config/feature-pooling-dmaap.properties deleted file mode 100644 index 59c4b472..00000000 --- a/feature-pooling-dmaap/src/main/feature/config/feature-pooling-dmaap.properties +++ /dev/null @@ -1,87 +0,0 @@ -### -# ============LICENSE_START======================================================= -# feature-pooling-dmaap -# ================================================================================ -# Copyright (C) 2018-2020 AT&T Intellectual Property. All rights reserved. -# ================================================================================ -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ============LICENSE_END========================================================= -### - -# In general, the feature-specific properties begin with "pooling", -# and they may be made specific to a controller by prepending with -# "pooling.<controller-name>", instead. -# -# The available properties and their default values are shown below. - -# Whether or not the feature is enabled. -#pooling.enabled=false - -# The internal DMaaP topic used by a controller. Note: the controller -# name is required for this property. -#pooling.<controller-name>.topic = - -# Maximum number of events to retain in the queue while a new host waits -# to be assigned work. -#pooling.offline.queue.limit=1000 - -# Maximum age, in milliseconds, of events to be retained in the queue. -# Events older than this are discarded. -#pooling.offline.queue.age.milliseconds=60000 - -# Time, in milliseconds, to wait for an "Offline" message to be published -# to DMaaP before the connection may be closed. -#pooling.offline.publish.wait.milliseconds=3000 - -# Time, in milliseconds, to wait for this host's initial heart beat. This -# is used to verify connectivity to the internal DMaaP topic. -#pooling.start.heartbeat.milliseconds=100000 - -# Time, in milliseconds, to wait before attempting to re-active this -# host when it was not assigned any work. -#pooling.reactivate.milliseconds=50000 - -# Time, in milliseconds, to wait for other hosts to identify themselves -# when this host is started. -#pooling.identification.milliseconds=50000 - -# Time, in milliseconds, to wait for heart beats from this host, or its -# predecessor, during the active state. -#pooling.active.heartbeat.milliseconds=50000 - -# Time, in milliseconds, to wait between heart beat generations. -#pooling.inter.heartbeat.milliseconds=15000 - -# Topic used for inter-host communication for a particular controller -# pooling.<controller-name>.topic=XXX - -# Each controller that is enabled should have its own topic and the -# corresponding dmaap.xxx properties. However, for now, just assume that -# the usecases features will not both be enabled at the same time. - -pooling.usecases.enabled=true -pooling.usecases.topic=${env:POOLING_TOPIC} - -# the list of sources and sinks should be identical -dmaap.source.topics=POOLING_TOPIC -dmaap.sink.topics=POOLING_TOPIC - -dmaap.source.topics.POOLING_TOPIC.servers=${env:DMAAP_SERVERS} -dmaap.source.topics.POOLING_TOPIC.effectiveTopic=${env:POOLING_TOPIC} -dmaap.source.topics.POOLING_TOPIC.apiKey= -dmaap.source.topics.POOLING_TOPIC.apiSecret= - -dmaap.sink.topics.POOLING_TOPIC.servers=${env:DMAAP_SERVERS} -dmaap.sink.topics.POOLING_TOPIC.effectiveTopic=${env:POOLING_TOPIC} -dmaap.sink.topics.POOLING_TOPIC.apiKey= -dmaap.sink.topics.POOLING_TOPIC.apiSecret= diff --git a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/CancellableScheduledTask.java b/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/CancellableScheduledTask.java deleted file mode 100644 index f0d3b267..00000000 --- a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/CancellableScheduledTask.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * ONAP - * ================================================================================ - * Copyright (C) 2018-2019 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; - -/** - * A scheduled task that can be cancelled. - */ -@FunctionalInterface -public interface CancellableScheduledTask { - - /** - * Cancels the scheduled task. - */ - void cancel(); -} diff --git a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/DmaapManager.java b/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/DmaapManager.java deleted file mode 100644 index c0358f65..00000000 --- a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/DmaapManager.java +++ /dev/null @@ -1,232 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * ONAP - * ================================================================================ - * Copyright (C) 2018-2021 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 java.util.List; -import lombok.Getter; -import org.onap.policy.common.endpoints.event.comm.TopicEndpoint; -import org.onap.policy.common.endpoints.event.comm.TopicEndpointManager; -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.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Manages the internal DMaaP topic. Assumes all topics are managed by - * {@link TopicEndpoint#manager}. - */ -public class DmaapManager { - - private static final Logger logger = LoggerFactory.getLogger(DmaapManager.class); - - /** - * Name of the DMaaP topic. - */ - @Getter - private final String topic; - - /** - * Topic source whose filter is to be manipulated. - */ - private final TopicSource topicSource; - - /** - * Where to publish messages. - */ - private final TopicSink topicSink; - - /** - * {@code True} if the consumer is running, {@code false} otherwise. - */ - private boolean consuming = false; - - /** - * {@code True} if the publisher is running, {@code false} otherwise. - */ - private boolean publishing = false; - - /** - * Constructs the manager, but does not start the source or sink. - * - * @param topic name of the internal DMaaP topic - * @throws PoolingFeatureException if an error occurs - */ - public DmaapManager(String topic) throws PoolingFeatureException { - - logger.info("initializing bus for topic {}", topic); - - try { - this.topic = topic; - - this.topicSource = findTopicSource(); - this.topicSink = findTopicSink(); - - } catch (IllegalArgumentException e) { - logger.error("failed to attach to topic {}", topic); - throw new PoolingFeatureException(e); - } - } - - /** - * Finds the topic source associated with the internal DMaaP topic. - * - * @return the topic source - * @throws PoolingFeatureException if the source doesn't exist or is not filterable - */ - private TopicSource findTopicSource() throws PoolingFeatureException { - for (TopicSource src : getTopicSources()) { - if (topic.equals(src.getTopic())) { - return src; - } - } - - throw new PoolingFeatureException("missing topic source " + topic); - } - - /** - * Finds the topic sink associated with the internal DMaaP topic. - * - * @return the topic sink - * @throws PoolingFeatureException if the sink doesn't exist - */ - private TopicSink findTopicSink() throws PoolingFeatureException { - for (TopicSink sink : getTopicSinks()) { - if (topic.equals(sink.getTopic())) { - return sink; - } - } - - throw new PoolingFeatureException("missing topic sink " + topic); - } - - /** - * Starts the publisher, if it isn't already running. - */ - public void startPublisher() { - if (publishing) { - return; - } - - logger.info("start publishing to topic {}", topic); - publishing = true; - } - - /** - * Stops the publisher. - * - * @param waitMs time, in milliseconds, to wait for the sink to transmit any queued messages and - * close - */ - public void stopPublisher(long waitMs) { - if (!publishing) { - return; - } - - /* - * Give the sink a chance to transmit messages in the queue. It would be better if "waitMs" - * could be passed to sink.stop(), but that isn't an option at this time. - */ - try { - Thread.sleep(waitMs); - - } catch (InterruptedException e) { - logger.warn("message transmission stopped due to {}", e.getMessage()); - Thread.currentThread().interrupt(); - } - - logger.info("stop publishing to topic {}", topic); - publishing = false; - } - - /** - * Starts the consumer, if it isn't already running. - * - * @param listener listener to register with the source - */ - public void startConsumer(TopicListener listener) { - if (consuming) { - return; - } - - logger.info("start consuming from topic {}", topic); - topicSource.register(listener); - consuming = true; - } - - /** - * Stops the consumer. - * - * @param listener listener to unregister with the source - */ - public void stopConsumer(TopicListener listener) { - if (!consuming) { - return; - } - - logger.info("stop consuming from topic {}", topic); - consuming = false; - topicSource.unregister(listener); - } - - /** - * Publishes a message to the sink. - * - * @param msg message to be published - * @throws PoolingFeatureException if an error occurs or the publisher isn't running - */ - public void publish(String msg) throws PoolingFeatureException { - if (!publishing) { - throw new PoolingFeatureException(new IllegalStateException("no topic sink " + topic)); - } - - try { - if (!topicSink.send(msg)) { - throw new PoolingFeatureException("failed to send to topic sink " + topic); - } - - } catch (IllegalStateException e) { - throw new PoolingFeatureException("cannot send to topic sink " + topic, e); - } - } - - /* - * The remaining methods may be overridden by junit tests. - */ - - /** - * Get topic source. - * - * @return the topic sources - */ - protected List<TopicSource> getTopicSources() { - return TopicEndpointManager.getManager().getTopicSources(); - } - - /** - * Get topic sinks. - * - * @return the topic sinks - */ - protected List<TopicSink> getTopicSinks() { - return TopicEndpointManager.getManager().getTopicSinks(); - } -} diff --git a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/PoolingFeature.java b/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/PoolingFeature.java deleted file mode 100644 index 5c61fb85..00000000 --- a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/PoolingFeature.java +++ /dev/null @@ -1,396 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * ONAP - * ================================================================================ - * Copyright (C) 2018-2021 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 java.util.List; -import java.util.Properties; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CountDownLatch; -import lombok.AccessLevel; -import lombok.Getter; -import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure; -import org.onap.policy.common.endpoints.event.comm.TopicEndpointManager; -import org.onap.policy.common.endpoints.event.comm.TopicSink; -import org.onap.policy.common.endpoints.event.comm.TopicSource; -import org.onap.policy.common.utils.properties.SpecProperties; -import org.onap.policy.common.utils.properties.exception.PropertyException; -import org.onap.policy.drools.controller.DroolsController; -import org.onap.policy.drools.features.DroolsControllerFeatureApi; -import org.onap.policy.drools.features.PolicyControllerFeatureApi; -import org.onap.policy.drools.features.PolicyEngineFeatureApi; -import org.onap.policy.drools.persistence.SystemPersistenceConstants; -import org.onap.policy.drools.system.PolicyController; -import org.onap.policy.drools.system.PolicyControllerConstants; -import org.onap.policy.drools.system.PolicyEngine; -import org.onap.policy.drools.util.FeatureEnabledChecker; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Controller/session pooling. Multiple hosts may be launched, all servicing the same - * controllers/sessions. When this feature is enabled, the requests are divided across the different - * hosts, instead of all running on a single, active host. - * - * <p>With each controller, there is an - * associated DMaaP topic that is used for internal communication between the different hosts - * serving the controller. - */ -public class PoolingFeature implements PolicyEngineFeatureApi, PolicyControllerFeatureApi, DroolsControllerFeatureApi { - - private static final Logger logger = LoggerFactory.getLogger(PoolingFeature.class); - - /** - * ID of this host. - */ - @Getter - private final String host; - - /** - * Entire set of feature properties, including those specific to various controllers. - */ - private Properties featProps = null; - - /** - * Maps a controller name to its associated manager. - */ - private final ConcurrentHashMap<String, PoolingManagerImpl> ctlr2pool = new ConcurrentHashMap<>(107); - - /** - * Decremented each time a manager enters the Active state. Used by junit tests. - */ - @Getter(AccessLevel.PROTECTED) - private final CountDownLatch activeLatch = new CountDownLatch(1); - - /** - * Topic names passed to beforeOffer(), which are saved for when the beforeInsert() is - * called later. As multiple threads can be active within the methods at the same - * time, we must keep this in thread local storage. - */ - private ThreadLocal<String> offerTopics = new ThreadLocal<>(); - - /** - * Constructor. - */ - public PoolingFeature() { - super(); - - this.host = UUID.randomUUID().toString(); - } - - @Override - public int getSequenceNumber() { - return 0; - } - - @Override - public boolean beforeStart(PolicyEngine engine) { - logger.info("initializing {}", PoolingProperties.FEATURE_NAME); - featProps = getProperties(PoolingProperties.FEATURE_NAME); - - // remove any generic pooling topic - always use controller-specific property - featProps.remove(PoolingProperties.POOLING_TOPIC); - - initTopicSources(featProps); - initTopicSinks(featProps); - - return false; - } - - @Override - public boolean beforeStart(PolicyController controller) { - return doManager(controller, mgr -> { - mgr.beforeStart(); - return false; - }); - } - - /** - * Adds the controller and a new pooling manager to {@link #ctlr2pool}. - * - * @throws PoolingFeatureRtException if an error occurs - */ - @Override - public boolean afterCreate(PolicyController controller) { - - if (featProps == null) { - logger.error("pooling feature properties have not been loaded"); - throw new PoolingFeatureRtException(new IllegalStateException("missing pooling feature properties")); - } - - String name = controller.getName(); - - var specProps = new SpecProperties(PoolingProperties.PREFIX, name, featProps); - - if (FeatureEnabledChecker.isFeatureEnabled(specProps, PoolingProperties.FEATURE_ENABLED)) { - try { - // get & validate the properties - var props = new PoolingProperties(name, featProps); - - logger.info("pooling enabled for {}", name); - ctlr2pool.computeIfAbsent(name, xxx -> makeManager(host, controller, props, activeLatch)); - - } catch (PropertyException e) { - logger.error("pooling disabled due to exception for {}", name); - throw new PoolingFeatureRtException(e); - } - - } else { - logger.info("pooling disabled for {}", name); - } - - - return false; - } - - @Override - public boolean afterStart(PolicyController controller) { - return doManager(controller, mgr -> { - mgr.afterStart(); - return false; - }); - } - - @Override - public boolean beforeStop(PolicyController controller) { - return doManager(controller, mgr -> { - mgr.beforeStop(); - return false; - }); - } - - @Override - public boolean afterStop(PolicyController controller) { - return doManager(controller, mgr -> { - mgr.afterStop(); - return false; - }); - } - - @Override - public boolean afterShutdown(PolicyController controller) { - return commonShutdown(controller); - } - - @Override - public boolean afterHalt(PolicyController controller) { - return commonShutdown(controller); - } - - private boolean commonShutdown(PolicyController controller) { - deleteManager(controller); - return false; - } - - @Override - public boolean beforeLock(PolicyController controller) { - return doManager(controller, mgr -> { - mgr.beforeLock(); - return false; - }); - } - - @Override - public boolean afterUnlock(PolicyController controller) { - return doManager(controller, mgr -> { - mgr.afterUnlock(); - return false; - }); - } - - @Override - public boolean beforeOffer(PolicyController controller, CommInfrastructure protocol, String topic2, String event) { - /* - * As this is invoked a lot, we'll directly call the manager's method instead of using the - * functional interface via doManager(). - */ - PoolingManagerImpl mgr = ctlr2pool.get(controller.getName()); - if (mgr == null) { - return false; - } - - if (mgr.beforeOffer(topic2, event)) { - return true; - } - - offerTopics.set(topic2); - return false; - } - - @Override - public boolean beforeInsert(DroolsController droolsController, Object fact) { - - String topic = offerTopics.get(); - if (topic == null) { - logger.warn("missing arguments for feature-pooling-dmaap in beforeInsert"); - return false; - } - - PolicyController controller; - try { - controller = getController(droolsController); - - } catch (IllegalArgumentException | IllegalStateException e) { - logger.warn("cannot get controller for {} {}", droolsController.getGroupId(), - droolsController.getArtifactId(), e); - return false; - } - - - if (controller == null) { - logger.warn("cannot determine controller for {} {}", droolsController.getGroupId(), - droolsController.getArtifactId()); - return false; - } - - /* - * As this is invoked a lot, we'll directly call the manager's method instead of using the - * functional interface via doManager(). - */ - PoolingManagerImpl mgr = ctlr2pool.get(controller.getName()); - if (mgr == null) { - return false; - } - - return mgr.beforeInsert(topic, fact); - } - - @Override - public boolean afterOffer(PolicyController controller, CommInfrastructure protocol, String topic, String event, - boolean success) { - - // clear any stored arguments - offerTopics.remove(); - - return false; - } - - /** - * Executes a function using the manager associated with the controller. Catches any exceptions - * from the function and re-throws it as a runtime exception. - * - * @param controller controller - * @param func function to be executed - * @return {@code true} if the function handled the request, {@code false} otherwise - * @throws PoolingFeatureRtException if an error occurs - */ - private boolean doManager(PolicyController controller, MgrFunc func) { - PoolingManagerImpl mgr = ctlr2pool.get(controller.getName()); - if (mgr == null) { - return false; - } - - try { - return func.apply(mgr); - - } catch (PoolingFeatureException e) { - throw new PoolingFeatureRtException(e); - } - } - - /** - * Deletes the manager associated with a controller. - * - * @param controller controller - * @throws PoolingFeatureRtException if an error occurs - */ - private void deleteManager(PolicyController controller) { - - String name = controller.getName(); - logger.info("remove feature-pool-dmaap manager for {}", name); - - ctlr2pool.remove(name); - } - - /** - * Function that operates on a manager. - */ - @FunctionalInterface - private static interface MgrFunc { - - /** - * Apply. - * - * @param mgr manager - * @return {@code true} if the request was handled by the manager, {@code false} otherwise - * @throws PoolingFeatureException feature exception - */ - boolean apply(PoolingManagerImpl mgr) throws PoolingFeatureException; - } - - /* - * The remaining methods may be overridden by junit tests. - */ - - /** - * Get properties. - * - * @param featName feature name - * @return the properties for the specified feature - */ - protected Properties getProperties(String featName) { - return SystemPersistenceConstants.getManager().getProperties(featName); - } - - /** - * Makes a pooling manager for a controller. - * - * @param host name/uuid of this host - * @param controller controller - * @param props properties to use to configure the manager - * @param activeLatch decremented when the manager goes Active - * @return a new pooling manager - */ - protected PoolingManagerImpl makeManager(String host, PolicyController controller, PoolingProperties props, - CountDownLatch activeLatch) { - return new PoolingManagerImpl(host, controller, props, activeLatch); - } - - /** - * Gets the policy controller associated with a drools controller. - * - * @param droolsController drools controller - * @return the policy controller associated with a drools controller - */ - protected PolicyController getController(DroolsController droolsController) { - return PolicyControllerConstants.getFactory().get(droolsController); - } - - /** - * Initializes the topic sources. - * - * @param props properties used to configure the topics - * @return the topic sources - */ - protected List<TopicSource> initTopicSources(Properties props) { - return TopicEndpointManager.getManager().addTopicSources(props); - } - - /** - * Initializes the topic sinks. - * - * @param props properties used to configure the topics - * @return the topic sinks - */ - protected List<TopicSink> initTopicSinks(Properties props) { - return TopicEndpointManager.getManager().addTopicSinks(props); - } -} diff --git a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/PoolingFeatureException.java b/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/PoolingFeatureException.java deleted file mode 100644 index c3c81879..00000000 --- a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/PoolingFeatureException.java +++ /dev/null @@ -1,50 +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; - -/** - * Exception thrown by the pooling feature. - */ -public class PoolingFeatureException extends Exception { - private static final long serialVersionUID = 1L; - - public PoolingFeatureException() { - super(); - } - - public PoolingFeatureException(String message) { - super(message); - } - - public PoolingFeatureException(Throwable cause) { - super(cause); - } - - public PoolingFeatureException(String message, Throwable cause) { - super(message, cause); - } - - public PoolingFeatureException(String message, Throwable cause, boolean enableSuppression, - boolean writableStackTrace) { - super(message, cause, enableSuppression, writableStackTrace); - } - -} diff --git a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/PoolingFeatureRtException.java b/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/PoolingFeatureRtException.java deleted file mode 100644 index 6fdb6c69..00000000 --- a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/PoolingFeatureRtException.java +++ /dev/null @@ -1,50 +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; - -/** - * A runtime exception thrown by the pooling feature. - */ -public class PoolingFeatureRtException extends RuntimeException { - private static final long serialVersionUID = 1L; - - public PoolingFeatureRtException() { - super(); - } - - public PoolingFeatureRtException(String message) { - super(message); - } - - public PoolingFeatureRtException(Throwable cause) { - super(cause); - } - - public PoolingFeatureRtException(String message, Throwable cause) { - super(message, cause); - } - - public PoolingFeatureRtException(String message, Throwable cause, boolean enableSuppression, - boolean writableStackTrace) { - super(message, cause, enableSuppression, writableStackTrace); - } - -} diff --git a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/PoolingManager.java b/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/PoolingManager.java deleted file mode 100644 index cc8e3a4d..00000000 --- a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/PoolingManager.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * ONAP - * ================================================================================ - * Copyright (C) 2018-2020 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ - -package org.onap.policy.drools.pooling; - -import org.onap.policy.drools.pooling.message.BucketAssignments; -import org.onap.policy.drools.pooling.message.Message; -import org.onap.policy.drools.pooling.state.State; -import org.onap.policy.drools.pooling.state.StateTimerTask; - -/** - * Pooling manager for a single PolicyController. - */ -public interface PoolingManager { - - /** - * Gets the properties used to configure the manager. - * - * @return pooling properties - */ - PoolingProperties getProperties(); - - /** - * Gets the host id. - * - * @return the host id - */ - String getHost(); - - /** - * Gets the name of the internal DMaaP topic used by this manager to communicate with - * its other hosts. - * - * @return the name of the internal DMaaP topic - */ - String getTopic(); - - /** - * Starts distributing requests according to the given bucket assignments. - * - * @param assignments must <i>not</i> be {@code null} - */ - void startDistributing(BucketAssignments assignments); - - /** - * Gets the current bucket assignments. - * - * @return the current bucket assignments, or {@code null} if no assignments have been - * made - */ - BucketAssignments getAssignments(); - - /** - * Publishes a message to the internal topic on the administrative channel. - * - * @param msg message to be published - */ - void publishAdmin(Message msg); - - /** - * Publishes a message to the internal topic on a particular channel. - * - * @param channel channel on which the message should be published - * @param msg message to be published - */ - void publish(String channel, Message msg); - - /** - * Schedules a timer to fire after a delay. - * - * @param delayMs delay, in milliseconds - * @param task task - * @return a new scheduled task - */ - CancellableScheduledTask schedule(long delayMs, StateTimerTask task); - - /** - * Schedules a timer to fire repeatedly. - * - * @param initialDelayMs initial delay, in milliseconds - * @param delayMs delay, in milliseconds - * @param task task - * @return a new scheduled task - */ - CancellableScheduledTask scheduleWithFixedDelay(long initialDelayMs, long delayMs, StateTimerTask task); - - /** - * Transitions to the "start" state. - * - * @return the new state - */ - State goStart(); - - /** - * Transitions to the "query" state. - * - * @return the new state - */ - State goQuery(); - - /** - * Transitions to the "active" state. - * - * @return the new state - */ - State goActive(); - - /** - * Transitions to the "inactive" state. - * - * @return the new state - */ - State goInactive(); - -} diff --git a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/PoolingManagerImpl.java b/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/PoolingManagerImpl.java deleted file mode 100644 index a50997c2..00000000 --- a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/PoolingManagerImpl.java +++ /dev/null @@ -1,646 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * ONAP - * ================================================================================ - * Copyright (C) 2018-2021 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 com.google.gson.JsonParseException; -import java.lang.reflect.InvocationTargetException; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import lombok.Getter; -import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure; -import org.onap.policy.common.endpoints.event.comm.TopicListener; -import org.onap.policy.drools.controller.DroolsController; -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.pooling.message.Offline; -import org.onap.policy.drools.pooling.state.ActiveState; -import org.onap.policy.drools.pooling.state.IdleState; -import org.onap.policy.drools.pooling.state.InactiveState; -import org.onap.policy.drools.pooling.state.QueryState; -import org.onap.policy.drools.pooling.state.StartState; -import org.onap.policy.drools.pooling.state.State; -import org.onap.policy.drools.pooling.state.StateTimerTask; -import org.onap.policy.drools.protocol.coders.EventProtocolCoderConstants; -import org.onap.policy.drools.system.PolicyController; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Implementation of a {@link PoolingManager}. Until bucket assignments have been made, - * events coming from external topics are saved in a queue for later processing. Once - * assignments are made, the saved events are processed. In addition, while the controller - * is locked, events are still forwarded to other hosts and bucket assignments are still - * updated, based on any {@link Leader} messages that it receives. - */ -public class PoolingManagerImpl implements PoolingManager, TopicListener { - - private static final Logger logger = LoggerFactory.getLogger(PoolingManagerImpl.class); - - /** - * Maximum number of times a message can be forwarded. - */ - public static final int MAX_HOPS = 5; - - /** - * ID of this host. - */ - @Getter - private final String host; - - /** - * Properties with which this was configured. - */ - @Getter - private final PoolingProperties properties; - - /** - * Associated controller. - */ - private final PolicyController controller; - - /** - * Decremented each time the manager enters the Active state. Used by junit tests. - */ - private final CountDownLatch activeLatch; - - /** - * Used to encode & decode request objects received from & sent to a rule engine. - */ - private final Serializer serializer; - - /** - * Internal DMaaP topic used by this controller. - */ - @Getter - private final String topic; - - /** - * Manager for the internal DMaaP topic. - */ - private final DmaapManager dmaapMgr; - - /** - * Lock used while updating {@link #current}. In general, public methods must use - * this, while private methods assume the lock is already held. - */ - private final Object curLocker = new Object(); - - /** - * Current state. - * - * <p>This uses a finite state machine, wherein the state object contains all of the data - * relevant to that state. Each state object has a process() method, specific to each - * type of {@link Message} subclass. The method returns the next state object, or - * {@code null} if the state is to remain the same. - */ - private State current; - - /** - * Current bucket assignments or {@code null}. - */ - @Getter - private BucketAssignments assignments = null; - - /** - * Pool used to execute timers. - */ - private ScheduledThreadPoolExecutor scheduler = null; - - /** - * Constructs the manager, initializing all of the data structures. - * - * @param host name/uuid of this host - * @param controller controller with which this is associated - * @param props feature properties specific to the controller - * @param activeLatch latch to be decremented each time the manager enters the Active - * state - */ - public PoolingManagerImpl(String host, PolicyController controller, PoolingProperties props, - CountDownLatch activeLatch) { - this.host = host; - this.controller = controller; - this.properties = props; - this.activeLatch = activeLatch; - - try { - this.serializer = new Serializer(); - this.topic = props.getPoolingTopic(); - this.dmaapMgr = makeDmaapManager(props.getPoolingTopic()); - this.current = new IdleState(this); - - logger.info("allocating host {} to controller {} for topic {}", host, controller.getName(), topic); - - } catch (ClassCastException e) { - logger.error("not a topic listener, controller {}", controller.getName()); - throw new PoolingFeatureRtException(e); - - } catch (PoolingFeatureException e) { - logger.error("failed to attach internal DMaaP topic to controller {}", controller.getName()); - throw new PoolingFeatureRtException(e); - } - } - - /** - * Should only be used by junit tests. - * - * @return the current state - */ - protected State getCurrent() { - synchronized (curLocker) { - return current; - } - } - - /** - * Indicates that the controller is about to start. Starts the publisher for the - * internal topic, and creates a thread pool for the timers. - */ - public void beforeStart() { - synchronized (curLocker) { - if (scheduler == null) { - dmaapMgr.startPublisher(); - - logger.debug("make scheduler thread for topic {}", getTopic()); - scheduler = makeScheduler(); - - /* - * Only a handful of timers at any moment, thus we can afford to take the - * time to remove them when they're cancelled. - */ - scheduler.setRemoveOnCancelPolicy(true); - scheduler.setMaximumPoolSize(1); - scheduler.setExecuteExistingDelayedTasksAfterShutdownPolicy(false); - scheduler.setContinueExistingPeriodicTasksAfterShutdownPolicy(false); - } - } - } - - /** - * Indicates that the controller has successfully started. Starts the consumer for the - * internal topic, enters the {@link StartState}, and sets the filter for the initial - * state. - */ - public void afterStart() { - synchronized (curLocker) { - if (current instanceof IdleState) { - dmaapMgr.startConsumer(this); - changeState(new StartState(this)); - } - } - } - - /** - * Indicates that the controller is about to stop. Stops the consumer, the scheduler, - * and the current state. - */ - public void beforeStop() { - ScheduledThreadPoolExecutor sched; - - synchronized (curLocker) { - sched = scheduler; - scheduler = null; - - if (!(current instanceof IdleState)) { - changeState(new IdleState(this)); - dmaapMgr.stopConsumer(this); - publishAdmin(new Offline(getHost())); - } - - assignments = null; - } - - if (sched != null) { - logger.debug("stop scheduler for topic {}", getTopic()); - sched.shutdownNow(); - } - } - - /** - * Indicates that the controller has stopped. Stops the publisher and logs a warning - * if any events are still in the queue. - */ - public void afterStop() { - synchronized (curLocker) { - /* - * stop the publisher, but allow time for any Offline message to be - * transmitted - */ - dmaapMgr.stopPublisher(properties.getOfflinePubWaitMs()); - } - } - - /** - * Indicates that the controller is about to be locked. Enters the idle state, as all - * it will be doing is forwarding messages. - */ - public void beforeLock() { - logger.info("locking manager for topic {}", getTopic()); - - synchronized (curLocker) { - changeState(new IdleState(this)); - } - } - - /** - * Indicates that the controller has been unlocked. Enters the start state, if the - * controller is running. - */ - public void afterUnlock() { - logger.info("unlocking manager for topic {}", getTopic()); - - synchronized (curLocker) { - if (controller.isAlive() && current instanceof IdleState && scheduler != null) { - changeState(new StartState(this)); - } - } - } - - /** - * Changes the finite state machine to a new state, provided the new state is not - * {@code null}. - * - * @param newState new state, or {@code null} if to remain unchanged - */ - private void changeState(State newState) { - if (newState != null) { - current.cancelTimers(); - current = newState; - - newState.start(); - } - } - - @Override - public CancellableScheduledTask schedule(long delayMs, StateTimerTask task) { - // wrap the task in a TimerAction and schedule it - ScheduledFuture<?> fut = scheduler.schedule(new TimerAction(task), delayMs, TimeUnit.MILLISECONDS); - - // wrap the future in a "CancellableScheduledTask" - return () -> fut.cancel(false); - } - - @Override - public CancellableScheduledTask scheduleWithFixedDelay(long initialDelayMs, long delayMs, StateTimerTask task) { - // wrap the task in a TimerAction and schedule it - ScheduledFuture<?> fut = scheduler.scheduleWithFixedDelay(new TimerAction(task), initialDelayMs, delayMs, - TimeUnit.MILLISECONDS); - - // wrap the future in a "CancellableScheduledTask" - return () -> fut.cancel(false); - } - - @Override - public void publishAdmin(Message msg) { - publish(Message.ADMIN, msg); - } - - @Override - public void publish(String channel, Message msg) { - logger.info("publish {} to {} on topic {}", msg.getClass().getSimpleName(), channel, getTopic()); - - msg.setChannel(channel); - - try { - // ensure it's valid before we send it - msg.checkValidity(); - - String txt = serializer.encodeMsg(msg); - dmaapMgr.publish(txt); - - } catch (JsonParseException e) { - logger.error("failed to serialize message for topic {} channel {}", topic, channel, e); - - } catch (PoolingFeatureException e) { - logger.error("failed to publish message for topic {} channel {}", topic, channel, e); - } - } - - /** - * Handles an event from the internal topic. - * - * @param commType comm infrastructure - * @param topic2 topic - * @param event event - */ - @Override - public void onTopicEvent(CommInfrastructure commType, String topic2, String event) { - - if (event == null) { - logger.error("null event on topic {}", topic); - return; - } - - synchronized (curLocker) { - // it's on the internal topic - handleInternal(event); - } - } - - /** - * Called by the PolicyController before it offers the event to the DroolsController. - * If the controller is locked, then it isn't processing events. However, they still - * need to be forwarded, thus in that case, they are decoded and forwarded. - * - * <p>On the other hand, if the controller is not locked, then we just return immediately - * and let {@link #beforeInsert(Object, String, String, Object) beforeInsert()} handle - * it instead, as it already has the decoded message. - * - * @param topic2 topic - * @param event event - * @return {@code true} if the event was handled by the manager, {@code false} if it - * must still be handled by the invoker - */ - public boolean beforeOffer(String topic2, String event) { - - if (!controller.isLocked()) { - // we should NOT intercept this message - let the invoker handle it - return false; - } - - return handleExternal(topic2, decodeEvent(topic2, event)); - } - - /** - * Called by the DroolsController before it inserts the event into the rule engine. - * - * @param topic2 topic - * @param event event, as an object - * @return {@code true} if the event was handled by the manager, {@code false} if it - * must still be handled by the invoker - */ - public boolean beforeInsert(String topic2, Object event) { - return handleExternal(topic2, event); - } - - /** - * Handles an event from an external topic. - * - * @param topic2 topic - * @param event event, as an object, or {@code null} if it cannot be decoded - * @return {@code true} if the event was handled by the manager, {@code false} if it - * must still be handled by the invoker - */ - private boolean handleExternal(String topic2, Object event) { - if (event == null) { - // no event - let the invoker handle it - return false; - } - - synchronized (curLocker) { - return handleExternal(topic2, event, event.hashCode()); - } - } - - /** - * Handles an event from an external topic. - * - * @param topic2 topic - * @param event event, as an object - * @param eventHashCode event's hash code - * @return {@code true} if the event was handled, {@code false} if the invoker should - * handle it - */ - private boolean handleExternal(String topic2, Object event, int eventHashCode) { - if (assignments == null) { - // no bucket assignments yet - handle locally - logger.info("handle event locally for request {}", event); - - // we did NOT consume the event - return false; - - } else { - return handleEvent(topic2, event, eventHashCode); - } - } - - /** - * Handles a {@link Forward} event, possibly forwarding it again. - * - * @param topic2 topic - * @param event event, as an object - * @param eventHashCode event's hash code - * @return {@code true} if the event was handled, {@code false} if the invoker should - * handle it - */ - private boolean handleEvent(String topic2, Object event, int eventHashCode) { - String target = assignments.getAssignedHost(eventHashCode); - - if (target == null) { - /* - * This bucket has no assignment - just discard the event - */ - logger.warn("discarded event for unassigned bucket from topic {}", topic2); - return true; - } - - if (target.equals(host)) { - /* - * Message belongs to this host - allow the controller to handle it. - */ - logger.info("handle local event for request {} from topic {}", event, topic2); - return false; - } - - // not our message, consume the event - logger.warn("discarded event for host {} from topic {}", target, topic2); - return true; - } - - /** - * Decodes an event from a String into an event Object. - * - * @param topic2 topic - * @param event event - * @return the decoded event object, or {@code null} if it can't be decoded - */ - private Object decodeEvent(String topic2, String event) { - DroolsController drools = controller.getDrools(); - - // check if this topic has a decoder - - if (!canDecodeEvent(drools, topic2)) { - - logger.warn("{}: DECODING-UNSUPPORTED {}:{}:{}", drools, topic2, drools.getGroupId(), - drools.getArtifactId()); - return null; - } - - // decode - - try { - return decodeEventWrapper(drools, topic2, event); - - } catch (UnsupportedOperationException | IllegalStateException | IllegalArgumentException e) { - logger.debug("{}: DECODE FAILED: {} <- {} because of {}", drools, topic2, event, e.getMessage(), e); - return null; - } - } - - /** - * Handles an event from the internal topic. This uses reflection to identify the - * appropriate process() method to invoke, based on the type of Message that was - * decoded. - * - * @param event the serialized {@link Message} read from the internal topic - */ - private void handleInternal(String event) { - Class<?> clazz = null; - - try { - Message msg = serializer.decodeMsg(event); - - // get the class BEFORE checking the validity - clazz = msg.getClass(); - - msg.checkValidity(); - - var meth = current.getClass().getMethod("process", msg.getClass()); - changeState((State) meth.invoke(current, msg)); - - } catch (JsonParseException e) { - logger.warn("failed to decode message for topic {}", topic, e); - - } catch (NoSuchMethodException | SecurityException e) { - logger.error("no processor for message {} for topic {}", clazz, topic, e); - - } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException - | PoolingFeatureException e) { - logger.error("failed to process message {} for topic {}", clazz, topic, e); - } - } - - @Override - public void startDistributing(BucketAssignments asgn) { - synchronized (curLocker) { - int sz = (asgn == null ? 0 : asgn.getAllHosts().size()); - logger.info("new assignments for {} hosts on topic {}", sz, getTopic()); - assignments = asgn; - } - } - - @Override - public State goStart() { - return new StartState(this); - } - - @Override - public State goQuery() { - return new QueryState(this); - } - - @Override - public State goActive() { - activeLatch.countDown(); - return new ActiveState(this); - } - - @Override - public State goInactive() { - return new InactiveState(this); - } - - /** - * Action to run a timer task. Only runs the task if the machine is still in the state - * that it was in when the timer was created. - */ - private class TimerAction implements Runnable { - - /** - * State of the machine when the timer was created. - */ - private State origState; - - /** - * Task to be executed. - */ - private StateTimerTask task; - - /** - * Constructor. - * - * @param task task to execute when this timer runs - */ - public TimerAction(StateTimerTask task) { - this.origState = current; - this.task = task; - } - - @Override - public void run() { - synchronized (curLocker) { - if (current == origState) { - changeState(task.fire()); - } - } - } - } - - /** - * Creates a DMaaP manager. - * - * @param topic name of the internal DMaaP topic - * @return a new DMaaP manager - * @throws PoolingFeatureException if an error occurs - */ - protected DmaapManager makeDmaapManager(String topic) throws PoolingFeatureException { - return new DmaapManager(topic); - } - - /** - * Creates a scheduled thread pool. - * - * @return a new scheduled thread pool - */ - protected ScheduledThreadPoolExecutor makeScheduler() { - return new ScheduledThreadPoolExecutor(1); - } - - /** - * Determines if the event can be decoded. - * - * @param drools drools controller - * @param topic topic on which the event was received - * @return {@code true} if the event can be decoded, {@code false} otherwise - */ - protected boolean canDecodeEvent(DroolsController drools, String topic) { - return EventProtocolCoderConstants.getManager().isDecodingSupported(drools.getGroupId(), drools.getArtifactId(), - topic); - } - - /** - * Decodes the event. - * - * @param drools drools controller - * @param topic topic on which the event was received - * @param event event text to be decoded - * @return the decoded event - * @throws IllegalArgumentException illegal argument - * @throw UnsupportedOperationException unsupported operation - * @throws IllegalStateException illegal state - */ - protected Object decodeEventWrapper(DroolsController drools, String topic, String event) { - return EventProtocolCoderConstants.getManager().decode(drools.getGroupId(), drools.getArtifactId(), topic, - event); - } -} diff --git a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/PoolingProperties.java b/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/PoolingProperties.java deleted file mode 100644 index 08b2753f..00000000 --- a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/PoolingProperties.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * ONAP - * ================================================================================ - * Copyright (C) 2018, 2021 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 java.util.Properties; -import lombok.Getter; -import lombok.Setter; -import org.onap.policy.common.utils.properties.BeanConfigurator; -import org.onap.policy.common.utils.properties.Property; -import org.onap.policy.common.utils.properties.SpecProperties; -import org.onap.policy.common.utils.properties.exception.PropertyException; - -/** - * Properties used by the pooling feature, specific to a controller. - */ -@Getter -@Setter -public class PoolingProperties { - - /** - * The feature name, used to retrieve properties. - */ - public static final String FEATURE_NAME = "feature-pooling-dmaap"; - - /** - * Feature properties all begin with this prefix. - */ - public static final String PREFIX = "pooling."; - - public static final String FEATURE_ENABLED = PREFIX + "enabled"; - public static final String POOLING_TOPIC = PREFIX + "topic"; - public static final String OFFLINE_LIMIT = PREFIX + "offline.queue.limit"; - public static final String OFFLINE_AGE_MS = PREFIX + "offline.queue.age.milliseconds"; - public static final String OFFLINE_PUB_WAIT_MS = PREFIX + "offline.publish.wait.milliseconds"; - public static final String START_HEARTBEAT_MS = PREFIX + "start.heartbeat.milliseconds"; - public static final String REACTIVATE_MS = PREFIX + "reactivate.milliseconds"; - public static final String IDENTIFICATION_MS = PREFIX + "identification.milliseconds"; - public static final String ACTIVE_HEARTBEAT_MS = PREFIX + "active.heartbeat.milliseconds"; - public static final String INTER_HEARTBEAT_MS = PREFIX + "inter.heartbeat.milliseconds"; - - /** - * Type of item that the extractors will be extracting. - */ - public static final String EXTRACTOR_TYPE = "requestId"; - - /** - * Prefix for extractor properties. - */ - public static final String PROP_EXTRACTOR_PREFIX = "extractor." + EXTRACTOR_TYPE; - - /** - * Properties from which this was constructed. - */ - private Properties source; - - /** - * Topic used for inter-host communication. - */ - @Property(name = POOLING_TOPIC) - private String poolingTopic; - - /** - * Maximum number of events to retain in the queue while waiting for - * buckets to be assigned. - */ - @Property(name = OFFLINE_LIMIT, defaultValue = "1000") - private int offlineLimit; - - /** - * Maximum age, in milliseconds, of events to be retained in the queue. - * Events older than this are discarded. - */ - @Property(name = OFFLINE_AGE_MS, defaultValue = "60000") - private long offlineAgeMs; - - /** - * Time, in milliseconds, to wait for an "Offline" message to be published - * to DMaaP. - */ - @Property(name = OFFLINE_PUB_WAIT_MS, defaultValue = "3000") - private long offlinePubWaitMs; - - /** - * Time, in milliseconds, to wait for this host's heart beat during the - * start-up state. - */ - @Property(name = START_HEARTBEAT_MS, defaultValue = "100000") - private long startHeartbeatMs; - - /** - * Time, in milliseconds, to wait before attempting to re-active this - * host when it has no bucket assignments. - */ - @Property(name = REACTIVATE_MS, defaultValue = "50000") - private long reactivateMs; - - /** - * Time, in milliseconds, to wait for all Identification messages to - * arrive during the query state. - */ - @Property(name = IDENTIFICATION_MS, defaultValue = "50000") - private long identificationMs; - - /** - * Time, in milliseconds, to wait for heart beats from this host, or its - * predecessor, during the active state. - */ - @Property(name = ACTIVE_HEARTBEAT_MS, defaultValue = "50000") - private long activeHeartbeatMs; - - /** - * Time, in milliseconds, to wait between heart beat generations during - * the active and start-up states. - */ - @Property(name = INTER_HEARTBEAT_MS, defaultValue = "15000") - private long interHeartbeatMs; - - /** - * Constructor. - * - * @param controllerName the name of the controller - * @param props set of properties used to configure this - * @throws PropertyException if an error occurs - * - */ - public PoolingProperties(String controllerName, Properties props) throws PropertyException { - source = props; - - new BeanConfigurator().configureFromProperties(this, new SpecProperties(PREFIX, controllerName, props)); - } -} diff --git a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/Serializer.java b/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/Serializer.java deleted file mode 100644 index 15c98e0d..00000000 --- a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/Serializer.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * ONAP - * ================================================================================ - * Copyright (C) 2018-2021 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 com.google.gson.Gson; -import com.google.gson.JsonElement; -import com.google.gson.JsonParseException; -import java.util.HashMap; -import java.util.Map; -import org.onap.policy.drools.pooling.message.Heartbeat; -import org.onap.policy.drools.pooling.message.Identification; -import org.onap.policy.drools.pooling.message.Leader; -import org.onap.policy.drools.pooling.message.Message; -import org.onap.policy.drools.pooling.message.Offline; -import org.onap.policy.drools.pooling.message.Query; - -/** - * Serialization helper functions. - */ -public class Serializer { - - /** - * The message type is stored in fields of this name within the JSON. - */ - private static final String TYPE_FIELD = "type"; - - /** - * Used to encode & decode JSON messages sent & received, respectively, on the - * internal DMaaP topic. - */ - private final Gson gson = new Gson(); - - /** - * Maps a message subclass to its type. - */ - private static final Map<Class<? extends Message>, String> class2type = new HashMap<>(); - - /** - * Maps a message type to the appropriate subclass. - */ - private static final Map<String, Class<? extends Message>> type2class = new HashMap<>(); - - static { - class2type.put(Heartbeat.class, "heartbeat"); - class2type.put(Identification.class, "identification"); - class2type.put(Leader.class, "leader"); - class2type.put(Offline.class, "offline"); - class2type.put(Query.class, "query"); - - class2type.forEach((clazz, type) -> type2class.put(type, clazz)); - } - - /** - * Encodes a filter. - * - * @param filter filter to be encoded - * @return the filter, serialized as a JSON string - */ - public String encodeFilter(Map<String, Object> filter) { - return gson.toJson(filter); - } - - /** - * Encodes a message. - * - * @param msg message to be encoded - * @return the message, serialized as a JSON string - */ - public String encodeMsg(Message msg) { - JsonElement jsonEl = gson.toJsonTree(msg); - - String type = class2type.get(msg.getClass()); - if (type == null) { - throw new JsonParseException("cannot serialize " + msg.getClass()); - } - - jsonEl.getAsJsonObject().addProperty(TYPE_FIELD, type); - - return gson.toJson(jsonEl); - } - - /** - * Decodes a JSON string into a Message. - * - * @param msg JSON string representing the message - * @return the message - */ - public Message decodeMsg(String msg) { - JsonElement jsonEl = gson.fromJson(msg, JsonElement.class); - - JsonElement typeEl = jsonEl.getAsJsonObject().get(TYPE_FIELD); - if (typeEl == null) { - throw new JsonParseException("cannot deserialize " + Message.class - + " because it does not contain a field named " + TYPE_FIELD); - - } - - Class<? extends Message> clazz = type2class.get(typeEl.getAsString()); - if (clazz == null) { - throw new JsonParseException("cannot deserialize " + typeEl); - } - - return gson.fromJson(jsonEl, clazz); - } -} diff --git a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/message/BucketAssignments.java b/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/message/BucketAssignments.java deleted file mode 100644 index 584edcec..00000000 --- a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/message/BucketAssignments.java +++ /dev/null @@ -1,204 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * ONAP - * ================================================================================ - * Copyright (C) 2018-2021 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 java.util.Arrays; -import java.util.HashSet; -import java.util.Set; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import org.onap.policy.drools.pooling.PoolingFeatureException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Bucket assignments, which is simply an array of host names. - */ -@Getter -@Setter -@NoArgsConstructor -public class BucketAssignments { - - private static final Logger logger = LoggerFactory.getLogger(BucketAssignments.class); - - /** - * The number of bits in the maximum number of buckets. - */ - private static final int MAX_BUCKET_BITS = 10; - - /** - * Maximum number of buckets. Must be a power of two. - */ - public static final int MAX_BUCKETS = 1 << MAX_BUCKET_BITS; - - /** - * Used to ensure that a hash code is not negative. - */ - private static final int MAX_BUCKETS_MASK = MAX_BUCKETS - 1; - - /** - * Identifies the host serving a particular bucket. - */ - private String[] hostArray = null; - - - /** - * Constructor. - * - * @param hostArray maps a bucket number (i.e., array index) to a host. All values - * must be non-null - */ - public BucketAssignments(String[] hostArray) { - this.hostArray = hostArray; - } - - /** - * Gets the leader, which is the host with the minimum UUID. - * - * @return the assignment leader - */ - public String getLeader() { - if (hostArray == null) { - return null; - } - - String leader = null; - - for (String host : hostArray) { - if (host != null && (leader == null || host.compareTo(leader) < 0)) { - leader = host; - } - } - - return leader; - - } - - /** - * Determines if a host has an assignment. - * - * @param host host to be checked - * @return {@code true} if the host has an assignment, {@code false} otherwise - */ - public boolean hasAssignment(String host) { - if (hostArray == null) { - return false; - } - - for (String host2 : hostArray) { - if (host.equals(host2)) { - return true; - } - } - - return false; - } - - /** - * Gets all of the hosts that have an assignment. - * - * @return all of the hosts that have an assignment - */ - public Set<String> getAllHosts() { - Set<String> set = new HashSet<>(); - if (hostArray == null) { - return set; - } - - for (String host : hostArray) { - if (host != null) { - set.add(host); - } - } - - return set; - } - - /** - * Gets the host assigned to a given bucket. - * - * @param hashCode hash code of the item whose assignment is desired - * @return the assigned host, or {@code null} if the item has no assigned host - */ - public String getAssignedHost(int hashCode) { - if (hostArray == null || hostArray.length == 0) { - logger.error("no buckets have been assigned"); - return null; - } - - return hostArray[(Math.abs(hashCode) & MAX_BUCKETS_MASK) % hostArray.length]; - } - - /** - * Gets the number of buckets. - * - * @return the number of buckets - */ - public int size() { - return (hostArray != null ? hostArray.length : 0); - } - - /** - * Checks the validity of the assignments, verifying that all buckets have been - * assigned to a host. - * - * @throws PoolingFeatureException if the assignments are invalid - */ - public void checkValidity() throws PoolingFeatureException { - if (hostArray == null || hostArray.length == 0) { - throw new PoolingFeatureException("missing hosts in message bucket assignments"); - } - - if (hostArray.length > MAX_BUCKETS) { - throw new PoolingFeatureException("too many hosts in message bucket assignments"); - } - - for (var x = 0; x < hostArray.length; ++x) { - if (hostArray[x] == null) { - throw new PoolingFeatureException("bucket " + x + " has no assignment"); - } - } - } - - @Override - public int hashCode() { - final var prime = 31; - var result = 1; - result = prime * result + Arrays.hashCode(hostArray); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - BucketAssignments other = (BucketAssignments) obj; - return Arrays.equals(hostArray, other.hostArray); - } -} diff --git a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/message/Heartbeat.java b/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/message/Heartbeat.java deleted file mode 100644 index 0721fe7a..00000000 --- a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/message/Heartbeat.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * ONAP - * ================================================================================ - * Copyright (C) 2018, 2021 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 lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -/** - * Heart beat message sent to self, or to the succeeding host. - */ -@Getter -@Setter -@NoArgsConstructor -public class Heartbeat extends Message { - - /** - * Time, in milliseconds, when this was created. - */ - private long timestampMs; - - /** - * Constructor. - * - * @param source host on which the message originated - * @param timestampMs time, in milliseconds, associated with the message - */ - public Heartbeat(String source, long timestampMs) { - super(source); - - this.timestampMs = timestampMs; - } -} diff --git a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/message/Identification.java b/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/message/Identification.java deleted file mode 100644 index 2ca4dd75..00000000 --- a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/message/Identification.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * ONAP - * ================================================================================ - * Copyright (C) 2018, 2021 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 lombok.NoArgsConstructor; - -/** - * Identifies the source host and the bucket assignments which it knows about. - */ -@NoArgsConstructor -public class Identification extends MessageWithAssignments { - - /** - * Constructor. - * - * @param source host on which the message originated - * @param assignments assignments - */ - public Identification(String source, BucketAssignments assignments) { - super(source, assignments); - } -} diff --git a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/message/Leader.java b/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/message/Leader.java deleted file mode 100644 index 239f7491..00000000 --- a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/message/Leader.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * ONAP - * ================================================================================ - * Copyright (C) 2018-2019, 2021 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 lombok.NoArgsConstructor; -import org.onap.policy.drools.pooling.PoolingFeatureException; - -/** - * Indicates that the "source" of this message is now the "lead" host. - */ -@NoArgsConstructor -public class Leader extends MessageWithAssignments { - - /** - * Constructor. - * - * @param source host on which the message originated - * @param assignments assignments - */ - public Leader(String source, BucketAssignments assignments) { - super(source, assignments); - } - - /** - * Also verifies that buckets have been assigned and that the source is - * indeed the leader. - */ - @Override - public void checkValidity() throws PoolingFeatureException { - - super.checkValidity(); - - BucketAssignments assignments = getAssignments(); - if (assignments == null) { - throw new PoolingFeatureException("missing message bucket assignments"); - } - - String leader = getSource(); - - if (!assignments.hasAssignment(leader)) { - throw new PoolingFeatureException("leader " + leader + " has no bucket assignments"); - } - - for (String host : assignments.getHostArray()) { - if (host.compareTo(leader) < 0) { - throw new PoolingFeatureException("invalid leader " + leader + ", should be " + host); - } - } - } - -} diff --git a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/message/Message.java b/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/message/Message.java deleted file mode 100644 index 0154fc7c..00000000 --- a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/message/Message.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * ONAP - * ================================================================================ - * Copyright (C) 2018-2019, 2021 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 lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import org.onap.policy.drools.pooling.PoolingFeatureException; - -/** - * Messages sent on the internal topic. - */ -@Getter -@Setter -@NoArgsConstructor -public class Message { - - /** - * Name of the administrative channel. - */ - public static final String ADMIN = "_admin"; - - /** - * Host that originated the message. - */ - private String source; - - /** - * Channel on which the message is routed, which is either the target host - * or {@link #ADMIN}. - */ - private String channel; - - - /** - * Constructor. - * - * @param source host on which the message originated - */ - public Message(String source) { - this.source = source; - } - - /** - * Checks the validity of the message, including verifying that required - * fields are not missing. - * - * @throws PoolingFeatureException if the message is invalid - */ - public void checkValidity() throws PoolingFeatureException { - if (source == null || source.isEmpty()) { - throw new PoolingFeatureException("missing message source"); - } - - if (channel == null || channel.isEmpty()) { - throw new PoolingFeatureException("missing message channel"); - } - } - -} diff --git a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/message/MessageWithAssignments.java b/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/message/MessageWithAssignments.java deleted file mode 100644 index adf17b25..00000000 --- a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/message/MessageWithAssignments.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * ONAP - * ================================================================================ - * Copyright (C) 2018-2019, 2021 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 lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import org.onap.policy.drools.pooling.PoolingFeatureException; - -/** - * A Message that includes bucket assignments. - */ -@NoArgsConstructor -public class MessageWithAssignments extends Message { - - /** - * Bucket assignments, as known by the source host. - */ - @Getter - @Setter - private BucketAssignments assignments; - - - /** - * Constructor. - * - * @param source host on which the message originated - * @param assignments assignements - */ - public MessageWithAssignments(String source, BucketAssignments assignments) { - super(source); - - this.assignments = assignments; - } - - /** - * If there are any assignments, it verifies there validity. - */ - @Override - public void checkValidity() throws PoolingFeatureException { - - super.checkValidity(); - - if (assignments != null) { - assignments.checkValidity(); - } - } - -} diff --git a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/message/Offline.java b/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/message/Offline.java deleted file mode 100644 index 7a3a3b47..00000000 --- a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/message/Offline.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * ONAP - * ================================================================================ - * Copyright (C) 2018, 2021 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 lombok.NoArgsConstructor; - -/** - * Indicates that the source host is going offline and will be unable to process - * any further requests. - */ -@NoArgsConstructor -public class Offline extends Message { - - /** - * Constructor. - * - * @param source host on which the message originated - */ - public Offline(String source) { - super(source); - } -} diff --git a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/message/Query.java b/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/message/Query.java deleted file mode 100644 index d349a789..00000000 --- a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/message/Query.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * ONAP - * ================================================================================ - * Copyright (C) 2018, 2021 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 lombok.NoArgsConstructor; - -/** - * Query the other hosts for their identification. - */ -@NoArgsConstructor -public class Query extends Message { - - /** - * Constructor. - * - * @param source host on which the message originated - */ - public Query(String source) { - super(source); - } -} diff --git a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/state/ActiveState.java b/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/state/ActiveState.java deleted file mode 100644 index a53e7572..00000000 --- a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/state/ActiveState.java +++ /dev/null @@ -1,269 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * ONAP - * ================================================================================ - * Copyright (C) 2018, 2020-2021 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 java.util.Arrays; -import java.util.TreeSet; -import lombok.AccessLevel; -import lombok.Getter; -import org.onap.policy.drools.pooling.PoolingManager; -import org.onap.policy.drools.pooling.message.Heartbeat; -import org.onap.policy.drools.pooling.message.Leader; -import org.onap.policy.drools.pooling.message.Offline; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * The active state. In this state, this host has one more more bucket assignments and - * processes any events associated with one of its buckets. Other events are forwarded to - * appropriate target hosts. - */ -@Getter(AccessLevel.PROTECTED) -public class ActiveState extends ProcessingState { - - private static final Logger logger = LoggerFactory.getLogger(ActiveState.class); - - /** - * Set of hosts that have been assigned a bucket. - */ - @Getter(AccessLevel.NONE) - private final TreeSet<String> assigned = new TreeSet<>(); - - /** - * Host that comes after this host, or {@code null} if it has no successor. - */ - private String succHost = null; - - /** - * Host that comes before this host, or "" if it has no predecessor. - */ - private String predHost = ""; - - /** - * {@code True} if we saw this host's heart beat since the last check, {@code false} - * otherwise. - */ - private boolean myHeartbeatSeen = false; - - /** - * {@code True} if we saw the predecessor's heart beat since the last check, - * {@code false} otherwise. - */ - private boolean predHeartbeatSeen = false; - - - /** - * Constructor. - * - * @param mgr pooling manager - */ - public ActiveState(PoolingManager mgr) { - super(mgr, mgr.getAssignments().getLeader()); - - assigned.addAll(Arrays.asList(mgr.getAssignments().getHostArray())); - - detmNeighbors(); - } - - /** - * Determine this host's neighbors based on the order of the host UUIDs. Updates - * {@link #succHost} and {@link #predHost}. - */ - private void detmNeighbors() { - if (assigned.size() < 2) { - logger.info("this host has no neighbors on topic {}", getTopic()); - /* - * this host is the only one with any assignments - it has no neighbors - */ - succHost = null; - predHost = ""; - return; - } - - if ((succHost = assigned.higher(getHost())) == null) { - // wrapped around - successor is the first host in the set - succHost = assigned.first(); - } - logger.info("this host's successor is {} on topic {}", succHost, getTopic()); - - if ((predHost = assigned.lower(getHost())) == null) { - // wrapped around - predecessor is the last host in the set - predHost = assigned.last(); - } - logger.info("this host's predecessor is {} on topic {}", predHost, getTopic()); - } - - @Override - public void start() { - super.start(); - addTimers(); - genHeartbeat(); - } - - /** - * Adds the timers. - */ - private void addTimers() { - logger.info("add timers"); - - /* - * heart beat generator - */ - long genMs = getProperties().getInterHeartbeatMs(); - - scheduleWithFixedDelay(genMs, genMs, () -> { - genHeartbeat(); - return null; - }); - - /* - * my heart beat checker - */ - long waitMs = getProperties().getActiveHeartbeatMs(); - - scheduleWithFixedDelay(waitMs, waitMs, () -> { - if (myHeartbeatSeen) { - myHeartbeatSeen = false; - return null; - } - - // missed my heart beat - logger.error("missed my heartbeat on topic {}", getTopic()); - - return missedHeartbeat(); - }); - - /* - * predecessor heart beat checker - */ - if (!predHost.isEmpty()) { - - scheduleWithFixedDelay(waitMs, waitMs, () -> { - if (predHeartbeatSeen) { - predHeartbeatSeen = false; - return null; - } - - // missed the predecessor's heart beat - logger.warn("missed predecessor's heartbeat on topic {}", getTopic()); - - publish(makeQuery()); - - return goQuery(); - }); - } - } - - /** - * Generates a heart beat for this host and its successor. - */ - private void genHeartbeat() { - var msg = makeHeartbeat(System.currentTimeMillis()); - publish(getHost(), msg); - - if (succHost != null) { - publish(succHost, msg); - } - } - - @Override - public State process(Heartbeat msg) { - String src = msg.getSource(); - - if (src == null) { - logger.warn("Heartbeat message has no source on topic {}", getTopic()); - - } else if (src.equals(getHost())) { - logger.info("saw my heartbeat on topic {}", getTopic()); - myHeartbeatSeen = true; - - } else if (src.equals(predHost)) { - logger.info("saw heartbeat from {} on topic {}", src, getTopic()); - predHeartbeatSeen = true; - - } else { - logger.info("ignored heartbeat message from {} on topic {}", src, getTopic()); - } - - return null; - } - - @Override - public State process(Leader msg) { - if (!isValid(msg)) { - return null; - } - - String src = msg.getSource(); - - if (getHost().compareTo(src) < 0) { - // our host would be a better leader - find out what's up - logger.warn("unexpected Leader message from {} on topic {}", src, getTopic()); - return goQuery(); - } - - logger.info("have a new leader {} on topic {}", src, getTopic()); - - return goActive(msg.getAssignments()); - } - - @Override - public State process(Offline msg) { - String src = msg.getSource(); - - if (src == null) { - logger.warn("Offline message has no source on topic {}", getTopic()); - return null; - - } else if (!assigned.contains(src)) { - /* - * the offline host wasn't assigned any buckets, so just ignore the message - */ - logger.info("ignore Offline message from unassigned source {} on topic {}", src, getTopic()); - return null; - - } else if (isLeader() || (predHost.equals(src) && predHost.equals(assigned.first()))) { - /* - * Case 1: We are the leader. - * - * Case 2: Our predecessor was the leader and it has gone offline - we should - * become the leader. - * - * In either case, we are now the leader and we must re-balance the buckets - * since one of the hosts has gone offline. - */ - - logger.info("Offline message from source {} on topic {}", src, getTopic()); - - assigned.remove(src); - - return becomeLeader(assigned); - - } else { - /* - * Otherwise, we don't care right now - we'll wait for the leader to tell us - * it's been removed. - */ - logger.info("ignore Offline message from source {} on topic {}", src, getTopic()); - return null; - } - } -} diff --git a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/state/IdleState.java b/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/state/IdleState.java deleted file mode 100644 index 4878c241..00000000 --- a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/state/IdleState.java +++ /dev/null @@ -1,33 +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 org.onap.policy.drools.pooling.PoolingManager; - -/** - * Idle state, used when offline. - */ -public class IdleState extends State { - - public IdleState(PoolingManager mgr) { - super(mgr); - } -} diff --git a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/state/InactiveState.java b/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/state/InactiveState.java deleted file mode 100644 index 579dc16d..00000000 --- a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/state/InactiveState.java +++ /dev/null @@ -1,80 +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 org.onap.policy.drools.pooling.PoolingManager; -import org.onap.policy.drools.pooling.message.Leader; -import org.onap.policy.drools.pooling.message.Query; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * The inactive state. In this state, we just wait a bit and then try to re-activate. In - * the meantime, all messages are ignored. - */ -public class InactiveState extends State { - - private static final Logger logger = LoggerFactory.getLogger(InactiveState.class); - - /** - * Constructor. - * - * @param mgr pooling manager - */ - public InactiveState(PoolingManager mgr) { - super(mgr); - } - - @Override - public void start() { - super.start(); - schedule(getProperties().getReactivateMs(), this::goStart); - } - - @Override - public State process(Leader msg) { - if (isValid(msg)) { - logger.info("received Leader message from {} on topic {}", msg.getSource(), getTopic()); - return goActive(msg.getAssignments()); - } - - return null; - } - - /** - * Generates an Identification message and goes to the query state. - */ - @Override - public State process(Query msg) { - logger.info("received Query message on topic {}", getTopic()); - publish(makeIdentification()); - return goQuery(); - } - - /** - * Remains in this state, without resetting any timers. - */ - @Override - protected State goInactive() { - return null; - } - -} diff --git a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/state/ProcessingState.java b/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/state/ProcessingState.java deleted file mode 100644 index 8bbb6ad8..00000000 --- a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/state/ProcessingState.java +++ /dev/null @@ -1,399 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * ONAP - * ================================================================================ - * Copyright (C) 2018, 2021 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 java.util.Collection; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.Map; -import java.util.Queue; -import java.util.Set; -import java.util.SortedSet; -import java.util.TreeSet; -import lombok.Getter; -import lombok.NonNull; -import lombok.Setter; -import org.onap.policy.drools.pooling.PoolingManager; -import org.onap.policy.drools.pooling.message.BucketAssignments; -import org.onap.policy.drools.pooling.message.Leader; -import org.onap.policy.drools.pooling.message.Query; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Any state in which events are being processed locally and forwarded, as appropriate. - */ -@Getter -public class ProcessingState extends State { - - private static final Logger logger = LoggerFactory.getLogger(ProcessingState.class); - - /** - * Current known leader, never {@code null}. - */ - @NonNull - @Setter - private String leader; - - /** - * Constructor. - * - * @param mgr pooling manager - * @param leader current known leader, which need not be the same as the assignment - * leader. Never {@code null} - * @throws IllegalArgumentException if an argument is invalid - */ - public ProcessingState(PoolingManager mgr, String leader) { - super(mgr); - - if (leader == null) { - throw new IllegalArgumentException("null leader"); - } - - BucketAssignments assignments = mgr.getAssignments(); - - if (assignments != null) { - String[] arr = assignments.getHostArray(); - if (arr != null && arr.length == 0) { - throw new IllegalArgumentException("zero-length bucket assignments"); - } - } - - this.leader = leader; - } - - /** - * Generates an Identification message and goes to the query state. - */ - @Override - public State process(Query msg) { - logger.info("received Query message on topic {}", getTopic()); - publish(makeIdentification()); - return goQuery(); - } - - /** - * Sets the assignments. - * - * @param assignments new assignments, or {@code null} - */ - protected final void setAssignments(BucketAssignments assignments) { - if (assignments != null) { - startDistributing(assignments); - } - } - - /** - * Determines if this host is the leader, based on the current assignments. - * - * @return {@code true} if this host is the leader, {@code false} otherwise - */ - public boolean isLeader() { - return getHost().equals(leader); - } - - /** - * Becomes the leader. Publishes a Leader message and enters the {@link ActiveState}. - * - * @param alive hosts that are known to be alive - * - * @return the new state - */ - protected State becomeLeader(SortedSet<String> alive) { - String newLeader = getHost(); - - if (!newLeader.equals(alive.first())) { - throw new IllegalArgumentException(newLeader + " cannot replace " + alive.first()); - } - - var msg = makeLeader(alive); - logger.info("{}/{} hosts have an assignment", msg.getAssignments().getAllHosts().size(), alive.size()); - - publish(msg); - - return goActive(msg.getAssignments()); - } - - /** - * Makes a leader message. Assumes "this" host is the leader, and thus appears as the - * first host in the set of hosts that are still alive. - * - * @param alive hosts that are known to be alive - * - * @return a new message - */ - private Leader makeLeader(Set<String> alive) { - return new Leader(getHost(), makeAssignments(alive)); - } - - /** - * Makes a set of bucket assignments. Assumes "this" host is the leader. - * - * @param alive hosts that are known to be alive - * - * @return a new set of bucket assignments - */ - private BucketAssignments makeAssignments(Set<String> alive) { - - // make a working array from the CURRENT assignments - String[] bucket2host = makeBucketArray(); - - TreeSet<String> avail = new TreeSet<>(alive); - - // if we have more hosts than buckets, then remove the extra hosts - removeExcessHosts(bucket2host.length, avail); - - // create a host bucket for each available host - Map<String, HostBucket> host2hb = new HashMap<>(); - avail.forEach(host -> host2hb.put(host, new HostBucket(host))); - - // add bucket indices to the appropriate host bucket - addIndicesToHostBuckets(bucket2host, host2hb); - - // convert the collection back to an array - fillArray(host2hb.values(), bucket2host); - - // update bucket2host with new assignments - rebalanceBuckets(host2hb.values(), bucket2host); - - return new BucketAssignments(bucket2host); - } - - /** - * Makes a bucket array, copying the current assignments, if available. - * - * @return a new bucket array - */ - private String[] makeBucketArray() { - BucketAssignments asgn = getAssignments(); - if (asgn == null) { - return new String[BucketAssignments.MAX_BUCKETS]; - } - - String[] oldArray = asgn.getHostArray(); - if (oldArray.length == 0) { - return new String[BucketAssignments.MAX_BUCKETS]; - } - - var newArray = new String[oldArray.length]; - System.arraycopy(oldArray, 0, newArray, 0, oldArray.length); - - return newArray; - } - - /** - * Removes excess hosts from the set of available hosts. Assumes "this" host is the - * leader, and thus appears as the first host in the set. - * - * @param maxHosts maximum number of hosts to be retained - * @param avail available hosts - */ - private void removeExcessHosts(int maxHosts, SortedSet<String> avail) { - while (avail.size() > maxHosts) { - /* - * Don't remove this host, as it's the leader. Since the leader is always at - * the front of the sorted set, we'll just pick off hosts from the back of the - * set. - */ - String host = avail.last(); - avail.remove(host); - - logger.warn("not using extra host {} for topic {}", host, getTopic()); - } - } - - /** - * Adds bucket indices to {@link HostBucket} objects. Buckets that are unassigned or - * assigned to a host that does not appear within the map are re-assigned to a host - * that appears within the map. - * - * @param bucket2host bucket assignments - * @param host2data maps a host name to its {@link HostBucket} - */ - private void addIndicesToHostBuckets(String[] bucket2host, Map<String, HostBucket> host2data) { - LinkedList<Integer> nullBuckets = new LinkedList<>(); - - for (var x = 0; x < bucket2host.length; ++x) { - String host = bucket2host[x]; - if (host == null) { - nullBuckets.add(x); - - } else { - HostBucket hb = host2data.get(host); - if (hb == null) { - nullBuckets.add(x); - - } else { - hb.add(x); - } - } - } - - // assign the null buckets to other hosts - assignNullBuckets(nullBuckets, host2data.values()); - } - - /** - * Assigns null buckets (i.e., those having no assignment) to available hosts. - * - * @param buckets buckets that still need to be assigned to hosts - * @param coll collection of current host-bucket assignments - */ - private void assignNullBuckets(Queue<Integer> buckets, Collection<HostBucket> coll) { - // assign null buckets to the hosts with the fewest buckets - TreeSet<HostBucket> assignments = new TreeSet<>(coll); - - for (Integer index : buckets) { - // add it to the host with the shortest bucket list - HostBucket newhb = assignments.pollFirst(); - newhb.add(index); - - // put the item back into the queue, with its new count - assignments.add(newhb); - } - } - - /** - * Re-balances the buckets, taking from those that have a larger count and giving to - * those that have a smaller count. Populates an output array with the new - * assignments. - * - * @param coll current bucket assignment - * @param bucket2host array to be populated with the new assignments - */ - private void rebalanceBuckets(Collection<HostBucket> coll, String[] bucket2host) { - if (coll.size() <= 1) { - // only one hosts - nothing to rebalance - return; - } - - TreeSet<HostBucket> assignments = new TreeSet<>(coll); - - for (;;) { - HostBucket smaller = assignments.pollFirst(); - HostBucket larger = assignments.pollLast(); - - if (larger.size() - smaller.size() <= 1) { - // it's as balanced as it will get - break; - } - - // move the bucket from the larger to the smaller - Integer bucket = larger.remove(); - smaller.add(bucket); - - bucket2host[bucket] = smaller.host; - - // put the items back, with their new counts - assignments.add(larger); - assignments.add(smaller); - } - - } - - /** - * Fills the array with the host assignments. - * - * @param coll the host assignments - * @param bucket2host array to be filled - */ - private void fillArray(Collection<HostBucket> coll, String[] bucket2host) { - for (HostBucket hb : coll) { - for (Integer index : hb.buckets) { - bucket2host[index] = hb.host; - } - } - } - - /** - * Tracks buckets that have been assigned to a host. - */ - protected static class HostBucket implements Comparable<HostBucket> { - /** - * Host to which the buckets have been assigned. - */ - private String host; - - /** - * Buckets that have been assigned to this host. - */ - private Queue<Integer> buckets = new LinkedList<>(); - - /** - * Constructor. - * - * @param host host - */ - public HostBucket(String host) { - this.host = host; - } - - /** - * Removes the next bucket from the list. - * - * @return the next bucket - */ - public final Integer remove() { - return buckets.remove(); - } - - /** - * Adds a bucket to the list. - * - * @param index index of the bucket to add - */ - public final void add(Integer index) { - buckets.add(index); - } - - /** - * Size. - * - * @return the number of buckets assigned to this host - */ - public final int size() { - return buckets.size(); - } - - /** - * Compares host buckets, first by the number of buckets, and then by the host - * name. - */ - @Override - public final int compareTo(HostBucket other) { - int diff = buckets.size() - other.buckets.size(); - if (diff == 0) { - diff = host.compareTo(other.host); - } - return diff; - } - - @Override - public final int hashCode() { - throw new UnsupportedOperationException("HostBucket cannot be hashed"); - } - - @Override - public final boolean equals(Object obj) { - throw new UnsupportedOperationException("cannot compare HostBuckets"); - } - } -} diff --git a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/state/QueryState.java b/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/state/QueryState.java deleted file mode 100644 index 3e6f9d58..00000000 --- a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/state/QueryState.java +++ /dev/null @@ -1,204 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * ONAP - * ================================================================================ - * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved. - * Modifications Copyright (C) Nordix Foundation. - * ================================================================================ - * 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 java.util.TreeSet; -import org.onap.policy.drools.pooling.PoolingManager; -import org.onap.policy.drools.pooling.message.BucketAssignments; -import org.onap.policy.drools.pooling.message.Identification; -import org.onap.policy.drools.pooling.message.Leader; -import org.onap.policy.drools.pooling.message.Offline; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * The Query state. In this state, the host waits for the other hosts to identify - * themselves. Eventually, a leader should come forth. If not, it will transition to the - * active or inactive state, depending on whether it has an assignment in the - * current bucket assignments. The other possibility is that it may <i>become</i> the - * leader, in which case it will also transition to the active state. - */ -public class QueryState extends ProcessingState { - - private static final Logger logger = LoggerFactory.getLogger(QueryState.class); - - /** - * Hosts that have sent an "Identification" message. Always includes this host. - */ - private final TreeSet<String> alive = new TreeSet<>(); - - /** - * {@code True} if we saw our own Identification method, {@code false} otherwise. - */ - private boolean sawSelfIdent = false; - - /** - * Constructor. - * - * @param mgr manager - */ - public QueryState(PoolingManager mgr) { - // this host is the leader, until a better candidate identifies itself - super(mgr, mgr.getHost()); - - alive.add(getHost()); - } - - @Override - public void start() { - super.start(); - - // start identification timer - awaitIdentification(); - } - - /** - * Starts a timer to wait for all Identification messages to arrive. - */ - private void awaitIdentification() { - - /* - * Once we've waited long enough for all Identification messages to arrive, become - * the leader, assuming we should. - */ - - schedule(getProperties().getIdentificationMs(), () -> { - - if (!sawSelfIdent) { - // didn't see our identification - logger.error("missed our own Ident message on topic {}", getTopic()); - return missedHeartbeat(); - - } else if (isLeader()) { - // "this" host is the new leader - logger.info("this host is the new leader for topic {}", getTopic()); - return becomeLeader(alive); - - } else { - // not the leader - return to previous state - logger.info("no new leader on topic {}", getTopic()); - return goActive(getAssignments()); - } - }); - } - - @Override - public State goQuery() { - return null; - } - - @Override - public State process(Identification msg) { - - if (getHost().equals(msg.getSource())) { - logger.info("saw our own Ident message on topic {}", getTopic()); - sawSelfIdent = true; - - } else { - logger.info("received Ident message from {} on topic {}", msg.getSource(), getTopic()); - recordInfo(msg.getSource(), msg.getAssignments()); - } - - return null; - } - - /** - * If the message leader is better than the leader we have, then go active with it. - * Otherwise, simply treat it like an {@link Identification} message. - */ - @Override - public State process(Leader msg) { - if (!isValid(msg)) { - return null; - } - - String source = msg.getSource(); - BucketAssignments asgn = msg.getAssignments(); - - // go active, if this has a leader that's the same or better than the one we have - if (source.compareTo(getLeader()) <= 0) { - logger.warn("leader with {} on topic {}", source, getTopic()); - return goActive(asgn); - } - - /* - * The message does not have an acceptable leader, but we'll still record its - * info. - */ - logger.info("record leader info from {} on topic {}", source, getTopic()); - recordInfo(source, asgn); - - return null; - } - - @Override - public State process(Offline msg) { - String host = msg.getSource(); - - if (host != null && !host.equals(getHost())) { - logger.warn("host {} offline on topic {}", host, getTopic()); - alive.remove(host); - setLeader(alive.first()); - - } else { - logger.info("ignored offline message from {} on topic {}", msg.getSource(), getTopic()); - } - - return null; - } - - /** - * Records info from a message, adding the source host name to {@link #alive}, and - * updating the bucket assignments. - * - * @param source the message's source host - * @param assignments assignments, or {@code null} - */ - private void recordInfo(String source, BucketAssignments assignments) { - // add this message's source host to "alive" - if (source != null) { - alive.add(source); - setLeader(alive.first()); - } - - if (assignments == null || assignments.getLeader() == null) { - return; - } - - // record assignments, if we don't have any yet - BucketAssignments current = getAssignments(); - if (current == null) { - logger.info("received initial assignments on topic {}", getTopic()); - setAssignments(assignments); - return; - } - - /* - * Record assignments, if the new assignments have a better (i.e., lesser) leader. - */ - String curldr = current.getLeader(); - if (curldr == null || assignments.getLeader().compareTo(curldr) < 0) { - logger.info("use new assignments from {} on topic {}", source, getTopic()); - setAssignments(assignments); - } - } -} diff --git a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/state/StartState.java b/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/state/StartState.java deleted file mode 100644 index c582d6e0..00000000 --- a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/state/StartState.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * ONAP - * ================================================================================ - * Copyright (C) 2018, 2020-2021 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 lombok.Getter; -import org.onap.policy.drools.pooling.PoolingManager; -import org.onap.policy.drools.pooling.message.Heartbeat; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * The start state. Upon entry, a heart beat is generated and the event filter is changed - * to look for just that particular message. Once the message is seen, it goes into the - * {@link QueryState}. - */ -@Getter -public class StartState extends State { - - private static final Logger logger = LoggerFactory.getLogger(StartState.class); - - /** - * Time stamp inserted into the heart beat message. - */ - private long hbTimestampMs = System.currentTimeMillis(); - - /** - * Constructor. - * - * @param mgr pooling manager - */ - public StartState(PoolingManager mgr) { - super(mgr); - } - - @Override - public void start() { - - super.start(); - - var hb = makeHeartbeat(hbTimestampMs); - publish(getHost(), hb); - - /* - * heart beat generator - */ - long genMs = getProperties().getInterHeartbeatMs(); - - scheduleWithFixedDelay(genMs, genMs, () -> { - publish(getHost(), hb); - return null; - }); - - /* - * my heart beat checker - */ - schedule(getProperties().getStartHeartbeatMs(), () -> { - logger.error("missed heartbeat on topic {}", getTopic()); - return internalTopicFailed(); - }); - } - - /** - * Transitions to the query state if the heart beat originated from this host and its - * time stamp matches. - */ - @Override - public State process(Heartbeat msg) { - if (msg.getTimestampMs() == hbTimestampMs && getHost().equals(msg.getSource())) { - // saw our own heart beat - transition to query state - logger.info("saw our own heartbeat on topic {}", getTopic()); - publish(makeQuery()); - return goQuery(); - - } else { - logger.info("ignored old heartbeat message from {} on topic {}", msg.getSource(), getTopic()); - } - - return null; - } -} diff --git a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/state/State.java b/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/state/State.java deleted file mode 100644 index 66728ee2..00000000 --- a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/state/State.java +++ /dev/null @@ -1,372 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * ONAP - * ================================================================================ - * Copyright (C) 2018, 2020-2021 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 java.util.LinkedList; -import java.util.List; -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.Heartbeat; -import org.onap.policy.drools.pooling.message.Identification; -import org.onap.policy.drools.pooling.message.Leader; -import org.onap.policy.drools.pooling.message.Offline; -import org.onap.policy.drools.pooling.message.Query; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * A state in the finite state machine. - * - * <p>A state may have several timers associated with it, which must be cancelled whenever - * the state is changed. Assumes that timers are not continuously added to the same state. - */ -public abstract class State { - - private static final Logger logger = LoggerFactory.getLogger(State.class); - - /** - * Host pool manager. - */ - private final PoolingManager mgr; - - /** - * Timers added by this state. - */ - private final List<CancellableScheduledTask> timers = new LinkedList<>(); - - /** - * Constructor. - * - * @param mgr pooling manager - */ - protected State(PoolingManager mgr) { - this.mgr = mgr; - } - - /** - * Cancels the timers added by this state. - */ - public final void cancelTimers() { - timers.forEach(CancellableScheduledTask::cancel); - } - - /** - * Starts the state. The default method simply logs a message and returns. - */ - public void start() { - logger.info("entered {} for topic {}", getClass().getSimpleName(), getTopic()); - } - - /** - * Transitions to the "start" state. - * - * @return the new state - */ - public final State goStart() { - return mgr.goStart(); - } - - /** - * Transitions to the "query" state. - * - * @return the new state - */ - public State goQuery() { - return mgr.goQuery(); - } - - /** - * Goes active with a new set of assignments. - * - * @param asgn new assignments - * @return the new state, either Active or Inactive, depending on whether or not this - * host has an assignment - */ - protected State goActive(BucketAssignments asgn) { - startDistributing(asgn); - - if (asgn != null && asgn.hasAssignment(getHost())) { - return mgr.goActive(); - - } else { - return goInactive(); - } - } - - /** - * Transitions to the "inactive" state. - * - * @return the new state - */ - protected State goInactive() { - return mgr.goInactive(); - } - - /** - * Processes a message. The default method just returns {@code null}. - * - * @param msg message to be processed - * @return the new state, or {@code null} if the state is unchanged - */ - public State process(Heartbeat msg) { - logger.info("ignored heartbeat message from {} on topic {}", msg.getSource(), getTopic()); - return null; - } - - /** - * Processes a message. The default method just returns {@code null}. - * - * @param msg message to be processed - * @return the new state, or {@code null} if the state is unchanged - */ - public State process(Identification msg) { - logger.info("ignored ident message from {} on topic {}", msg.getSource(), getTopic()); - return null; - } - - /** - * Processes a message. The default method copies the assignments and then returns - * {@code null}. - * - * @param msg message to be processed - * @return the new state, or {@code null} if the state is unchanged - */ - public State process(Leader msg) { - if (isValid(msg)) { - logger.info("extract assignments from Leader message from {} on topic {}", msg.getSource(), getTopic()); - startDistributing(msg.getAssignments()); - } - - return null; - } - - /** - * Processes a message. The default method just returns {@code null}. - * - * @param msg message to be processed - * @return the new state, or {@code null} if the state is unchanged - */ - public State process(Offline msg) { - logger.info("ignored offline message from {} on topic {}", msg.getSource(), getTopic()); - return null; - } - - /** - * Processes a message. The default method just returns {@code null}. - * - * @param msg message to be processed - * @return the new state, or {@code null} if the state is unchanged - */ - public State process(Query msg) { - logger.info("ignored Query message from {} on topic {}", msg.getSource(), getTopic()); - return null; - } - - /** - * Determines if a message is valid and did not originate from this host. - * - * @param msg message to be validated - * @return {@code true} if the message is valid, {@code false} otherwise - */ - protected boolean isValid(Leader msg) { - BucketAssignments asgn = msg.getAssignments(); - if (asgn == null) { - logger.warn("Leader message from {} has no assignments for topic {}", msg.getSource(), getTopic()); - return false; - } - - // ignore Leader messages from ourself - String source = msg.getSource(); - if (source == null || source.equals(getHost())) { - logger.debug("ignore Leader message from {} for topic {}", msg.getSource(), getTopic()); - return false; - } - - // the new leader must equal the source - boolean result = source.equals(asgn.getLeader()); - - if (!result) { - logger.warn("Leader message from {} has an invalid assignment for topic {}", msg.getSource(), getTopic()); - } - - return result; - } - - /** - * Publishes a message. - * - * @param msg message to be published - */ - protected final void publish(Identification msg) { - mgr.publishAdmin(msg); - } - - /** - * Publishes a message. - * - * @param msg message to be published - */ - protected final void publish(Leader msg) { - mgr.publishAdmin(msg); - } - - /** - * Publishes a message. - * - * @param msg message to be published - */ - protected final void publish(Offline msg) { - mgr.publishAdmin(msg); - } - - /** - * Publishes a message. - * - * @param msg message to be published - */ - protected final void publish(Query msg) { - mgr.publishAdmin(msg); - } - - /** - * Publishes a message on the specified channel. - * - * @param channel channel - * @param msg message to be published - */ - protected final void publish(String channel, Heartbeat msg) { - mgr.publish(channel, msg); - } - - /** - * Starts distributing messages using the specified bucket assignments. - * - * @param assignments assignments - */ - protected final void startDistributing(BucketAssignments assignments) { - if (assignments != null) { - mgr.startDistributing(assignments); - } - } - - /** - * Schedules a timer to fire after a delay. - * - * @param delayMs delay in ms - * @param task task - */ - protected final void schedule(long delayMs, StateTimerTask task) { - timers.add(mgr.schedule(delayMs, task)); - } - - /** - * Schedules a timer to fire repeatedly. - * - * @param initialDelayMs initial delay ms - * @param delayMs delay ms - * @param task task - */ - protected final void scheduleWithFixedDelay(long initialDelayMs, long delayMs, StateTimerTask task) { - timers.add(mgr.scheduleWithFixedDelay(initialDelayMs, delayMs, task)); - } - - /** - * Indicates that we failed to see our own heartbeat; must be a problem with the - * internal topic. Assumes the problem is temporary and continues to use the current - * bucket assignments. - * - * @return a new {@link StartState} - */ - protected final State missedHeartbeat() { - publish(makeOffline()); - - return mgr.goStart(); - } - - /** - * Indicates that the internal topic failed; this should only be invoked from the - * StartState. Discards bucket assignments and begins processing everything locally. - * - * @return a new {@link InactiveState} - */ - protected final State internalTopicFailed() { - publish(makeOffline()); - mgr.startDistributing(null); - - return mgr.goInactive(); - } - - /** - * Makes a heart beat message. - * - * @param timestampMs time, in milliseconds, associated with the message - * - * @return a new message - */ - protected final Heartbeat makeHeartbeat(long timestampMs) { - return new Heartbeat(getHost(), timestampMs); - } - - /** - * Makes an Identification message. - * - * @return a new message - */ - protected Identification makeIdentification() { - return new Identification(getHost(), getAssignments()); - } - - /** - * Makes an "offline" message. - * - * @return a new message - */ - protected final Offline makeOffline() { - return new Offline(getHost()); - } - - /** - * Makes a query message. - * - * @return a new message - */ - protected final Query makeQuery() { - return new Query(getHost()); - } - - public final BucketAssignments getAssignments() { - return mgr.getAssignments(); - } - - public final String getHost() { - return mgr.getHost(); - } - - public final String getTopic() { - return mgr.getTopic(); - } - - public final PoolingProperties getProperties() { - return mgr.getProperties(); - } -} diff --git a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/state/StateTimerTask.java b/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/state/StateTimerTask.java deleted file mode 100644 index e4607f81..00000000 --- a/feature-pooling-dmaap/src/main/java/org/onap/policy/drools/pooling/state/StateTimerTask.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * ONAP - * ================================================================================ - * Copyright (C) 2018-2019 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; - -/** - * Task to be executed when a timer fires within a {@link State}. - */ -@FunctionalInterface -public interface StateTimerTask { - - /** - * Fires the timer. - * - * @return the new state, or {@code null} if the state is unchanged - */ - State fire(); - -} diff --git a/feature-pooling-dmaap/src/main/resources/META-INF/services/org.onap.policy.drools.features.DroolsControllerFeatureApi b/feature-pooling-dmaap/src/main/resources/META-INF/services/org.onap.policy.drools.features.DroolsControllerFeatureApi deleted file mode 100644 index cd59e469..00000000 --- a/feature-pooling-dmaap/src/main/resources/META-INF/services/org.onap.policy.drools.features.DroolsControllerFeatureApi +++ /dev/null @@ -1 +0,0 @@ -org.onap.policy.drools.pooling.PoolingFeature diff --git a/feature-pooling-dmaap/src/main/resources/META-INF/services/org.onap.policy.drools.features.PolicyControllerFeatureApi b/feature-pooling-dmaap/src/main/resources/META-INF/services/org.onap.policy.drools.features.PolicyControllerFeatureApi deleted file mode 100644 index cd59e469..00000000 --- a/feature-pooling-dmaap/src/main/resources/META-INF/services/org.onap.policy.drools.features.PolicyControllerFeatureApi +++ /dev/null @@ -1 +0,0 @@ -org.onap.policy.drools.pooling.PoolingFeature diff --git a/feature-pooling-dmaap/src/main/resources/META-INF/services/org.onap.policy.drools.features.PolicyEngineFeatureApi b/feature-pooling-dmaap/src/main/resources/META-INF/services/org.onap.policy.drools.features.PolicyEngineFeatureApi deleted file mode 100644 index cd59e469..00000000 --- a/feature-pooling-dmaap/src/main/resources/META-INF/services/org.onap.policy.drools.features.PolicyEngineFeatureApi +++ /dev/null @@ -1 +0,0 @@ -org.onap.policy.drools.pooling.PoolingFeature diff --git a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/DmaapManagerTest.java b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/DmaapManagerTest.java deleted file mode 100644 index ec554fc9..00000000 --- a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/DmaapManagerTest.java +++ /dev/null @@ -1,319 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * ONAP - * ================================================================================ - * Copyright (C) 2018-2020 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ - -package org.onap.policy.drools.pooling; - -import static org.assertj.core.api.Assertions.assertThatCode; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.CountDownLatch; -import org.junit.Before; -import org.junit.Test; -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; - -public class DmaapManagerTest { - - private static final String EXPECTED = "expected"; - private static final String MY_TOPIC = "my.topic"; - private static final String MSG = "a message"; - - private TopicListener listener; - private TopicSource source; - private boolean gotSources; - private TopicSink sink; - private boolean gotSinks; - private DmaapManager mgr; - - /** - * Setup. - * - * @throws Exception throws an exception - */ - @Before - public void setUp() throws Exception { - listener = mock(TopicListener.class); - source = mock(TopicSource.class); - gotSources = false; - sink = mock(TopicSink.class); - gotSinks = false; - - when(source.getTopic()).thenReturn(MY_TOPIC); - - when(sink.getTopic()).thenReturn(MY_TOPIC); - when(sink.send(any())).thenReturn(true); - - mgr = new DmaapManagerImpl(MY_TOPIC); - } - - @Test - public void testDmaapManager() { - // verify that the init methods were called - assertTrue(gotSources); - assertTrue(gotSinks); - } - - @Test(expected = PoolingFeatureException.class) - public void testDmaapManager_PoolingEx() throws PoolingFeatureException { - // force error by having no topics match - when(source.getTopic()).thenReturn(""); - - new DmaapManagerImpl(MY_TOPIC); - } - - @Test(expected = PoolingFeatureException.class) - public void testDmaapManager_IllegalArgEx() throws PoolingFeatureException { - // force error - new DmaapManagerImpl(MY_TOPIC) { - @Override - protected List<TopicSource> getTopicSources() { - throw new IllegalArgumentException(EXPECTED); - } - }; - } - - @Test - public void testGetTopic() { - assertEquals(MY_TOPIC, mgr.getTopic()); - } - - @Test(expected = PoolingFeatureException.class) - public void testFindTopicSource_NotFound() throws PoolingFeatureException { - // one item in list, and its topic doesn't match - new DmaapManagerImpl(MY_TOPIC) { - @Override - protected List<TopicSource> getTopicSources() { - return Arrays.asList(mock(TopicSource.class)); - } - }; - } - - @Test(expected = PoolingFeatureException.class) - public void testFindTopicSource_EmptyList() throws PoolingFeatureException { - // empty list - new DmaapManagerImpl(MY_TOPIC) { - @Override - protected List<TopicSource> getTopicSources() { - return Collections.emptyList(); - } - }; - } - - @Test(expected = PoolingFeatureException.class) - public void testFindTopicSink_NotFound() throws PoolingFeatureException { - // one item in list, and its topic doesn't match - new DmaapManagerImpl(MY_TOPIC) { - @Override - protected List<TopicSink> getTopicSinks() { - return Arrays.asList(mock(TopicSink.class)); - } - }; - } - - @Test(expected = PoolingFeatureException.class) - public void testFindTopicSink_EmptyList() throws PoolingFeatureException { - // empty list - new DmaapManagerImpl(MY_TOPIC) { - @Override - protected List<TopicSink> getTopicSinks() { - return Collections.emptyList(); - } - }; - } - - @Test - public void testStartPublisher() throws PoolingFeatureException { - - mgr.startPublisher(); - - // restart should have no effect - mgr.startPublisher(); - - // should be able to publish now - mgr.publish(MSG); - verify(sink).send(MSG); - } - - @Test - public void testStopPublisher() throws PoolingFeatureException { - // not publishing yet, so stopping should have no effect - mgr.stopPublisher(0); - - // now start it - mgr.startPublisher(); - - // this time, stop should do something - mgr.stopPublisher(0); - - // re-stopping should have no effect - assertThatCode(() -> mgr.stopPublisher(0)).doesNotThrowAnyException(); - } - - @Test - public void testStopPublisher_WithDelay() throws PoolingFeatureException { - - mgr.startPublisher(); - - long tbeg = System.currentTimeMillis(); - - mgr.stopPublisher(100L); - - assertTrue(System.currentTimeMillis() >= tbeg + 100L); - } - - @Test - public void testStopPublisher_WithDelayInterrupted() throws Exception { - - mgr.startPublisher(); - - long minms = 2000L; - - // tell the publisher to stop in minms + additional time - CountDownLatch latch = new CountDownLatch(1); - Thread thread = new Thread(() -> { - latch.countDown(); - mgr.stopPublisher(minms + 3000L); - }); - thread.start(); - - // wait for the thread to start - latch.await(); - - // interrupt it - it should immediately finish its work - thread.interrupt(); - - // wait for it to stop, but only wait the minimum time - thread.join(minms); - - assertFalse(thread.isAlive()); - } - - @Test - public void testStartConsumer() { - // not started yet - verify(source, never()).register(any()); - - mgr.startConsumer(listener); - verify(source).register(listener); - - // restart should have no effect - mgr.startConsumer(listener); - verify(source).register(listener); - } - - @Test - public void testStopConsumer() { - // not consuming yet, so stopping should have no effect - mgr.stopConsumer(listener); - verify(source, never()).unregister(any()); - - // now start it - mgr.startConsumer(listener); - - // this time, stop should do something - mgr.stopConsumer(listener); - verify(source).unregister(listener); - - // re-stopping should have no effect - mgr.stopConsumer(listener); - verify(source).unregister(listener); - } - - @Test - public void testPublish() throws PoolingFeatureException { - // cannot publish before starting - assertThatThrownBy(() -> mgr.publish(MSG)).as("publish,pre").isInstanceOf(PoolingFeatureException.class); - - mgr.startPublisher(); - - // publish several messages - mgr.publish(MSG); - verify(sink).send(MSG); - - mgr.publish(MSG + "a"); - verify(sink).send(MSG + "a"); - - mgr.publish(MSG + "b"); - verify(sink).send(MSG + "b"); - - // stop and verify we can no longer publish - mgr.stopPublisher(0); - assertThatThrownBy(() -> mgr.publish(MSG)).as("publish,stopped").isInstanceOf(PoolingFeatureException.class); - } - - @Test(expected = PoolingFeatureException.class) - public void testPublish_SendFailed() throws PoolingFeatureException { - mgr.startPublisher(); - - // arrange for send() to fail - when(sink.send(MSG)).thenReturn(false); - - mgr.publish(MSG); - } - - @Test(expected = PoolingFeatureException.class) - public void testPublish_SendEx() throws PoolingFeatureException { - mgr.startPublisher(); - - // arrange for send() to throw an exception - doThrow(new IllegalStateException(EXPECTED)).when(sink).send(MSG); - - mgr.publish(MSG); - } - - /** - * Manager with overrides. - */ - private class DmaapManagerImpl extends DmaapManager { - - public DmaapManagerImpl(String topic) throws PoolingFeatureException { - super(topic); - } - - @Override - protected List<TopicSource> getTopicSources() { - gotSources = true; - - // three sources, with the desired one in the middle - return Arrays.asList(mock(TopicSource.class), source, mock(TopicSource.class)); - } - - @Override - protected List<TopicSink> getTopicSinks() { - gotSinks = true; - - // three sinks, with the desired one in the middle - return Arrays.asList(mock(TopicSink.class), sink, mock(TopicSink.class)); - } - } -} 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 deleted file mode 100644 index b8970f1f..00000000 --- a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/EndToEndFeatureTest.java +++ /dev/null @@ -1,809 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * ONAP - * ================================================================================ - * Copyright (C) 2018-2021 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.google.gson.Gson; -import com.google.gson.JsonParseException; -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.TopicEndpointManager; -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: <dl> <dt>PolicyEngine, PolicyController, DroolsController</dt> <dd>mocked</dd> - * </dl> - * - * <p>The following fields must be set before executing this: <ul> <li>UEB_SERVERS</li> - * <li>INTERNAL_TOPIC</li> <li>EXTERNAL_TOPIC</li> </ul> - */ -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; - - /** - * Used to decode events from the external topic. - */ - private static final Gson mapper = new Gson(); - - /** - * Used to identify the current host. - */ - private static final ThreadLocal<Host> currentHost = new ThreadLocal<Host>(); - - /** - * 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() { - externalSink = TopicEndpointManager.getManager().addTopicSinks(makeSinkProperties(EXTERNAL_TOPIC)).get(0); - externalSink.start(); - - internalSink = TopicEndpointManager.getManager().addTopicSinks(makeSinkProperties(INTERNAL_TOPIC)).get(0); - internalSink.start(); - } - - /** - * Tear down after class. - * - */ - @AfterClass - public static void tearDownAfterClass() { - externalSink.stop(); - internalSink.stop(); - } - - /** - * Setup. - */ - @Before - public void setUp() { - ctx = null; - } - - /** - * Tear down. - */ - @After - public void tearDown() { - if (ctx != null) { - ctx.destroy(); - } - } - - /* - * This test should only be run manually, after configuring all of the fields, - * thus it is ignored. - */ - @Ignore - @Test - public void test_SingleHost() throws Exception { // NOSONAR - run(70, 1); - } - - /* - * This test should only be run manually, after configuring all of the fields, - * thus it is ignored. - */ - @Ignore - @Test - public void test_TwoHosts() throws Exception { // NOSONAR - run(200, 2); - } - - /* - * This test should only be run manually, after configuring all of the fields, - * thus it is ignored. - */ - @Ignore - @Test - public void test_ThreeHosts() throws Exception { // NOSONAR - 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; - } - - /** - * Decodes an event. - * - * @param event event - * @return the decoded event, or {@code null} if it cannot be decoded - */ - private static Object decodeEvent(String event) { - try { - return mapper.fromJson(event, TreeMap.class); - - } catch (JsonParseException e) { - logger.warn("cannot decode external event", e); - return null; - } - } - - /** - * Context used for a single test case. - */ - private static class Context { - - /** - * Hosts that have been added to this context. - */ - private final Deque<Host> hosts = new LinkedList<>(); - - /** - * Maps a drools controller to its policy controller. - */ - private final IdentityHashMap<DroolsController, PolicyController> 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 events number of events to be processed - */ - public Context(int events) { - eventCounter = new CountDownLatch(events); - } - - /** - * 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); - } - - /** - * 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; - - /** - * {@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 = TopicEndpointManager.getManager().addTopicSources(makeSourceProperties(EXTERNAL_TOPIC)) - .get(0); - internalSource = TopicEndpointManager.getManager().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); - - feature = new PoolingFeatureImpl(context, this); - } - - /** - * 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() { - 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 - * <i>AggregatedPolicyController.onTopicEvent</i>. - */ - private static class MyExternalTopicListener implements Answer<Void> { - - 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 = 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; - } - } - - /** - * Feature with overrides. - */ - private static class PoolingFeatureImpl extends PoolingFeature { - - private final Context context; - private final Host host; - - /** - * Constructor. - * - * @param context context - */ - public PoolingFeatureImpl(Context context, Host host) { - this.context = context; - this.host = host; - - /* - * 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; - } - - @Override - protected PoolingManagerImpl makeManager(String hostName, PolicyController controller, PoolingProperties props, - CountDownLatch activeLatch) { - - /* - * Set this before creating the test, because the test's superclass - * constructor uses it before the test object has a chance to store it. - */ - currentHost.set(host); - - return new PoolingManagerTest(hostName, controller, props, activeLatch); - } - } - - /** - * Pooling Manager with overrides. - */ - private static class PoolingManagerTest extends PoolingManagerImpl { - - /** - * Constructor. - * - * @param hostName the host - * @param controller the controller - * @param props the properties - * @param activeLatch the latch - */ - public PoolingManagerTest(String hostName, PolicyController controller, - PoolingProperties props, CountDownLatch activeLatch) { - - super(hostName, controller, props, activeLatch); - } - - @Override - protected DmaapManager makeDmaapManager(String topic) throws PoolingFeatureException { - return new DmaapManagerImpl(topic); - } - - @Override - protected boolean canDecodeEvent(DroolsController drools, String topic) { - return true; - } - - @Override - protected Object decodeEventWrapper(DroolsController drools, String topic, String event) { - return decodeEvent(event); - } - } - - /** - * DMaaP Manager with overrides. - */ - private static class DmaapManagerImpl extends DmaapManager { - - /** - * Constructor. - * - * @param topic the topic - * @throws PoolingFeatureException if an error occurs - */ - public DmaapManagerImpl(String topic) throws PoolingFeatureException { - super(topic); - } - - @Override - protected List<TopicSource> getTopicSources() { - Host host = currentHost.get(); - return Arrays.asList(host.internalSource, host.externalSource); - } - - @Override - protected List<TopicSink> getTopicSinks() { - return Arrays.asList(internalSink, externalSink); - } - } - - /** - * 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/FeatureTest.java b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/FeatureTest.java deleted file mode 100644 index bbd4c19f..00000000 --- a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/FeatureTest.java +++ /dev/null @@ -1,1040 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * ONAP - * ================================================================================ - * Copyright (C) 2018-2021 AT&T Intellectual Property. All rights reserved. - * Modifications Copyright (C) 2020 Nordix Foundation - * ================================================================================ - * 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.google.gson.Gson; -import com.google.gson.JsonParseException; -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.BlockingQueue; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; -import lombok.Getter; -import org.apache.commons.lang3.tuple.Pair; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; -import org.onap.policy.common.endpoints.event.comm.Topic; -import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure; -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.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. However, the following are not: - * <dl> - * <dt>DMaaP sources and sinks</dt> - * <dd>simulated using queues. There is one queue for the external topic, and one queue - * for each host's internal topic. Messages published to the "admin" channel are simply - * sent to all of the hosts' internal topic queues</dd> - * <dt>PolicyEngine, PolicyController, DroolsController</dt> - * <dd>mocked</dd> - * </dl> - * - * <p>Invoke {@link #runSlow()}, before the test, to slow things down. - */ - -public class FeatureTest { - private static final Logger logger = LoggerFactory.getLogger(FeatureTest.class); - /** - * Name of the topic used for inter-host communication. - */ - private static final String INTERNAL_TOPIC = "my.internal.topic"; - /** - * Name of the topic from which "external" events "arrive". - */ - private static final String EXTERNAL_TOPIC = "my.external.topic"; - /** - * Name of the controller. - */ - private static final String CONTROLLER1 = "controller.one"; - private static long stdReactivateWaitMs = 200; - private static long stdIdentificationMs = 60; - private static long stdStartHeartbeatMs = 60; - private static long stdActiveHeartbeatMs = 50; - private static long stdInterHeartbeatMs = 5; - private static long stdOfflinePubWaitMs = 2; - private static long stdPollMs = 2; - private static long stdInterPollMs = 2; - private static long stdEventWaitSec = 10; - /** - * Used to decode events from the external topic. - */ - private static final Gson mapper = new Gson(); - /** - * Used to identify the current context. - */ - private static final ThreadLocal<Context> currentContext = new ThreadLocal<Context>(); - /** - * Context for the current test case. - */ - private Context ctx; - /** - * Setup. - */ - - @Before - public void setUp() { - ctx = null; - } - /** - * Tear down. - */ - - @After - public void tearDown() { - if (ctx != null) { - ctx.destroy(); - } - } - - @Test - public void test_SingleHost() throws Exception { - run(70, 1); - } - - @Test - public void test_TwoHosts() throws Exception { - run(200, 2); - } - - @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(); - for (int x = 0; x < nmessages; ++x) { - ctx.offerExternal(makeMessage(x)); - } - ctx.awaitEvents(stdEventWaitSec, TimeUnit.SECONDS); - assertEquals(0, ctx.getDecodeErrors()); - assertEquals(0, ctx.getRemainingEvents()); - ctx.checkAllSawAMsg(); - } - - private String makeMessage(int reqnum) { - return "{\"reqid\":\"req" + reqnum + "\", \"data\":\"hello " + reqnum + "\"}"; - } - /** - * Invoke this to slow the timers down. - */ - - protected static void runSlow() { - stdReactivateWaitMs = 10000; - stdIdentificationMs = 10000; - stdStartHeartbeatMs = 15000; - stdActiveHeartbeatMs = 12000; - stdInterHeartbeatMs = 5000; - stdOfflinePubWaitMs = 2; - stdPollMs = 2; - stdInterPollMs = 2000; - stdEventWaitSec = 1000; - } - /** - * Decodes an event. - * - * @param event event - * @return the decoded event, or {@code null} if it cannot be decoded - */ - - private static Object decodeEvent(String event) { - try { - return mapper.fromJson(event, TreeMap.class); - } catch (JsonParseException e) { - logger.warn("cannot decode external event", e); - return null; - } - } - /** - * Context used for a single test case. - */ - - private static class Context { - /** - * Hosts that have been added to this context. - */ - private final Deque<Host> hosts = new LinkedList<>(); - /** - * Maps a drools controller to its policy controller. - */ - private final IdentityHashMap<DroolsController, PolicyController> drools2policy = new IdentityHashMap<>(); - /** - * Maps a channel to its queue. Does <i>not</i> include the "admin" channel. - */ - private final ConcurrentMap<String, BlockingQueue<String>> channel2queue = new ConcurrentHashMap<>(7); - /** - * Counts the number of decode errors. - */ - private final AtomicInteger numDecodeErrors = new AtomicInteger(0); - /** - * Number of events we're still waiting to receive. - */ - private final CountDownLatch eventCounter; - /** - * The current host. Set by {@link #withHost(Host, VoidFunction)} and used by - * {@link #getCurrentHost()}. - */ - private Host currentHost = null; - - /** - * Constructor. - * - * @param events number of events to be processed - */ - - public Context(int events) { - eventCounter = new CountDownLatch(events); - } - /** - * 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; - } - } - - /** - * Sets {@link #currentHost} to the specified host, and then invokes the given - * function. Resets {@link #currentHost} to {@code null} before returning. - * - * @param host host - * @param func function to invoke - */ - - public void withHost(Host host, VoidFunction func) { - currentHost = host; - func.apply(); - currentHost = null; - } - - /** - * Offers an event to the external topic. As each host needs a copy, it is posted - * to each Host's queue. - * - * @param event event - */ - - public void offerExternal(String event) { - for (Host host : hosts) { - host.getExternalTopic().offer(event); - } - } - - /** - * Adds an internal channel to the set of channels. - * - * @param channel channel - * @param queue the channel's queue - */ - - public void addInternal(String channel, BlockingQueue<String> queue) { - channel2queue.put(channel, queue); - } - - /** - * Offers a message to all internal channels. - * - * @param message message - */ - - public void offerInternal(String message) { - channel2queue.values().forEach(queue -> queue.offer(message)); - } - - /** - * 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 numDecodeErrors.get(); - } - - /** - * Increments the count of decode errors. - */ - - public void bumpDecodeErrors() { - numDecodeErrors.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 - */ - - public boolean awaitEvents(long time, TimeUnit units) throws InterruptedException { - return eventCounter.await(time, units); - } - - /** - * Gets the current host, provided this is used from within a call to - * {@link #withHost(Host, VoidFunction)}. - * - * @return the current host, or {@code null} if there is no current host - */ - - public Host getCurrentHost() { - return currentHost; - } - } - - /** - * Simulates a single "host". - */ - - private static class Host { - private final Context context; - private final PoolingFeature feature; - - /** - * {@code True} if this host has processed a message, {@code false} otherwise. - */ - - private final AtomicBoolean sawMsg = new AtomicBoolean(false); - - /** - * This host's internal "DMaaP" topic. - */ - - private final BlockingQueue<String> msgQueue = new LinkedBlockingQueue<>(); - - /** - * Queue for the external "DMaaP" topic. - */ - @Getter - private final BlockingQueue<String> externalTopic = new LinkedBlockingQueue<String>(); - - /** - * Source that reads from the external topic and posts to the listener. - */ - - private TopicSource externalSource; - - // 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) { - this.context = context; - when(controller.getName()).thenReturn(CONTROLLER1); - when(controller.getDrools()).thenReturn(drools); - // 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); - // arrange to read from the external topic - externalSource = new TopicSourceImpl(EXTERNAL_TOPIC, externalTopic); - feature = new PoolingFeatureImpl(context); - } - - /** - * Get name. - * - * @return the host name - */ - - public String getName() { - return feature.getHost(); - } - - /** - * 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() { - context.withHost(this, () -> { - feature.beforeStart(engine); - feature.afterCreate(controller); - // assign the queue for this host's internal topic - context.addInternal(getName(), msgQueue); - 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(); - } - - /** - * Get internal queue. - * - * @return the queue associated with this host's internal topic - */ - - public BlockingQueue<String> getInternalQueue() { - return msgQueue; - } - } - - /** - * Listener for the external topic. Simulates the actions taken by - * <i>AggregatedPolicyController.onTopicEvent</i>. - */ - - private static class MyExternalTopicListener implements Answer<Void> { - 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 = 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; - } - } - - /** - * Sink implementation that puts a message on the queue specified by the - * <i>channel</i> embedded within the message. If it's the "admin" channel, then the - * message is placed on all queues. - */ - - private static class TopicSinkImpl extends TopicImpl implements TopicSink { - private final Context context; - - /** - * Constructor. - * - * @param context context - */ - - public TopicSinkImpl(Context context) { - this.context = context; - } - - @Override - public synchronized boolean send(String message) { - if (!isAlive()) { - return false; - } - try { - context.offerInternal(message); - return true; - } catch (JsonParseException e) { - logger.warn("could not decode message: {}", message); - context.bumpDecodeErrors(); - return false; - } - } - } - - /** - * Source implementation that reads from a queue associated with a topic. - */ - - private static class TopicSourceImpl extends TopicImpl implements TopicSource { - - private final String topic; - /** - * Queue from which to retrieve messages. - */ - private final BlockingQueue<String> queue; - /** - * Manages the current consumer thread. The "first" item is used as a trigger to - * tell the thread to stop processing, while the "second" item is triggered <i>by - * the thread</i> when it completes. - */ - private AtomicReference<Pair<CountDownLatch, CountDownLatch>> pair = new AtomicReference<>(null); - - /** - * Constructor. - * - * @param type topic type - * @param queue topic from which to read - */ - - public TopicSourceImpl(String type, BlockingQueue<String> queue) { - this.topic = type; - this.queue = queue; - } - - @Override - public String getTopic() { - return topic; - } - - @Override - public boolean offer(String event) { - throw new UnsupportedOperationException("offer topic source"); - } - - /** - * Starts a thread that takes messages from the queue and gives them to the - * listener. Stops the thread of any previously registered listener. - */ - - @Override - public void register(TopicListener listener) { - Pair<CountDownLatch, CountDownLatch> newPair = Pair.of(new CountDownLatch(1), new CountDownLatch(1)); - reregister(newPair); - Thread thread = new Thread(() -> { - try { - do { - processMessages(newPair.getLeft(), listener); - } while (!newPair.getLeft().await(stdInterPollMs, TimeUnit.MILLISECONDS)); - logger.info("topic source thread completed"); - } catch (InterruptedException e) { - logger.warn("topic source thread aborted", e); - Thread.currentThread().interrupt(); - } catch (RuntimeException e) { - logger.warn("topic source thread aborted", e); - } - newPair.getRight().countDown(); - }); - thread.setDaemon(true); - thread.start(); - } - - /** - * Stops the thread of <i>any</i> currently registered listener. - */ - - @Override - public void unregister(TopicListener listener) { - reregister(null); - } - - /** - * Registers a new "pair" with this source, stopping the consumer associated with - * any previous registration. - * - * @param newPair the new "pair", or {@code null} to unregister - */ - - private void reregister(Pair<CountDownLatch, CountDownLatch> newPair) { - try { - Pair<CountDownLatch, CountDownLatch> oldPair = pair.getAndSet(newPair); - if (oldPair == null) { - if (newPair == null) { - // unregister was invoked twice in a row - logger.warn("re-unregister for topic source"); - } - // no previous thread to stop - return; - } - // need to stop the previous thread - // tell it to stop - oldPair.getLeft().countDown(); - // wait for it to stop - if (!oldPair.getRight().await(2, TimeUnit.SECONDS)) { - logger.warn("old topic registration is still running"); - } - } catch (InterruptedException e) { - logger.warn("old topic registration may still be running", e); - Thread.currentThread().interrupt(); - } - if (newPair != null) { - // register was invoked twice in a row - logger.warn("re-register for topic source"); - } - } - - /** - * Polls for messages from the topic and offers them to the listener. - * - * @param stopped triggered if processing should stop - * @param listener listener - * @throws InterruptedException throws interrupted exception - */ - - private void processMessages(CountDownLatch stopped, TopicListener listener) throws InterruptedException { - for (int x = 0; x < 5 && stopped.getCount() > 0; ++x) { - String msg = queue.poll(stdPollMs, TimeUnit.MILLISECONDS); - if (msg == null) { - return; - } - listener.onTopicEvent(CommInfrastructure.UEB, topic, msg); - } - } - } - - /** - * Topic implementation. Most methods just throw - * {@link UnsupportedOperationException}. - */ - - private static class TopicImpl implements Topic { - - /** - * Constructor. - */ - - public TopicImpl() { - super(); - } - - @Override - public String getTopic() { - return INTERNAL_TOPIC; - } - - @Override - public String getEffectiveTopic() { - return INTERNAL_TOPIC; - } - - @Override - public CommInfrastructure getTopicCommInfrastructure() { - throw new UnsupportedOperationException("topic protocol"); - } - - @Override - public List<String> getServers() { - throw new UnsupportedOperationException("topic servers"); - } - - @Override - public String[] getRecentEvents() { - throw new UnsupportedOperationException("topic events"); - } - - @Override - public void register(TopicListener topicListener) { - throw new UnsupportedOperationException("register topic"); - } - - @Override - public void unregister(TopicListener topicListener) { - throw new UnsupportedOperationException("unregister topic"); - } - - @Override - public synchronized boolean start() { - return true; - } - - @Override - public synchronized boolean stop() { - return true; - } - - @Override - public synchronized void shutdown() { - // do nothing - } - - @Override - public synchronized boolean isAlive() { - return true; - } - - @Override - public boolean lock() { - throw new UnsupportedOperationException("lock topicink"); - } - - @Override - public boolean unlock() { - throw new UnsupportedOperationException("unlock topic"); - } - - @Override - public boolean isLocked() { - throw new UnsupportedOperationException("topic isLocked"); - } - } - - /** - * Feature with overrides. - */ - - private static class PoolingFeatureImpl extends PoolingFeature { - private final Context context; - - /** - * Constructor. - * - * @param context context - */ - - public PoolingFeatureImpl(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), - "" + stdOfflinePubWaitMs); - props.setProperty(specialize(PoolingProperties.START_HEARTBEAT_MS, CONTROLLER1), - "" + stdStartHeartbeatMs); - props.setProperty(specialize(PoolingProperties.REACTIVATE_MS, CONTROLLER1), "" + stdReactivateWaitMs); - props.setProperty(specialize(PoolingProperties.IDENTIFICATION_MS, CONTROLLER1), "" + stdIdentificationMs); - props.setProperty(specialize(PoolingProperties.ACTIVE_HEARTBEAT_MS, CONTROLLER1), - "" + stdActiveHeartbeatMs); - props.setProperty(specialize(PoolingProperties.INTER_HEARTBEAT_MS, CONTROLLER1), - "" + stdInterHeartbeatMs); - 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; - } - - @Override - protected PoolingManagerImpl makeManager(String host, PolicyController controller, PoolingProperties props, - CountDownLatch activeLatch) { - currentContext.set(context); - return new PoolingManagerTest(host, controller, props, activeLatch); - } - } - - /** - * Pooling Manager with overrides. - */ - - private static class PoolingManagerTest extends PoolingManagerImpl { - - /** - * Constructor. - * - * @param host the host - * @param controller the controller - * @param props the properties - * @param activeLatch the latch - */ - - public PoolingManagerTest(String host, PolicyController controller, PoolingProperties props, - CountDownLatch activeLatch) { - super(host, controller, props, activeLatch); - } - - @Override - protected DmaapManager makeDmaapManager(String topic) throws PoolingFeatureException { - return new DmaapManagerImpl(topic); - } - - @Override - protected boolean canDecodeEvent(DroolsController drools, String topic) { - return true; - } - - @Override - protected Object decodeEventWrapper(DroolsController drools, String topic, String event) { - return decodeEvent(event); - } - } - - /** - * DMaaP Manager with overrides. - */ - - private static class DmaapManagerImpl extends DmaapManager { - - /** - * Constructor. - * - * @param topic the topic - * @throws PoolingFeatureException if an error occurs - */ - - public DmaapManagerImpl(String topic) throws PoolingFeatureException { - super(topic); - } - - @Override - protected List<TopicSource> getTopicSources() { - return Arrays.asList(new TopicSourceImpl(INTERNAL_TOPIC, - currentContext.get().getCurrentHost().getInternalQueue())); - } - - @Override - protected List<TopicSink> getTopicSinks() { - return Arrays.asList(new TopicSinkImpl(currentContext.get())); - } - } - - /** - * Controller that also implements the {@link TopicListener} interface. - */ - - private static interface ListenerController extends PolicyController, TopicListener { - } - - /** - * Simple function that takes no arguments and returns nothing. - */ - - @FunctionalInterface - private static interface VoidFunction { - void apply(); - } -} diff --git a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/PoolingFeatureExceptionTest.java b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/PoolingFeatureExceptionTest.java deleted file mode 100644 index 731736a1..00000000 --- a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/PoolingFeatureExceptionTest.java +++ /dev/null @@ -1,35 +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 org.junit.Test; -import org.onap.policy.common.utils.test.ExceptionsTester; - -public class PoolingFeatureExceptionTest extends ExceptionsTester { - - @Test - public void test() { - assertEquals(5, test(PoolingFeatureException.class)); - } - -} diff --git a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/PoolingFeatureRtExceptionTest.java b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/PoolingFeatureRtExceptionTest.java deleted file mode 100644 index f505ccdf..00000000 --- a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/PoolingFeatureRtExceptionTest.java +++ /dev/null @@ -1,35 +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 org.junit.Test; -import org.onap.policy.common.utils.test.ExceptionsTester; - -public class PoolingFeatureRtExceptionTest extends ExceptionsTester { - - @Test - public void test() { - assertEquals(5, test(PoolingFeatureRtException.class)); - } - -} diff --git a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/PoolingFeatureTest.java b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/PoolingFeatureTest.java deleted file mode 100644 index 02a4db5c..00000000 --- a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/PoolingFeatureTest.java +++ /dev/null @@ -1,547 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * ONAP - * ================================================================================ - * Copyright (C) 2018, 2020 AT&T Intellectual Property. All rights reserved. - * Modifications Copyright (C) 2020 Nordix Foundation - * ================================================================================ - * 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.assertFalse; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; -import java.util.Properties; -import java.util.concurrent.CountDownLatch; -import org.apache.commons.lang3.tuple.Pair; -import org.junit.Before; -import org.junit.Test; -import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure; -import org.onap.policy.common.endpoints.event.comm.TopicSink; -import org.onap.policy.common.endpoints.event.comm.TopicSource; -import org.onap.policy.drools.controller.DroolsController; -import org.onap.policy.drools.system.PolicyController; -import org.onap.policy.drools.system.PolicyEngine; - -public class PoolingFeatureTest { - - private static final String CONTROLLER1 = "controllerA"; - private static final String CONTROLLER2 = "controllerB"; - private static final String CONTROLLER_DISABLED = "controllerDisabled"; - private static final String CONTROLLER_EX = "controllerException"; - private static final String CONTROLLER_UNKNOWN = "controllerUnknown"; - - private static final String TOPIC1 = "topic.one"; - private static final String TOPIC2 = "topic.two"; - - private static final String EVENT1 = "event.one"; - private static final String EVENT2 = "event.two"; - - private static final Object OBJECT1 = new Object(); - private static final Object OBJECT2 = new Object(); - - private Properties props; - private PolicyEngine engine; - private PolicyController controller1; - private PolicyController controller2; - private PolicyController controllerDisabled; - private PolicyController controllerException; - private PolicyController controllerUnknown; - private DroolsController drools1; - private DroolsController drools2; - private DroolsController droolsDisabled; - private List<Pair<PoolingManagerImpl, PoolingProperties>> managers; - private PoolingManagerImpl mgr1; - private PoolingManagerImpl mgr2; - - private PoolingFeature pool; - - /** - * Setup. - * - * @throws Exception exception - */ - @Before - public void setUp() throws Exception { - props = initProperties(); - engine = mock(PolicyEngine.class); - controller1 = mock(PolicyController.class); - controller2 = mock(PolicyController.class); - controllerDisabled = mock(PolicyController.class); - controllerException = mock(PolicyController.class); - controllerUnknown = mock(PolicyController.class); - drools1 = mock(DroolsController.class); - drools2 = mock(DroolsController.class); - droolsDisabled = mock(DroolsController.class); - managers = new LinkedList<>(); - - when(controller1.getName()).thenReturn(CONTROLLER1); - when(controller2.getName()).thenReturn(CONTROLLER2); - when(controllerDisabled.getName()).thenReturn(CONTROLLER_DISABLED); - when(controllerException.getName()).thenReturn(CONTROLLER_EX); - when(controllerUnknown.getName()).thenReturn(CONTROLLER_UNKNOWN); - - pool = new PoolingFeatureImpl(); - - pool.beforeStart(engine); - - pool.afterCreate(controller1); - pool.afterCreate(controller2); - - mgr1 = managers.get(0).getLeft(); - mgr2 = managers.get(1).getLeft(); - } - - @Test - public void test() { - assertEquals(2, managers.size()); - } - - @Test - public void testGetHost() { - String host = pool.getHost(); - assertNotNull(host); - - // create another and ensure it generates another host name - pool = new PoolingFeatureImpl(); - String host2 = pool.getHost(); - assertNotNull(host2); - - assertNotEquals(host, host2); - } - - @Test - public void testGetSequenceNumber() { - assertEquals(0, pool.getSequenceNumber()); - } - - @Test - public void testBeforeStartEngine() { - pool = new PoolingFeatureImpl(); - - assertFalse(pool.beforeStart(engine)); - } - - @Test - public void testAfterCreate() { - managers.clear(); - pool = new PoolingFeatureImpl(); - pool.beforeStart(engine); - - assertFalse(pool.afterCreate(controller1)); - assertEquals(1, managers.size()); - - // duplicate - assertFalse(pool.afterCreate(controller1)); - assertEquals(1, managers.size()); - - // second controller - assertFalse(pool.afterCreate(controller2)); - assertEquals(2, managers.size()); - } - - @Test - public void testAfterCreate_NotEnabled() { - managers.clear(); - pool = new PoolingFeatureImpl(); - pool.beforeStart(engine); - - assertFalse(pool.afterCreate(controllerDisabled)); - assertTrue(managers.isEmpty()); - } - - @Test(expected = PoolingFeatureRtException.class) - public void testAfterCreate_PropertyEx() { - managers.clear(); - pool = new PoolingFeatureImpl(); - pool.beforeStart(engine); - - pool.afterCreate(controllerException); - } - - @Test(expected = PoolingFeatureRtException.class) - public void testAfterCreate_NoProps() { - pool = new PoolingFeatureImpl(); - - // did not perform globalInit, which is an error - - pool.afterCreate(controller1); - } - - @Test - public void testAfterCreate_NoFeatProps() { - managers.clear(); - pool = new PoolingFeatureImpl(); - pool.beforeStart(engine); - - assertFalse(pool.afterCreate(controllerUnknown)); - assertTrue(managers.isEmpty()); - } - - @Test - public void testBeforeStart() throws Exception { - assertFalse(pool.beforeStart(controller1)); - verify(mgr1).beforeStart(); - - // ensure it's still in the map by re-invoking - assertFalse(pool.beforeStart(controller1)); - verify(mgr1, times(2)).beforeStart(); - - assertFalse(pool.beforeStart(controllerDisabled)); - } - - @Test - public void testAfterStart() { - assertFalse(pool.afterStart(controller1)); - verify(mgr1).afterStart(); - - // ensure it's still in the map by re-invoking - assertFalse(pool.afterStart(controller1)); - verify(mgr1, times(2)).afterStart(); - - assertFalse(pool.afterStart(controllerDisabled)); - } - - @Test - public void testBeforeStop() { - assertFalse(pool.beforeStop(controller1)); - verify(mgr1).beforeStop(); - - // ensure it's still in the map by re-invoking - assertFalse(pool.beforeStop(controller1)); - verify(mgr1, times(2)).beforeStop(); - - assertFalse(pool.beforeStop(controllerDisabled)); - } - - @Test - public void testAfterStop() { - assertFalse(pool.afterStop(controller1)); - verify(mgr1).afterStop(); - - assertFalse(pool.afterStop(controllerDisabled)); - - // count should be unchanged - verify(mgr1).afterStop(); - } - - @Test - public void testAfterHalt() { - assertFalse(pool.afterHalt(controller1)); - assertFalse(pool.afterHalt(controller1)); - - verify(mgr1, never()).afterStop(); - - assertFalse(pool.afterStop(controllerDisabled)); - } - - @Test - public void testAfterShutdown() { - assertFalse(pool.afterShutdown(controller1)); - assertFalse(pool.afterShutdown(controller1)); - - verify(mgr1, never()).afterStop(); - - assertFalse(pool.afterStop(controllerDisabled)); - } - - @Test - public void testBeforeLock() { - assertFalse(pool.beforeLock(controller1)); - verify(mgr1).beforeLock(); - - // ensure it's still in the map by re-invoking - assertFalse(pool.beforeLock(controller1)); - verify(mgr1, times(2)).beforeLock(); - - assertFalse(pool.beforeLock(controllerDisabled)); - } - - @Test - public void testAfterUnlock() { - assertFalse(pool.afterUnlock(controller1)); - verify(mgr1).afterUnlock(); - - // ensure it's still in the map by re-invoking - assertFalse(pool.afterUnlock(controller1)); - verify(mgr1, times(2)).afterUnlock(); - - assertFalse(pool.afterUnlock(controllerDisabled)); - } - - @Test - public void testBeforeOffer() { - assertFalse(pool.beforeOffer(controller1, CommInfrastructure.UEB, TOPIC1, EVENT1)); - verify(mgr1).beforeOffer(TOPIC1, EVENT1); - - // ensure that the args were captured - pool.beforeInsert(drools1, OBJECT1); - verify(mgr1).beforeInsert(TOPIC1, OBJECT1); - - - // ensure it's still in the map by re-invoking - assertFalse(pool.beforeOffer(controller1, CommInfrastructure.UEB, TOPIC2, EVENT2)); - verify(mgr1).beforeOffer(TOPIC2, EVENT2); - - // ensure that the new args were captured - pool.beforeInsert(drools1, OBJECT2); - verify(mgr1).beforeInsert(TOPIC2, OBJECT2); - - - assertFalse(pool.beforeOffer(controllerDisabled, CommInfrastructure.UEB, TOPIC1, EVENT1)); - } - - @Test - public void testBeforeOffer_NotFound() { - assertFalse(pool.beforeOffer(controllerDisabled, CommInfrastructure.UEB, TOPIC1, EVENT1)); - } - - @Test - public void testBeforeOffer_MgrTrue() { - - // manager will return true - when(mgr1.beforeOffer(any(), any())).thenReturn(true); - - assertTrue(pool.beforeOffer(controller1, CommInfrastructure.UEB, TOPIC1, EVENT1)); - verify(mgr1).beforeOffer(TOPIC1, EVENT1); - - // ensure it's still in the map by re-invoking - assertTrue(pool.beforeOffer(controller1, CommInfrastructure.UEB, TOPIC2, EVENT2)); - verify(mgr1).beforeOffer(TOPIC2, EVENT2); - - assertFalse(pool.beforeOffer(controllerDisabled, CommInfrastructure.UEB, TOPIC1, EVENT1)); - } - - @Test - public void testBeforeInsert() { - pool.beforeOffer(controller1, CommInfrastructure.UEB, TOPIC1, EVENT1); - assertFalse(pool.beforeInsert(drools1, OBJECT1)); - verify(mgr1).beforeInsert(TOPIC1, OBJECT1); - - // ensure it's still in the map by re-invoking - pool.beforeOffer(controller1, CommInfrastructure.UEB, TOPIC2, EVENT2); - assertFalse(pool.beforeInsert(drools1, OBJECT2)); - verify(mgr1).beforeInsert(TOPIC2, OBJECT2); - - pool.beforeOffer(controllerDisabled, CommInfrastructure.UEB, TOPIC2, EVENT2); - assertFalse(pool.beforeInsert(droolsDisabled, OBJECT1)); - } - - @Test - public void testBeforeInsert_NoArgs() { - - // call beforeInsert without beforeOffer - assertFalse(pool.beforeInsert(drools1, OBJECT1)); - verify(mgr1, never()).beforeInsert(any(), any()); - - assertFalse(pool.beforeInsert(droolsDisabled, OBJECT1)); - verify(mgr1, never()).beforeInsert(any(), any()); - } - - @Test - public void testBeforeInsert_ArgEx() { - // generate exception - pool = new PoolingFeatureImpl() { - @Override - protected PolicyController getController(DroolsController droolsController) { - throw new IllegalArgumentException(); - } - }; - - pool.beforeOffer(controller1, CommInfrastructure.UEB, TOPIC1, EVENT1); - assertFalse(pool.beforeInsert(drools1, OBJECT1)); - verify(mgr1, never()).beforeInsert(any(), any()); - } - - @Test - public void testBeforeInsert_StateEx() { - // generate exception - pool = new PoolingFeatureImpl() { - @Override - protected PolicyController getController(DroolsController droolsController) { - throw new IllegalStateException(); - } - }; - - pool.beforeOffer(controller1, CommInfrastructure.UEB, TOPIC1, EVENT1); - assertFalse(pool.beforeInsert(drools1, OBJECT1)); - verify(mgr1, never()).beforeInsert(any(), any()); - } - - @Test - public void testBeforeInsert_NullController() { - - // return null controller - pool = new PoolingFeatureImpl() { - @Override - protected PolicyController getController(DroolsController droolsController) { - return null; - } - }; - - pool.beforeOffer(controller1, CommInfrastructure.UEB, TOPIC1, EVENT1); - assertFalse(pool.beforeInsert(drools1, OBJECT1)); - verify(mgr1, never()).beforeInsert(any(), any()); - } - - @Test - public void testBeforeInsert_NotFound() { - - pool.beforeOffer(controllerDisabled, CommInfrastructure.UEB, TOPIC2, EVENT2); - assertFalse(pool.beforeInsert(droolsDisabled, OBJECT1)); - } - - @Test - public void testAfterOffer() { - // this will create OfferArgs - pool.beforeOffer(controller1, CommInfrastructure.UEB, TOPIC1, EVENT1); - - // this should clear them - assertFalse(pool.afterOffer(controller1, CommInfrastructure.UEB, TOPIC2, EVENT2, true)); - - assertFalse(pool.beforeInsert(drools1, OBJECT1)); - verify(mgr1, never()).beforeInsert(any(), any()); - - - assertFalse(pool.beforeInsert(droolsDisabled, OBJECT1)); - } - - @Test - public void testDoManager() throws Exception { - assertFalse(pool.beforeStart(controller1)); - verify(mgr1).beforeStart(); - - // ensure it's still in the map by re-invoking - assertFalse(pool.beforeStart(controller1)); - verify(mgr1, times(2)).beforeStart(); - - - // different controller - assertFalse(pool.beforeStart(controller2)); - verify(mgr2).beforeStart(); - - // ensure it's still in the map by re-invoking - assertFalse(pool.beforeStart(controller2)); - verify(mgr2, times(2)).beforeStart(); - - - assertFalse(pool.beforeStart(controllerDisabled)); - } - - @Test - public void testDoManager_NotFound() { - assertFalse(pool.beforeStart(controllerDisabled)); - } - - @Test(expected = RuntimeException.class) - public void testDoManager_Ex() throws Exception { - - // generate exception - doThrow(new RuntimeException()).when(mgr1).beforeStart(); - - pool.beforeStart(controller1); - } - - private Properties initProperties() { - Properties props = new Properties(); - - initProperties(props, "A", 0); - initProperties(props, "B", 1); - initProperties(props, "Exception", 2); - - props.setProperty("pooling.controllerDisabled.enabled", "false"); - - props.setProperty("pooling.controllerException.offline.queue.limit", "INVALID NUMBER"); - - return props; - } - - private void initProperties(Properties props, String suffix, int offset) { - props.setProperty("pooling.controller" + suffix + ".topic", "topic." + suffix); - props.setProperty("pooling.controller" + suffix + ".enabled", "true"); - props.setProperty("pooling.controller" + suffix + ".offline.queue.limit", String.valueOf(5 + offset)); - props.setProperty("pooling.controller" + suffix + ".offline.queue.age.milliseconds", - String.valueOf(100 + offset)); - props.setProperty("pooling.controller" + suffix + ".start.heartbeat.milliseconds", String.valueOf(10 + offset)); - props.setProperty("pooling.controller" + suffix + ".reactivate.milliseconds", String.valueOf(20 + offset)); - props.setProperty("pooling.controller" + suffix + ".identification.milliseconds", String.valueOf(30 + offset)); - props.setProperty("pooling.controller" + suffix + ".active.heartbeat.milliseconds", - String.valueOf(40 + offset)); - props.setProperty("pooling.controller" + suffix + ".inter.heartbeat.milliseconds", String.valueOf(50 + offset)); - } - - /** - * Feature with overrides. - */ - private class PoolingFeatureImpl extends PoolingFeature { - - @Override - protected Properties getProperties(String featName) { - if (PoolingProperties.FEATURE_NAME.equals(featName)) { - return props; - } else { - throw new IllegalArgumentException("unknown feature name"); - } - } - - @Override - protected PoolingManagerImpl makeManager(String host, PolicyController controller, PoolingProperties props, - CountDownLatch activeLatch) { - - PoolingManagerImpl mgr = mock(PoolingManagerImpl.class); - - managers.add(Pair.of(mgr, props)); - - return mgr; - } - - @Override - protected PolicyController getController(DroolsController droolsController) { - if (droolsController == drools1) { - return controller1; - } else if (droolsController == drools2) { - return controller2; - } else if (droolsController == droolsDisabled) { - return controllerDisabled; - } else { - throw new IllegalArgumentException("unknown drools controller"); - } - } - - @Override - protected List<TopicSource> initTopicSources(Properties props) { - return Collections.emptyList(); - } - - @Override - protected List<TopicSink> initTopicSinks(Properties props) { - return Collections.emptyList(); - } - } -} diff --git a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/PoolingManagerImplTest.java b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/PoolingManagerImplTest.java deleted file mode 100644 index 21bd62d1..00000000 --- a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/PoolingManagerImplTest.java +++ /dev/null @@ -1,994 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * ONAP - * ================================================================================ - * Copyright (C) 2018-2020 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ - -package org.onap.policy.drools.pooling; - -import static org.assertj.core.api.Assertions.assertThatCode; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.contains; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.LinkedList; -import java.util.Properties; -import java.util.Queue; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure; -import org.onap.policy.common.endpoints.event.comm.TopicListener; -import org.onap.policy.drools.controller.DroolsController; -import org.onap.policy.drools.pooling.message.BucketAssignments; -import org.onap.policy.drools.pooling.message.Heartbeat; -import org.onap.policy.drools.pooling.message.Message; -import org.onap.policy.drools.pooling.message.Offline; -import org.onap.policy.drools.pooling.state.ActiveState; -import org.onap.policy.drools.pooling.state.IdleState; -import org.onap.policy.drools.pooling.state.InactiveState; -import org.onap.policy.drools.pooling.state.QueryState; -import org.onap.policy.drools.pooling.state.StartState; -import org.onap.policy.drools.pooling.state.State; -import org.onap.policy.drools.system.PolicyController; - -public class PoolingManagerImplTest { - - 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 long STD_OFFLINE_PUB_WAIT_MS = STD_INTER_HEARTBEAT_MS + 1; - - private static final String MY_HOST = "my.host"; - private static final String HOST2 = "other.host"; - - private static final String MY_CONTROLLER = "my.controller"; - private static final String MY_TOPIC = "my.topic"; - - private static final String TOPIC2 = "topic.two"; - - private static final String THE_EVENT = "the event"; - - private static final Object DECODED_EVENT = new Object(); - - /** - * Number of dmaap.publish() invocations that should be issued when the manager is - * started. - */ - private static final int START_PUB = 1; - - /** - * Futures that have been allocated due to calls to scheduleXxx(). - */ - private Queue<ScheduledFuture<?>> futures; - - private PoolingProperties poolProps; - private ListeningController controller; - private DmaapManager dmaap; - private boolean gotDmaap; - private ScheduledThreadPoolExecutor sched; - private int schedCount; - private DroolsController drools; - private Serializer ser; - private CountDownLatch active; - - private PoolingManagerImpl mgr; - - /** - * Setup. - * - * @throws Exception throws exception - */ - @Before - public void setUp() throws Exception { - Properties plainProps = new Properties(); - - poolProps = mock(PoolingProperties.class); - when(poolProps.getSource()).thenReturn(plainProps); - when(poolProps.getPoolingTopic()).thenReturn(MY_TOPIC); - when(poolProps.getStartHeartbeatMs()).thenReturn(STD_HEARTBEAT_WAIT_MS); - when(poolProps.getReactivateMs()).thenReturn(STD_REACTIVATE_WAIT_MS); - when(poolProps.getIdentificationMs()).thenReturn(STD_IDENTIFICATION_MS); - when(poolProps.getActiveHeartbeatMs()).thenReturn(STD_ACTIVE_HEARTBEAT_MS); - when(poolProps.getInterHeartbeatMs()).thenReturn(STD_INTER_HEARTBEAT_MS); - when(poolProps.getOfflinePubWaitMs()).thenReturn(STD_OFFLINE_PUB_WAIT_MS); - - futures = new LinkedList<>(); - ser = new Serializer(); - active = new CountDownLatch(1); - - dmaap = mock(DmaapManager.class); - gotDmaap = false; - controller = mock(ListeningController.class); - sched = mock(ScheduledThreadPoolExecutor.class); - schedCount = 0; - drools = mock(DroolsController.class); - - when(controller.getName()).thenReturn(MY_CONTROLLER); - when(controller.getDrools()).thenReturn(drools); - when(controller.isAlive()).thenReturn(true); - - when(sched.schedule(any(Runnable.class), any(Long.class), any(TimeUnit.class))).thenAnswer(args -> { - ScheduledFuture<?> fut = mock(ScheduledFuture.class); - futures.add(fut); - - return fut; - }); - - when(sched.scheduleWithFixedDelay(any(Runnable.class), any(Long.class), any(Long.class), any(TimeUnit.class))) - .thenAnswer(args -> { - ScheduledFuture<?> fut = mock(ScheduledFuture.class); - futures.add(fut); - - return fut; - }); - - mgr = new PoolingManagerTest(MY_HOST, controller, poolProps, active); - } - - @Test - public void testPoolingManagerImpl() throws Exception { - assertTrue(gotDmaap); - - State st = mgr.getCurrent(); - assertTrue(st instanceof IdleState); - - // ensure the state is attached to the manager - assertEquals(mgr.getHost(), st.getHost()); - } - - @Test - public void testPoolingManagerImpl_PoolEx() throws PoolingFeatureException { - // throw an exception when we try to create the dmaap manager - PoolingFeatureException ex = new PoolingFeatureException(); - - assertThatThrownBy(() -> new PoolingManagerTest(MY_HOST, controller, poolProps, active) { - @Override - protected DmaapManager makeDmaapManager(String topic) throws PoolingFeatureException { - throw ex; - } - }).isInstanceOf(PoolingFeatureRtException.class).hasCause(ex); - } - - @Test - public void testGetCurrent() throws Exception { - assertEquals(IdleState.class, mgr.getCurrent().getClass()); - - startMgr(); - - assertEquals(StartState.class, mgr.getCurrent().getClass()); - } - - @Test - public void testGetHost() { - assertEquals(MY_HOST, mgr.getHost()); - - mgr = new PoolingManagerTest(HOST2, controller, poolProps, active); - assertEquals(HOST2, mgr.getHost()); - } - - @Test - public void testGetTopic() { - assertEquals(MY_TOPIC, mgr.getTopic()); - } - - @Test - public void testGetProperties() { - assertEquals(poolProps, mgr.getProperties()); - } - - @Test - public void testBeforeStart() throws Exception { - // not running yet - mgr.beforeStart(); - - verify(dmaap).startPublisher(); - - assertEquals(1, schedCount); - verify(sched).setMaximumPoolSize(1); - verify(sched).setContinueExistingPeriodicTasksAfterShutdownPolicy(false); - - - // try again - nothing should happen - mgr.beforeStart(); - - verify(dmaap).startPublisher(); - - assertEquals(1, schedCount); - verify(sched).setMaximumPoolSize(1); - verify(sched).setContinueExistingPeriodicTasksAfterShutdownPolicy(false); - } - - @Test - public void testAfterStart() throws Exception { - startMgr(); - - verify(dmaap).startConsumer(mgr); - - State st = mgr.getCurrent(); - assertTrue(st instanceof StartState); - - // ensure the state is attached to the manager - assertEquals(mgr.getHost(), st.getHost()); - - ArgumentCaptor<Long> timeCap = ArgumentCaptor.forClass(Long.class); - ArgumentCaptor<TimeUnit> unitCap = ArgumentCaptor.forClass(TimeUnit.class); - verify(sched).schedule(any(Runnable.class), timeCap.capture(), unitCap.capture()); - - assertEquals(STD_HEARTBEAT_WAIT_MS, timeCap.getValue().longValue()); - assertEquals(TimeUnit.MILLISECONDS, unitCap.getValue()); - - - // already started - nothing else happens - mgr.afterStart(); - - verify(dmaap).startConsumer(mgr); - - assertTrue(mgr.getCurrent() instanceof StartState); - - verify(sched).schedule(any(Runnable.class), any(Long.class), any(TimeUnit.class)); - } - - @Test - public void testBeforeStop() throws Exception { - startMgr(); - mgr.startDistributing(makeAssignments(false)); - - verify(dmaap, times(START_PUB)).publish(any()); - - mgr.beforeStop(); - - verify(dmaap).stopConsumer(mgr); - verify(sched).shutdownNow(); - verify(dmaap, times(START_PUB + 1)).publish(any()); - verify(dmaap).publish(contains("offline")); - - assertTrue(mgr.getCurrent() instanceof IdleState); - - // verify that next message is handled locally - assertFalse(mgr.beforeInsert(TOPIC2, DECODED_EVENT)); - verify(dmaap, times(START_PUB + 1)).publish(any()); - } - - @Test - public void testBeforeStop_NotRunning() throws Exception { - final State st = mgr.getCurrent(); - - mgr.beforeStop(); - - verify(dmaap, never()).stopConsumer(any()); - verify(sched, never()).shutdownNow(); - - // hasn't changed states either - assertEquals(st, mgr.getCurrent()); - } - - @Test - public void testBeforeStop_AfterPartialStart() throws Exception { - // call beforeStart but not afterStart - mgr.beforeStart(); - - final State st = mgr.getCurrent(); - - mgr.beforeStop(); - - // should still shut the scheduler down - verify(sched).shutdownNow(); - - verify(dmaap, never()).stopConsumer(any()); - - // hasn't changed states - assertEquals(st, mgr.getCurrent()); - } - - @Test - public void testAfterStop() throws Exception { - startMgr(); - mgr.beforeStop(); - - mgr.afterStop(); - - verify(dmaap).stopPublisher(STD_OFFLINE_PUB_WAIT_MS); - } - - @Test - public void testBeforeLock() throws Exception { - startMgr(); - - mgr.beforeLock(); - - assertTrue(mgr.getCurrent() instanceof IdleState); - } - - @Test - public void testAfterUnlock_AliveIdle() throws Exception { - // this really shouldn't happen - - lockMgr(); - - mgr.afterUnlock(); - - // stays in idle state, because it has no scheduler - assertTrue(mgr.getCurrent() instanceof IdleState); - } - - @Test - public void testAfterUnlock_AliveStarted() throws Exception { - startMgr(); - lockMgr(); - - mgr.afterUnlock(); - - assertTrue(mgr.getCurrent() instanceof StartState); - } - - @Test - public void testAfterUnlock_StoppedIdle() throws Exception { - startMgr(); - lockMgr(); - - // controller is stopped - when(controller.isAlive()).thenReturn(false); - - mgr.afterUnlock(); - - assertTrue(mgr.getCurrent() instanceof IdleState); - } - - @Test - public void testAfterUnlock_StoppedStarted() throws Exception { - startMgr(); - - // Note: don't lockMgr() - - // controller is stopped - when(controller.isAlive()).thenReturn(false); - - mgr.afterUnlock(); - - assertTrue(mgr.getCurrent() instanceof StartState); - } - - @Test - public void testChangeState() throws Exception { - // start should invoke changeState() - startMgr(); - - /* - * now go offline while it's locked - */ - lockMgr(); - - // should have cancelled the timers - assertEquals(2, futures.size()); - verify(futures.poll()).cancel(false); - verify(futures.poll()).cancel(false); - - /* - * now go back online - */ - unlockMgr(); - - // new timers should now be active - assertEquals(2, futures.size()); - verify(futures.poll(), never()).cancel(false); - verify(futures.poll(), never()).cancel(false); - } - - @Test - public void testSchedule() throws Exception { - // must start the scheduler - startMgr(); - - CountDownLatch latch = new CountDownLatch(1); - - mgr.schedule(STD_ACTIVE_HEARTBEAT_MS, () -> { - latch.countDown(); - return null; - }); - - // capture the task - ArgumentCaptor<Runnable> taskCap = ArgumentCaptor.forClass(Runnable.class); - ArgumentCaptor<Long> timeCap = ArgumentCaptor.forClass(Long.class); - ArgumentCaptor<TimeUnit> unitCap = ArgumentCaptor.forClass(TimeUnit.class); - - verify(sched, times(2)).schedule(taskCap.capture(), timeCap.capture(), unitCap.capture()); - - assertEquals(STD_ACTIVE_HEARTBEAT_MS, timeCap.getValue().longValue()); - assertEquals(TimeUnit.MILLISECONDS, unitCap.getValue()); - - // execute it - taskCap.getValue().run(); - - assertEquals(0, latch.getCount()); - } - - @Test - public void testScheduleWithFixedDelay() throws Exception { - // must start the scheduler - startMgr(); - - CountDownLatch latch = new CountDownLatch(1); - - mgr.scheduleWithFixedDelay(STD_HEARTBEAT_WAIT_MS, STD_ACTIVE_HEARTBEAT_MS, () -> { - latch.countDown(); - return null; - }); - - // capture the task - ArgumentCaptor<Runnable> taskCap = ArgumentCaptor.forClass(Runnable.class); - ArgumentCaptor<Long> initCap = ArgumentCaptor.forClass(Long.class); - ArgumentCaptor<Long> timeCap = ArgumentCaptor.forClass(Long.class); - ArgumentCaptor<TimeUnit> unitCap = ArgumentCaptor.forClass(TimeUnit.class); - - verify(sched, times(2)).scheduleWithFixedDelay(taskCap.capture(), initCap.capture(), timeCap.capture(), - unitCap.capture()); - - assertEquals(STD_HEARTBEAT_WAIT_MS, initCap.getValue().longValue()); - assertEquals(STD_ACTIVE_HEARTBEAT_MS, timeCap.getValue().longValue()); - assertEquals(TimeUnit.MILLISECONDS, unitCap.getValue()); - - // execute it - taskCap.getValue().run(); - - assertEquals(0, latch.getCount()); - } - - @Test - public void testPublishAdmin() throws Exception { - Offline msg = new Offline(mgr.getHost()); - mgr.publishAdmin(msg); - - assertEquals(Message.ADMIN, msg.getChannel()); - - verify(dmaap).publish(any()); - } - - @Test - public void testPublish() throws Exception { - Offline msg = new Offline(mgr.getHost()); - mgr.publish("my.channel", msg); - - assertEquals("my.channel", msg.getChannel()); - - verify(dmaap).publish(any()); - } - - @Test - public void testPublish_InvalidMsg() throws Exception { - // message is missing data - mgr.publish(Message.ADMIN, new Offline()); - - // should not have attempted to publish it - verify(dmaap, never()).publish(any()); - } - - @Test - public void testPublish_DmaapEx() throws Exception { - - // generate exception - doThrow(new PoolingFeatureException()).when(dmaap).publish(any()); - - assertThatCode(() -> mgr.publish(Message.ADMIN, new Offline(mgr.getHost()))).doesNotThrowAnyException(); - } - - @Test - public void testOnTopicEvent() throws Exception { - startMgr(); - - StartState st = (StartState) mgr.getCurrent(); - - /* - * give it its heart beat, that should cause it to transition to the Query state. - */ - Heartbeat hb = new Heartbeat(mgr.getHost(), st.getHbTimestampMs()); - hb.setChannel(Message.ADMIN); - - String msg = ser.encodeMsg(hb); - - mgr.onTopicEvent(CommInfrastructure.UEB, MY_TOPIC, msg); - - assertTrue(mgr.getCurrent() instanceof QueryState); - } - - @Test - public void testOnTopicEvent_NullEvent() throws Exception { - startMgr(); - - assertThatCode(() -> mgr.onTopicEvent(CommInfrastructure.UEB, TOPIC2, null)).doesNotThrowAnyException(); - } - - @Test - public void testBeforeOffer_Unlocked() throws Exception { - startMgr(); - - // route the message to another host - mgr.startDistributing(makeAssignments(false)); - - assertFalse(mgr.beforeOffer(TOPIC2, THE_EVENT)); - } - - @Test - public void testBeforeOffer_Locked() throws Exception { - startMgr(); - lockMgr(); - - // route the message to another host - mgr.startDistributing(makeAssignments(false)); - - assertTrue(mgr.beforeOffer(TOPIC2, THE_EVENT)); - } - - @Test - public void testBeforeInsert() throws Exception { - startMgr(); - lockMgr(); - - // route the message to this host - mgr.startDistributing(makeAssignments(true)); - - assertFalse(mgr.beforeInsert(TOPIC2, DECODED_EVENT)); - } - - @Test - public void testHandleExternalCommInfrastructureStringStringString_NullReqId() throws Exception { - validateHandleReqId(null); - } - - @Test - public void testHandleExternalCommInfrastructureStringStringString_EmptyReqId() throws Exception { - validateHandleReqId(""); - } - - @Test - public void testHandleExternalCommInfrastructureStringStringString_InvalidMsg() throws Exception { - startMgr(); - - assertFalse(mgr.beforeInsert(TOPIC2, "invalid message")); - } - - @Test - public void testHandleExternalCommInfrastructureStringStringString() throws Exception { - validateUnhandled(); - } - - @Test - public void testHandleExternalForward_NoAssignments() throws Exception { - validateUnhandled(); - } - - @Test - public void testHandleExternalForward() throws Exception { - validateNoForward(); - } - - @Test - public void testHandleEvent_NullTarget() throws Exception { - // buckets have null targets - validateDiscarded(new BucketAssignments(new String[] {null, null})); - } - - @Test - public void testHandleEvent_SameHost() throws Exception { - validateNoForward(); - } - - @Test - public void testHandleEvent_DiffHost() throws Exception { - // route the message to the *OTHER* host - validateDiscarded(makeAssignments(false)); - } - - @Test - public void testDecodeEvent_CannotDecode() throws Exception { - - mgr = new PoolingManagerTest(MY_HOST, controller, poolProps, active) { - @Override - protected boolean canDecodeEvent(DroolsController drools2, String topic2) { - return false; - } - }; - - startMgr(); - - when(controller.isLocked()).thenReturn(true); - - // create assignments, though they are irrelevant - mgr.startDistributing(makeAssignments(false)); - - assertFalse(mgr.beforeOffer(TOPIC2, THE_EVENT)); - } - - @Test - public void testDecodeEvent_UnsuppEx() throws Exception { - - // generate exception - mgr = new PoolingManagerTest(MY_HOST, controller, poolProps, active) { - @Override - protected Object decodeEventWrapper(DroolsController drools2, String topic2, String event) { - throw new UnsupportedOperationException(); - } - }; - - startMgr(); - - when(controller.isLocked()).thenReturn(true); - - // create assignments, though they are irrelevant - mgr.startDistributing(makeAssignments(false)); - - assertFalse(mgr.beforeOffer(TOPIC2, THE_EVENT)); - } - - @Test - public void testDecodeEvent_ArgEx() throws Exception { - // generate exception - mgr = new PoolingManagerTest(MY_HOST, controller, poolProps, active) { - @Override - protected Object decodeEventWrapper(DroolsController drools2, String topic2, String event) { - throw new IllegalArgumentException(); - } - }; - - startMgr(); - - when(controller.isLocked()).thenReturn(true); - - // create assignments, though they are irrelevant - mgr.startDistributing(makeAssignments(false)); - - assertFalse(mgr.beforeOffer(TOPIC2, THE_EVENT)); - } - - @Test - public void testDecodeEvent_StateEx() throws Exception { - // generate exception - mgr = new PoolingManagerTest(MY_HOST, controller, poolProps, active) { - @Override - protected Object decodeEventWrapper(DroolsController drools2, String topic2, String event) { - throw new IllegalStateException(); - } - }; - - startMgr(); - - when(controller.isLocked()).thenReturn(true); - - // create assignments, though they are irrelevant - mgr.startDistributing(makeAssignments(false)); - - assertFalse(mgr.beforeOffer(TOPIC2, THE_EVENT)); - } - - @Test - public void testDecodeEvent() throws Exception { - startMgr(); - - when(controller.isLocked()).thenReturn(true); - - // route to another host - mgr.startDistributing(makeAssignments(false)); - - assertTrue(mgr.beforeOffer(TOPIC2, THE_EVENT)); - } - - @Test - public void testHandleInternal() throws Exception { - startMgr(); - - StartState st = (StartState) mgr.getCurrent(); - - /* - * give it its heart beat, that should cause it to transition to the Query state. - */ - Heartbeat hb = new Heartbeat(mgr.getHost(), st.getHbTimestampMs()); - hb.setChannel(Message.ADMIN); - - String msg = ser.encodeMsg(hb); - - mgr.onTopicEvent(CommInfrastructure.UEB, MY_TOPIC, msg); - - assertTrue(mgr.getCurrent() instanceof QueryState); - } - - @Test - public void testHandleInternal_IoEx() throws Exception { - startMgr(); - - mgr.onTopicEvent(CommInfrastructure.UEB, MY_TOPIC, "invalid message"); - - assertTrue(mgr.getCurrent() instanceof StartState); - } - - @Test - public void testHandleInternal_PoolEx() throws Exception { - startMgr(); - - StartState st = (StartState) mgr.getCurrent(); - - Heartbeat hb = new Heartbeat(mgr.getHost(), st.getHbTimestampMs()); - - /* - * do NOT set the channel - this will cause the message to be invalid, triggering - * an exception - */ - - String msg = ser.encodeMsg(hb); - - mgr.onTopicEvent(CommInfrastructure.UEB, MY_TOPIC, msg); - - assertTrue(mgr.getCurrent() instanceof StartState); - } - - @Test - public void testStartDistributing() throws Exception { - validateNoForward(); - - - // null assignments should cause message to be processed locally - mgr.startDistributing(null); - assertFalse(mgr.beforeInsert(TOPIC2, DECODED_EVENT)); - verify(dmaap, times(START_PUB)).publish(any()); - - - // message for this host - mgr.startDistributing(makeAssignments(true)); - assertFalse(mgr.beforeInsert(TOPIC2, DECODED_EVENT)); - - - // message for another host - mgr.startDistributing(makeAssignments(false)); - assertTrue(mgr.beforeInsert(TOPIC2, DECODED_EVENT)); - } - - @Test - public void testGoStart() { - State st = mgr.goStart(); - assertTrue(st instanceof StartState); - assertEquals(mgr.getHost(), st.getHost()); - } - - @Test - public void testGoQuery() { - BucketAssignments asgn = new BucketAssignments(new String[] {HOST2}); - mgr.startDistributing(asgn); - - State st = mgr.goQuery(); - - assertTrue(st instanceof QueryState); - assertEquals(mgr.getHost(), st.getHost()); - assertEquals(asgn, mgr.getAssignments()); - } - - @Test - public void testGoActive() { - BucketAssignments asgn = new BucketAssignments(new String[] {HOST2}); - mgr.startDistributing(asgn); - - State st = mgr.goActive(); - - assertTrue(st instanceof ActiveState); - assertEquals(mgr.getHost(), st.getHost()); - assertEquals(asgn, mgr.getAssignments()); - assertEquals(0, active.getCount()); - } - - @Test - public void testGoInactive() { - State st = mgr.goInactive(); - assertTrue(st instanceof InactiveState); - assertEquals(mgr.getHost(), st.getHost()); - assertEquals(1, active.getCount()); - } - - @Test - public void testTimerActionRun() throws Exception { - // must start the scheduler - startMgr(); - - CountDownLatch latch = new CountDownLatch(1); - - mgr.schedule(STD_ACTIVE_HEARTBEAT_MS, () -> { - latch.countDown(); - return null; - }); - - // capture the task - ArgumentCaptor<Runnable> taskCap = ArgumentCaptor.forClass(Runnable.class); - - verify(sched, times(2)).schedule(taskCap.capture(), any(Long.class), any(TimeUnit.class)); - - // execute it - taskCap.getValue().run(); - - assertEquals(0, latch.getCount()); - } - - @Test - public void testTimerActionRun_DiffState() throws Exception { - // must start the scheduler - startMgr(); - - CountDownLatch latch = new CountDownLatch(1); - - mgr.schedule(STD_ACTIVE_HEARTBEAT_MS, () -> { - latch.countDown(); - return null; - }); - - // capture the task - ArgumentCaptor<Runnable> taskCap = ArgumentCaptor.forClass(Runnable.class); - - verify(sched, times(2)).schedule(taskCap.capture(), any(Long.class), any(TimeUnit.class)); - - // give it a heartbeat so that it transitions to the query state - StartState st = (StartState) mgr.getCurrent(); - Heartbeat hb = new Heartbeat(mgr.getHost(), st.getHbTimestampMs()); - hb.setChannel(Message.ADMIN); - - String msg = ser.encodeMsg(hb); - - mgr.onTopicEvent(CommInfrastructure.UEB, MY_TOPIC, msg); - - assertTrue(mgr.getCurrent() instanceof QueryState); - - // execute it - taskCap.getValue().run(); - - // it should NOT have counted down - assertEquals(1, latch.getCount()); - } - - private void validateHandleReqId(String requestId) throws PoolingFeatureException { - startMgr(); - - assertFalse(mgr.beforeInsert(TOPIC2, DECODED_EVENT)); - } - - private void validateNoForward() throws PoolingFeatureException { - startMgr(); - - // route the message to this host - mgr.startDistributing(makeAssignments(true)); - - assertFalse(mgr.beforeInsert(TOPIC2, DECODED_EVENT)); - - verify(dmaap, times(START_PUB)).publish(any()); - } - - private void validateUnhandled() throws PoolingFeatureException { - startMgr(); - assertFalse(mgr.beforeInsert(TOPIC2, DECODED_EVENT)); - } - - private void validateDiscarded(BucketAssignments bucketAssignments) throws PoolingFeatureException { - startMgr(); - - // buckets have null targets - mgr.startDistributing(bucketAssignments); - - assertTrue(mgr.beforeInsert(TOPIC2, DECODED_EVENT)); - } - - /** - * Makes an assignment with two buckets. - * - * @param sameHost {@code true} if the {@link #REQUEST_ID} should hash to the - * manager's bucket, {@code false} if it should hash to the other host's bucket - * @return a new bucket assignment - */ - private BucketAssignments makeAssignments(boolean sameHost) { - int slot = DECODED_EVENT.hashCode() % 2; - - // slot numbers are 0 and 1 - reverse them if it's for a different host - if (!sameHost) { - slot = 1 - slot; - } - - String[] asgn = new String[2]; - asgn[slot] = mgr.getHost(); - asgn[1 - slot] = HOST2; - - return new BucketAssignments(asgn); - } - - /** - * Invokes methods necessary to start the manager. - * - * @throws PoolingFeatureException if an error occurs - */ - private void startMgr() throws PoolingFeatureException { - mgr.beforeStart(); - mgr.afterStart(); - } - - /** - * Invokes methods necessary to lock the manager. - */ - private void lockMgr() { - mgr.beforeLock(); - when(controller.isLocked()).thenReturn(true); - } - - /** - * Invokes methods necessary to unlock the manager. - */ - private void unlockMgr() { - mgr.afterUnlock(); - when(controller.isLocked()).thenReturn(false); - } - - /** - * Used to create a mock object that implements both super interfaces. - */ - private static interface ListeningController extends TopicListener, PolicyController { - - } - - /** - * Manager with overrides. - */ - private class PoolingManagerTest extends PoolingManagerImpl { - - public PoolingManagerTest(String host, PolicyController controller, PoolingProperties props, - CountDownLatch activeLatch) { - - super(host, controller, props, activeLatch); - } - - @Override - protected DmaapManager makeDmaapManager(String topic) throws PoolingFeatureException { - gotDmaap = true; - return dmaap; - } - - @Override - protected ScheduledThreadPoolExecutor makeScheduler() { - ++schedCount; - return sched; - } - - @Override - protected boolean canDecodeEvent(DroolsController drools2, String topic2) { - return (drools2 == drools && TOPIC2.equals(topic2)); - } - - @Override - protected Object decodeEventWrapper(DroolsController drools2, String topic2, String event) { - if (drools2 == drools && TOPIC2.equals(topic2) && event == THE_EVENT) { - return DECODED_EVENT; - } else { - return null; - } - } - } -} diff --git a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/PoolingPropertiesTest.java b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/PoolingPropertiesTest.java deleted file mode 100644 index b15908dc..00000000 --- a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/PoolingPropertiesTest.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * ONAP - * ================================================================================ - * Copyright (C) 2018, 2020 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ - -package org.onap.policy.drools.pooling; - -import static org.assertj.core.api.Assertions.assertThatCode; -import static org.junit.Assert.assertEquals; -import static org.onap.policy.drools.pooling.PoolingProperties.ACTIVE_HEARTBEAT_MS; -import static org.onap.policy.drools.pooling.PoolingProperties.FEATURE_ENABLED; -import static org.onap.policy.drools.pooling.PoolingProperties.IDENTIFICATION_MS; -import static org.onap.policy.drools.pooling.PoolingProperties.INTER_HEARTBEAT_MS; -import static org.onap.policy.drools.pooling.PoolingProperties.OFFLINE_AGE_MS; -import static org.onap.policy.drools.pooling.PoolingProperties.OFFLINE_LIMIT; -import static org.onap.policy.drools.pooling.PoolingProperties.OFFLINE_PUB_WAIT_MS; -import static org.onap.policy.drools.pooling.PoolingProperties.POOLING_TOPIC; -import static org.onap.policy.drools.pooling.PoolingProperties.PREFIX; -import static org.onap.policy.drools.pooling.PoolingProperties.REACTIVATE_MS; -import static org.onap.policy.drools.pooling.PoolingProperties.START_HEARTBEAT_MS; - -import java.util.Properties; -import java.util.function.Function; -import org.junit.Before; -import org.junit.Test; -import org.onap.policy.common.utils.properties.exception.PropertyException; - -public class PoolingPropertiesTest { - - private static final String CONTROLLER = "a.controller"; - - private static final String STD_POOLING_TOPIC = "my.topic"; - public static final boolean STD_FEATURE_ENABLED = true; - public static final int STD_OFFLINE_LIMIT = 10; - public static final long STD_OFFLINE_AGE_MS = 1000L; - public static final long STD_OFFLINE_PUB_WAIT_MS = 2000L; - public static final long STD_START_HEARTBEAT_MS = 3000L; - public static final long STD_REACTIVATE_MS = 4000L; - public static final long STD_IDENTIFICATION_MS = 5000L; - public static final long STD_LEADER_MS = 6000L; - public static final long STD_ACTIVE_HEARTBEAT_MS = 7000L; - public static final long STD_INTER_HEARTBEAT_MS = 8000L; - - private Properties plain; - private PoolingProperties pooling; - - /** - * Setup. - * - * @throws Exception throws an exception - */ - @Before - public void setUp() throws Exception { - plain = makeProperties(); - - pooling = new PoolingProperties(CONTROLLER, plain); - } - - @Test - public void testPoolingProperties() throws PropertyException { - // ensure no exceptions - assertThatCode(() -> new PoolingProperties(CONTROLLER, plain)).doesNotThrowAnyException(); - } - - @Test - public void testGetSource() { - assertEquals(plain, pooling.getSource()); - } - - @Test - public void testGetPoolingTopic() { - assertEquals(STD_POOLING_TOPIC, pooling.getPoolingTopic()); - } - - @Test - public void testGetOfflineLimit() throws PropertyException { - doTest(OFFLINE_LIMIT, STD_OFFLINE_LIMIT, 1000, xxx -> pooling.getOfflineLimit()); - } - - @Test - public void testGetOfflineAgeMs() throws PropertyException { - doTest(OFFLINE_AGE_MS, STD_OFFLINE_AGE_MS, 60000L, xxx -> pooling.getOfflineAgeMs()); - } - - @Test - public void testGetOfflinePubWaitMs() throws PropertyException { - doTest(OFFLINE_PUB_WAIT_MS, STD_OFFLINE_PUB_WAIT_MS, 3000L, xxx -> pooling.getOfflinePubWaitMs()); - } - - @Test - public void testGetStartHeartbeatMs() throws PropertyException { - doTest(START_HEARTBEAT_MS, STD_START_HEARTBEAT_MS, 100000L, xxx -> pooling.getStartHeartbeatMs()); - } - - @Test - public void testGetReactivateMs() throws PropertyException { - doTest(REACTIVATE_MS, STD_REACTIVATE_MS, 50000L, xxx -> pooling.getReactivateMs()); - } - - @Test - public void testGetIdentificationMs() throws PropertyException { - doTest(IDENTIFICATION_MS, STD_IDENTIFICATION_MS, 50000L, xxx -> pooling.getIdentificationMs()); - } - - @Test - public void testGetActiveHeartbeatMs() throws PropertyException { - doTest(ACTIVE_HEARTBEAT_MS, STD_ACTIVE_HEARTBEAT_MS, 50000L, xxx -> pooling.getActiveHeartbeatMs()); - } - - @Test - public void testGetInterHeartbeatMs() throws PropertyException { - doTest(INTER_HEARTBEAT_MS, STD_INTER_HEARTBEAT_MS, 15000L, xxx -> pooling.getInterHeartbeatMs()); - } - - /** - * Tests a particular property. Verifies that the correct value is returned if the - * specialized property has a value or the property has no value. Also verifies that - * the property name can be generalized. - * - * @param propnm name of the property of interest - * @param specValue expected specialized value - * @param dfltValue expected default value - * @param func function to get the field - * @throws PropertyException if an error occurs - */ - private <T> void doTest(String propnm, T specValue, T dfltValue, Function<Void, T> func) throws PropertyException { - /* - * With specialized property - */ - pooling = new PoolingProperties(CONTROLLER, plain); - assertEquals("special " + propnm, specValue, func.apply(null)); - - /* - * Without the property - should use the default value. - */ - plain.remove(specialize(propnm, CONTROLLER)); - plain.remove(propnm); - pooling = new PoolingProperties(CONTROLLER, plain); - assertEquals("default " + propnm, dfltValue, func.apply(null)); - } - - /** - * Makes a set of properties, where all of the properties are specialized for the - * controller. - * - * @return a new property set - */ - private Properties makeProperties() { - Properties props = new Properties(); - - props.setProperty(specialize(POOLING_TOPIC, CONTROLLER), STD_POOLING_TOPIC); - props.setProperty(specialize(FEATURE_ENABLED, CONTROLLER), "" + STD_FEATURE_ENABLED); - props.setProperty(specialize(OFFLINE_LIMIT, CONTROLLER), "" + STD_OFFLINE_LIMIT); - props.setProperty(specialize(OFFLINE_AGE_MS, CONTROLLER), "" + STD_OFFLINE_AGE_MS); - props.setProperty(specialize(OFFLINE_PUB_WAIT_MS, CONTROLLER), "" + STD_OFFLINE_PUB_WAIT_MS); - props.setProperty(specialize(START_HEARTBEAT_MS, CONTROLLER), "" + STD_START_HEARTBEAT_MS); - props.setProperty(specialize(REACTIVATE_MS, CONTROLLER), "" + STD_REACTIVATE_MS); - props.setProperty(specialize(IDENTIFICATION_MS, CONTROLLER), "" + STD_IDENTIFICATION_MS); - props.setProperty(specialize(ACTIVE_HEARTBEAT_MS, CONTROLLER), "" + STD_ACTIVE_HEARTBEAT_MS); - props.setProperty(specialize(INTER_HEARTBEAT_MS, CONTROLLER), "" + STD_INTER_HEARTBEAT_MS); - - return props; - } - - /** - * 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; - } -} diff --git a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/SerializerTest.java b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/SerializerTest.java deleted file mode 100644 index f4cd940c..00000000 --- a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/SerializerTest.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * ONAP - * ================================================================================ - * Copyright (C) 2018-2020 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ - -package org.onap.policy.drools.pooling; - -import static org.assertj.core.api.Assertions.assertThatCode; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; - -import com.google.gson.JsonParseException; -import org.junit.Test; -import org.onap.policy.drools.pooling.message.Message; -import org.onap.policy.drools.pooling.message.Query; - -public class SerializerTest { - - @Test - public void testSerializer() { - assertThatCode(() -> new Serializer()).doesNotThrowAnyException(); - } - - @Test - public void testEncodeMsg_testDecodeMsg() throws Exception { - Serializer ser = new Serializer(); - - Query msg = new Query("hostA"); - msg.setChannel("channelB"); - - String encoded = ser.encodeMsg(msg); - assertNotNull(encoded); - - Message decoded = ser.decodeMsg(encoded); - assertEquals(Query.class, decoded.getClass()); - - assertEquals(msg.getSource(), decoded.getSource()); - assertEquals(msg.getChannel(), decoded.getChannel()); - - // should work a second time, too - encoded = ser.encodeMsg(msg); - assertNotNull(encoded); - - decoded = ser.decodeMsg(encoded); - assertEquals(Query.class, decoded.getClass()); - - assertEquals(msg.getSource(), decoded.getSource()); - assertEquals(msg.getChannel(), decoded.getChannel()); - - // invalid subclass when encoding - Message msg2 = new Message() {}; - assertThatThrownBy(() -> ser.encodeMsg(msg2)).isInstanceOf(JsonParseException.class) - .hasMessageContaining("cannot serialize"); - - // missing type when decoding - final String enc2 = encoded.replaceAll("type", "other-field-name"); - - assertThatThrownBy(() -> ser.decodeMsg(enc2)).isInstanceOf(JsonParseException.class) - .hasMessageContaining("does not contain a field named"); - - // invalid type - final String enc3 = encoded.replaceAll("query", "invalid-type"); - - assertThatThrownBy(() -> ser.decodeMsg(enc3)).isInstanceOf(JsonParseException.class) - .hasMessage("cannot deserialize \"invalid-type\""); - } - -} diff --git a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/feature-pooling-dmaap.properties b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/feature-pooling-dmaap.properties deleted file mode 100644 index 3273a21e..00000000 --- a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/feature-pooling-dmaap.properties +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright 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. - -pooling.controllerA.topic = topic.A -pooling.controllerA.enabled = true -pooling.controllerA.offline.queue.limit = 5 -pooling.controllerA.offline.queue.age.milliseconds = 100 -pooling.controllerA.start.heartbeat.milliseconds = 10 -pooling.controllerA.reactivate.milliseconds = 20 -pooling.controllerA.identification.milliseconds = 30 -pooling.controllerA.active.heartbeat.milliseconds = 40 -pooling.controllerA.inter.heartbeat.milliseconds = 50 - -pooling.controllerB.topic = topic.B -pooling.controllerB.enabled = true -pooling.controllerB.offline.queue.limit = 6 -pooling.controllerB.offline.queue.age.milliseconds = 101 -pooling.controllerB.start.heartbeat.milliseconds = 11 -pooling.controllerB.reactivate.milliseconds = 21 -pooling.controllerB.identification.milliseconds = 31 -pooling.controllerB.active.heartbeat.milliseconds = 41 -pooling.controllerB.inter.heartbeat.milliseconds = 51 - -pooling.controllerDisabled.enabled = false - -# this has an invalid property -pooling.controllerException.topic = topic.B -pooling.controllerException.enabled = true -pooling.controllerException.offline.queue.limit = INVALID NUMBER -pooling.controllerException.offline.queue.age.milliseconds = 101 -pooling.controllerException.start.heartbeat.milliseconds = 11 -pooling.controllerException.reactivate.milliseconds = 21 -pooling.controllerException.identification.milliseconds = 31 -pooling.controllerException.active.heartbeat.milliseconds = 41 -pooling.controllerException.inter.heartbeat.milliseconds = 51 diff --git a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/BucketAssignmentsTest.java b/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/BucketAssignmentsTest.java deleted file mode 100644 index 5eaeddca..00000000 --- a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/BucketAssignmentsTest.java +++ /dev/null @@ -1,360 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * ONAP - * ================================================================================ - * Copyright (C) 2018, 2020 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ - -package org.onap.policy.drools.pooling.message; - -import static org.assertj.core.api.Assertions.assertThatCode; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.util.Arrays; -import java.util.SortedSet; -import java.util.TreeSet; -import org.junit.Test; -import org.onap.policy.drools.pooling.PoolingFeatureException; - -public class BucketAssignmentsTest { - - @Test - public void testBucketAssignments() { - assertThatCode(() -> new BucketAssignments()).doesNotThrowAnyException(); - } - - @Test - public void testBucketAssignmentsStringArray() { - String[] arr = {"abc", "def"}; - BucketAssignments asgn = new BucketAssignments(arr); - - assertNotNull(asgn.getHostArray()); - assertEquals(arr.toString(), asgn.getHostArray().toString()); - } - - @Test - public void testGetHostArray_testSetHostArray() { - - String[] arr = {"abc", "def"}; - BucketAssignments asgn = new BucketAssignments(arr); - - assertNotNull(asgn.getHostArray()); - assertEquals(arr.toString(), asgn.getHostArray().toString()); - - String[] arr2 = {"xyz"}; - asgn.setHostArray(arr2); - - assertNotNull(asgn.getHostArray()); - assertEquals(arr2.toString(), asgn.getHostArray().toString()); - } - - @Test - public void testGetLeader() { - // host array is null - BucketAssignments asgn = new BucketAssignments(); - assertNull(asgn.getLeader()); - - // array is non-null, but empty - asgn.setHostArray(new String[0]); - assertNull(asgn.getLeader()); - - // all entries are null - asgn.setHostArray(new String[5]); - assertNull(asgn.getLeader()); - - // some entries are null - asgn.setHostArray(new String[] {null, "abc", null}); - assertEquals("abc", asgn.getLeader()); - - // only one entry - asgn.setHostArray(new String[] {"abc"}); - assertEquals("abc", asgn.getLeader()); - - // first is least - asgn.setHostArray(new String[] {"Ahost", "Bhost", "Chost"}); - assertEquals("Ahost", asgn.getLeader()); - - // middle is least - asgn.setHostArray(new String[] {"Xhost", "Bhost", "Chost"}); - assertEquals("Bhost", asgn.getLeader()); - - // last is least - asgn.setHostArray(new String[] {"Xhost", "Yhost", "Chost"}); - assertEquals("Chost", asgn.getLeader()); - - // multiple entries - asgn.setHostArray(new String[] {"Xhost", "Bhost", "Chost", "Bhost", "Xhost", "Chost"}); - assertEquals("Bhost", asgn.getLeader()); - } - - @Test - public void testHasAssignment() { - // host array is null - BucketAssignments asgn = new BucketAssignments(); - assertFalse(asgn.hasAssignment("abc")); - - // array is non-null, but empty - asgn.setHostArray(new String[0]); - assertFalse(asgn.hasAssignment("abc")); - - // all entries are null - asgn.setHostArray(new String[5]); - assertFalse(asgn.hasAssignment("abc")); - - // some entries are null - asgn.setHostArray(new String[] {null, "abc", null}); - assertTrue(asgn.hasAssignment("abc")); - - // only one entry - asgn.setHostArray(new String[] {"abc"}); - assertTrue(asgn.hasAssignment("abc")); - - // appears as first entry - asgn.setHostArray(new String[] {"abc", "Bhost", "Chost"}); - assertTrue(asgn.hasAssignment("abc")); - - // appears in middle - asgn.setHostArray(new String[] {"Xhost", "abc", "Chost"}); - assertTrue(asgn.hasAssignment("abc")); - - // appears last - asgn.setHostArray(new String[] {"Xhost", "Yhost", "abc"}); - assertTrue(asgn.hasAssignment("abc")); - - // appears repeatedly - asgn.setHostArray(new String[] {"Xhost", "Bhost", "Chost", "Bhost", "Xhost", "Chost"}); - assertTrue(asgn.hasAssignment("Bhost")); - } - - @Test - public void testGetAllHosts() { - // host array is null - BucketAssignments asgn = new BucketAssignments(); - assertEquals("[]", getSortedHosts(asgn).toString()); - - // array is non-null, but empty - asgn.setHostArray(new String[0]); - assertEquals("[]", getSortedHosts(asgn).toString()); - - // all entries are null - asgn.setHostArray(new String[5]); - assertEquals("[]", getSortedHosts(asgn).toString()); - - // some entries are null - asgn.setHostArray(new String[] {null, "abc", null}); - assertEquals("[abc]", getSortedHosts(asgn).toString()); - - // only one entry - asgn.setHostArray(new String[] {"abc"}); - assertEquals("[abc]", getSortedHosts(asgn).toString()); - - // multiple, repeated entries - asgn.setHostArray(new String[] {"def", "abc", "def", "ghi", "def", "def", "xyz"}); - assertEquals("[abc, def, ghi, xyz]", getSortedHosts(asgn).toString()); - } - - /** - * Gets the hosts, sorted, so that the order is predictable. - * - * @param asgn assignment whose hosts are to be retrieved - * @return a new, sorted set of hosts - */ - private SortedSet<String> getSortedHosts(BucketAssignments asgn) { - return new TreeSet<>(asgn.getAllHosts()); - } - - @Test - public void testGetAssignedHost() { - // host array is null - BucketAssignments asgn = new BucketAssignments(); - assertNull(asgn.getAssignedHost(3)); - - // array is non-null, but empty - asgn.setHostArray(new String[0]); - assertNull(asgn.getAssignedHost(3)); - - // all entries are null - asgn.setHostArray(new String[5]); - assertNull(asgn.getAssignedHost(3)); - - // multiple, repeated entries - String[] arr = {"def", "abc", "def", "ghi", "def", "def", "xyz"}; - asgn.setHostArray(arr); - - /* - * get assignments for consecutive integers, including negative numbers and - * numbers extending past the length of the array. - * - */ - TreeSet<String> seen = new TreeSet<>(); - for (int x = -1; x < arr.length + 2; ++x) { - seen.add(asgn.getAssignedHost(x)); - } - - TreeSet<String> expected = new TreeSet<>(Arrays.asList(arr)); - assertEquals(expected, seen); - - // try a much bigger number - assertNotNull(asgn.getAssignedHost(arr.length * 1000)); - } - - @Test - public void testSize() { - // host array is null - BucketAssignments asgn = new BucketAssignments(); - assertEquals(0, asgn.size()); - - // array is non-null, but empty - asgn.setHostArray(new String[0]); - assertEquals(0, asgn.size()); - - // all entries are null - asgn.setHostArray(new String[5]); - assertEquals(5, asgn.size()); - - // multiple, repeated entries - String[] arr = {"def", "abc", "def", "ghi", "def", "def", "xyz"}; - asgn.setHostArray(arr); - assertEquals(arr.length, asgn.size()); - } - - @Test - public void testCheckValidity() throws Exception { - // host array is null - BucketAssignments asgn = new BucketAssignments(); - expectException(asgn); - - // array is non-null, but empty - asgn.setHostArray(new String[0]); - expectException(asgn); - - // array is too big - asgn.setHostArray(new String[BucketAssignments.MAX_BUCKETS + 1]); - expectException(asgn); - - // all entries are null - asgn.setHostArray(new String[5]); - expectException(asgn); - - // null at the beginning - asgn.setHostArray(new String[] {null, "Bhost", "Chost"}); - expectException(asgn); - - // null in the middle - asgn.setHostArray(new String[] {"Ahost", null, "Chost"}); - expectException(asgn); - - // null at the end - asgn.setHostArray(new String[] {"Ahost", "Bhost", null}); - expectException(asgn); - - // only one entry - asgn.setHostArray(new String[] {"abc"}); - asgn.checkValidity(); - - // multiple entries - asgn.setHostArray(new String[] {"Ahost", "Bhost", "Chost"}); - asgn.checkValidity(); - } - - @Test - public void testHashCode() { - // with null assignments - BucketAssignments asgn = new BucketAssignments(); - asgn.hashCode(); - - // with empty array - asgn = new BucketAssignments(new String[0]); - asgn.hashCode(); - - // with null items - asgn = new BucketAssignments(new String[] {"abc", null, "def"}); - asgn.hashCode(); - - // same assignments - asgn = new BucketAssignments(new String[] {"abc", null, "def"}); - int code = asgn.hashCode(); - - asgn = new BucketAssignments(new String[] {"abc", null, "def"}); - assertEquals(code, asgn.hashCode()); - - // slightly different values (i.e., changed "def" to "eef") - asgn = new BucketAssignments(new String[] {"abc", null, "eef"}); - assertNotEquals(code, asgn.hashCode()); - } - - @Test - public void testEquals() { - // null object - BucketAssignments asgn = new BucketAssignments(); - assertNotEquals(asgn, null); - - // same object - asgn = new BucketAssignments(); - assertEquals(asgn, asgn); - - // different class of object - asgn = new BucketAssignments(); - assertNotEquals(asgn, "not an assignment object"); - - assertNotEquals(asgn, new BucketAssignments(new String[] {"abc"})); - - // with null assignments - asgn = new BucketAssignments(); - assertEquals(asgn, new BucketAssignments()); - - // with empty array - asgn = new BucketAssignments(new String[0]); - assertEquals(asgn, asgn); - - assertNotEquals(asgn, new BucketAssignments()); - assertNotEquals(asgn, new BucketAssignments(new String[] {"abc"})); - - // with null items - String[] arr = {"abc", null, "def"}; - asgn = new BucketAssignments(arr); - assertEquals(asgn, asgn); - assertEquals(asgn, new BucketAssignments(arr)); - assertEquals(asgn, new BucketAssignments(new String[] {"abc", null, "def"})); - - assertNotEquals(asgn, new BucketAssignments()); - assertNotEquals(asgn, new BucketAssignments(new String[] {"abc", null, "XYZ"})); - - assertNotEquals(asgn, new BucketAssignments()); - } - - /** - * Expects an exception when checkValidity() is called. - * - * @param asgn assignments to be checked - */ - private void expectException(BucketAssignments asgn) { - try { - asgn.checkValidity(); - fail("missing exception"); - - } catch (PoolingFeatureException expected) { - // success - } - } - -} 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 deleted file mode 100644 index d1a82f4f..00000000 --- a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/HeartbeatTest.java +++ /dev/null @@ -1,58 +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; - -public class HeartbeatTest extends SupportBasicMessageTester<Heartbeat> { - - /** - * Sequence number to validate time stamps within the heart beat. - */ - private long sequence = 0; - - public HeartbeatTest() { - super(Heartbeat.class); - } - - @Override - public Heartbeat makeValidMessage() { - Heartbeat msg = new Heartbeat(VALID_HOST, ++sequence); - msg.setChannel(VALID_CHANNEL); - - return msg; - } - - @Override - public void testDefaultConstructorFields(Heartbeat msg) { - super.testDefaultConstructorFields(msg); - - assertEquals(sequence, msg.getTimestampMs()); - } - - @Override - public void testValidFields(Heartbeat msg) { - super.testValidFields(msg); - - assertEquals(sequence, msg.getTimestampMs()); - } - -} 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 deleted file mode 100644 index 06336b3e..00000000 --- a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/IdentificationTest.java +++ /dev/null @@ -1,73 +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 org.junit.Before; -import org.junit.Test; - -public class IdentificationTest extends SupportMessageWithAssignmentsTester<Identification> { - - public IdentificationTest() { - super(Identification.class); - } - - @Before - public void setUp() { - setNullAssignments(false); - } - - /** - * The superclass will already invoke testJsonEncodeDecode() to verify that - * things work with a fully populated message. This verifies that it also - * works if the assignments are null. - * - * @throws Exception if an error occurs - */ - @Test - public final void testJsonEncodeDecode_WithNullAssignments() throws Exception { - setNullAssignments(true); - testJsonEncodeDecode(); - } - - /** - * The superclass will already invoke testCheckValidity() to - * verify that things work with a fully populated message. This verifies - * that it also works if the assignments are null. - * - * @throws Exception if an error occurs - */ - @Test - public void testCheckValidity_NullAssignments() throws Exception { - // null assignments are OK - Identification msg = makeValidMessage(); - msg.setAssignments(null); - msg.checkValidity(); - } - - @Override - public Identification makeValidMessage() { - Identification msg = new Identification(VALID_HOST, (isNullAssignments() ? null : VALID_ASGN)); - msg.setChannel(VALID_CHANNEL); - - return msg; - } - -} 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 deleted file mode 100644 index eefd45d4..00000000 --- a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/LeaderTest.java +++ /dev/null @@ -1,73 +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 org.junit.Before; -import org.junit.Test; - -public class LeaderTest extends SupportMessageWithAssignmentsTester<Leader> { - - public LeaderTest() { - super(Leader.class); - } - - @Before - public void setUp() { - setNullAssignments(false); - } - - /** - * The superclass will already invoke testCheckValidity_InvalidFields() to - * verify that things work with a fully populated message. This verifies - * that it also works if the assignments are null. - * - * @throws Exception if an error occurs - */ - @Test - public void testCheckValidity_InvalidFields_NullAssignments() throws Exception { - // null assignments are invalid - expectCheckValidityFailure(msg -> msg.setAssignments(null)); - } - - @Test - public void testCheckValidity_SourceIsNotLeader() throws Exception { - Leader ldr = makeValidMessage(); - - ldr.setSource("xyz"); - - // the source does not have an assignment - BucketAssignments asgnUnassigned = new BucketAssignments(new String[] {"abc", "def"}); - expectCheckValidityFailure(msg -> msg.setAssignments(asgnUnassigned)); - - // the source is not the smallest UUID in this assignment - BucketAssignments asgnNotSmallest = new BucketAssignments(new String[] {VALID_HOST_PREDECESSOR, VALID_HOST}); - expectCheckValidityFailure(msg -> msg.setAssignments(asgnNotSmallest)); - } - - @Override - public Leader makeValidMessage() { - Leader msg = new Leader(VALID_HOST, (isNullAssignments() ? null : VALID_ASGN)); - msg.setChannel(VALID_CHANNEL); - - return msg; - } - -} 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 deleted file mode 100644 index db8cd9f9..00000000 --- a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/MessageTest.java +++ /dev/null @@ -1,81 +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; - -public class MessageTest extends SupportBasicMessageTester<Message> { - - public MessageTest() { - super(Message.class); - } - - @Test - public void testGetSource_testSetSource() { - Message msg = new Message(); - - msg.setSource("hello"); - assertEquals("hello", msg.getSource()); - assertNull(msg.getChannel()); - - msg.setSource("world"); - assertEquals("world", msg.getSource()); - assertNull(msg.getChannel()); - } - - @Test - public void testGetChannel_testSetChannel() { - Message msg = new Message(); - - msg.setChannel("hello"); - assertEquals("hello", msg.getChannel()); - assertNull(msg.getSource()); - - msg.setChannel("world"); - assertEquals("world", msg.getChannel()); - assertNull(msg.getSource()); - } - - @Test - public void testCheckValidity_InvalidFields() { - // null or empty source - expectCheckValidityFailure_NullOrEmpty((msg, value) -> msg.setSource(value)); - - // null or empty channel - expectCheckValidityFailure_NullOrEmpty((msg, value) -> msg.setChannel(value)); - } - - /** - * Makes a message that will pass the validity check. - * - * @return a valid Message - */ - public Message makeValidMessage() { - Message msg = new Message(VALID_HOST); - msg.setChannel(VALID_CHANNEL); - - return msg; - } - -} 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 deleted file mode 100644 index 906733e9..00000000 --- a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/OfflineTest.java +++ /dev/null @@ -1,37 +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; - -public class OfflineTest extends SupportBasicMessageTester<Offline> { - - public OfflineTest() { - super(Offline.class); - } - - @Override - public Offline makeValidMessage() { - Offline msg = new Offline(VALID_HOST); - msg.setChannel(VALID_CHANNEL); - - return msg; - } - -} 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 deleted file mode 100644 index 933dddfd..00000000 --- a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/QueryTest.java +++ /dev/null @@ -1,37 +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; - -public class QueryTest extends SupportBasicMessageTester<Query> { - - public QueryTest() { - super(Query.class); - } - - @Override - public Query makeValidMessage() { - Query msg = new Query(VALID_HOST); - msg.setChannel(VALID_CHANNEL); - - return msg; - } - -} 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 deleted file mode 100644 index 86247835..00000000 --- a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/SupportBasicMessageTester.java +++ /dev/null @@ -1,250 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * ONAP - * ================================================================================ - * Copyright (C) 2018-2019 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 org.junit.Test; -import org.onap.policy.drools.pooling.PoolingFeatureException; -import org.onap.policy.drools.pooling.Serializer; - -/** - * Superclass used to test subclasses of {@link Message}. - * - * @param <T> type of {@link Message} subclass that this tests - */ -public abstract class SupportBasicMessageTester<T extends Message> { - // 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 Serializer mapper = new Serializer(); - - /** - * The subclass of the type of Message being tested. - */ - private final Class<T> subclazz; - - /** - * Constructor. - * - * @param subclazz subclass of {@link Message} being tested - */ - public SupportBasicMessageTester(Class<T> 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; - if (originalMsg.getClass() == Message.class) { - msg = originalMsg; - } else { - msg = mapper.decodeMsg(mapper.encodeMsg(originalMsg)); - } - - 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<T> 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<T> 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 <T> type of Message the function updates - */ - @FunctionalInterface - public static interface MessageUpdateFunction<T extends Message> { - - /** - * Updates a message. - * - * @param msg message to be updated - */ - void update(T msg); - } - - /** - * Function that updates a single field within a message. - * - * @param <T> type of Message the function updates - */ - @FunctionalInterface - public static interface MessageFieldUpdateFunction<T extends Message> { - - /** - * Updates a field within a message. - * - * @param msg message to be updated - * @param newValue new field value - */ - 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 deleted file mode 100644 index bf245feb..00000000 --- a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/message/SupportMessageWithAssignmentsTester.java +++ /dev/null @@ -1,113 +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 <T> type of {@link MessageWithAssignments} subclass that this tests - */ -public abstract class SupportMessageWithAssignmentsTester<T extends MessageWithAssignments> - extends SupportBasicMessageTester<T> { - // 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<T> 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 deleted file mode 100644 index 771f694e..00000000 --- a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/state/ActiveStateTest.java +++ /dev/null @@ -1,470 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * ONAP - * ================================================================================ - * Copyright (C) 2018, 2020 AT&T Intellectual Property. All rights reserved. - * Modifications Copyright (C) 2020 Nordix Foundation - * ================================================================================ - * 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.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.atLeast; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.Arrays; -import org.apache.commons.lang3.tuple.Pair; -import org.apache.commons.lang3.tuple.Triple; -import org.junit.Before; -import org.junit.Test; -import org.onap.policy.drools.pooling.message.BucketAssignments; -import org.onap.policy.drools.pooling.message.Heartbeat; -import org.onap.policy.drools.pooling.message.Leader; -import org.onap.policy.drools.pooling.message.Offline; -import org.onap.policy.drools.pooling.message.Query; - -public class ActiveStateTest extends SupportBasicStateTester { - - private ActiveState state; - - /** - * Setup. - */ - @Override - @Before - public void setUp() throws Exception { - super.setUp(); - - state = new ActiveState(mgr); - } - - @Test - public void testStart() { - state.start(); - - // ensure the timers were created - verify(mgr, atLeast(1)).scheduleWithFixedDelay(anyLong(), anyLong(), any(StateTimerTask.class)); - - // ensure a heart beat was generated - Pair<String, Heartbeat> msg = capturePublishedMessage(Heartbeat.class); - assertEquals(MY_HOST, msg.getRight().getSource()); - } - - @Test - public void testProcessHeartbeat_NullHost() { - assertNull(state.process(new Heartbeat())); - - assertFalse(state.isMyHeartbeatSeen()); - assertFalse(state.isPredHeartbeatSeen()); - - verify(mgr, never()).goInactive(); - verify(mgr, never()).goQuery(); - } - - @Test - public void testProcessHeartbeat_MyHost() { - assertNull(state.process(new Heartbeat(MY_HOST, 0L))); - - assertTrue(state.isMyHeartbeatSeen()); - assertFalse(state.isPredHeartbeatSeen()); - - verify(mgr, never()).goInactive(); - verify(mgr, never()).goQuery(); - } - - @Test - public void testProcessHeartbeat_Predecessor() { - assertNull(state.process(new Heartbeat(HOST2, 0L))); - - assertFalse(state.isMyHeartbeatSeen()); - assertTrue(state.isPredHeartbeatSeen()); - - verify(mgr, never()).goInactive(); - verify(mgr, never()).goQuery(); - } - - @Test - public void testProcessHeartbeat_OtherHost() { - assertNull(state.process(new Heartbeat(HOST3, 0L))); - - assertFalse(state.isMyHeartbeatSeen()); - assertFalse(state.isPredHeartbeatSeen()); - - verify(mgr, never()).goInactive(); - verify(mgr, never()).goQuery(); - } - - @Test - public void testProcessOffline_NullHost() { - // should be ignored - assertNull(state.process(new Offline())); - } - - @Test - public void testProcessOffline_UnassignedHost() { - // HOST4 is not in the assignment list - should be ignored - assertNull(state.process(new Offline(HOST4))); - } - - @Test - public void testProcessOffline_IAmLeader() { - // configure the next state - State next = mock(State.class); - when(mgr.goActive()).thenReturn(next); - - // one of the assigned hosts went offline - assertEquals(next, state.process(new Offline(HOST1))); - - // should have sent a new Leader message - Leader msg = captureAdminMessage(Leader.class); - - assertEquals(MY_HOST, msg.getSource()); - - // check new bucket assignments - assertEquals(Arrays.asList(MY_HOST, MY_HOST, HOST2), Arrays.asList(msg.getAssignments().getHostArray())); - } - - @Test - public void testProcessOffline_PredecessorIsLeaderNowOffline() { - // configure the next state - State next = mock(State.class); - when(mgr.goActive()).thenReturn(next); - - // I am not the leader, but my predecessor was - mgr.startDistributing(new BucketAssignments(new String[] {PREV_HOST, MY_HOST, HOST1})); - state = new ActiveState(mgr); - - // my predecessor went offline - assertEquals(next, state.process(new Offline(PREV_HOST))); - - // should have sent a new Leader message - Leader msg = captureAdminMessage(Leader.class); - - assertEquals(MY_HOST, msg.getSource()); - - // check new bucket assignments - assertEquals(Arrays.asList(MY_HOST, MY_HOST, HOST1), Arrays.asList(msg.getAssignments().getHostArray())); - } - - @Test - public void testProcessOffline__PredecessorIsNotLeaderNowOffline() { - // I am not the leader, and neither is my predecessor - mgr.startDistributing(new BucketAssignments(new String[] {PREV_HOST, MY_HOST, PREV_HOST2})); - state = new ActiveState(mgr); - - /* - * - * PREV_HOST2 has buckets and is my predecessor, but it isn't the leader thus - * should be ignored. - */ - assertNull(state.process(new Offline(PREV_HOST2))); - } - - @Test - public void testProcessOffline_OtherAssignedHostOffline() { - // I am not the leader - mgr.startDistributing(new BucketAssignments(new String[] {PREV_HOST, MY_HOST, HOST1})); - state = new ActiveState(mgr); - - /* - * HOST1 has buckets, but it isn't the leader and it isn't my predecessor, thus - * should be ignored. - */ - assertNull(state.process(new Offline(HOST1))); - } - - @Test - public void testProcessLeader_Invalid() { - Leader msg = new Leader(PREV_HOST, null); - - // should stay in the same state, and not start distributing - assertNull(state.process(msg)); - verify(mgr, never()).startDistributing(any()); - verify(mgr, never()).goActive(); - verify(mgr, never()).goInactive(); - - // info should be unchanged - assertEquals(MY_HOST, state.getLeader()); - assertEquals(ASGN3, state.getAssignments()); - } - - @Test - public void testProcessLeader_BadLeader() { - String[] arr = {HOST2, HOST1}; - BucketAssignments asgn = new BucketAssignments(arr); - - // now send a Leader message for that leader - Leader msg = new Leader(HOST1, asgn); - - State next = mock(State.class); - when(mgr.goQuery()).thenReturn(next); - - // should go Query, but not start distributing - assertEquals(next, state.process(msg)); - verify(mgr, never()).startDistributing(asgn); - } - - @Test - public void testProcessLeader_GoodLeader() { - String[] arr = {HOST2, PREV_HOST, MY_HOST}; - BucketAssignments asgn = new BucketAssignments(arr); - - // now send a Leader message for that leader - Leader msg = new Leader(PREV_HOST, asgn); - - State next = mock(State.class); - when(mgr.goActive()).thenReturn(next); - - // should go Active and start distributing - assertEquals(next, state.process(msg)); - verify(mgr).startDistributing(asgn); - } - - @Test - public void testActiveState() { - assertEquals(MY_HOST, state.getLeader()); - assertEquals(ASGN3, state.getAssignments()); - - // verify that it determined its neighbors - assertEquals(HOST1, state.getSuccHost()); - assertEquals(HOST2, state.getPredHost()); - } - - @Test - public void testDetmNeighbors() { - // if only one host (i.e., itself) - mgr.startDistributing(new BucketAssignments(new String[] {MY_HOST, MY_HOST})); - state = new ActiveState(mgr); - assertEquals(null, state.getSuccHost()); - assertEquals("", state.getPredHost()); - - // two hosts - mgr.startDistributing(new BucketAssignments(new String[] {MY_HOST, HOST2})); - state = new ActiveState(mgr); - assertEquals(HOST2, state.getSuccHost()); - assertEquals(HOST2, state.getPredHost()); - - // three hosts - mgr.startDistributing(new BucketAssignments(new String[] {HOST3, MY_HOST, HOST2})); - state = new ActiveState(mgr); - assertEquals(HOST2, state.getSuccHost()); - assertEquals(HOST3, state.getPredHost()); - - // more hosts - mgr.startDistributing(new BucketAssignments(new String[] {HOST3, MY_HOST, HOST2, HOST4})); - state = new ActiveState(mgr); - assertEquals(HOST2, state.getSuccHost()); - assertEquals(HOST4, state.getPredHost()); - } - - @Test - public void testAddTimers_WithPredecessor() { - // invoke start() to add the timers - state.start(); - - assertEquals(3, repeatedSchedules.size()); - - Triple<Long, Long, StateTimerTask> timer; - - // heart beat generator - timer = repeatedTasks.remove(); - assertEquals(STD_INTER_HEARTBEAT_MS, timer.getLeft().longValue()); - assertEquals(STD_INTER_HEARTBEAT_MS, timer.getMiddle().longValue()); - - // my heart beat checker - timer = repeatedTasks.remove(); - assertEquals(STD_ACTIVE_HEARTBEAT_MS, timer.getLeft().longValue()); - assertEquals(STD_ACTIVE_HEARTBEAT_MS, timer.getMiddle().longValue()); - - // predecessor's heart beat checker - timer = repeatedTasks.remove(); - assertEquals(STD_ACTIVE_HEARTBEAT_MS, timer.getLeft().longValue()); - assertEquals(STD_ACTIVE_HEARTBEAT_MS, timer.getMiddle().longValue()); - } - - @Test - public void testAddTimers_SansPredecessor() { - // only one host, thus no predecessor - mgr.startDistributing(new BucketAssignments(new String[] {MY_HOST, MY_HOST})); - state = new ActiveState(mgr); - - // invoke start() to add the timers - state.start(); - - assertEquals(2, repeatedSchedules.size()); - - Triple<Long, Long, StateTimerTask> timer; - - // heart beat generator - timer = repeatedTasks.remove(); - assertEquals(STD_INTER_HEARTBEAT_MS, timer.getLeft().longValue()); - assertEquals(STD_INTER_HEARTBEAT_MS, timer.getMiddle().longValue()); - - // my heart beat checker - timer = repeatedTasks.remove(); - assertEquals(STD_ACTIVE_HEARTBEAT_MS, timer.getLeft().longValue()); - assertEquals(STD_ACTIVE_HEARTBEAT_MS, timer.getMiddle().longValue()); - } - - @Test - public void testAddTimers_HeartbeatGenerator() { - // only one host so we only have to look at one heart beat at a time - mgr.startDistributing(new BucketAssignments(new String[] {MY_HOST})); - state = new ActiveState(mgr); - - // invoke start() to add the timers - state.start(); - - Triple<Long, Long, StateTimerTask> task = repeatedTasks.remove(); - - verify(mgr).publish(anyString(), any(Heartbeat.class)); - - // fire the task - assertNull(task.getRight().fire()); - - // should have generated a second pair of heart beats - verify(mgr, times(2)).publish(anyString(), any(Heartbeat.class)); - - Pair<String, Heartbeat> msg = capturePublishedMessage(Heartbeat.class); - assertEquals(MY_HOST, msg.getLeft()); - assertEquals(MY_HOST, msg.getRight().getSource()); - } - - @Test - public void testAddTimers_MyHeartbeatSeen() { - // invoke start() to add the timers - state.start(); - - Triple<Long, Long, StateTimerTask> task = repeatedTasks.get(1); - - // indicate that this host is still alive - state.process(new Heartbeat(MY_HOST, 0L)); - - // set up next state - State next = mock(State.class); - when(mgr.goInactive()).thenReturn(next); - - // fire the task - should not transition - assertNull(task.getRight().fire()); - - verify(mgr, never()).publishAdmin(any(Query.class)); - } - - @Test - public void testAddTimers_MyHeartbeatMissed() { - // invoke start() to add the timers - state.start(); - - Triple<Long, Long, StateTimerTask> task = repeatedTasks.get(1); - - // set up next state - State next = mock(State.class); - when(mgr.goStart()).thenReturn(next); - - // fire the task - should transition - assertEquals(next, task.getRight().fire()); - - // should continue to distribute - verify(mgr, never()).startDistributing(null); - - // should publish an offline message - Offline msg = captureAdminMessage(Offline.class); - assertEquals(MY_HOST, msg.getSource()); - } - - @Test - public void testAddTimers_PredecessorHeartbeatSeen() { - // invoke start() to add the timers - state.start(); - - Triple<Long, Long, StateTimerTask> task = repeatedTasks.get(2); - - // indicate that the predecessor is still alive - state.process(new Heartbeat(HOST2, 0L)); - - // set up next state, just in case - State next = mock(State.class); - when(mgr.goQuery()).thenReturn(next); - - // fire the task - should NOT transition - assertNull(task.getRight().fire()); - - verify(mgr, never()).publishAdmin(any(Query.class)); - } - - @Test - public void testAddTimers_PredecessorHeartbeatMissed() { - // invoke start() to add the timers - state.start(); - - Triple<Long, Long, StateTimerTask> task = repeatedTasks.get(2); - - // set up next state - State next = mock(State.class); - when(mgr.goQuery()).thenReturn(next); - - // fire the task - should transition - assertEquals(next, task.getRight().fire()); - - verify(mgr).publishAdmin(any(Query.class)); - } - - @Test - public void testGenHeartbeat_OneHost() { - // only one host (i.e., itself) - mgr.startDistributing(new BucketAssignments(new String[] {MY_HOST})); - state = new ActiveState(mgr); - - state.start(); - - verify(mgr, times(1)).publish(any(), any()); - - Pair<String, Heartbeat> msg = capturePublishedMessage(Heartbeat.class); - assertEquals(MY_HOST, msg.getLeft()); - assertEquals(MY_HOST, msg.getRight().getSource()); - } - - @Test - public void testGenHeartbeat_MultipleHosts() { - state.start(); - - verify(mgr, times(2)).publish(any(), any()); - - Pair<String, Heartbeat> msg; - int index = 0; - - // this message should go to itself - msg = capturePublishedMessage(Heartbeat.class, index++); - assertEquals(MY_HOST, msg.getLeft()); - assertEquals(MY_HOST, msg.getRight().getSource()); - - // this message should go to its successor - msg = capturePublishedMessage(Heartbeat.class, index++); - assertEquals(HOST1, msg.getLeft()); - assertEquals(MY_HOST, msg.getRight().getSource()); - } - -} 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 deleted file mode 100644 index 5cc88d3a..00000000 --- a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/state/IdleStateTest.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * ONAP - * ================================================================================ - * Copyright (C) 2018, 2020 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ - -package org.onap.policy.drools.pooling.state; - -import static org.junit.Assert.assertNull; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import org.junit.Before; -import org.junit.Test; -import org.onap.policy.drools.pooling.message.BucketAssignments; -import org.onap.policy.drools.pooling.message.Heartbeat; -import org.onap.policy.drools.pooling.message.Identification; -import org.onap.policy.drools.pooling.message.Leader; -import org.onap.policy.drools.pooling.message.Offline; -import org.onap.policy.drools.pooling.message.Query; - -public class IdleStateTest extends SupportBasicStateTester { - - private IdleState state; - - /** - * Setup. - */ - @Before - public void setUp() throws Exception { - super.setUp(); - - state = new IdleState(mgr); - } - - @Test - public void testProcessHeartbeat() { - assertNull(state.process(new Heartbeat(PREV_HOST, 0L))); - verifyNothingPublished(); - } - - @Test - public void testProcessIdentification() { - assertNull(state.process(new Identification(PREV_HOST, null))); - verifyNothingPublished(); - } - - @Test - public void testProcessLeader() { - BucketAssignments asgn = new BucketAssignments(new String[] {HOST2, PREV_HOST, MY_HOST}); - Leader msg = new Leader(PREV_HOST, asgn); - - State next = mock(State.class); - when(mgr.goActive()).thenReturn(next); - - // should stay in current state, but start distributing - assertNull(state.process(msg)); - verify(mgr).startDistributing(asgn); - } - - @Test - public void testProcessOffline() { - assertNull(state.process(new Offline(PREV_HOST))); - verifyNothingPublished(); - } - - @Test - public void testProcessQuery() { - assertNull(state.process(new Query())); - verifyNothingPublished(); - } - - /** - * Verifies that nothing was published on either channel. - */ - private void verifyNothingPublished() { - verify(mgr, never()).publish(any(), any()); - verify(mgr, never()).publishAdmin(any()); - } -} 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 deleted file mode 100644 index f8f70461..00000000 --- a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/state/InactiveStateTest.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * ONAP - * ================================================================================ - * Copyright (C) 2018, 2020 AT&T Intellectual Property. All rights reserved. - * Modifications Copyright (C) 2020 Nordix Foundation - * ================================================================================ - * 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.assertEquals; -import static org.junit.Assert.assertNull; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import org.apache.commons.lang3.tuple.Pair; -import org.junit.Before; -import org.junit.Test; -import org.onap.policy.drools.pooling.message.BucketAssignments; -import org.onap.policy.drools.pooling.message.Identification; -import org.onap.policy.drools.pooling.message.Leader; -import org.onap.policy.drools.pooling.message.Query; - -public class InactiveStateTest extends SupportBasicStateTester { - - private InactiveState state; - - /** - * Setup. - * - */ - @Override - @Before - public void setUp() throws Exception { - super.setUp(); - - state = new InactiveState(mgr); - } - - @Test - public void testProcessLeader() { - State next = mock(State.class); - when(mgr.goActive()).thenReturn(next); - - String[] arr = {PREV_HOST, MY_HOST, HOST1}; - BucketAssignments asgn = new BucketAssignments(arr); - Leader msg = new Leader(PREV_HOST, asgn); - - assertEquals(next, state.process(msg)); - verify(mgr).startDistributing(asgn); - } - - @Test - public void testProcessLeader_Invalid() { - Leader msg = new Leader(PREV_HOST, null); - - // should stay in the same state, and not start distributing - assertNull(state.process(msg)); - verify(mgr, never()).startDistributing(any()); - verify(mgr, never()).goActive(); - verify(mgr, never()).goInactive(); - } - - @Test - public void testProcessQuery() { - State next = mock(State.class); - when(mgr.goQuery()).thenReturn(next); - - assertEquals(next, state.process(new Query())); - - Identification ident = captureAdminMessage(Identification.class); - assertEquals(MY_HOST, ident.getSource()); - assertEquals(ASGN3, ident.getAssignments()); - } - - @Test - public void testGoInatcive() { - assertNull(state.goInactive()); - } - - @Test - public void testStart() { - state.start(); - - Pair<Long, StateTimerTask> timer = onceTasks.remove(); - - assertEquals(STD_REACTIVATE_WAIT_MS, timer.getLeft().longValue()); - - // invoke the task - it should go to the state returned by the mgr - State next = mock(State.class); - when(mgr.goStart()).thenReturn(next); - - assertEquals(next, timer.getRight().fire()); - } - - @Test - public void testInactiveState() { - /* - * Prove the state is attached to the manager by invoking getHost(), which - * delegates to the manager. - */ - assertEquals(MY_HOST, state.getHost()); - } - -} 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 deleted file mode 100644 index 02cbe491..00000000 --- a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/state/ProcessingStateTest.java +++ /dev/null @@ -1,393 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * ONAP - * ================================================================================ - * Copyright (C) 2018, 2020-2021 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.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNotSame; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.Arrays; -import org.junit.Before; -import org.junit.Test; -import org.onap.policy.drools.pooling.message.BucketAssignments; -import org.onap.policy.drools.pooling.message.Identification; -import org.onap.policy.drools.pooling.message.Leader; -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 SupportBasicStateTester { - - private ProcessingState state; - private HostBucket hostBucket; - - /** - * Setup. - */ - @Before - public void setUp() throws Exception { - super.setUp(); - - state = new ProcessingState(mgr, MY_HOST); - hostBucket = new HostBucket(MY_HOST); - } - - @Test - public void testProcessQuery() { - State next = mock(State.class); - when(mgr.goQuery()).thenReturn(next); - - assertEquals(next, state.process(new Query())); - - Identification ident = captureAdminMessage(Identification.class); - assertEquals(MY_HOST, ident.getSource()); - assertEquals(ASGN3, ident.getAssignments()); - } - - @Test - public void testProcessingState() { - /* - * Null assignments should be OK. - */ - when(mgr.getAssignments()).thenReturn(null); - state = new ProcessingState(mgr, LEADER); - - /* - * Empty assignments should be OK. - */ - when(mgr.getAssignments()).thenReturn(EMPTY_ASGN); - state = new ProcessingState(mgr, LEADER); - assertEquals(MY_HOST, state.getHost()); - assertEquals(LEADER, state.getLeader()); - assertEquals(EMPTY_ASGN, state.getAssignments()); - - /* - * Now try something with assignments. - */ - when(mgr.getAssignments()).thenReturn(ASGN3); - state = new ProcessingState(mgr, LEADER); - - /* - * Prove the state is attached to the manager by invoking getHost(), which - * delegates to the manager. - */ - assertEquals(MY_HOST, state.getHost()); - - assertEquals(LEADER, state.getLeader()); - assertEquals(ASGN3, state.getAssignments()); - } - - @Test(expected = IllegalArgumentException.class) - public void testProcessingState_NullLeader() { - when(mgr.getAssignments()).thenReturn(EMPTY_ASGN); - state = new ProcessingState(mgr, null); - } - - @Test(expected = IllegalArgumentException.class) - public void testProcessingState_ZeroLengthHostArray() { - when(mgr.getAssignments()).thenReturn(new BucketAssignments(new String[] {})); - state = new ProcessingState(mgr, LEADER); - } - - @Test - public void testGetAssignments() { - // assignments from constructor - assertEquals(ASGN3, state.getAssignments()); - - // null assignments - no effect - state.setAssignments(null); - assertEquals(ASGN3, state.getAssignments()); - - // empty assignments - state.setAssignments(EMPTY_ASGN); - assertEquals(EMPTY_ASGN, state.getAssignments()); - - // non-empty assignments - state.setAssignments(ASGN3); - assertEquals(ASGN3, state.getAssignments()); - } - - @Test - public void testSetAssignments() { - state.setAssignments(null); - verify(mgr, never()).startDistributing(any()); - - state.setAssignments(ASGN3); - verify(mgr).startDistributing(ASGN3); - } - - @Test - public void testGetLeader() { - // check value from constructor - assertEquals(MY_HOST, state.getLeader()); - - state.setLeader(HOST2); - assertEquals(HOST2, state.getLeader()); - - state.setLeader(HOST3); - assertEquals(HOST3, state.getLeader()); - } - - @Test - public void testSetLeader() { - state.setLeader(MY_HOST); - assertEquals(MY_HOST, state.getLeader()); - } - - @Test(expected = NullPointerException.class) - public void testSetLeader_Null() { - state.setLeader(null); - } - - @Test - public void testIsLeader() { - state.setLeader(MY_HOST); - assertTrue(state.isLeader()); - - state.setLeader(HOST2); - assertFalse(state.isLeader()); - } - - @Test - public void testBecomeLeader() { - State next = mock(State.class); - when(mgr.goActive()).thenReturn(next); - - assertEquals(next, state.becomeLeader(sortHosts(MY_HOST, HOST2))); - - Leader msg = captureAdminMessage(Leader.class); - - verify(mgr).startDistributing(msg.getAssignments()); - verify(mgr).goActive(); - } - - @Test(expected = IllegalArgumentException.class) - public void testBecomeLeader_NotFirstAlive() { - // alive list contains something before my host name - state.becomeLeader(sortHosts(PREV_HOST, MY_HOST)); - } - - @Test - public void testMakeLeader() throws Exception { - state.becomeLeader(sortHosts(MY_HOST, HOST2)); - - Leader msg = captureAdminMessage(Leader.class); - - // need a channel before invoking checkValidity() - msg.setChannel(Message.ADMIN); - - msg.checkValidity(); - - assertEquals(MY_HOST, msg.getSource()); - assertNotNull(msg.getAssignments()); - assertTrue(msg.getAssignments().hasAssignment(MY_HOST)); - assertTrue(msg.getAssignments().hasAssignment(HOST2)); - - // this one wasn't in the list of hosts, so it should have been removed - assertFalse(msg.getAssignments().hasAssignment(HOST1)); - } - - @Test - public void testMakeAssignments() throws Exception { - state.becomeLeader(sortHosts(MY_HOST, HOST2)); - - captureAssignments().checkValidity(); - } - - @Test - public void testMakeBucketArray_NullAssignments() { - when(mgr.getAssignments()).thenReturn(null); - state = new ProcessingState(mgr, MY_HOST); - state.becomeLeader(sortHosts(MY_HOST)); - - String[] arr = captureHostArray(); - - assertEquals(BucketAssignments.MAX_BUCKETS, arr.length); - - assertTrue(Arrays.asList(arr).stream().allMatch(host -> MY_HOST.equals(host))); - } - - @Test - public void testMakeBucketArray_ZeroAssignments() { - // bucket assignment with a zero-length array - state.setAssignments(new BucketAssignments(new String[0])); - - state.becomeLeader(sortHosts(MY_HOST)); - - String[] arr = captureHostArray(); - - assertEquals(BucketAssignments.MAX_BUCKETS, arr.length); - - assertTrue(Arrays.asList(arr).stream().allMatch(host -> MY_HOST.equals(host))); - } - - @Test - public void testMakeBucketArray() { - /* - * All hosts are still alive, so it should have the exact same assignments as it - * had to start. - */ - state.setAssignments(ASGN3); - state.becomeLeader(sortHosts(HOST_ARR3)); - - String[] arr = captureHostArray(); - - assertNotSame(HOST_ARR3, arr); - assertEquals(Arrays.asList(HOST_ARR3), Arrays.asList(arr)); - } - - @Test - public void testRemoveExcessHosts() { - /* - * All hosts are still alive, plus some others. - */ - state.setAssignments(ASGN3); - state.becomeLeader(sortHosts(MY_HOST, HOST1, HOST2, HOST3, HOST4)); - - // assignments should be unchanged - assertEquals(Arrays.asList(HOST_ARR3), captureHostList()); - } - - @Test - public void testAddIndicesToHostBuckets() { - // some are null, some hosts are no longer alive - String[] asgn = {null, MY_HOST, HOST3, null, HOST4, HOST1, HOST2}; - - state.setAssignments(new BucketAssignments(asgn)); - state.becomeLeader(sortHosts(MY_HOST, HOST1, HOST2)); - - // every bucket should be assigned to one of the three hosts - String[] expected = {MY_HOST, MY_HOST, HOST1, HOST2, MY_HOST, HOST1, HOST2}; - assertEquals(Arrays.asList(expected), captureHostList()); - } - - @Test - public void testAssignNullBuckets() { - /* - * Ensure buckets are assigned to the host with the fewest buckets. - */ - String[] asgn = {MY_HOST, HOST1, MY_HOST, null, null, null, null, null, MY_HOST}; - - state.setAssignments(new BucketAssignments(asgn)); - state.becomeLeader(sortHosts(MY_HOST, HOST1, HOST2)); - - String[] expected = {MY_HOST, HOST1, MY_HOST, HOST2, HOST1, HOST2, HOST1, HOST2, MY_HOST}; - assertEquals(Arrays.asList(expected), captureHostList()); - } - - @Test - public void testRebalanceBuckets() { - /* - * Some are very lopsided. - */ - String[] asgn = {MY_HOST, HOST1, MY_HOST, MY_HOST, MY_HOST, MY_HOST, HOST1, HOST2, HOST1, HOST3}; - - state.setAssignments(new BucketAssignments(asgn)); - state.becomeLeader(sortHosts(MY_HOST, HOST1, HOST2, HOST3)); - - String[] expected = {HOST2, HOST1, HOST3, MY_HOST, MY_HOST, MY_HOST, HOST1, HOST2, HOST1, HOST3}; - assertEquals(Arrays.asList(expected), captureHostList()); - } - - @Test - public void testHostBucketRemove_testHostBucketAdd_testHostBucketSize() { - assertEquals(0, hostBucket.size()); - - hostBucket.add(20); - hostBucket.add(30); - hostBucket.add(40); - assertEquals(3, hostBucket.size()); - - assertEquals(20, hostBucket.remove().intValue()); - assertEquals(30, hostBucket.remove().intValue()); - assertEquals(1, hostBucket.size()); - - // add more before taking the last item - hostBucket.add(50); - hostBucket.add(60); - assertEquals(3, hostBucket.size()); - - assertEquals(40, hostBucket.remove().intValue()); - assertEquals(50, hostBucket.remove().intValue()); - assertEquals(60, hostBucket.remove().intValue()); - assertEquals(0, hostBucket.size()); - - // add more AFTER taking the last item - hostBucket.add(70); - assertEquals(70, hostBucket.remove().intValue()); - assertEquals(0, hostBucket.size()); - } - - @Test - public void testHostBucketCompareTo() { - HostBucket hb1 = new HostBucket(PREV_HOST); - HostBucket hb2 = new HostBucket(MY_HOST); - - assertEquals(0, hb1.compareTo(hb1)); - assertEquals(0, hb1.compareTo(new HostBucket(PREV_HOST))); - - // both empty - assertTrue(hb1.compareTo(hb2) < 0); - assertTrue(hb2.compareTo(hb1) > 0); - - // hb1 has one bucket, so it should not be larger - hb1.add(100); - assertTrue(hb1.compareTo(hb2) > 0); - assertTrue(hb2.compareTo(hb1) < 0); - - // hb1 has two buckets, so it should still be larger - hb1.add(200); - assertTrue(hb1.compareTo(hb2) > 0); - assertTrue(hb2.compareTo(hb1) < 0); - - // hb1 has two buckets, hb2 has one, so hb1 should still be larger - hb2.add(1000); - assertTrue(hb1.compareTo(hb2) > 0); - assertTrue(hb2.compareTo(hb1) < 0); - - // same number of buckets, so hb2 should now be larger - hb2.add(2000); - assertTrue(hb1.compareTo(hb2) < 0); - assertTrue(hb2.compareTo(hb1) > 0); - - // hb2 has more buckets, it should still be larger - hb2.add(3000); - assertTrue(hb1.compareTo(hb2) < 0); - assertTrue(hb2.compareTo(hb1) > 0); - } - - @Test(expected = UnsupportedOperationException.class) - public void testHostBucketHashCode() { - hostBucket.hashCode(); - } - - @Test(expected = UnsupportedOperationException.class) - public void testHostBucketEquals() { - hostBucket.equals(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 deleted file mode 100644 index 70abb96a..00000000 --- a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/state/QueryStateTest.java +++ /dev/null @@ -1,444 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * ONAP - * ================================================================================ - * Copyright (C) 2018, 2020 AT&T Intellectual Property. All rights reserved. - * Modifications Copyright (C) 2020 Nordix Foundation - * ================================================================================ - * 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.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import org.apache.commons.lang3.tuple.Pair; -import org.junit.Before; -import org.junit.Test; -import org.onap.policy.drools.pooling.message.BucketAssignments; -import org.onap.policy.drools.pooling.message.Identification; -import org.onap.policy.drools.pooling.message.Leader; -import org.onap.policy.drools.pooling.message.Offline; - -public class QueryStateTest extends SupportBasicStateTester { - - private QueryState state; - - /** - * Setup. - */ - @Override - @Before - public void setUp() throws Exception { - super.setUp(); - - state = new QueryState(mgr); - } - - @Test - public void testGoQuery() { - assertNull(state.goQuery()); - } - - @Test - public void testStart() { - state.start(); - - Pair<Long, StateTimerTask> timer = onceTasks.remove(); - - assertEquals(STD_IDENTIFICATION_MS, timer.getLeft().longValue()); - assertNotNull(timer.getRight()); - } - - @Test - public void testProcessIdentification_SameSource() { - String[] arr = {HOST2, PREV_HOST, MY_HOST}; - BucketAssignments asgn = new BucketAssignments(arr); - - assertNull(state.process(new Identification(MY_HOST, asgn))); - - // info should be unchanged - assertEquals(MY_HOST, state.getLeader()); - verify(mgr, never()).startDistributing(asgn); - } - - @Test - public void testProcessIdentification_DiffSource() { - String[] arr = {HOST2, PREV_HOST, MY_HOST}; - BucketAssignments asgn = new BucketAssignments(arr); - - assertNull(state.process(new Identification(HOST2, asgn))); - - // leader should be unchanged - assertEquals(MY_HOST, state.getLeader()); - - // should have picked up the assignments - verify(mgr).startDistributing(asgn); - } - - @Test - public void testProcessLeader_Invalid() { - Leader msg = new Leader(PREV_HOST, null); - - // should stay in the same state, and not start distributing - assertNull(state.process(msg)); - verify(mgr, never()).startDistributing(any()); - verify(mgr, never()).goActive(); - verify(mgr, never()).goInactive(); - - // info should be unchanged - assertEquals(MY_HOST, state.getLeader()); - assertEquals(ASGN3, state.getAssignments()); - } - - @Test - public void testProcessLeader_SameLeader() { - String[] arr = {HOST2, PREV_HOST, MY_HOST}; - BucketAssignments asgn = new BucketAssignments(arr); - - // identify a leader that's better than my host - assertEquals(null, state.process(new Identification(PREV_HOST, asgn))); - - // now send a Leader message for that leader - Leader msg = new Leader(PREV_HOST, asgn); - - State next = mock(State.class); - when(mgr.goActive()).thenReturn(next); - - // should go Active and start distributing - assertEquals(next, state.process(msg)); - verify(mgr, never()).goInactive(); - - // Ident msg + Leader msg = times(2) - verify(mgr, times(2)).startDistributing(asgn); - } - - @Test - public void testProcessLeader_BetterLeaderWithAssignment() { - String[] arr = {HOST2, PREV_HOST, MY_HOST}; - BucketAssignments asgn = new BucketAssignments(arr); - Leader msg = new Leader(PREV_HOST, asgn); - - State next = mock(State.class); - when(mgr.goActive()).thenReturn(next); - - // should go Active and start distributing - assertEquals(next, state.process(msg)); - verify(mgr).startDistributing(asgn); - verify(mgr, never()).goInactive(); - } - - @Test - public void testProcessLeader_BetterLeaderWithoutAssignment() { - String[] arr = {HOST2, PREV_HOST, HOST1}; - BucketAssignments asgn = new BucketAssignments(arr); - Leader msg = new Leader(PREV_HOST, asgn); - - State next = mock(State.class); - when(mgr.goInactive()).thenReturn(next); - - // should go Inactive, but start distributing - assertEquals(next, state.process(msg)); - verify(mgr).startDistributing(asgn); - verify(mgr, never()).goActive(); - } - - @Test - public void testProcessLeader_NotABetterLeader() { - // no assignments yet - mgr.startDistributing(null); - state = new QueryState(mgr); - - BucketAssignments asgn = new BucketAssignments(new String[] {HOST1, HOST2}); - Leader msg = new Leader(HOST1, asgn); - - State next = mock(State.class); - when(mgr.goInactive()).thenReturn(next); - - // should stay in the same state - assertNull(state.process(msg)); - verify(mgr, never()).goActive(); - verify(mgr, never()).goInactive(); - - // should have started distributing - verify(mgr).startDistributing(asgn); - - // this host should still be the leader - assertEquals(MY_HOST, state.getLeader()); - - // new assignments - assertEquals(asgn, state.getAssignments()); - } - - @Test - public void testProcessOffline_NullHost() { - assertNull(state.process(new Offline())); - assertEquals(MY_HOST, state.getLeader()); - } - - @Test - public void testProcessOffline_SameHost() { - assertNull(state.process(new Offline(MY_HOST))); - assertEquals(MY_HOST, state.getLeader()); - } - - @Test - public void testProcessOffline_DiffHost() { - BucketAssignments asgn = new BucketAssignments(new String[] {PREV_HOST, HOST1}); - mgr.startDistributing(asgn); - state = new QueryState(mgr); - - // tell it that the hosts are alive - state.process(new Identification(PREV_HOST, asgn)); - state.process(new Identification(HOST1, asgn)); - - // #2 goes offline - assertNull(state.process(new Offline(HOST1))); - - // #1 should still be the leader - assertEquals(PREV_HOST, state.getLeader()); - - // #1 goes offline - assertNull(state.process(new Offline(PREV_HOST))); - - // this should still be the leader now - assertEquals(MY_HOST, state.getLeader()); - } - - @Test - public void testQueryState() { - /* - * Prove the state is attached to the manager by invoking getHost(), which - * delegates to the manager. - */ - assertEquals(MY_HOST, state.getHost()); - } - - @Test - public void testAwaitIdentification_MissingSelfIdent() { - state.start(); - - Pair<Long, StateTimerTask> timer = onceTasks.remove(); - - assertEquals(STD_IDENTIFICATION_MS, timer.getLeft().longValue()); - assertNotNull(timer.getRight()); - - // should published an Offline message and go inactive - - State next = mock(State.class); - when(mgr.goStart()).thenReturn(next); - - assertEquals(next, timer.getRight().fire()); - - // should continue distributing - verify(mgr, never()).startDistributing(null); - - Offline msg = captureAdminMessage(Offline.class); - assertEquals(MY_HOST, msg.getSource()); - } - - @Test - public void testAwaitIdentification_Leader() { - state.start(); - state.process(new Identification(MY_HOST, null)); - - Pair<Long, StateTimerTask> timer = onceTasks.remove(); - - assertEquals(STD_IDENTIFICATION_MS, timer.getLeft().longValue()); - assertNotNull(timer.getRight()); - - State next = mock(State.class); - when(mgr.goActive()).thenReturn(next); - - assertEquals(next, timer.getRight().fire()); - - // should have published a Leader message - Leader msg = captureAdminMessage(Leader.class); - assertEquals(MY_HOST, msg.getSource()); - assertTrue(msg.getAssignments().hasAssignment(MY_HOST)); - } - - @Test - public void testAwaitIdentification_HasAssignment() { - // not the leader, but has an assignment - BucketAssignments asgn = new BucketAssignments(new String[] {PREV_HOST, MY_HOST, HOST2}); - mgr.startDistributing(asgn); - state = new QueryState(mgr); - - state.start(); - state.process(new Identification(MY_HOST, null)); - - // tell it the leader is still active - state.process(new Identification(PREV_HOST, asgn)); - - Pair<Long, StateTimerTask> timer = onceTasks.remove(); - - assertEquals(STD_IDENTIFICATION_MS, timer.getLeft().longValue()); - assertNotNull(timer.getRight()); - - // set up active state, as that's what it should return - State next = mock(State.class); - when(mgr.goActive()).thenReturn(next); - - assertEquals(next, timer.getRight().fire()); - - // should NOT have published a Leader message - assertTrue(admin.isEmpty()); - - // should have gone active with the current assignments - verify(mgr).goActive(); - } - - @Test - public void testAwaitIdentification_NoAssignment() { - // not the leader and no assignment - BucketAssignments asgn = new BucketAssignments(new String[] {HOST1, HOST2}); - mgr.startDistributing(asgn); - state = new QueryState(mgr); - - state.start(); - state.process(new Identification(MY_HOST, null)); - - // tell it the leader is still active - state.process(new Identification(PREV_HOST, asgn)); - - Pair<Long, StateTimerTask> timer = onceTasks.remove(); - - assertEquals(STD_IDENTIFICATION_MS, timer.getLeft().longValue()); - assertNotNull(timer.getRight()); - - // set up inactive state, as that's what it should return - State next = mock(State.class); - when(mgr.goInactive()).thenReturn(next); - - assertEquals(next, timer.getRight().fire()); - - // should NOT have published a Leader message - assertTrue(admin.isEmpty()); - } - - @Test - public void testRecordInfo_NullSource() { - state.setAssignments(ASGN3); - state.setLeader(MY_HOST); - - BucketAssignments asgn = new BucketAssignments(new String[] {PREV_HOST, MY_HOST, HOST2}); - state.process(new Identification(null, asgn)); - - // leader unchanged - assertEquals(MY_HOST, state.getLeader()); - - // assignments still updated - assertEquals(asgn, state.getAssignments()); - } - - @Test - public void testRecordInfo_SourcePreceedsMyHost() { - state.setAssignments(ASGN3); - state.setLeader(MY_HOST); - - BucketAssignments asgn = new BucketAssignments(new String[] {PREV_HOST, MY_HOST, HOST2}); - state.process(new Identification(PREV_HOST, asgn)); - - // new leader - assertEquals(PREV_HOST, state.getLeader()); - - // assignments still updated - assertEquals(asgn, state.getAssignments()); - } - - @Test - public void testRecordInfo_SourceFollowsMyHost() { - mgr.startDistributing(null); - state.setLeader(MY_HOST); - - BucketAssignments asgn = new BucketAssignments(new String[] {HOST1, HOST2}); - state.process(new Identification(HOST1, asgn)); - - // leader unchanged - assertEquals(MY_HOST, state.getLeader()); - - // assignments still updated - assertEquals(asgn, state.getAssignments()); - } - - @Test - public void testRecordInfo_NewIsNull() { - state.setAssignments(ASGN3); - state.process(new Identification(HOST1, null)); - - assertEquals(ASGN3, state.getAssignments()); - } - - @Test - public void testRecordInfo_NewIsEmpty() { - state.setAssignments(ASGN3); - state.process(new Identification(PREV_HOST, new BucketAssignments())); - - assertEquals(ASGN3, state.getAssignments()); - } - - @Test - public void testRecordInfo_OldIsNull() { - mgr.startDistributing(null); - - BucketAssignments asgn = new BucketAssignments(new String[] {HOST1, HOST2}); - state.process(new Identification(HOST1, asgn)); - - assertEquals(asgn, state.getAssignments()); - } - - @Test - public void testRecordInfo_OldIsEmpty() { - state.setAssignments(new BucketAssignments()); - - BucketAssignments asgn = new BucketAssignments(new String[] {HOST1, HOST2}); - state.process(new Identification(HOST1, asgn)); - - assertEquals(asgn, state.getAssignments()); - } - - @Test - public void testRecordInfo_NewLeaderPreceedsOld() { - state.setAssignments(ASGN3); - state.setLeader(MY_HOST); - - BucketAssignments asgn = new BucketAssignments(new String[] {PREV_HOST, MY_HOST, HOST2}); - state.process(new Identification(HOST3, asgn)); - - assertEquals(asgn, state.getAssignments()); - } - - @Test - public void testRecordInfo_NewLeaderSucceedsOld() { - state.setAssignments(ASGN3); - state.setLeader(MY_HOST); - - BucketAssignments asgn = new BucketAssignments(new String[] {HOST2, HOST3}); - state.process(new Identification(HOST3, asgn)); - - // should be unchanged - assertEquals(ASGN3, state.getAssignments()); - } - -} 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 deleted file mode 100644 index 3d64687f..00000000 --- a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/state/StartStateTest.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * ONAP - * ================================================================================ - * Copyright (C) 2018, 2020 AT&T Intellectual Property. All rights reserved. - * Modifications Copyright (C) 2020 Nordix Foundation - * ================================================================================ - * 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.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import org.apache.commons.lang3.tuple.Pair; -import org.apache.commons.lang3.tuple.Triple; -import org.junit.Before; -import org.junit.Test; -import org.onap.policy.drools.pooling.message.Heartbeat; -import org.onap.policy.drools.pooling.message.Identification; -import org.onap.policy.drools.pooling.message.Leader; -import org.onap.policy.drools.pooling.message.Offline; -import org.onap.policy.drools.pooling.message.Query; - -public class StartStateTest extends SupportBasicStateTester { - - private StartState state; - - /** - * Setup. - */ - @Override - @Before - public void setUp() throws Exception { - super.setUp(); - - state = new StartState(mgr); - } - - @Test - public void testStart() { - state.start(); - - Pair<String, Heartbeat> msg = capturePublishedMessage(Heartbeat.class); - - assertEquals(MY_HOST, msg.getLeft()); - assertEquals(state.getHbTimestampMs(), msg.getRight().getTimestampMs()); - - - /* - * Verify heartbeat generator - */ - Triple<Long, Long, StateTimerTask> generator = repeatedTasks.removeFirst(); - - assertEquals(STD_INTER_HEARTBEAT_MS, generator.getLeft().longValue()); - assertEquals(STD_INTER_HEARTBEAT_MS, generator.getMiddle().longValue()); - - // invoke the task - it should generate another heartbeat - assertEquals(null, generator.getRight().fire()); - verify(mgr, times(2)).publish(MY_HOST, msg.getRight()); - - // and again - assertEquals(null, generator.getRight().fire()); - verify(mgr, times(3)).publish(MY_HOST, msg.getRight()); - - - /* - * Verify heartbeat checker - */ - Pair<Long, StateTimerTask> checker = onceTasks.removeFirst(); - - assertEquals(STD_HEARTBEAT_WAIT_MS, checker.getLeft().longValue()); - - // invoke the task - it should go to the state returned by the mgr - State next = mock(State.class); - when(mgr.goInactive()).thenReturn(next); - - assertEquals(next, checker.getRight().fire()); - - verify(mgr).startDistributing(null); - } - - @Test - public void testStartStatePoolingManager() { - /* - * Prove the state is attached to the manager by invoking getHost(), which - * delegates to the manager. - */ - assertEquals(MY_HOST, state.getHost()); - } - - @Test - public void testStartStateState() { - // create a new state from the current state - state = new StartState(mgr); - - /* - * Prove the state is attached to the manager by invoking getHost(), which - * delegates to the manager. - */ - assertEquals(MY_HOST, state.getHost()); - } - - @Test - public void testProcessHeartbeat() { - Heartbeat msg = new Heartbeat(); - - // no matching data in heart beat - assertNull(state.process(msg)); - verify(mgr, never()).publishAdmin(any()); - - // same source, different time stamp - msg.setSource(MY_HOST); - msg.setTimestampMs(state.getHbTimestampMs() - 1); - assertNull(state.process(msg)); - verify(mgr, never()).publishAdmin(any()); - - // same time stamp, different source - msg.setSource("unknown"); - msg.setTimestampMs(state.getHbTimestampMs()); - assertNull(state.process(msg)); - verify(mgr, never()).publishAdmin(any()); - - // matching heart beat - msg.setSource(MY_HOST); - msg.setTimestampMs(state.getHbTimestampMs()); - - State next = mock(State.class); - when(mgr.goQuery()).thenReturn(next); - - assertEquals(next, state.process(msg)); - - verify(mgr).publishAdmin(any(Query.class)); - } - - @Test - public void testProcessIdentification() { - assertNull(state.process(new Identification(MY_HOST, null))); - } - - @Test - public void testProcessLeader() { - assertNull(state.process(new Leader(MY_HOST, null))); - } - - @Test - public void testProcessOffline() { - assertNull(state.process(new Offline(HOST1))); - } - - @Test - public void testProcessQuery() { - assertNull(state.process(new Query())); - } - - @Test - public void testGetHbTimestampMs() { - long tcurrent = System.currentTimeMillis(); - assertTrue(new StartState(mgr).getHbTimestampMs() >= tcurrent); - - tcurrent = System.currentTimeMillis(); - assertTrue(new StartState(mgr).getHbTimestampMs() >= tcurrent); - } - -} 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 deleted file mode 100644 index 87868a76..00000000 --- a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/state/StateTest.java +++ /dev/null @@ -1,465 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * ONAP - * ================================================================================ - * Copyright (C) 2018, 2020 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ - -package org.onap.policy.drools.pooling.state; - -import static org.assertj.core.api.Assertions.assertThatCode; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import org.junit.Before; -import org.junit.Test; -import org.onap.policy.drools.pooling.CancellableScheduledTask; -import org.onap.policy.drools.pooling.PoolingManager; -import org.onap.policy.drools.pooling.message.BucketAssignments; -import org.onap.policy.drools.pooling.message.Heartbeat; -import org.onap.policy.drools.pooling.message.Identification; -import org.onap.policy.drools.pooling.message.Leader; -import org.onap.policy.drools.pooling.message.Offline; -import org.onap.policy.drools.pooling.message.Query; - -public class StateTest extends SupportBasicStateTester { - - private State state; - - /** - * Setup. - */ - @Before - public void setUp() throws Exception { - super.setUp(); - - state = new MyState(mgr); - } - - @Test - public void testStatePoolingManager() { - /* - * Prove the state is attached to the manager by invoking getHost(), which - * delegates to the manager. - */ - assertEquals(MY_HOST, state.getHost()); - } - - @Test - public void testStateState() { - // allocate a new state, copying from the old state - state = new MyState(mgr); - - /* - * Prove the state is attached to the manager by invoking getHost(), which - * delegates to the manager. - */ - assertEquals(MY_HOST, state.getHost()); - } - - @Test - public void testCancelTimers() { - int delay = 100; - int initDelay = 200; - - /* - * Create three tasks tasks. - */ - - StateTimerTask task1 = mock(StateTimerTask.class); - StateTimerTask task2 = mock(StateTimerTask.class); - StateTimerTask task3 = mock(StateTimerTask.class); - - // two tasks via schedule() - state.schedule(delay, task1); - state.schedule(delay, task2); - - // one task via scheduleWithFixedDelay() - state.scheduleWithFixedDelay(initDelay, delay, task3); - - // ensure all were scheduled, but not yet canceled - verify(mgr).schedule(delay, task1); - verify(mgr).schedule(delay, task2); - verify(mgr).scheduleWithFixedDelay(initDelay, delay, task3); - - CancellableScheduledTask sched1 = onceSchedules.removeFirst(); - CancellableScheduledTask sched2 = onceSchedules.removeFirst(); - CancellableScheduledTask sched3 = repeatedSchedules.removeFirst(); - - verify(sched1, never()).cancel(); - verify(sched2, never()).cancel(); - verify(sched3, never()).cancel(); - - /* - * Cancel the timers. - */ - state.cancelTimers(); - - // verify that all were cancelled - verify(sched1).cancel(); - verify(sched2).cancel(); - verify(sched3).cancel(); - } - - @Test - public void testStart() { - assertThatCode(() -> state.start()).doesNotThrowAnyException(); - } - - @Test - public void testGoStart() { - State next = mock(State.class); - when(mgr.goStart()).thenReturn(next); - - State next2 = state.goStart(); - assertEquals(next, next2); - } - - @Test - public void testGoQuery() { - State next = mock(State.class); - when(mgr.goQuery()).thenReturn(next); - - State next2 = state.goQuery(); - assertEquals(next, next2); - } - - @Test - public void testGoActive_WithAssignment() { - State act = mock(State.class); - State inact = mock(State.class); - - when(mgr.goActive()).thenReturn(act); - when(mgr.goInactive()).thenReturn(inact); - - String[] arr = {HOST2, PREV_HOST, MY_HOST}; - BucketAssignments asgn = new BucketAssignments(arr); - - assertEquals(act, state.goActive(asgn)); - - verify(mgr).startDistributing(asgn); - } - - @Test - public void testGoActive_WithoutAssignment() { - State act = mock(State.class); - State inact = mock(State.class); - - when(mgr.goActive()).thenReturn(act); - when(mgr.goInactive()).thenReturn(inact); - - String[] arr = {HOST2, PREV_HOST}; - BucketAssignments asgn = new BucketAssignments(arr); - - assertEquals(inact, state.goActive(asgn)); - - verify(mgr).startDistributing(asgn); - } - - @Test - public void testGoActive_NullAssignment() { - State act = mock(State.class); - State inact = mock(State.class); - - when(mgr.goActive()).thenReturn(act); - when(mgr.goInactive()).thenReturn(inact); - - assertEquals(inact, state.goActive(null)); - - verify(mgr, never()).startDistributing(any()); - } - - @Test - public void testGoInactive() { - State next = mock(State.class); - when(mgr.goInactive()).thenReturn(next); - - State next2 = state.goInactive(); - assertEquals(next, next2); - } - - @Test - public void testProcessHeartbeat() { - assertNull(state.process(new Heartbeat())); - } - - @Test - public void testProcessIdentification() { - assertNull(state.process(new Identification())); - } - - @Test - public void testProcessLeader() { - String[] arr = {HOST2, HOST1}; - BucketAssignments asgn = new BucketAssignments(arr); - Leader msg = new Leader(HOST1, asgn); - - // should ignore it - assertEquals(null, state.process(msg)); - verify(mgr).startDistributing(asgn); - } - - @Test - public void testProcessLeader_Invalid() { - Leader msg = new Leader(PREV_HOST, null); - - // should stay in the same state, and not start distributing - assertNull(state.process(msg)); - verify(mgr, never()).startDistributing(any()); - verify(mgr, never()).goActive(); - verify(mgr, never()).goInactive(); - } - - @Test - public void testIsValidLeader_NullAssignment() { - assertFalse(state.isValid(new Leader(PREV_HOST, null))); - } - - @Test - public void testIsValidLeader_NullSource() { - String[] arr = {HOST2, PREV_HOST, MY_HOST}; - BucketAssignments asgn = new BucketAssignments(arr); - assertFalse(state.isValid(new Leader(null, asgn))); - } - - @Test - public void testIsValidLeader_EmptyAssignment() { - assertFalse(state.isValid(new Leader(PREV_HOST, new BucketAssignments()))); - } - - @Test - public void testIsValidLeader_FromSelf() { - String[] arr = {HOST2, MY_HOST}; - BucketAssignments asgn = new BucketAssignments(arr); - - assertFalse(state.isValid(new Leader(MY_HOST, asgn))); - } - - @Test - public void testIsValidLeader_WrongLeader() { - String[] arr = {HOST2, HOST3}; - BucketAssignments asgn = new BucketAssignments(arr); - - assertFalse(state.isValid(new Leader(HOST1, asgn))); - } - - @Test - public void testIsValidLeader() { - String[] arr = {HOST2, HOST1}; - BucketAssignments asgn = new BucketAssignments(arr); - - assertTrue(state.isValid(new Leader(HOST1, asgn))); - } - - @Test - public void testProcessOffline() { - assertNull(state.process(new Offline())); - } - - @Test - public void testProcessQuery() { - assertNull(state.process(new Query())); - } - - @Test - public void testPublishIdentification() { - Identification msg = new Identification(); - state.publish(msg); - - verify(mgr).publishAdmin(msg); - } - - @Test - public void testPublishLeader() { - Leader msg = new Leader(); - state.publish(msg); - - verify(mgr).publishAdmin(msg); - } - - @Test - public void testPublishOffline() { - Offline msg = new Offline(); - state.publish(msg); - - verify(mgr).publishAdmin(msg); - } - - @Test - public void testPublishQuery() { - Query msg = new Query(); - state.publish(msg); - - verify(mgr).publishAdmin(msg); - } - - @Test - public void testPublishStringHeartbeat() { - String chnl = "channelH"; - Heartbeat msg = new Heartbeat(); - - state.publish(chnl, msg); - - verify(mgr).publish(chnl, msg); - } - - @Test - public void testStartDistributing() { - BucketAssignments asgn = new BucketAssignments(); - state.startDistributing(asgn); - - verify(mgr).startDistributing(asgn); - } - - @Test - public void testStartDistributing_NullAssignments() { - state.startDistributing(null); - - verify(mgr, never()).startDistributing(any()); - } - - @Test - public void testSchedule() { - int delay = 100; - - StateTimerTask task = mock(StateTimerTask.class); - - state.schedule(delay, task); - - CancellableScheduledTask sched = onceSchedules.removeFirst(); - - // scheduled, but not canceled yet - verify(mgr).schedule(delay, task); - verify(sched, never()).cancel(); - - /* - * Ensure the state added the timer to its list by telling it to cancel its timers - * and then seeing if this timer was canceled. - */ - state.cancelTimers(); - verify(sched).cancel(); - } - - @Test - public void testScheduleWithFixedDelay() { - int initdel = 100; - int delay = 200; - - StateTimerTask task = mock(StateTimerTask.class); - - state.scheduleWithFixedDelay(initdel, delay, task); - - CancellableScheduledTask sched = repeatedSchedules.removeFirst(); - - // scheduled, but not canceled yet - verify(mgr).scheduleWithFixedDelay(initdel, delay, task); - verify(sched, never()).cancel(); - - /* - * Ensure the state added the timer to its list by telling it to cancel its timers - * and then seeing if this timer was canceled. - */ - state.cancelTimers(); - verify(sched).cancel(); - } - - @Test - public void testMissedHeartbeat() { - State next = mock(State.class); - when(mgr.goStart()).thenReturn(next); - - State next2 = state.missedHeartbeat(); - assertEquals(next, next2); - - // should continue to distribute - verify(mgr, never()).startDistributing(null); - - Offline msg = captureAdminMessage(Offline.class); - assertEquals(MY_HOST, msg.getSource()); - } - - @Test - public void testInternalTopicFailed() { - State next = mock(State.class); - when(mgr.goInactive()).thenReturn(next); - - State next2 = state.internalTopicFailed(); - assertEquals(next, next2); - - // should stop distributing - verify(mgr).startDistributing(null); - - Offline msg = captureAdminMessage(Offline.class); - assertEquals(MY_HOST, msg.getSource()); - } - - @Test - public void testMakeHeartbeat() { - long timestamp = 30000L; - Heartbeat msg = state.makeHeartbeat(timestamp); - - assertEquals(MY_HOST, msg.getSource()); - assertEquals(timestamp, msg.getTimestampMs()); - } - - @Test - public void testMakeIdentification() { - Identification ident = state.makeIdentification(); - assertEquals(MY_HOST, ident.getSource()); - assertEquals(ASGN3, ident.getAssignments()); - } - - @Test - public void testMakeOffline() { - Offline msg = state.makeOffline(); - - assertEquals(MY_HOST, msg.getSource()); - } - - @Test - public void testMakeQuery() { - Query msg = state.makeQuery(); - - assertEquals(MY_HOST, msg.getSource()); - } - - @Test - public void testGetHost() { - assertEquals(MY_HOST, state.getHost()); - } - - @Test - public void testGetTopic() { - assertEquals(MY_TOPIC, state.getTopic()); - } - - /** - * State used for testing purposes, with abstract methods implemented. - */ - private class MyState extends State { - - public MyState(PoolingManager mgr) { - super(mgr); - } - } -} 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 deleted file mode 100644 index 18d77ba7..00000000 --- a/feature-pooling-dmaap/src/test/java/org/onap/policy/drools/pooling/state/SupportBasicStateTester.java +++ /dev/null @@ -1,282 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * ONAP - * ================================================================================ - * Copyright (C) 2018, 2020 AT&T Intellectual Property. All rights reserved. - * Modifications Copyright (C) 2020 Nordix Foundation - * ================================================================================ - * 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.SortedSet; -import java.util.TreeSet; -import java.util.concurrent.atomic.AtomicReference; -import org.apache.commons.lang3.tuple.Pair; -import org.apache.commons.lang3.tuple.Triple; -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; - -/** - * 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<CancellableScheduledTask> onceSchedules; - - /** - * Tasks captured via schedule(). - */ - protected LinkedList<Pair<Long, StateTimerTask>> onceTasks; - - /** - * Scheduled tasks returned by scheduleWithFixedDelay(). - */ - protected LinkedList<CancellableScheduledTask> repeatedSchedules; - - /** - * Tasks captured via scheduleWithFixedDelay(). - */ - protected LinkedList<Triple<Long, Long, StateTimerTask>> repeatedTasks; - - /** - * Messages captured via publish(). - */ - protected LinkedList<Pair<String, Message>> published; - - /** - * Messages captured via publishAdmin(). - */ - protected LinkedList<Message> 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) {}; - - // capture publish() arguments - doAnswer(invocation -> { - Object[] args = invocation.getArguments(); - published.add(Pair.of((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(Pair.of((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(Triple.of((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<BucketAssignments> 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<String> 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<String> 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 extends Message> T captureAdminMessage(Class<T> 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 extends Message> T captureAdminMessage(Class<T> 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 <T extends Message> Pair<String, T> capturePublishedMessage(Class<T> 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 <T extends Message> Pair<String, T> capturePublishedMessage(Class<T> clazz, int index) { - Pair<String, Message> msg = published.get(index); - return Pair.of(msg.getLeft(), clazz.cast(msg.getRight())); - } -} diff --git a/feature-pooling-dmaap/src/test/resources/logback-test.xml b/feature-pooling-dmaap/src/test/resources/logback-test.xml deleted file mode 100644 index 45d8201d..00000000 --- a/feature-pooling-dmaap/src/test/resources/logback-test.xml +++ /dev/null @@ -1,36 +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========================================================= - --> -<configuration> - - <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> - <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> - <Pattern> - %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%M\(%line\) - %msg%n - </Pattern> - </encoder> - </appender> - - <logger name="org.onap.policy.drools.http.server.test" level="INFO"/> - - <root level="WARN"> - <appender-ref ref="STDOUT"/> - </root> - -</configuration>
\ No newline at end of file |