From c274fd4a91bdbd86d8fc719f12834133adc6584d Mon Sep 17 00:00:00 2001 From: "adheli.tavares" Date: Tue, 17 Sep 2024 14:19:51 +0100 Subject: Increase code coverage in policy-core and policy-utils Issue-ID: POLICY-5068 Change-Id: I598b674fd623ff56c2e7b0316c114e7c270c2b3f Signed-off-by: adheli.tavares --- policy-core/pom.xml | 4 + .../onap/policy/drools/core/PolicyContainer.java | 149 +++++++------ .../policy/drools/core/DroolsContainerTest.java | 106 +++++----- .../policy/drools/core/PolicyContainerTest.java | 230 +++++++++++++++++++++ .../drools/core/PolicySessionFeatureApiMock.java | 6 + .../policy/drools/core/jmx/PdpJmxListenerTest.java | 66 ++++++ .../drools/core/lock/AlwaysFailLockTest.java | 6 + .../drools/core/lock/AlwaysSuccessLockTest.java | 25 +++ .../policy/drools/system/internal/LockManager.java | 3 +- .../internal/NullDroolsControllerTest.java | 89 +++++--- .../drools/system/PolicyEngineManagerTest.java | 166 ++++++++------- policy-utils/pom.xml | 4 + .../org/onap/policy/drools/metrics/Metric.java | 4 +- .../onap/policy/drools/policies/DomainMaker.java | 27 +-- .../org/onap/policy/drools/metrics/MetricTest.java | 32 ++- .../policy/drools/policies/DomainMakerTest.java | 72 ++++++- .../org/onap/policy/drools/utils/LookupTest.java | 57 +++++ .../onap/policy/drools/utils/PropertyUtilTest.java | 125 ++++++----- 18 files changed, 858 insertions(+), 313 deletions(-) create mode 100644 policy-core/src/test/java/org/onap/policy/drools/core/PolicyContainerTest.java create mode 100644 policy-core/src/test/java/org/onap/policy/drools/core/jmx/PdpJmxListenerTest.java create mode 100644 policy-utils/src/test/java/org/onap/policy/drools/utils/LookupTest.java diff --git a/policy-core/pom.xml b/policy-core/pom.xml index 57fd613c..9eb0af1a 100644 --- a/policy-core/pom.xml +++ b/policy-core/pom.xml @@ -133,6 +133,10 @@ org.glassfish.hk2.external jakarta.inject + + org.springframework + spring-test + diff --git a/policy-core/src/main/java/org/onap/policy/drools/core/PolicyContainer.java b/policy-core/src/main/java/org/onap/policy/drools/core/PolicyContainer.java index ec5ceb21..533ac223 100644 --- a/policy-core/src/main/java/org/onap/policy/drools/core/PolicyContainer.java +++ b/policy-core/src/main/java/org/onap/policy/drools/core/PolicyContainer.java @@ -28,6 +28,8 @@ import java.util.HashSet; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import lombok.Getter; +import lombok.NonNull; +import org.apache.commons.lang3.StringUtils; import org.kie.api.KieServices; import org.kie.api.builder.KieScanner; import org.kie.api.builder.Message; @@ -49,13 +51,13 @@ public class PolicyContainer implements Startable { // get an instance of logger private static final Logger logger = LoggerFactory.getLogger(PolicyContainer.class); // 'KieServices' singleton - private static KieServices kieServices = KieServices.Factory.get(); + private static final KieServices kieServices = KieServices.Factory.get(); // set of all 'PolicyContainer' instances private static final HashSet containers = new HashSet<>(); // maps feature objects to per-PolicyContainer data - private ConcurrentHashMap adjuncts = new ConcurrentHashMap<>(); + private final ConcurrentHashMap adjuncts = new ConcurrentHashMap<>(); // 'KieContainer' associated with this 'PolicyContainer' @Getter @@ -90,9 +92,9 @@ public class PolicyContainer implements Startable { * *

An exception occurs if the creation of the 'KieContainer' fails. * - * @param groupId the 'groupId' associated with the artifact + * @param groupId the 'groupId' associated with the artifact * @param artifactId the artifact name - * @param version a comma-separated list of possible versions + * @param version a comma-separated list of possible versions */ public PolicyContainer(String groupId, String artifactId, String version) { this(kieServices.newReleaseId(groupId, artifactId, version)); @@ -112,7 +114,7 @@ public class PolicyContainer implements Startable { if (newReleaseId.getVersion().contains(",")) { // this is actually a comma-separated list of release ids newReleaseId = - loadArtifact(newReleaseId.getGroupId(), newReleaseId.getArtifactId(), newReleaseId.getVersion()); + loadArtifact(newReleaseId.getGroupId(), newReleaseId.getArtifactId(), newReleaseId.getVersion()); } else { kieContainer = kieServices.newKieContainer(newReleaseId); } @@ -138,9 +140,9 @@ public class PolicyContainer implements Startable { * Load an artifact into a new KieContainer. This method handles the case where the 'version' is * actually a comma-separated list of versions. * - * @param groupId the 'groupId' associated with the artifact + * @param groupId the 'groupId' associated with the artifact * @param artifactId the artifact name - * @param version a comma-separated list of possible versions + * @param version a comma-separated list of possible versions */ private ReleaseId loadArtifact(String groupId, String artifactId, String version) { String[] versions = version.split(","); @@ -180,15 +182,11 @@ public class PolicyContainer implements Startable { } /** - * Get name. + * Get name in the form of (groupId + ":" + artifactId + ":" + version) + * Note that the name changes after a successful call to 'updateToVersion', although + * typically only the 'version' part changes. * - * @return the name of the container, which is the String equivalent of the 'ReleaseId'. It has - * the form: - * - * (groupId + ":" + artifactId + ":" + version) - * - * Note that the name changes after a successful call to 'updateToVersion', although - * typically only the 'version' part changes. + * @return the name of the container, which is the String equivalent of the 'ReleaseId'. */ public String getName() { return kieContainer.getReleaseId().toString(); @@ -204,7 +202,7 @@ public class PolicyContainer implements Startable { } /** - * Get group Id. + * Get group id. * * @return the Maven GroupId of the top-level artifact wrapped by the container. */ @@ -235,7 +233,7 @@ public class PolicyContainer implements Startable { * Fetch the named 'PolicySession'. * * @param name the name of the KieSession (which is also the name of the associated - * PolicySession) + * PolicySession) * @return a PolicySession if found, 'null' if not */ public PolicySession getPolicySession(String name) { @@ -245,7 +243,7 @@ public class PolicyContainer implements Startable { /** * Internal method to create a PolicySession, possibly restoring it from persistent storage. * - * @param name of the KieSession and PolicySession + * @param name of the KieSession and PolicySession * @param kieBaseName name of the associated 'KieBase' instance * @return a new or existing PolicySession, or 'null' if not found */ @@ -255,7 +253,7 @@ public class PolicyContainer implements Startable { PolicySession session = sessions.computeIfAbsent(name, key -> makeSession(name, kieBaseName)); logger.info("activatePolicySession:session - {} is returned.", - session == null ? "null" : session.getFullName()); + session == null ? "null" : session.getFullName()); return session; } } @@ -307,30 +305,32 @@ public class PolicyContainer implements Startable { * provides a way for 'KieSession' instances that are created programmatically to fit into this * framework. * - * @param name the name for the new 'PolicySession' + * @param name the name for the new 'PolicySession' * @param kieSession a 'KieSession' instance, that will be included in this infrastructure * @return the new 'PolicySession' * @throws IllegalArgumentException if 'kieSession' does not reside within this container - * @throws IllegalStateException if a 'PolicySession' already exists with this name + * @throws IllegalStateException if a 'PolicySession' already exists with this name */ public PolicySession adoptKieSession(String name, KieSession kieSession) { - if (name == null) { + if (StringUtils.isBlank(name)) { logger.warn("adoptKieSession:input name is null"); throw new IllegalArgumentException("KieSession input name is null " + getName()); - } else if (kieSession == null) { + } + + if (kieSession == null) { logger.warn("adoptKieSession:input kieSession is null"); throw new IllegalArgumentException("KieSession '" + name + "' is null " + getName()); - } else { - logger.info("adoptKieSession:name: {} kieSession: {}", name, kieSession); } + + logger.info("adoptKieSession:name: {} kieSession: {}", name, kieSession); // fetch KieBase, and verify it belongs to this KieContainer var match = false; var kieBase = kieSession.getKieBase(); logger.info("adoptKieSession:kieBase: {}", kieBase); for (String kieBaseName : kieContainer.getKieBaseNames()) { logger.info("adoptKieSession:kieBaseName: {}", kieBaseName); - if (kieBase == kieContainer.getKieBase(kieBaseName)) { + if (kieBase.equals(kieContainer.getKieBase(kieBaseName))) { match = true; break; } @@ -338,9 +338,9 @@ public class PolicyContainer implements Startable { logger.info("adoptKieSession:match {}", match); // if we don't have a match yet, the last chance is to look at the // default KieBase, if it exists - if (!match && kieBase != kieContainer.getKieBase()) { + if (!match && !kieBase.equals(kieContainer.getKieBase())) { throw new IllegalArgumentException( - "KieSession '" + name + "' does not reside within container " + getName()); + "KieSession '" + name + "' does not reside within container " + getName()); } synchronized (sessions) { @@ -370,15 +370,13 @@ public class PolicyContainer implements Startable { * This call 'KieContainer.updateToVersion()', and returns the associated response as a String. * If successful, the name of this 'PolicyContainer' changes to match the new version. * - * @param newVersion this is the version to update to (the 'groupId' and 'artifactId' remain the - * same) - * @return the list of messages associated with the update (not sure if this can be 'null', or - * how to determine success/failure) + * @param newVersion this is the version to update to ('groupId' and 'artifactId' remain the same) + * @return the list of messages associated with the update */ public String updateToVersion(String newVersion) { var releaseId = kieContainer.getReleaseId(); - var results = this.updateToVersion( - kieServices.newReleaseId(releaseId.getGroupId(), releaseId.getArtifactId(), newVersion)); + var results = this.updateToVersion(kieServices.newReleaseId(releaseId.getGroupId(), + releaseId.getArtifactId(), newVersion)); List messages = results == null ? null : results.getMessages(); return messages == null ? null : messages.toString(); @@ -455,46 +453,46 @@ public class PolicyContainer implements Startable { * * @param releaseId the release id used to create the container */ - public synchronized void startScanner(ReleaseId releaseId) { + public synchronized void startScanner(@NonNull ReleaseId releaseId) { String version = releaseId.getVersion(); - if (scannerStarted || scanner != null || version == null) { + if (!isValidVersion(version)) { + logger.warn("version is invalid - check if empty or if it's not LATEST, RELEASE or SNAPSHOT"); return; } - if (!("LATEST".equals(version) || "RELEASE".equals(version) || version.endsWith("-SNAPSHOT"))) { + if (isScannerStarted()) { + logger.warn("scanner already started"); return; } // create the scanner, and poll at 60 second intervals - try { - scannerStarted = true; - // start this in a separate thread -- it can block for a long time - new Thread("Scanner Starter " + getName()) { - @Override - public void run() { + scannerStarted = true; + + // start this in a separate thread -- it can block for a long time + new Thread("Scanner Starter " + getName()) { + @Override + public void run() { + try { scanner = kieServices.newKieScanner(kieContainer); scanner.start(60000L); + } catch (Exception e) { + // sometimes the scanner initialization fails for some reason + logger.error("startScanner error", e); } - }.start(); - } catch (Exception e) { - // sometimes the scanner initialization fails for some reason - logger.error("startScanner error", e); - } + } + }.start(); } /** * Insert a fact into a specific named session. * - * @param name this is the session name + * @param name this is the session name * @param object this is the fact to be inserted into the session * @return 'true' if the named session was found, 'false' if not */ public boolean insert(String name, Object object) { - // TODO: Should the definition of 'name' be expanded to include an - // alternate entry point as well? For example, 'name.entryPoint' (or - // something other than '.' if that is a problem). synchronized (sessions) { PolicySession session = sessions.get(name); if (session != null) { @@ -568,7 +566,7 @@ public class PolicyContainer implements Startable { Collection localSessions; synchronized (sessions) { - // local set containing all of the sessions + // local set containing all the sessions localSessions = new HashSet<>(sessions.values()); // clear the 'name->session' map in 'PolicyContainer' @@ -631,7 +629,7 @@ public class PolicyContainer implements Startable { Collection localSessions; synchronized (sessions) { - // local set containing all of the sessions + // local set containing all the sessions localSessions = new HashSet<>(sessions.values()); // clear the 'name->session' map in 'PolicyContainer' @@ -667,7 +665,7 @@ public class PolicyContainer implements Startable { * This method is called when the host goes from the 'standby->active' state. */ public static void activate() { - // start all of the 'PolicyContainer' instances + // start all the 'PolicyContainer' instances for (PolicyContainer container : containers) { try { container.start(); @@ -681,7 +679,7 @@ public class PolicyContainer implements Startable { * This method is called when the host goes from the 'active->standby' state. */ public static void deactivate() { - // deactivate all of the 'PolicyContainer' instances + // deactivate all the 'PolicyContainer' instances for (PolicyContainer container : containers) { try { container.stop(); @@ -694,7 +692,7 @@ public class PolicyContainer implements Startable { /** * This method does the following: * - *

1) Initializes logging 2) Starts the DroolsPDP Integrity Monitor 3) Initilaizes persistence + *

1) Initializes logging 2) Starts the DroolsPDP Integrity Monitor 3) Initializes persistence * *

It no longer reads in properties files, o creates 'PolicyContainer' instances. * @@ -718,7 +716,7 @@ public class PolicyContainer implements Startable { * Fetch the adjunct object associated with a given feature. * * @param object this is typically the singleton feature object that is used as a key, but it - * might also be useful to use nested objects within the feature as keys. + * might also be useful to use nested objects within the feature as keys. * @return a feature-specific object associated with the key, or 'null' if it is not found. */ public Object getAdjunct(Object object) { @@ -729,9 +727,9 @@ public class PolicyContainer implements Startable { * Store the adjunct object associated with a given feature. * * @param object this is typically the singleton feature object that is used as a key, but it - * might also be useful to use nested objects within the feature as keys. - * @param value a feature-specific object associated with the key, or 'null' if the - * feature-specific object should be removed + * might also be useful to use nested objects within the feature as keys. + * @param value a feature-specific object associated with the key, or 'null' if the + * feature-specific object should be removed */ public void setAdjunct(Object object, Object value) { if (value == null) { @@ -768,4 +766,33 @@ public class PolicyContainer implements Startable { KieUtils.addKiePackages(kieContainer.getKieBase(name), kiePackages); } } + + /** + * Checks if boolean scannerStarted is true and if scanner itself is not null. + * + * @return true if the above is all true, false otherwise. + */ + public boolean isScannerStarted() { + return scannerStarted || scanner != null; + } + + /** + * Validation of a release version for starting a scanner. + * Can be valid if LATEST, RELEASE or SNAPSHOT version. + * + * @param version release version + * @return true if valid based on values above, false otherwise. + */ + protected boolean isValidVersion(String version) { + if (StringUtils.isBlank(version)) { + logger.warn("version is empty"); + return false; + } + + if (version.toUpperCase().contains("LATEST") || version.toUpperCase().contains("RELEASE")) { + return true; + } else { + return version.toUpperCase().endsWith("-SNAPSHOT"); + } + } } diff --git a/policy-core/src/test/java/org/onap/policy/drools/core/DroolsContainerTest.java b/policy-core/src/test/java/org/onap/policy/drools/core/DroolsContainerTest.java index abed9727..d6804b60 100644 --- a/policy-core/src/test/java/org/onap/policy/drools/core/DroolsContainerTest.java +++ b/policy-core/src/test/java/org/onap/policy/drools/core/DroolsContainerTest.java @@ -79,44 +79,7 @@ public class DroolsContainerTest { */ @Test void createAndUpdate() throws Exception { - // make sure feature log starts out clean - PolicySessionFeatureApiMock.getLog(); - - // run 'globalInit', and verify expected feature hook fired - PolicyContainer.globalInit(new String[0]); - assertEquals(List.of("globalInit"), - PolicySessionFeatureApiMock.getLog()); - - // initial conditions -- there should be no containers - assertEquals(0, PolicyContainer.getPolicyContainers().size()); - - // create the container, and start it - PolicyContainer container = - new PolicyContainer("org.onap.policy.drools-pdp", - "drools-artifact1", "17.1.0-SNAPSHOT"); - container.start(); - assertTrue(container.isAlive()); - - // verify expected feature hooks fired - assertEquals(Arrays.asList("activatePolicySession", - "newPolicySession", - "selectThreadModel"), - PolicySessionFeatureApiMock.getLog()); - - // this container should be on the list - { - Collection containers = - PolicyContainer.getPolicyContainers(); - assertEquals(1, containers.size()); - assertTrue(containers.contains(container)); - } - - // verify initial container attributes - assertEquals("org.onap.policy.drools-pdp:drools-artifact1:17.1.0-SNAPSHOT", - container.getName()); - assertEquals("org.onap.policy.drools-pdp", container.getGroupId()); - assertEquals("drools-artifact1", container.getArtifactId()); - assertEquals("17.1.0-SNAPSHOT", container.getVersion()); + PolicyContainer container = validateCreatedContainer(); try { // fetch the session, and verify that it exists @@ -225,20 +188,17 @@ public class DroolsContainerTest { // run 'globalInit', and verify expected feature hook fired PolicyContainer.globalInit(new String[0]); - assertEquals(List.of("globalInit-exception"), - PolicySessionFeatureApiMock.getLog()); + assertEquals(List.of("globalInit-exception"), PolicySessionFeatureApiMock.getLog()); // initial conditions -- there should be no containers assertEquals(0, PolicyContainer.getPolicyContainers().size()); - String versionList = - "17.3.0-SNAPSHOT,17.1.0-SNAPSHOT,17.2.0-SNAPSHOT"; + String versionList = "17.3.0-SNAPSHOT,17.1.0-SNAPSHOT,17.2.0-SNAPSHOT"; // versions should be tried in order -- the 17.1.0-SNAPSHOT should "win", // given the fact that '17.3.0-SNAPSHOT' doesn't exist PolicyContainer container = - new PolicyContainer("org.onap.policy.drools-pdp", - "drools-artifact1", versionList); + new PolicyContainer("org.onap.policy.drools-pdp", "drools-artifact1", versionList); // the following should be equivalent to 'container.start()' PolicyContainer.activate(); assertTrue(container.isAlive()); @@ -251,15 +211,12 @@ public class DroolsContainerTest { // this container should be on the list { - Collection containers = - PolicyContainer.getPolicyContainers(); - assertEquals(1, containers.size()); - assertTrue(containers.contains(container)); + Collection containers = PolicyContainer.getPolicyContainers(); + assertTrue(containers.contains(container) && (containers.size() == 1)); } // verify initial container attributes - assertEquals("org.onap.policy.drools-pdp:drools-artifact1:17.1.0-SNAPSHOT", - container.getName()); + assertEquals("org.onap.policy.drools-pdp:drools-artifact1:17.1.0-SNAPSHOT", container.getName()); assertEquals("org.onap.policy.drools-pdp", container.getGroupId()); assertEquals("drools-artifact1", container.getArtifactId()); assertEquals("17.1.0-SNAPSHOT", container.getVersion()); @@ -288,8 +245,7 @@ public class DroolsContainerTest { // get all sessions, and verify that this one is the only one { Collection sessions = container.getPolicySessions(); - assertEquals(1, sessions.size()); - assertTrue(sessions.contains(session)); + assertTrue(sessions.contains(session) && (1 == sessions.size())); } // verify session attributes @@ -341,4 +297,50 @@ public class DroolsContainerTest { // final conditions -- there should be no containers assertEquals(0, PolicyContainer.getPolicyContainers().size()); } + + /** + * Creates a policy container. + * @return a container used on create and update test + */ + private static PolicyContainer validateCreatedContainer() { + // make sure feature log starts out clean + PolicySessionFeatureApiMock.getLog(); + + // run 'globalInit', and verify expected feature hook fired + PolicyContainer.globalInit(new String[0]); + assertEquals(List.of("globalInit"), + PolicySessionFeatureApiMock.getLog()); + + // initial conditions -- there should be no containers + assertEquals(0, PolicyContainer.getPolicyContainers().size()); + + // create the container, and start it + PolicyContainer container = + new PolicyContainer("org.onap.policy.drools-pdp", + "drools-artifact1", "17.1.0-SNAPSHOT"); + container.start(); + assertTrue(container.isAlive()); + + // verify expected feature hooks fired + assertEquals(Arrays.asList("activatePolicySession", + "newPolicySession", + "selectThreadModel"), + PolicySessionFeatureApiMock.getLog()); + + // this container should be on the list + { + Collection containers = + PolicyContainer.getPolicyContainers(); + assertEquals(1, containers.size()); + assertTrue(containers.contains(container)); + } + + // verify initial container attributes + assertEquals("org.onap.policy.drools-pdp:drools-artifact1:17.1.0-SNAPSHOT", + container.getName()); + assertEquals("org.onap.policy.drools-pdp", container.getGroupId()); + assertEquals("drools-artifact1", container.getArtifactId()); + assertEquals("17.1.0-SNAPSHOT", container.getVersion()); + return container; + } } diff --git a/policy-core/src/test/java/org/onap/policy/drools/core/PolicyContainerTest.java b/policy-core/src/test/java/org/onap/policy/drools/core/PolicyContainerTest.java new file mode 100644 index 00000000..72c8d2d3 --- /dev/null +++ b/policy-core/src/test/java/org/onap/policy/drools/core/PolicyContainerTest.java @@ -0,0 +1,230 @@ +/*- + * ============LICENSE_START================================================ + * policy-core + * ========================================================================= + * 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.core; + +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.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNull; +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 org.junit.jupiter.api.Test; +import org.kie.api.KieBase; +import org.kie.api.KieServices; +import org.kie.api.builder.KieScanner; +import org.kie.api.builder.ReleaseId; +import org.kie.api.event.rule.AgendaEventListener; +import org.kie.api.event.rule.RuleRuntimeEventListener; +import org.kie.api.runtime.KieContainer; +import org.kie.api.runtime.KieSession; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.springframework.test.util.ReflectionTestUtils; + +class PolicyContainerTest { + + private static final String VERSION = "1.0.0"; + + @Test + void adoptKieSession_Exceptions() { + var mockKieSession = mock(KieSession.class); + var policyContainer = mock(PolicyContainer.class); + + when(policyContainer.getName()).thenReturn("kieReleaseName"); + when(policyContainer.adoptKieSession(any(), eq(mockKieSession))).thenCallRealMethod(); + when(policyContainer.adoptKieSession("name", null)).thenCallRealMethod(); + + assertThatThrownBy(() -> policyContainer.adoptKieSession("", mockKieSession)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("KieSession input name is null kieReleaseName"); + + assertThatThrownBy(() -> policyContainer.adoptKieSession(null, mockKieSession)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("KieSession input name is null kieReleaseName"); + + assertThatThrownBy(() -> policyContainer.adoptKieSession("name", null)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("KieSession 'name' is null kieReleaseName"); + } + + @Test + void testAdoptKieSession() { + var mockKieSession = mock(KieSession.class); + doNothing().when(mockKieSession).addEventListener(any(AgendaEventListener.class)); + doNothing().when(mockKieSession).addEventListener(any(RuleRuntimeEventListener.class)); + + var policyContainer = mock(PolicyContainer.class); + when(policyContainer.adoptKieSession("name", mockKieSession)).thenCallRealMethod(); + when(policyContainer.getName()).thenReturn("kieReleaseName"); + + var mockKieBase = mock(KieBase.class); + when(mockKieSession.getKieBase()).thenReturn(mockKieBase); + + var mockKieContainer = mock(KieContainer.class); + when(policyContainer.getKieContainer()).thenReturn(mockKieContainer); + when(mockKieContainer.getKieBase("baseName")).thenReturn(mockKieBase); + when(mockKieContainer.getKieBaseNames()).thenReturn(List.of("baseName")); + when(mockKieContainer.getKieBase()).thenReturn(mockKieBase); + + HashMap sessions = new HashMap<>(); + ReflectionTestUtils.setField(policyContainer, "sessions", sessions); + ReflectionTestUtils.setField(policyContainer, "kieContainer", mockKieContainer); + + assertNotNull(policyContainer.adoptKieSession("name", mockKieSession)); + assertThatThrownBy(() -> policyContainer.adoptKieSession("name", mockKieSession)) + .isInstanceOf(IllegalStateException.class) + .hasMessageContaining("PolicySession 'name' already exists"); + } + + @Test + void testAdoptKieSession_KieBaseDoesntMatch() { + var mockKieSession = mock(KieSession.class); + + var policyContainer = mock(PolicyContainer.class); + when(policyContainer.adoptKieSession("name", mockKieSession)).thenCallRealMethod(); + when(policyContainer.getName()).thenReturn("kieReleaseName"); + + var mockKieBase = mock(KieBase.class); + when(mockKieSession.getKieBase()).thenReturn(mockKieBase); + var mockKieBase2 = mock(KieBase.class); + + var mockKieContainer = mock(KieContainer.class); + when(policyContainer.getKieContainer()).thenReturn(mockKieContainer); + when(mockKieContainer.getKieBase("baseName")).thenReturn(mockKieBase2); + when(mockKieContainer.getKieBaseNames()).thenReturn(List.of("baseName")); + when(mockKieContainer.getKieBase()).thenReturn(mockKieBase2); + + ReflectionTestUtils.setField(policyContainer, "kieContainer", mockKieContainer); + + assertThatThrownBy(() -> policyContainer.adoptKieSession("name", mockKieSession)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("KieSession 'name' does not reside within container kieReleaseName"); + } + + @Test + void startScanner_Exceptions() { + var policyContainer = mock(PolicyContainer.class); + doCallRealMethod().when(policyContainer).startScanner(any(ReleaseId.class)); + doCallRealMethod().when(policyContainer).startScanner(isNull()); + when(policyContainer.isScannerStarted()).thenCallRealMethod(); + + assertThatThrownBy(() -> policyContainer.startScanner(null)) + .hasMessageContaining("releaseId is marked non-null but is null"); + assertFalse(policyContainer.isScannerStarted()); + + // shouldn't throw exception, but won't start scanner as version is null + var mockVersionNull = mock(ReleaseId.class); + when(mockVersionNull.getVersion()).thenReturn(null); + when(policyContainer.isValidVersion(isNull())).thenCallRealMethod(); + assertDoesNotThrow(() -> policyContainer.startScanner(mockVersionNull)); + assertFalse(policyContainer.isScannerStarted()); + + var mockVersionSnapshot = mock(ReleaseId.class); + when(mockVersionSnapshot.getVersion()).thenReturn(VERSION); + when(policyContainer.isValidVersion(VERSION)).thenCallRealMethod(); + assertDoesNotThrow(() -> policyContainer.startScanner(mockVersionSnapshot)); + assertFalse(policyContainer.isScannerStarted()); + } + + @Test + void startScanner_SnapshotVersion() { + var policyContainer = mock(PolicyContainer.class); + when(policyContainer.isScannerStarted()).thenCallRealMethod(); + when(policyContainer.isValidVersion(VERSION + "-SNAPSHOT")).thenCallRealMethod(); + + var mockVersionSnapshot = mock(ReleaseId.class); + when(mockVersionSnapshot.getVersion()).thenReturn(VERSION + "-SNAPSHOT"); + + doCallRealMethod().when(policyContainer).startScanner(mockVersionSnapshot); + + assertDoesNotThrow(() -> policyContainer.startScanner(mockVersionSnapshot)); + assertTrue(policyContainer.isScannerStarted()); + } + + @Test + void startScanner_LatestVersion() { + var policyContainer = mock(PolicyContainer.class); + when(policyContainer.isScannerStarted()).thenCallRealMethod(); + when(policyContainer.isValidVersion(anyString())).thenCallRealMethod(); + + var mockLatestVersion = mock(ReleaseId.class); + when(mockLatestVersion.getVersion()).thenReturn(VERSION + "LATEST"); + + doCallRealMethod().when(policyContainer).startScanner(mockLatestVersion); + + assertDoesNotThrow(() -> policyContainer.startScanner(mockLatestVersion)); + assertTrue(policyContainer.isScannerStarted()); + } + + @Test + void startScanner_ReleaseVersion() { + var mockKieServices = mock(KieServices.class); + when(mockKieServices.newKieScanner(any(KieContainer.class))).thenReturn(mock(KieScanner.class)); + + try (MockedStatic factory = Mockito.mockStatic(KieServices.Factory.class)) { + factory.when(KieServices.Factory::get).thenReturn(mockKieServices); + assertEquals(mockKieServices, KieServices.Factory.get()); + + var policyContainer = mock(PolicyContainer.class); + when(policyContainer.isScannerStarted()).thenCallRealMethod(); + when(policyContainer.isValidVersion(VERSION + "RELEASE")).thenCallRealMethod(); + + var mockLatestVersion = mock(ReleaseId.class); + when(mockLatestVersion.getVersion()).thenReturn(VERSION + "RELEASE"); + + doCallRealMethod().when(policyContainer).startScanner(mockLatestVersion); + + assertDoesNotThrow(() -> policyContainer.startScanner(mockLatestVersion)); + assertTrue(policyContainer.isScannerStarted()); + + // try again, but should come out at checking if scanner is already started. + assertDoesNotThrow(() -> policyContainer.startScanner(mockLatestVersion)); + } + } + + @Test + void insert() { + var policyContainer = mock(PolicyContainer.class); + var object = new Object(); + when(policyContainer.insert("name", object)).thenCallRealMethod(); + + HashMap sessions = new HashMap<>(); + ReflectionTestUtils.setField(policyContainer, "sessions", sessions); + + assertFalse(policyContainer.insert("name", object)); + } + + @Test + void deactivate() { + assertDoesNotThrow(PolicyContainer::deactivate); + } +} \ No newline at end of file diff --git a/policy-core/src/test/java/org/onap/policy/drools/core/PolicySessionFeatureApiMock.java b/policy-core/src/test/java/org/onap/policy/drools/core/PolicySessionFeatureApiMock.java index d8257067..f0e5b516 100644 --- a/policy-core/src/test/java/org/onap/policy/drools/core/PolicySessionFeatureApiMock.java +++ b/policy-core/src/test/java/org/onap/policy/drools/core/PolicySessionFeatureApiMock.java @@ -86,6 +86,7 @@ public class PolicySessionFeatureApiMock implements PolicySessionFeatureApi { /** * {@inheritDoc}. */ + @Override public void globalInit(String[] args, String configDir) { addLog("globalInit"); } @@ -93,6 +94,7 @@ public class PolicySessionFeatureApiMock implements PolicySessionFeatureApi { /** * {@inheritDoc}. */ + @Override public KieSession activatePolicySession(PolicyContainer policyContainer, String name, String kieBaseName) { addLog("activatePolicySession"); return null; @@ -101,6 +103,7 @@ public class PolicySessionFeatureApiMock implements PolicySessionFeatureApi { /** * {@inheritDoc}. */ + @Override public void newPolicySession(PolicySession policySession) { addLog("newPolicySession"); } @@ -108,6 +111,7 @@ public class PolicySessionFeatureApiMock implements PolicySessionFeatureApi { /** * {@inheritDoc}. */ + @Override public PolicySession.ThreadModel selectThreadModel(PolicySession session) { addLog("selectThreadModel"); return null; @@ -116,6 +120,7 @@ public class PolicySessionFeatureApiMock implements PolicySessionFeatureApi { /** * {@inheritDoc}. */ + @Override public void disposeKieSession(PolicySession policySession) { addLog("disposeKieSession"); } @@ -123,6 +128,7 @@ public class PolicySessionFeatureApiMock implements PolicySessionFeatureApi { /** * {@inheritDoc}. */ + @Override public void destroyKieSession(PolicySession policySession) { addLog("destroyKieSession"); } diff --git a/policy-core/src/test/java/org/onap/policy/drools/core/jmx/PdpJmxListenerTest.java b/policy-core/src/test/java/org/onap/policy/drools/core/jmx/PdpJmxListenerTest.java new file mode 100644 index 00000000..d81dc3e9 --- /dev/null +++ b/policy-core/src/test/java/org/onap/policy/drools/core/jmx/PdpJmxListenerTest.java @@ -0,0 +1,66 @@ +/*- + * ============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.core.jmx; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.lang.management.ManagementFactory; +import javax.management.InstanceAlreadyExistsException; +import javax.management.InstanceNotFoundException; +import javax.management.MBeanRegistrationException; +import javax.management.MBeanServer; +import javax.management.MalformedObjectNameException; +import javax.management.NotCompliantMBeanException; +import javax.management.ObjectName; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +class PdpJmxListenerTest { + + @Test + void test() { + Assertions.assertDoesNotThrow(PdpJmxListener::start); + Assertions.assertDoesNotThrow(PdpJmxListener::stop); + } + + @Test + void testExceptions() + throws MalformedObjectNameException, NotCompliantMBeanException, InstanceAlreadyExistsException, + MBeanRegistrationException, InstanceNotFoundException { + + var mockMBean = Mockito.mock(MBeanServer.class); + Mockito.doThrow(MBeanRegistrationException.class).when(mockMBean) + .registerMBean(PdpJmx.getInstance(), new ObjectName("PolicyEngine:type=PdpJmx")); + Mockito.doThrow(MBeanRegistrationException.class).when(mockMBean) + .unregisterMBean(new ObjectName("PolicyEngine:type=PdpJmx")); + + // trying to reach exception catch clause, but can't validate if exception was thrown + try (MockedStatic factory = Mockito.mockStatic(ManagementFactory.class)) { + factory.when(ManagementFactory::getPlatformMBeanServer).thenReturn(mockMBean); + assertEquals(mockMBean, ManagementFactory.getPlatformMBeanServer()); + + Assertions.assertDoesNotThrow(PdpJmxListener::start); + Assertions.assertDoesNotThrow(PdpJmxListener::stop); + } + } +} \ No newline at end of file diff --git a/policy-core/src/test/java/org/onap/policy/drools/core/lock/AlwaysFailLockTest.java b/policy-core/src/test/java/org/onap/policy/drools/core/lock/AlwaysFailLockTest.java index 51273d7d..02c3fead 100644 --- a/policy-core/src/test/java/org/onap/policy/drools/core/lock/AlwaysFailLockTest.java +++ b/policy-core/src/test/java/org/onap/policy/drools/core/lock/AlwaysFailLockTest.java @@ -22,6 +22,7 @@ package org.onap.policy.drools.core.lock; import static org.assertj.core.api.Assertions.assertThatCode; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; @@ -52,4 +53,9 @@ class AlwaysFailLockTest extends AlwaysLockBaseTest { assertFalse(lock.free()); assertTrue(lock.isUnavailable()); } + + @Test + void testExtend() { + assertDoesNotThrow(() -> lock.extend(10, callback)); + } } diff --git a/policy-core/src/test/java/org/onap/policy/drools/core/lock/AlwaysSuccessLockTest.java b/policy-core/src/test/java/org/onap/policy/drools/core/lock/AlwaysSuccessLockTest.java index 80f81f92..0104d0a8 100644 --- a/policy-core/src/test/java/org/onap/policy/drools/core/lock/AlwaysSuccessLockTest.java +++ b/policy-core/src/test/java/org/onap/policy/drools/core/lock/AlwaysSuccessLockTest.java @@ -25,6 +25,7 @@ import static org.assertj.core.api.Assertions.assertThatCode; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; @@ -67,4 +68,28 @@ class AlwaysSuccessLockTest extends AlwaysLockBaseTest { assertEquals(HOLD_SEC2, lock.getHoldSec()); assertSame(callback2, lock.getCallback()); } + + @Test + void testNullArgs() { + assertThrows(NullPointerException.class, + () -> new AlwaysSuccessLock(null, RESOURCE, OWNER_KEY, HOLD_SEC, callback)); + + assertThrows(NullPointerException.class, + () -> new AlwaysSuccessLock(LockState.WAITING, null, OWNER_KEY, HOLD_SEC, callback)); + + assertThrows(NullPointerException.class, + () -> new AlwaysSuccessLock(LockState.WAITING, RESOURCE, null, HOLD_SEC, callback)); + + assertThrows(NullPointerException.class, + () -> new AlwaysSuccessLock(LockState.WAITING, RESOURCE, OWNER_KEY, HOLD_SEC, null)); + + assertThrows(NullPointerException.class, + () -> new AlwaysSuccessLock(null, OWNER_KEY, HOLD_SEC, callback)); + + assertThrows(NullPointerException.class, + () -> new AlwaysSuccessLock(RESOURCE, null, HOLD_SEC, callback)); + + assertThrows(NullPointerException.class, + () -> new AlwaysSuccessLock(RESOURCE, OWNER_KEY, HOLD_SEC, null)); + } } diff --git a/policy-management/src/main/java/org/onap/policy/drools/system/internal/LockManager.java b/policy-management/src/main/java/org/onap/policy/drools/system/internal/LockManager.java index 1683b0f5..fa264426 100644 --- a/policy-management/src/main/java/org/onap/policy/drools/system/internal/LockManager.java +++ b/policy-management/src/main/java/org/onap/policy/drools/system/internal/LockManager.java @@ -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. @@ -122,7 +123,7 @@ public abstract class LockManager implements PolicyRe /** * After performing checks, this invokes * {@link #makeLock(LockState, String, String, int, LockCallback)} to create a lock - * object, inserts it into the map, and then invokes {@link #finishLock(MgrLock)}. + * object, inserts it into the map, and then invokes {@link #finishLock(FeatureLockImpl)}. */ @Override public Lock createLock(String resourceId, String ownerKey, int holdSec, LockCallback callback, diff --git a/policy-management/src/test/java/org/onap/policy/drools/controller/internal/NullDroolsControllerTest.java b/policy-management/src/test/java/org/onap/policy/drools/controller/internal/NullDroolsControllerTest.java index f61412d9..ccefcc6f 100644 --- a/policy-management/src/test/java/org/onap/policy/drools/controller/internal/NullDroolsControllerTest.java +++ b/policy-management/src/test/java/org/onap/policy/drools/controller/internal/NullDroolsControllerTest.java @@ -22,6 +22,7 @@ package org.onap.policy.drools.controller.internal; import static org.assertj.core.api.Assertions.assertThatCode; +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; @@ -36,32 +37,35 @@ import org.onap.policy.drools.controller.DroolsControllerConstants; class NullDroolsControllerTest { + private final NullDroolsController controller = new NullDroolsController(); + private static final String NULL_EXCEPTION = "marked non-null but is null"; + @Test void testStart() { - DroolsController controller = new NullDroolsController(); - controller.start(); - assertFalse(controller.isAlive()); - controller.stop(); - assertFalse(controller.isAlive()); - controller.shutdown(); - assertFalse(controller.isAlive()); - controller.halt(); - assertFalse(controller.isAlive()); + DroolsController controller1 = new NullDroolsController(); + controller1.start(); + assertFalse(controller1.isAlive()); + controller1.stop(); + assertFalse(controller1.isAlive()); + controller1.shutdown(); + assertFalse(controller1.isAlive()); + controller1.halt(); + assertFalse(controller1.isAlive()); } @Test void testSerialize() { assertThatCode(() -> new GsonTestUtils().compareGson(new NullDroolsController(), - NullDroolsControllerTest.class)).doesNotThrowAnyException(); + NullDroolsControllerTest.class)).doesNotThrowAnyException(); } @Test void testLock() { - DroolsController controller = new NullDroolsController(); - controller.lock(); - assertFalse(controller.isLocked()); - controller.unlock(); - assertFalse(controller.isLocked()); + DroolsController controller1 = new NullDroolsController(); + controller1.lock(); + assertFalse(controller1.isLocked()); + controller1.unlock(); + assertFalse(controller1.isLocked()); } @Test @@ -81,78 +85,75 @@ class NullDroolsControllerTest { @Test void getSessionNames() { - assertTrue(new NullDroolsController().getSessionNames().isEmpty()); + assertTrue(controller.getSessionNames().isEmpty()); } @Test void getCanonicalSessionNames() { - assertTrue(new NullDroolsController().getCanonicalSessionNames().isEmpty()); + assertTrue(controller.getCanonicalSessionNames().isEmpty()); } @Test void offer() { - assertFalse(new NullDroolsController().offer(null, null)); + assertFalse(controller.offer(null, null)); + assertFalse(controller.offer(null)); } @Test void deliver() { - var controller = new NullDroolsController(); assertThrows(IllegalStateException.class, () -> controller.deliver(null, null)); } @Test void getRecentSourceEvents() { - assertEquals(0, new NullDroolsController().getRecentSourceEvents().length); + assertEquals(0, controller.getRecentSourceEvents().length); } @Test void getRecentSinkEvents() { - assertEquals(0, new NullDroolsController().getRecentSinkEvents().length); + assertEquals(0, controller.getRecentSinkEvents().length); } @Test void getContainer() { - assertNull(new NullDroolsController().getContainer()); + assertNull(controller.getContainer()); } @Test void getDomains() { - assertTrue(new NullDroolsController().getBaseDomainNames().isEmpty()); + assertTrue(controller.getBaseDomainNames().isEmpty()); } @Test void ownsCoder() { - var controller = new NullDroolsController(); assertThrows(IllegalStateException.class, () -> controller.ownsCoder(null, 0)); } @Test void fetchModelClass() { - var controller = new NullDroolsController(); var className = this.getClass().getName(); assertThrows(IllegalArgumentException.class, () -> controller.fetchModelClass(className)); } @Test void isBrained() { - assertFalse(new NullDroolsController().isBrained()); + assertFalse(controller.isBrained()); } @Test void stringify() { - assertNotNull(new NullDroolsController().toString()); + assertNotNull(controller.toString()); } @Test void updateToVersion() { - var controller = new NullDroolsController(); assertThrows(IllegalArgumentException.class, () -> controller.updateToVersion(null, null, null, null, null)); } @Test void factClassNames() { - assertTrue(new NullDroolsController().factClassNames(null).isEmpty()); + assertTrue(controller.factClassNames(null).isEmpty()); } @Test @@ -162,18 +163,40 @@ class NullDroolsControllerTest { @Test void facts() { - assertTrue(new NullDroolsController().facts(null, null, true).isEmpty()); + assertTrue(controller.facts(null, null, true).isEmpty()); + assertTrue(controller.facts("sessionName", Object.class).isEmpty()); + + assertThatThrownBy(() -> controller.facts(null, Object.class)).hasMessageContaining(NULL_EXCEPTION); + assertThatThrownBy(() -> controller.facts("sessionName", null)).hasMessageContaining(NULL_EXCEPTION); } @Test void factQuery() { - assertTrue(new NullDroolsController().factQuery(null, null, null, false).isEmpty()); + assertTrue(controller.factQuery(null, null, null, false).isEmpty()); } @Test void exists() { Object o1 = new Object(); - assertFalse(new NullDroolsController().exists("blah", o1)); - assertFalse(new NullDroolsController().exists(o1)); + assertFalse(controller.exists("blah", o1)); + assertFalse(controller.exists(o1)); + + assertThatThrownBy(() -> controller.exists("blah", null)).hasMessageContaining(NULL_EXCEPTION); + assertThatThrownBy(() -> controller.exists(null, o1)).hasMessageContaining(NULL_EXCEPTION); + assertThatThrownBy(() -> controller.exists(null)).hasMessageContaining(NULL_EXCEPTION); + } + + @Test + void testDelete() { + assertThatThrownBy(() -> controller.delete("sessionName", null)).hasMessageContaining(NULL_EXCEPTION); + assertThatThrownBy(() -> controller.delete(null, Object.class)).hasMessageContaining(NULL_EXCEPTION); + assertThatThrownBy(() -> controller.delete(null)).hasMessageContaining(NULL_EXCEPTION); + Object o1 = null; + assertThatThrownBy(() -> controller.delete(o1)).hasMessageContaining(NULL_EXCEPTION); + + assertFalse(controller.delete("sessionName", new Object())); + assertFalse(controller.delete("sessionName", Object.class)); + assertFalse(controller.delete(new Object())); + assertFalse(controller.delete(Object.class)); } } diff --git a/policy-management/src/test/java/org/onap/policy/drools/system/PolicyEngineManagerTest.java b/policy-management/src/test/java/org/onap/policy/drools/system/PolicyEngineManagerTest.java index 0b88b3f1..138ad9f8 100644 --- a/policy-management/src/test/java/org/onap/policy/drools/system/PolicyEngineManagerTest.java +++ b/policy-management/src/test/java/org/onap/policy/drools/system/PolicyEngineManagerTest.java @@ -102,7 +102,7 @@ class PolicyEngineManagerTest { private static final Object MY_EVENT = new Object(); private static final GsonTestUtils gson = new GsonMgmtTestBuilder().addTopicSourceMock().addTopicSinkMock() - .addHttpServletServerMock().build(); + .addHttpServletServerMock().build(); private Properties properties; private PolicyEngineFeatureApi prov1; @@ -579,30 +579,34 @@ class PolicyEngineManagerTest { verify(prov1).afterConfigure(mgr); verify(prov2).afterConfigure(mgr); + // other tests + checkBeforeAfter( + (prov, flag) -> when(prov.beforeConfigure(mgr, properties)).thenReturn(flag), + (prov, flag) -> when(prov.afterConfigure(mgr)).thenReturn(flag), + () -> mgr.configure(properties), + prov -> verify(prov).beforeConfigure(mgr, properties), + () -> assertSame(properties, mgr.getProperties()), + prov -> verify(prov).afterConfigure(mgr)); + } + + @Test + void testConfigureProperties_InvalidProperties() throws Exception { // middle stuff throws exception - still calls afterXxx - setUp(); when(endpoint.addTopicSources(properties)).thenThrow(new IllegalArgumentException(EXPECTED)); when(endpoint.addTopicSinks(properties)).thenThrow(new IllegalArgumentException(EXPECTED)); when(serverFactory.build(properties)).thenThrow(new IllegalArgumentException(EXPECTED)); when(clientFactory.build(properties)).thenThrow(new IllegalArgumentException(EXPECTED)); mgr.configure(properties); verify(prov2).afterConfigure(mgr); + } + @Test + void testConfigureProperties_NullProperties() { // null properties - nothing should be invoked - setUp(); Properties nullProps = null; assertThatIllegalArgumentException().isThrownBy(() -> mgr.configure(nullProps)); verify(prov1, never()).beforeConfigure(mgr, properties); verify(prov1, never()).afterConfigure(mgr); - - // other tests - checkBeforeAfter( - (prov, flag) -> when(prov.beforeConfigure(mgr, properties)).thenReturn(flag), - (prov, flag) -> when(prov.afterConfigure(mgr)).thenReturn(flag), - () -> mgr.configure(properties), - prov -> verify(prov).beforeConfigure(mgr, properties), - () -> assertSame(properties, mgr.getProperties()), - prov -> verify(prov).afterConfigure(mgr)); } @Test @@ -631,17 +635,8 @@ class PolicyEngineManagerTest { } @Test - void testCreatePolicyController() throws Exception { - assertEquals(controller, mgr.createPolicyController(MY_NAME, properties)); - - verify(contProv1).beforeCreate(MY_NAME, properties); - verify(contProv2).beforeCreate(MY_NAME, properties); - verify(controller, never()).lock(); - verify(contProv1).afterCreate(controller); - verify(contProv2).afterCreate(controller); - + void testCreatePolicy_FirstProviderThrowsException() { // first provider throws exceptions - same result - setUp(); when(contProv1.beforeCreate(MY_NAME, properties)).thenThrow(new RuntimeException(EXPECTED)); when(contProv1.afterCreate(controller)).thenThrow(new RuntimeException(EXPECTED)); assertEquals(controller, mgr.createPolicyController(MY_NAME, properties)); @@ -651,17 +646,11 @@ class PolicyEngineManagerTest { verify(controller, never()).lock(); verify(contProv1).afterCreate(controller); verify(contProv2).afterCreate(controller); + } - // locked - same result, but engine locked - setUp(); - mgr.lock(); - assertEquals(controller, mgr.createPolicyController(MY_NAME, properties)); - verify(contProv1).beforeCreate(MY_NAME, properties); - verify(controller, times(2)).lock(); - verify(contProv2).afterCreate(controller); - + @Test + void testCreatePolicyController_InvalidProperties() throws Exception { // empty name in properties - same result - setUp(); properties.setProperty(DroolsPropertyConstants.PROPERTY_CONTROLLER_NAME, ""); assertEquals(controller, mgr.createPolicyController(MY_NAME, properties)); verify(contProv1).beforeCreate(MY_NAME, properties); @@ -677,6 +666,25 @@ class PolicyEngineManagerTest { properties.setProperty(DroolsPropertyConstants.PROPERTY_CONTROLLER_NAME, "mistmatched-name"); assertThatIllegalStateException().isThrownBy(() -> mgr.createPolicyController(MY_NAME, properties)); verify(contProv1, never()).beforeCreate(MY_NAME, properties); + } + + @Test + void testCreatePolicyController() throws Exception { + assertEquals(controller, mgr.createPolicyController(MY_NAME, properties)); + + verify(contProv1).beforeCreate(MY_NAME, properties); + verify(contProv2).beforeCreate(MY_NAME, properties); + verify(controller, never()).lock(); + verify(contProv1).afterCreate(controller); + verify(contProv2).afterCreate(controller); + + // locked - same result, but engine locked + setUp(); + mgr.lock(); + assertEquals(controller, mgr.createPolicyController(MY_NAME, properties)); + verify(contProv1).beforeCreate(MY_NAME, properties); + verify(controller, times(2)).lock(); + verify(contProv2).afterCreate(controller); // first provider generates controller - stops after first provider setUp(); @@ -902,7 +910,7 @@ class PolicyEngineManagerTest { * Tests the start() method, after setting some option. * * @param expectedResult what start() is expected to return - * @param setOption function that sets an option + * @param setOption function that sets an option * @throws Throwable if an error occurs during setup */ private void testStart(boolean expectedResult, RunnableWithEx setOption) throws Throwable { @@ -1004,7 +1012,7 @@ class PolicyEngineManagerTest { * Tests the stop() method, after setting some option. * * @param expectedResult what stop() is expected to return - * @param setOption function that sets an option + * @param setOption function that sets an option * @throws Throwable if an error occurs during setup */ private void testStop(boolean expectedResult, RunnableWithEx setOption) throws Throwable { @@ -1211,7 +1219,7 @@ class PolicyEngineManagerTest { * Tests the lock() method, after setting some option. * * @param expectedResult what lock() is expected to return - * @param setOption function that sets an option + * @param setOption function that sets an option * @throws Throwable if an error occurs during setup */ private void testLock(boolean expectedResult, RunnableWithEx setOption) throws Throwable { @@ -1287,7 +1295,7 @@ class PolicyEngineManagerTest { * Tests the unlock() method, after setting some option. * * @param expectedResult what unlock() is expected to return - * @param setOption function that sets an option + * @param setOption function that sets an option * @throws Throwable if an error occurs during setup */ private void testUnlock(boolean expectedResult, RunnableWithEx setOption) throws Throwable { @@ -1411,8 +1419,8 @@ class PolicyEngineManagerTest { assertEquals(1, mgr.getStats().getSubgroupStats().get(CONTROLLOOP).getPolicyExecutedFailCount()); Summary.Child.Value summary = - PolicyEngineManagerImpl.transLatencySecsSummary - .labels(CONTROLLER1, CONTROLLOOP, POLICY, PdpResponseStatus.FAIL.name()).get(); + PolicyEngineManagerImpl.transLatencySecsSummary + .labels(CONTROLLER1, CONTROLLOOP, POLICY, PdpResponseStatus.FAIL.name()).get(); assertEquals(0, summary.count, 0.0); assertEquals(0, summary.sum, 0.0); @@ -1423,8 +1431,8 @@ class PolicyEngineManagerTest { mgr.transaction(CONTROLLER1, CONTROLLOOP, metric); summary = - PolicyEngineManagerImpl.transLatencySecsSummary - .labels(CONTROLLER1, CONTROLLOOP, POLICY, PdpResponseStatus.FAIL.name()).get(); + PolicyEngineManagerImpl.transLatencySecsSummary + .labels(CONTROLLER1, CONTROLLOOP, POLICY, PdpResponseStatus.FAIL.name()).get(); assertEquals(1, summary.count, 0.0); assertEquals(5, summary.sum, 0.0); @@ -1553,7 +1561,7 @@ class PolicyEngineManagerTest { mgr.start(); when(sink1.send(any())).thenThrow(new ArithmeticException(EXPECTED)); assertThatThrownBy(() -> mgr.deliver(CommInfrastructure.NOOP, MY_TOPIC, MY_EVENT)) - .isInstanceOf(ArithmeticException.class); + .isInstanceOf(ArithmeticException.class); /* * For remaining tests, have the controller handle delivery. @@ -1610,7 +1618,7 @@ class PolicyEngineManagerTest { // unknown topic assertThatIllegalStateException() - .isThrownBy(() -> mgr.deliver(CommInfrastructure.NOOP, "unknown-topic", MESSAGE)); + .isThrownBy(() -> mgr.deliver(CommInfrastructure.NOOP, "unknown-topic", MESSAGE)); // locked mgr.lock(); @@ -1737,7 +1745,7 @@ class PolicyEngineManagerTest { // not configured yet, thus no lock manager assertThatIllegalStateException() - .isThrownBy(() -> mgr.createLock(MY_RESOURCE, MY_OWNER, 10, callback, false)); + .isThrownBy(() -> mgr.createLock(MY_RESOURCE, MY_OWNER, 10, callback, false)); // now configure it and try again mgr.configure(properties); @@ -1745,14 +1753,14 @@ class PolicyEngineManagerTest { // test illegal args assertThatThrownBy(() -> mgr.createLock(null, MY_OWNER, 10, callback, false)) - .hasMessageContaining("resourceId"); + .hasMessageContaining("resourceId"); assertThatThrownBy(() -> mgr.createLock(MY_RESOURCE, null, 10, callback, false)) - .hasMessageContaining("ownerKey"); + .hasMessageContaining("ownerKey"); assertThatIllegalArgumentException() - .isThrownBy(() -> mgr.createLock(MY_RESOURCE, MY_OWNER, -1, callback, false)) - .withMessageContaining("holdSec"); + .isThrownBy(() -> mgr.createLock(MY_RESOURCE, MY_OWNER, -1, callback, false)) + .withMessageContaining("holdSec"); assertThatThrownBy(() -> mgr.createLock(MY_RESOURCE, MY_OWNER, 10, null, false)) - .hasMessageContaining("callback"); + .hasMessageContaining("callback"); } @Test @@ -1850,19 +1858,19 @@ class PolicyEngineManagerTest { * Performs an operation that has a beforeXxx method and an afterXxx method. Tries * combinations where beforeXxx and afterXxx return {@code true} and {@code false}. * - * @param setBefore function to set the return value of a provider's beforeXxx method - * @param setAfter function to set the return value of a provider's afterXxx method - * @param action invokes the operation + * @param setBefore function to set the return value of a provider's beforeXxx method + * @param setAfter function to set the return value of a provider's afterXxx method + * @param action invokes the operation * @param verifyBefore verifies that a provider's beforeXxx method was invoked * @param verifyMiddle verifies that the action occurring between the beforeXxx loop - * and the afterXxx loop was invoked - * @param verifyAfter verifies that a provider's afterXxx method was invoked + * and the afterXxx loop was invoked + * @param verifyAfter verifies that a provider's afterXxx method was invoked * @throws Exception if an error occurs while calling {@link #setUp()} */ private void checkBeforeAfter(BiConsumer setBefore, - BiConsumer setAfter, Runnable action, - Consumer verifyBefore, Runnable verifyMiddle, - Consumer verifyAfter) throws Exception { + BiConsumer setAfter, Runnable action, + Consumer verifyBefore, Runnable verifyMiddle, + Consumer verifyAfter) throws Exception { checkBeforeAfter_FalseFalse(setBefore, setAfter, action, verifyBefore, verifyMiddle, verifyAfter); checkBeforeAfter_FalseTrue(setBefore, setAfter, action, verifyBefore, verifyMiddle, verifyAfter); @@ -1875,19 +1883,19 @@ class PolicyEngineManagerTest { * Performs an operation that has a beforeXxx method and an afterXxx method. Tries the * case where both the beforeXxx and afterXxx methods return {@code false}. * - * @param setBefore function to set the return value of a provider's beforeXxx method - * @param setAfter function to set the return value of a provider's afterXxx method - * @param action invokes the operation + * @param setBefore function to set the return value of a provider's beforeXxx method + * @param setAfter function to set the return value of a provider's afterXxx method + * @param action invokes the operation * @param verifyBefore verifies that a provider's beforeXxx method was invoked * @param verifyMiddle verifies that the action occurring between the beforeXxx loop - * and the afterXxx loop was invoked - * @param verifyAfter verifies that a provider's afterXxx method was invoked + * and the afterXxx loop was invoked + * @param verifyAfter verifies that a provider's afterXxx method was invoked * @throws Exception if an error occurs while calling {@link #setUp()} */ private void checkBeforeAfter_FalseFalse(BiConsumer setBefore, - BiConsumer setAfter, Runnable action, - Consumer verifyBefore, Runnable verifyMiddle, - Consumer verifyAfter) throws Exception { + BiConsumer setAfter, Runnable action, + Consumer verifyBefore, Runnable verifyMiddle, + Consumer verifyAfter) throws Exception { setUp(); @@ -1916,19 +1924,19 @@ class PolicyEngineManagerTest { * case where the first provider's afterXxx returns {@code true}, while the others * return {@code false}. * - * @param setBefore function to set the return value of a provider's beforeXxx method - * @param setAfter function to set the return value of a provider's afterXxx method - * @param action invokes the operation + * @param setBefore function to set the return value of a provider's beforeXxx method + * @param setAfter function to set the return value of a provider's afterXxx method + * @param action invokes the operation * @param verifyBefore verifies that a provider's beforeXxx method was invoked * @param verifyMiddle verifies that the action occurring between the beforeXxx loop - * and the afterXxx loop was invoked - * @param verifyAfter verifies that a provider's afterXxx method was invoked + * and the afterXxx loop was invoked + * @param verifyAfter verifies that a provider's afterXxx method was invoked * @throws Exception if an error occurs while calling {@link #setUp()} */ private void checkBeforeAfter_FalseTrue(BiConsumer setBefore, - BiConsumer setAfter, Runnable action, - Consumer verifyBefore, Runnable verifyMiddle, - Consumer verifyAfter) throws Exception { + BiConsumer setAfter, Runnable action, + Consumer verifyBefore, Runnable verifyMiddle, + Consumer verifyAfter) throws Exception { setUp(); @@ -1957,19 +1965,19 @@ class PolicyEngineManagerTest { * case where the first provider's beforeXxx returns {@code true}, while the others * return {@code false}. * - * @param setBefore function to set the return value of a provider's beforeXxx method - * @param setAfter function to set the return value of a provider's afterXxx method - * @param action invokes the operation + * @param setBefore function to set the return value of a provider's beforeXxx method + * @param setAfter function to set the return value of a provider's afterXxx method + * @param action invokes the operation * @param verifyBefore verifies that a provider's beforeXxx method was invoked * @param verifyMiddle verifies that the action occurring between the beforeXxx loop - * and the afterXxx loop was invoked - * @param verifyAfter verifies that a provider's afterXxx method was invoked + * and the afterXxx loop was invoked + * @param verifyAfter verifies that a provider's afterXxx method was invoked * @throws Exception if an error occurs while calling {@link #setUp()} */ private void checkBeforeAfter_TrueFalse(BiConsumer setBefore, - BiConsumer setAfter, Runnable action, - Consumer verifyBefore, Runnable verifyMiddle, - Consumer verifyAfter) throws Exception { + BiConsumer setAfter, Runnable action, + Consumer verifyBefore, Runnable verifyMiddle, + Consumer verifyAfter) throws Exception { setUp(); diff --git a/policy-utils/pom.xml b/policy-utils/pom.xml index 319711a1..09c4e142 100644 --- a/policy-utils/pom.xml +++ b/policy-utils/pom.xml @@ -70,5 +70,9 @@ net.jimblackler.jsonschemafriend core + + org.springframework + spring-test + diff --git a/policy-utils/src/main/java/org/onap/policy/drools/metrics/Metric.java b/policy-utils/src/main/java/org/onap/policy/drools/metrics/Metric.java index 01ff58f5..c2755211 100644 --- a/policy-utils/src/main/java/org/onap/policy/drools/metrics/Metric.java +++ b/policy-utils/src/main/java/org/onap/policy/drools/metrics/Metric.java @@ -3,6 +3,7 @@ * ONAP * ================================================================================ * Copyright (C) 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. @@ -134,8 +135,7 @@ public class Metric { } if (endTime != null && startTime != null) { - this.elapsedTime = - Duration.between(startTime, endTime).toMillis(); + this.elapsedTime = Duration.between(startTime, endTime).toMillis(); return; } diff --git a/policy-utils/src/main/java/org/onap/policy/drools/policies/DomainMaker.java b/policy-utils/src/main/java/org/onap/policy/drools/policies/DomainMaker.java index 84c81cf0..27dfee49 100644 --- a/policy-utils/src/main/java/org/onap/policy/drools/policies/DomainMaker.java +++ b/policy-utils/src/main/java/org/onap/policy/drools/policies/DomainMaker.java @@ -31,7 +31,6 @@ import org.onap.policy.common.utils.coder.StandardCoder; import org.onap.policy.common.utils.resources.ResourceUtils; import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy; -import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -70,7 +69,7 @@ public class DomainMaker { return false; } - return validators.get(policyType).isConformant(json); + return getValidator(policyType).isConformant(json); } /** @@ -94,7 +93,7 @@ public class DomainMaker { } try { - return validators.get(policyType).encode(domainPolicy) != null; + return getValidator(policyType).encode(domainPolicy) != null; } catch (CoderException e) { logger.info("policy {}:{} is not conformant", policyType, domainPolicy.getClass().getName(), e); return false; @@ -116,7 +115,7 @@ public class DomainMaker { } try { - validators.get(policy.getTypeIdentifier()).conformance(rawPolicy); + getValidator(policy.getTypeIdentifier()).conformance(rawPolicy); } catch (CoderException e) { logger.error("policy {}:{}:{} is not conformant", policy.getTypeIdentifier(), policy.getName(), policy.getVersion(), e); @@ -137,7 +136,7 @@ public class DomainMaker { } try { - validators.get(policyType).encode(domainPolicy); + getValidator(policyType).encode(domainPolicy); } catch (CoderException e) { logger.error("policy {}:{} is not conformant", policyType, domainPolicy.getClass().getName(), e); return false; @@ -190,29 +189,21 @@ public class DomainMaker { public T convertTo(@NonNull ToscaConceptIdentifier policyType, @NonNull String json, @NonNull Class clazz) throws CoderException { if (isRegistered(policyType)) { - return validators.get(policyType).decode(json, clazz); + return getValidator(policyType).decode(json, clazz); } else { return nonValCoder.decode(json, clazz); } } - /** - * Converts a Tosca Policy Type specification to a domain-specific json specification. - */ - public String convertToSchema(@NonNull ToscaPolicyType policyType) { - // - // TODO: // NOSONAR - // 1. Convert Tosca Policy Type definition schema to suitable json schema. - // 2. Call registerValidator to register - throw new UnsupportedOperationException("schema generation from policy type is not supported"); - } - public boolean isRegistered(@NonNull ToscaConceptIdentifier policyType) { return validators.containsKey(policyType) || registerValidator(policyType); } + private StandardValCoder getValidator(ToscaConceptIdentifier policyType) { + return validators.get(policyType); + } - private String serialize(@NonNull ToscaPolicy policy) { + private String serialize(ToscaPolicy policy) { String rawPolicy = null; try { rawPolicy = nonValCoder.encode(policy); diff --git a/policy-utils/src/test/java/org/onap/policy/drools/metrics/MetricTest.java b/policy-utils/src/test/java/org/onap/policy/drools/metrics/MetricTest.java index 924d1c95..f1999cce 100644 --- a/policy-utils/src/test/java/org/onap/policy/drools/metrics/MetricTest.java +++ b/policy-utils/src/test/java/org/onap/policy/drools/metrics/MetricTest.java @@ -48,12 +48,12 @@ class MetricTest { void testPojo() { PojoClass metric = PojoClassFactory.getPojoClass(Metric.class); Validator val = ValidatorBuilder - .create() - .with(new SetterMustExistRule()) - .with(new GetterMustExistRule()) - .with(new SetterTester()) - .with(new GetterTester()) - .build(); + .create() + .with(new SetterMustExistRule()) + .with(new GetterMustExistRule()) + .with(new SetterTester()) + .with(new GetterTester()) + .build(); val.validate(metric); } @@ -190,4 +190,24 @@ class MetricTest { Instant now = Instant.now(); assertEquals(new SimpleDateFormat(Metric.DATE_FORMAT).format(Date.from(now)), Metric.toTimestamp(now)); } + + @Test + void testElapsedTime_EndTimeStartTimeNullValues() { + // test seems unnecessary, but when setElapsedTime receives null, + // the method tries to calculate elapsed time between start and end time, + // which only having the values was covered. + Metric metric = new Metric(); + + metric.setElapsedTime(null); + assertNull(metric.getElapsedTime()); + + metric.setEndTime(Instant.now()); + metric.setElapsedTime(null); + assertNull(metric.getElapsedTime()); + + metric = new Metric(); + metric.setStartTime(Instant.now()); + metric.setElapsedTime(null); + assertNull(metric.getElapsedTime()); + } } \ No newline at end of file diff --git a/policy-utils/src/test/java/org/onap/policy/drools/policies/DomainMakerTest.java b/policy-utils/src/test/java/org/onap/policy/drools/policies/DomainMakerTest.java index f8ffa503..8fbf237f 100644 --- a/policy-utils/src/test/java/org/onap/policy/drools/policies/DomainMakerTest.java +++ b/policy-utils/src/test/java/org/onap/policy/drools/policies/DomainMakerTest.java @@ -26,6 +26,8 @@ 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.mock; +import static org.mockito.Mockito.when; import java.io.IOException; import java.nio.file.Files; @@ -40,7 +42,7 @@ import org.onap.policy.drools.models.domains.a.Nested; import org.onap.policy.drools.models.domains.a.Properties; import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy; -import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyType; +import org.springframework.test.util.ReflectionTestUtils; class DomainMakerTest { @@ -62,6 +64,13 @@ class DomainMakerTest { policyTypeId.setVersion("2.0.0"); assertFalse(domainMaker.isConformant(policyTypeId, rawJsonPolicyType)); + + // for code coverage + assertThatThrownBy(() -> domainMaker.isConformant(null, "{\"json\":\"valid\"}")) + .hasMessageContaining("policyType is marked non-null but is null"); + + assertThatThrownBy(() -> domainMaker.isConformant(policyTypeId, null)) + .hasMessageContaining("json is marked non-null but is null"); } @Test @@ -93,6 +102,12 @@ class DomainMakerTest { // not registered schema for policy type policyTypeId.setVersion("2.0.0"); assertFalse(domainMaker.isDomainConformant(policyTypeId, domainAPolicy)); + + assertThatThrownBy(() -> domainMaker.isDomainConformant(null, domainAPolicy)) + .hasMessageContaining("policyType is marked non-null but is null"); + + assertThatThrownBy(() -> domainMaker.isDomainConformant(policyTypeId, null)) + .hasMessageContaining("domainPolicy is marked non-null but is null"); } @@ -117,6 +132,12 @@ class DomainMakerTest { policy2.setTypeVersion("4.2.5"); assertFalse(domainMaker.conformance(policy2)); assertFalse(domainMaker.conformance(policy2.getTypeIdentifier(), domainAPolicy)); + + assertThatThrownBy(() -> domainMaker.conformance(null, domainAPolicy)) + .hasMessageContaining("policyType is marked non-null but is null"); + + assertThatThrownBy(() -> domainMaker.conformance(null)) + .hasMessageContaining("policy is marked non-null but is null"); } @Test @@ -136,6 +157,15 @@ class DomainMakerTest { assertFalse(domainMaker.isConformant(policy)); assertFalse(domainMaker.registerValidator(policy.getTypeIdentifier(), "$schema")); + + assertThatThrownBy(() -> domainMaker.registerValidator(null)) + .hasMessageContaining("policyType is marked non-null but is null"); + + assertThatThrownBy(() -> domainMaker.registerValidator(null, "$schema")) + .hasMessageContaining("policyType is marked non-null but is null"); + + assertThatThrownBy(() -> domainMaker.registerValidator(policy.getTypeIdentifier(), null)) + .hasMessageContaining("schema is marked non-null but is null"); } @Test @@ -146,14 +176,21 @@ class DomainMakerTest { assertNotNull(domainMaker.convertTo(getToscaPolicy("src/test/resources/policyA-no-policy-type.json"), DomainAPolicy.class)); - } - @Test - void testConvertToSchema() { - ToscaPolicyType type = new ToscaPolicyType(); - assertThatThrownBy(() -> domainMaker - .convertToSchema(type)) - .isInstanceOf(UnsupportedOperationException.class); + assertThatThrownBy(() -> domainMaker.convertTo(null, DomainAPolicy.class)) + .hasMessageContaining("toscaPolicy is marked non-null but is null"); + + assertThatThrownBy(() -> domainMaker.convertTo(mock(ToscaPolicy.class), null)) + .hasMessageContaining("clazz is marked non-null but is null"); + + assertThatThrownBy(() -> domainMaker.convertTo(null, "json", DomainAPolicy.class)) + .hasMessageContaining("policyType is marked non-null but is null"); + + assertThatThrownBy(() -> domainMaker.convertTo(mock(ToscaConceptIdentifier.class), null, DomainAPolicy.class)) + .hasMessageContaining("json is marked non-null but is null"); + + assertThatThrownBy(() -> domainMaker.convertTo(mock(ToscaConceptIdentifier.class), "json", null)) + .hasMessageContaining("clazz is marked non-null but is null"); } @Test @@ -166,6 +203,25 @@ class DomainMakerTest { new ToscaConceptIdentifier("policy.type.external", "7.7.9"); assertFalse(domainMaker.isRegistered(policyTypeId2)); + assertThatThrownBy(() -> domainMaker.isRegistered(null)) + .hasMessageContaining("policyType is marked non-null but is null"); + } + + @Test + void testIsConformant_SerializeReturnsNull() throws CoderException { + var mockDomainMaker = mock(DomainMaker.class); + var mockToscaPolicy = mock(ToscaPolicy.class); + when(mockDomainMaker.isConformant(mockToscaPolicy)).thenCallRealMethod(); + + var mockCoder = mock(StandardCoder.class); + when(mockCoder.encode(mockToscaPolicy)).thenThrow(new CoderException("error")); + ReflectionTestUtils.setField(mockDomainMaker, "nonValCoder", mockCoder); + + assertFalse(mockDomainMaker.isConformant(mockToscaPolicy)); + + when(mockDomainMaker.conformance(mockToscaPolicy)).thenCallRealMethod(); + when(mockDomainMaker.isRegistered(mockToscaPolicy.getTypeIdentifier())).thenReturn(true); + assertFalse(mockDomainMaker.conformance(mockToscaPolicy)); } private String getJsonFromFile(String filePath) throws IOException { diff --git a/policy-utils/src/test/java/org/onap/policy/drools/utils/LookupTest.java b/policy-utils/src/test/java/org/onap/policy/drools/utils/LookupTest.java new file mode 100644 index 00000000..dd043b47 --- /dev/null +++ b/policy-utils/src/test/java/org/onap/policy/drools/utils/LookupTest.java @@ -0,0 +1,57 @@ +/*- + * ============LICENSE_START================================================ + * 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.utils; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; +import org.onap.policy.common.utils.security.CryptoCoder; + +class LookupTest { + + @Test + void testCryptoLookup() { + var cryptoCoder = new CryptoCoderValueLookup(new CryptoCoder() { + @Override + public String encrypt(String s) { + return String.valueOf(s.hashCode()); + } + + @Override + public String decrypt(String s) { + return s; + } + }); + + assertTrue(cryptoCoder.lookup("hello").startsWith("enc")); + assertNull(cryptoCoder.lookup(null)); + assertNull(cryptoCoder.lookup("")); + } + + @Test + void testEnvDefaultLookup() { + var envLookup = new EnvironmentVariableWithDefaultLookup(); + + assertNull(envLookup.lookup(null)); + assertNull(envLookup.lookup("")); + assertEquals("", envLookup.lookup(":")); + } +} \ No newline at end of file diff --git a/policy-utils/src/test/java/org/onap/policy/drools/utils/PropertyUtilTest.java b/policy-utils/src/test/java/org/onap/policy/drools/utils/PropertyUtilTest.java index f2676e5d..bec22237 100644 --- a/policy-utils/src/test/java/org/onap/policy/drools/utils/PropertyUtilTest.java +++ b/policy-utils/src/test/java/org/onap/policy/drools/utils/PropertyUtilTest.java @@ -22,6 +22,8 @@ package org.onap.policy.drools.utils; 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.assertTrue; import java.io.File; @@ -93,7 +95,8 @@ public class PropertyUtilTest { // create a directory for temporary files directory = new File(UUID.randomUUID().toString()); - directory.mkdir(); + var isDirCreated = directory.mkdir(); + logger.info("directory created: {}", isDirCreated); } /** @@ -141,8 +144,7 @@ public class PropertyUtilTest { public void propertiesChanged(Properties properties, Set changedKeys) { // When a notification is received, store the values in the // 'returns' array, and signal using the same array. - logger.info("Listener invoked: properties=" + properties - + ", changedKeys=" + changedKeys); + logger.info("Listener invoked: properties={}, changedKeys={}", properties, changedKeys); returns[0] = properties; returns[1] = changedKeys; synchronized (returns) { @@ -181,6 +183,73 @@ public class PropertyUtilTest { } + /** + * This tests the 'PropertyUtil.Listener' interface. + */ + @Test + void testListenerInterface() throws Exception { + logger.info("testListenerInterface: test receipt of dynamic updates"); + + // create initial property file + Properties prop1 = new Properties(); + prop1.setProperty("p1", "p1 value"); + prop1.setProperty("p2", "p2 value"); + prop1.setProperty("p3", "p3 value"); + logger.info("Create initial properties file: {}", prop1); + File file1 = createFile("createAndReadPropertyFile-2", prop1); + + // create a listener for the notification interface + Object[] returns = new Object[2]; + PropertyUtil.Listener listener = createListenerThread(returns); + + // read it in, and do a comparison + Properties prop2 = PropertyUtil.getProperties(file1, listener); + logger.info("Read in properties: {}", prop2); + assertEquals(prop1, prop2); + assertEquals("p1 value", prop2.getProperty("p1")); + assertEquals("p2 value", prop2.getProperty("p2")); + assertEquals("p3 value", prop2.getProperty("p3")); + + // make some changes, and update the file (p3 is left unchanged) + prop2.remove("p1"); // remove one property + prop2.setProperty("p2", "new p2 value"); // change one property + prop2.setProperty("p4", "p4 value"); // add a new property + logger.info("Modified properties: {}", prop2); + + // now, update the file, and wait for notification + synchronized (returns) { + createFile("createAndReadPropertyFile-2", prop2); + + // wait up to 60 seconds, although we should receive notification + // in 10 seconds or less (if things are working) + returns.wait(60000L); + } + + // verify we have the updates + assertEquals(prop2, returns[0]); + + // verify that we have the expected set of keys + assertEquals(new TreeSet<>(Arrays.asList("p1", "p2", "p4")), returns[1]); + + String filePath = file1.getAbsolutePath(); + PropertyUtil.stopListening(filePath, listener); + } + + @Test + void testGetProperties_ListenerNull() throws IOException { + String filepath = "src/test/resources/interpolation.properties"; + File propertiesFile = new File(filepath); + assertNotNull(propertiesFile); + PropertyUtil.Listener listener = null; + var result = PropertyUtil.getProperties(propertiesFile, listener); + assertNotNull(result); + assertInstanceOf(Properties.class, result); + + var anotherResult = PropertyUtil.getProperties(filepath, listener); + assertNotNull(anotherResult); + assertInstanceOf(Properties.class, anotherResult); + } + private void testGetDefaultCryptoSystemProps() throws IOException { // system properties + default crypto coder PropertyUtil.setDefaultCryptoCoder(new CryptoUtils(INTERPOLATION_CRYPTO_KEY)); @@ -251,54 +320,4 @@ public class PropertyUtilTest { assertEquals(System.getProperty("user.home"), props.getProperty(INTERPOLATION_SYS)); assertEquals(INTERPOLATION_ENVD_DEFAULT_VALUE, props.getProperty(INTERPOLATION_ENVD_DEFAULT)); } - - /** - * This tests the 'PropertyUtil.Listener' interface. - */ - @Test - void testListenerInterface() throws Exception { - logger.info("testListenerInterface: test receipt of dynamic updates"); - - // create initial property file - Properties prop1 = new Properties(); - prop1.setProperty("p1", "p1 value"); - prop1.setProperty("p2", "p2 value"); - prop1.setProperty("p3", "p3 value"); - logger.info("Create initial properties file: " + prop1); - File file1 = createFile("createAndReadPropertyFile-2", prop1); - - // create a listener for the notification interface - Object[] returns = new Object[2]; - PropertyUtil.Listener listener = createListenerThread(returns); - - // read it in, and do a comparison - Properties prop2 = PropertyUtil.getProperties(file1, listener); - logger.info("Read in properties: " + prop2); - assertEquals(prop1, prop2); - assertEquals("p1 value", prop2.getProperty("p1")); - assertEquals("p2 value", prop2.getProperty("p2")); - assertEquals("p3 value", prop2.getProperty("p3")); - - // make some changes, and update the file (p3 is left unchanged) - prop2.remove("p1"); // remove one property - prop2.setProperty("p2", "new p2 value"); // change one property - prop2.setProperty("p4", "p4 value"); // add a new property - logger.info("Modified properties: " + prop2); - - // now, update the file, and wait for notification - synchronized (returns) { - createFile("createAndReadPropertyFile-2", prop2); - - // wait up to 60 seconds, although we should receive notification - // in 10 seconds or less (if things are working) - returns.wait(60000L); - } - - // verify we have the updates - assertEquals(prop2, returns[0]); - - // verify that we have the expected set of keys - assertEquals(new TreeSet(Arrays.asList(new String[]{"p1", "p2", "p4"})), - returns[1]); - } } -- cgit 1.2.3-korg