diff options
Diffstat (limited to 'policy-core')
8 files changed, 479 insertions, 113 deletions
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 @@ <groupId>org.glassfish.hk2.external</groupId> <artifactId>jakarta.inject</artifactId> </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-test</artifactId> + </dependency> </dependencies> </project> 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<PolicyContainer> containers = new HashSet<>(); // maps feature objects to per-PolicyContainer data - private ConcurrentHashMap<Object, Object> adjuncts = new ConcurrentHashMap<>(); + private final ConcurrentHashMap<Object, Object> adjuncts = new ConcurrentHashMap<>(); // 'KieContainer' associated with this 'PolicyContainer' @Getter @@ -90,9 +92,9 @@ public class PolicyContainer implements Startable { * * <p>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<Message> 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<PolicySession> 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<PolicySession> 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: * - * <p>1) Initializes logging 2) Starts the DroolsPDP Integrity Monitor 3) Initilaizes persistence + * <p>1) Initializes logging 2) Starts the DroolsPDP Integrity Monitor 3) Initializes persistence * * <p>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<PolicyContainer> 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<PolicyContainer> containers = - PolicyContainer.getPolicyContainers(); - assertEquals(1, containers.size()); - assertTrue(containers.contains(container)); + Collection<PolicyContainer> 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<PolicySession> 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<PolicyContainer> 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<String, PolicySession> 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<KieServices.Factory> 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<String, PolicySession> 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<ManagementFactory> 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<AlwaysFailLock> { 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<AlwaysSuccessLock> { 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)); + } } |