Increase code coverage in policy-management 18/138918/4
authoradheli.tavares <adheli.tavares@est.tech>
Tue, 10 Sep 2024 08:17:27 +0000 (09:17 +0100)
committeradheli.tavares <adheli.tavares@est.tech>
Thu, 12 Sep 2024 10:42:16 +0000 (11:42 +0100)
Issue-ID: POLICY-5068
Change-Id: Ie7ac44a948fe559306b1aa3a403d888c352be7f2
Signed-off-by: adheli.tavares <adheli.tavares@est.tech>
28 files changed:
policy-management/src/main/java/org/onap/policy/drools/controller/IndexedDroolsControllerFactory.java
policy-management/src/main/java/org/onap/policy/drools/controller/internal/MavenDroolsController.java
policy-management/src/main/java/org/onap/policy/drools/features/PolicyControllerFeatureApi.java
policy-management/src/main/java/org/onap/policy/drools/persistence/FileSystemPersistence.java
policy-management/src/main/java/org/onap/policy/drools/protocol/coders/EventProtocolCoder.java
policy-management/src/main/java/org/onap/policy/drools/protocol/coders/GenericEventProtocolCoder.java
policy-management/src/main/java/org/onap/policy/drools/protocol/coders/GsonProtocolCoderToolset.java
policy-management/src/main/java/org/onap/policy/drools/protocol/coders/MultiplexorEventProtocolCoder.java
policy-management/src/main/java/org/onap/policy/drools/protocol/coders/ProtocolCoderToolset.java
policy-management/src/main/java/org/onap/policy/drools/protocol/coders/TopicCoderFilterConfiguration.java
policy-management/src/test/java/org/onap/policy/drools/controller/IndexedDroolsControllerFactoryTest.java [new file with mode: 0644]
policy-management/src/test/java/org/onap/policy/drools/controller/internal/MavenDroolsControllerUpgradesTest.java
policy-management/src/test/java/org/onap/policy/drools/features/DroolsControllerFeatureApiTest.java [new file with mode: 0644]
policy-management/src/test/java/org/onap/policy/drools/features/PolicyControllerFeatureApiTest.java [new file with mode: 0644]
policy-management/src/test/java/org/onap/policy/drools/features/PolicyEngineFeatureApiTest.java [new file with mode: 0644]
policy-management/src/test/java/org/onap/policy/drools/persistence/FileSystemPersistenceTest.java [new file with mode: 0644]
policy-management/src/test/java/org/onap/policy/drools/protocol/coders/EventProtocolCoderTest.java
policy-management/src/test/java/org/onap/policy/drools/protocol/coders/GenericProtocolCoderTest.java [new file with mode: 0644]
policy-management/src/test/java/org/onap/policy/drools/protocol/coders/GsonProtocolCoderToolsetTest.java [new file with mode: 0644]
policy-management/src/test/java/org/onap/policy/drools/protocol/coders/MultiplexorEventProtocolCoderTest.java [new file with mode: 0644]
policy-management/src/test/java/org/onap/policy/drools/protocol/coders/ProtocolCoderToolsetTest.java
policy-management/src/test/java/org/onap/policy/drools/protocol/coders/TopicCoderFilterConfigurationTest.java [new file with mode: 0644]
policy-management/src/test/java/org/onap/policy/drools/server/restful/test/RestManagerTest.java
policy-management/src/test/java/org/onap/policy/drools/stats/PolicyStatsManagerTest.java
policy-management/src/test/java/org/onap/policy/drools/stats/PolicyStatsTest.java
policy-management/src/test/java/org/onap/policy/drools/system/PolicyControllerFactoryTest.java
policy-management/src/test/java/org/onap/policy/drools/system/PolicyEngineManagerTest.java
policy-management/src/test/java/org/onap/policy/drools/system/internal/FeatureLockImplTest.java

index 7f28f9b..a6459d6 100644 (file)
@@ -28,6 +28,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 import lombok.NonNull;
+import org.apache.commons.lang3.StringUtils;
 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.TopicSink;
@@ -62,7 +63,7 @@ class IndexedDroolsControllerFactory implements DroolsControllerFactory {
     /**
      * Null Drools Controller.
      */
-    protected NullDroolsController nullDroolsController = new NullDroolsController();
+    protected NullDroolsController nullDroolsController;
 
     /**
      * Constructs the object.
@@ -71,11 +72,11 @@ class IndexedDroolsControllerFactory implements DroolsControllerFactory {
 
         /* Add a NULL controller which will always be present in the hash */
 
-        DroolsController controller = new NullDroolsController();
-        String controllerId = controller.getGroupId() + ":" + controller.getArtifactId();
+        nullDroolsController = new NullDroolsController();
+        String controllerId = nullDroolsController.getGroupId() + ":" + nullDroolsController.getArtifactId();
 
         synchronized (this) {
-            droolsControllers.put(controllerId, controller);
+            droolsControllers.put(controllerId, nullDroolsController);
         }
     }
 
@@ -84,17 +85,17 @@ class IndexedDroolsControllerFactory implements DroolsControllerFactory {
             List<? extends TopicSink> eventSinks) throws LinkageError {
 
         String groupId = properties.getProperty(DroolsPropertyConstants.RULES_GROUPID);
-        if (groupId == null || groupId.isEmpty()) {
+        if (StringUtils.isBlank(groupId)) {
             groupId = DroolsControllerConstants.NO_GROUP_ID;
         }
 
         String artifactId = properties.getProperty(DroolsPropertyConstants.RULES_ARTIFACTID);
-        if (artifactId == null || artifactId.isEmpty()) {
+        if (StringUtils.isBlank(artifactId)) {
             artifactId = DroolsControllerConstants.NO_ARTIFACT_ID;
         }
 
         String version = properties.getProperty(DroolsPropertyConstants.RULES_VERSION);
-        if (version == null || version.isEmpty()) {
+        if (StringUtils.isBlank(version)) {
             version = DroolsControllerConstants.NO_VERSION;
         }
 
@@ -110,15 +111,15 @@ class IndexedDroolsControllerFactory implements DroolsControllerFactory {
             List<TopicCoderFilterConfiguration> decoderConfigurations,
             List<TopicCoderFilterConfiguration> encoderConfigurations) throws LinkageError {
 
-        if (newGroupId == null || newGroupId.isEmpty()) {
+        if (StringUtils.isBlank(newGroupId)) {
             throw new IllegalArgumentException("Missing maven group-id coordinate");
         }
 
-        if (newArtifactId == null || newArtifactId.isEmpty()) {
+        if (StringUtils.isBlank(newArtifactId)) {
             throw new IllegalArgumentException("Missing maven artifact-id coordinate");
         }
 
-        if (newVersion == null || newVersion.isEmpty()) {
+        if (StringUtils.isBlank(newVersion)) {
             throw new IllegalArgumentException("Missing maven version coordinate");
         }
 
@@ -240,7 +241,7 @@ class IndexedDroolsControllerFactory implements DroolsControllerFactory {
             String eventClasses = properties
                     .getProperty(propertyTopicEntityPrefix + PolicyEndPointProperties.PROPERTY_TOPIC_EVENTS_SUFFIX);
 
-            if (eventClasses == null || eventClasses.isEmpty()) {
+            if (StringUtils.isBlank(eventClasses)) {
                 logger.warn("There are no event classes for topic {}", firstTopic);
                 continue;
             }
@@ -280,7 +281,7 @@ class IndexedDroolsControllerFactory implements DroolsControllerFactory {
                 + PolicyEndPointProperties.PROPERTY_TOPIC_EVENTS_CUSTOM_MODEL_CODER_GSON_SUFFIX);
 
         CustomGsonCoder customGsonCoder = null;
-        if (customGson != null && !customGson.isEmpty()) {
+        if (StringUtils.isNotBlank(customGson)) {
             try {
                 customGsonCoder = new CustomGsonCoder(customGson);
             } catch (IllegalArgumentException e) {
@@ -375,7 +376,7 @@ class IndexedDroolsControllerFactory implements DroolsControllerFactory {
     @Override
     public DroolsController get(String groupId, String artifactId, String version) {
 
-        if (groupId == null || artifactId == null || groupId.isEmpty() || artifactId.isEmpty()) {
+        if (StringUtils.isBlank(groupId) || StringUtils.isBlank(artifactId)) {
             throw new IllegalArgumentException("Missing maven coordinates: " + groupId + ":" + artifactId);
         }
 
index 68a6915..aa701df 100644 (file)
@@ -3,7 +3,7 @@
  * ONAP
  * ================================================================================
  * Copyright (C) 2017-2021 AT&T Intellectual Property. All rights reserved.
- * Modifications Copyright (C) 2023 Nordix Foundation.
+ * Modifications Copyright (C) 2023-2024 Nordix Foundation.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -31,6 +31,7 @@ import java.util.stream.Collectors;
 import lombok.Getter;
 import lombok.NonNull;
 import org.apache.commons.collections4.queue.CircularFifoQueue;
+import org.apache.commons.lang3.StringUtils;
 import org.drools.core.ClassObjectFilter;
 import org.kie.api.definition.KiePackage;
 import org.kie.api.definition.rule.Query;
@@ -219,7 +220,7 @@ public class MavenDroolsController implements DroolsController {
     }
 
     private void validateText(String text, String errorMessage) {
-        if (text == null || text.isEmpty()) {
+        if (StringUtils.isBlank(text)) {
             throw new IllegalArgumentException(errorMessage);
         }
     }
index f022bf1..15b48a5 100644 (file)
@@ -3,6 +3,7 @@
  * ONAP
  * ================================================================================
  * Copyright (C) 2017-2020 AT&T Intellectual Property. All rights reserved.
+ * Modifications Copyright (C) 2024 Nordix Foundation.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -32,7 +33,7 @@ public interface PolicyControllerFeatureApi extends OrderedService {
      * called before creating a controller with name 'name' and
      * properties 'properties'.
      *
-     * @param name name of the the controller
+     * @param name name of the controller
      * @param properties configuration properties
      *
      * @return a policy controller.   A take over of the creation operation
index 9fb76d8..717a6f5 100644 (file)
@@ -35,6 +35,7 @@ import java.util.List;
 import java.util.Properties;
 import java.util.function.BiPredicate;
 import lombok.Getter;
+import lombok.NonNull;
 import lombok.ToString;
 import org.onap.policy.drools.properties.DroolsPropertyConstants;
 import org.onap.policy.drools.utils.PropertyUtil;
@@ -151,7 +152,7 @@ public class FileSystemPersistence implements SystemPersistence {
         }
     }
 
-    protected Properties getProperties(Path propertiesPath) {
+    protected Properties getProperties(@NonNull Path propertiesPath) {
         if (!Files.exists(propertiesPath)) {
             throw new IllegalArgumentException("properties for " + propertiesPath + " are not persisted.");
         }
index 88b2525..7cfa5a3 100644 (file)
@@ -4,6 +4,7 @@
  * ================================================================================
  * Copyright (C) 2017-2019,2022 AT&T Intellectual Property. All rights reserved.
  * Modifications Copyright(C) 2018 Samsung Electronics Co., Ltd.
+ * Modifications Copyright (C) 2024 Nordix Foundation.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -35,7 +36,7 @@ public interface EventProtocolCoder {
     @Getter
     @Setter
     @AllArgsConstructor
-    public static class CoderFilters {
+    class CoderFilters {
 
         /**
          * coder class.
@@ -54,13 +55,9 @@ public interface EventProtocolCoder {
 
         @Override
         public String toString() {
-            return "CoderFilters [factClass="
-                           + factClass
-                           + ", filter="
-                           + filter
-                           + ", modelClassLoaderHash="
-                           + modelClassLoaderHash
-                           + "]";
+            return "CoderFilters [factClass=" + factClass
+                + ", filter=" + filter
+                + ", modelClassLoaderHash=" + modelClassLoaderHash + "]";
         }
     }
 
index 0729c70..6fe1648 100644 (file)
@@ -3,6 +3,7 @@
  * ONAP
  * ================================================================================
  * Copyright (C) 2019-2020, 2021 AT&T Intellectual Property. All rights reserved.
+ * Modifications Copyright (C) 2024 Nordix Foundation.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 package org.onap.policy.drools.protocol.coders;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
 import org.onap.policy.drools.controller.DroolsController;
 import org.onap.policy.drools.controller.DroolsControllerConstants;
 import org.onap.policy.drools.protocol.coders.EventProtocolCoder.CoderFilters;
+import org.onap.policy.drools.system.PolicyDroolsPdpRuntimeException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -43,7 +48,7 @@ abstract class GenericEventProtocolCoder {
     private static final String INVALID_GROUP_ID_MSG = "Invalid group id";
     private static final String INVALID_TOPIC_MSG = "Invalid Topic";
     private static final String UNSUPPORTED_MSG = "Unsupported";
-    private static final String UNSUPPORTED_EX_MSG = "Unsupported:";
+    private static final String UNSUPPORTED_EX_MSG = "Unsupported: ";
     private static final String MISSING_CLASS = "class must be provided";
 
     private static final Logger logger = LoggerFactory.getLogger(GenericEventProtocolCoder.class);
@@ -52,37 +57,26 @@ abstract class GenericEventProtocolCoder {
      * Mapping topic:controller-id -> /<protocol-decoder-toolset/> where protocol-coder-toolset contains
      * a gson-protocol-coder-toolset.
      */
-    protected final HashMap<String, ProtocolCoderToolset> coders =
-            new HashMap<>();
+    protected final HashMap<String, ProtocolCoderToolset> coders = new HashMap<>();
 
     /**
      * Mapping topic + classname -> Protocol Set.
      */
-    protected final HashMap<String, List<ProtocolCoderToolset>>
-            reverseCoders = new HashMap<>();
+    protected final HashMap<String, List<ProtocolCoderToolset>> reverseCoders = new HashMap<>();
 
     /**
      * Index a new coder.
      */
     public void add(EventProtocolParams eventProtocolParams) {
-        if (eventProtocolParams.getGroupId() == null || eventProtocolParams.getGroupId().isEmpty()) {
-            throw new IllegalArgumentException(INVALID_GROUP_ID_MSG);
-        }
 
-        if (eventProtocolParams.getArtifactId() == null || eventProtocolParams.getArtifactId().isEmpty()) {
-            throw new IllegalArgumentException(INVALID_ARTIFACT_ID_MSG);
-        }
+        validateKeyParameters(eventProtocolParams.getGroupId(),
+            eventProtocolParams.getArtifactId(),
+            eventProtocolParams.getTopic());
 
-        if (eventProtocolParams.getTopic() == null || eventProtocolParams.getTopic().isEmpty()) {
-            throw new IllegalArgumentException(INVALID_TOPIC_MSG);
-        }
-
-        if (eventProtocolParams.getEventClass() == null) {
-            throw new IllegalArgumentException("Invalid Event Class");
-        }
+        validateStringParameter(eventProtocolParams.getEventClass(), "Invalid Event Class");
 
         String key = this.codersKey(eventProtocolParams.getGroupId(), eventProtocolParams.getArtifactId(),
-                eventProtocolParams.getTopic());
+            eventProtocolParams.getTopic());
         String reverseKey = this.reverseCodersKey(eventProtocolParams.getTopic(), eventProtocolParams.getEventClass());
 
         synchronized (this) {
@@ -91,22 +85,16 @@ abstract class GenericEventProtocolCoder {
 
                 logger.info("{}: adding coders for existing {}: {}", this, key, toolset);
 
-                toolset
-                        .addCoder(
-                                eventProtocolParams.getEventClass(),
-                                eventProtocolParams.getProtocolFilter(),
-                                eventProtocolParams.getModelClassLoaderHash());
+                toolset.addCoder(
+                    eventProtocolParams.getEventClass(),
+                    eventProtocolParams.getProtocolFilter(),
+                    eventProtocolParams.getModelClassLoaderHash());
 
                 if (!reverseCoders.containsKey(reverseKey)) {
-                    logger.info(
-                            "{}: adding new reverse coders (multiple classes case) for {}:{}: {}",
-                            this,
-                            reverseKey,
-                            key,
-                            toolset);
-
-                    List<ProtocolCoderToolset> reverseMappings =
-                            new ArrayList<>();
+                    logger.info("{}: adding new reverse coders (multiple classes case) for {}:{}: {}",
+                        this, reverseKey, key, toolset);
+
+                    List<ProtocolCoderToolset> reverseMappings = new ArrayList<>();
                     reverseMappings.add(toolset);
                     reverseCoders.put(reverseKey, reverseMappings);
                 }
@@ -128,20 +116,15 @@ abstract class GenericEventProtocolCoder {
             // There is another controller (different group id/artifact id/topic)
             // that shares the class and the topic.
 
-            List<ProtocolCoderToolset> toolsets =
-                    reverseCoders.get(reverseKey);
+            List<ProtocolCoderToolset> toolsets = reverseCoders.get(reverseKey);
             var present = false;
             for (ProtocolCoderToolset parserSet : toolsets) {
-                // just doublecheck
+                // just double check
                 present = parserSet.getControllerId().equals(key);
                 if (present) {
                     /* anomaly */
-                    logger.error(
-                            "{}: unexpected toolset reverse mapping found for {}:{}: {}",
-                            this,
-                            reverseKey,
-                            key,
-                            parserSet);
+                    logger.error("{}: unexpected toolset reverse mapping found for {}:{}: {}",
+                        this, reverseKey, key, parserSet);
                 }
             }
 
@@ -191,17 +174,7 @@ abstract class GenericEventProtocolCoder {
      */
     public void remove(String groupId, String artifactId, String topic) {
 
-        if (groupId == null || groupId.isEmpty()) {
-            throw new IllegalArgumentException(INVALID_GROUP_ID_MSG);
-        }
-
-        if (artifactId == null || artifactId.isEmpty()) {
-            throw new IllegalArgumentException(INVALID_ARTIFACT_ID_MSG);
-        }
-
-        if (topic == null || topic.isEmpty()) {
-            throw new IllegalArgumentException(INVALID_TOPIC_MSG);
-        }
+        validateKeyParameters(groupId, artifactId, topic);
 
         String key = this.codersKey(groupId, artifactId, topic);
 
@@ -225,23 +198,23 @@ abstract class GenericEventProtocolCoder {
             return;
         }
 
-        List<ProtocolCoderToolset> toolsets =
-                this.reverseCoders.get(reverseKey);
-        Iterator<ProtocolCoderToolset> toolsetsIter =
-                toolsets.iterator();
+        List<ProtocolCoderToolset> toolsets = this.reverseCoders.getOrDefault(reverseKey, Collections.emptyList());
+
+        if (toolsets.isEmpty()) {
+            logger.info("{}: removing reverse mapping for {}: ", this, reverseKey);
+            this.reverseCoders.remove(reverseKey);
+            return;
+        }
+
+        Iterator<ProtocolCoderToolset> toolsetsIter = toolsets.iterator();
+
         while (toolsetsIter.hasNext()) {
             ProtocolCoderToolset toolset = toolsetsIter.next();
             if (toolset.getControllerId().equals(key)) {
-                logger.info(
-                        "{}: removed coder from toolset for {} from reverse mapping", this, reverseKey);
+                logger.info("{}: removed coder from toolset for {} from reverse mapping", this, reverseKey);
                 toolsetsIter.remove();
             }
         }
-
-        if (this.reverseCoders.get(reverseKey).isEmpty()) {
-            logger.info("{}: removing reverse mapping for {}: ", this, reverseKey);
-            this.reverseCoders.remove(reverseKey);
-        }
     }
 
     /**
@@ -250,23 +223,14 @@ abstract class GenericEventProtocolCoder {
      * @param groupId    group id
      * @param artifactId artifact id
      * @param topic      topic
-     * @return true if its is codable
+     * @return true if it's supported to be coded
      */
     public boolean isCodingSupported(String groupId, String artifactId, String topic) {
 
-        if (groupId == null || groupId.isEmpty()) {
-            throw new IllegalArgumentException(INVALID_GROUP_ID_MSG);
-        }
-
-        if (artifactId == null || artifactId.isEmpty()) {
-            throw new IllegalArgumentException(INVALID_ARTIFACT_ID_MSG);
-        }
-
-        if (topic == null || topic.isEmpty()) {
-            throw new IllegalArgumentException(INVALID_TOPIC_MSG);
-        }
+        validateKeyParameters(groupId, artifactId, topic);
 
         String key = this.codersKey(groupId, artifactId, topic);
+
         synchronized (this) {
             return coders.containsKey(key);
         }
@@ -280,14 +244,14 @@ abstract class GenericEventProtocolCoder {
      * @param topic      topic
      * @param json       json string to convert to object
      * @return the decoded object
-     * @throws IllegalArgumentException      if invalid argument is provided
-     * @throws UnsupportedOperationException if the operation cannot be performed
+     * @throws IllegalArgumentException        if invalid argument is provided
+     * @throws PolicyDroolsPdpRuntimeException if the operation cannot be performed
      */
     public Object decode(String groupId, String artifactId, String topic, String json) {
 
         if (!isCodingSupported(groupId, artifactId, topic)) {
             throw new IllegalArgumentException(
-                    UNSUPPORTED_EX_MSG + codersKey(groupId, artifactId, topic) + " for encoding");
+                UNSUPPORTED_EX_MSG + codersKey(groupId, artifactId, topic) + " for encoding");
         }
 
         String key = this.codersKey(groupId, artifactId, topic);
@@ -321,9 +285,7 @@ abstract class GenericEventProtocolCoder {
             throw new IllegalArgumentException(UNSUPPORTED_EX_MSG + codersKey(groupId, artifactId, topic));
         }
 
-        if (event == null) {
-            throw new IllegalArgumentException("Unsupported topic:" + topic);
-        }
+        validateObjectParameter(event, "Event cannot be null or empty");
 
         // reuse the decoder set, since there must be affinity in the model
         String key = this.codersKey(groupId, artifactId, topic);
@@ -341,25 +303,18 @@ abstract class GenericEventProtocolCoder {
      */
     public String encode(String topic, Object event) {
 
-        if (event == null) {
-            throw new IllegalArgumentException("Invalid encoded class");
-        }
+        validateObjectParameter(event, "Event cannot be null or empty");
 
-        if (topic == null || topic.isEmpty()) {
-            throw new IllegalArgumentException("Invalid topic");
-        }
+        validateStringParameter(topic, INVALID_TOPIC_MSG);
 
         String reverseKey = this.reverseCodersKey(topic, event.getClass().getName());
         if (!this.reverseCoders.containsKey(reverseKey)) {
             throw new IllegalArgumentException("no reverse coder has been found");
         }
 
-        List<ProtocolCoderToolset> toolsets =
-                this.reverseCoders.get(reverseKey);
+        List<ProtocolCoderToolset> toolsets = this.reverseCoders.get(reverseKey);
 
-        String key =
-                codersKey(
-                        toolsets.get(0).getGroupId(), toolsets.get(0).getArtifactId(), topic);
+        String key = codersKey(toolsets.get(0).getGroupId(), toolsets.get(0).getArtifactId(), topic);
         return this.encodeInternal(key, event);
     }
 
@@ -374,13 +329,9 @@ abstract class GenericEventProtocolCoder {
      */
     public String encode(String topic, Object encodedClass, DroolsController droolsController) {
 
-        if (encodedClass == null) {
-            throw new IllegalArgumentException("Invalid encoded class");
-        }
+        validateObjectParameter(encodedClass, "Invalid encoded class");
 
-        if (topic == null || topic.isEmpty()) {
-            throw new IllegalArgumentException("Invalid topic");
-        }
+        validateStringParameter(topic, INVALID_TOPIC_MSG);
 
         String key = codersKey(droolsController.getGroupId(), droolsController.getArtifactId(), topic);
         return this.encodeInternal(key, encodedClass);
@@ -397,31 +348,19 @@ abstract class GenericEventProtocolCoder {
      */
     protected String encodeInternal(String key, Object event) {
 
-        logger.debug("{}: encode for {}: {}", this, key, event);    // NOSONAR
-
-        /*
-         * It seems that sonar declares the previous logging line as a security vulnerability
-         * when logging the topic variable.   The static code analysis indicates that
-         * the path starts in org.onap.policy.drools.server.restful.RestManager::decode(),
-         * but the request is rejected if the topic contains invalid characters (the sonar description
-         * mentions "/r/n/t" characters) all of which are validated against in the checkValidNameInput(topic).
-         * Furthermore production instances are assumed not to have debug enabled, nor the REST telemetry API
-         * should be published externally.  An additional note is that Path URLs containing spaces and newlines
-         * will be rejected earlier in the HTTP protocol libraries (jetty) so an URL of the form
-         * "https://../to\npic" won't even make it here.
-         */
+        logger.debug("{}: encode for {}: {}", this, key, event);
 
         ProtocolCoderToolset coderTools = coders.get(key);
         try {
             String json = coderTools.encode(event);
-            if (json != null && !json.isEmpty()) {
+            if (!StringUtils.isBlank(json)) {
                 return json;
             }
         } catch (Exception e) {
             logger.warn("{}: cannot encode (first) for {}: {}", this, key, event, e);
         }
 
-        throw new UnsupportedOperationException("Cannot decode with gson");
+        throw new UnsupportedOperationException("Cannot encode with gson");
     }
 
     /**
@@ -443,50 +382,37 @@ abstract class GenericEventProtocolCoder {
             return droolsControllers;
         }
 
-        List<ProtocolCoderToolset> toolsets =
-                this.reverseCoders.get(reverseKey);
+        List<ProtocolCoderToolset> toolsets = this.reverseCoders.getOrDefault(reverseKey, Collections.emptyList());
 
         // There must be multiple toolsets associated with <topic,classname> reverseKey
         // case 2 different controllers use the same models and register the same encoder for
         // the same topic.  This is assumed not to occur often but for the purpose of encoding
-        // but there should be no side-effects.  Ownership is crosscheck against classname and
+        // but there should be no side effects.  Ownership is crosscheck against classname and
         // classloader reference.
 
-        if (toolsets == null || toolsets.isEmpty()) {
-            throw new IllegalStateException(
-                    "No Encoders toolsets available for topic "
-                            + topic
-                            + " encoder "
-                            + encodedClass.getClass().getName());
-        }
-
         for (ProtocolCoderToolset encoderSet : toolsets) {
             addToolsetControllers(droolsControllers, encodedClass, encoderSet);
         }
 
         if (droolsControllers.isEmpty()) {
-            throw new IllegalStateException(
-                    "No Encoders toolsets available for "
-                            + topic
-                            + ":"
-                            + encodedClass.getClass().getName());
+            throw new IllegalStateException("No Encoders toolsets available for " + topic + ":"
+                + encodedClass.getClass().getName());
         }
 
         return droolsControllers;
     }
 
     private void addToolsetControllers(List<DroolsController> droolsControllers, Object encodedClass,
-                    ProtocolCoderToolset encoderSet) {
+                                       ProtocolCoderToolset encoderSet) {
         // figure out the right toolset
         String groupId = encoderSet.getGroupId();
         String artifactId = encoderSet.getArtifactId();
         List<CoderFilters> coderFilters = encoderSet.getCoders();
         for (CoderFilters coder : coderFilters) {
             if (coder.getFactClass().equals(encodedClass.getClass().getName())) {
-                var droolsController =
-                                DroolsControllerConstants.getFactory().get(groupId, artifactId, "");
+                var droolsController = DroolsControllerConstants.getFactory().get(groupId, artifactId, "");
                 if (droolsController.ownsCoder(
-                        encodedClass.getClass(), coder.getModelClassLoaderHash())) {
+                    encodedClass.getClass(), coder.getModelClassLoaderHash())) {
                     droolsControllers.add(droolsController);
                 }
             }
@@ -523,19 +449,13 @@ abstract class GenericEventProtocolCoder {
      */
     public List<CoderFilters> getFilters(String groupId, String artifactId) {
 
-        if (groupId == null || groupId.isEmpty()) {
-            throw new IllegalArgumentException(INVALID_GROUP_ID_MSG);
-        }
-
-        if (artifactId == null || artifactId.isEmpty()) {
-            throw new IllegalArgumentException(INVALID_ARTIFACT_ID_MSG);
-        }
+        validateStringParameter(groupId, INVALID_GROUP_ID_MSG);
+        validateStringParameter(artifactId, INVALID_ARTIFACT_ID_MSG);
 
         String key = this.codersKey(groupId, artifactId, "");
 
         List<CoderFilters> codersFilters = new ArrayList<>();
-        for (Map.Entry<String, ProtocolCoderToolset> entry :
-                coders.entrySet()) {
+        for (Map.Entry<String, ProtocolCoderToolset> entry : coders.entrySet()) {
             if (entry.getKey().startsWith(key)) {
                 codersFilters.addAll(entry.getValue().getCoders());
             }
@@ -555,15 +475,13 @@ abstract class GenericEventProtocolCoder {
      * @throws IllegalArgumentException if invalid input
      */
     public CoderFilters getFilters(
-            String groupId, String artifactId, String topic, String classname) {
+        String groupId, String artifactId, String topic, String classname) {
 
         if (!isCodingSupported(groupId, artifactId, topic)) {
             throw new IllegalArgumentException(UNSUPPORTED_EX_MSG + codersKey(groupId, artifactId, topic));
         }
 
-        if (classname == null || classname.isEmpty()) {
-            throw new IllegalArgumentException("classname must be provided");
-        }
+        validateStringParameter(classname, "classname must be provided");
 
         String key = this.codersKey(groupId, artifactId, topic);
         ProtocolCoderToolset coderTools = coders.get(key);
@@ -580,7 +498,7 @@ abstract class GenericEventProtocolCoder {
      * @throws IllegalArgumentException if invalid input
      */
     public ProtocolCoderToolset getCoders(
-            String groupId, String artifactId, String topic) {
+        String groupId, String artifactId, String topic) {
 
         if (!isCodingSupported(groupId, artifactId, topic)) {
             throw new IllegalArgumentException(UNSUPPORTED_EX_MSG + codersKey(groupId, artifactId, topic));
@@ -598,22 +516,16 @@ abstract class GenericEventProtocolCoder {
      * @return list of coders
      * @throws IllegalArgumentException if invalid input
      */
-    public List<ProtocolCoderToolset> getCoders(
-            String groupId, String artifactId) {
+    public List<ProtocolCoderToolset> getCoders(String groupId, String artifactId) {
 
-        if (groupId == null || groupId.isEmpty()) {
-            throw new IllegalArgumentException(INVALID_GROUP_ID_MSG);
-        }
+        validateStringParameter(groupId, INVALID_GROUP_ID_MSG);
 
-        if (artifactId == null || artifactId.isEmpty()) {
-            throw new IllegalArgumentException(INVALID_ARTIFACT_ID_MSG);
-        }
+        validateStringParameter(artifactId, INVALID_ARTIFACT_ID_MSG);
 
         String key = this.codersKey(groupId, artifactId, "");
 
         List<ProtocolCoderToolset> coderToolset = new ArrayList<>();
-        for (Map.Entry<String, ProtocolCoderToolset> entry :
-                coders.entrySet()) {
+        for (Map.Entry<String, ProtocolCoderToolset> entry : coders.entrySet()) {
             if (entry.getKey().startsWith(key)) {
                 coderToolset.add(entry.getValue());
             }
@@ -631,19 +543,12 @@ abstract class GenericEventProtocolCoder {
      */
     public List<CoderFilters> getReverseFilters(String topic, String codedClass) {
 
-        if (topic == null || topic.isEmpty()) {
-            throw new IllegalArgumentException(UNSUPPORTED_MSG);
-        }
+        validateStringParameter(topic, INVALID_TOPIC_MSG);
 
-        if (codedClass == null) {
-            throw new IllegalArgumentException(MISSING_CLASS);
-        }
+        validateStringParameter(codedClass, MISSING_CLASS);
 
         String key = this.reverseCodersKey(topic, codedClass);
-        List<ProtocolCoderToolset> toolsets = this.reverseCoders.get(key);
-        if (toolsets == null) {
-            throw new IllegalArgumentException("No Coder found for " + key);
-        }
+        List<ProtocolCoderToolset> toolsets = this.reverseCoders.getOrDefault(key, Collections.emptyList());
 
         List<CoderFilters> coderFilters = new ArrayList<>();
         for (ProtocolCoderToolset toolset : toolsets) {
@@ -656,79 +561,70 @@ abstract class GenericEventProtocolCoder {
     /**
      * returns group and artifact id of the creator of the encoder.
      *
-     * @param topic topic
-     * @param fact  fact
+     * @param topic        topic
+     * @param encodedClass class encoder
      * @return the drools controller
      */
-    DroolsController getDroolsController(String topic, Object fact) {
-
-        if (topic == null || topic.isEmpty()) {
-            throw new IllegalArgumentException(UNSUPPORTED_MSG);
-        }
-
-        if (fact == null) {
-            throw new IllegalArgumentException(MISSING_CLASS);
-        }
-
-        List<DroolsController> droolsControllers = droolsCreators(topic, fact);
+    DroolsController getDroolsController(String topic, Object encodedClass) {
+        List<DroolsController> droolsControllers = getDroolsControllers(topic, encodedClass);
 
         if (droolsControllers.isEmpty()) {
-            throw new IllegalArgumentException("Invalid Topic: " + topic);
+            throw new IllegalArgumentException(UNSUPPORTED_MSG + " topic " + topic
+                + " and encodedClass " + encodedClass.getClass());
         }
 
-        if (droolsControllers.size() > 1) {
-            logger.warn(
-                    "{}: multiple drools-controller {} for {}:{} ",
-                    this,
-                    droolsControllers,
-                    topic,
-                    fact.getClass().getName());
-            // continue
-        }
         return droolsControllers.get(0);
     }
 
     /**
      * returns group and artifact id of the creator of the encoder.
      *
-     * @param topic topic
-     * @param fact  fact
+     * @param topic        topic
+     * @param encodedClass class encoder
      * @return list of drools controllers
      */
-    List<DroolsController> getDroolsControllers(String topic, Object fact) {
+    List<DroolsController> getDroolsControllers(String topic, Object encodedClass) {
 
-        if (topic == null || topic.isEmpty()) {
-            throw new IllegalArgumentException(UNSUPPORTED_MSG);
-        }
+        validateStringParameter(topic, INVALID_TOPIC_MSG);
 
-        if (fact == null) {
-            throw new IllegalArgumentException(MISSING_CLASS);
-        }
+        validateObjectParameter(encodedClass, MISSING_CLASS);
 
-        List<DroolsController> droolsControllers = droolsCreators(topic, fact);
+        List<DroolsController> droolsControllers = droolsCreators(topic, encodedClass);
         if (droolsControllers.size() > 1) {
             // unexpected
-            logger.warn(
-                    "{}: multiple drools-controller {} for {}:{} ",
-                    this,
-                    droolsControllers,
-                    topic,
-                    fact.getClass().getName());
+            logger.warn("{}: multiple drools-controller {} for {}:{} ",
+                this, droolsControllers, topic, encodedClass.getClass().getName());
             // continue
         }
         return droolsControllers;
     }
 
+    private void validateKeyParameters(String groupId, String artifactId, String topic) {
+        validateStringParameter(groupId, INVALID_GROUP_ID_MSG);
+        validateStringParameter(artifactId, INVALID_ARTIFACT_ID_MSG);
+        validateStringParameter(topic, INVALID_TOPIC_MSG);
+    }
+
+    private static void validateStringParameter(String value, String errorMessage) {
+        if (StringUtils.isBlank(value)) {
+            throw new IllegalArgumentException(errorMessage);
+        }
+    }
+
+    private static void validateObjectParameter(Object object, String errorMessage) {
+        if (Objects.isNull(object)) {
+            throw new IllegalArgumentException(errorMessage);
+        }
+    }
+
     /*
-     * Note: this only logs the KEYSETS, thus lombok ToString annotation is not used.
+     * Note: this only logs the KEY SETS, thus lombok ToString annotation is not used.
      * Otherwise, it results in too much verbosity.
      */
     @Override
     public String toString() {
-        return "GenericEventProtocolCoder [coders="
-                + coders.keySet()
-                + ", reverseCoders="
-                + reverseCoders.keySet()
-                + "]";
+        return "GenericEventProtocolCoder "
+            + "[coders=" + coders.keySet() + ", "
+            + "reverseCoders=" + reverseCoders.keySet() + "]";
     }
 }
index 8084461..18fcb1a 100644 (file)
@@ -3,6 +3,7 @@
  * ONAP
  * ================================================================================
  * Copyright (C) 2019-2022 AT&T Intellectual Property. All rights reserved.
+ * Modifications Copyright (C) 2024 Nordix Foundation.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -62,7 +63,7 @@ class GsonProtocolCoderToolset extends ProtocolCoderToolset {
     public static class GsonUtcAdapter implements JsonSerializer<ZonedDateTime>, JsonDeserializer<ZonedDateTime> {
         @Override
         public ZonedDateTime deserialize(JsonElement element, Type type,
-                JsonDeserializationContext context) {
+                                         JsonDeserializationContext context) {
             try {
                 return ZonedDateTime.parse(element.getAsString(), format);
             } catch (final Exception e) {
@@ -73,7 +74,7 @@ class GsonProtocolCoderToolset extends ProtocolCoderToolset {
 
         @Override
         public JsonElement serialize(ZonedDateTime datetime, Type type,
-                JsonSerializationContext context) {
+                                     JsonSerializationContext context) {
             return new JsonPrimitive(datetime.format(format));
         }
     }
@@ -112,7 +113,7 @@ class GsonProtocolCoderToolset extends ProtocolCoderToolset {
      * Toolset to encode/decode tools associated with a topic.
      *
      * @param eventProtocolParams parameter object for event encoder
-     * @param controllerId controller id
+     * @param controllerId        controller id
      */
     public GsonProtocolCoderToolset(EventProtocolParams eventProtocolParams, String controllerId) {
         super(eventProtocolParams, controllerId);
@@ -145,7 +146,7 @@ class GsonProtocolCoderToolset extends ProtocolCoderToolset {
     public Object decode(String json) {
 
         final var droolsController =
-                        DroolsControllerConstants.getFactory().get(this.groupId, this.artifactId, "");
+            DroolsControllerConstants.getFactory().get(this.groupId, this.artifactId, "");
         if (droolsController == null) {
             logger.warn("{}: no drools-controller to process {}", this, json);
             throw new IllegalStateException("no drools-controller to process event");
@@ -163,35 +164,36 @@ class GsonProtocolCoderToolset extends ProtocolCoderToolset {
             if (decoderClass == null) {
                 logger.warn(CANNOT_FETCH_CLASS, this, decoderFilter.getFactClass());
                 throw new IllegalStateException(
-                        FETCH_CLASS_EX_MSG + decoderFilter.getFactClass());
+                    FETCH_CLASS_EX_MSG + decoderFilter.getFactClass());
             }
         } catch (final Exception e) {
             logger.warn(CANNOT_FETCH_CLASS, this, decoderFilter.getFactClass());
             throw new UnsupportedOperationException(
-                    FETCH_CLASS_EX_MSG + decoderFilter.getFactClass(), e);
+                FETCH_CLASS_EX_MSG + decoderFilter.getFactClass(), e);
         }
 
         if (this.customCoder != null) {
             try {
                 final var gsonClassContainer =
-                        droolsController.fetchModelClass(this.customCoder.getClassContainer());
+                    droolsController.fetchModelClass(this.customCoder.getClassContainer());
                 final var gsonField = gsonClassContainer.getField(this.customCoder.staticCoderField);
                 final var gsonObject = gsonField.get(null);
                 final var fromJsonMethod = gsonObject.getClass().getDeclaredMethod("fromJson",
-                        String.class, Class.class);
+                    String.class, Class.class);
                 return fromJsonMethod.invoke(gsonObject, json, decoderClass);
             } catch (final Exception e) {
                 logger.warn(CANNOT_FETCH_CLASS, this, decoderFilter.getFactClass());
-                throw new UnsupportedOperationException(
-                        FETCH_CLASS_EX_MSG + decoderFilter.getFactClass(), e);
+                throw new UnsupportedOperationException("cannot decode with customCoder: "
+                    + customCoder.getClassContainer()
+                    + " using application class " + decoderFilter.getFactClass(), e);
             }
         } else {
             try {
-                return this.decoder.fromJson(json, decoderClass);
+                return this.getDecoder().fromJson(json, decoderClass);
             } catch (final Exception e) {
                 logger.warn("{} cannot decode {} into {}", this, json, decoderClass.getName());
                 throw new UnsupportedOperationException(
-                        "cannot decode into " + decoderFilter.getFactClass(), e);
+                    "cannot decode into " + decoderFilter.getFactClass(), e);
             }
         }
     }
@@ -205,21 +207,20 @@ class GsonProtocolCoderToolset extends ProtocolCoderToolset {
         if (this.customCoder != null) {
             try {
                 final var droolsController =
-                                DroolsControllerConstants.getFactory().get(this.groupId, this.artifactId, null);
+                    DroolsControllerConstants.getFactory().get(this.groupId, this.artifactId, null);
                 final Class<?> gsonClassContainer =
-                        droolsController.fetchModelClass(this.customCoder.getClassContainer());
+                    droolsController.fetchModelClass(this.customCoder.getClassContainer());
                 final var gsonField = gsonClassContainer.getField(this.customCoder.staticCoderField);
                 final var gsonObject = gsonField.get(null);
-                final var toJsonMethod =
-                        gsonObject.getClass().getDeclaredMethod("toJson", Object.class);
+                final var toJsonMethod = gsonObject.getClass().getDeclaredMethod("toJson", Object.class);
                 return (String) toJsonMethod.invoke(gsonObject, event);
             } catch (final Exception e) {
                 logger.warn("{} cannot custom-encode {}", this, event);
-                throw new UnsupportedOperationException("event cannot be encoded", e);
+                throw new UnsupportedOperationException("event cannot be custom encoded", e);
             }
         } else {
             try {
-                return this.encoder.toJson(event);
+                return this.getEncoder().toJson(event);
             } catch (final Exception e) {
                 logger.warn("{} cannot encode {}", this, event);
                 throw new UnsupportedOperationException("event cannot be encoded", e);
index 3fea682..cfbf2e4 100644 (file)
@@ -3,6 +3,7 @@
  * ONAP
  * ================================================================================
  * Copyright (C) 2019, 2021 AT&T Intellectual Property. All rights reserved.
+ * Modifications Copyright (C) 2024 Nordix Foundation.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,7 +21,6 @@
 
 package org.onap.policy.drools.protocol.coders;
 
-import java.util.ArrayList;
 import java.util.List;
 import lombok.ToString;
 import org.onap.policy.drools.controller.DroolsController;
@@ -126,19 +126,7 @@ class MultiplexorEventProtocolCoder implements EventProtocolCoder {
      */
     @Override
     public Object decode(String groupId, String artifactId, String topic, String json) {
-        logger.debug("{}: decode {}:{}:{}:{}", this, groupId, artifactId, topic, json);  // NOSONAR
-
-        /*
-         * It seems that sonar declares the previous logging line as a security vulnerability
-         * when logging the topic variable.   The static code analysis indicates that
-         * the path starts in org.onap.policy.drools.server.restful.RestManager::decode(),
-         * but the request is rejected if the topic contains invalid characters (the sonar description
-         * mentions "/r/n/t" characters) which are validated against in the checkValidNameInput(topic).
-         * Furthermore production instances are assumed not to have debug enabled, nor the REST telemetry API
-         * should be published externally.  An additional note is that Path URLs containing spaces and newlines
-         * will be failed earlier at the HTTP protocol libraries (jetty, etc ..) so an URL of the form
-         * "https://../to\npic" won't even make it here.
-         */
+        logger.debug("{}: decode {}:{}:{}:{}", this, groupId, artifactId, topic, json);
         return this.decoders.decode(groupId, artifactId, topic, json);
     }
 
@@ -156,13 +144,7 @@ class MultiplexorEventProtocolCoder implements EventProtocolCoder {
      */
     @Override
     public String encode(String topic, Object event) {
-        logger.debug("{}: encode {}:{}", this, topic, event);  // NOSONAR
-
-        /*
-         * See explanation for decode(String groupId, String artifactId, String topic, String json).
-         * The same applies here as it is called from
-         * org.onap.policy.drools.server.restful.RestManager::encode(),
-         */
+        logger.debug("{}: encode {}:{}", this, topic, event);
         return this.encoders.encode(topic, event);
     }
 
@@ -187,8 +169,7 @@ class MultiplexorEventProtocolCoder implements EventProtocolCoder {
      * {@inheritDoc}.
      */
     @Override
-    public CoderFilters getDecoderFilters(
-            String groupId, String artifactId, String topic, String classname) {
+    public CoderFilters getDecoderFilters(String groupId, String artifactId, String topic, String classname) {
         return this.decoders.getFilters(groupId, artifactId, topic, classname);
     }
 
@@ -205,18 +186,11 @@ class MultiplexorEventProtocolCoder implements EventProtocolCoder {
      */
     @Override
     public ProtocolCoderToolset getDecoders(String groupId, String artifactId, String topic) {
-        ProtocolCoderToolset decoderToolsets =
-                this.decoders.getCoders(groupId, artifactId, topic);
-        if (decoderToolsets == null) {
-            throw new IllegalArgumentException(
-                    "Decoders not found for " + groupId + ":" + artifactId + ":" + topic);
-        }
-
-        return decoderToolsets;
+        return this.decoders.getCoders(groupId, artifactId, topic);
     }
 
     /**
-     * get all deocders by maven coordinates and topic.
+     * get all decoders by maven coordinates and topic.
      *
      * @param groupId    group id
      * @param artifactId artifact id
@@ -225,14 +199,7 @@ class MultiplexorEventProtocolCoder implements EventProtocolCoder {
      */
     @Override
     public List<ProtocolCoderToolset> getDecoders(String groupId, String artifactId) {
-
-        List<ProtocolCoderToolset> decoderToolsets =
-                this.decoders.getCoders(groupId, artifactId);
-        if (decoderToolsets == null) {
-            throw new IllegalArgumentException("Decoders not found for " + groupId + ":" + artifactId);
-        }
-
-        return new ArrayList<>(decoderToolsets);
+        return this.decoders.getCoders(groupId, artifactId);
     }
 
     /**
index 277c4ed..5cd6870 100644 (file)
@@ -4,6 +4,7 @@
  * ================================================================================
  * Copyright (C) 2017-2022 AT&T Intellectual Property. All rights reserved.
  * Modifications Copyright (C) 2018 Samsung Electronics Co., Ltd.
+ * Modifications Copyright (C) 2024 Nordix Foundation.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -26,6 +27,7 @@ import java.util.List;
 import java.util.concurrent.CopyOnWriteArrayList;
 import lombok.Getter;
 import lombok.Setter;
+import org.apache.commons.lang3.StringUtils;
 import org.onap.policy.drools.protocol.coders.EventProtocolCoder.CoderFilters;
 import org.onap.policy.drools.protocol.coders.TopicCoderFilterConfiguration.CustomCoder;
 import org.slf4j.Logger;
@@ -82,7 +84,7 @@ public abstract class ProtocolCoderToolset {
      */
     protected ProtocolCoderToolset(EventProtocolParams eventProtocolParams, String controllerId) {
 
-        if (eventProtocolParams == null || controllerId == null) {
+        if (eventProtocolParams == null || StringUtils.isBlank(controllerId)) {
             throw new IllegalArgumentException("Invalid input");
         }
 
@@ -104,7 +106,7 @@ public abstract class ProtocolCoderToolset {
      * @return the decoder filters or null if not found
      */
     public CoderFilters getCoder(String classname) {
-        if (classname == null || classname.isEmpty()) {
+        if (StringUtils.isBlank(classname)) {
             throw new IllegalArgumentException("no classname provided");
         }
 
@@ -132,7 +134,7 @@ public abstract class ProtocolCoderToolset {
      * @param filter filter
      */
     public void addCoder(String eventClass, JsonProtocolFilter filter, int modelClassLoaderHash) {
-        if (eventClass == null || eventClass.isEmpty()) {
+        if (StringUtils.isBlank(eventClass)) {
             throw new IllegalArgumentException("no event class provided");
         }
 
@@ -152,7 +154,7 @@ public abstract class ProtocolCoderToolset {
      * @param eventClass event class
      */
     public void removeCoders(String eventClass) {
-        if (eventClass == null || eventClass.isEmpty()) {
+        if (StringUtils.isBlank(eventClass)) {
             throw new IllegalArgumentException("no event class provided");
         }
 
index 4dd132b..69bc052 100644 (file)
@@ -3,6 +3,7 @@
  * policy-management
  * ================================================================================
  * Copyright (C) 2017-2021 AT&T Intellectual Property. All rights reserved.
+ * Modifications Copyright (C) 2024 Nordix Foundation.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -25,6 +26,7 @@ import lombok.AllArgsConstructor;
 import lombok.Getter;
 import lombok.Setter;
 import lombok.ToString;
+import org.apache.commons.lang3.StringUtils;
 
 @Getter
 @ToString
@@ -51,19 +53,21 @@ public class TopicCoderFilterConfiguration {
          * @param rawCustomCoder with format: &lt;class-containing-custom-coder&gt;,&lt;static-coder-field&gt.
          */
         protected CustomCoder(String rawCustomCoder) {
-            if (rawCustomCoder != null && !rawCustomCoder.isEmpty()) {
-
-                this.classContainer = rawCustomCoder.substring(0, rawCustomCoder.indexOf(','));
-                if (this.classContainer == null || this.classContainer.isEmpty()) {
-                    throw new IllegalArgumentException(
-                            "No classname to create CustomCoder cannot be created");
-                }
-
-                this.staticCoderField = rawCustomCoder.substring(rawCustomCoder.indexOf(',') + 1);
-                if (this.staticCoderField == null || this.staticCoderField.isEmpty()) {
-                    throw new IllegalArgumentException(
-                            "No staticCoderField to create CustomCoder cannot be created for class " + classContainer);
-                }
+            if (StringUtils.isBlank(rawCustomCoder)) {
+                throw new IllegalArgumentException("Constructor argument cannot be empty. "
+                    + "Use format \"customCoderClass,staticCoderField\"");
+            }
+
+            this.classContainer = rawCustomCoder.substring(0, rawCustomCoder.indexOf(','));
+            if (StringUtils.isBlank(this.classContainer)) {
+                throw new IllegalArgumentException(
+                    "No classname to create CustomCoder cannot be created");
+            }
+
+            this.staticCoderField = rawCustomCoder.substring(rawCustomCoder.indexOf(',') + 1);
+            if (StringUtils.isBlank(this.staticCoderField)) {
+                throw new IllegalArgumentException(
+                    "No staticCoderField to create CustomCoder cannot be created for class " + classContainer);
             }
         }
 
@@ -74,11 +78,11 @@ public class TopicCoderFilterConfiguration {
          * @param staticCoderField static coder field
          */
         protected CustomCoder(String className, String staticCoderField) {
-            if (className == null || className.isEmpty()) {
+            if (StringUtils.isBlank(className)) {
                 throw new IllegalArgumentException("No classname to create CustomCoder cannot be created");
             }
 
-            if (staticCoderField == null || staticCoderField.isEmpty()) {
+            if (StringUtils.isBlank(staticCoderField)) {
                 throw new IllegalArgumentException(
                         "No staticCoderField to create CustomCoder cannot be created for class " + className);
             }
diff --git a/policy-management/src/test/java/org/onap/policy/drools/controller/IndexedDroolsControllerFactoryTest.java b/policy-management/src/test/java/org/onap/policy/drools/controller/IndexedDroolsControllerFactoryTest.java
new file mode 100644 (file)
index 0000000..39a03db
--- /dev/null
@@ -0,0 +1,154 @@
+/*-
+ * ============LICENSE_START===============================================
+ * ONAP
+ * ========================================================================
+ * Copyright (C) 2024 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.controller;
+
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.onap.policy.drools.protocol.coders.TopicCoderFilterConfiguration;
+import org.springframework.test.util.ReflectionTestUtils;
+
+class IndexedDroolsControllerFactoryTest {
+
+    IndexedDroolsControllerFactory factory;
+    static final String GROUP_ID = "groupId";
+    static final String ARTIFACT_ID = "artifactId";
+    static final String VERSION = "version";
+    static final String OTHER_VERSION = "otherVersion";
+
+    @BeforeEach
+    void setUp() {
+        this.factory = new IndexedDroolsControllerFactory();
+    }
+
+    @Test
+    void build_EmptyArguments() {
+        var props = new Properties();
+        List<TopicCoderFilterConfiguration> decoderConfigs = List.of();
+        List<TopicCoderFilterConfiguration> encoderConfigs = List.of();
+
+        assertThatThrownBy(() -> factory.build(props, "", ARTIFACT_ID, VERSION, decoderConfigs, encoderConfigs))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("Missing maven group-id coordinate");
+
+        assertThatThrownBy(() -> factory.build(props, GROUP_ID, "", VERSION, decoderConfigs, encoderConfigs))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("Missing maven artifact-id coordinate");
+
+        assertThatThrownBy(() -> factory.build(props, GROUP_ID, ARTIFACT_ID, "", decoderConfigs, encoderConfigs))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("Missing maven version coordinate");
+    }
+
+    @Test
+    void testBuild_CheckControllerCopy() {
+        var props = new Properties();
+        List<TopicCoderFilterConfiguration> decoderConfigs = List.of();
+        List<TopicCoderFilterConfiguration> encoderConfigs = List.of();
+
+        var mockFactory = mock(IndexedDroolsControllerFactory.class);
+        when(mockFactory.build(props, GROUP_ID, ARTIFACT_ID, VERSION, decoderConfigs, encoderConfigs))
+            .thenCallRealMethod();
+
+        var controller = mock(DroolsController.class);
+        doNothing().when(controller).updateToVersion(GROUP_ID, ARTIFACT_ID, VERSION, decoderConfigs, encoderConfigs);
+        when(controller.getVersion()).thenReturn(OTHER_VERSION);
+        Map<String, DroolsController> controllers = new HashMap<>();
+        controllers.put(GROUP_ID + ":" + ARTIFACT_ID, controller);
+        ReflectionTestUtils.setField(mockFactory, "droolsControllers", controllers);
+
+        assertNotNull(mockFactory.build(props, GROUP_ID, ARTIFACT_ID, VERSION, decoderConfigs, encoderConfigs));
+    }
+
+    @Test
+    void unmanage() {
+        assertThatThrownBy(() -> factory.unmanage(null))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("No controller provided");
+
+        var mockController = mock(DroolsController.class);
+        when(mockController.isBrained()).thenReturn(false)
+            .thenReturn(true).thenReturn(true);
+        when(mockController.getGroupId()).thenReturn(GROUP_ID);
+        when(mockController.getArtifactId()).thenReturn(ARTIFACT_ID);
+
+        var mockFactory = mock(IndexedDroolsControllerFactory.class);
+        doCallRealMethod().when(mockFactory).unmanage(mockController);
+        when(mockFactory.toString()).thenCallRealMethod();
+
+        Map<String, DroolsController> controllers = new HashMap<>();
+        controllers.put(GROUP_ID + ":" + ARTIFACT_ID, mockController);
+        ReflectionTestUtils.setField(mockFactory, "droolsControllers", controllers);
+
+        // should return after isBrained returns false
+        assertDoesNotThrow(() -> mockFactory.unmanage(mockController));
+        assertFalse(mockFactory.droolsControllers.isEmpty());
+        assertEquals("IndexedDroolsControllerFactory [#droolsControllers=1]", mockFactory.toString());
+
+        // should go ahead and remove controller from hash map
+        assertDoesNotThrow(() -> mockFactory.unmanage(mockController));
+        assertTrue(mockFactory.droolsControllers.isEmpty());
+        assertEquals("IndexedDroolsControllerFactory [#droolsControllers=0]", mockFactory.toString());
+
+        controllers.put("anotherKey", mockController);
+        ReflectionTestUtils.setField(mockFactory, "droolsControllers", controllers);
+
+        // should return after comparing the key in the hash map (does not match)
+        assertDoesNotThrow(() -> mockFactory.unmanage(mockController));
+        assertFalse(mockFactory.droolsControllers.isEmpty());
+        assertEquals("IndexedDroolsControllerFactory [#droolsControllers=1]", mockFactory.toString());
+    }
+
+    @Test
+    void shutdown() {
+        var mockController = mock(DroolsController.class);
+        doNothing().when(mockController).shutdown();
+
+        var mockFactory = mock(IndexedDroolsControllerFactory.class);
+        doNothing().when(mockFactory).unmanage(mockController);
+
+        assertDoesNotThrow(() -> mockFactory.shutdown(mockController));
+    }
+
+    @Test
+    void get_EmptyParameters() {
+        assertThatThrownBy(() -> factory.get("", ARTIFACT_ID, VERSION))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("Missing maven coordinates");
+        assertThatThrownBy(() -> factory.get(GROUP_ID, "", VERSION))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("Missing maven coordinates");
+    }
+}
\ No newline at end of file
index 38b38a8..753296a 100644 (file)
@@ -88,7 +88,7 @@ public class MavenDroolsControllerUpgradesTest {
             KieUtils.installArtifact(
                 Paths.get(DROOLS_RESOURCES_DIR + RULES_BASE + KMODULE_EXT).toFile(),
                 Paths.get(DROOLS_RESOURCES_DIR + name + POM_EXT).toFile(),
-               DROOLS_KJAR_RESOURCES_DIR + KBNAME_RULES + "/" + KBPACKAGE_RULES + "/",
+                DROOLS_KJAR_RESOURCES_DIR + KBNAME_RULES + "/" + KBPACKAGE_RULES + "/",
                 drls);
     }
 
@@ -105,8 +105,8 @@ public class MavenDroolsControllerUpgradesTest {
         rulesDescriptor2 =
             install("rules2",
                 Stream.of(path.toFile(),
-                          Paths.get(DROOLS_RESOURCES_DIR + "rules2" + DRL_EXT).toFile())
-                      .collect(Collectors.toList()));
+                        Paths.get(DROOLS_RESOURCES_DIR + "rules2" + DRL_EXT).toFile())
+                    .collect(Collectors.toList()));
 
         LoggerUtils.setLevel("ROOT", "WARN");
         LoggerUtils.setLevel("org.onap.policy.drools.controller.internal", "INFO");
@@ -169,13 +169,13 @@ public class MavenDroolsControllerUpgradesTest {
 
     private void summary() {
         logger.info("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
-        logger.info("Controller: " + controller.getGroupId() + ":" + controller.getArtifactId()
-            + ":" + controller.getVersion());
+        logger.info("Controller: {}:{}:{}", controller.getGroupId(), controller.getArtifactId(),
+            controller.getVersion());
         logger.info(".....................................................................");
-        logger.info("KIE-BASES: " + KieUtils.getBases(controller.getContainer().getKieContainer()));
-        logger.info("KIE-PACKAGE-NAMES: " + KieUtils.getPackageNames(controller.getContainer().getKieContainer()));
-        logger.info("KIE-RULE-NAMES: " + KieUtils.getRuleNames(controller.getContainer().getKieContainer()));
-        logger.info("FACTS: " + controller.facts(KBSESSION_RULES, Object.class));
+        logger.info("KIE-BASES: {}", KieUtils.getBases(controller.getContainer().getKieContainer()));
+        logger.info("KIE-PACKAGE-NAMES: {}", KieUtils.getPackageNames(controller.getContainer().getKieContainer()));
+        logger.info("KIE-RULE-NAMES: {}", KieUtils.getRuleNames(controller.getContainer().getKieContainer()));
+        logger.info("FACTS: {}", controller.facts(KBSESSION_RULES, Object.class));
         logger.info("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
     }
 
@@ -190,25 +190,25 @@ public class MavenDroolsControllerUpgradesTest {
         controller.getContainer()
             .getPolicySession(KBSESSION_RULES)
             .getKieSession()
-                .addEventListener(new RuleRuntimeEventListener() {
-                    @Override
-                    public void objectInserted(ObjectInsertedEvent objectInsertedEvent) {
-                        logger.info("RULE {}: inserting {}",
-                            objectInsertedEvent.getRule().getName(), objectInsertedEvent.getObject());
-                    }
-
-                    @Override
-                    public void objectUpdated(ObjectUpdatedEvent objectUpdatedEvent) {
-                        logger.info("RULE {}: updating {}",
-                            objectUpdatedEvent.getRule().getName(), objectUpdatedEvent.getObject());
-                    }
-
-                    @Override
-                    public void objectDeleted(ObjectDeletedEvent objectDeletedEvent) {
-                        logger.info("RULE {}: deleting {}",
-                            objectDeletedEvent.getRule().getName(), objectDeletedEvent.getOldObject());
-                    }
-                });
+            .addEventListener(new RuleRuntimeEventListener() {
+                @Override
+                public void objectInserted(ObjectInsertedEvent objectInsertedEvent) {
+                    logger.info("RULE {}: inserting {}",
+                        objectInsertedEvent.getRule().getName(), objectInsertedEvent.getObject());
+                }
+
+                @Override
+                public void objectUpdated(ObjectUpdatedEvent objectUpdatedEvent) {
+                    logger.info("RULE {}: updating {}",
+                        objectUpdatedEvent.getRule().getName(), objectUpdatedEvent.getObject());
+                }
+
+                @Override
+                public void objectDeleted(ObjectDeletedEvent objectDeletedEvent) {
+                    logger.info("RULE {}: deleting {}",
+                        objectDeletedEvent.getRule().getName(), objectDeletedEvent.getOldObject());
+                }
+            });
 
         controller.getContainer()
             .getPolicySession(KBSESSION_RULES)
diff --git a/policy-management/src/test/java/org/onap/policy/drools/features/DroolsControllerFeatureApiTest.java b/policy-management/src/test/java/org/onap/policy/drools/features/DroolsControllerFeatureApiTest.java
new file mode 100644 (file)
index 0000000..83171da
--- /dev/null
@@ -0,0 +1,83 @@
+/*-
+ * ============LICENSE_START===============================================
+ * ONAP
+ * ========================================================================
+ * Copyright (C) 2024 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.features;
+
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+import java.util.Collections;
+import java.util.Properties;
+import org.junit.jupiter.api.Test;
+import org.onap.policy.common.endpoints.event.comm.TopicSink;
+import org.onap.policy.drools.controller.DroolsController;
+
+/**
+ * DroolsControllerFeatureApi is implemented in other modules, therefore, coverage is not coming up in this module.
+ * This class has no intention of unit testing features, sole goal is raise coverage.
+ */
+class DroolsControllerFeatureApiTest {
+
+    DroolsControllerFeatureApi testClass = new TestDroolsControllerFeatureApi();
+    Properties props = new Properties();
+    DroolsController controller;
+    TopicSink sink;
+    Object fact;
+
+    @Test
+    void beforeInstance() {
+        assertNull(testClass.beforeInstance(props, "group", "artifact", "version",
+            Collections.emptyList(), Collections.emptyList()));
+    }
+
+    @Test
+    void afterInstance() {
+        assertFalse(testClass.afterInstance(controller, props));
+    }
+
+    @Test
+    void beforeInsert() {
+        assertFalse(testClass.beforeInsert(controller, props));
+    }
+
+    @Test
+    void afterInsert() {
+        assertFalse(testClass.afterInsert(controller, fact, false));
+    }
+
+    @Test
+    void beforeDeliver() {
+        assertFalse(testClass.beforeDeliver(controller, sink, fact));
+    }
+
+    @Test
+    void afterDeliver() {
+        assertFalse(testClass.afterDeliver(controller, sink, fact, "json", false));
+    }
+
+    static class TestDroolsControllerFeatureApi implements DroolsControllerFeatureApi {
+
+        @Override
+        public int getSequenceNumber() {
+            return 30;
+        }
+    }
+}
\ No newline at end of file
diff --git a/policy-management/src/test/java/org/onap/policy/drools/features/PolicyControllerFeatureApiTest.java b/policy-management/src/test/java/org/onap/policy/drools/features/PolicyControllerFeatureApiTest.java
new file mode 100644 (file)
index 0000000..f48bf93
--- /dev/null
@@ -0,0 +1,171 @@
+/*-
+ * ============LICENSE_START===============================================
+ * ONAP
+ * ========================================================================
+ * Copyright (C) 2024 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.features;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure.NOOP;
+
+import java.util.Properties;
+import org.junit.jupiter.api.Test;
+import org.onap.policy.drools.protocol.configuration.DroolsConfiguration;
+import org.onap.policy.drools.system.PolicyController;
+
+/**
+ * PolicyControllerFeatureApi is implemented in other modules, therefore, coverage is not coming up in this module.
+ * This class has no intention of unit testing features, sole goal is raise coverage.
+ */
+class PolicyControllerFeatureApiTest {
+
+    PolicyControllerFeatureApi testClass = new TestPolicyControllerFeatureApi();
+    Properties props = new Properties();
+    PolicyController controller;
+    DroolsConfiguration configuration;
+
+
+    @Test
+    void beforeCreate() {
+        assertNull(testClass.beforeCreate("name", props));
+    }
+
+    @Test
+    void afterCreate() {
+        assertFalse(testClass.afterCreate(controller));
+    }
+
+    @Test
+    void beforeInstance() {
+        assertNull(testClass.beforeInstance("name", props));
+    }
+
+    @Test
+    void afterInstance() {
+        assertFalse(testClass.afterInstance(controller, props));
+    }
+
+    @Test
+    void beforeStart() {
+        assertFalse(testClass.beforeStart(controller));
+    }
+
+    @Test
+    void afterStart() {
+        assertFalse(testClass.afterStart(controller));
+    }
+
+    @Test
+    void beforeStop() {
+        assertFalse(testClass.beforeStop(controller));
+    }
+
+    @Test
+    void afterStop() {
+        assertFalse(testClass.afterStop(controller));
+    }
+
+    @Test
+    void beforePatch() {
+        assertFalse(testClass.beforePatch(controller, configuration, configuration));
+    }
+
+    @Test
+    void afterPatch() {
+        assertFalse(testClass.afterPatch(controller, configuration, configuration, true));
+    }
+
+    @Test
+    void beforeLock() {
+        assertFalse(testClass.beforeLock(controller));
+    }
+
+    @Test
+    void afterLock() {
+        assertFalse(testClass.afterLock(controller));
+    }
+
+    @Test
+    void beforeUnlock() {
+        assertFalse(testClass.beforeUnlock(controller));
+    }
+
+    @Test
+    void afterUnlock() {
+        assertFalse(testClass.afterUnlock(controller));
+    }
+
+    @Test
+    void beforeShutdown() {
+        assertFalse(testClass.beforeShutdown(controller));
+    }
+
+    @Test
+    void afterShutdown() {
+        assertFalse(testClass.afterShutdown(controller));
+    }
+
+    @Test
+    void beforeHalt() {
+        assertFalse(testClass.beforeHalt(controller));
+    }
+
+    @Test
+    void afterHalt() {
+        assertFalse(testClass.afterHalt(controller));
+    }
+
+    @Test
+    void beforeOffer() {
+        assertFalse(testClass.beforeOffer(controller, new Object()));
+    }
+
+    @Test
+    void testBeforeOffer() {
+        assertFalse(testClass.beforeOffer(controller, NOOP, "topic", "event"));
+    }
+
+    @Test
+    void afterOffer() {
+        assertFalse(testClass.afterOffer(controller, new Object(), true));
+    }
+
+    @Test
+    void testAfterOffer() {
+        assertFalse(testClass.afterOffer(controller, NOOP, "topic", "event", true));
+    }
+
+    @Test
+    void beforeDeliver() {
+        assertFalse(testClass.beforeDeliver(controller, NOOP, "topic", "event"));
+    }
+
+    @Test
+    void afterDeliver() {
+        assertFalse(testClass.afterDeliver(controller, NOOP, "topic", "event", true));
+    }
+
+    static class TestPolicyControllerFeatureApi implements PolicyControllerFeatureApi {
+
+        @Override
+        public int getSequenceNumber() {
+            return 20;
+        }
+    }
+}
\ No newline at end of file
diff --git a/policy-management/src/test/java/org/onap/policy/drools/features/PolicyEngineFeatureApiTest.java b/policy-management/src/test/java/org/onap/policy/drools/features/PolicyEngineFeatureApiTest.java
new file mode 100644 (file)
index 0000000..90feeb2
--- /dev/null
@@ -0,0 +1,174 @@
+/*-
+ * ============LICENSE_START===============================================
+ * ONAP
+ * ========================================================================
+ * Copyright (C) 2024 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.features;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.mockito.Mockito.mock;
+
+import java.util.Properties;
+import org.junit.jupiter.api.Test;
+import org.onap.policy.common.endpoints.event.comm.Topic;
+import org.onap.policy.drools.core.lock.PolicyResourceLockManager;
+import org.onap.policy.drools.protocol.configuration.PdpdConfiguration;
+import org.onap.policy.drools.system.PolicyEngine;
+
+/**
+ * PolicyEngineFeatureApi is implemented in other modules, therefore, coverage is not coming up in this module.
+ * This class has no intention of unit testing features, sole goal is raise coverage.
+ */
+class PolicyEngineFeatureApiTest {
+
+    PolicyEngineFeatureApi testClass = new TestPolicyEngineFeatureApi();
+
+    PolicyEngine policyEngine = mock(PolicyEngine.class);
+    Properties props = new Properties();
+
+    @Test
+    void beforeBoot() {
+        assertFalse(testClass.beforeBoot(policyEngine, new String[] {"a", "b"}));
+    }
+
+    @Test
+    void afterBoot() {
+        assertFalse(testClass.afterBoot(policyEngine));
+    }
+
+    @Test
+    void beforeConfigure() {
+        assertFalse(testClass.beforeConfigure(policyEngine, props));
+    }
+
+    @Test
+    void afterConfigure() {
+        assertFalse(testClass.afterConfigure(policyEngine));
+    }
+
+    @Test
+    void beforeActivate() {
+        assertFalse(testClass.beforeActivate(policyEngine));
+    }
+
+    @Test
+    void afterActivate() {
+        assertFalse(testClass.afterActivate(policyEngine));
+    }
+
+    @Test
+    void beforeDeactivate() {
+        assertFalse(testClass.beforeDeactivate(policyEngine));
+    }
+
+    @Test
+    void afterDeactivate() {
+        assertFalse(testClass.afterDeactivate(policyEngine));
+    }
+
+    @Test
+    void beforeStart() {
+        assertFalse(testClass.beforeStart(policyEngine));
+    }
+
+    @Test
+    void afterStart() {
+        assertFalse(testClass.afterStart(policyEngine));
+    }
+
+    @Test
+    void beforeStop() {
+        assertFalse(testClass.beforeStop(policyEngine));
+    }
+
+    @Test
+    void afterStop() {
+        assertFalse(testClass.afterStop(policyEngine));
+    }
+
+    @Test
+    void beforeLock() {
+        assertFalse(testClass.beforeLock(policyEngine));
+    }
+
+    @Test
+    void afterLock() {
+        assertFalse(testClass.afterLock(policyEngine));
+    }
+
+    @Test
+    void beforeUnlock() {
+        assertFalse(testClass.beforeUnlock(policyEngine));
+    }
+
+    @Test
+    void afterUnlock() {
+        assertFalse(testClass.afterUnlock(policyEngine));
+    }
+
+    @Test
+    void beforeShutdown() {
+        assertFalse(testClass.beforeShutdown(policyEngine));
+    }
+
+    @Test
+    void afterShutdown() {
+        assertFalse(testClass.afterShutdown(policyEngine));
+    }
+
+    @Test
+    void beforeOnTopicEvent() {
+        assertFalse(testClass.beforeOnTopicEvent(policyEngine, Topic.CommInfrastructure.NOOP, "topic", "event"));
+    }
+
+    @Test
+    void afterOnTopicEvent() {
+        assertFalse(testClass.afterOnTopicEvent(policyEngine, mock(PdpdConfiguration.class),
+            Topic.CommInfrastructure.NOOP, "topic", "event"));
+    }
+
+    @Test
+    void beforeOpen() {
+        assertFalse(testClass.beforeOpen(policyEngine));
+    }
+
+    @Test
+    void afterOpen() {
+        assertFalse(testClass.afterOpen(policyEngine));
+    }
+
+    @Test
+    void beforeCreateLockManager() {
+        assertNull(testClass.beforeCreateLockManager());
+    }
+
+    @Test
+    void afterCreateLockManager() {
+        assertFalse(testClass.afterCreateLockManager(policyEngine, props, mock(PolicyResourceLockManager.class)));
+    }
+
+    static class TestPolicyEngineFeatureApi implements PolicyEngineFeatureApi {
+
+        @Override
+        public int getSequenceNumber() {
+            return 10;
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/policy-management/src/test/java/org/onap/policy/drools/persistence/FileSystemPersistenceTest.java b/policy-management/src/test/java/org/onap/policy/drools/persistence/FileSystemPersistenceTest.java
new file mode 100644 (file)
index 0000000..80a8dc6
--- /dev/null
@@ -0,0 +1,78 @@
+/*-
+ * ============LICENSE_START===============================================
+ * ONAP
+ * ========================================================================
+ * Copyright (C) 2024 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.persistence;
+
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.nio.file.Path;
+import org.junit.jupiter.api.Test;
+
+class FileSystemPersistenceTest {
+
+    FileSystemPersistence persistence = new FileSystemPersistence();
+
+    @Test
+    void testSetConfiguration_FileIsNotDirectory() {
+        persistence.configurationPath = Path.of("src/test/resources/echo.drl");
+        assertThrows(IllegalStateException.class, () -> persistence.setConfigurationDir());
+        assertThatThrownBy(() -> persistence.setConfigurationDir())
+            .hasMessageContaining("config directory: src/test/resources/echo.drl is not a directory");
+    }
+
+    @Test
+    void testSetConfiguration_InvalidDir() {
+        persistence.configurationPath = Path.of("/opt/path"); // opt path needs sudo
+        assertThrows(IllegalStateException.class, () -> persistence.setConfigurationDir());
+        assertThatThrownBy(() -> persistence.setConfigurationDir())
+            .hasMessageContaining("cannot create /opt/path");
+    }
+
+    @Test
+    void testGetProperties_Exception() {
+        assertThatThrownBy(() -> persistence.getProperties(""))
+            .hasMessageContaining("properties name must be provided");
+
+        String propName = null;
+        assertThatThrownBy(() -> persistence.getProperties(propName)) // for code coverage
+            .hasMessageContaining("properties name must be provided");
+    }
+
+    @Test
+    void testGetEnvironmentProperties_Exception() {
+        assertThatThrownBy(() -> persistence.getEnvironmentProperties(""))
+            .hasMessageContaining("environment name must be provided");
+
+        String propName = null;
+        assertThatThrownBy(() -> persistence.getEnvironmentProperties(propName)) // for code coverage
+            .hasMessageContaining("environment name must be provided");
+    }
+
+    @Test
+    void testGetProperties_ByPathException() {
+        assertThatThrownBy(() -> persistence.getProperties(Path.of("/path/does/not/exist.properties")))
+            .hasMessageContaining("properties for /path/does/not/exist.properties are not persisted.");
+
+        Path pathProps = null;
+        assertThatThrownBy(() -> persistence.getProperties(pathProps)) // for code coverage
+            .hasMessageContaining("propertiesPath is marked non-null but is null");
+    }
+}
index 6d461ee..c98467e 100644 (file)
@@ -22,6 +22,7 @@
 
 package org.onap.policy.drools.protocol.coders;
 
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.util.Properties;
@@ -88,4 +89,30 @@ class EventProtocolCoderTest {
 
         EventProtocolCoderConstants.getManager().removeEncoders(ENCODER_GROUP, ENCODER_ARTIFACT, NOOP_TOPIC);
     }
+
+    @Test
+    void test_extra() {
+        final Properties noopSinkProperties = new Properties();
+        noopSinkProperties.put(PolicyEndPointProperties.PROPERTY_NOOP_SINK_TOPICS, NOOP_TOPIC);
+
+        TopicEndpointManager.getManager().addTopicSinks(noopSinkProperties);
+
+        var encoder = EventProtocolParams.builder().groupId(ENCODER_GROUP).artifactId(ENCODER_ARTIFACT)
+            .topic(NOOP_TOPIC).eventClass(DroolsConfiguration.class.getName())
+            .protocolFilter(new JsonProtocolFilter()).customGsonCoder(null)
+            .modelClassLoaderHash(DroolsConfiguration.class.getName().hashCode()).build();
+
+        EventProtocolCoderConstants.getManager().addEncoder(encoder);
+
+        final String json = EventProtocolCoderConstants.getManager().encode(NOOP_TOPIC,
+            new DroolsConfiguration(ENCODER_ARTIFACT, ENCODER_GROUP, ENCODER_VERSION));
+
+        assertTrue(json.contains(ENCODER_GROUP));
+        assertTrue(json.contains(ENCODER_ARTIFACT));
+
+        // check if adding same encoder doesn't throw any exceptions as expected
+        assertDoesNotThrow(() -> EventProtocolCoderConstants.getManager().addEncoder(encoder));
+        EventProtocolCoderConstants.getManager().removeEncoders(ENCODER_GROUP, ENCODER_ARTIFACT, NOOP_TOPIC);
+        EventProtocolCoderConstants.getManager().removeEncoders("NotExistentGroup", ENCODER_ARTIFACT, NOOP_TOPIC);
+    }
 }
diff --git a/policy-management/src/test/java/org/onap/policy/drools/protocol/coders/GenericProtocolCoderTest.java b/policy-management/src/test/java/org/onap/policy/drools/protocol/coders/GenericProtocolCoderTest.java
new file mode 100644 (file)
index 0000000..7a8be59
--- /dev/null
@@ -0,0 +1,651 @@
+/*-
+ * ============LICENSE_START===============================================
+ * ONAP
+ * ========================================================================
+ * Copyright (C) 2024 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.protocol.coders;
+
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+import org.onap.policy.drools.controller.DroolsController;
+import org.onap.policy.drools.controller.DroolsControllerConstants;
+import org.onap.policy.drools.controller.DroolsControllerFactory;
+import org.onap.policy.drools.controller.internal.NullDroolsController;
+import org.springframework.test.util.ReflectionTestUtils;
+
+class GenericProtocolCoderTest {
+
+    EventProtocolEncoder encoder = new EventProtocolEncoder();
+    EventProtocolDecoder decoder = new EventProtocolDecoder();
+
+    private static final String GROUP_ID = "groupId";
+    private static final String ARTIFACT_ID = "artifactId";
+    private static final String TOPIC = "topic";
+    private static final String VALID_KEY = GROUP_ID + ":" + ARTIFACT_ID + ":" + TOPIC;
+    private static final String INVALID_KEY = "anotherKey";
+
+    @Test
+    void testAdd_ReverseCoder() {
+        var params = new EventProtocolParams(GROUP_ID, ARTIFACT_ID, TOPIC, "java.lang.Object",
+            mock(JsonProtocolFilter.class), mock(TopicCoderFilterConfiguration.CustomGsonCoder.class), 1);
+
+        var myKey = "group:artifact:topic";
+
+        var mockEncoder = mock(EventProtocolEncoder.class);
+        // set the key to be returned when checking the hash maps
+        when(mockEncoder.codersKey(GROUP_ID, ARTIFACT_ID, TOPIC)).thenReturn(myKey);
+        when(mockEncoder.reverseCodersKey(GROUP_ID, "java.lang.Object")).thenReturn(myKey);
+        doCallRealMethod().when(mockEncoder).add(params);
+
+
+        // create the hash maps for coders/reverseCoders
+        var toolset = mock(ProtocolCoderToolset.class);
+        HashMap<String, ProtocolCoderToolset> coders = new HashMap<>();
+        coders.put(myKey, toolset);
+        ReflectionTestUtils.setField(mockEncoder, "coders", coders);
+        HashMap<String, List<ProtocolCoderToolset>> reverseCoders = new HashMap<>();
+        reverseCoders.put("group:javaClass", new ArrayList<>(List.of(toolset)));
+        ReflectionTestUtils.setField(mockEncoder, "reverseCoders", reverseCoders);
+
+        assertDoesNotThrow(() -> mockEncoder.add(params));
+        assertEquals(2, mockEncoder.reverseCoders.size());
+        assertEquals(1, mockEncoder.coders.size());
+    }
+
+    @Test
+    void testAdd_InvalidParams_GroupId() {
+        var mockEventProtocolsParams = mock(EventProtocolParams.class);
+        when(mockEventProtocolsParams.getGroupId()).thenReturn(null);
+
+        assertThatThrownBy(() -> encoder.add(mockEventProtocolsParams))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("Invalid group id");
+
+        when(mockEventProtocolsParams.getGroupId()).thenReturn("");
+
+        assertThatThrownBy(() -> encoder.add(mockEventProtocolsParams))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("Invalid group id");
+    }
+
+    @Test
+    void testAdd_InvalidParams_ArtifactId() {
+        var mockEventProtocolsParams = mock(EventProtocolParams.class);
+        when(mockEventProtocolsParams.getGroupId()).thenReturn(GROUP_ID);
+        when(mockEventProtocolsParams.getArtifactId()).thenReturn(null);
+
+        assertThatThrownBy(() -> encoder.add(mockEventProtocolsParams))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("Invalid artifact id");
+
+        when(mockEventProtocolsParams.getArtifactId()).thenReturn("");
+
+        assertThatThrownBy(() -> encoder.add(mockEventProtocolsParams))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("Invalid artifact id");
+    }
+
+    @Test
+    void testAdd_InvalidParams_Topic() {
+        var mockEventProtocolsParams = mock(EventProtocolParams.class);
+        when(mockEventProtocolsParams.getGroupId()).thenReturn(GROUP_ID);
+        when(mockEventProtocolsParams.getArtifactId()).thenReturn(ARTIFACT_ID);
+        when(mockEventProtocolsParams.getTopic()).thenReturn(null);
+
+        assertThatThrownBy(() -> encoder.add(mockEventProtocolsParams))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("Invalid Topic");
+
+        when(mockEventProtocolsParams.getGroupId()).thenReturn(GROUP_ID);
+        when(mockEventProtocolsParams.getArtifactId()).thenReturn(ARTIFACT_ID);
+        when(mockEventProtocolsParams.getTopic()).thenReturn("");
+
+        assertThatThrownBy(() -> encoder.add(mockEventProtocolsParams))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("Invalid Topic");
+    }
+
+    @Test
+    void testAdd_InvalidParams_EventClass() {
+        var mockEventProtocolsParams = mock(EventProtocolParams.class);
+        when(mockEventProtocolsParams.getGroupId()).thenReturn(GROUP_ID);
+        when(mockEventProtocolsParams.getArtifactId()).thenReturn(ARTIFACT_ID);
+        when(mockEventProtocolsParams.getTopic()).thenReturn(TOPIC);
+        when(mockEventProtocolsParams.getEventClass()).thenReturn(null);
+
+        assertThatThrownBy(() -> encoder.add(mockEventProtocolsParams))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("Invalid Event Class");
+    }
+
+    @Test
+    void testDecode_Exceptions() {
+        var mockDecoder = mock(EventProtocolDecoder.class);
+        when(mockDecoder.isCodingSupported(GROUP_ID, ARTIFACT_ID, TOPIC))
+            .thenReturn(false);
+        when(mockDecoder.decode(GROUP_ID, ARTIFACT_ID, TOPIC, null))
+            .thenCallRealMethod();
+        when(mockDecoder.codersKey(GROUP_ID, ARTIFACT_ID, TOPIC))
+            .thenCallRealMethod();
+
+        assertThatThrownBy(() -> mockDecoder.decode(GROUP_ID, ARTIFACT_ID, TOPIC, null))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("Unsupported: groupId:artifactId:topic for encoding");
+    }
+
+    @Test
+    void testDecode_ExceptionCantDecode() {
+        var mockDecoder = mock(EventProtocolDecoder.class);
+
+        HashMap<String, ProtocolCoderToolset> coders = new HashMap<>();
+        var params = mock(EventProtocolParams.class);
+        coders.put("groupId:artifactId:topic", new GsonProtocolCoderToolset(params, "controllerId"));
+        ReflectionTestUtils.setField(mockDecoder, "coders", coders);
+
+        when(mockDecoder.isCodingSupported(GROUP_ID, ARTIFACT_ID, TOPIC))
+            .thenReturn(true);
+        when(mockDecoder.decode(GROUP_ID, ARTIFACT_ID, TOPIC, null))
+            .thenCallRealMethod();
+        when(mockDecoder.codersKey(GROUP_ID, ARTIFACT_ID, TOPIC))
+            .thenCallRealMethod();
+
+        assertThatThrownBy(() -> mockDecoder.decode(GROUP_ID, ARTIFACT_ID, TOPIC, null))
+            .isInstanceOf(UnsupportedOperationException.class)
+            .hasMessageContaining("Cannot decode with gson");
+    }
+
+    @Test
+    void testDecode_Decode() {
+        var mockDecoder = mock(EventProtocolDecoder.class);
+        var myKey = "groupId:artifactId:topic";
+        var json = "{\"json\":\"true\"}";
+
+        HashMap<String, ProtocolCoderToolset> coders = new HashMap<>();
+        var mockToolset = mock(ProtocolCoderToolset.class);
+        when(mockToolset.decode(json))
+            .thenReturn(new Object()) // success case
+            .thenReturn(null); // failure case
+
+        coders.put(myKey, mockToolset);
+        ReflectionTestUtils.setField(mockDecoder, "coders", coders);
+
+        when(mockDecoder.isCodingSupported(GROUP_ID, ARTIFACT_ID, TOPIC)).thenReturn(true);
+        when(mockDecoder.codersKey(GROUP_ID, ARTIFACT_ID, TOPIC)).thenReturn(myKey);
+        when(mockDecoder.decode(GROUP_ID, ARTIFACT_ID, TOPIC, json))
+            .thenCallRealMethod();
+
+        assertNotNull(mockDecoder.decode(GROUP_ID, ARTIFACT_ID, TOPIC, json));
+
+        assertThatThrownBy(() -> mockDecoder.decode(GROUP_ID, ARTIFACT_ID, TOPIC, json))
+            .isInstanceOf(UnsupportedOperationException.class)
+            .hasMessageContaining("Cannot decode with gson");
+    }
+
+    @Test
+    void testEncode_WithGroupArtifactTopicAndEvent() {
+        var mockEncoder = mock(EventProtocolEncoder.class);
+        var event = new Object();
+        when(mockEncoder.isCodingSupported(GROUP_ID, ARTIFACT_ID, TOPIC))
+            .thenReturn(false);
+        when(mockEncoder.encode(GROUP_ID, ARTIFACT_ID, TOPIC, event))
+            .thenCallRealMethod();
+        when(mockEncoder.codersKey(GROUP_ID, ARTIFACT_ID, TOPIC))
+            .thenCallRealMethod();
+
+        assertThatThrownBy(() -> mockEncoder.encode(GROUP_ID, ARTIFACT_ID, TOPIC, event))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("Unsupported: groupId:artifactId:topic");
+
+        // test with event null
+        when(mockEncoder.isCodingSupported(GROUP_ID, ARTIFACT_ID, TOPIC))
+            .thenReturn(true);
+        when(mockEncoder.codersKey(GROUP_ID, ARTIFACT_ID, TOPIC))
+            .thenCallRealMethod();
+        when(mockEncoder.encode(GROUP_ID, ARTIFACT_ID, TOPIC, null))
+            .thenCallRealMethod();
+
+        assertThatThrownBy(() -> mockEncoder.encode(GROUP_ID, ARTIFACT_ID, TOPIC, null))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("Event cannot be null or empty");
+    }
+
+    @Test
+    void testEncode_WithGroupArtifactTopicAndEvent_ReturnJson() {
+        var mockEncoder = mock(EventProtocolEncoder.class);
+        var event = new Object();
+        var myKey = "group:artifact:topic";
+
+        // test with event null
+        when(mockEncoder.isCodingSupported(GROUP_ID, ARTIFACT_ID, TOPIC)).thenReturn(true);
+        when(mockEncoder.codersKey(GROUP_ID, ARTIFACT_ID, TOPIC)).thenReturn(myKey);
+        when(mockEncoder.encode(GROUP_ID, ARTIFACT_ID, TOPIC, event)).thenCallRealMethod();
+        when(mockEncoder.encodeInternal(myKey, event)).thenCallRealMethod();
+
+        var mockToolset = mock(ProtocolCoderToolset.class);
+        when(mockToolset.encode(event)).thenReturn("{\"json\":\"true\"}");
+
+        HashMap<String, ProtocolCoderToolset> coders = new HashMap<>();
+        coders.put(myKey, mockToolset);
+        ReflectionTestUtils.setField(mockEncoder, "coders", coders);
+
+        var result = mockEncoder.encode(GROUP_ID, ARTIFACT_ID, TOPIC, event);
+        assertNotNull(result);
+        assertEquals("{\"json\":\"true\"}", result);
+    }
+
+    @Test
+    void testEncode_WithTopicAndEvent() {
+        var event = new Object();
+
+        assertThatThrownBy(() -> encoder.encode(null, event))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("Invalid Topic");
+
+        assertThatThrownBy(() -> encoder.encode("", event))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("Invalid Topic");
+
+        assertThatThrownBy(() -> encoder.encode(TOPIC, null))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("Event cannot be null or empty");
+
+        assertThatThrownBy(() -> encoder.encode(TOPIC, event))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("no reverse coder has been found");
+    }
+
+    @Test
+    void testEncode_WithTopicEncodedClassAndDroolsController() {
+        var encodedClass = new Object();
+        var droolsController = new NullDroolsController();
+
+        assertThatThrownBy(() -> encoder.encode(null, encodedClass, droolsController))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("Invalid Topic");
+
+        assertThatThrownBy(() -> encoder.encode("", encodedClass, droolsController))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("Invalid Topic");
+
+        assertThatThrownBy(() -> encoder.encode(TOPIC, null, droolsController))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("Invalid encoded class");
+
+        assertThatThrownBy(() -> encoder.encode(TOPIC, encodedClass, droolsController))
+            .isInstanceOf(UnsupportedOperationException.class)
+            .hasMessageContaining("Cannot encode with gson");
+    }
+
+    @Test
+    void testEncode_WithTopicEncodedClassAndDroolsController_ReturnNullJson() {
+        var encodedClass = new Object();
+        var droolsController = new NullDroolsController();
+        var mockCoderTools = mock(ProtocolCoderToolset.class);
+        when(mockCoderTools.encode(encodedClass)).thenReturn(null);
+
+        var mockEncoder = mock(EventProtocolEncoder.class);
+        when(mockEncoder.codersKey(anyString(), anyString(), anyString())).thenReturn("myKey");
+        when(mockEncoder.encodeInternal("myKey", encodedClass)).thenCallRealMethod();
+        when(mockEncoder.encode(TOPIC, encodedClass, droolsController)).thenCallRealMethod();
+
+        HashMap<String, ProtocolCoderToolset> coders = new HashMap<>();
+        coders.put("myKey", mockCoderTools);
+        ReflectionTestUtils.setField(mockEncoder, "coders", coders);
+
+        assertThatThrownBy(() -> mockEncoder.encode(TOPIC, encodedClass, droolsController))
+            .isInstanceOf(UnsupportedOperationException.class)
+            .hasMessageContaining("Cannot encode with gson");
+    }
+
+    @Test
+    void droolsCreators() {
+        var encodedClass = new Object();
+        assertTrue(encoder.droolsCreators(TOPIC, encodedClass).isEmpty());
+    }
+
+    @Test
+    void droolsCreators_ContainsReverseKey() {
+        var encodedClass = new Object();
+        var mockDecoder = mock(EventProtocolDecoder.class);
+        when(mockDecoder.droolsCreators(TOPIC, encodedClass)).thenCallRealMethod();
+        when(mockDecoder.reverseCodersKey(TOPIC, encodedClass.getClass().getName()))
+            .thenReturn("topic:java.lang.Object");
+
+        HashMap<String, List<ProtocolCoderToolset>> reverseCoders = new HashMap<>();
+        reverseCoders.put("topic:java.lang.Object", List.of());
+        ReflectionTestUtils.setField(mockDecoder, "reverseCoders", reverseCoders);
+
+        assertThatThrownBy(() -> mockDecoder.droolsCreators(TOPIC, encodedClass))
+            .isInstanceOf(IllegalStateException.class)
+            .hasMessageContaining("No Encoders toolsets available for topic:java.lang.Object");
+    }
+
+    @Test
+    void droolsCreators_ContainsReverseKey_ReturnControllers() {
+        var encodedClass = new Object();
+        var mockDecoder = mock(EventProtocolDecoder.class);
+        when(mockDecoder.droolsCreators(TOPIC, encodedClass)).thenCallRealMethod();
+        when(mockDecoder.reverseCodersKey(TOPIC, encodedClass.getClass().getName()))
+            .thenReturn("group:artifact:topic");
+
+        var toolset = mock(ProtocolCoderToolset.class);
+        when(toolset.getGroupId()).thenReturn(GROUP_ID);
+        when(toolset.getArtifactId()).thenReturn(ARTIFACT_ID);
+
+        var mockCoders = mock(EventProtocolCoder.CoderFilters.class);
+        when(mockCoders.getFactClass()).thenReturn("java.lang.Object");
+        when(mockCoders.getModelClassLoaderHash()).thenReturn(1);
+        when(toolset.getCoders()).thenReturn(List.of(mockCoders));
+
+        HashMap<String, List<ProtocolCoderToolset>> reverseCoders = new HashMap<>();
+        var toolsetList = new ArrayList<ProtocolCoderToolset>();
+        toolsetList.add(toolset);
+        reverseCoders.put("group:artifact:topic", toolsetList);
+        ReflectionTestUtils.setField(mockDecoder, "reverseCoders", reverseCoders);
+
+        var mockDroolsController = mock(DroolsController.class);
+        when(mockDroolsController.ownsCoder(encodedClass.getClass(), 1)).thenReturn(true);
+
+        var mockFactory = mock(DroolsControllerFactory.class);
+        when(mockFactory.get(GROUP_ID, ARTIFACT_ID, "")).thenReturn(mockDroolsController);
+
+        try (MockedStatic<DroolsControllerConstants> factory = Mockito.mockStatic(DroolsControllerConstants.class)) {
+            factory.when(DroolsControllerConstants::getFactory).thenReturn(mockFactory);
+            assertEquals(mockFactory, DroolsControllerConstants.getFactory());
+            assertFalse(mockDecoder.droolsCreators(TOPIC, encodedClass).isEmpty());
+        }
+    }
+
+    @Test
+    void testGetFilters_WithGroupArtifactAndTopic() {
+        assertThatThrownBy(() -> encoder.getFilters(GROUP_ID, ARTIFACT_ID, TOPIC))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("Unsupported: groupId:artifactId:topic");
+
+        var mockEncoder = mock(EventProtocolEncoder.class);
+        when(mockEncoder.isCodingSupported(GROUP_ID, ARTIFACT_ID, TOPIC)).thenReturn(true);
+        when((mockEncoder.codersKey(GROUP_ID, ARTIFACT_ID, TOPIC))).thenCallRealMethod();
+        when(mockEncoder.getFilters(GROUP_ID, ARTIFACT_ID, TOPIC)).thenCallRealMethod();
+
+        HashMap<String, ProtocolCoderToolset> coders = new HashMap<>();
+        var mockCoderTools = mock(ProtocolCoderToolset.class);
+        when(mockCoderTools.getCoders()).thenReturn(List.of());
+        coders.put(VALID_KEY, mockCoderTools);
+        ReflectionTestUtils.setField(mockEncoder, "coders", coders);
+
+        assertTrue(mockEncoder.getFilters(GROUP_ID, ARTIFACT_ID, TOPIC).isEmpty());
+    }
+
+    @Test
+    void testGetFilters_WithGroupAndArtifact() {
+        assertTrue(encoder.getFilters(GROUP_ID, ARTIFACT_ID).isEmpty());
+
+        assertThatThrownBy(() -> encoder.getFilters("", ARTIFACT_ID))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("Invalid group");
+
+        assertThatThrownBy(() -> encoder.getFilters(GROUP_ID, ""))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("Invalid artifact");
+    }
+
+    @Test
+    void testGetFilters_WithGroupArtifactTopicAndClassName() {
+        assertThatThrownBy(() -> encoder.getFilters(GROUP_ID, ARTIFACT_ID, TOPIC, "className"))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("Unsupported: groupId:artifactId:topic");
+    }
+
+    @Test
+    void testGetFilters_WithGroupArtifactTopicAndClassNameNull() {
+        var mockEncoder = mock(EventProtocolEncoder.class);
+        when(mockEncoder.isCodingSupported(GROUP_ID, ARTIFACT_ID, TOPIC)).thenReturn(true);
+        when(mockEncoder.getFilters(GROUP_ID, ARTIFACT_ID, TOPIC, ""))
+            .thenCallRealMethod();
+
+        assertThatThrownBy(() -> mockEncoder.getFilters(GROUP_ID, ARTIFACT_ID, TOPIC, ""))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("classname must be provided");
+    }
+
+    @Test
+    void testGetFilters_WithGroupArtifactTopicAndClassName_ReturnValue() {
+        var mockEncoder = mock(EventProtocolEncoder.class);
+        when(mockEncoder.isCodingSupported(GROUP_ID, ARTIFACT_ID, TOPIC)).thenReturn(true);
+        when(mockEncoder.getFilters(GROUP_ID, ARTIFACT_ID, TOPIC, "className"))
+            .thenCallRealMethod();
+        when((mockEncoder.codersKey(GROUP_ID, ARTIFACT_ID, TOPIC))).thenCallRealMethod();
+
+        HashMap<String, ProtocolCoderToolset> coders = new HashMap<>();
+        var mockCoderTools = mock(ProtocolCoderToolset.class);
+        when(mockCoderTools.getCoder("className")).thenReturn(null);
+        coders.put(VALID_KEY, mockCoderTools);
+        ReflectionTestUtils.setField(mockEncoder, "coders", coders);
+
+        assertNull(mockEncoder.getFilters(GROUP_ID, ARTIFACT_ID, TOPIC, "className"));
+    }
+
+    @Test
+    void testGetCoders_ReturnObject() {
+        var mockEncoder = mock(EventProtocolEncoder.class);
+        when(mockEncoder.isCodingSupported(GROUP_ID, ARTIFACT_ID, TOPIC)).thenReturn(true);
+        when(mockEncoder.getCoders(GROUP_ID, ARTIFACT_ID, TOPIC))
+            .thenCallRealMethod();
+        HashMap<String, ProtocolCoderToolset> coders = new HashMap<>();
+        ReflectionTestUtils.setField(mockEncoder, "coders", coders);
+
+        assertNull(mockEncoder.getCoders(GROUP_ID, ARTIFACT_ID, TOPIC));
+    }
+
+    @Test
+    void testGetCoders_ReturnList() {
+        assertThatThrownBy(() -> encoder.getCoders("", ARTIFACT_ID))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("Invalid group");
+
+        assertThatThrownBy(() -> encoder.getCoders(GROUP_ID, ""))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("Invalid artifact");
+
+        assertTrue(encoder.getCoders(GROUP_ID, ARTIFACT_ID).isEmpty());
+
+        // mock a successful return
+        var mockEncoder = mock(EventProtocolEncoder.class);
+        HashMap<String, ProtocolCoderToolset> coders = new HashMap<>();
+        var params = mock(EventProtocolParams.class);
+        coders.put(VALID_KEY, new GsonProtocolCoderToolset(params, "controllerId"));
+        ReflectionTestUtils.setField(mockEncoder, "coders", coders);
+        when(mockEncoder.codersKey(GROUP_ID, ARTIFACT_ID, "")).thenCallRealMethod();
+        when(mockEncoder.getCoders(GROUP_ID, ARTIFACT_ID)).thenCallRealMethod();
+
+        var resultList = mockEncoder.getCoders(GROUP_ID, ARTIFACT_ID);
+        assertFalse(resultList.isEmpty());
+        assertEquals(1, resultList.size());
+
+        var emptyResult = mockEncoder.getCoders("group2", "artifact2");
+        assertTrue(emptyResult.isEmpty());
+    }
+
+    @Test
+    void testGetReverseFilters() {
+        assertThatThrownBy(() -> decoder.getReverseFilters("", "codedClass"))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("Invalid Topic");
+
+        assertThatThrownBy(() -> decoder.getReverseFilters(TOPIC, ""))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("class must be provided");
+
+        assertTrue(decoder.getReverseFilters(TOPIC, "codedClass").isEmpty());
+    }
+
+    @Test
+    void testGetReverseFilters_ReturnToolset() {
+        var mockDecoder = mock(EventProtocolDecoder.class);
+
+        // mock a successful return
+        HashMap<String, List<ProtocolCoderToolset>> reverseCoders = new HashMap<>();
+        var params = mock(EventProtocolParams.class);
+        var toolset = new GsonProtocolCoderToolset(params, "controllerId");
+        reverseCoders.put("topic:codedClass", List.of(toolset));
+        ReflectionTestUtils.setField(mockDecoder, "reverseCoders", reverseCoders);
+
+        when(mockDecoder.reverseCodersKey(TOPIC, "codedClass")).thenReturn("topic:codedClass");
+        when(mockDecoder.getReverseFilters(TOPIC, "codedClass")).thenCallRealMethod();
+
+        var resultList = mockDecoder.getReverseFilters(TOPIC, "codedClass");
+        assertFalse(resultList.isEmpty());
+        assertEquals(1, resultList.size());
+    }
+
+    @Test
+    void testGetDroolsController_Exception() {
+        var fact = new Object();
+        assertThatThrownBy(() -> decoder.getDroolsController("", fact))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("Invalid Topic");
+
+        assertThatThrownBy(() -> decoder.getDroolsController(TOPIC, null))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("class must be provided");
+
+        assertThatThrownBy(() -> decoder.getDroolsController(TOPIC, fact))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("Unsupported topic topic and encodedClass class java.lang.Object");
+    }
+
+    @Test
+    void testGetDroolsController_ReturnObject() {
+        var mockDecoder = mock(EventProtocolDecoder.class);
+        var droolsController = new NullDroolsController();
+        var droolsController2 = new NullDroolsController();
+        var fact = new Object();
+
+        // mock first call to return only one controller, then second call should return 2 controllers
+        when(mockDecoder.getDroolsControllers(TOPIC, fact))
+            .thenReturn(List.of(droolsController))
+            .thenReturn(List.of(droolsController, droolsController2));
+        when(mockDecoder.getDroolsController(TOPIC, fact)).thenCallRealMethod();
+
+        var result = mockDecoder.getDroolsController(TOPIC, fact);
+        assertNotNull(result);
+
+        // second call supposed to return 2 controllers internally, but still return 1 item
+        var result2 = mockDecoder.getDroolsController(TOPIC, fact);
+        assertNotNull(result2);
+    }
+
+    @Test
+    void testGetDroolsControllers_Exception() {
+        var fact = new Object();
+        assertThatThrownBy(() -> decoder.getDroolsControllers("", fact))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("Invalid Topic");
+
+        assertThatThrownBy(() -> decoder.getDroolsControllers(TOPIC, null))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("class must be provided");
+
+        assertTrue(decoder.getDroolsControllers(TOPIC, fact).isEmpty());
+    }
+
+    @Test
+    void testGetDroolsControllers_ReturnValues() {
+        var mockDecoder = mock(EventProtocolDecoder.class);
+        var droolsController = new NullDroolsController();
+        var droolsController2 = new NullDroolsController();
+        var fact = new Object();
+
+        // mock first call to return only one controller, then second call should return 2 controllers
+        when(mockDecoder.droolsCreators(TOPIC, fact))
+            .thenReturn(List.of(droolsController))
+            .thenReturn(List.of(droolsController, droolsController2));
+        when(mockDecoder.getDroolsControllers(TOPIC, fact)).thenCallRealMethod();
+
+        var result = mockDecoder.getDroolsControllers(TOPIC, fact);
+        assertEquals(1, result.size());
+
+        // second call supposed to return 2 controllers
+        var result2 = mockDecoder.getDroolsControllers(TOPIC, fact);
+        assertEquals(2, result2.size());
+    }
+
+    @Test
+    void testRemove() {
+        var mockDecoder = mock(EventProtocolDecoder.class);
+        doCallRealMethod().when(mockDecoder).remove(GROUP_ID, ARTIFACT_ID, TOPIC);
+        when(mockDecoder.codersKey(GROUP_ID, ARTIFACT_ID, TOPIC)).thenCallRealMethod();
+        when(mockDecoder.reverseCodersKey(TOPIC, "className")).thenReturn(INVALID_KEY);
+
+        var toolset = mock(ProtocolCoderToolset.class);
+        var mockCoders = new EventProtocolCoder.CoderFilters("className", mock(JsonProtocolFilter.class), 1);
+        when(toolset.getCoders()).thenReturn(List.of(mockCoders));
+
+        HashMap<String, ProtocolCoderToolset> coders = new HashMap<>();
+        coders.put(VALID_KEY, toolset);
+        ReflectionTestUtils.setField(mockDecoder, "coders", coders);
+        HashMap<String, List<ProtocolCoderToolset>> reverseCoders = new HashMap<>();
+        reverseCoders.put(VALID_KEY, new ArrayList<>(List.of(toolset)));
+        ReflectionTestUtils.setField(mockDecoder, "reverseCoders", reverseCoders);
+
+        assertDoesNotThrow(() -> mockDecoder.remove(GROUP_ID, ARTIFACT_ID, TOPIC));
+        assertEquals(1, mockDecoder.reverseCoders.size());
+        assertTrue(mockDecoder.coders.isEmpty());
+    }
+
+    @Test
+    void testRemove2() {
+        var myKey = "group:artifact:topic";
+        var mockDecoder = mock(EventProtocolDecoder.class);
+        doCallRealMethod().when(mockDecoder).remove(GROUP_ID, ARTIFACT_ID, TOPIC);
+        when(mockDecoder.codersKey(GROUP_ID, ARTIFACT_ID, TOPIC)).thenReturn(myKey);
+        when(mockDecoder.reverseCodersKey(TOPIC, "className")).thenReturn(myKey);
+
+        var toolset = mock(ProtocolCoderToolset.class);
+        var mockCoders = new EventProtocolCoder.CoderFilters("className", mock(JsonProtocolFilter.class), 1);
+        when(toolset.getCoders()).thenReturn(List.of(mockCoders));
+
+        HashMap<String, ProtocolCoderToolset> coders = new HashMap<>();
+        coders.put(myKey, toolset);
+        ReflectionTestUtils.setField(mockDecoder, "coders", coders);
+        HashMap<String, List<ProtocolCoderToolset>> reverseCoders = new HashMap<>();
+        reverseCoders.put(myKey, new ArrayList<>());
+        ReflectionTestUtils.setField(mockDecoder, "reverseCoders", reverseCoders);
+
+        assertDoesNotThrow(() -> mockDecoder.remove(GROUP_ID, ARTIFACT_ID, TOPIC));
+        assertTrue(mockDecoder.reverseCoders.isEmpty());
+        assertTrue(mockDecoder.coders.isEmpty());
+    }
+
+}
\ No newline at end of file
diff --git a/policy-management/src/test/java/org/onap/policy/drools/protocol/coders/GsonProtocolCoderToolsetTest.java b/policy-management/src/test/java/org/onap/policy/drools/protocol/coders/GsonProtocolCoderToolsetTest.java
new file mode 100644 (file)
index 0000000..4bd2aab
--- /dev/null
@@ -0,0 +1,197 @@
+/*-
+ * ============LICENSE_START===============================================
+ * ONAP
+ * ========================================================================
+ * Copyright (C) 2024 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.protocol.coders;
+
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.junit.jupiter.api.Assertions.assertAll;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonIOException;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSyntaxException;
+import java.lang.reflect.Type;
+import java.time.Instant;
+import java.time.ZonedDateTime;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+import org.mockito.stubbing.Answer;
+import org.onap.policy.drools.controller.DroolsControllerConstants;
+import org.onap.policy.drools.controller.DroolsControllerFactory;
+import org.onap.policy.drools.controller.internal.NullDroolsController;
+import org.springframework.test.util.ReflectionTestUtils;
+
+class GsonProtocolCoderToolsetTest {
+
+    @Test
+    void decode() {
+        var mockGsonToolset = mock(GsonProtocolCoderToolset.class);
+        ReflectionTestUtils.setField(mockGsonToolset, "groupId", "group");
+        ReflectionTestUtils.setField(mockGsonToolset, "artifactId", "artifact");
+        doCallRealMethod().when(mockGsonToolset).decode("json");
+
+        var decoderClass = ProtocolCoderToolsetTest.ThreeStrings.class;
+        var mockGson = mock(Gson.class);
+        when(mockGson.fromJson("json", decoderClass)).thenThrow(new JsonSyntaxException("error"));
+        when(mockGsonToolset.getDecoder()).thenReturn(mockGson);
+
+        var mockCustomCoder = mock(TopicCoderFilterConfiguration.CustomCoder.class);
+        when(mockCustomCoder.getClassContainer()).thenReturn("classContainer");
+        ReflectionTestUtils.setField(mockGsonToolset, "customCoder", mockCustomCoder);
+
+        var mockFilter = mock(EventProtocolCoder.CoderFilters.class);
+        when(mockFilter.getFactClass()).thenReturn("someClassName");
+        when(mockGsonToolset.filter("json")).thenReturn(mockFilter);
+
+        var droolsController = mock(NullDroolsController.class);
+        when(droolsController.fetchModelClass("someClassName"))
+            .thenReturn(null)
+            .thenAnswer((Answer<Class<?>>) invocation -> decoderClass)
+            .thenAnswer((Answer<Class<?>>) invocation -> decoderClass);
+        when(droolsController.fetchModelClass("classContainer")).thenReturn(null);
+
+        var mockFactory = mock(DroolsControllerFactory.class);
+        when(mockFactory.get("group", "artifact", ""))
+            .thenReturn(null)
+            .thenReturn(droolsController);
+
+        try (MockedStatic<DroolsControllerConstants> factory = Mockito.mockStatic(DroolsControllerConstants.class)) {
+            factory.when(DroolsControllerConstants::getFactory).thenReturn(mockFactory);
+            assertEquals(mockFactory, DroolsControllerConstants.getFactory());
+
+            // first call to fail when droolsController returns null
+            assertThatThrownBy(() -> mockGsonToolset.decode("json"))
+                .isInstanceOf(IllegalStateException.class)
+                .hasMessageContaining("no drools-controller to process event");
+
+            // second call to fail when droolsController.fetchModelClass returns null
+            assertThatThrownBy(() -> mockGsonToolset.decode("json"))
+                .isInstanceOf(UnsupportedOperationException.class)
+                .hasMessageContaining("cannot fetch application class someClassName");
+
+            // third call to fail when droolsController.fetchModelClass returns null when using customCoder
+            assertThatThrownBy(() -> mockGsonToolset.decode("json"))
+                .isInstanceOf(UnsupportedOperationException.class)
+                .hasMessageContaining("cannot decode with customCoder: classContainer")
+                .hasMessageContaining("using application class someClassName");
+
+            // set customCoder to null to test default decoder
+            ReflectionTestUtils.setField(mockGsonToolset, "customCoder", null);
+
+            // fourth call to fail when decoder can't parse json
+            assertThatThrownBy(() -> mockGsonToolset.decode("json"))
+                .isInstanceOf(UnsupportedOperationException.class)
+                .hasMessageContaining("cannot decode into");
+        }
+    }
+
+    @Test
+    void encode() {
+        var event = new Object();
+
+        var mockGsonToolset = mock(GsonProtocolCoderToolset.class);
+        ReflectionTestUtils.setField(mockGsonToolset, "groupId", "group");
+        ReflectionTestUtils.setField(mockGsonToolset, "artifactId", "artifact");
+        doCallRealMethod().when(mockGsonToolset).encode(event);
+
+        var mockGson = mock(Gson.class);
+        when(mockGson.toJson(event)).thenThrow(new JsonIOException("error"));
+        when(mockGsonToolset.getEncoder()).thenReturn(mockGson);
+
+        var mockCustomCoder = mock(TopicCoderFilterConfiguration.CustomCoder.class);
+        ReflectionTestUtils.setField(mockGsonToolset, "customCoder", mockCustomCoder);
+
+        var mockFactory = mock(DroolsControllerFactory.class);
+        when(mockFactory.get("group", "artifact", "")).thenReturn(null);
+
+        try (MockedStatic<DroolsControllerConstants> factory = Mockito.mockStatic(DroolsControllerConstants.class)) {
+            factory.when(DroolsControllerConstants::getFactory).thenReturn(mockFactory);
+            assertEquals(mockFactory, DroolsControllerConstants.getFactory());
+
+            // first call to encode fails with droolsController returning null, therefore, can't process event
+            assertThatThrownBy(() -> mockGsonToolset.encode(event))
+                .isInstanceOf(UnsupportedOperationException.class)
+                .hasMessageContaining("event cannot be custom encoded");
+
+            // set customCoder to null to test default encoder
+            ReflectionTestUtils.setField(mockGsonToolset, "customCoder", null);
+
+            // second call to encode fails when gson.toJson raises an exception
+            assertThatThrownBy(() -> mockGsonToolset.encode(event))
+                .isInstanceOf(UnsupportedOperationException.class)
+                .hasMessageContaining("event cannot be encoded");
+        }
+    }
+
+    @Test
+    void test_GsonInstantAdapter() {
+        var instantAdapter = new GsonProtocolCoderToolset.GsonInstantAdapter();
+
+        var currentTime = System.currentTimeMillis();
+        var json = mock(JsonElement.class);
+        when(json.getAsLong()).thenReturn(currentTime);
+
+        var result = instantAdapter.deserialize(json, mock(Type.class), mock(JsonDeserializationContext.class));
+        assertInstanceOf(Instant.class, result);
+        assertEquals(currentTime, result.toEpochMilli());
+
+        var jsonResult = instantAdapter.serialize(result, mock(Type.class), mock(JsonSerializationContext.class));
+        assertInstanceOf(JsonElement.class, jsonResult);
+        assertEquals(currentTime, jsonResult.getAsLong());
+    }
+
+    @Test
+    void test_GsonUtcAdapter() {
+        var utcAdapter = new GsonProtocolCoderToolset.GsonUtcAdapter();
+
+        var currentZone = ZonedDateTime.now();
+        var formattedCurrentZone = ZonedDateTime.now().format(GsonProtocolCoderToolset.format);
+        var json = mock(JsonElement.class);
+        when(json.getAsString()).thenReturn(formattedCurrentZone).thenReturn("invalid json");
+
+        var result = utcAdapter.deserialize(json, mock(Type.class), mock(JsonDeserializationContext.class));
+        assertNotNull(result);
+        assertAll(() -> {
+            assertEquals(currentZone.getYear(), result.getYear());
+            assertEquals(currentZone.getMonth(), result.getMonth());
+            assertEquals(currentZone.getDayOfMonth(), result.getDayOfMonth());
+            assertEquals(currentZone.getHour(), result.getHour());
+            assertEquals(currentZone.getMinute(), result.getMinute());
+            assertEquals(currentZone.getSecond(), result.getSecond());
+        });
+
+        // when json.getAsString returns invalid json, should fail and return null
+        assertNull(utcAdapter.deserialize(json, mock(Type.class), mock(JsonDeserializationContext.class)));
+
+        var result2 = utcAdapter.serialize(result, mock(Type.class), mock(JsonSerializationContext.class));
+        assertNotNull(result2);
+        assertEquals(formattedCurrentZone, result2.getAsString());
+    }
+}
\ No newline at end of file
diff --git a/policy-management/src/test/java/org/onap/policy/drools/protocol/coders/MultiplexorEventProtocolCoderTest.java b/policy-management/src/test/java/org/onap/policy/drools/protocol/coders/MultiplexorEventProtocolCoderTest.java
new file mode 100644 (file)
index 0000000..c64e9bc
--- /dev/null
@@ -0,0 +1,308 @@
+/*-
+ * ============LICENSE_START===============================================
+ * ONAP
+ * ========================================================================
+ * Copyright (C) 2024 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.protocol.coders;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.onap.policy.drools.controller.DroolsController;
+import org.springframework.test.util.ReflectionTestUtils;
+
+class MultiplexorEventProtocolCoderTest {
+
+    @Mock
+    EventProtocolEncoder encoder;
+
+    @Mock
+    EventProtocolDecoder decoder;
+
+    MultiplexorEventProtocolCoder coder = new MultiplexorEventProtocolCoder();
+
+    AutoCloseable closeable;
+
+    private static final String GROUP_ID = "group";
+    private static final String ARTIFACT_ID = "artifact";
+    private static final String TOPIC = "topic";
+
+    @BeforeEach
+    void setUp() {
+        closeable = MockitoAnnotations.openMocks(this);
+        ReflectionTestUtils.setField(coder, "encoders", encoder);
+        ReflectionTestUtils.setField(coder, "decoders", decoder);
+    }
+
+    @AfterEach
+    void tearDown() throws Exception {
+        closeable.close();
+    }
+
+    @Test
+    void addDecoder() {
+        var mockParams = mock(EventProtocolParams.class);
+        doNothing().when(decoder).add(mockParams);
+
+        assertDoesNotThrow(() -> coder.addDecoder(mockParams));
+    }
+
+    @Test
+    void addEncoder() {
+        var mockParams = mock(EventProtocolParams.class);
+        doNothing().when(encoder).add(mockParams);
+
+        assertDoesNotThrow(() -> coder.addEncoder(mockParams));
+    }
+
+    @Test
+    void removeDecoders() {
+        doNothing().when(decoder).remove(GROUP_ID, ARTIFACT_ID, TOPIC);
+        assertDoesNotThrow(() -> coder.removeDecoders(GROUP_ID, ARTIFACT_ID, TOPIC));
+    }
+
+    @Test
+    void removeEncoders() {
+        doNothing().when(encoder).remove(GROUP_ID, ARTIFACT_ID, TOPIC);
+        assertDoesNotThrow(() -> coder.removeEncoders(GROUP_ID, ARTIFACT_ID, TOPIC));
+    }
+
+    @Test
+    void isDecodingSupported() {
+        HashMap<String, ProtocolCoderToolset> coders = new HashMap<>();
+        coders.put("otherGroup:artifact:topic", mock(ProtocolCoderToolset.class));
+        ReflectionTestUtils.setField(decoder, "coders", coders);
+        when(decoder.codersKey(GROUP_ID, ARTIFACT_ID, TOPIC)).thenCallRealMethod();
+        when(decoder.isCodingSupported(GROUP_ID, ARTIFACT_ID, TOPIC))
+            .thenReturn(true)
+            .thenCallRealMethod();
+        assertTrue(coder.isDecodingSupported(GROUP_ID, ARTIFACT_ID, TOPIC));
+        assertFalse(coder.isDecodingSupported(GROUP_ID, ARTIFACT_ID, TOPIC));
+    }
+
+    @Test
+    void isEncodingSupported() {
+        HashMap<String, ProtocolCoderToolset> coders = new HashMap<>();
+        coders.put("otherGroup:artifact:topic", mock(ProtocolCoderToolset.class));
+        ReflectionTestUtils.setField(encoder, "coders", coders);
+        when(encoder.codersKey(GROUP_ID, ARTIFACT_ID, TOPIC)).thenCallRealMethod();
+        when(encoder.isCodingSupported(GROUP_ID, ARTIFACT_ID, TOPIC))
+            .thenReturn(true)
+            .thenCallRealMethod();
+        assertTrue(coder.isEncodingSupported(GROUP_ID, ARTIFACT_ID, TOPIC));
+        assertFalse(coder.isEncodingSupported(GROUP_ID, ARTIFACT_ID, TOPIC));
+    }
+
+    @Test
+    void decode() {
+        when(decoder.decode(GROUP_ID, ARTIFACT_ID, TOPIC, "{}"))
+            .thenReturn(new Object())
+            .thenCallRealMethod();
+        when(decoder.isCodingSupported(GROUP_ID, ARTIFACT_ID, TOPIC)).thenReturn(false);
+
+        // first mock call to return directly new Object()
+        assertNotNull(coder.decode(GROUP_ID, ARTIFACT_ID, TOPIC, "{}"));
+
+        // second mock call to check isCodingSupport return false, then throws exception
+        assertThrows(IllegalArgumentException.class,
+            () -> coder.decode(GROUP_ID, ARTIFACT_ID, TOPIC, "{}"));
+    }
+
+    @Test
+    void encode() {
+        var event = new Object();
+        when(encoder.encode(GROUP_ID, ARTIFACT_ID, TOPIC, event))
+            .thenReturn("{}")
+            .thenCallRealMethod();
+        when(encoder.isCodingSupported(GROUP_ID, ARTIFACT_ID, TOPIC)).thenReturn(false);
+
+        // first mock call to return directly new Object()
+        assertNotNull(coder.encode(GROUP_ID, ARTIFACT_ID, TOPIC, event));
+
+        // second mock call to check isCodingSupport return false, then throws exception
+        assertThrows(IllegalArgumentException.class,
+            () -> coder.encode(GROUP_ID, ARTIFACT_ID, TOPIC, event));
+    }
+
+    @Test
+    void encode_WithTopicAndEvent() {
+        var event = new Object();
+        when(encoder.encode(TOPIC, event)).thenReturn("{}");
+
+        var result = coder.encode(TOPIC, event);
+        assertNotNull(result);
+        assertInstanceOf(String.class, result);
+    }
+
+    @Test
+    void encode_WithTopicEncodedClassAndController() {
+        var event = new Object();
+        var controller = mock(DroolsController.class);
+        when(encoder.encode(TOPIC, event, controller)).thenReturn("{}");
+
+        var result = coder.encode(TOPIC, event, controller);
+        assertNotNull(result);
+        assertInstanceOf(String.class, result);
+    }
+
+    @Test
+    void getDecoderFilters() {
+        when(decoder.getFilters(GROUP_ID, ARTIFACT_ID, TOPIC))
+            .thenReturn(new ArrayList<>())
+            .thenCallRealMethod();
+        when(decoder.isCodingSupported(GROUP_ID, ARTIFACT_ID, TOPIC)).thenReturn(false);
+
+        // first mock call return a list
+        var result = coder.getDecoderFilters(GROUP_ID, ARTIFACT_ID, TOPIC);
+        assertTrue(result.isEmpty());
+
+        // second call goes for real method, with isCodingSupported mocked to false, exception is thrown
+        assertThrows(IllegalArgumentException.class,
+            () -> coder.getDecoderFilters(GROUP_ID, ARTIFACT_ID, TOPIC));
+    }
+
+    @Test
+    void testGetDecoderFilters_WithGroupArtifactTopicAndClassName() {
+        when(decoder.getFilters(GROUP_ID, ARTIFACT_ID, TOPIC, "className"))
+            .thenReturn(mock(EventProtocolCoder.CoderFilters.class))
+            .thenCallRealMethod();
+        when(decoder.isCodingSupported(GROUP_ID, ARTIFACT_ID, TOPIC)).thenReturn(false);
+
+        // first mock call return a mock object
+        assertNotNull(coder.getDecoderFilters(GROUP_ID, ARTIFACT_ID, TOPIC, "className"));
+
+        // second call goes for real method, with isCodingSupported mocked to false, exception is thrown
+        assertThrows(IllegalArgumentException.class,
+            () -> coder.getDecoderFilters(GROUP_ID, ARTIFACT_ID, TOPIC, "className"));
+    }
+
+    @Test
+    void testGetDecoderFilters_WithGroupAndArtifact() {
+        when(decoder.getFilters(GROUP_ID, ARTIFACT_ID)).thenReturn(new ArrayList<>());
+
+        assertThat(coder.getDecoderFilters(GROUP_ID, ARTIFACT_ID, TOPIC)).isEmpty();
+    }
+
+    @Test
+    void getDecoders() {
+        when(decoder.getCoders(GROUP_ID, ARTIFACT_ID, TOPIC))
+            .thenReturn(mock(ProtocolCoderToolset.class))
+            .thenCallRealMethod();
+        when(decoder.isCodingSupported(GROUP_ID, ARTIFACT_ID, TOPIC)).thenReturn(false);
+
+        assertNotNull(coder.getDecoders(GROUP_ID, ARTIFACT_ID, TOPIC));
+        assertThrows(IllegalArgumentException.class,
+            () -> coder.getDecoders(GROUP_ID, ARTIFACT_ID, TOPIC));
+    }
+
+    @Test
+    void testGetDecoders_WithGroupAndArtifact() {
+        when(decoder.getCoders(GROUP_ID, ARTIFACT_ID)).thenReturn(new ArrayList<>());
+
+        assertThat(coder.getDecoders(GROUP_ID, ARTIFACT_ID)).isEmpty();
+    }
+
+    @Test
+    void getEncoderFilters() {
+        when(encoder.getFilters(GROUP_ID, ARTIFACT_ID, TOPIC))
+            .thenReturn(new ArrayList<>())
+            .thenCallRealMethod();
+        when(encoder.isCodingSupported(GROUP_ID, ARTIFACT_ID, TOPIC)).thenReturn(false);
+
+        // first mock call return a list
+        var result = coder.getEncoderFilters(GROUP_ID, ARTIFACT_ID, TOPIC);
+        assertTrue(result.isEmpty());
+
+        // second call goes for real method, with isCodingSupported mocked to false, exception is thrown
+        assertThrows(IllegalArgumentException.class,
+            () -> coder.getEncoderFilters(GROUP_ID, ARTIFACT_ID, TOPIC));
+    }
+
+    @Test
+    void testGetEncoderFilters_WithGroupArtifactTopicAndClassName() {
+        when(encoder.getFilters(GROUP_ID, ARTIFACT_ID, TOPIC, "className"))
+            .thenReturn(mock(EventProtocolCoder.CoderFilters.class))
+            .thenCallRealMethod();
+        when(encoder.isCodingSupported(GROUP_ID, ARTIFACT_ID, TOPIC)).thenReturn(false);
+
+        // first mock call return a mock object
+        assertNotNull(coder.getEncoderFilters(GROUP_ID, ARTIFACT_ID, TOPIC, "className"));
+
+        // second call goes for real method, with isCodingSupported mocked to false, exception is thrown
+        assertThrows(IllegalArgumentException.class,
+            () -> coder.getEncoderFilters(GROUP_ID, ARTIFACT_ID, TOPIC, "className"));
+    }
+
+    @Test
+    void testGetEncoderFilters_WithGroupAndArtifact() {
+        when(encoder.getFilters(GROUP_ID, ARTIFACT_ID)).thenReturn(new ArrayList<>());
+
+        assertThat(coder.getEncoderFilters(GROUP_ID, ARTIFACT_ID, TOPIC)).isEmpty();
+    }
+
+    @Test
+    void getReverseEncoderFilters() {
+        when(encoder.getReverseFilters(TOPIC, "codedClass")).thenReturn(new ArrayList<>());
+        assertThat(coder.getReverseEncoderFilters(TOPIC, "codedClass")).isEmpty();
+    }
+
+    @Test
+    void getDroolsController() {
+        var fact = new Object();
+        // mock success
+        when(encoder.getDroolsController(TOPIC, fact))
+            .thenReturn(mock(DroolsController.class))
+            .thenCallRealMethod();
+        // mock failure
+        when(encoder.getDroolsControllers(TOPIC, fact)).thenReturn(new ArrayList<>());
+
+        // first call gets mock DroolsController - pass
+        assertNotNull(coder.getDroolsController(TOPIC, fact));
+        // second call goes through the method, then call inside method that returns empty list, throws an exception
+        assertThrows(IllegalArgumentException.class, () -> coder.getDroolsController(TOPIC, fact));
+    }
+
+    @Test
+    void getDroolsControllers() {
+        var fact = new Object();
+        when(encoder.getDroolsControllers(TOPIC, fact)).thenReturn(new ArrayList<>());
+
+        assertThat(coder.getDroolsControllers(TOPIC, fact)).isEmpty();
+    }
+
+    @Test
+    void testToString() {
+        assertThat(coder.toString())
+            .contains("MultiplexorEventProtocolCoder");
+    }
+}
\ No newline at end of file
index 659965f..cb4397c 100644 (file)
 package org.onap.policy.drools.protocol.coders;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
@@ -53,6 +61,7 @@ import org.onap.policy.drools.protocol.coders.TopicCoderFilterConfiguration.Cust
 import org.onap.policy.drools.util.KieUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.test.util.ReflectionTestUtils;
 
 /**
  * ProtocolCoder Toolset Junits.
@@ -62,12 +71,12 @@ public class ProtocolCoderToolsetTest {
     private static final String JUNIT_PROTOCOL_CODER_TOPIC = JUNIT_PROTOCOL_CODER_ARTIFACT_ID;
     private static final String CONTROLLER_ID = "blah";
 
-    private static final Logger logger = LoggerFactory.getLogger(ProtocolCoderToolset.class);
+    private static final Logger logger = LoggerFactory.getLogger(ProtocolCoderToolsetTest.class);
 
     private static volatile ReleaseId releaseId;
 
     // customCoder has to be public to be accessed in tests below
-    public static final Gson customCoder = new GsonBuilder().create();
+    public static final Gson customCoder = new GsonBuilder().create(); // NOSONAR actually being used in the test
 
     private DroolsController controller;
 
@@ -77,9 +86,9 @@ public class ProtocolCoderToolsetTest {
     @BeforeAll
     public static void setUpClass() throws IOException {
         releaseId = KieUtils.installArtifact(Paths.get(MavenDroolsControllerTest.JUNIT_ECHO_KMODULE_PATH).toFile(),
-                        Paths.get(MavenDroolsControllerTest.JUNIT_ECHO_KMODULE_POM_PATH).toFile(),
-                        MavenDroolsControllerTest.JUNIT_ECHO_KJAR_DRL_PATH,
-                        Paths.get(MavenDroolsControllerTest.JUNIT_ECHO_KMODULE_DRL_PATH).toFile());
+            Paths.get(MavenDroolsControllerTest.JUNIT_ECHO_KMODULE_POM_PATH).toFile(),
+            MavenDroolsControllerTest.JUNIT_ECHO_KJAR_DRL_PATH,
+            Paths.get(MavenDroolsControllerTest.JUNIT_ECHO_KMODULE_DRL_PATH).toFile());
     }
 
     /**
@@ -105,6 +114,55 @@ public class ProtocolCoderToolsetTest {
         testGsonToolset(createFilterSet());
     }
 
+    @Test
+    void testExceptions() {
+        // should fail without params
+        assertThrows(IllegalArgumentException.class,
+            () -> new GsonProtocolCoderToolset(null, "controller"));
+
+        // should fail without controller ID
+        assertThrows(IllegalArgumentException.class,
+            () -> new GsonProtocolCoderToolset(mock(EventProtocolParams.class), ""));
+
+        // set mock under test - always call real method under test
+        var toolset = mock(GsonProtocolCoderToolset.class);
+        when(toolset.getCoder("")).thenCallRealMethod();
+
+        // should fail calling with empty classname
+        assertThatThrownBy(() -> toolset.getCoder(""))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("no classname provided");
+
+        // should fail when trying to add coder with empty event class
+        doCallRealMethod().when(toolset).addCoder(anyString(), any(JsonProtocolFilter.class), anyInt());
+        assertThatThrownBy(() -> toolset.addCoder("", mock(JsonProtocolFilter.class), 1))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("no event class provided");
+
+        // should fail when trying to remove coder with empty event
+        doCallRealMethod().when(toolset).removeCoders(anyString());
+        assertThatThrownBy(() -> toolset.removeCoders(""))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("no event class provided");
+
+        // set coders to empty list
+        when(toolset.filter(anyString())).thenCallRealMethod();
+        ReflectionTestUtils.setField(toolset, "coders", List.of());
+
+        // should fail when trying to find a filter from an empty list
+        assertThatThrownBy(() -> toolset.filter(""))
+            .isInstanceOf(IllegalStateException.class)
+            .hasMessageContaining("No coders available");
+
+        // there is a coder in the list, but can't check if accepts json when coder doesn't have filter
+        var mockCoderFilter = mock(CoderFilters.class);
+        when(mockCoderFilter.getFilter()).thenReturn(null);
+        ReflectionTestUtils.setField(toolset, "coders", List.of(mockCoderFilter));
+
+        assertNull(toolset.filter("json"));
+
+    }
+
     /**
      * Test the Gson toolset.
      *
@@ -112,10 +170,10 @@ public class ProtocolCoderToolsetTest {
      */
     private void testGsonToolset(JsonProtocolFilter protocolFilter) {
         GsonProtocolCoderToolset gsonToolset =
-                        new GsonProtocolCoderToolset(EventProtocolParams.builder().topic(JUNIT_PROTOCOL_CODER_TOPIC)
-                                        .groupId(releaseId.getGroupId()).artifactId(releaseId.getArtifactId())
-                                        .eventClass(ThreeStrings.class.getName()).protocolFilter(protocolFilter)
-                                        .customGsonCoder(null).modelClassLoaderHash(12345678).build(), CONTROLLER_ID);
+            new GsonProtocolCoderToolset(EventProtocolParams.builder().topic(JUNIT_PROTOCOL_CODER_TOPIC)
+                .groupId(releaseId.getGroupId()).artifactId(releaseId.getArtifactId())
+                .eventClass(ThreeStrings.class.getName()).protocolFilter(protocolFilter)
+                .customGsonCoder(null).modelClassLoaderHash(12345678).build(), CONTROLLER_ID);
 
         assertNotNull(gsonToolset.getEncoder());
         assertNotNull(gsonToolset.getDecoder());
@@ -154,7 +212,7 @@ public class ProtocolCoderToolsetTest {
     }
 
     private void decode(JsonProtocolFilter protocolFilter, ProtocolCoderToolset coderToolset,
-                    ThreeStrings triple, String tripleEncoded) {
+                        ThreeStrings triple, String tripleEncoded) {
 
         try {
             coderToolset.decode(tripleEncoded);
@@ -212,7 +270,7 @@ public class ProtocolCoderToolsetTest {
         assertNotNull(coderToolset.getCoder(ThreeStrings.class.getName()).getFilter().getRule());
 
         assertEquals("[?($.third =~ /.*/)]",
-                        coderToolset.getCoder(ThreeStrings.class.getName()).getFilter().getRule());
+            coderToolset.getCoder(ThreeStrings.class.getName()).getFilter().getRule());
     }
 
     private void validateInitialization(JsonProtocolFilter protocolFilter, ProtocolCoderToolset coderToolset) {
@@ -241,16 +299,21 @@ public class ProtocolCoderToolsetTest {
         sinkConfig.put(PolicyEndPointProperties.PROPERTY_NOOP_SINK_TOPICS, JUNIT_PROTOCOL_CODER_TOPIC);
         final List<TopicSink> noopTopics = TopicEndpointManager.getManager().addTopicSinks(sinkConfig);
 
+        Properties droolsControllerConfig = getDroolsControllerConfig();
+
+        return DroolsControllerConstants.getFactory().build(droolsControllerConfig, null, noopTopics);
+    }
+
+    private static Properties getDroolsControllerConfig() {
         Properties droolsControllerConfig = new Properties();
         droolsControllerConfig.put(DroolsPropertyConstants.RULES_GROUPID, releaseId.getGroupId());
         droolsControllerConfig.put(DroolsPropertyConstants.RULES_ARTIFACTID, releaseId.getArtifactId());
         droolsControllerConfig.put(DroolsPropertyConstants.RULES_VERSION, releaseId.getVersion());
         droolsControllerConfig.put(
-                        PolicyEndPointProperties.PROPERTY_NOOP_SINK_TOPICS + "." + JUNIT_PROTOCOL_CODER_TOPIC
-                                        + PolicyEndPointProperties.PROPERTY_TOPIC_EVENTS_SUFFIX,
-                        ThreeStrings.class.getName());
-
-        return DroolsControllerConstants.getFactory().build(droolsControllerConfig, null, noopTopics);
+            PolicyEndPointProperties.PROPERTY_NOOP_SINK_TOPICS + "." + JUNIT_PROTOCOL_CODER_TOPIC
+                + PolicyEndPointProperties.PROPERTY_TOPIC_EVENTS_SUFFIX,
+            ThreeStrings.class.getName());
+        return droolsControllerConfig;
     }
 
     private JsonProtocolFilter createFilterSet() {
diff --git a/policy-management/src/test/java/org/onap/policy/drools/protocol/coders/TopicCoderFilterConfigurationTest.java b/policy-management/src/test/java/org/onap/policy/drools/protocol/coders/TopicCoderFilterConfigurationTest.java
new file mode 100644 (file)
index 0000000..5429a94
--- /dev/null
@@ -0,0 +1,75 @@
+/*-
+ * ============LICENSE_START===============================================
+ * ONAP
+ * ========================================================================
+ * Copyright (C) 2024 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.protocol.coders;
+
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+import java.util.List;
+import org.junit.jupiter.api.Test;
+
+class TopicCoderFilterConfigurationTest {
+
+    @Test
+    void setCustomGsonCoder() {
+        var topic = "topic";
+        var decodeFilter = new TopicCoderFilterConfiguration
+            .PotentialCoderFilter("codedClass", new JsonProtocolFilter("rule"));
+        var customCoder = new TopicCoderFilterConfiguration
+            .CustomGsonCoder("className", "staticCoderField");
+        var topicConfig = new TopicCoderFilterConfiguration(topic, List.of(decodeFilter), customCoder);
+
+        assertNotNull(topicConfig);
+        assertNotNull(topicConfig.getCoderFilters());
+        assertEquals("topic", topicConfig.getTopic());
+
+        assertEquals("className", topicConfig.getCustomGsonCoder().getClassContainer());
+
+        var customCoder2 = new TopicCoderFilterConfiguration.CustomGsonCoder("className2,staticCoderField2");
+        topicConfig.setCustomGsonCoder(customCoder2);
+
+        assertEquals("className2", topicConfig.getCustomGsonCoder().getClassContainer());
+    }
+
+    @Test
+    void setCustomCoder_Exceptions() {
+        assertThatThrownBy(() -> new TopicCoderFilterConfiguration.CustomGsonCoder("", "staticCoderField"))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("No classname to create CustomCoder cannot be created");
+
+        assertThatThrownBy(() -> new TopicCoderFilterConfiguration.CustomGsonCoder("className", ""))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("No staticCoderField to create CustomCoder cannot be created for class className");
+
+        assertThatThrownBy(() -> new TopicCoderFilterConfiguration.CustomGsonCoder(",staticCoderField"))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("No classname to create CustomCoder cannot be created");
+
+        assertThatThrownBy(() -> new TopicCoderFilterConfiguration.CustomGsonCoder("className,"))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("No staticCoderField to create CustomCoder cannot be created for class className");
+
+        assertThatThrownBy(() -> new TopicCoderFilterConfiguration.CustomGsonCoder(""))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("Constructor argument cannot be empty.");
+    }
+}
\ No newline at end of file
index 6a17f26..1ceff3d 100644 (file)
@@ -127,7 +127,6 @@ public class RestManagerTest {
         Properties controllerProps = new Properties();
         PolicyEngineConstants.getManager().createPolicyController(FOO_CONTROLLER, controllerProps);
 
-        // client = HttpClients.createDefault();
         CredentialsProvider provider = new BasicCredentialsProvider();
         UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(TELEMETRY_USER, TELEMETRY_PASSWORD);
         provider.setCredentials(AuthScope.ANY, credentials);
@@ -249,7 +248,7 @@ public class RestManagerTest {
 
     private void requestTest(HttpRequestBase request, int statusCode) throws IOException {
         CloseableHttpResponse resp = client.execute(request);
-        logger.info(request.getRequestLine() + "response code: {}", resp.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", request.getRequestLine(), resp.getStatusLine().getStatusCode());
         assertEquals(statusCode, resp.getStatusLine().getStatusCode());
         request.releaseConnection();
     }
@@ -291,13 +290,13 @@ public class RestManagerTest {
         CloseableHttpResponse response;
         httpGet = new HttpGet(HOST_URL + "/engine/swagger");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(200, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
     }
 
     @Test
-    void testGet() throws IOException {
+    void testGetEngine() throws IOException {
         HttpGet httpGet;
         CloseableHttpResponse response;
 
@@ -306,45 +305,46 @@ public class RestManagerTest {
          * /engine/inputs /engine/properties /engine/environment /engine/switches
          * /engine/controllers
          */
+
         httpGet = new HttpGet(HOST_URL + "/engine");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(200, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
         httpGet = new HttpGet(HOST_URL + "/engine/features");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(200, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
         httpGet = new HttpGet(HOST_URL + "/engine/features/inventory");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(200, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
         httpGet = new HttpGet(HOST_URL + "/engine/features/foobar");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(404, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
         httpGet = new HttpGet(HOST_URL + "/engine/inputs");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(200, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
         httpGet = new HttpGet(HOST_URL + "/engine/properties");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(200, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
         httpGet = new HttpGet(HOST_URL + "/engine/environment");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(200, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
@@ -352,26 +352,32 @@ public class RestManagerTest {
         httpGet = new HttpGet(HOST_URL + "/engine/environment/foo");
         response = client.execute(httpGet);
         String responseBody = this.getResponseBody(response);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
-        logger.info(httpGet.getRequestLine() + " response body: {}", responseBody);
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
+        logger.info("{} response body: {}", httpGet.getRequestLine(), responseBody);
         assertEquals(200, response.getStatusLine().getStatusCode());
         assertEquals("bar", responseBody);
         httpGet.releaseConnection();
 
         httpGet = new HttpGet(HOST_URL + "/engine/switches");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(200, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
         httpGet = new HttpGet(HOST_URL + "/engine/controllers");
         response = client.execute(httpGet);
         responseBody = this.getResponseBody(response);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
-        logger.info(httpGet.getRequestLine() + " response body: {}", responseBody);
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
+        logger.info("{} response body: {}", httpGet.getRequestLine(), responseBody);
         assertEquals(200, response.getStatusLine().getStatusCode());
         assertEquals("[\"" + FOO_CONTROLLER + "\"]", responseBody);
         httpGet.releaseConnection();
+    }
+
+    @Test
+    void testGet_EngineControllers() throws IOException {
+        HttpGet httpGet;
+        CloseableHttpResponse response;
 
         /*
          * GET: /engine/controllers/inventory /engine/controllers/features
@@ -381,39 +387,46 @@ public class RestManagerTest {
          */
         httpGet = new HttpGet(HOST_URL + "/engine/controllers/inventory");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(200, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
         httpGet = new HttpGet(HOST_URL + "/engine/controllers/features");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(200, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
         httpGet = new HttpGet(HOST_URL + "/engine/controllers/features/inventory");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(200, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
         httpGet = new HttpGet(HOST_URL + "/engine/controllers/features/dummy");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(404, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
         httpGet = new HttpGet(HOST_URL + "/engine/controllers/" + FOO_CONTROLLER);
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(200, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
         httpGet = new HttpGet(HOST_URL + "/engine/controllers/nonexistantcontroller");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(404, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
+    }
+
+    @Test
+    void testGet() throws IOException {
+        HttpGet httpGet;
+        CloseableHttpResponse response;
+        String responseBody;
 
         /*
          * GET: /engine/controllers/controllerName/properties
@@ -423,52 +436,45 @@ public class RestManagerTest {
         httpGet = new HttpGet(HOST_URL + "/engine/controllers/" + FOO_CONTROLLER + "/properties");
         response = client.execute(httpGet);
         responseBody = this.getResponseBody(response);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
-        logger.info(httpGet.getRequestLine() + " response code: {}", responseBody);
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), responseBody);
         assertEquals(200, response.getStatusLine().getStatusCode());
         assertEquals("{}", responseBody);
         httpGet.releaseConnection();
 
         httpGet = new HttpGet(HOST_URL + "/engine/controllers/nonexistantcontroller/properties");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(404, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
         httpGet = new HttpGet(HOST_URL + "/engine/controllers/" + FOO_CONTROLLER + "/inputs");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(200, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
         httpGet = new HttpGet(HOST_URL + "/engine/controllers/" + FOO_CONTROLLER + "/switches");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(200, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
         httpGet = new HttpGet(HOST_URL + "/engine/controllers/" + FOO_CONTROLLER + "/drools");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(200, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
         httpGet = new HttpGet(HOST_URL + "/engine/controllers/nonexistantcontroller/drools");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(404, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
-
-        testGetDroolsControllers();
-
-        testGetControllersDecoders();
-
-        testGetTopics();
-
-        testGetEngineTools();
     }
 
-    private static void testGetDroolsControllers() throws IOException {
+    @Test
+    void testGetDroolsControllers() throws IOException {
         CloseableHttpResponse response;
         HttpGet httpGet;
         /*
@@ -480,43 +486,44 @@ public class RestManagerTest {
          */
         httpGet = new HttpGet(HOST_URL + "/engine/controllers/" + FOO_CONTROLLER + "/drools/facts");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(200, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
         httpGet = new HttpGet(HOST_URL + "/engine/controllers/nonexistantcontroller/drools/facts");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(404, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
         httpGet = new HttpGet(HOST_URL + "/engine/controllers/" + FOO_CONTROLLER + "/drools/facts/session");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(200, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
         httpGet = new HttpGet(HOST_URL + "/engine/controllers/" + FOO_CONTROLLER + "/drools/facts/session/factType");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(200, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
         httpGet = new HttpGet(
             HOST_URL + "/engine/controllers/" + FOO_CONTROLLER + "/drools/facts/session/query/queriedEntity");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(200, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
         httpGet = new HttpGet(HOST_URL + "/engine/controllers/dummy" + "/drools/facts/session/query/queriedEntity");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(404, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
     }
 
-    private static void testGetEngineTools() throws IOException {
+    @Test
+    void testGetEngineTools() throws IOException {
         CloseableHttpResponse response;
         HttpGet httpGet;
         /*
@@ -524,24 +531,25 @@ public class RestManagerTest {
          */
         httpGet = new HttpGet(HOST_URL + "/engine/tools/uuid");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(200, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
         httpGet = new HttpGet(HOST_URL + "/engine/tools/loggers");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(200, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
         httpGet = new HttpGet(HOST_URL + "/engine/tools/loggers/ROOT");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(200, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
     }
 
-    private static void testGetControllersDecoders() throws IOException {
+    @Test
+    void testGetControllersDecoders() throws IOException {
         HttpGet httpGet;
         CloseableHttpResponse response;
         /*
@@ -556,68 +564,69 @@ public class RestManagerTest {
          */
         httpGet = new HttpGet(HOST_URL + "/engine/controllers/" + FOO_CONTROLLER + "/decoders");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(200, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
         httpGet = new HttpGet(HOST_URL + "/engine/controllers/nonexistantcontroller/decoders");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(404, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
         httpGet = new HttpGet(HOST_URL + "/engine/controllers/" + FOO_CONTROLLER + "/decoders/filters");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(200, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
         httpGet = new HttpGet(HOST_URL + "/engine/controllers/nonexistantcontroller/decoders/filters");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(404, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
         httpGet = new HttpGet(HOST_URL + "/engine/controllers/" + FOO_CONTROLLER + "/decoders/topic");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(404, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
         httpGet = new HttpGet(HOST_URL + "/engine/controllers/" + FOO_CONTROLLER + "/decoders/topic/filters");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(404, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
         httpGet = new HttpGet(HOST_URL + "/engine/controllers/" + FOO_CONTROLLER + "/decoders/topic/filters/factType");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(404, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
         httpGet = new HttpGet(
             HOST_URL + "/engine/controllers/" + FOO_CONTROLLER + "/decoders/topic/filters/factType/rules");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(404, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
         httpGet = new HttpGet(
             HOST_URL + "/engine/controllers/" + FOO_CONTROLLER + "/decoders/topic/filters/factType/rules/ruleName");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(404, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
         httpGet = new HttpGet(HOST_URL + "/engine/controllers/" + FOO_CONTROLLER + "/encoders");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(200, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
     }
 
-    private static void testGetTopics() throws IOException {
+    @Test
+    void testGetKafkaTopics() throws IOException {
         CloseableHttpResponse response;
         HttpGet httpGet;
         /*
@@ -635,169 +644,186 @@ public class RestManagerTest {
          */
         httpGet = new HttpGet(HOST_URL + "/engine/topics");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(200, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
         httpGet = new HttpGet(HOST_URL + "/engine/topics/switches");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(200, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
         httpGet = new HttpGet(HOST_URL + "/engine/topics/sources");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(200, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
         httpGet = new HttpGet(HOST_URL + "/engine/topics/sinks");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(200, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
         httpGet = new HttpGet(HOST_URL + "/engine/topics/sources/kafka");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(200, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
         httpGet = new HttpGet(HOST_URL + "/engine/topics/sinks/kafka");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(200, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
-        httpGet = new HttpGet(HOST_URL + "/engine/topics/sources/noop");
+        httpGet = new HttpGet(HOST_URL + "/engine/topics/sources/kafka/" + KAFKA_TOPIC);
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(200, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
-        httpGet = new HttpGet(HOST_URL + "/engine/topics/sinks/noop");
+        httpGet = new HttpGet(HOST_URL + "/engine/topics/sources/kafka/foobar");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
-        assertEquals(200, response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
+        assertEquals(500, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
-        httpGet = new HttpGet(HOST_URL + "/engine/topics/sources/kafka/" + KAFKA_TOPIC);
+        httpGet = new HttpGet(HOST_URL + "/engine/topics/sinks/kafka/" + KAFKA_TOPIC);
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(200, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
-        httpGet = new HttpGet(HOST_URL + "/engine/topics/sources/kafka/foobar");
+        httpGet = new HttpGet(HOST_URL + "/engine/topics/sinks/kafka/foobar");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(500, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
-        httpGet = new HttpGet(HOST_URL + "/engine/topics/sinks/kafka/" + KAFKA_TOPIC);
+        httpGet = new HttpGet(HOST_URL + "/engine/topics/sources/kafka/" + KAFKA_TOPIC + "/events");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(200, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
-        httpGet = new HttpGet(HOST_URL + "/engine/topics/sinks/kafka/foobar");
+        httpGet = new HttpGet(HOST_URL + "/engine/topics/sources/kafka/foobar/events");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(500, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
-        httpGet = new HttpGet(HOST_URL + "/engine/topics/sources/noop/" + NOOP_TOPIC);
+        httpGet = new HttpGet(HOST_URL + "/engine/topics/sinks/kafka/" + KAFKA_TOPIC + "/events");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(200, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
-        httpGet = new HttpGet(HOST_URL + "/engine/topics/sources/noop/foobar");
+        httpGet = new HttpGet(HOST_URL + "/engine/topics/sinks/kafka/foobar/events");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(500, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
-        httpGet = new HttpGet(HOST_URL + "/engine/topics/sinks/noop/" + NOOP_TOPIC);
+        httpGet = new HttpGet(HOST_URL + "/engine/topics/sources/kafka/" + KAFKA_TOPIC + "/switches");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(200, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
-        httpGet = new HttpGet(HOST_URL + "/engine/topics/sinks/noop/foobar");
+        httpGet = new HttpGet(HOST_URL + "/engine/topics/sinks/kafka/" + KAFKA_TOPIC + "/switches");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
-        assertEquals(500, response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
+        assertEquals(200, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
+    }
 
-        httpGet = new HttpGet(HOST_URL + "/engine/topics/sources/kafka/" + KAFKA_TOPIC + "/events");
+    @Test
+    void testGetNoopTopics() throws IOException {
+        CloseableHttpResponse response;
+        HttpGet httpGet;
+        /*
+         * GET: /engine/topics
+         * /engine/topics/sources/noop
+         * /engine/topics/sinks/noop
+         * /engine/topics/sources/noop/topic
+         * /engine/topics/sinks/noop/topic
+         * /engine/topics/sources/noop/topic/events
+         * /engine/topics/sinks/noop/topic/events
+         * /engine/topics/sources/noop/topic/switches
+         * /engine/topics/sinks/noop/topic/switches
+         */
+
+        httpGet = new HttpGet(HOST_URL + "/engine/topics/sources/noop");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(200, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
-        httpGet = new HttpGet(HOST_URL + "/engine/topics/sources/kafka/foobar/events");
+        httpGet = new HttpGet(HOST_URL + "/engine/topics/sinks/noop");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
-        assertEquals(500, response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
+        assertEquals(200, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
-        httpGet = new HttpGet(HOST_URL + "/engine/topics/sinks/kafka/" + KAFKA_TOPIC + "/events");
+        httpGet = new HttpGet(HOST_URL + "/engine/topics/sources/noop/" + NOOP_TOPIC);
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(200, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
-        httpGet = new HttpGet(HOST_URL + "/engine/topics/sinks/kafka/foobar/events");
+        httpGet = new HttpGet(HOST_URL + "/engine/topics/sources/noop/foobar");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(500, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
-        httpGet = new HttpGet(HOST_URL + "/engine/topics/sources/noop/" + NOOP_TOPIC + "/events");
+        httpGet = new HttpGet(HOST_URL + "/engine/topics/sinks/noop/" + NOOP_TOPIC);
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(200, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
-        httpGet = new HttpGet(HOST_URL + "/engine/topics/sources/noop/foobar/events");
+        httpGet = new HttpGet(HOST_URL + "/engine/topics/sinks/noop/foobar");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(500, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
-        httpGet = new HttpGet(HOST_URL + "/engine/topics/sinks/noop/" + NOOP_TOPIC + "/events");
+        httpGet = new HttpGet(HOST_URL + "/engine/topics/sources/noop/" + NOOP_TOPIC + "/events");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(200, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
-        httpGet = new HttpGet(HOST_URL + "/engine/topics/sinks/noop/foobar/events");
+        httpGet = new HttpGet(HOST_URL + "/engine/topics/sources/noop/foobar/events");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(500, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
-        httpGet = new HttpGet(HOST_URL + "/engine/topics/sources/kafka/" + KAFKA_TOPIC + "/switches");
+        httpGet = new HttpGet(HOST_URL + "/engine/topics/sinks/noop/" + NOOP_TOPIC + "/events");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(200, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
-        httpGet = new HttpGet(HOST_URL + "/engine/topics/sources/noop/" + NOOP_TOPIC + "/switches");
+        httpGet = new HttpGet(HOST_URL + "/engine/topics/sinks/noop/foobar/events");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
-        assertEquals(200, response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
+        assertEquals(500, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
-        httpGet = new HttpGet(HOST_URL + "/engine/topics/sinks/kafka/" + KAFKA_TOPIC + "/switches");
+        httpGet = new HttpGet(HOST_URL + "/engine/topics/sources/noop/" + NOOP_TOPIC + "/switches");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(200, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
 
         httpGet = new HttpGet(HOST_URL + "/engine/topics/sinks/noop/" + NOOP_TOPIC + "/switches");
         response = client.execute(httpGet);
-        logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode());
+        logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode());
         assertEquals(200, response.getStatusLine().getStatusCode());
         httpGet.releaseConnection();
     }
index 118c4d7..c13a466 100644 (file)
@@ -21,6 +21,7 @@
 
 package org.onap.policy.drools.stats;
 
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
 import org.junit.jupiter.api.Test;
@@ -42,4 +43,17 @@ class PolicyStatsManagerTest {
         assertEquals(1, stats.getSubgroupStats().get("foo").getPolicyExecutedFailCount());
         assertEquals(2, stats.getSubgroupStats().get("blah").getPolicyExecutedFailCount());
     }
+
+    @Test
+    void test_Exceptions() {
+        PolicyStatsManager stats = new PolicyStatsManager();
+        assertThatThrownBy(() -> stats.stat("foo", null))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("transaction is marked non-null but is nul");
+
+        Metric trans = new Metric();
+        assertThatThrownBy(() -> stats.stat(null, trans))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("subGroupName is marked non-null but is null");
+    }
 }
\ No newline at end of file
index 3f26e82..6b76837 100644 (file)
@@ -22,6 +22,7 @@
 package org.onap.policy.drools.stats;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
 import org.junit.jupiter.api.Test;
@@ -74,6 +75,14 @@ class PolicyStatsTest {
         assertThat(stats.getBirthTime()).isLessThanOrEqualTo(trans2.getStartTime().toEpochMilli());
     }
 
+    @Test
+    void test_Exception() {
+        PolicyStats stats = new PolicyStats();
+        assertThatThrownBy(() -> stats.stat(null))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessageContaining("trans is marked non-null but is null");
+    }
+
     private Metric createTrans() {
         Metric trans = new Metric();
         trans.setStartTime(null);
index 615ffe2..8a388df 100644 (file)
@@ -35,7 +35,6 @@ import static org.mockito.Mockito.when;
 import static org.onap.policy.drools.properties.DroolsPropertyConstants.PROPERTY_CONTROLLER_TYPE;
 
 import java.util.Arrays;
-import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
 import java.util.Properties;
@@ -504,9 +503,9 @@ class PolicyControllerFactoryTest {
 
         @Override
         public DroolsController beforeInstance(Properties properties,
-                String groupId, String artifactId, String version,
-                List<TopicCoderFilterConfiguration> decoderConfigurations,
-                List<TopicCoderFilterConfiguration> encoderConfigurations) {
+                                               String groupId, String artifactId, String version,
+                                               List<TopicCoderFilterConfiguration> decoderConfigurations,
+                                               List<TopicCoderFilterConfiguration> encoderConfigurations) {
 
             if (POLICY_CONTROLLER_BUILDER_TAG.equals(properties.getProperty(PROPERTY_CONTROLLER_TYPE))) {
                 return new NullDroolsController();
index 8dae42e..0b88b3f 100644 (file)
@@ -731,7 +731,7 @@ class PolicyEngineManagerTest {
     }
 
     @Test
-    void testUpdatePolicyController() throws Exception {
+    void testUpdatePolicyController_Exceptions() throws Exception {
         assertEquals(controller3, mgr.updatePolicyController(config3));
         verify(engine).createPolicyController(CONTROLLER3, properties);
 
@@ -775,7 +775,10 @@ class PolicyEngineManagerTest {
         setUp();
         when(persist.getControllerProperties(CONTROLLER3)).thenThrow(new LinkageError(EXPECTED));
         assertThatIllegalStateException().isThrownBy(() -> mgr.updatePolicyController(config3));
+    }
 
+    @Test
+    void testUpdatePolicyController() throws Exception {
         /*
          * For remaining tests, the factory will return the controller instead of creating
          * one.
@@ -954,14 +957,7 @@ class PolicyEngineManagerTest {
         assertTrue(mgr.stop());
         verify(prov1).beforeStop(mgr);
         verify(prov2).beforeStop(mgr);
-        verify(controller, never()).stop();
-        verify(source1, never()).stop();
-        verify(sink1, never()).stop();
-        verify(endpoint, never()).stop();
-        verify(server1, never()).stop();
-        verify(client1, never()).stop();
-        verify(prov1, never()).afterStop(mgr);
-        verify(prov2, never()).afterStop(mgr);
+        verifyNeverCalled();
 
         // controller fails to stop - still does everything
         testStop(false, () -> when(controller.stop()).thenReturn(false));
@@ -1999,6 +1995,17 @@ class PolicyEngineManagerTest {
         assertThatThrownBy(() -> verifyAfter.accept(prov2)).isInstanceOf(AssertionError.class);
     }
 
+    private void verifyNeverCalled() {
+        verify(controller, never()).stop();
+        verify(source1, never()).stop();
+        verify(sink1, never()).stop();
+        verify(endpoint, never()).stop();
+        verify(server1, never()).stop();
+        verify(client1, never()).stop();
+        verify(prov1, never()).afterStop(mgr);
+        verify(prov2, never()).afterStop(mgr);
+    }
+
     /**
      * Manager with overrides.
      */
index 8a10c51..6d2380f 100644 (file)
@@ -213,22 +213,6 @@ class FeatureLockImplTest {
         verify(callback, never()).lockUnavailable(any());
     }
 
-    /**
-     * Tests doNotify() when there is no session.
-     */
-    @Test
-    void testDoNotifyNoSession() {
-        MyLock lock = new MyLock(LockState.WAITING, RESOURCE, OWNER_KEY, HOLD_SEC, callback);
-        lock.grant();
-
-        assertTrue(lock.isActive());
-        assertEquals(1, lock.nupdates);
-
-        invokeCallback();
-        verify(callback).lockAvailable(any());
-        verify(callback, never()).lockUnavailable(any());
-    }
-
     @Test
     void testFreeAllowed() {
         MyLock lock = new MyLock(LockState.WAITING, RESOURCE, OWNER_KEY, HOLD_SEC, callback);