diff options
95 files changed, 5488 insertions, 2760 deletions
@@ -31,11 +31,6 @@ repositories: - 'policy/drools-pdp' committers: - <<: *onap_releng_ptl - - name: 'Pamela Dragosh' - email: 'pd1248@att.com' - company: 'ATT' - id: 'pdragosh' - timezone: 'America/New_York' - name: 'Jorge Hernandez' email: 'jorge.hernandez-herrero@att.com' company: 'ATT' @@ -46,6 +41,11 @@ committers: company: 'Bell Canada' id: 'ramverma' timezone: 'America/Montreal' + - name: 'Liam Fallon' + email: 'liam.fallon@est.tech' + id: 'liamfallon' + company: 'Ericsson' + timezone: 'Europe/Ireland' - name: 'Ramesh Murugan Iyer' email: 'ramesh.murugan.iyer@est.tech' company: 'Ericsson' @@ -89,3 +89,7 @@ tsc: - type: 'Addition' name: 'Adheli Tavares' link: https://lists.onap.org/g/onap-tsc/message/9296 + #Stepped Down + - type: 'Removal' + name: 'Pamela Dragosh' + link: https://lists.onap.org/g/onap-tsc/message/9550 diff --git a/feature-distributed-locking/src/assembly/assemble_zip.xml b/feature-distributed-locking/src/assembly/assemble_zip.xml index 2112fbcd..3def9898 100644 --- a/feature-distributed-locking/src/assembly/assemble_zip.xml +++ b/feature-distributed-locking/src/assembly/assemble_zip.xml @@ -3,6 +3,7 @@ feature-distributed-locking ================================================================================ Copyright (C) 2018 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. @@ -59,12 +60,6 @@ <excludes/> </fileSet> <fileSet> - <directory>src/main/feature/db</directory> - <outputDirectory>db</outputDirectory> - <fileMode>0744</fileMode> - <excludes/> - </fileSet> - <fileSet> <directory>src/main/feature/install</directory> <outputDirectory>install</outputDirectory> <fileMode>0744</fileMode> diff --git a/feature-distributed-locking/src/main/feature/config/feature-distributed-locking.properties b/feature-distributed-locking/src/main/feature/config/feature-distributed-locking.properties index 69629e15..fa311260 100644 --- a/feature-distributed-locking/src/main/feature/config/feature-distributed-locking.properties +++ b/feature-distributed-locking/src/main/feature/config/feature-distributed-locking.properties @@ -3,7 +3,7 @@ # ONAP # ================================================================================ # Copyright (C) 2018-2019, 2021-2022 AT&T Intellectual Property. All rights reserved. -# Modifications Copyright (C) 2023 Nordix Foundation. +# Modifications Copyright (C) 2023-2024 Nordix Foundation. # ================================================================================ # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ ### #Database properties -jakarta.persistence.jdbc.driver=org.mariadb.jdbc.Driver +jakarta.persistence.jdbc.driver=${envd:JDBC_DRIVER} jakarta.persistence.jdbc.url=${envd:JDBC_URL}pooling${envd:JDBC_OPTS} jakarta.persistence.jdbc.user=${envd:SQL_USER} jakarta.persistence.jdbc.password=${envd:SQL_PASSWORD} diff --git a/feature-distributed-locking/src/main/feature/db/pooling/sql/1804-distributedlocking.downgrade.sql b/feature-distributed-locking/src/main/feature/db/pooling/sql/1804-distributedlocking.downgrade.sql deleted file mode 100644 index cd1b815d..00000000 --- a/feature-distributed-locking/src/main/feature/db/pooling/sql/1804-distributedlocking.downgrade.sql +++ /dev/null @@ -1,20 +0,0 @@ -# ============LICENSE_START======================================================= -# feature-distributed-locking -# ================================================================================ -# Copyright (C) 2018 AT&T Intellectual Property. All rights reserved. -# ================================================================================ -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ============LICENSE_END========================================================= - -use pooling; -drop table if exists locks;
\ No newline at end of file diff --git a/feature-distributed-locking/src/main/feature/db/pooling/sql/1804-distributedlocking.upgrade.sql b/feature-distributed-locking/src/main/feature/db/pooling/sql/1804-distributedlocking.upgrade.sql deleted file mode 100644 index 07b30738..00000000 --- a/feature-distributed-locking/src/main/feature/db/pooling/sql/1804-distributedlocking.upgrade.sql +++ /dev/null @@ -1,30 +0,0 @@ -# ============LICENSE_START======================================================= -# feature-distributed-locking -# ================================================================================ -# Copyright (C) 2018, 2022 AT&T Intellectual Property. All rights reserved. -# ================================================================================ -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ============LICENSE_END========================================================= - -SET foreign_key_checks=0; - -CREATE TABLE if NOT EXISTS pooling.locks( - resourceId VARCHAR(128), - host VARCHAR(128), - owner VARCHAR(128), - expirationTime BIGINT, - PRIMARY KEY (resourceId), - INDEX idx_expirationTime(expirationTime), - INDEX idx_host(host)); - -SET foreign_key_checks=1;
\ No newline at end of file diff --git a/feature-distributed-locking/src/main/feature/db/pooling/sql/1811-distributedlocking.downgrade.sql b/feature-distributed-locking/src/main/feature/db/pooling/sql/1811-distributedlocking.downgrade.sql deleted file mode 100644 index 55a883f2..00000000 --- a/feature-distributed-locking/src/main/feature/db/pooling/sql/1811-distributedlocking.downgrade.sql +++ /dev/null @@ -1,19 +0,0 @@ -# ============LICENSE_START======================================================= -# feature-distributed-locking -# ================================================================================ -# Copyright (C) 2018, 2021 AT&T Intellectual Property. All rights reserved. -# ================================================================================ -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ============LICENSE_END========================================================= - -ALTER TABLE pooling.locks modify if exists expirationTime bigint(20) default 0; diff --git a/feature-distributed-locking/src/main/feature/db/pooling/sql/1811-distributedlocking.upgrade.sql b/feature-distributed-locking/src/main/feature/db/pooling/sql/1811-distributedlocking.upgrade.sql deleted file mode 100644 index 0cdad5b9..00000000 --- a/feature-distributed-locking/src/main/feature/db/pooling/sql/1811-distributedlocking.upgrade.sql +++ /dev/null @@ -1,23 +0,0 @@ -# ============LICENSE_START======================================================= -# feature-distributed-locking -# ================================================================================ -# Copyright (C) 2018, 2021-2022 AT&T Intellectual Property. All rights reserved. -# ================================================================================ -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ============LICENSE_END========================================================= - -SET foreign_key_checks=0; - -ALTER TABLE pooling.locks MODIFY expirationTime TIMESTAMP DEFAULT '1971-01-01 00:00:00.000000'; - -SET foreign_key_checks=1; diff --git a/feature-distributed-locking/src/main/feature/install/disable b/feature-distributed-locking/src/main/feature/install/disable deleted file mode 100644 index be455734..00000000 --- a/feature-distributed-locking/src/main/feature/install/disable +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env sh - -# ============LICENSE_START======================================================= -# ONAP -# ================================================================================ -# Copyright (C) 2018-2021 AT&T Intellectual Property. All rights reserved. -# ================================================================================ -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ============LICENSE_END========================================================= - -if [ "${DEBUG}" = "y" ]; then - set -x -fi - -${POLICY_HOME}/bin/db-migrator -s pooling -o downgrade - diff --git a/feature-distributed-locking/src/main/feature/install/enable b/feature-distributed-locking/src/main/feature/install/enable deleted file mode 100644 index af202f56..00000000 --- a/feature-distributed-locking/src/main/feature/install/enable +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env sh - -# ============LICENSE_START======================================================= -# ONAP -# ================================================================================ -# Copyright (C) 2018-2021 AT&T Intellectual Property. All rights reserved. -# ================================================================================ -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ============LICENSE_END========================================================= - -if [ "${DEBUG}" = "y" ]; then - set -x -fi - -${POLICY_HOME}/bin/db-migrator -s pooling -o upgrade - diff --git a/feature-distributed-locking/src/main/java/org/onap/policy/distributed/locking/DistributedLockManager.java b/feature-distributed-locking/src/main/java/org/onap/policy/distributed/locking/DistributedLockManager.java index d7f857eb..e9f1453a 100644 --- a/feature-distributed-locking/src/main/java/org/onap/policy/distributed/locking/DistributedLockManager.java +++ b/feature-distributed-locking/src/main/java/org/onap/policy/distributed/locking/DistributedLockManager.java @@ -3,6 +3,7 @@ * ONAP * ================================================================================ * Copyright (C) 2019-2022 AT&T Intellectual Property. All rights reserved. + * Modifications Copyright (C) 2024 Nordix Foundation. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,6 +25,9 @@ import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import java.sql.SQLTransientException; +import java.sql.Timestamp; +import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.HashSet; import java.util.Map; import java.util.Properties; @@ -57,11 +61,8 @@ import org.slf4j.LoggerFactory; * Distributed implementation of the Lock Feature. Maintains locks across servers using a * shared DB. * - * <p/> - * Note: this implementation does <i>not</i> honor the waitForLocks={@code true} - * parameter. - * - * <p/> + * <p>Note: this implementation does <i>not</i> honor the waitForLocks={@code true} + * parameter.<p/> * Additional Notes: * <dl> * <li>The <i>owner</i> field in the DB is not derived from the lock's owner info, but is @@ -77,7 +78,7 @@ import org.slf4j.LoggerFactory; * </dl> */ public class DistributedLockManager extends LockManager<DistributedLockManager.DistributedLock> - implements PolicyEngineFeatureApi { + implements PolicyEngineFeatureApi { private static final Logger logger = LoggerFactory.getLogger(DistributedLockManager.class); @@ -141,11 +142,11 @@ public class DistributedLockManager extends LockManager<DistributedLockManager.D } @Override - public PolicyResourceLockManager beforeCreateLockManager(PolicyEngine engine, Properties properties) { + public PolicyResourceLockManager beforeCreateLockManager() { try { this.pdpName = PolicyEngineConstants.getManager().getPdpName(); - this.featProps = new DistributedLockProperties(getProperties(CONFIGURATION_PROPERTIES_NAME)); + this.featProps = new DistributedLockProperties(getProperties()); this.dataSource = makeDataSource(); return this; @@ -176,9 +177,9 @@ public class DistributedLockManager extends LockManager<DistributedLockManager.D * Make data source. * * @return a new, pooled data source - * @throws Exception exception + * @throws SQLException exception */ - protected BasicDataSource makeDataSource() throws Exception { + protected BasicDataSource makeDataSource() throws SQLException { var props = new Properties(); props.put("driverClassName", featProps.getDbDriver()); props.put("url", featProps.getDbUrl()); @@ -199,7 +200,7 @@ public class DistributedLockManager extends LockManager<DistributedLockManager.D logger.info("deleting all expired locks from the DB"); try (var conn = dataSource.getConnection(); - var stmt = conn.prepareStatement("DELETE FROM pooling.locks WHERE expirationTime <= now()")) { + var stmt = conn.prepareStatement("DELETE FROM pooling.locks WHERE expirationTime <= now()")) { int ndel = stmt.executeUpdate(); logger.info("deleted {} expired locks from the DB", ndel); @@ -398,17 +399,17 @@ public class DistributedLockManager extends LockManager<DistributedLockManager.D /** * Constructs the object. * - * @param state initial state of the lock + * @param state initial state of the lock * @param resourceId identifier of the resource to be locked - * @param ownerKey information identifying the owner requesting the lock - * @param holdSec amount of time, in seconds, for which the lock should be held, - * after which it will automatically be released - * @param callback callback to be invoked once the lock is granted, or - * subsequently lost; must not be {@code null} - * @param feature feature containing this lock + * @param ownerKey information identifying the owner requesting the lock + * @param holdSec amount of time, in seconds, for which the lock should be held, + * after which it will automatically be released + * @param callback callback to be invoked once the lock is granted, or + * subsequently lost; must not be {@code null} + * @param feature feature containing this lock */ public DistributedLock(LockState state, String resourceId, String ownerKey, int holdSec, LockCallback callback, - DistributedLockManager feature) { + DistributedLockManager feature) { super(state, resourceId, ownerKey, holdSec, callback); this.feature = feature; @@ -531,7 +532,6 @@ public class DistributedLockManager extends LockManager<DistributedLockManager.D * there are no more requests in the queue. * * @param prevReq the previous request that was just run - * * @return the next request, or {@code null} if the queue is empty */ private synchronized RunnableWithEx getNextRequest(RunnableWithEx prevReq) { @@ -699,19 +699,19 @@ public class DistributedLockManager extends LockManager<DistributedLockManager.D * Inserts the lock into the DB. * * @param conn DB connection - * @return {@code true} if a record was successfully inserted, {@code false} - * otherwise + * @return {@code true} if a record was successfully inserted, {@code false}otherwise * @throws SQLException if a DB error occurs */ protected boolean doDbInsert(Connection conn) throws SQLException { logger.info("insert lock record {}", this); - try (var stmt = conn.prepareStatement("INSERT INTO pooling.locks (resourceId, host, owner, expirationTime) " - + "values (?, ?, ?, timestampadd(second, ?, now()))")) { + var time = Instant.now().plus(getHoldSec(), ChronoUnit.SECONDS); + String sql = "INSERT INTO pooling.locks (resourceId, host, owner, expirationTime) values (?, ?, ?, ?)"; + try (var stmt = conn.prepareStatement(sql)) { stmt.setString(1, getResourceId()); stmt.setString(2, feature.pdpName); stmt.setString(3, feature.uuidString); - stmt.setInt(4, getHoldSec()); + stmt.setTimestamp(4, new Timestamp(time.toEpochMilli())); stmt.executeUpdate(); @@ -726,20 +726,21 @@ public class DistributedLockManager extends LockManager<DistributedLockManager.D * Updates the lock in the DB. * * @param conn DB connection - * @return {@code true} if a record was successfully updated, {@code false} - * otherwise + * @return {@code true} if a record was successfully updated, {@code false} otherwise * @throws SQLException if a DB error occurs */ protected boolean doDbUpdate(Connection conn) throws SQLException { logger.info("update lock record {}", this); - try (var stmt = conn.prepareStatement("UPDATE pooling.locks SET resourceId=?, host=?, owner=?," - + " expirationTime=timestampadd(second, ?, now()) WHERE resourceId=?" - + " AND ((host=? AND owner=?) OR expirationTime < now())")) { + var time = Instant.now().plus(getHoldSec(), ChronoUnit.SECONDS); + var query = "UPDATE pooling.locks SET resourceId=?, host=?, owner=?," + + " expirationTime=? WHERE resourceId=?" + + " AND ((host=? AND owner=?) OR expirationTime < now())"; + try (var stmt = conn.prepareStatement(query)) { stmt.setString(1, getResourceId()); stmt.setString(2, feature.pdpName); stmt.setString(3, feature.uuidString); - stmt.setInt(4, getHoldSec()); + stmt.setTimestamp(4, new Timestamp(time.toEpochMilli())); stmt.setString(5, getResourceId()); stmt.setString(6, this.hostName); @@ -764,8 +765,8 @@ public class DistributedLockManager extends LockManager<DistributedLockManager.D */ protected void doDbDelete(Connection conn) throws SQLException { logger.info("delete lock record {}", this); - try (var stmt = conn - .prepareStatement("DELETE FROM pooling.locks WHERE resourceId=? AND host=? AND owner=?")) { + var query = "DELETE FROM pooling.locks WHERE resourceId=? AND host=? AND owner=?"; + try (var stmt = conn.prepareStatement(query)) { stmt.setString(1, getResourceId()); stmt.setString(2, this.hostName); @@ -793,8 +794,8 @@ public class DistributedLockManager extends LockManager<DistributedLockManager.D @Override public String toString() { return "DistributedLock [state=" + getState() + ", resourceId=" + getResourceId() + ", ownerKey=" - + getOwnerKey() + ", holdSec=" + getHoldSec() + ", hostName=" + hostName + ", uuidString=" - + uuidString + "]"; + + getOwnerKey() + ", holdSec=" + getHoldSec() + ", hostName=" + hostName + ", uuidString=" + + uuidString + "]"; } } @@ -811,12 +812,13 @@ public class DistributedLockManager extends LockManager<DistributedLockManager.D // these may be overridden by junit tests - protected Properties getProperties(String fileName) { - return SystemPersistenceConstants.getManager().getProperties(fileName); + protected Properties getProperties() { + return SystemPersistenceConstants.getManager().getProperties( + DistributedLockManager.CONFIGURATION_PROPERTIES_NAME); } protected DistributedLock makeLock(LockState state, String resourceId, String ownerKey, int holdSec, - LockCallback callback) { + LockCallback callback) { return new DistributedLock(state, resourceId, ownerKey, holdSec, callback, this); } } diff --git a/feature-distributed-locking/src/test/java/org/onap/policy/distributed/locking/DistributedLockManagerTest.java b/feature-distributed-locking/src/test/java/org/onap/policy/distributed/locking/DistributedLockManagerTest.java index 2e173cf0..579d53cc 100644 --- a/feature-distributed-locking/src/test/java/org/onap/policy/distributed/locking/DistributedLockManagerTest.java +++ b/feature-distributed-locking/src/test/java/org/onap/policy/distributed/locking/DistributedLockManagerTest.java @@ -141,12 +141,12 @@ class DistributedLockManagerTest { private LockCallback callback; @Mock - private BasicDataSource datasrc; + private BasicDataSource dataSource; private DistributedLock lock; - private AtomicInteger nactive; - private AtomicInteger nsuccesses; + private AtomicInteger numActive; + private AtomicInteger numSuccess; private DistributedLockManager feature; AutoCloseable closeable; @@ -204,8 +204,8 @@ class DistributedLockManagerTest { session.setPolicySession(); - nactive = new AtomicInteger(0); - nsuccesses = new AtomicInteger(0); + numActive = new AtomicInteger(0); + numSuccess = new AtomicInteger(0); cleanDb(); @@ -248,7 +248,7 @@ class DistributedLockManagerTest { @Test void testBeforeCreateLockManager() { - assertSame(feature, feature.beforeCreateLockManager(engine, new Properties())); + assertSame(feature, feature.beforeCreateLockManager()); } /** @@ -260,13 +260,12 @@ class DistributedLockManagerTest { feature = new MyLockingFeature(false) { @Override - protected Properties getProperties(String fileName) { + protected Properties getProperties() { throw new IllegalArgumentException(EXPECTED_EXCEPTION); } }; - Properties props = new Properties(); - assertThatThrownBy(() -> feature.beforeCreateLockManager(engine, props)) + assertThatThrownBy(() -> feature.beforeCreateLockManager()) .isInstanceOf(DistributedLockManagerException.class); } @@ -317,7 +316,6 @@ class DistributedLockManagerTest { /** * Tests deleteExpiredDbLocks(), when getConnection() throws an exception. - * */ @Test void testDeleteExpiredDbLocksEx() { @@ -347,7 +345,6 @@ class DistributedLockManagerTest { /** * Tests afterStop(), when the data source throws an exception when close() is called. - * */ @Test void testAfterStopEx() { @@ -416,10 +413,10 @@ class DistributedLockManagerTest { void testCreateLockNotLatestInstance() { DistributedLockManager.setLatestInstance(null); - Lock lock = feature.createLock(RESOURCE, OWNER_KEY, HOLD_SEC, callback, false); - assertTrue(lock.isUnavailable()); + Lock newLock = feature.createLock(RESOURCE, OWNER_KEY, HOLD_SEC, callback, false); + assertTrue(newLock.isUnavailable()); verify(callback, never()).lockAvailable(any()); - verify(callback).lockUnavailable(lock); + verify(callback).lockUnavailable(newLock); } @Test @@ -532,11 +529,11 @@ class DistributedLockManagerTest { feature = new MyLockingFeature(true) { @Override - protected BasicDataSource makeDataSource() throws Exception { + protected BasicDataSource makeDataSource() throws SQLException { // get the real data source BasicDataSource src2 = super.makeDataSource(); - when(datasrc.getConnection()).thenAnswer(answer -> { + when(dataSource.getConnection()).thenAnswer(answer -> { DistributedLock lck = freeLock.getAndSet(null); if (lck != null) { // free it @@ -549,7 +546,7 @@ class DistributedLockManagerTest { return src2.getConnection(); }); - return datasrc; + return dataSource; } }; @@ -596,11 +593,11 @@ class DistributedLockManagerTest { @Test void testDistributedLockNoArgs() { - DistributedLock lock = new DistributedLock(); - assertNull(lock.getResourceId()); - assertNull(lock.getOwnerKey()); - assertNull(lock.getCallback()); - assertEquals(0, lock.getHoldSec()); + DistributedLock newLock = new DistributedLock(); + assertNull(newLock.getResourceId()); + assertNull(newLock.getOwnerKey()); + assertNull(newLock.getCallback()); + assertEquals(0, newLock.getHoldSec()); } @Test @@ -615,15 +612,15 @@ class DistributedLockManagerTest { @Test void testDistributedLockSerializable() throws Exception { - DistributedLock lock = getLock(RESOURCE, callback); - lock = roundTrip(lock); + DistributedLock newLock = getLock(RESOURCE, callback); + newLock = roundTrip(newLock); - assertTrue(lock.isWaiting()); + assertTrue(newLock.isWaiting()); - assertEquals(RESOURCE, lock.getResourceId()); - assertEquals(OWNER_KEY, lock.getOwnerKey()); - assertNull(lock.getCallback()); - assertEquals(HOLD_SEC, lock.getHoldSec()); + assertEquals(RESOURCE, newLock.getResourceId()); + assertEquals(OWNER_KEY, newLock.getOwnerKey()); + assertNull(newLock.getCallback()); + assertEquals(HOLD_SEC, newLock.getHoldSec()); } @Test @@ -690,13 +687,13 @@ class DistributedLockManagerTest { */ @Test void testDistributedLockFreeSerialized() throws Exception { - DistributedLock lock = getLock(RESOURCE, callback); + DistributedLock newLock = getLock(RESOURCE, callback); feature = new MyLockingFeature(true); - lock = roundTrip(lock); - assertTrue(lock.free()); - assertTrue(lock.isUnavailable()); + newLock = roundTrip(newLock); + assertTrue(newLock.free()); + assertTrue(newLock.isUnavailable()); } /** @@ -706,13 +703,13 @@ class DistributedLockManagerTest { */ @Test void testDistributedLockFreeNoFeature() throws Exception { - DistributedLock lock = getLock(RESOURCE, callback); + DistributedLock newLock = getLock(RESOURCE, callback); DistributedLockManager.setLatestInstance(null); - lock = roundTrip(lock); - assertFalse(lock.free()); - assertTrue(lock.isUnavailable()); + newLock = roundTrip(newLock); + assertFalse(newLock.free()); + assertTrue(newLock.isUnavailable()); } /** @@ -788,28 +785,28 @@ class DistributedLockManagerTest { */ @Test void testDistributedLockExtendSerialized() throws Exception { - DistributedLock lock = getLock(RESOURCE, callback); + DistributedLock newLock = getLock(RESOURCE, callback); // run doLock runLock(0, 0); - assertTrue(lock.isActive()); + assertTrue(newLock.isActive()); feature = new MyLockingFeature(true); - lock = roundTrip(lock); - assertTrue(lock.isActive()); + newLock = roundTrip(newLock); + assertTrue(newLock.isActive()); - LockCallback scallback = mock(LockCallback.class); + LockCallback mockCallback = mock(LockCallback.class); - lock.extend(HOLD_SEC, scallback); - assertTrue(lock.isWaiting()); + newLock.extend(HOLD_SEC, mockCallback); + assertTrue(newLock.isWaiting()); // run doExtend (in new feature) runLock(0, 0); - assertTrue(lock.isActive()); + assertTrue(newLock.isActive()); - verify(scallback).lockAvailable(lock); - verify(scallback, never()).lockUnavailable(lock); + verify(mockCallback).lockAvailable(newLock); + verify(mockCallback, never()).lockUnavailable(newLock); } /** @@ -819,24 +816,24 @@ class DistributedLockManagerTest { */ @Test void testDistributedLockExtendNoFeature() throws Exception { - DistributedLock lock = getLock(RESOURCE, callback); + DistributedLock newLock = getLock(RESOURCE, callback); // run doLock runLock(0, 0); - assertTrue(lock.isActive()); + assertTrue(newLock.isActive()); DistributedLockManager.setLatestInstance(null); - lock = roundTrip(lock); - assertTrue(lock.isActive()); + newLock = roundTrip(newLock); + assertTrue(newLock.isActive()); LockCallback scallback = mock(LockCallback.class); - lock.extend(HOLD_SEC, scallback); - assertTrue(lock.isUnavailable()); + newLock.extend(HOLD_SEC, scallback); + assertTrue(newLock.isUnavailable()); - verify(scallback, never()).lockAvailable(lock); - verify(scallback).lockUnavailable(lock); + verify(scallback, never()).lockAvailable(newLock); + verify(scallback).lockUnavailable(newLock); } /** @@ -964,7 +961,7 @@ class DistributedLockManagerTest { feature = new MyLockingFeature(true) { @Override protected DistributedLock makeLock(LockState state, String resourceId, String ownerKey, int holdSec, - LockCallback callback) { + LockCallback callback) { return new DistributedLock(state, resourceId, ownerKey, holdSec, callback, feature) { private static final long serialVersionUID = 1L; @@ -1015,13 +1012,13 @@ class DistributedLockManagerTest { @Test void testDistributedLockDoRequestRunExWaiting() throws SQLException { // throw run-time exception - when(datasrc.getConnection()).thenThrow(new IllegalStateException(EXPECTED_EXCEPTION)); + when(dataSource.getConnection()).thenThrow(new IllegalStateException(EXPECTED_EXCEPTION)); // use a data source that throws an exception when getConnection() is called feature = new MyLockingFeature(true) { @Override protected BasicDataSource makeDataSource() { - return datasrc; + return dataSource; } }; @@ -1045,7 +1042,7 @@ class DistributedLockManagerTest { @Test void testDistributedLockDoRequestRunExUnavailable() throws SQLException { // throw run-time exception - when(datasrc.getConnection()).thenAnswer(answer -> { + when(dataSource.getConnection()).thenAnswer(answer -> { lock.free(); throw new IllegalStateException(EXPECTED_EXCEPTION); }); @@ -1054,7 +1051,7 @@ class DistributedLockManagerTest { feature = new MyLockingFeature(true) { @Override protected BasicDataSource makeDataSource() { - return datasrc; + return dataSource; } }; @@ -1232,7 +1229,6 @@ class DistributedLockManagerTest { /** * Tests doUnlock() when a DB exception is thrown. - * */ @Test void testDistributedLockDoUnlockEx() { @@ -1337,7 +1333,6 @@ class DistributedLockManagerTest { /** * Tests doExtend() when both update and insert fail. - * */ @Test void testDistributedLockDoExtendNeitherSucceeds() { @@ -1348,7 +1343,7 @@ class DistributedLockManagerTest { feature = new MyLockingFeature(true) { @Override protected DistributedLock makeLock(LockState state, String resourceId, String ownerKey, int holdSec, - LockCallback callback) { + LockCallback callback) { return new DistributedLock(state, resourceId, ownerKey, holdSec, callback, feature) { private static final long serialVersionUID = 1L; private int ntimes = 0; @@ -1437,7 +1432,7 @@ class DistributedLockManagerTest { feature = new DistributedLockManager(); // this should create a thread pool - feature.beforeCreateLockManager(engine, new Properties()); + feature.beforeCreateLockManager(); feature.afterStart(engine); assertThatCode(this::shutdownFeature).doesNotThrowAnyException(); @@ -1447,14 +1442,14 @@ class DistributedLockManagerTest { * Performs a multithreaded test of the locking facility. * * @throws InterruptedException if the current thread is interrupted while waiting for - * the background threads to complete + * the background threads to complete */ @Test void testMultiThreaded() throws InterruptedException { ReflectionTestUtils.setField(PolicyEngineConstants.getManager(), POLICY_ENGINE_EXECUTOR_FIELD, realExec); feature = new DistributedLockManager(); - feature.beforeCreateLockManager(PolicyEngineConstants.getManager(), new Properties()); + feature.beforeCreateLockManager(); feature.afterStart(PolicyEngineConstants.getManager()); List<MyThread> threads = new ArrayList<>(MAX_THREADS); @@ -1475,7 +1470,7 @@ class DistributedLockManagerTest { } } - assertTrue(nsuccesses.get() > 0); + assertTrue(numSuccess.get() > 0); } private DistributedLock getLock(String resource, LockCallback callback) { @@ -1511,9 +1506,9 @@ class DistributedLockManagerTest { /** * Runs a lock action (e.g., doLock, doUnlock). * - * @param nskip number of actions in the work queue to skip + * @param nskip number of actions in the work queue to skip * @param nadditional number of additional actions that appear in the work queue - * <i>after</i> the desired action + * <i>after</i> the desired action */ void runLock(int nskip, int nadditional) { ArgumentCaptor<Runnable> captor = ArgumentCaptor.forClass(Runnable.class); @@ -1544,7 +1539,7 @@ class DistributedLockManagerTest { */ private int getRecordCount() throws SQLException { try (PreparedStatement stmt = conn.prepareStatement("SELECT count(*) FROM pooling.locks"); - ResultSet result = stmt.executeQuery()) { + ResultSet result = stmt.executeQuery()) { if (result.next()) { return result.getInt(1); @@ -1561,16 +1556,16 @@ class DistributedLockManagerTest { * * @param resourceId ID of the resource of interest * @param uuidString UUID string of the owner - * @param holdSec seconds for which the lock was to be held - * @param tbegin earliest time, in milliseconds, at which the record could have been - * inserted into the DB + * @param holdSec seconds for which the lock was to be held + * @param tbegin earliest time, in milliseconds, at which the record could have been + * inserted into the DB * @return {@code true} if a record is found, {@code false} otherwise * @throws SQLException if an error occurs accessing the DB */ private boolean recordInRange(String resourceId, String uuidString, int holdSec, long tbegin) throws SQLException { try (PreparedStatement stmt = - conn.prepareStatement("SELECT timestampdiff(second, now(), expirationTime) FROM pooling.locks" - + " WHERE resourceId=? AND host=? AND owner=?")) { + conn.prepareStatement("SELECT timestampdiff(second, now(), expirationTime) FROM pooling.locks" + + " WHERE resourceId=? AND host=? AND owner=?")) { stmt.setString(1, resourceId); stmt.setString(2, feature.getPdpName()); @@ -1592,8 +1587,8 @@ class DistributedLockManagerTest { /** * Inserts a record into the DB. * - * @param resourceId ID of the resource of interest - * @param uuidString UUID string of the owner + * @param resourceId ID of the resource of interest + * @param uuidString UUID string of the owner * @param expireOffset offset, in seconds, from "now", at which the lock should expire * @throws SQLException if an error occurs accessing the DB */ @@ -1604,8 +1599,8 @@ class DistributedLockManagerTest { private void insertRecord(String resourceId, String hostName, String uuidString, int expireOffset) throws SQLException { try (PreparedStatement stmt = - conn.prepareStatement("INSERT INTO pooling.locks (resourceId, host, owner, expirationTime) " - + "values (?, ?, ?, timestampadd(second, ?, now()))")) { + conn.prepareStatement("INSERT INTO pooling.locks (resourceId, host, owner, expirationTime) " + + "values (?, ?, ?, timestampadd(second, ?, now()))")) { stmt.setString(1, resourceId); stmt.setString(2, hostName); @@ -1619,8 +1614,8 @@ class DistributedLockManagerTest { /** * Updates a record in the DB. * - * @param resourceId ID of the resource of interest - * @param newUuid UUID string of the <i>new</i> owner + * @param resourceId ID of the resource of interest + * @param newUuid UUID string of the <i>new</i> owner * @param expireOffset offset, in seconds, from "now", at which the lock should expire * @throws SQLException if an error occurs accessing the DB */ @@ -1650,7 +1645,7 @@ class DistributedLockManagerTest { ReflectionTestUtils.setField(PolicyEngineConstants.getManager(), POLICY_ENGINE_EXECUTOR_FIELD, exsvc); if (init) { - beforeCreateLockManager(engine, new Properties()); + beforeCreateLockManager(); start(); afterStart(engine); } @@ -1671,14 +1666,14 @@ class DistributedLockManagerTest { this.isTransient = isTransient; - this.beforeCreateLockManager(engine, new Properties()); + this.beforeCreateLockManager(); this.start(); this.afterStart(engine); } @Override - protected BasicDataSource makeDataSource() throws Exception { - lenient().when(datasrc.getConnection()).thenAnswer(answer -> { + protected BasicDataSource makeDataSource() throws SQLException { + lenient().when(dataSource.getConnection()).thenAnswer(answer -> { if (freeLock) { freeLock = false; lock.free(); @@ -1687,9 +1682,9 @@ class DistributedLockManagerTest { throw makeEx(); }); - doThrow(makeEx()).when(datasrc).close(); + doThrow(makeEx()).when(dataSource).close(); - return datasrc; + return dataSource; } protected SQLException makeEx() { @@ -1715,7 +1710,7 @@ class DistributedLockManagerTest { @Override protected DistributedLock makeLock(LockState state, String resourceId, String ownerKey, int holdSec, - LockCallback callback) { + LockCallback callback) { return new DistributedLock(state, resourceId, ownerKey, holdSec, callback, feature) { private static final long serialVersionUID = 1L; @@ -1785,27 +1780,27 @@ class DistributedLockManagerTest { } }; - Lock lock = feature.createLock(RESOURCE, getName(), HOLD_SEC, cb, false); + Lock newLock = feature.createLock(RESOURCE, getName(), HOLD_SEC, cb, false); // wait for callback, whether available or unavailable assertTrue(sem.tryAcquire(5, TimeUnit.SECONDS)); - if (!lock.isActive()) { + if (!newLock.isActive()) { return; } - nsuccesses.incrementAndGet(); + numSuccess.incrementAndGet(); - assertEquals(1, nactive.incrementAndGet()); + assertEquals(1, numActive.incrementAndGet()); - lock.extend(HOLD_SEC2, cb); + newLock.extend(HOLD_SEC2, cb); assertTrue(sem.tryAcquire(5, TimeUnit.SECONDS)); - assertTrue(lock.isActive()); + assertTrue(newLock.isActive()); // decrement BEFORE free() - nactive.decrementAndGet(); + numActive.decrementAndGet(); - assertTrue(lock.free()); - assertTrue(lock.isUnavailable()); + assertTrue(newLock.free()); + assertTrue(newLock.isUnavailable()); } catch (InterruptedException e) { Thread.currentThread().interrupt(); diff --git a/feature-healthcheck/src/assembly/assemble_zip.xml b/feature-healthcheck/src/assembly/assemble_zip.xml index 0e2eaa8b..3f60900e 100644 --- a/feature-healthcheck/src/assembly/assemble_zip.xml +++ b/feature-healthcheck/src/assembly/assemble_zip.xml @@ -3,6 +3,7 @@ feature-healthcheck ================================================================================ Copyright (C) 2017 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. @@ -59,12 +60,6 @@ <excludes/> </fileSet> <fileSet> - <directory>src/main/feature/db</directory> - <outputDirectory>db</outputDirectory> - <fileMode>0744</fileMode> - <excludes/> - </fileSet> - <fileSet> <directory>src/main/feature/install</directory> <outputDirectory>install</outputDirectory> <fileMode>0744</fileMode> diff --git a/feature-healthcheck/src/test/java/org/onap/policy/drools/healthcheck/HealthCheckFeatureTest.java b/feature-healthcheck/src/test/java/org/onap/policy/drools/healthcheck/HealthCheckFeatureTest.java index 7cf7ed5f..90413041 100644 --- a/feature-healthcheck/src/test/java/org/onap/policy/drools/healthcheck/HealthCheckFeatureTest.java +++ b/feature-healthcheck/src/test/java/org/onap/policy/drools/healthcheck/HealthCheckFeatureTest.java @@ -23,6 +23,7 @@ package org.onap.policy.drools.healthcheck; 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.Mockito.doAnswer; @@ -115,58 +116,31 @@ public class HealthCheckFeatureTest { var reports = healthcheck(manager); serverChecks(reports); checkReports(reports, List.of("STUCK"), - HttpStatus.OK_200, HttpStatus.getMessage(200)); + HttpStatus.OK_200, HttpStatus.getMessage(200)); checkReports(reports, List.of("echo"), 1, "[echo:{java.lang.String=1}]"); /* mock controller and clients stuck */ RestMockHealthCheck.stuck = true; // make the server named STUCK unresponsive doAnswer(AdditionalAnswers - .answersWithDelay((manager.getTimeoutSeconds() + 2) * 1000L, - invocationOnMock -> new HashMap<String, Integer>())) - .when(manager).getFactTypes(any(), any()); + .answersWithDelay((manager.getTimeoutSeconds() + 2) * 1000L, + invocationOnMock -> new HashMap<String, Integer>())) + .when(manager).getFactTypes(any(), any()); reports = healthcheck(manager); RestMockHealthCheck.stuck = false; // unstuck the server named STUCK serverChecks(reports); checkReports(reports, List.of("STUCK"), - HealthCheckManager.TIMEOUT_CODE, HealthCheckManager.TIMEOUT_MESSAGE); + HealthCheckManager.TIMEOUT_CODE, HealthCheckManager.TIMEOUT_MESSAGE); - assertTrue(RestMockHealthCheck.WAIT * 1000 > HealthCheckManagerTest.select(reports, "STUCK", - HealthCheckManager.TIMEOUT_CODE, HealthCheckManager.TIMEOUT_MESSAGE) - .get(0).getElapsedTime()); + assertTrue(RestMockHealthCheck.wait * 1000 > HealthCheckManagerTest.select(reports, "STUCK", + HealthCheckManager.TIMEOUT_CODE, HealthCheckManager.TIMEOUT_MESSAGE) + .get(0).getElapsedTime()); feature.afterShutdown(PolicyEngineConstants.getManager()); } - private void checkReports(Reports reports, List<String> reportNames, int code, String message) { - reportNames - .forEach(name -> assertEquals(1, - HealthCheckManagerTest.select(reports, name, code, message).size())); - } - - private Reports healthcheck(HealthCheck manager) { - var reports = manager.healthCheck(); - logger.info("{}", reports); - return reports; - } - - private void checkOpen(int port) throws InterruptedException { - if (!NetworkUtil.isTcpPortOpen("localhost", port, 5, 10000L)) { - throw new IllegalStateException("cannot connect to port " + port); - } - } - - private void serverChecks(Reports reports) { - checkReports(reports, List.of("HEALTHCHECK", "LIVENESS"), - HttpStatus.OK_200, HttpStatus.getMessage(200)); - checkReports(reports, List.of("UNAUTH"), - HttpStatus.UNAUTHORIZED_401, HttpStatus.getMessage(401)); - checkReports(reports, List.of(HealthCheckManager.ENGINE_NAME), - HealthCheckManager.SUCCESS_CODE, HealthCheckManager.ENABLED_MESSAGE); - } - @Test void testGetSequenceNumber() { assertEquals(1000, new HealthCheckFeature().getSequenceNumber()); @@ -218,6 +192,38 @@ public class HealthCheckFeatureTest { assertFalse(feature.afterShutdown(null)); } + @Test + void testGetManager() { + assertNotNull(new HealthCheckFeature().getManager()); + } + + private void checkReports(Reports reports, List<String> reportNames, int code, String message) { + reportNames + .forEach(name -> assertEquals(1, + HealthCheckManagerTest.select(reports, name, code, message).size())); + } + + private Reports healthcheck(HealthCheck manager) { + var reports = manager.healthCheck(); + logger.info("{}", reports); + return reports; + } + + private void checkOpen(int port) throws InterruptedException { + if (!NetworkUtil.isTcpPortOpen("localhost", port, 5, 10000L)) { + throw new IllegalStateException("cannot connect to port " + port); + } + } + + private void serverChecks(Reports reports) { + checkReports(reports, List.of("HEALTHCHECK", "LIVENESS"), + HttpStatus.OK_200, HttpStatus.getMessage(200)); + checkReports(reports, List.of("UNAUTH"), + HttpStatus.UNAUTHORIZED_401, HttpStatus.getMessage(401)); + checkReports(reports, List.of(HealthCheckManager.ENGINE_NAME), + HealthCheckManager.SUCCESS_CODE, HealthCheckManager.ENABLED_MESSAGE); + } + /** * Feature that returns a particular monitor. */ diff --git a/feature-healthcheck/src/test/java/org/onap/policy/drools/healthcheck/RestMockHealthCheck.java b/feature-healthcheck/src/test/java/org/onap/policy/drools/healthcheck/RestMockHealthCheck.java index d2376d9d..ace32dc4 100644 --- a/feature-healthcheck/src/test/java/org/onap/policy/drools/healthcheck/RestMockHealthCheck.java +++ b/feature-healthcheck/src/test/java/org/onap/policy/drools/healthcheck/RestMockHealthCheck.java @@ -3,6 +3,7 @@ * ONAP * ================================================================================ * Copyright (C) 2017-2018,2022 AT&T Intellectual Property. All rights reserved. + * Modifications Copyright (C) 2024 Nordix Foundation. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,7 +37,7 @@ public class RestMockHealthCheck { protected static final String OK_MESSAGE = "All Alive"; protected static volatile boolean stuck = false; - protected static volatile long WAIT = 15; + protected static volatile long wait = 15; @GET @Path("healthcheck/test") @@ -49,7 +50,7 @@ public class RestMockHealthCheck { @Path("healthcheck/stuck") @Produces({MediaType.APPLICATION_JSON, YamlMessageBodyHandler.APPLICATION_YAML}) public Response stuck() { - await().atMost(WAIT, TimeUnit.SECONDS).until(() -> !stuck); + await().atMost(wait, TimeUnit.SECONDS).until(() -> !stuck); return Response.status(Status.OK).entity("I may be stuck: " + stuck).build(); } } diff --git a/feature-legacy-config/src/main/feature/config/feature-legacy-config.properties b/feature-legacy-config/src/main/feature/config/feature-legacy-config.properties index 9cb73c58..087f40c9 100644 --- a/feature-legacy-config/src/main/feature/config/feature-legacy-config.properties +++ b/feature-legacy-config/src/main/feature/config/feature-legacy-config.properties @@ -26,4 +26,5 @@ kafka.source.topics.pdpd-configuration.apiSecret=${envd:PDPD_CONFIGURATION_API_S kafka.source.topics.pdpd-configuration.consumerGroup=${envd:PDPD_CONFIGURATION_CONSUMER_GROUP} kafka.source.topics.pdpd-configuration.consumerInstance=${envd:PDPD_CONFIGURATION_CONSUMER_INSTANCE} kafka.source.topics.pdpd-configuration.managed=false -kafka.source.topics.pdpd-configuration.https=${envd:KAFKA_HTTPS:false} +kafka.source.topics.pdpd-configuration.https=${env:KAFKA_HTTPS:false} +kafka.source.topics.pdpd-configuration.additionalProps=${env:KAFKA_ADDITIONAL_PROPS} diff --git a/feature-lifecycle/src/main/feature/config/feature-lifecycle.properties b/feature-lifecycle/src/main/feature/config/feature-lifecycle.properties index 4a60650c..45dfabdd 100644 --- a/feature-lifecycle/src/main/feature/config/feature-lifecycle.properties +++ b/feature-lifecycle/src/main/feature/config/feature-lifecycle.properties @@ -31,9 +31,11 @@ kafka.source.topics.policy-pdp-pap.effectiveTopic=${envd:POLICY_PDP_PAP_TOPIC} kafka.source.topics.policy-pdp-pap.apiKey=${envd:POLICY_PDP_PAP_API_KEY} kafka.source.topics.policy-pdp-pap.apiSecret=${envd:POLICY_PDP_PAP_API_SECRET} kafka.source.topics.policy-pdp-pap.https=${envd:KAFKA_HTTPS:false} +kafka.source.topics.policy-pdp-pap.additionalProps=${env:KAFKA_ADDITIONAL_PROPS} kafka.sink.topics.policy-pdp-pap.servers=${envd:KAFKA_SERVERS} kafka.sink.topics.policy-pdp-pap.effectiveTopic=${envd:POLICY_PDP_PAP_TOPIC} kafka.sink.topics.policy-pdp-pap.apiKey=${envd:POLICY_PDP_PAP_API_KEY} kafka.sink.topics.policy-pdp-pap.apiSecret=${envd:POLICY_PDP_PAP_API_SECRET} kafka.sink.topics.policy-pdp-pap.https=${envd:KAFKA_HTTPS:false} +kafka.sink.topics.policy-pdp-pap.additionalProps=${env:KAFKA_ADDITIONAL_PROPS} diff --git a/feature-lifecycle/src/main/java/org/onap/policy/drools/lifecycle/LifecycleFeature.java b/feature-lifecycle/src/main/java/org/onap/policy/drools/lifecycle/LifecycleFeature.java index a50deb21..1fc45747 100644 --- a/feature-lifecycle/src/main/java/org/onap/policy/drools/lifecycle/LifecycleFeature.java +++ b/feature-lifecycle/src/main/java/org/onap/policy/drools/lifecycle/LifecycleFeature.java @@ -3,7 +3,7 @@ * ONAP * ================================================================================ * Copyright (C) 2019-2021 AT&T Intellectual Property. All rights reserved. - * Modifications Copyright (C) 2023 Nordix Foundation. + * Modifications Copyright (C) 2023-2024 Nordix Foundation. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -38,7 +38,7 @@ public class LifecycleFeature * Lifecycle FSM. */ @Getter - public static LifecycleFsm fsm = new LifecycleFsm(); + static LifecycleFsm fsm = new LifecycleFsm(); @Override public int getSequenceNumber() { diff --git a/feature-lifecycle/src/main/java/org/onap/policy/drools/lifecycle/LifecycleStateRunning.java b/feature-lifecycle/src/main/java/org/onap/policy/drools/lifecycle/LifecycleStateRunning.java index 2d5c66b3..14796cea 100644 --- a/feature-lifecycle/src/main/java/org/onap/policy/drools/lifecycle/LifecycleStateRunning.java +++ b/feature-lifecycle/src/main/java/org/onap/policy/drools/lifecycle/LifecycleStateRunning.java @@ -4,7 +4,7 @@ * ================================================================================ * Copyright (C) 2019-2021 AT&T Intellectual Property. All rights reserved. * Modifications Copyright (C) 2019 Bell Canada. - * Modifications Copyright (C) 2021, 2023 Nordix Foundation. + * Modifications Copyright (C) 2021, 2023-2024 Nordix Foundation. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -203,13 +203,15 @@ public abstract class LifecycleStateRunning extends LifecycleStateDefault { List<ToscaPolicy> failedUndeployPolicies = undeployPolicies(policies); if (!failedUndeployPolicies.isEmpty()) { - logger.warn("update-policies: undeployment failures: {}", fsm.getPolicyIdsMessage(failedUndeployPolicies)); + var failures = fsm.getPolicyIdsMessage(failedUndeployPolicies); + logger.warn("update-policies: undeployment failures: {}", failures); failedUndeployPolicies.forEach(fsm::failedUndeployPolicyAction); } List<ToscaPolicy> failedDeployPolicies = deployPolicies(policies); if (!failedDeployPolicies.isEmpty()) { - logger.warn("update-policies: deployment failures: {}", fsm.getPolicyIdsMessage(failedDeployPolicies)); + var failures = fsm.getPolicyIdsMessage(failedDeployPolicies); + logger.warn("update-policies: deployment failures: {}", failures); failedDeployPolicies.forEach(fsm::failedDeployPolicyAction); } @@ -237,11 +239,15 @@ public abstract class LifecycleStateRunning extends LifecycleStateDefault { List<ToscaPolicy> preNonNativePolicies = fsm.getNonNativePolicies(preActivePoliciesMap); preNonNativePolicies.retainAll(fsm.getNonNativePolicies(activePoliciesByType)); + var nonNativePoliciesIds = fsm.getPolicyIdsMessage(preNonNativePolicies); + var activePoliciesIds = fsm.getPolicyIdsMessage(activeNativeArtifactPolicies); + logger.info("re-applying non-native policies {} because new native artifact policies have been found: {}", - fsm.getPolicyIdsMessage(preNonNativePolicies), fsm.getPolicyIdsMessage(activeNativeArtifactPolicies)); + nonNativePoliciesIds, activePoliciesIds); List<ToscaPolicy> failedPolicies = syncPolicies(preNonNativePolicies, this::deployPolicy); - logger.info("re-applying non-native policies failures: {}", fsm.getPolicyIdsMessage(failedPolicies)); + var failedPoliciesIds = fsm.getPolicyIdsMessage(failedPolicies); + logger.info("re-applying non-native policies failures: {}", failedPoliciesIds); return failedPolicies; } @@ -268,9 +274,11 @@ public abstract class LifecycleStateRunning extends LifecycleStateDefault { List<ToscaPolicy> preNativeArtifactPolicies = fsm.getNativeArtifactPolicies(preActivePoliciesMap); preNativeArtifactPolicies.retainAll(fsm.getNativeArtifactPolicies(activePoliciesByType)); + var candidateIds = fsm.getPolicyIdsMessage(preNativeArtifactPolicies); + var activeIds = fsm.getPolicyIdsMessage(activeNativeControllerPolicies); + logger.info("reapply candidate native artifact policies {} as new native controller policies {} were found", - fsm.getPolicyIdsMessage(preNativeArtifactPolicies), - fsm.getPolicyIdsMessage(activeNativeControllerPolicies)); + candidateIds, activeIds); // from the intersection, only need to reapply those for which there is a new native // controller policy @@ -295,12 +303,14 @@ public abstract class LifecycleStateRunning extends LifecycleStateDefault { } } + var nativeArtPolIds = fsm.getPolicyIdsMessage(preNativeArtifactPoliciesToApply); + var newNativeCtrlPolIds = fsm.getPolicyIdsMessage(activeNativeControllerPolicies); logger.info("reapply set of native artifact policies {} as new native controller policies {} were found", - fsm.getPolicyIdsMessage(preNativeArtifactPoliciesToApply), - fsm.getPolicyIdsMessage(activeNativeControllerPolicies)); + nativeArtPolIds, newNativeCtrlPolIds); List<ToscaPolicy> failedPolicies = syncPolicies(preNativeArtifactPoliciesToApply, this::deployPolicy); - logger.info("re-applying native artifact policies failures: {}", fsm.getPolicyIdsMessage(failedPolicies)); + var failedIds = fsm.getPolicyIdsMessage(failedPolicies); + logger.info("re-applying native artifact policies failures: {}", failedIds); // since we want non-native policies to be reapplied when a new native artifact policy has been // reapplied here, remove it from the preActivePolicies, so it is detected as new. diff --git a/feature-lifecycle/src/main/java/org/onap/policy/drools/server/restful/RestLifecycleManager.java b/feature-lifecycle/src/main/java/org/onap/policy/drools/server/restful/RestLifecycleManager.java index a4abdf37..c755c444 100644 --- a/feature-lifecycle/src/main/java/org/onap/policy/drools/server/restful/RestLifecycleManager.java +++ b/feature-lifecycle/src/main/java/org/onap/policy/drools/server/restful/RestLifecycleManager.java @@ -1,7 +1,7 @@ /*- * ============LICENSE_START======================================================= * Copyright (C) 2019-2022 AT&T Intellectual Property. All rights reserved. - * Modifications Copyright (C) 2021, 2023-2023 Nordix Foundation. + * Modifications Copyright (C) 2021, 2023-2024 Nordix Foundation. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -417,7 +417,7 @@ public class RestLifecycleManager implements LifecycleApi { private PdpUpdate getUndeployPolicyUpdate(List<ToscaPolicy> policies) { PdpUpdate update = getPolicyUpdate(); - update.setPoliciesToBeUndeployed(LifecycleFeature.fsm.getPolicyIds(policies)); + update.setPoliciesToBeUndeployed(LifecycleFeature.getFsm().getPolicyIds(policies)); return update; } diff --git a/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/ControllerSupport.java b/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/ControllerSupport.java index 858e8495..eadafe7c 100644 --- a/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/ControllerSupport.java +++ b/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/ControllerSupport.java @@ -35,6 +35,8 @@ import org.onap.policy.drools.system.PolicyController; import org.onap.policy.drools.system.PolicyControllerConstants; import org.onap.policy.drools.util.KieUtils; import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Controller Test Support. @@ -42,6 +44,8 @@ import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy; @Getter public class ControllerSupport { + private static final Logger logger = LoggerFactory.getLogger(ControllerSupport.class); + protected static final String JUNIT_KMODULE_DRL_PATH = "src/test/resources/lifecycle.drl"; protected static final String JUNIT_KMODULE_POM_PATH = "src/test/resources/lifecycle.pom"; protected static final String JUNIT_KMODULE_PATH = "src/test/resources/lifecycle.kmodule"; @@ -62,20 +66,19 @@ public class ControllerSupport { /** * Create controller. */ - public PolicyController createController() throws IOException { + public void createController() throws IOException { try { PolicyController controller = getController(); controller.getDrools().delete(ToscaPolicy.class); - return controller; - } catch (IllegalArgumentException ignored) { // NOSONAR - ; // checkstyle + } catch (IllegalArgumentException e) { + logger.debug("error when creating controller", e); } ReleaseId coordinates = installArtifact(); Properties controllerProps = getControllerProps(coordinates); - return PolicyControllerConstants.getFactory().build(name, controllerProps); + PolicyControllerConstants.getFactory().build(name, controllerProps); } private Properties getControllerProps(ReleaseId coordinates) { @@ -140,7 +143,7 @@ public class ControllerSupport { * Change final marker in static field. */ public static <T> Field unsetFinalStaticAccess(Class<T> clazz, String fieldName) - throws NoSuchFieldException { + throws NoSuchFieldException { Field field = clazz.getDeclaredField(fieldName); field.setAccessible(true); diff --git a/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/LifecycleFeatureTest.java b/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/LifecycleFeatureTest.java new file mode 100644 index 00000000..bb22316c --- /dev/null +++ b/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/LifecycleFeatureTest.java @@ -0,0 +1,164 @@ +/* + * ============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.lifecycle; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.onap.policy.drools.lifecycle.LifecycleFsm.CONFIGURATION_PROPERTIES_NAME; + +import java.util.Properties; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.mockito.junit.jupiter.MockitoExtension; +import org.onap.policy.drools.persistence.FileSystemPersistence; +import org.onap.policy.drools.persistence.SystemPersistenceConstants; +import org.onap.policy.drools.system.PolicyController; +import org.onap.policy.drools.system.PolicyEngine; + +@ExtendWith(MockitoExtension.class) +class LifecycleFeatureTest { + + LifecycleFeature feature; + + @Mock + LifecycleFsm fsm; + + @Mock + PolicyController controller; + + @Mock + PolicyEngine engine; + + AutoCloseable closeable; + + @BeforeEach + void setUp() { + closeable = MockitoAnnotations.openMocks(this); + + var props = new Properties(); + var fileManager = mock(FileSystemPersistence.class); + lenient().when(fileManager.getProperties(CONFIGURATION_PROPERTIES_NAME)).thenReturn(props); + + try (MockedStatic<SystemPersistenceConstants> constants = + Mockito.mockStatic(SystemPersistenceConstants.class)) { + constants.when(SystemPersistenceConstants::getManager).thenReturn(fileManager); + feature = mock(LifecycleFeature.class); + } + } + + @AfterEach + void tearDown() throws Exception { + closeable.close(); + } + + @Test + void getSequenceNumber() { + when(feature.getSequenceNumber()).thenCallRealMethod(); + + assertEquals(1, feature.getSequenceNumber()); + } + + @Test + void afterStart() { + when(fsm.start()).thenReturn(true); + doNothing().when(fsm).start(controller); + + when(feature.afterStart(engine)).thenCallRealMethod(); + when(feature.afterStart(controller)).thenCallRealMethod(); + + try (MockedStatic<LifecycleFeature> factory = Mockito.mockStatic(LifecycleFeature.class)) { + factory.when(LifecycleFeature::getFsm).thenReturn(fsm); + assertEquals(fsm, LifecycleFeature.getFsm()); + + assertFalse(feature.afterStart(controller)); + assertFalse(feature.afterStart(engine)); + } + } + + @Test + void beforeStop() { + when(fsm.stop()).thenReturn(true); + doNothing().when(fsm).stop(controller); + + when(feature.beforeStop(engine)).thenCallRealMethod(); + when(feature.beforeStop(controller)).thenCallRealMethod(); + + try (MockedStatic<LifecycleFeature> factory = Mockito.mockStatic(LifecycleFeature.class)) { + factory.when(LifecycleFeature::getFsm).thenReturn(fsm); + assertEquals(fsm, LifecycleFeature.getFsm()); + + assertFalse(feature.beforeStop(controller)); + assertFalse(feature.beforeStop(engine)); + } + } + + @Test + void beforeShutdown() { + doNothing().when(fsm).shutdown(); + + when(feature.beforeShutdown(engine)).thenCallRealMethod(); + + try (MockedStatic<LifecycleFeature> factory = Mockito.mockStatic(LifecycleFeature.class)) { + factory.when(LifecycleFeature::getFsm).thenReturn(fsm); + assertEquals(fsm, LifecycleFeature.getFsm()); + + assertFalse(feature.beforeShutdown(engine)); + } + } + + @Test + void beforeLock() { + doNothing().when(fsm).stop(controller); + + when(feature.beforeLock(controller)).thenCallRealMethod(); + + try (MockedStatic<LifecycleFeature> factory = Mockito.mockStatic(LifecycleFeature.class)) { + factory.when(LifecycleFeature::getFsm).thenReturn(fsm); + assertEquals(fsm, LifecycleFeature.getFsm()); + + assertFalse(feature.beforeLock(controller)); + } + } + + @Test + void afterUnlock() { + doNothing().when(fsm).start(controller); + + when(feature.afterUnlock(controller)).thenCallRealMethod(); + + try (MockedStatic<LifecycleFeature> factory = Mockito.mockStatic(LifecycleFeature.class)) { + factory.when(LifecycleFeature::getFsm).thenReturn(fsm); + assertEquals(fsm, LifecycleFeature.getFsm()); + + assertFalse(feature.afterUnlock(controller)); + } + } +}
\ No newline at end of file diff --git a/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/LifecycleFsmTest.java b/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/LifecycleFsmTest.java index cae3bb3b..9538cc44 100644 --- a/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/LifecycleFsmTest.java +++ b/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/LifecycleFsmTest.java @@ -228,6 +228,11 @@ public class LifecycleFsmTest { fsm.getPolicyIds(List.of(opPolicy, controllerPolicy)).toString()); } + @Test + void testGetSequenceNumber() { + assertEquals(1, new LifecycleFeature().getSequenceNumber()); + } + protected void deployAllPolicies() { fsm.deployedPolicyAction(controllerPolicy); fsm.deployedPolicyAction(controller2Policy); diff --git a/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/LifecycleFsmUpdateTest.java b/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/LifecycleFsmUpdateTest.java index 8f0c19db..c24c61cf 100644 --- a/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/LifecycleFsmUpdateTest.java +++ b/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/LifecycleFsmUpdateTest.java @@ -143,7 +143,7 @@ public class LifecycleFsmUpdateTest { noopTopicProperties.put(PolicyEndPointProperties.PROPERTY_NOOP_SINK_TOPICS, TestConstants.APPC_CL_TOPIC); TopicEndpointManager.getManager().addTopics(noopTopicProperties); - savedFsm = LifecycleFeature.fsm; + savedFsm = LifecycleFeature.getFsm(); } /** @@ -174,7 +174,7 @@ public class LifecycleFsmUpdateTest { public void init() throws CoderException, IOException, NoSuchFieldException, IllegalAccessException { fsm = new LifecycleFsm() { @Override - protected ScheduledExecutorService makeExecutor() { // NOSONAR + protected ScheduledExecutorService makeExecutor() { return new PseudoScheduledExecutorService(new TestTimeMulti()); } }; @@ -417,14 +417,14 @@ public class LifecycleFsmUpdateTest { protected void verifyNativeArtifactPolicies(List<ToscaPolicy> policies) throws CoderException { // check that a brained controller exists for each native artifact policy for (ToscaPolicy policy : policies) { - NativeArtifactPolicy artifactPolicy = fsm.getDomainMaker().convertTo(policy, NativeArtifactPolicy.class); - String controllerName = artifactPolicy.getProperties().getController().getName(); + NativeArtifactPolicy naPolicy = fsm.getDomainMaker().convertTo(policy, NativeArtifactPolicy.class); + String controllerName = naPolicy.getProperties().getController().getName(); assertTrue(PolicyControllerConstants.getFactory().get(controllerName).getDrools().isBrained()); - assertEquals(artifactPolicy.getProperties().getRulesArtifact().getGroupId(), + assertEquals(naPolicy.getProperties().getRulesArtifact().getGroupId(), PolicyControllerConstants.getFactory().get(controllerName).getDrools().getGroupId()); - assertEquals(artifactPolicy.getProperties().getRulesArtifact().getArtifactId(), + assertEquals(naPolicy.getProperties().getRulesArtifact().getArtifactId(), PolicyControllerConstants.getFactory().get(controllerName).getDrools().getArtifactId()); - assertEquals(artifactPolicy.getProperties().getRulesArtifact().getVersion(), + assertEquals(naPolicy.getProperties().getRulesArtifact().getVersion(), PolicyControllerConstants.getFactory().get(controllerName).getDrools().getVersion()); } } @@ -446,9 +446,9 @@ public class LifecycleFsmUpdateTest { // and there is a controller policy for each controllerName for (ToscaPolicy nativePolicy : nativeArtifactPolicies) { - NativeArtifactPolicy artifactPolicy = + NativeArtifactPolicy naPolicy = fsm.getDomainMaker().convertTo(nativePolicy, NativeArtifactPolicy.class); - String artifactControllerName = artifactPolicy.getProperties().getController().getName(); + String artifactControllerName = naPolicy.getProperties().getController().getName(); // brained controller check assertTrue(PolicyControllerConstants.getFactory().get(artifactControllerName).getDrools().isBrained(), @@ -545,13 +545,13 @@ public class LifecycleFsmUpdateTest { protected List<ControllerPolicy> getNativeControllerPolicies(List<ToscaPolicy> nativePolicies, String controllerName) { - return nativePolicies.stream().map(controllerPolicy -> { + return nativePolicies.stream().map(nativePolicy -> { try { - return fsm.getDomainMaker().convertTo(controllerPolicy, ControllerPolicy.class); + return fsm.getDomainMaker().convertTo(nativePolicy, ControllerPolicy.class); } catch (CoderException ex) { - throw new RuntimeException(controllerPolicy.getIdentifier().toString(), ex); + throw new RuntimeException(nativePolicy.getIdentifier().toString(), ex); } - }).filter(controllerPolicy -> controllerName.equals(controllerPolicy.getProperties().getControllerName())) + }).filter(nativePolicy -> controllerName.equals(nativePolicy.getProperties().getControllerName())) .collect(Collectors.toList()); } diff --git a/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/LifecycleStateActiveTest.java b/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/LifecycleStateActiveTest.java index 86e6ce3c..80fe946f 100644 --- a/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/LifecycleStateActiveTest.java +++ b/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/LifecycleStateActiveTest.java @@ -186,8 +186,6 @@ class LifecycleStateActiveTest extends LifecycleStateRunningTest { @Test void testUpdate() throws IOException, CoderException { - // TODO: extract repeated similar assertion blocks into their own helper methods - PdpUpdate update = new PdpUpdate(); update.setName(PolicyEngineConstants.getManager().getPdpName()); update.setPdpGroup("W"); @@ -311,9 +309,9 @@ class LifecycleStateActiveTest extends LifecycleStateRunningTest { factPolicies = controllerSupport.getFacts(ToscaPolicy.class); assertEquals(2, factPolicies.size()); - assertTrue(factPolicies.stream().noneMatch((ff) -> Objects.equals(toscaPolicyRestartV1, ff))); - assertTrue(factPolicies.stream().anyMatch((ff) -> Objects.equals(toscaPolicyRestartV2, ff))); - assertTrue(factPolicies.stream().anyMatch((ff) -> Objects.equals(toscaPolicyFirewall, ff))); + assertTrue(factPolicies.stream().noneMatch(ff -> Objects.equals(toscaPolicyRestartV1, ff))); + assertTrue(factPolicies.stream().anyMatch(ff -> Objects.equals(toscaPolicyRestartV2, ff))); + assertTrue(factPolicies.stream().anyMatch(ff -> Objects.equals(toscaPolicyFirewall, ff))); assertEquals(2, fsm.policiesMap.size()); long originalInterval = fsm.getStatusTimerSeconds(); diff --git a/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/LifecycleStatePassiveTest.java b/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/LifecycleStatePassiveTest.java index 01fb90b5..67e741ac 100644 --- a/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/LifecycleStatePassiveTest.java +++ b/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/LifecycleStatePassiveTest.java @@ -72,13 +72,13 @@ class LifecycleStatePassiveTest extends LifecycleStateRunningTest { fsm.start(controllerSupport.getController()); assertSame(controllerSupport.getController(), ((PolicyTypeDroolsController) fsm.getController( - new ToscaConceptIdentifier( - ControllerSupport.POLICY_TYPE_COMPLIANT_OP, ControllerSupport.POLICY_TYPE_VERSION))) + new ToscaConceptIdentifier( + ControllerSupport.POLICY_TYPE_COMPLIANT_OP, ControllerSupport.POLICY_TYPE_VERSION))) .controllers().get(0)); fsm.stop(controllerSupport.getController()); assertNull(fsm.getController(new ToscaConceptIdentifier(ControllerSupport.POLICY_TYPE_COMPLIANT_OP, - ControllerSupport.POLICY_TYPE_VERSION))); + ControllerSupport.POLICY_TYPE_VERSION))); fsm.shutdown(); } @@ -98,16 +98,6 @@ class LifecycleStatePassiveTest extends LifecycleStateRunningTest { assertBasicTerminated(); } - private void simpleStart() { - assertTrue(fsm.start()); - assertBasicPassive(); - } - - private void simpleStop() { - assertTrue(fsm.stop()); - assertBasicTerminated(); - } - @Test void testShutdown() throws Exception { simpleStop(); @@ -129,14 +119,6 @@ class LifecycleStatePassiveTest extends LifecycleStateRunningTest { fsm.shutdown(); } - private void status() { - waitUntil(5, TimeUnit.SECONDS, isStatus(PdpState.PASSIVE, 1)); - waitUntil(fsm.statusTimerSeconds + 2, TimeUnit.SECONDS, isStatus(PdpState.PASSIVE, 1 + 1)); - waitUntil(fsm.statusTimerSeconds + 2, TimeUnit.SECONDS, isStatus(PdpState.PASSIVE, 1 + 2)); - assertTrue(fsm.status()); - waitUntil(200, TimeUnit.MILLISECONDS, isStatus(PdpState.PASSIVE, 1 + 3)); - } - @Test void testUpdate() throws CoderException { controllerSupport.getController().getDrools().delete(ToscaPolicy.class); @@ -154,7 +136,7 @@ class LifecycleStatePassiveTest extends LifecycleStateRunningTest { int qlength = fsm.client.getSink().getRecentEvents().length; PdpStatus lastStatus = new StandardCoder().decode(fsm.client.getSink().getRecentEvents()[qlength - 1], - PdpStatus.class); + PdpStatus.class); assertEquals("foo", lastStatus.getPdpType()); assertEquals(update.getRequestId(), lastStatus.getRequestId()); assertEquals(update.getRequestId(), lastStatus.getResponse().getResponseTo()); @@ -165,21 +147,10 @@ class LifecycleStatePassiveTest extends LifecycleStateRunningTest { assertEquals("z", fsm.getSubGroup()); assertBasicPassive(); - ToscaPolicy toscaPolicy = - getExamplesPolicy("policies/vCPE.policy.operational.input.tosca.json", "operational.restart"); + var policyResourcePath = "policies/vCPE.policy.operational.input.tosca.json"; + ToscaPolicy toscaPolicy = getExamplesPolicy(policyResourcePath, "operational.restart"); toscaPolicy.getProperties().put("controllerName", "lifecycle"); - update.setPoliciesToBeDeployed(List.of(toscaPolicy)); - - assertFalse(fsm.update(update)); - - assertEquals(PdpState.PASSIVE, fsm.state()); - assertEquals(interval, fsm.getStatusTimerSeconds()); - assertEquals(LifecycleFsm.DEFAULT_PDP_GROUP, fsm.getGroup()); - assertEquals("z", fsm.getSubGroup()); - assertBasicPassive(); - - assertEquals(2, fsm.policyTypesMap.size()); - assertTrue(fsm.policiesMap.isEmpty()); + verifyVcpePolicyDeployed(update, toscaPolicy, interval); update.setPdpGroup(null); update.setPdpSubgroup(null); @@ -222,32 +193,7 @@ class LifecycleStatePassiveTest extends LifecycleStateRunningTest { assertBasicPassive(); assertEquals(0, controllerSupport.getController().getDrools().factCount("junits")); - // The "update" event will undeploy "toscaPolicy" and deploy "toscaPolicy2" - ToscaPolicy toscaPolicy2 = - getExamplesPolicy("policies/vFirewall.policy.operational.input.tosca.json", "operational.modifyconfig"); - toscaPolicy.getProperties().remove("controllerName"); - update.setPoliciesToBeUndeployed(List.of(toscaPolicy.getIdentifier())); - update.setPoliciesToBeDeployed(List.of(toscaPolicy2)); - assertTrue(fsm.update(update)); - assertEquals(3, fsm.policyTypesMap.size()); - assertEquals(1, fsm.policiesMap.size()); - assertEquals(toscaPolicy2, fsm.policiesMap.get(toscaPolicy2.getIdentifier())); - assertNull(fsm.policiesMap.get(toscaPolicy.getIdentifier())); - assertEquals(0, controllerSupport.getController().getDrools().factCount("junits")); - - update.setPdpGroup(null); - update.setPdpSubgroup(null); - update.setPoliciesToBeUndeployed(List.of(toscaPolicy2.getIdentifier())); - update.setPoliciesToBeDeployed(List.of()); - assertTrue(fsm.update(update)); - assertEquals(3, fsm.policyTypesMap.size()); - assertEquals(0, fsm.policiesMap.size()); - assertEquals(PdpState.PASSIVE, fsm.state()); - assertEquals(interval, fsm.getStatusTimerSeconds()); - assertEquals(LifecycleFsm.DEFAULT_PDP_GROUP, fsm.getGroup()); - assertNull(fsm.getSubGroup()); - assertBasicPassive(); - assertEquals(0, controllerSupport.getController().getDrools().factCount("junits")); + verifyUpdateUndeployToscaPolicyDeployToscaPolicy2(toscaPolicy, update, interval); fsm.shutdown(); } @@ -309,6 +255,16 @@ class LifecycleStatePassiveTest extends LifecycleStateRunningTest { fsm.shutdown(); } + private void simpleStart() { + assertTrue(fsm.start()); + assertBasicPassive(); + } + + private void simpleStop() { + assertTrue(fsm.stop()); + assertBasicTerminated(); + } + private void assertBasicTerminated() { assertEquals(PdpState.TERMINATED, fsm.state.state()); assertFalse(fsm.isAlive()); @@ -348,4 +304,57 @@ class LifecycleStatePassiveTest extends LifecycleStateRunningTest { assertFalse(fsm.statusTask.isCancelled()); assertFalse(fsm.statusTask.isDone()); } + + private void status() { + waitUntil(5, TimeUnit.SECONDS, isStatus(PdpState.PASSIVE, 1)); + waitUntil(fsm.statusTimerSeconds + 2, TimeUnit.SECONDS, isStatus(PdpState.PASSIVE, 1 + 1)); + waitUntil(fsm.statusTimerSeconds + 2, TimeUnit.SECONDS, isStatus(PdpState.PASSIVE, 1 + 2)); + assertTrue(fsm.status()); + waitUntil(200, TimeUnit.MILLISECONDS, isStatus(PdpState.PASSIVE, 1 + 3)); + } + + private void verifyVcpePolicyDeployed(PdpUpdate update, ToscaPolicy toscaPolicy, long interval) { + update.setPoliciesToBeDeployed(List.of(toscaPolicy)); + + assertFalse(fsm.update(update)); + + assertEquals(PdpState.PASSIVE, fsm.state()); + assertEquals(interval, fsm.getStatusTimerSeconds()); + assertEquals(LifecycleFsm.DEFAULT_PDP_GROUP, fsm.getGroup()); + assertEquals("z", fsm.getSubGroup()); + assertBasicPassive(); + + assertEquals(2, fsm.policyTypesMap.size()); + assertTrue(fsm.policiesMap.isEmpty()); + } + + private void verifyUpdateUndeployToscaPolicyDeployToscaPolicy2(ToscaPolicy toscaPolicy, PdpUpdate update, + long interval) throws CoderException { + // The "update" event will undeploy "toscaPolicy" and deploy "toscaPolicy2" + String policyResourcePath = "policies/vFirewall.policy.operational.input.tosca.json"; + ToscaPolicy toscaPolicy2 = getExamplesPolicy(policyResourcePath, "operational.modifyconfig"); + toscaPolicy.getProperties().remove("controllerName"); + update.setPoliciesToBeUndeployed(List.of(toscaPolicy.getIdentifier())); + update.setPoliciesToBeDeployed(List.of(toscaPolicy2)); + assertTrue(fsm.update(update)); + assertEquals(3, fsm.policyTypesMap.size()); + assertEquals(1, fsm.policiesMap.size()); + assertEquals(toscaPolicy2, fsm.policiesMap.get(toscaPolicy2.getIdentifier())); + assertNull(fsm.policiesMap.get(toscaPolicy.getIdentifier())); + assertEquals(0, controllerSupport.getController().getDrools().factCount("junits")); + + update.setPdpGroup(null); + update.setPdpSubgroup(null); + update.setPoliciesToBeUndeployed(List.of(toscaPolicy2.getIdentifier())); + update.setPoliciesToBeDeployed(List.of()); + assertTrue(fsm.update(update)); + assertEquals(3, fsm.policyTypesMap.size()); + assertEquals(0, fsm.policiesMap.size()); + assertEquals(PdpState.PASSIVE, fsm.state()); + assertEquals(interval, fsm.getStatusTimerSeconds()); + assertEquals(LifecycleFsm.DEFAULT_PDP_GROUP, fsm.getGroup()); + assertNull(fsm.getSubGroup()); + assertBasicPassive(); + assertEquals(0, controllerSupport.getController().getDrools().factCount("junits")); + } } diff --git a/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/LifecycleStateSafeTest.java b/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/LifecycleStateSafeTest.java index 4c292b42..3d69ea9a 100644 --- a/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/LifecycleStateSafeTest.java +++ b/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/LifecycleStateSafeTest.java @@ -36,10 +36,11 @@ class LifecycleStateSafeTest extends LifecycleStateUnsupportedTest { } @Override - public LifecycleState create(LifecycleFsm fsm) { - return new LifecycleStateSafe(fsm); + public void create(LifecycleFsm fsm) { + new LifecycleStateSafe(fsm); } + @Override @Test public void constructor() { super.constructor(); diff --git a/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/LifecycleStateTestTest.java b/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/LifecycleStateTestTest.java index 89aae201..e6c7d145 100644 --- a/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/LifecycleStateTestTest.java +++ b/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/LifecycleStateTestTest.java @@ -36,10 +36,11 @@ class LifecycleStateTestTest extends LifecycleStateUnsupportedTest { } @Override - public LifecycleState create(LifecycleFsm fsm) { - return new LifecycleStateTest(fsm); + public void create(LifecycleFsm fsm) { + new LifecycleStateTest(fsm); } + @Override @Test public void constructor() { super.constructor(); diff --git a/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/LifecycleStateUnsupportedTest.java b/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/LifecycleStateUnsupportedTest.java index b5ec6aca..bd412179 100644 --- a/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/LifecycleStateUnsupportedTest.java +++ b/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/LifecycleStateUnsupportedTest.java @@ -24,12 +24,14 @@ package org.onap.policy.drools.lifecycle; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import java.util.ArrayList; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.onap.policy.drools.persistence.SystemPersistenceConstants; import org.onap.policy.models.pdp.concepts.PdpStateChange; import org.onap.policy.models.pdp.concepts.PdpUpdate; +import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy; /** * Lifecycle State Unsupported Test. @@ -52,7 +54,7 @@ public abstract class LifecycleStateUnsupportedTest { this.state = state; } - public abstract LifecycleState create(LifecycleFsm fsm); + public abstract void create(LifecycleFsm fsm); @Test public void constructor() { @@ -109,4 +111,11 @@ public abstract class LifecycleStateUnsupportedTest { assertThatThrownBy(() -> state.transitionToState(active)) .isInstanceOf(UnsupportedOperationException.class); } + + @Test + public void updatePolicies() { + var list = new ArrayList<ToscaPolicy>(); + assertThatThrownBy(() -> state.updatePolicies(list)) + .isInstanceOf(UnsupportedOperationException.class); + } } diff --git a/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/PolicyTypeDroolsControllerTest.java b/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/PolicyTypeDroolsControllerTest.java index 999860a0..1208662a 100644 --- a/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/PolicyTypeDroolsControllerTest.java +++ b/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/PolicyTypeDroolsControllerTest.java @@ -21,16 +21,24 @@ package org.onap.policy.drools.lifecycle; +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.assertSame; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.Mockito.doCallRealMethod; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; -import org.junit.jupiter.api.BeforeEach; +import java.util.ArrayList; +import java.util.List; import org.junit.jupiter.api.Test; import org.onap.policy.common.utils.coder.CoderException; import org.onap.policy.drools.domain.models.operational.OperationalPolicy; import org.onap.policy.drools.system.PolicyControllerConstants; +import org.onap.policy.drools.system.internal.AggregatedPolicyController; +import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy; /** @@ -41,7 +49,7 @@ class PolicyTypeDroolsControllerTest extends LifecycleStateRunningTest { // Operational vCPE Policies private static final String OP_POLICY_NAME_VCPE = "operational.restart"; private static final String VCPE_OPERATIONAL_DROOLS_POLICY_JSON = - "policies/vCPE.policy.operational.input.tosca.json"; + "policies/vCPE.policy.operational.input.tosca.json"; private ToscaPolicy policy; private PolicyTypeDroolsController controller; @@ -49,7 +57,6 @@ class PolicyTypeDroolsControllerTest extends LifecycleStateRunningTest { /** * Test initialization. */ - @BeforeEach public void init() throws CoderException { fsm = makeFsmWithPseudoTime(); policy = getExamplesPolicy(VCPE_OPERATIONAL_DROOLS_POLICY_JSON, OP_POLICY_NAME_VCPE); @@ -72,7 +79,8 @@ class PolicyTypeDroolsControllerTest extends LifecycleStateRunningTest { } @Test - void testDeployUndeploy() { + void testDeployUndeploy() throws CoderException { + init(); /* non-existing controller */ assertFalse(controller.undeploy(policy)); assertFalse(controller.deploy(policy)); @@ -97,6 +105,40 @@ class PolicyTypeDroolsControllerTest extends LifecycleStateRunningTest { undeploy(); // one more time } + @Test + void testNullExceptions() { + var mockController = mock(PolicyTypeDroolsController.class); + when(mockController.deploy(isNull())).thenCallRealMethod(); + doCallRealMethod().when(mockController).remove(isNull()); + when(mockController.undeploy(isNull())).thenCallRealMethod(); + doCallRealMethod().when(mockController).add(isNull()); + + assertThatThrownBy(() -> mockController.deploy(null)) + .hasMessageContaining("policy is marked non-null but is null"); + + assertThatThrownBy(() -> mockController.remove(null)) + .hasMessageContaining("controller is marked non-null but is null"); + + assertThatThrownBy(() -> mockController.undeploy(null)) + .hasMessageContaining("policy is marked non-null but is null"); + + assertThatThrownBy(() -> mockController.add(null)) + .hasMessageContaining("controller is marked non-null but is null"); + } + + @Test + void testAddController_DoesNotMatchPolicyType() { + var newController = mock(AggregatedPolicyController.class); + when(newController.getPolicyTypes()).thenReturn(new ArrayList<>(List.of(mock(ToscaConceptIdentifier.class)))); + when(newController.getName()).thenReturn("mockControllerName"); + + var mockController = mock(PolicyTypeDroolsController.class); + doCallRealMethod().when(mockController).add(newController); + + assertThatThrownBy(() -> mockController.add(newController)) + .hasMessageContaining("controller mockControllerName does not support"); + } + protected void undeploy() { assertTrue(controller.undeploy(policy)); assertFalse(controllerSupport.getController().getDrools().exists(policy)); diff --git a/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/PolicyTypeNativeArtifactControllerTest.java b/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/PolicyTypeNativeArtifactControllerTest.java index 26e6bbe4..ae11fd27 100644 --- a/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/PolicyTypeNativeArtifactControllerTest.java +++ b/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/PolicyTypeNativeArtifactControllerTest.java @@ -114,8 +114,6 @@ class PolicyTypeNativeArtifactControllerTest extends LifecycleStateRunningTest { /* idempotence */ assertTrue(controller.deploy(policy)); assertDeployed(); - - // TODO: test a point version upgrade } private void assertUndeployed() { diff --git a/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/PolicyTypeNativeDroolsControllerTest.java b/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/PolicyTypeNativeDroolsControllerTest.java index a964d134..29272a01 100644 --- a/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/PolicyTypeNativeDroolsControllerTest.java +++ b/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/PolicyTypeNativeDroolsControllerTest.java @@ -46,7 +46,7 @@ import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy; class PolicyTypeNativeDroolsControllerTest extends LifecycleStateRunningTest { private static final String EXAMPLE_NATIVE_DROOLS_POLICY_NAME = "example.controller"; private static final String EXAMPLE_NATIVE_DROOLS_POLICY_JSON = - "src/test/resources/tosca-policy-native-controller-example.json"; + "src/test/resources/tosca-policy-native-controller-example.json"; /** * Test initialization. @@ -75,7 +75,7 @@ class PolicyTypeNativeDroolsControllerTest extends LifecycleStateRunningTest { ToscaPolicy policy = getPolicyFromFile(EXAMPLE_NATIVE_DROOLS_POLICY_JSON, EXAMPLE_NATIVE_DROOLS_POLICY_NAME); ControllerPolicy controllerPolicy = fsm.getDomainMaker().convertTo(policy, ControllerPolicy.class); PolicyTypeNativeDroolsController controller = - new PolicyTypeNativeDroolsController(policy.getTypeIdentifier(), fsm); + new PolicyTypeNativeDroolsController(policy.getTypeIdentifier(), fsm); assertTrue(controller.undeploy(policy)); assertThatIllegalArgumentException().isThrownBy( () -> PolicyControllerConstants.getFactory().get(controllerPolicy.getName())); @@ -103,9 +103,9 @@ class PolicyTypeNativeDroolsControllerTest extends LifecycleStateRunningTest { TopicEndpointManager.getManager().addTopics(noopTopicProperties); ToscaPolicy nativeControllerPolicy = - getExamplesPolicy("policies/usecases.native.controller.policy.input.tosca.json", "usecases"); + getExamplesPolicy("policies/usecases.native.controller.policy.input.tosca.json", "usecases"); PolicyTypeNativeDroolsController controller = - new PolicyTypeNativeDroolsController(nativeControllerPolicy.getTypeIdentifier(), fsm); + new PolicyTypeNativeDroolsController(nativeControllerPolicy.getTypeIdentifier(), fsm); assertTrue(controller.deploy(nativeControllerPolicy)); Properties properties = PolicyControllerConstants.getFactory().get("usecases").getProperties(); @@ -115,70 +115,90 @@ class PolicyTypeNativeDroolsControllerTest extends LifecycleStateRunningTest { assertNull(properties.getProperty("rules.artifactId")); assertNull(properties.getProperty("rules.version")); + assertSourceTopics(properties); + + assertSinkTopics(properties); + + assertEquals("test", properties.getProperty("notes")); + assertEquals("auto", properties.getProperty("persistence.type")); + + assertTrue(controller.undeploy(nativeControllerPolicy)); + } + + private static void assertSourceTopics(Properties properties) { assertEquals("dcae_topic,appc-cl,appc-lcm-write,sdnr-cl-rsp", - properties.getProperty("noop.source.topics")); - assertEquals("appc-cl,appc-lcm-read,policy-cl-mgt,dcae_cl_rsp", - properties.getProperty("noop.sink.topics")); + properties.getProperty("noop.source.topics")); assertEquals("org.onap.policy.controlloop.CanonicalOnset,org.onap.policy.controlloop.CanonicalAbated", - properties.getProperty("noop.source.topics.dcae_topic.events")); + properties.getProperty("noop.source.topics.dcae_topic.events")); + assertEquals("[?($.closedLoopEventStatus == 'ONSET')]", - properties - .getProperty("noop.source.topics.dcae_topic.events.org.onap.policy.controlloop.CanonicalOnset.filter")); + properties.getProperty("noop.source.topics.dcae_topic.events." + + "org.onap.policy.controlloop.CanonicalOnset.filter")); + assertEquals("[?($.closedLoopEventStatus == 'ABATED')]", - properties - .getProperty("noop.source.topics.dcae_topic.events." - + "org.onap.policy.controlloop.CanonicalAbated.filter")); + properties.getProperty("noop.source.topics.dcae_topic.events." + + "org.onap.policy.controlloop.CanonicalAbated.filter")); + assertEquals("org.onap.policy.controlloop.util.Serialization,gson", - properties.getProperty("noop.source.topics.dcae_topic.events.custom.gson")); + properties.getProperty("noop.source.topics.dcae_topic.events.custom.gson")); + + assertEquals("org.onap.policy.appc.Response", + properties.getProperty("noop.source.topics.appc-cl.events")); - assertEquals("org.onap.policy.appc.Response", properties.getProperty("noop.source.topics.appc-cl.events")); assertEquals("[?($.CommonHeader && $.Status)]", - properties - .getProperty("noop.source.topics.appc-cl.events.org.onap.policy.appc.Response.filter")); + properties.getProperty("noop.source.topics.appc-cl.events.org.onap.policy.appc.Response.filter")); + assertEquals("org.onap.policy.appc.util.Serialization,gsonPretty", - properties.getProperty("noop.source.topics.appc-cl.events.custom.gson")); + properties.getProperty("noop.source.topics.appc-cl.events.custom.gson")); assertEquals("org.onap.policy.appclcm.AppcLcmMessageWrapper", - properties.getProperty("noop.source.topics.appc-lcm-write.events")); + properties.getProperty("noop.source.topics.appc-lcm-write.events")); + assertEquals("[?($.type == 'response')]", - properties - .getProperty("noop.source.topics.appc-lcm-write.events." - + "org.onap.policy.appclcm.AppcLcmMessageWrapper.filter")); + properties.getProperty("noop.source.topics.appc-lcm-write.events." + + "org.onap.policy.appclcm.AppcLcmMessageWrapper.filter")); + assertEquals("org.onap.policy.appclcm.util.Serialization,gson", - properties.getProperty("noop.source.topics.appc-lcm-write.events.custom.gson")); + properties.getProperty("noop.source.topics.appc-lcm-write.events.custom.gson")); assertEquals("org.onap.policy.sdnr.PciResponseWrapper", - properties.getProperty("noop.source.topics.sdnr-cl-rsp.events")); + properties.getProperty("noop.source.topics.sdnr-cl-rsp.events")); + assertEquals("[?($.type == 'response')]", - properties - .getProperty("noop.source.topics.sdnr-cl-rsp.events." - + "org.onap.policy.sdnr.PciResponseWrapper.filter")); + properties.getProperty("noop.source.topics.sdnr-cl-rsp.events." + + "org.onap.policy.sdnr.PciResponseWrapper.filter")); + assertEquals("org.onap.policy.sdnr.util.Serialization,gson", - properties.getProperty("noop.source.topics.sdnr-cl-rsp.events.custom.gson")); + properties.getProperty("noop.source.topics.sdnr-cl-rsp.events.custom.gson")); + } + + private static void assertSinkTopics(Properties properties) { + assertEquals("appc-cl,appc-lcm-read,policy-cl-mgt,dcae_cl_rsp", + properties.getProperty("noop.sink.topics")); + + assertEquals("org.onap.policy.appc.Request", + properties.getProperty("noop.sink.topics.appc-cl.events")); - assertEquals("org.onap.policy.appc.Request", properties.getProperty("noop.sink.topics.appc-cl.events")); assertEquals("org.onap.policy.appc.util.Serialization,gsonPretty", - properties.getProperty("noop.sink.topics.appc-cl.events.custom.gson")); + properties.getProperty("noop.sink.topics.appc-cl.events.custom.gson")); assertEquals("org.onap.policy.appclcm.AppcLcmMessageWrapper", - properties.getProperty("noop.sink.topics.appc-lcm-read.events")); + properties.getProperty("noop.sink.topics.appc-lcm-read.events")); + assertEquals("org.onap.policy.appclcm.util.Serialization,gson", - properties.getProperty("noop.sink.topics.appc-lcm-read.events.custom.gson")); + properties.getProperty("noop.sink.topics.appc-lcm-read.events.custom.gson")); assertEquals("org.onap.policy.controlloop.VirtualControlLoopNotification", - properties.getProperty("noop.sink.topics.policy-cl-mgt.events")); - assertEquals("org.onap.policy.controlloop.util.Serialization,gsonPretty", - properties.getProperty("noop.sink.topics.policy-cl-mgt.events.custom.gson")); + properties.getProperty("noop.sink.topics.policy-cl-mgt.events")); - assertEquals("org.onap.policy.controlloop.ControlLoopResponse", - properties.getProperty("noop.sink.topics.dcae_cl_rsp.events")); assertEquals("org.onap.policy.controlloop.util.Serialization,gsonPretty", - properties.getProperty("noop.sink.topics.dcae_cl_rsp.events.custom.gson")); + properties.getProperty("noop.sink.topics.policy-cl-mgt.events.custom.gson")); - assertEquals("test", properties.getProperty("notes")); - assertEquals("auto", properties.getProperty("persistence.type")); + assertEquals("org.onap.policy.controlloop.ControlLoopResponse", + properties.getProperty("noop.sink.topics.dcae_cl_rsp.events")); - assertTrue(controller.undeploy(nativeControllerPolicy)); + assertEquals("org.onap.policy.controlloop.util.Serialization,gsonPretty", + properties.getProperty("noop.sink.topics.dcae_cl_rsp.events.custom.gson")); } } diff --git a/feature-lifecycle/src/test/java/org/onap/policy/drools/server/restful/RestLifecycleManagerTest.java b/feature-lifecycle/src/test/java/org/onap/policy/drools/server/restful/RestLifecycleManagerTest.java index fcf946e4..8aa3f43b 100644 --- a/feature-lifecycle/src/test/java/org/onap/policy/drools/server/restful/RestLifecycleManagerTest.java +++ b/feature-lifecycle/src/test/java/org/onap/policy/drools/server/restful/RestLifecycleManagerTest.java @@ -187,14 +187,7 @@ public class RestLifecycleManagerTest { /* start up configuration */ - resourceLists("policyTypes", 2); - get("policyTypes/onap.policies.native.drools.Artifact/1.0.0", Status.OK.getStatusCode()); - get("policyTypes/onap.policies.native.drools.Controller/1.0.0", Status.OK.getStatusCode()); - get("policyTypes/onap.policies.controlloop.operational.common.Drools/1.0.0", Status.NOT_FOUND.getStatusCode()); - - resourceLists("policies", 0); - get("policies/example.controller/1.0.0", Status.NOT_FOUND.getStatusCode()); - get("policies/example.artifact/1.0.0", Status.NOT_FOUND.getStatusCode()); + assertStartup(); /* start lifecycle */ @@ -208,35 +201,17 @@ public class RestLifecycleManagerTest { ToscaPolicy nativeControllerPolicy = getPolicyFromFile(EXAMPLE_NATIVE_CONTROLLER_POLICY_JSON, EXAMPLE_NATIVE_CONTROLLER_POLICY_NAME); - booleanPost("policies", toString(nativeControllerPolicy), Status.OK.getStatusCode(), Boolean.TRUE); - - assertTrue(PolicyControllerConstants.getFactory().get("lifecycle").isAlive()); - assertFalse(PolicyControllerConstants.getFactory().get("lifecycle").getDrools().isBrained()); - assertFalse(PolicyControllerConstants.getFactory().get("lifecycle").getDrools().isAlive()); - - get("policyTypes/onap.policies.controlloop.operational.common.Drools/1.0.0", Status.NOT_FOUND.getStatusCode()); - - resourceLists("policies", 1); - get("policies/example.controller/1.0.0", Status.OK.getStatusCode()); + assertAddNativeControllerPolicy(nativeControllerPolicy); /* add native artifact policy */ ToscaPolicy nativeArtifactPolicy = getPolicyFromFile(EXAMPLE_NATIVE_ARTIFACT_POLICY_JSON, EXAMPLE_NATIVE_ARTIFACT_POLICY_NAME); - booleanPost("policies", toString(nativeArtifactPolicy), Status.OK.getStatusCode(), Boolean.TRUE); - - assertTrue(PolicyControllerConstants.getFactory().get("lifecycle").isAlive()); - assertTrue(PolicyControllerConstants.getFactory().get("lifecycle").getDrools().isBrained()); - assertTrue(PolicyControllerConstants.getFactory().get("lifecycle").getDrools().isAlive()); + assertAddNativeArtifactPolicy(nativeArtifactPolicy); /* verify new supported operational policy types */ - resourceLists("policyTypes", 5); - get("policyTypes/onap.policies.native.drools.Artifact/1.0.0", Status.OK.getStatusCode()); - get("policyTypes/onap.policies.native.drools.Controller/1.0.0", Status.OK.getStatusCode()); - get("policyTypes/onap.policies.controlloop.operational.common.Drools/1.0.0", Status.OK.getStatusCode()); - get("policyTypes/onap.policies.type1.type2/1.0.0", Status.OK.getStatusCode()); - get("policyTypes/onap.policies.typeA/1.0.0", Status.OK.getStatusCode()); + verifySupportedOperationalPolicyTypes(5, Status.OK); /* verify controller and artifact policies */ @@ -268,6 +243,48 @@ public class RestLifecycleManagerTest { /* individual deploy/undeploy operations */ + assertDeployUndeploy(opPolicy); + + /* delete native artifact policy */ + + verifyDeleteNativeArtifactPolicy(opPolicy); + + /* delete native controller policy */ + + verifyDeleteNativeControllerPolicy(opPolicy); + + metrics(); + } + + private void verifyDeleteNativeControllerPolicy(ToscaPolicy opPolicy) throws CoderException { + booleanDelete("policies/example.controller/1.0.0", Status.OK.getStatusCode()); + + verifySupportedOperationalPolicyTypes(2, Status.NOT_FOUND); + + resourceLists("policies", 0); + get("policies/" + opPolicy.getName() + "/" + opPolicy.getVersion(), Status.NOT_FOUND.getStatusCode()); + get("policies/example.artifact/1.0.0", Status.NOT_FOUND.getStatusCode()); + get("policies/example.controller/1.0.0", Status.NOT_FOUND.getStatusCode()); + + assertThatIllegalArgumentException().isThrownBy(() -> PolicyControllerConstants.getFactory().get("lifecycle")); + opPolicy.getMetadata().remove("policy-id"); + assertThat(listPost(toString(opPolicy), Status.NOT_ACCEPTABLE.getStatusCode())).isEmpty(); + } + + private void verifyDeleteNativeArtifactPolicy(ToscaPolicy opPolicy) { + booleanDelete("policies/example.artifact/1.0.0", Status.OK.getStatusCode()); + assertTrue(PolicyControllerConstants.getFactory().get("lifecycle").isAlive()); + assertFalse(PolicyControllerConstants.getFactory().get("lifecycle").getDrools().isBrained()); + + verifySupportedOperationalPolicyTypes(2, Status.NOT_FOUND); + + resourceLists("policies", 1); + get("policies/" + opPolicy.getName() + "/" + opPolicy.getVersion(), Status.NOT_FOUND.getStatusCode()); + get("policies/example.artifact/1.0.0", Status.NOT_FOUND.getStatusCode()); + get("policies/example.controller/1.0.0", Status.OK.getStatusCode()); + } + + private void assertDeployUndeploy(ToscaPolicy opPolicy) throws CoderException { resourceLists("policies/operations", 3); booleanPost("policies/operations/deployment", toString(opPolicy), Status.OK.getStatusCode(), Boolean.TRUE); @@ -290,46 +307,47 @@ public class RestLifecycleManagerTest { get("policies/" + opPolicy.getName() + "/" + opPolicy.getVersion(), Status.NOT_FOUND.getStatusCode()); get("policies/example.controller/1.0.0", Status.OK.getStatusCode()); get("policies/example.artifact/1.0.0", Status.OK.getStatusCode()); + } - /* delete native artifact policy */ + private void verifySupportedOperationalPolicyTypes(int size, Status status) { + resourceLists("policyTypes", size); + get("policyTypes/onap.policies.native.drools.Artifact/1.0.0", Status.OK.getStatusCode()); + get("policyTypes/onap.policies.native.drools.Controller/1.0.0", Status.OK.getStatusCode()); + get("policyTypes/onap.policies.controlloop.operational.common.Drools/1.0.0", status.getStatusCode()); + get("policyTypes/onap.policies.type1.type2/1.0.0", status.getStatusCode()); + get("policyTypes/onap.policies.typeA/1.0.0", status.getStatusCode()); + } + + private void assertAddNativeArtifactPolicy(ToscaPolicy nativeArtifactPolicy) throws CoderException { + booleanPost("policies", toString(nativeArtifactPolicy), Status.OK.getStatusCode(), Boolean.TRUE); + + assertTrue(PolicyControllerConstants.getFactory().get("lifecycle").isAlive()); + assertTrue(PolicyControllerConstants.getFactory().get("lifecycle").getDrools().isBrained()); + assertTrue(PolicyControllerConstants.getFactory().get("lifecycle").getDrools().isAlive()); + } + + private void assertAddNativeControllerPolicy(ToscaPolicy nativeControllerPolicy) throws CoderException { + booleanPost("policies", toString(nativeControllerPolicy), Status.OK.getStatusCode(), Boolean.TRUE); - booleanDelete("policies/example.artifact/1.0.0", Status.OK.getStatusCode()); assertTrue(PolicyControllerConstants.getFactory().get("lifecycle").isAlive()); assertFalse(PolicyControllerConstants.getFactory().get("lifecycle").getDrools().isBrained()); + assertFalse(PolicyControllerConstants.getFactory().get("lifecycle").getDrools().isAlive()); - resourceLists("policyTypes", 2); - get("policyTypes/onap.policies.native.drools.Artifact/1.0.0", Status.OK.getStatusCode()); - get("policyTypes/onap.policies.native.drools.Controller/1.0.0", Status.OK.getStatusCode()); get("policyTypes/onap.policies.controlloop.operational.common.Drools/1.0.0", Status.NOT_FOUND.getStatusCode()); - get("policyTypes/onap.policies.type1.type2/1.0.0", Status.NOT_FOUND.getStatusCode()); - get("policyTypes/onap.policies.typeA/1.0.0", Status.NOT_FOUND.getStatusCode()); resourceLists("policies", 1); - get("policies/" + opPolicy.getName() + "/" + opPolicy.getVersion(), Status.NOT_FOUND.getStatusCode()); - get("policies/example.artifact/1.0.0", Status.NOT_FOUND.getStatusCode()); get("policies/example.controller/1.0.0", Status.OK.getStatusCode()); + } - /* delete native controller policy */ - - booleanDelete("policies/example.controller/1.0.0", Status.OK.getStatusCode()); - + private void assertStartup() { resourceLists("policyTypes", 2); get("policyTypes/onap.policies.native.drools.Artifact/1.0.0", Status.OK.getStatusCode()); get("policyTypes/onap.policies.native.drools.Controller/1.0.0", Status.OK.getStatusCode()); get("policyTypes/onap.policies.controlloop.operational.common.Drools/1.0.0", Status.NOT_FOUND.getStatusCode()); - get("policyTypes/onap.policies.type1.type2/1.0.0", Status.NOT_FOUND.getStatusCode()); - get("policyTypes/onap.policies.typeA/1.0.0", Status.NOT_FOUND.getStatusCode()); resourceLists("policies", 0); - get("policies/" + opPolicy.getName() + "/" + opPolicy.getVersion(), Status.NOT_FOUND.getStatusCode()); - get("policies/example.artifact/1.0.0", Status.NOT_FOUND.getStatusCode()); get("policies/example.controller/1.0.0", Status.NOT_FOUND.getStatusCode()); - - assertThatIllegalArgumentException().isThrownBy(() -> PolicyControllerConstants.getFactory().get("lifecycle")); - opPolicy.getMetadata().remove("policy-id"); - assertThat(listPost(toString(opPolicy), Status.NOT_ACCEPTABLE.getStatusCode())).isEmpty(); - - metrics(); + get("policies/example.artifact/1.0.0", Status.NOT_FOUND.getStatusCode()); } private void testNotNativePolicy(ToscaPolicy toscaPolicy) throws CoderException { diff --git a/feature-no-locking/src/assembly/assemble_zip.xml b/feature-no-locking/src/assembly/assemble_zip.xml index 2c74fc00..ded6dff7 100644 --- a/feature-no-locking/src/assembly/assemble_zip.xml +++ b/feature-no-locking/src/assembly/assemble_zip.xml @@ -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. @@ -60,12 +61,6 @@ <excludes/> </fileSet> <fileSet> - <directory>src/main/feature/db</directory> - <outputDirectory>db</outputDirectory> - <fileMode>0744</fileMode> - <excludes/> - </fileSet> - <fileSet> <directory>src/main/feature/install</directory> <outputDirectory>install</outputDirectory> <fileMode>0744</fileMode> diff --git a/feature-no-locking/src/main/java/org/onap/policy/no/locking/NoLockManager.java b/feature-no-locking/src/main/java/org/onap/policy/no/locking/NoLockManager.java index 49ea0af9..449f7480 100644 --- a/feature-no-locking/src/main/java/org/onap/policy/no/locking/NoLockManager.java +++ b/feature-no-locking/src/main/java/org/onap/policy/no/locking/NoLockManager.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. @@ -20,7 +21,6 @@ package org.onap.policy.no.locking; -import java.util.Properties; import lombok.NoArgsConstructor; import lombok.ToString; import org.onap.policy.drools.core.lock.AlwaysSuccessLock; @@ -28,7 +28,6 @@ import org.onap.policy.drools.core.lock.Lock; import org.onap.policy.drools.core.lock.LockCallback; import org.onap.policy.drools.core.lock.PolicyResourceLockManager; import org.onap.policy.drools.features.PolicyEngineFeatureApi; -import org.onap.policy.drools.system.PolicyEngine; /** * In contrast with other implementations the no-lock manager provides non-synchronized access @@ -43,8 +42,8 @@ public class NoLockManager implements PolicyResourceLockManager, PolicyEngineFea @Override public Lock createLock(String resourceId, String ownerKey, int holdSec, - LockCallback callback, boolean waitForLock) { - var successLock = new AlwaysSuccessLock(resourceId, ownerKey, holdSec, callback); + LockCallback callback, boolean waitForLock) { + var successLock = new AlwaysSuccessLock(resourceId, ownerKey, holdSec, callback); successLock.notifyAvailable(); return successLock; } @@ -90,7 +89,7 @@ public class NoLockManager implements PolicyResourceLockManager, PolicyEngineFea } @Override - public PolicyResourceLockManager beforeCreateLockManager(PolicyEngine engine, Properties properties) { + public PolicyResourceLockManager beforeCreateLockManager() { return this; } } diff --git a/feature-no-locking/src/test/java/org/onap/policy/no/locking/NoLockManagerTest.java b/feature-no-locking/src/test/java/org/onap/policy/no/locking/NoLockManagerTest.java index 5b5e0964..22f3f5d1 100644 --- a/feature-no-locking/src/test/java/org/onap/policy/no/locking/NoLockManagerTest.java +++ b/feature-no-locking/src/test/java/org/onap/policy/no/locking/NoLockManagerTest.java @@ -93,7 +93,7 @@ public class NoLockManagerTest { @Test void testBeforeCreateLockManager() { - assertEquals(nlm, nlm.beforeCreateLockManager(null, null)); + assertEquals(nlm, nlm.beforeCreateLockManager()); } @Test diff --git a/feature-pooling-messages/src/assembly/assemble_zip.xml b/feature-pooling-messages/src/assembly/assemble_zip.xml index 67424116..a4c7b0fa 100644 --- a/feature-pooling-messages/src/assembly/assemble_zip.xml +++ b/feature-pooling-messages/src/assembly/assemble_zip.xml @@ -3,6 +3,7 @@ feature-pooling-messages ================================================================================ Copyright (C) 2018 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. @@ -61,12 +62,6 @@ <excludes/> </fileSet> <fileSet> - <directory>src/main/feature/db</directory> - <outputDirectory>db</outputDirectory> - <fileMode>0744</fileMode> - <excludes/> - </fileSet> - <fileSet> <directory>src/main/feature/install</directory> <outputDirectory>install</outputDirectory> <fileMode>0744</fileMode> diff --git a/feature-pooling-messages/src/main/feature/config/feature-pooling-messages.properties b/feature-pooling-messages/src/main/feature/config/feature-pooling-messages.properties index 3870ede1..020df961 100644 --- a/feature-pooling-messages/src/main/feature/config/feature-pooling-messages.properties +++ b/feature-pooling-messages/src/main/feature/config/feature-pooling-messages.properties @@ -82,8 +82,10 @@ kafka.source.topics.policy-pdp-pooling.servers=${env:KAFKA_SERVERS} kafka.source.topics.policy-pdp-pooling.effectiveTopic=${env:POOLING_TOPIC} kafka.source.topics.policy-pdp-pooling.apiKey= kafka.source.topics.policy-pdp-pooling.apiSecret= +kafka.source.topics.policy-pdp-pooling.additionalProps=${env:KAFKA_ADDITIONAL_PROPS} kafka.sink.topics.policy-pdp-pooling.servers=${env:KAFKA_SERVERS} kafka.sink.topics.policy-pdp-pooling.effectiveTopic=${env:POOLING_TOPIC} kafka.sink.topics.policy-pdp-pooling.apiKey= kafka.sink.topics.policy-pdp-pooling.apiSecret= +kafka.sink.topics.policy-pdp-pooling.additionalProps=${env:KAFKA_ADDITIONAL_PROPS} diff --git a/feature-test-transaction/src/assembly/assemble_zip.xml b/feature-test-transaction/src/assembly/assemble_zip.xml index 9945a1c9..0b5763c4 100644 --- a/feature-test-transaction/src/assembly/assemble_zip.xml +++ b/feature-test-transaction/src/assembly/assemble_zip.xml @@ -3,6 +3,7 @@ feature-test-transaction ================================================================================ Copyright (C) 2017 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. @@ -59,11 +60,6 @@ <fileMode>0744</fileMode> </fileSet> <fileSet> - <directory>src/main/feature/db</directory> - <outputDirectory>db</outputDirectory> - <fileMode>0744</fileMode> - </fileSet> - <fileSet> <directory>src/main/feature/install</directory> <outputDirectory>install</outputDirectory> <fileMode>0744</fileMode> diff --git a/packages/base/src/files/bin/policy b/packages/base/src/files/bin/policy index 690fe1e5..c5ec37fa 100644 --- a/packages/base/src/files/bin/policy +++ b/packages/base/src/files/bin/policy @@ -4,6 +4,7 @@ # ONAP # ================================================================================ # Copyright (C) 2017-2021 AT&T Intellectual Property. All rights reserved. +# Modifications Copyright (C) 2024 Nordix Foundation. # ================================================================================ # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -72,13 +73,6 @@ function policy_status() { echo echo "[features]" features status - - local databases=$(ls -d "${POLICY_HOME}"/etc/db/migration/*/ 2>/dev/null) - if [ -n "${databases}" ]; then - echo "[migration]" - db-migrator -s ALL -o ok - fi - } function policy_start() { diff --git a/packages/docker/src/main/docker/Dockerfile b/packages/docker/src/main/docker/Dockerfile index a3d013d4..d263ba71 100644 --- a/packages/docker/src/main/docker/Dockerfile +++ b/packages/docker/src/main/docker/Dockerfile @@ -2,7 +2,7 @@ # Dockerfile # ============LICENSE_START======================================================= # Copyright (C) 2020-2021 AT&T Intellectual Property. All rights reserved. -# Modifications Copyright (C) 2022-2023 Nordix Foundation. +# Modifications Copyright (C) 2022-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. @@ -52,9 +52,7 @@ ENV http_proxy $http_proxy USER root RUN apk update && \ - apk add --no-cache mariadb-client \ - file \ - maven \ + apk add --no-cache file maven \ net-tools netcat-openbsd sudo less vim openssl \ && python3 -m pip install --no-cache-dir --upgrade setuptools http-prompt \ && python3 -m pip install --no-cache-dir httpie diff --git a/packages/docker/src/main/docker/pdpd-entrypoint.sh b/packages/docker/src/main/docker/pdpd-entrypoint.sh index 2caca628..c2e3f020 100644 --- a/packages/docker/src/main/docker/pdpd-entrypoint.sh +++ b/packages/docker/src/main/docker/pdpd-entrypoint.sh @@ -138,26 +138,6 @@ function serverConfig { done } -function db { - if [ "${DEBUG}" = "y" ]; then - echo "-- db --" - set -x - fi - - if [ -z "${SQL_HOST}" ]; then - return 0 - fi - - if [ -z "${SQL_PORT}" ]; then - export SQL_PORT=3306 - fi - - echo "Waiting for ${SQL_HOST}:${SQL_PORT} ..." - timeout 120 sh -c 'until nc -vz -w 20 "${SQL_HOST}" "${SQL_PORT}"; do echo -n "."; sleep 1; done' - - "${POLICY_HOME}"/bin/db-migrator -s ALL -o upgrade -} - function inspect { if [ "${DEBUG}" = "y" ]; then echo "-- inspect --" @@ -209,7 +189,6 @@ function configure { fi reload - db } function vmBoot { @@ -219,7 +198,6 @@ function vmBoot { fi reload - db start scripts "post.sh" } diff --git a/packages/docker/src/main/docker/suse.Dockerfile b/packages/docker/src/main/docker/suse.Dockerfile index e6bf9dbd..c83a5cc6 100644 --- a/packages/docker/src/main/docker/suse.Dockerfile +++ b/packages/docker/src/main/docker/suse.Dockerfile @@ -1,7 +1,7 @@ #------------------------------------------------------------------------------- # Dockerfile # ============LICENSE_START======================================================= -# Copyright (C) 2022 Nordix Foundation. +# Copyright (C) 2022, 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. @@ -56,7 +56,6 @@ RUN zypper -n -q install --no-recommends \ gzip \ java-17-openjdk-devel \ maven \ - mariadb-client \ netcat-openbsd \ python3 \ python3-pip \ 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/main/java/org/onap/policy/drools/core/jmx/PdpJmx.java b/policy-core/src/main/java/org/onap/policy/drools/core/jmx/PdpJmx.java index 4356d111..4aa8de49 100644 --- a/policy-core/src/main/java/org/onap/policy/drools/core/jmx/PdpJmx.java +++ b/policy-core/src/main/java/org/onap/policy/drools/core/jmx/PdpJmx.java @@ -27,7 +27,7 @@ import lombok.Getter; public class PdpJmx implements PdpJmxMBean { @Getter - private static PdpJmx instance = new PdpJmx(); + static PdpJmx instance = new PdpJmx(); private final AtomicLong updates = new AtomicLong(); private final AtomicLong actions = new AtomicLong(); 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)); + } } diff --git a/policy-management/src/main/java/org/onap/policy/drools/controller/IndexedDroolsControllerFactory.java b/policy-management/src/main/java/org/onap/policy/drools/controller/IndexedDroolsControllerFactory.java index 7f28f9bb..a6459d67 100644 --- a/policy-management/src/main/java/org/onap/policy/drools/controller/IndexedDroolsControllerFactory.java +++ b/policy-management/src/main/java/org/onap/policy/drools/controller/IndexedDroolsControllerFactory.java @@ -28,6 +28,7 @@ import java.util.List; import java.util.Map; import java.util.Properties; import lombok.NonNull; +import org.apache.commons.lang3.StringUtils; import org.onap.policy.common.endpoints.event.comm.Topic; import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure; import org.onap.policy.common.endpoints.event.comm.TopicSink; @@ -62,7 +63,7 @@ class IndexedDroolsControllerFactory implements DroolsControllerFactory { /** * Null Drools Controller. */ - protected NullDroolsController nullDroolsController = new NullDroolsController(); + protected NullDroolsController nullDroolsController; /** * Constructs the object. @@ -71,11 +72,11 @@ class IndexedDroolsControllerFactory implements DroolsControllerFactory { /* Add a NULL controller which will always be present in the hash */ - DroolsController controller = new NullDroolsController(); - String controllerId = controller.getGroupId() + ":" + controller.getArtifactId(); + nullDroolsController = new NullDroolsController(); + String controllerId = nullDroolsController.getGroupId() + ":" + nullDroolsController.getArtifactId(); synchronized (this) { - droolsControllers.put(controllerId, controller); + droolsControllers.put(controllerId, nullDroolsController); } } @@ -84,17 +85,17 @@ class IndexedDroolsControllerFactory implements DroolsControllerFactory { List<? extends TopicSink> eventSinks) throws LinkageError { String groupId = properties.getProperty(DroolsPropertyConstants.RULES_GROUPID); - if (groupId == null || groupId.isEmpty()) { + if (StringUtils.isBlank(groupId)) { groupId = DroolsControllerConstants.NO_GROUP_ID; } String artifactId = properties.getProperty(DroolsPropertyConstants.RULES_ARTIFACTID); - if (artifactId == null || artifactId.isEmpty()) { + if (StringUtils.isBlank(artifactId)) { artifactId = DroolsControllerConstants.NO_ARTIFACT_ID; } String version = properties.getProperty(DroolsPropertyConstants.RULES_VERSION); - if (version == null || version.isEmpty()) { + if (StringUtils.isBlank(version)) { version = DroolsControllerConstants.NO_VERSION; } @@ -110,15 +111,15 @@ class IndexedDroolsControllerFactory implements DroolsControllerFactory { List<TopicCoderFilterConfiguration> decoderConfigurations, List<TopicCoderFilterConfiguration> encoderConfigurations) throws LinkageError { - if (newGroupId == null || newGroupId.isEmpty()) { + if (StringUtils.isBlank(newGroupId)) { throw new IllegalArgumentException("Missing maven group-id coordinate"); } - if (newArtifactId == null || newArtifactId.isEmpty()) { + if (StringUtils.isBlank(newArtifactId)) { throw new IllegalArgumentException("Missing maven artifact-id coordinate"); } - if (newVersion == null || newVersion.isEmpty()) { + if (StringUtils.isBlank(newVersion)) { throw new IllegalArgumentException("Missing maven version coordinate"); } @@ -240,7 +241,7 @@ class IndexedDroolsControllerFactory implements DroolsControllerFactory { String eventClasses = properties .getProperty(propertyTopicEntityPrefix + PolicyEndPointProperties.PROPERTY_TOPIC_EVENTS_SUFFIX); - if (eventClasses == null || eventClasses.isEmpty()) { + if (StringUtils.isBlank(eventClasses)) { logger.warn("There are no event classes for topic {}", firstTopic); continue; } @@ -280,7 +281,7 @@ class IndexedDroolsControllerFactory implements DroolsControllerFactory { + PolicyEndPointProperties.PROPERTY_TOPIC_EVENTS_CUSTOM_MODEL_CODER_GSON_SUFFIX); CustomGsonCoder customGsonCoder = null; - if (customGson != null && !customGson.isEmpty()) { + if (StringUtils.isNotBlank(customGson)) { try { customGsonCoder = new CustomGsonCoder(customGson); } catch (IllegalArgumentException e) { @@ -375,7 +376,7 @@ class IndexedDroolsControllerFactory implements DroolsControllerFactory { @Override public DroolsController get(String groupId, String artifactId, String version) { - if (groupId == null || artifactId == null || groupId.isEmpty() || artifactId.isEmpty()) { + if (StringUtils.isBlank(groupId) || StringUtils.isBlank(artifactId)) { throw new IllegalArgumentException("Missing maven coordinates: " + groupId + ":" + artifactId); } diff --git a/policy-management/src/main/java/org/onap/policy/drools/controller/internal/MavenDroolsController.java b/policy-management/src/main/java/org/onap/policy/drools/controller/internal/MavenDroolsController.java index 68a69159..aa701dfd 100644 --- a/policy-management/src/main/java/org/onap/policy/drools/controller/internal/MavenDroolsController.java +++ b/policy-management/src/main/java/org/onap/policy/drools/controller/internal/MavenDroolsController.java @@ -3,7 +3,7 @@ * ONAP * ================================================================================ * Copyright (C) 2017-2021 AT&T Intellectual Property. All rights reserved. - * Modifications Copyright (C) 2023 Nordix Foundation. + * Modifications Copyright (C) 2023-2024 Nordix Foundation. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,6 +31,7 @@ import java.util.stream.Collectors; import lombok.Getter; import lombok.NonNull; import org.apache.commons.collections4.queue.CircularFifoQueue; +import org.apache.commons.lang3.StringUtils; import org.drools.core.ClassObjectFilter; import org.kie.api.definition.KiePackage; import org.kie.api.definition.rule.Query; @@ -219,7 +220,7 @@ public class MavenDroolsController implements DroolsController { } private void validateText(String text, String errorMessage) { - if (text == null || text.isEmpty()) { + if (StringUtils.isBlank(text)) { throw new IllegalArgumentException(errorMessage); } } diff --git a/policy-management/src/main/java/org/onap/policy/drools/features/PolicyControllerFeatureApi.java b/policy-management/src/main/java/org/onap/policy/drools/features/PolicyControllerFeatureApi.java index f022bf1d..15b48a5c 100644 --- a/policy-management/src/main/java/org/onap/policy/drools/features/PolicyControllerFeatureApi.java +++ b/policy-management/src/main/java/org/onap/policy/drools/features/PolicyControllerFeatureApi.java @@ -3,6 +3,7 @@ * ONAP * ================================================================================ * Copyright (C) 2017-2020 AT&T Intellectual Property. All rights reserved. + * Modifications Copyright (C) 2024 Nordix Foundation. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,7 +33,7 @@ public interface PolicyControllerFeatureApi extends OrderedService { * called before creating a controller with name 'name' and * properties 'properties'. * - * @param name name of the the controller + * @param name name of the controller * @param properties configuration properties * * @return a policy controller. A take over of the creation operation diff --git a/policy-management/src/main/java/org/onap/policy/drools/features/PolicyEngineFeatureApi.java b/policy-management/src/main/java/org/onap/policy/drools/features/PolicyEngineFeatureApi.java index 8edf394e..27b96999 100644 --- a/policy-management/src/main/java/org/onap/policy/drools/features/PolicyEngineFeatureApi.java +++ b/policy-management/src/main/java/org/onap/policy/drools/features/PolicyEngineFeatureApi.java @@ -182,7 +182,7 @@ public interface PolicyEngineFeatureApi extends OrderedService { * * @return true if this feature intercepts and takes ownership * of the operation preventing the invocation of - * lower priority features. False, otherwise.. + * lower priority features. False, otherwise. */ default boolean afterLock(PolicyEngine engine) { return false; @@ -281,7 +281,7 @@ public interface PolicyEngineFeatureApi extends OrderedService { * operation preventing the invocation of lower priority features. Null, * otherwise */ - default PolicyResourceLockManager beforeCreateLockManager(PolicyEngine engine, Properties properties) { + default PolicyResourceLockManager beforeCreateLockManager() { return null; } diff --git a/policy-management/src/main/java/org/onap/policy/drools/persistence/FileSystemPersistence.java b/policy-management/src/main/java/org/onap/policy/drools/persistence/FileSystemPersistence.java index 9fb76d87..717a6f58 100644 --- a/policy-management/src/main/java/org/onap/policy/drools/persistence/FileSystemPersistence.java +++ b/policy-management/src/main/java/org/onap/policy/drools/persistence/FileSystemPersistence.java @@ -35,6 +35,7 @@ import java.util.List; import java.util.Properties; import java.util.function.BiPredicate; import lombok.Getter; +import lombok.NonNull; import lombok.ToString; import org.onap.policy.drools.properties.DroolsPropertyConstants; import org.onap.policy.drools.utils.PropertyUtil; @@ -151,7 +152,7 @@ public class FileSystemPersistence implements SystemPersistence { } } - protected Properties getProperties(Path propertiesPath) { + protected Properties getProperties(@NonNull Path propertiesPath) { if (!Files.exists(propertiesPath)) { throw new IllegalArgumentException("properties for " + propertiesPath + " are not persisted."); } diff --git a/policy-management/src/main/java/org/onap/policy/drools/protocol/coders/EventProtocolCoder.java b/policy-management/src/main/java/org/onap/policy/drools/protocol/coders/EventProtocolCoder.java index 88b25255..7cfa5a3a 100644 --- a/policy-management/src/main/java/org/onap/policy/drools/protocol/coders/EventProtocolCoder.java +++ b/policy-management/src/main/java/org/onap/policy/drools/protocol/coders/EventProtocolCoder.java @@ -4,6 +4,7 @@ * ================================================================================ * Copyright (C) 2017-2019,2022 AT&T Intellectual Property. All rights reserved. * Modifications Copyright(C) 2018 Samsung Electronics Co., Ltd. + * Modifications Copyright (C) 2024 Nordix Foundation. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,7 +36,7 @@ public interface EventProtocolCoder { @Getter @Setter @AllArgsConstructor - public static class CoderFilters { + class CoderFilters { /** * coder class. @@ -54,13 +55,9 @@ public interface EventProtocolCoder { @Override public String toString() { - return "CoderFilters [factClass=" - + factClass - + ", filter=" - + filter - + ", modelClassLoaderHash=" - + modelClassLoaderHash - + "]"; + return "CoderFilters [factClass=" + factClass + + ", filter=" + filter + + ", modelClassLoaderHash=" + modelClassLoaderHash + "]"; } } diff --git a/policy-management/src/main/java/org/onap/policy/drools/protocol/coders/GenericEventProtocolCoder.java b/policy-management/src/main/java/org/onap/policy/drools/protocol/coders/GenericEventProtocolCoder.java index 0729c706..6fe1648a 100644 --- a/policy-management/src/main/java/org/onap/policy/drools/protocol/coders/GenericEventProtocolCoder.java +++ b/policy-management/src/main/java/org/onap/policy/drools/protocol/coders/GenericEventProtocolCoder.java @@ -3,6 +3,7 @@ * ONAP * ================================================================================ * Copyright (C) 2019-2020, 2021 AT&T Intellectual Property. All rights reserved. + * Modifications Copyright (C) 2024 Nordix Foundation. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,15 +22,19 @@ package org.onap.policy.drools.protocol.coders; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Objects; import lombok.AccessLevel; import lombok.NoArgsConstructor; +import org.apache.commons.lang3.StringUtils; import org.onap.policy.drools.controller.DroolsController; import org.onap.policy.drools.controller.DroolsControllerConstants; import org.onap.policy.drools.protocol.coders.EventProtocolCoder.CoderFilters; +import org.onap.policy.drools.system.PolicyDroolsPdpRuntimeException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -43,7 +48,7 @@ abstract class GenericEventProtocolCoder { private static final String INVALID_GROUP_ID_MSG = "Invalid group id"; private static final String INVALID_TOPIC_MSG = "Invalid Topic"; private static final String UNSUPPORTED_MSG = "Unsupported"; - private static final String UNSUPPORTED_EX_MSG = "Unsupported:"; + private static final String UNSUPPORTED_EX_MSG = "Unsupported: "; private static final String MISSING_CLASS = "class must be provided"; private static final Logger logger = LoggerFactory.getLogger(GenericEventProtocolCoder.class); @@ -52,37 +57,26 @@ abstract class GenericEventProtocolCoder { * Mapping topic:controller-id -> /<protocol-decoder-toolset/> where protocol-coder-toolset contains * a gson-protocol-coder-toolset. */ - protected final HashMap<String, ProtocolCoderToolset> coders = - new HashMap<>(); + protected final HashMap<String, ProtocolCoderToolset> coders = new HashMap<>(); /** * Mapping topic + classname -> Protocol Set. */ - protected final HashMap<String, List<ProtocolCoderToolset>> - reverseCoders = new HashMap<>(); + protected final HashMap<String, List<ProtocolCoderToolset>> reverseCoders = new HashMap<>(); /** * Index a new coder. */ public void add(EventProtocolParams eventProtocolParams) { - if (eventProtocolParams.getGroupId() == null || eventProtocolParams.getGroupId().isEmpty()) { - throw new IllegalArgumentException(INVALID_GROUP_ID_MSG); - } - if (eventProtocolParams.getArtifactId() == null || eventProtocolParams.getArtifactId().isEmpty()) { - throw new IllegalArgumentException(INVALID_ARTIFACT_ID_MSG); - } + validateKeyParameters(eventProtocolParams.getGroupId(), + eventProtocolParams.getArtifactId(), + eventProtocolParams.getTopic()); - if (eventProtocolParams.getTopic() == null || eventProtocolParams.getTopic().isEmpty()) { - throw new IllegalArgumentException(INVALID_TOPIC_MSG); - } - - if (eventProtocolParams.getEventClass() == null) { - throw new IllegalArgumentException("Invalid Event Class"); - } + validateStringParameter(eventProtocolParams.getEventClass(), "Invalid Event Class"); String key = this.codersKey(eventProtocolParams.getGroupId(), eventProtocolParams.getArtifactId(), - eventProtocolParams.getTopic()); + eventProtocolParams.getTopic()); String reverseKey = this.reverseCodersKey(eventProtocolParams.getTopic(), eventProtocolParams.getEventClass()); synchronized (this) { @@ -91,22 +85,16 @@ abstract class GenericEventProtocolCoder { logger.info("{}: adding coders for existing {}: {}", this, key, toolset); - toolset - .addCoder( - eventProtocolParams.getEventClass(), - eventProtocolParams.getProtocolFilter(), - eventProtocolParams.getModelClassLoaderHash()); + toolset.addCoder( + eventProtocolParams.getEventClass(), + eventProtocolParams.getProtocolFilter(), + eventProtocolParams.getModelClassLoaderHash()); if (!reverseCoders.containsKey(reverseKey)) { - logger.info( - "{}: adding new reverse coders (multiple classes case) for {}:{}: {}", - this, - reverseKey, - key, - toolset); - - List<ProtocolCoderToolset> reverseMappings = - new ArrayList<>(); + logger.info("{}: adding new reverse coders (multiple classes case) for {}:{}: {}", + this, reverseKey, key, toolset); + + List<ProtocolCoderToolset> reverseMappings = new ArrayList<>(); reverseMappings.add(toolset); reverseCoders.put(reverseKey, reverseMappings); } @@ -128,20 +116,15 @@ abstract class GenericEventProtocolCoder { // There is another controller (different group id/artifact id/topic) // that shares the class and the topic. - List<ProtocolCoderToolset> toolsets = - reverseCoders.get(reverseKey); + List<ProtocolCoderToolset> toolsets = reverseCoders.get(reverseKey); var present = false; for (ProtocolCoderToolset parserSet : toolsets) { - // just doublecheck + // just double check present = parserSet.getControllerId().equals(key); if (present) { /* anomaly */ - logger.error( - "{}: unexpected toolset reverse mapping found for {}:{}: {}", - this, - reverseKey, - key, - parserSet); + logger.error("{}: unexpected toolset reverse mapping found for {}:{}: {}", + this, reverseKey, key, parserSet); } } @@ -191,17 +174,7 @@ abstract class GenericEventProtocolCoder { */ public void remove(String groupId, String artifactId, String topic) { - if (groupId == null || groupId.isEmpty()) { - throw new IllegalArgumentException(INVALID_GROUP_ID_MSG); - } - - if (artifactId == null || artifactId.isEmpty()) { - throw new IllegalArgumentException(INVALID_ARTIFACT_ID_MSG); - } - - if (topic == null || topic.isEmpty()) { - throw new IllegalArgumentException(INVALID_TOPIC_MSG); - } + validateKeyParameters(groupId, artifactId, topic); String key = this.codersKey(groupId, artifactId, topic); @@ -225,23 +198,23 @@ abstract class GenericEventProtocolCoder { return; } - List<ProtocolCoderToolset> toolsets = - this.reverseCoders.get(reverseKey); - Iterator<ProtocolCoderToolset> toolsetsIter = - toolsets.iterator(); + List<ProtocolCoderToolset> toolsets = this.reverseCoders.getOrDefault(reverseKey, Collections.emptyList()); + + if (toolsets.isEmpty()) { + logger.info("{}: removing reverse mapping for {}: ", this, reverseKey); + this.reverseCoders.remove(reverseKey); + return; + } + + Iterator<ProtocolCoderToolset> toolsetsIter = toolsets.iterator(); + while (toolsetsIter.hasNext()) { ProtocolCoderToolset toolset = toolsetsIter.next(); if (toolset.getControllerId().equals(key)) { - logger.info( - "{}: removed coder from toolset for {} from reverse mapping", this, reverseKey); + logger.info("{}: removed coder from toolset for {} from reverse mapping", this, reverseKey); toolsetsIter.remove(); } } - - if (this.reverseCoders.get(reverseKey).isEmpty()) { - logger.info("{}: removing reverse mapping for {}: ", this, reverseKey); - this.reverseCoders.remove(reverseKey); - } } /** @@ -250,23 +223,14 @@ abstract class GenericEventProtocolCoder { * @param groupId group id * @param artifactId artifact id * @param topic topic - * @return true if its is codable + * @return true if it's supported to be coded */ public boolean isCodingSupported(String groupId, String artifactId, String topic) { - if (groupId == null || groupId.isEmpty()) { - throw new IllegalArgumentException(INVALID_GROUP_ID_MSG); - } - - if (artifactId == null || artifactId.isEmpty()) { - throw new IllegalArgumentException(INVALID_ARTIFACT_ID_MSG); - } - - if (topic == null || topic.isEmpty()) { - throw new IllegalArgumentException(INVALID_TOPIC_MSG); - } + validateKeyParameters(groupId, artifactId, topic); String key = this.codersKey(groupId, artifactId, topic); + synchronized (this) { return coders.containsKey(key); } @@ -280,14 +244,14 @@ abstract class GenericEventProtocolCoder { * @param topic topic * @param json json string to convert to object * @return the decoded object - * @throws IllegalArgumentException if invalid argument is provided - * @throws UnsupportedOperationException if the operation cannot be performed + * @throws IllegalArgumentException if invalid argument is provided + * @throws PolicyDroolsPdpRuntimeException if the operation cannot be performed */ public Object decode(String groupId, String artifactId, String topic, String json) { if (!isCodingSupported(groupId, artifactId, topic)) { throw new IllegalArgumentException( - UNSUPPORTED_EX_MSG + codersKey(groupId, artifactId, topic) + " for encoding"); + UNSUPPORTED_EX_MSG + codersKey(groupId, artifactId, topic) + " for encoding"); } String key = this.codersKey(groupId, artifactId, topic); @@ -321,9 +285,7 @@ abstract class GenericEventProtocolCoder { throw new IllegalArgumentException(UNSUPPORTED_EX_MSG + codersKey(groupId, artifactId, topic)); } - if (event == null) { - throw new IllegalArgumentException("Unsupported topic:" + topic); - } + validateObjectParameter(event, "Event cannot be null or empty"); // reuse the decoder set, since there must be affinity in the model String key = this.codersKey(groupId, artifactId, topic); @@ -341,25 +303,18 @@ abstract class GenericEventProtocolCoder { */ public String encode(String topic, Object event) { - if (event == null) { - throw new IllegalArgumentException("Invalid encoded class"); - } + validateObjectParameter(event, "Event cannot be null or empty"); - if (topic == null || topic.isEmpty()) { - throw new IllegalArgumentException("Invalid topic"); - } + validateStringParameter(topic, INVALID_TOPIC_MSG); String reverseKey = this.reverseCodersKey(topic, event.getClass().getName()); if (!this.reverseCoders.containsKey(reverseKey)) { throw new IllegalArgumentException("no reverse coder has been found"); } - List<ProtocolCoderToolset> toolsets = - this.reverseCoders.get(reverseKey); + List<ProtocolCoderToolset> toolsets = this.reverseCoders.get(reverseKey); - String key = - codersKey( - toolsets.get(0).getGroupId(), toolsets.get(0).getArtifactId(), topic); + String key = codersKey(toolsets.get(0).getGroupId(), toolsets.get(0).getArtifactId(), topic); return this.encodeInternal(key, event); } @@ -374,13 +329,9 @@ abstract class GenericEventProtocolCoder { */ public String encode(String topic, Object encodedClass, DroolsController droolsController) { - if (encodedClass == null) { - throw new IllegalArgumentException("Invalid encoded class"); - } + validateObjectParameter(encodedClass, "Invalid encoded class"); - if (topic == null || topic.isEmpty()) { - throw new IllegalArgumentException("Invalid topic"); - } + validateStringParameter(topic, INVALID_TOPIC_MSG); String key = codersKey(droolsController.getGroupId(), droolsController.getArtifactId(), topic); return this.encodeInternal(key, encodedClass); @@ -397,31 +348,19 @@ abstract class GenericEventProtocolCoder { */ protected String encodeInternal(String key, Object event) { - logger.debug("{}: encode for {}: {}", this, key, event); // NOSONAR - - /* - * It seems that sonar declares the previous logging line as a security vulnerability - * when logging the topic variable. The static code analysis indicates that - * the path starts in org.onap.policy.drools.server.restful.RestManager::decode(), - * but the request is rejected if the topic contains invalid characters (the sonar description - * mentions "/r/n/t" characters) all of which are validated against in the checkValidNameInput(topic). - * Furthermore production instances are assumed not to have debug enabled, nor the REST telemetry API - * should be published externally. An additional note is that Path URLs containing spaces and newlines - * will be rejected earlier in the HTTP protocol libraries (jetty) so an URL of the form - * "https://../to\npic" won't even make it here. - */ + logger.debug("{}: encode for {}: {}", this, key, event); ProtocolCoderToolset coderTools = coders.get(key); try { String json = coderTools.encode(event); - if (json != null && !json.isEmpty()) { + if (!StringUtils.isBlank(json)) { return json; } } catch (Exception e) { logger.warn("{}: cannot encode (first) for {}: {}", this, key, event, e); } - throw new UnsupportedOperationException("Cannot decode with gson"); + throw new UnsupportedOperationException("Cannot encode with gson"); } /** @@ -443,50 +382,37 @@ abstract class GenericEventProtocolCoder { return droolsControllers; } - List<ProtocolCoderToolset> toolsets = - this.reverseCoders.get(reverseKey); + List<ProtocolCoderToolset> toolsets = this.reverseCoders.getOrDefault(reverseKey, Collections.emptyList()); // There must be multiple toolsets associated with <topic,classname> reverseKey // case 2 different controllers use the same models and register the same encoder for // the same topic. This is assumed not to occur often but for the purpose of encoding - // but there should be no side-effects. Ownership is crosscheck against classname and + // but there should be no side effects. Ownership is crosscheck against classname and // classloader reference. - if (toolsets == null || toolsets.isEmpty()) { - throw new IllegalStateException( - "No Encoders toolsets available for topic " - + topic - + " encoder " - + encodedClass.getClass().getName()); - } - for (ProtocolCoderToolset encoderSet : toolsets) { addToolsetControllers(droolsControllers, encodedClass, encoderSet); } if (droolsControllers.isEmpty()) { - throw new IllegalStateException( - "No Encoders toolsets available for " - + topic - + ":" - + encodedClass.getClass().getName()); + throw new IllegalStateException("No Encoders toolsets available for " + topic + ":" + + encodedClass.getClass().getName()); } return droolsControllers; } private void addToolsetControllers(List<DroolsController> droolsControllers, Object encodedClass, - ProtocolCoderToolset encoderSet) { + ProtocolCoderToolset encoderSet) { // figure out the right toolset String groupId = encoderSet.getGroupId(); String artifactId = encoderSet.getArtifactId(); List<CoderFilters> coderFilters = encoderSet.getCoders(); for (CoderFilters coder : coderFilters) { if (coder.getFactClass().equals(encodedClass.getClass().getName())) { - var droolsController = - DroolsControllerConstants.getFactory().get(groupId, artifactId, ""); + var droolsController = DroolsControllerConstants.getFactory().get(groupId, artifactId, ""); if (droolsController.ownsCoder( - encodedClass.getClass(), coder.getModelClassLoaderHash())) { + encodedClass.getClass(), coder.getModelClassLoaderHash())) { droolsControllers.add(droolsController); } } @@ -523,19 +449,13 @@ abstract class GenericEventProtocolCoder { */ public List<CoderFilters> getFilters(String groupId, String artifactId) { - if (groupId == null || groupId.isEmpty()) { - throw new IllegalArgumentException(INVALID_GROUP_ID_MSG); - } - - if (artifactId == null || artifactId.isEmpty()) { - throw new IllegalArgumentException(INVALID_ARTIFACT_ID_MSG); - } + validateStringParameter(groupId, INVALID_GROUP_ID_MSG); + validateStringParameter(artifactId, INVALID_ARTIFACT_ID_MSG); String key = this.codersKey(groupId, artifactId, ""); List<CoderFilters> codersFilters = new ArrayList<>(); - for (Map.Entry<String, ProtocolCoderToolset> entry : - coders.entrySet()) { + for (Map.Entry<String, ProtocolCoderToolset> entry : coders.entrySet()) { if (entry.getKey().startsWith(key)) { codersFilters.addAll(entry.getValue().getCoders()); } @@ -555,15 +475,13 @@ abstract class GenericEventProtocolCoder { * @throws IllegalArgumentException if invalid input */ public CoderFilters getFilters( - String groupId, String artifactId, String topic, String classname) { + String groupId, String artifactId, String topic, String classname) { if (!isCodingSupported(groupId, artifactId, topic)) { throw new IllegalArgumentException(UNSUPPORTED_EX_MSG + codersKey(groupId, artifactId, topic)); } - if (classname == null || classname.isEmpty()) { - throw new IllegalArgumentException("classname must be provided"); - } + validateStringParameter(classname, "classname must be provided"); String key = this.codersKey(groupId, artifactId, topic); ProtocolCoderToolset coderTools = coders.get(key); @@ -580,7 +498,7 @@ abstract class GenericEventProtocolCoder { * @throws IllegalArgumentException if invalid input */ public ProtocolCoderToolset getCoders( - String groupId, String artifactId, String topic) { + String groupId, String artifactId, String topic) { if (!isCodingSupported(groupId, artifactId, topic)) { throw new IllegalArgumentException(UNSUPPORTED_EX_MSG + codersKey(groupId, artifactId, topic)); @@ -598,22 +516,16 @@ abstract class GenericEventProtocolCoder { * @return list of coders * @throws IllegalArgumentException if invalid input */ - public List<ProtocolCoderToolset> getCoders( - String groupId, String artifactId) { + public List<ProtocolCoderToolset> getCoders(String groupId, String artifactId) { - if (groupId == null || groupId.isEmpty()) { - throw new IllegalArgumentException(INVALID_GROUP_ID_MSG); - } + validateStringParameter(groupId, INVALID_GROUP_ID_MSG); - if (artifactId == null || artifactId.isEmpty()) { - throw new IllegalArgumentException(INVALID_ARTIFACT_ID_MSG); - } + validateStringParameter(artifactId, INVALID_ARTIFACT_ID_MSG); String key = this.codersKey(groupId, artifactId, ""); List<ProtocolCoderToolset> coderToolset = new ArrayList<>(); - for (Map.Entry<String, ProtocolCoderToolset> entry : - coders.entrySet()) { + for (Map.Entry<String, ProtocolCoderToolset> entry : coders.entrySet()) { if (entry.getKey().startsWith(key)) { coderToolset.add(entry.getValue()); } @@ -631,19 +543,12 @@ abstract class GenericEventProtocolCoder { */ public List<CoderFilters> getReverseFilters(String topic, String codedClass) { - if (topic == null || topic.isEmpty()) { - throw new IllegalArgumentException(UNSUPPORTED_MSG); - } + validateStringParameter(topic, INVALID_TOPIC_MSG); - if (codedClass == null) { - throw new IllegalArgumentException(MISSING_CLASS); - } + validateStringParameter(codedClass, MISSING_CLASS); String key = this.reverseCodersKey(topic, codedClass); - List<ProtocolCoderToolset> toolsets = this.reverseCoders.get(key); - if (toolsets == null) { - throw new IllegalArgumentException("No Coder found for " + key); - } + List<ProtocolCoderToolset> toolsets = this.reverseCoders.getOrDefault(key, Collections.emptyList()); List<CoderFilters> coderFilters = new ArrayList<>(); for (ProtocolCoderToolset toolset : toolsets) { @@ -656,79 +561,70 @@ abstract class GenericEventProtocolCoder { /** * returns group and artifact id of the creator of the encoder. * - * @param topic topic - * @param fact fact + * @param topic topic + * @param encodedClass class encoder * @return the drools controller */ - DroolsController getDroolsController(String topic, Object fact) { - - if (topic == null || topic.isEmpty()) { - throw new IllegalArgumentException(UNSUPPORTED_MSG); - } - - if (fact == null) { - throw new IllegalArgumentException(MISSING_CLASS); - } - - List<DroolsController> droolsControllers = droolsCreators(topic, fact); + DroolsController getDroolsController(String topic, Object encodedClass) { + List<DroolsController> droolsControllers = getDroolsControllers(topic, encodedClass); if (droolsControllers.isEmpty()) { - throw new IllegalArgumentException("Invalid Topic: " + topic); + throw new IllegalArgumentException(UNSUPPORTED_MSG + " topic " + topic + + " and encodedClass " + encodedClass.getClass()); } - if (droolsControllers.size() > 1) { - logger.warn( - "{}: multiple drools-controller {} for {}:{} ", - this, - droolsControllers, - topic, - fact.getClass().getName()); - // continue - } return droolsControllers.get(0); } /** * returns group and artifact id of the creator of the encoder. * - * @param topic topic - * @param fact fact + * @param topic topic + * @param encodedClass class encoder * @return list of drools controllers */ - List<DroolsController> getDroolsControllers(String topic, Object fact) { + List<DroolsController> getDroolsControllers(String topic, Object encodedClass) { - if (topic == null || topic.isEmpty()) { - throw new IllegalArgumentException(UNSUPPORTED_MSG); - } + validateStringParameter(topic, INVALID_TOPIC_MSG); - if (fact == null) { - throw new IllegalArgumentException(MISSING_CLASS); - } + validateObjectParameter(encodedClass, MISSING_CLASS); - List<DroolsController> droolsControllers = droolsCreators(topic, fact); + List<DroolsController> droolsControllers = droolsCreators(topic, encodedClass); if (droolsControllers.size() > 1) { // unexpected - logger.warn( - "{}: multiple drools-controller {} for {}:{} ", - this, - droolsControllers, - topic, - fact.getClass().getName()); + logger.warn("{}: multiple drools-controller {} for {}:{} ", + this, droolsControllers, topic, encodedClass.getClass().getName()); // continue } return droolsControllers; } + private void validateKeyParameters(String groupId, String artifactId, String topic) { + validateStringParameter(groupId, INVALID_GROUP_ID_MSG); + validateStringParameter(artifactId, INVALID_ARTIFACT_ID_MSG); + validateStringParameter(topic, INVALID_TOPIC_MSG); + } + + private static void validateStringParameter(String value, String errorMessage) { + if (StringUtils.isBlank(value)) { + throw new IllegalArgumentException(errorMessage); + } + } + + private static void validateObjectParameter(Object object, String errorMessage) { + if (Objects.isNull(object)) { + throw new IllegalArgumentException(errorMessage); + } + } + /* - * Note: this only logs the KEYSETS, thus lombok ToString annotation is not used. + * Note: this only logs the KEY SETS, thus lombok ToString annotation is not used. * Otherwise, it results in too much verbosity. */ @Override public String toString() { - return "GenericEventProtocolCoder [coders=" - + coders.keySet() - + ", reverseCoders=" - + reverseCoders.keySet() - + "]"; + return "GenericEventProtocolCoder " + + "[coders=" + coders.keySet() + ", " + + "reverseCoders=" + reverseCoders.keySet() + "]"; } } diff --git a/policy-management/src/main/java/org/onap/policy/drools/protocol/coders/GsonProtocolCoderToolset.java b/policy-management/src/main/java/org/onap/policy/drools/protocol/coders/GsonProtocolCoderToolset.java index 80844612..18fcb1a3 100644 --- a/policy-management/src/main/java/org/onap/policy/drools/protocol/coders/GsonProtocolCoderToolset.java +++ b/policy-management/src/main/java/org/onap/policy/drools/protocol/coders/GsonProtocolCoderToolset.java @@ -3,6 +3,7 @@ * ONAP * ================================================================================ * Copyright (C) 2019-2022 AT&T Intellectual Property. All rights reserved. + * Modifications Copyright (C) 2024 Nordix Foundation. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -62,7 +63,7 @@ class GsonProtocolCoderToolset extends ProtocolCoderToolset { public static class GsonUtcAdapter implements JsonSerializer<ZonedDateTime>, JsonDeserializer<ZonedDateTime> { @Override public ZonedDateTime deserialize(JsonElement element, Type type, - JsonDeserializationContext context) { + JsonDeserializationContext context) { try { return ZonedDateTime.parse(element.getAsString(), format); } catch (final Exception e) { @@ -73,7 +74,7 @@ class GsonProtocolCoderToolset extends ProtocolCoderToolset { @Override public JsonElement serialize(ZonedDateTime datetime, Type type, - JsonSerializationContext context) { + JsonSerializationContext context) { return new JsonPrimitive(datetime.format(format)); } } @@ -112,7 +113,7 @@ class GsonProtocolCoderToolset extends ProtocolCoderToolset { * Toolset to encode/decode tools associated with a topic. * * @param eventProtocolParams parameter object for event encoder - * @param controllerId controller id + * @param controllerId controller id */ public GsonProtocolCoderToolset(EventProtocolParams eventProtocolParams, String controllerId) { super(eventProtocolParams, controllerId); @@ -145,7 +146,7 @@ class GsonProtocolCoderToolset extends ProtocolCoderToolset { public Object decode(String json) { final var droolsController = - DroolsControllerConstants.getFactory().get(this.groupId, this.artifactId, ""); + DroolsControllerConstants.getFactory().get(this.groupId, this.artifactId, ""); if (droolsController == null) { logger.warn("{}: no drools-controller to process {}", this, json); throw new IllegalStateException("no drools-controller to process event"); @@ -163,35 +164,36 @@ class GsonProtocolCoderToolset extends ProtocolCoderToolset { if (decoderClass == null) { logger.warn(CANNOT_FETCH_CLASS, this, decoderFilter.getFactClass()); throw new IllegalStateException( - FETCH_CLASS_EX_MSG + decoderFilter.getFactClass()); + FETCH_CLASS_EX_MSG + decoderFilter.getFactClass()); } } catch (final Exception e) { logger.warn(CANNOT_FETCH_CLASS, this, decoderFilter.getFactClass()); throw new UnsupportedOperationException( - FETCH_CLASS_EX_MSG + decoderFilter.getFactClass(), e); + FETCH_CLASS_EX_MSG + decoderFilter.getFactClass(), e); } if (this.customCoder != null) { try { final var gsonClassContainer = - droolsController.fetchModelClass(this.customCoder.getClassContainer()); + droolsController.fetchModelClass(this.customCoder.getClassContainer()); final var gsonField = gsonClassContainer.getField(this.customCoder.staticCoderField); final var gsonObject = gsonField.get(null); final var fromJsonMethod = gsonObject.getClass().getDeclaredMethod("fromJson", - String.class, Class.class); + String.class, Class.class); return fromJsonMethod.invoke(gsonObject, json, decoderClass); } catch (final Exception e) { logger.warn(CANNOT_FETCH_CLASS, this, decoderFilter.getFactClass()); - throw new UnsupportedOperationException( - FETCH_CLASS_EX_MSG + decoderFilter.getFactClass(), e); + throw new UnsupportedOperationException("cannot decode with customCoder: " + + customCoder.getClassContainer() + + " using application class " + decoderFilter.getFactClass(), e); } } else { try { - return this.decoder.fromJson(json, decoderClass); + return this.getDecoder().fromJson(json, decoderClass); } catch (final Exception e) { logger.warn("{} cannot decode {} into {}", this, json, decoderClass.getName()); throw new UnsupportedOperationException( - "cannot decode into " + decoderFilter.getFactClass(), e); + "cannot decode into " + decoderFilter.getFactClass(), e); } } } @@ -205,21 +207,20 @@ class GsonProtocolCoderToolset extends ProtocolCoderToolset { if (this.customCoder != null) { try { final var droolsController = - DroolsControllerConstants.getFactory().get(this.groupId, this.artifactId, null); + DroolsControllerConstants.getFactory().get(this.groupId, this.artifactId, null); final Class<?> gsonClassContainer = - droolsController.fetchModelClass(this.customCoder.getClassContainer()); + droolsController.fetchModelClass(this.customCoder.getClassContainer()); final var gsonField = gsonClassContainer.getField(this.customCoder.staticCoderField); final var gsonObject = gsonField.get(null); - final var toJsonMethod = - gsonObject.getClass().getDeclaredMethod("toJson", Object.class); + final var toJsonMethod = gsonObject.getClass().getDeclaredMethod("toJson", Object.class); return (String) toJsonMethod.invoke(gsonObject, event); } catch (final Exception e) { logger.warn("{} cannot custom-encode {}", this, event); - throw new UnsupportedOperationException("event cannot be encoded", e); + throw new UnsupportedOperationException("event cannot be custom encoded", e); } } else { try { - return this.encoder.toJson(event); + return this.getEncoder().toJson(event); } catch (final Exception e) { logger.warn("{} cannot encode {}", this, event); throw new UnsupportedOperationException("event cannot be encoded", e); diff --git a/policy-management/src/main/java/org/onap/policy/drools/protocol/coders/MultiplexorEventProtocolCoder.java b/policy-management/src/main/java/org/onap/policy/drools/protocol/coders/MultiplexorEventProtocolCoder.java index 3fea6821..cfbf2e4f 100644 --- a/policy-management/src/main/java/org/onap/policy/drools/protocol/coders/MultiplexorEventProtocolCoder.java +++ b/policy-management/src/main/java/org/onap/policy/drools/protocol/coders/MultiplexorEventProtocolCoder.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. @@ -20,7 +21,6 @@ package org.onap.policy.drools.protocol.coders; -import java.util.ArrayList; import java.util.List; import lombok.ToString; import org.onap.policy.drools.controller.DroolsController; @@ -126,19 +126,7 @@ class MultiplexorEventProtocolCoder implements EventProtocolCoder { */ @Override public Object decode(String groupId, String artifactId, String topic, String json) { - logger.debug("{}: decode {}:{}:{}:{}", this, groupId, artifactId, topic, json); // NOSONAR - - /* - * It seems that sonar declares the previous logging line as a security vulnerability - * when logging the topic variable. The static code analysis indicates that - * the path starts in org.onap.policy.drools.server.restful.RestManager::decode(), - * but the request is rejected if the topic contains invalid characters (the sonar description - * mentions "/r/n/t" characters) which are validated against in the checkValidNameInput(topic). - * Furthermore production instances are assumed not to have debug enabled, nor the REST telemetry API - * should be published externally. An additional note is that Path URLs containing spaces and newlines - * will be failed earlier at the HTTP protocol libraries (jetty, etc ..) so an URL of the form - * "https://../to\npic" won't even make it here. - */ + logger.debug("{}: decode {}:{}:{}:{}", this, groupId, artifactId, topic, json); return this.decoders.decode(groupId, artifactId, topic, json); } @@ -156,13 +144,7 @@ class MultiplexorEventProtocolCoder implements EventProtocolCoder { */ @Override public String encode(String topic, Object event) { - logger.debug("{}: encode {}:{}", this, topic, event); // NOSONAR - - /* - * See explanation for decode(String groupId, String artifactId, String topic, String json). - * The same applies here as it is called from - * org.onap.policy.drools.server.restful.RestManager::encode(), - */ + logger.debug("{}: encode {}:{}", this, topic, event); return this.encoders.encode(topic, event); } @@ -187,8 +169,7 @@ class MultiplexorEventProtocolCoder implements EventProtocolCoder { * {@inheritDoc}. */ @Override - public CoderFilters getDecoderFilters( - String groupId, String artifactId, String topic, String classname) { + public CoderFilters getDecoderFilters(String groupId, String artifactId, String topic, String classname) { return this.decoders.getFilters(groupId, artifactId, topic, classname); } @@ -205,18 +186,11 @@ class MultiplexorEventProtocolCoder implements EventProtocolCoder { */ @Override public ProtocolCoderToolset getDecoders(String groupId, String artifactId, String topic) { - ProtocolCoderToolset decoderToolsets = - this.decoders.getCoders(groupId, artifactId, topic); - if (decoderToolsets == null) { - throw new IllegalArgumentException( - "Decoders not found for " + groupId + ":" + artifactId + ":" + topic); - } - - return decoderToolsets; + return this.decoders.getCoders(groupId, artifactId, topic); } /** - * get all deocders by maven coordinates and topic. + * get all decoders by maven coordinates and topic. * * @param groupId group id * @param artifactId artifact id @@ -225,14 +199,7 @@ class MultiplexorEventProtocolCoder implements EventProtocolCoder { */ @Override public List<ProtocolCoderToolset> getDecoders(String groupId, String artifactId) { - - List<ProtocolCoderToolset> decoderToolsets = - this.decoders.getCoders(groupId, artifactId); - if (decoderToolsets == null) { - throw new IllegalArgumentException("Decoders not found for " + groupId + ":" + artifactId); - } - - return new ArrayList<>(decoderToolsets); + return this.decoders.getCoders(groupId, artifactId); } /** diff --git a/policy-management/src/main/java/org/onap/policy/drools/protocol/coders/ProtocolCoderToolset.java b/policy-management/src/main/java/org/onap/policy/drools/protocol/coders/ProtocolCoderToolset.java index 277c4ed3..5cd68709 100644 --- a/policy-management/src/main/java/org/onap/policy/drools/protocol/coders/ProtocolCoderToolset.java +++ b/policy-management/src/main/java/org/onap/policy/drools/protocol/coders/ProtocolCoderToolset.java @@ -4,6 +4,7 @@ * ================================================================================ * Copyright (C) 2017-2022 AT&T Intellectual Property. All rights reserved. * Modifications Copyright (C) 2018 Samsung Electronics Co., Ltd. + * Modifications Copyright (C) 2024 Nordix Foundation. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,6 +27,7 @@ import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import lombok.Getter; import lombok.Setter; +import org.apache.commons.lang3.StringUtils; import org.onap.policy.drools.protocol.coders.EventProtocolCoder.CoderFilters; import org.onap.policy.drools.protocol.coders.TopicCoderFilterConfiguration.CustomCoder; import org.slf4j.Logger; @@ -82,7 +84,7 @@ public abstract class ProtocolCoderToolset { */ protected ProtocolCoderToolset(EventProtocolParams eventProtocolParams, String controllerId) { - if (eventProtocolParams == null || controllerId == null) { + if (eventProtocolParams == null || StringUtils.isBlank(controllerId)) { throw new IllegalArgumentException("Invalid input"); } @@ -104,7 +106,7 @@ public abstract class ProtocolCoderToolset { * @return the decoder filters or null if not found */ public CoderFilters getCoder(String classname) { - if (classname == null || classname.isEmpty()) { + if (StringUtils.isBlank(classname)) { throw new IllegalArgumentException("no classname provided"); } @@ -132,7 +134,7 @@ public abstract class ProtocolCoderToolset { * @param filter filter */ public void addCoder(String eventClass, JsonProtocolFilter filter, int modelClassLoaderHash) { - if (eventClass == null || eventClass.isEmpty()) { + if (StringUtils.isBlank(eventClass)) { throw new IllegalArgumentException("no event class provided"); } @@ -152,7 +154,7 @@ public abstract class ProtocolCoderToolset { * @param eventClass event class */ public void removeCoders(String eventClass) { - if (eventClass == null || eventClass.isEmpty()) { + if (StringUtils.isBlank(eventClass)) { throw new IllegalArgumentException("no event class provided"); } diff --git a/policy-management/src/main/java/org/onap/policy/drools/protocol/coders/TopicCoderFilterConfiguration.java b/policy-management/src/main/java/org/onap/policy/drools/protocol/coders/TopicCoderFilterConfiguration.java index 4dd132b9..69bc0527 100644 --- a/policy-management/src/main/java/org/onap/policy/drools/protocol/coders/TopicCoderFilterConfiguration.java +++ b/policy-management/src/main/java/org/onap/policy/drools/protocol/coders/TopicCoderFilterConfiguration.java @@ -3,6 +3,7 @@ * policy-management * ================================================================================ * Copyright (C) 2017-2021 AT&T Intellectual Property. All rights reserved. + * Modifications Copyright (C) 2024 Nordix Foundation. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,6 +26,7 @@ import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; import lombok.ToString; +import org.apache.commons.lang3.StringUtils; @Getter @ToString @@ -51,19 +53,21 @@ public class TopicCoderFilterConfiguration { * @param rawCustomCoder with format: <class-containing-custom-coder>,<static-coder-field>. */ protected CustomCoder(String rawCustomCoder) { - if (rawCustomCoder != null && !rawCustomCoder.isEmpty()) { - - this.classContainer = rawCustomCoder.substring(0, rawCustomCoder.indexOf(',')); - if (this.classContainer == null || this.classContainer.isEmpty()) { - throw new IllegalArgumentException( - "No classname to create CustomCoder cannot be created"); - } - - this.staticCoderField = rawCustomCoder.substring(rawCustomCoder.indexOf(',') + 1); - if (this.staticCoderField == null || this.staticCoderField.isEmpty()) { - throw new IllegalArgumentException( - "No staticCoderField to create CustomCoder cannot be created for class " + classContainer); - } + if (StringUtils.isBlank(rawCustomCoder)) { + throw new IllegalArgumentException("Constructor argument cannot be empty. " + + "Use format \"customCoderClass,staticCoderField\""); + } + + this.classContainer = rawCustomCoder.substring(0, rawCustomCoder.indexOf(',')); + if (StringUtils.isBlank(this.classContainer)) { + throw new IllegalArgumentException( + "No classname to create CustomCoder cannot be created"); + } + + this.staticCoderField = rawCustomCoder.substring(rawCustomCoder.indexOf(',') + 1); + if (StringUtils.isBlank(this.staticCoderField)) { + throw new IllegalArgumentException( + "No staticCoderField to create CustomCoder cannot be created for class " + classContainer); } } @@ -74,11 +78,11 @@ public class TopicCoderFilterConfiguration { * @param staticCoderField static coder field */ protected CustomCoder(String className, String staticCoderField) { - if (className == null || className.isEmpty()) { + if (StringUtils.isBlank(className)) { throw new IllegalArgumentException("No classname to create CustomCoder cannot be created"); } - if (staticCoderField == null || staticCoderField.isEmpty()) { + if (StringUtils.isBlank(staticCoderField)) { throw new IllegalArgumentException( "No staticCoderField to create CustomCoder cannot be created for class " + className); } diff --git a/policy-management/src/main/java/org/onap/policy/drools/server/restful/RestManager.java b/policy-management/src/main/java/org/onap/policy/drools/server/restful/RestManager.java index 48cd8140..503ba336 100644 --- a/policy-management/src/main/java/org/onap/policy/drools/server/restful/RestManager.java +++ b/policy-management/src/main/java/org/onap/policy/drools/server/restful/RestManager.java @@ -21,6 +21,16 @@ package org.onap.policy.drools.server.restful; +import static jakarta.ws.rs.core.Response.Status.BAD_REQUEST; +import static jakarta.ws.rs.core.Response.Status.CREATED; +import static jakarta.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR; +import static jakarta.ws.rs.core.Response.Status.NOT_ACCEPTABLE; +import static jakarta.ws.rs.core.Response.Status.NOT_FOUND; +import static jakarta.ws.rs.core.Response.Status.NOT_MODIFIED; +import static jakarta.ws.rs.core.Response.Status.OK; +import static jakarta.ws.rs.core.Response.Status.PARTIAL_CONTENT; +import static org.onap.policy.drools.properties.DroolsPropertyConstants.PROPERTY_CONTROLLER_NAME; + import ch.qos.logback.classic.LoggerContext; import com.google.re2j.Pattern; import jakarta.ws.rs.Consumes; @@ -56,6 +66,7 @@ import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; import lombok.ToString; +import org.apache.commons.lang3.StringUtils; import org.onap.policy.common.endpoints.event.comm.Topic; import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure; import org.onap.policy.common.endpoints.event.comm.TopicEndpointManager; @@ -64,15 +75,13 @@ import org.onap.policy.common.endpoints.event.comm.TopicSource; import org.onap.policy.common.endpoints.http.server.YamlMessageBodyHandler; import org.onap.policy.common.utils.logging.LoggerUtils; import org.onap.policy.drools.controller.DroolsController; -import org.onap.policy.drools.properties.DroolsPropertyConstants; -import org.onap.policy.drools.protocol.coders.EventProtocolCoder.CoderFilters; import org.onap.policy.drools.protocol.coders.EventProtocolCoderConstants; import org.onap.policy.drools.protocol.coders.JsonProtocolFilter; -import org.onap.policy.drools.protocol.coders.ProtocolCoderToolset; import org.onap.policy.drools.protocol.configuration.ControllerConfiguration; import org.onap.policy.drools.protocol.configuration.PdpdConfiguration; import org.onap.policy.drools.system.PolicyController; import org.onap.policy.drools.system.PolicyControllerConstants; +import org.onap.policy.drools.system.PolicyDroolsPdpRuntimeException; import org.onap.policy.drools.system.PolicyEngineConstants; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -86,13 +95,12 @@ import org.slf4j.LoggerFactory; @Consumes({MediaType.APPLICATION_JSON, YamlMessageBodyHandler.APPLICATION_YAML}) @ToString public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsApi, - PropertiesApi, EnvironmentApi, SwitchesApi, ControllersApi, - TopicsApi, ToolsApi { + PropertiesApi, EnvironmentApi, SwitchesApi, ControllersApi, + TopicsApi, ToolsApi { private static final String OFFER_FAILED = "{}: cannot offer to topic {} because of {}"; private static final String CANNOT_PERFORM_OPERATION = "cannot perform operation"; - private static final String NO_FILTERS = " no filters"; - private static final String NOT_FOUND = " not found: "; + private static final String NO_FILTERS = " has no filters"; private static final String NOT_FOUND_MSG = " not found"; private static final String DOES_NOT_EXIST_MSG = " does not exist"; private static final String NOT_ACCEPTABLE_MSG = " not acceptable"; @@ -144,19 +152,12 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA @GET @Path("engine/swagger") public Response swagger() { - - try (InputStream inputStream = getClass().getResourceAsStream(SWAGGER); - BufferedReader reader = new BufferedReader( - new InputStreamReader(Objects.requireNonNull(inputStream)))) { - String contents = reader.lines() - .collect(Collectors.joining(System.lineSeparator())); - return Response.status(Response.Status.OK) - .entity(contents) - .build(); - } catch (IOException e) { - logger.error("Cannot read swagger.json {} because of {}", e.getMessage(), e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR) - .build(); + try { + String contents = getSwaggerContents(); + return Response.status(OK).entity(contents).build(); + } catch (Exception e) { + logger.error("Cannot read swagger.json {} because of {}", e.getMessage(), e.toString()); + return Response.status(INTERNAL_SERVER_ERROR).build(); } } @@ -170,7 +171,7 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA @GET @Path("engine") public Response engine() { - return Response.status(Response.Status.OK).entity(PolicyEngineConstants.getManager()).build(); + return Response.status(OK).entity(PolicyEngineConstants.getManager()).build(); } /** @@ -187,10 +188,10 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA } catch (final IllegalStateException e) { logger.error("{}: cannot shutdown {} because of {}", this, PolicyEngineConstants.getManager(), e.getMessage(), e); - return Response.status(Response.Status.BAD_REQUEST).entity(PolicyEngineConstants.getManager()).build(); + return Response.status(BAD_REQUEST).entity(PolicyEngineConstants.getManager()).build(); } - return Response.status(Response.Status.OK).entity(PolicyEngineConstants.getManager()).build(); + return Response.status(OK).entity(PolicyEngineConstants.getManager()).build(); } /** @@ -202,15 +203,14 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA @GET @Path("engine/features") public Response engineFeatures() { - return Response.status(Response.Status.OK).entity(PolicyEngineConstants.getManager().getFeatures()).build(); + return Response.status(OK).entity(PolicyEngineConstants.getManager().getFeatures()).build(); } @Override @GET @Path("engine/features/inventory") public Response engineFeaturesInventory() { - return Response.status(Response.Status.OK).entity(PolicyEngineConstants.getManager().getFeatureProviders()) - .build(); + return Response.status(OK).entity(PolicyEngineConstants.getManager().getFeatureProviders()).build(); } /** @@ -223,11 +223,11 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA @Path("engine/features/{featureName}") public Response engineFeature(@PathParam("featureName") String featureName) { try { - return Response.status(Response.Status.OK) - .entity(PolicyEngineConstants.getManager().getFeatureProvider(featureName)).build(); + return Response.status(OK).entity(PolicyEngineConstants.getManager().getFeatureProvider(featureName)) + .build(); } catch (final IllegalArgumentException iae) { logger.debug("feature unavailable: {}", featureName, iae); - return Response.status(Response.Status.NOT_FOUND).entity(new Error(iae.getMessage())).build(); + return errorResponse(NOT_FOUND, iae.getMessage()); } } @@ -240,7 +240,7 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA @GET @Path("engine/inputs") public Response engineInputs() { - return Response.status(Response.Status.OK).entity(INPUTS).build(); + return Response.status(OK).entity(INPUTS).build(); } /** @@ -252,22 +252,16 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA @POST @Path("engine/inputs/configuration") public Response engineUpdate(PdpdConfiguration configuration) { - final PolicyController controller = null; - boolean success; try { - success = PolicyEngineConstants.getManager().configure(configuration); + if (PolicyEngineConstants.getManager().configure(configuration)) { + return Response.status(OK).entity(true).build(); + } } catch (final Exception e) { - success = false; logger.info("{}: cannot configure {} because of {}", this, PolicyEngineConstants.getManager(), e.getMessage(), e); } - if (!success) { - return Response.status(Response.Status.NOT_ACCEPTABLE).entity(new Error(CANNOT_PERFORM_OPERATION)) - .build(); - } else { - return Response.status(Response.Status.OK).entity(controller).build(); - } + return errorResponse(NOT_ACCEPTABLE, CANNOT_PERFORM_OPERATION); } /** @@ -279,7 +273,7 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA @GET @Path("engine/properties") public Response engineProperties() { - return Response.status(Response.Status.OK).entity(PolicyEngineConstants.getManager().getProperties()).build(); + return Response.status(OK).entity(PolicyEngineConstants.getManager().getProperties()).build(); } /** @@ -291,7 +285,7 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA @GET @Path("engine/environment") public Response engineEnvironment() { - return Response.status(Response.Status.OK).entity(PolicyEngineConstants.getManager().getEnvironment()).build(); + return Response.status(OK).entity(PolicyEngineConstants.getManager().getEnvironment()).build(); } /** @@ -304,8 +298,8 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA @Path("engine/environment/{envProperty}") @Consumes(MediaType.TEXT_PLAIN) public Response engineEnvironmentProperty(@PathParam("envProperty") String envProperty) { - return Response.status(Response.Status.OK) - .entity(PolicyEngineConstants.getManager().getEnvironmentProperty(envProperty)).build(); + return Response.status(OK).entity(PolicyEngineConstants.getManager().getEnvironmentProperty(envProperty)) + .build(); } /** @@ -320,7 +314,7 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA @Produces(MediaType.TEXT_PLAIN) public Response engineEnvironmentAdd(@PathParam("envProperty") String envProperty, String envValue) { final String previousValue = PolicyEngineConstants.getManager().setEnvironmentProperty(envProperty, envValue); - return Response.status(Response.Status.OK).entity(previousValue).build(); + return Response.status(OK).entity(previousValue).build(); } /** @@ -332,7 +326,7 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA @GET @Path("engine/switches") public Response engineSwitches() { - return Response.status(Response.Status.OK).entity(SWITCHES).build(); + return Response.status(OK).entity(SWITCHES).build(); } /** @@ -344,21 +338,15 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA @PUT @Path("engine/switches/activation") public Response engineActivation() { - var success = true; try { PolicyEngineConstants.getManager().activate(); + return Response.status(OK).entity(PolicyEngineConstants.getManager()).build(); } catch (final Exception e) { - success = false; logger.info("{}: cannot activate {} because of {}", this, PolicyEngineConstants.getManager(), e.getMessage(), e); } - if (!success) { - return Response.status(Response.Status.NOT_ACCEPTABLE).entity(new Error(CANNOT_PERFORM_OPERATION)) - .build(); - } else { - return Response.status(Response.Status.OK).entity(PolicyEngineConstants.getManager()).build(); - } + return errorResponse(NOT_ACCEPTABLE, CANNOT_PERFORM_OPERATION); } /** @@ -370,21 +358,15 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA @DELETE @Path("engine/switches/activation") public Response engineDeactivation() { - var success = true; try { PolicyEngineConstants.getManager().deactivate(); + return Response.status(OK).entity(PolicyEngineConstants.getManager()).build(); } catch (final Exception e) { - success = false; logger.info("{}: cannot deactivate {} because of {}", this, PolicyEngineConstants.getManager(), e.getMessage(), e); } - if (!success) { - return Response.status(Response.Status.NOT_ACCEPTABLE).entity(new Error(CANNOT_PERFORM_OPERATION)) - .build(); - } else { - return Response.status(Response.Status.OK).entity(PolicyEngineConstants.getManager()).build(); - } + return errorResponse(NOT_ACCEPTABLE, CANNOT_PERFORM_OPERATION); } /** @@ -396,11 +378,10 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA @PUT @Path("engine/switches/lock") public Response engineLock() { - final boolean success = PolicyEngineConstants.getManager().lock(); - if (success) { - return Response.status(Status.OK).entity(PolicyEngineConstants.getManager()).build(); + if (PolicyEngineConstants.getManager().lock()) { + return Response.status(OK).entity(PolicyEngineConstants.getManager()).build(); } else { - return Response.status(Status.NOT_ACCEPTABLE).entity(new Error(CANNOT_PERFORM_OPERATION)).build(); + return errorResponse(NOT_ACCEPTABLE, CANNOT_PERFORM_OPERATION); } } @@ -413,11 +394,10 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA @DELETE @Path("engine/switches/lock") public Response engineUnlock() { - final boolean success = PolicyEngineConstants.getManager().unlock(); - if (success) { - return Response.status(Status.OK).entity(PolicyEngineConstants.getManager()).build(); + if (PolicyEngineConstants.getManager().unlock()) { + return Response.status(OK).entity(PolicyEngineConstants.getManager()).build(); } else { - return Response.status(Status.NOT_ACCEPTABLE).entity(new Error(CANNOT_PERFORM_OPERATION)).build(); + return errorResponse(NOT_ACCEPTABLE, CANNOT_PERFORM_OPERATION); } } @@ -430,8 +410,7 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA @GET @Path("engine/controllers") public Response controllers() { - return Response.status(Response.Status.OK).entity(PolicyEngineConstants.getManager().getPolicyControllerIds()) - .build(); + return Response.status(OK).entity(PolicyEngineConstants.getManager().getPolicyControllerIds()).build(); } /** @@ -443,8 +422,7 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA @GET @Path("engine/controllers/inventory") public Response controllerInventory() { - return Response.status(Response.Status.OK).entity(PolicyEngineConstants.getManager().getPolicyControllers()) - .build(); + return Response.status(OK).entity(PolicyEngineConstants.getManager().getPolicyControllers()).build(); } /** @@ -457,54 +435,48 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA @Path("engine/controllers") public Response controllerAdd(Properties config) { if (config == null) { - return Response.status(Response.Status.BAD_REQUEST).entity(new Error("A configuration must be provided")) - .build(); + return errorResponse(BAD_REQUEST, "A configuration must be provided"); } - final String controllerName = config.getProperty(DroolsPropertyConstants.PROPERTY_CONTROLLER_NAME); + var controllerName = config.getProperty(PROPERTY_CONTROLLER_NAME); if (controllerName == null || controllerName.isEmpty()) { - return Response.status(Response.Status.BAD_REQUEST) - .entity(new Error( - "Configuration must have an entry for " + DroolsPropertyConstants.PROPERTY_CONTROLLER_NAME)) - .build(); + return errorResponse(BAD_REQUEST, "Configuration must have an entry for " + + PROPERTY_CONTROLLER_NAME); } PolicyController controller; try { controller = PolicyControllerConstants.getFactory().get(controllerName); if (controller != null) { - return Response.status(Response.Status.NOT_MODIFIED).entity(controller).build(); + return Response.status(NOT_MODIFIED).entity(controller).build(); } } catch (final IllegalArgumentException e) { logger.trace("OK ", e); // This is OK } catch (final IllegalStateException e) { logger.info(FETCH_POLICY_FAILED, this, e.getMessage(), e); - return Response.status(Response.Status.NOT_ACCEPTABLE).entity(new Error(controllerName + NOT_FOUND_MSG)) - .build(); + return errorResponse(NOT_ACCEPTABLE, controllerName + NOT_FOUND_MSG); } try { controller = PolicyEngineConstants.getManager().createPolicyController( - config.getProperty(DroolsPropertyConstants.PROPERTY_CONTROLLER_NAME), config); + config.getProperty(PROPERTY_CONTROLLER_NAME), config); } catch (IllegalArgumentException | IllegalStateException e) { logger.warn("{}: cannot create policy-controller because of {}", this, e.getMessage(), e); - return Response.status(Response.Status.BAD_REQUEST).entity(new Error(e.getMessage())).build(); + return errorResponse(BAD_REQUEST, e.getMessage()); } try { - final boolean success = controller.start(); - if (!success) { + if (!controller.start()) { logger.info("{}: cannot start {}", this, controller); - return Response.status(Response.Status.PARTIAL_CONTENT) - .entity(new Error(controllerName + " can't be started")).build(); + return errorResponse(PARTIAL_CONTENT, controllerName + " can't be started"); } } catch (final IllegalStateException e) { logger.info("{}: cannot start {} because of {}", this, controller, e.getMessage(), e); - return Response.status(Response.Status.PARTIAL_CONTENT).entity(controller).build(); + return Response.status(PARTIAL_CONTENT).entity(controller).build(); } - return Response.status(Response.Status.CREATED).entity(controller).build(); + return Response.status(CREATED).entity(controller).build(); } /** @@ -516,7 +488,7 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA @GET @Path("engine/controllers/features") public Response controllerFeatures() { - return Response.status(Response.Status.OK).entity(PolicyEngineConstants.getManager().getFeatures()).build(); + return Response.status(OK).entity(PolicyEngineConstants.getManager().getFeatures()).build(); } /** @@ -528,8 +500,7 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA @GET @Path("engine/controllers/features/inventory") public Response controllerFeaturesInventory() { - return Response.status(Response.Status.OK) - .entity(PolicyControllerConstants.getFactory().getFeatureProviders()).build(); + return Response.status(OK).entity(PolicyControllerConstants.getFactory().getFeatureProviders()).build(); } /** @@ -542,12 +513,11 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA @Path("engine/controllers/features/{featureName}") public Response controllerFeature(@PathParam("featureName") String featureName) { try { - return Response.status(Response.Status.OK) - .entity(PolicyControllerConstants.getFactory().getFeatureProvider(featureName)) + return Response.status(OK).entity(PolicyControllerConstants.getFactory().getFeatureProvider(featureName)) .build(); } catch (final IllegalArgumentException iae) { logger.debug("{}: cannot feature {} because of {}", this, featureName, iae.getMessage(), iae); - return Response.status(Response.Status.NOT_FOUND).entity(new Error(iae.getMessage())).build(); + return errorResponse(NOT_FOUND, iae.getMessage()); } } @@ -562,8 +532,7 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA public Response controller(@PathParam("controller") String controllerName) { return catchArgStateGenericEx( - () -> Response.status(Response.Status.OK) - .entity(PolicyControllerConstants.getFactory().get(controllerName)).build(), + () -> Response.status(OK).entity(PolicyControllerConstants.getFactory().get(controllerName)).build(), e -> { logger.debug(FETCH_POLICY_BY_NAME_FAILED, this, controllerName, e.getMessage(), e); return (controllerName); @@ -584,28 +553,25 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA try { controller = PolicyControllerConstants.getFactory().get(controllerName); if (controller == null) { - return Response.status(Response.Status.BAD_REQUEST) - .entity(new Error(controllerName + DOES_NOT_EXIST_MSG)).build(); + return errorResponse(BAD_REQUEST, controllerName + DOES_NOT_EXIST_MSG); } } catch (final IllegalArgumentException e) { logger.debug(FETCH_POLICY_BY_NAME_FAILED, this, controllerName, e.getMessage(), e); - return Response.status(Response.Status.BAD_REQUEST) - .entity(new Error(controllerName + NOT_FOUND + e.getMessage())).build(); + return errorResponse(BAD_REQUEST, controllerName + NOT_FOUND_MSG + ": " + e.getMessage()); } catch (final IllegalStateException e) { logger.debug(FETCH_POLICY_BY_NAME_FAILED, this, controllerName, e.getMessage(), e); - return Response.status(Response.Status.NOT_ACCEPTABLE) - .entity(new Error(controllerName + NOT_ACCEPTABLE_MSG)).build(); + return errorResponse(NOT_ACCEPTABLE, controllerName + NOT_ACCEPTABLE_MSG); } try { PolicyEngineConstants.getManager().removePolicyController(controllerName); } catch (IllegalArgumentException | IllegalStateException e) { - logger.debug("{}: cannot remove policy-controller {} because of {}", this, controllerName, e.getMessage(), - e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(new Error(e.getMessage())).build(); + logger.debug("{}: cannot remove policy-controller {} because of {}", + this, controllerName, e.getMessage(), e); + return errorResponse(INTERNAL_SERVER_ERROR, e.getMessage()); } - return Response.status(Response.Status.OK).entity(controller).build(); + return Response.status(OK).entity(controller).build(); } /** @@ -620,8 +586,8 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA public Response controllerProperties(@PathParam("controller") String controllerName) { return catchArgStateGenericEx(() -> { - final PolicyController controller = PolicyControllerConstants.getFactory().get(controllerName); - return Response.status(Response.Status.OK).entity(controller.getProperties()).build(); + var controller = PolicyControllerConstants.getFactory().get(controllerName); + return Response.status(OK).entity(controller.getProperties()).build(); }, e -> { logger.debug(FETCH_POLICY_BY_NAME_FAILED, this, controllerName, e.getMessage(), e); @@ -638,7 +604,7 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA @GET @Path("engine/controllers/{controller}/inputs") public Response controllerInputs(@PathParam("controller") String controllerName) { - return Response.status(Response.Status.OK).entity(INPUTS).build(); + return Response.status(OK).entity(INPUTS).build(); } /** @@ -650,27 +616,25 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA @POST @Path("engine/controllers/{controller}/inputs/configuration") public Response controllerUpdate(ControllerConfiguration controllerConfiguration, - @PathParam("controller") String controllerName) { + @PathParam("controller") String controllerName) { - if (controllerName == null || controllerName.isEmpty() || controllerConfiguration == null + if (StringUtils.isBlank(controllerName) || controllerConfiguration == null || !controllerName.equals(controllerConfiguration.getName())) { - return Response.status(Response.Status.BAD_REQUEST) + return Response.status(BAD_REQUEST) .entity("A valid or matching controller names must be provided").build(); } return catchArgStateGenericEx(() -> { - var controller = - PolicyEngineConstants.getManager().updatePolicyController(controllerConfiguration); + var controller = PolicyEngineConstants.getManager().updatePolicyController(controllerConfiguration); if (controller == null) { - return Response.status(Response.Status.BAD_REQUEST) - .entity(new Error(controllerName + DOES_NOT_EXIST_MSG)).build(); + return errorResponse(BAD_REQUEST, controllerName + DOES_NOT_EXIST_MSG); } - return Response.status(Response.Status.OK).entity(controller).build(); + return Response.status(OK).entity(controller).build(); }, e -> { - logger.info("{}: cannot update policy-controller {} because of {}", this, controllerName, - e.getMessage(), e); + logger.info("{}: cannot update policy-controller {} because of {}", + this, controllerName, e.getMessage(), e); return (controllerName); }); } @@ -684,7 +648,7 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA @GET @Path("engine/controllers/{controller}/switches") public Response controllerSwitches(@PathParam("controller") String controllerName) { - return Response.status(Response.Status.OK).entity(SWITCHES).build(); + return Response.status(OK).entity(SWITCHES).build(); } /** @@ -697,12 +661,10 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA @Path("engine/controllers/{controller}/switches/lock") public Response controllerLock(@PathParam("controller") String controllerName) { var policyController = PolicyControllerConstants.getFactory().get(controllerName); - final boolean success = policyController.lock(); - if (success) { - return Response.status(Status.OK).entity(policyController).build(); + if (policyController.lock()) { + return Response.status(OK).entity(policyController).build(); } else { - return Response.status(Status.NOT_ACCEPTABLE) - .entity(new Error("Controller " + controllerName + " cannot be locked")).build(); + return errorResponse(NOT_ACCEPTABLE, "Controller " + controllerName + " cannot be locked"); } } @@ -718,10 +680,9 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA var policyController = PolicyControllerConstants.getFactory().get(controllerName); final boolean success = policyController.unlock(); if (success) { - return Response.status(Status.OK).entity(policyController).build(); + return Response.status(OK).entity(policyController).build(); } else { - return Response.status(Status.NOT_ACCEPTABLE) - .entity(new Error("Controller " + controllerName + " cannot be unlocked")).build(); + return errorResponse(NOT_ACCEPTABLE, "Controller " + controllerName + " cannot be unlocked"); } } @@ -737,7 +698,7 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA return catchArgStateGenericEx(() -> { var drools = this.getDroolsController(controllerName); - return Response.status(Response.Status.OK).entity(drools).build(); + return Response.status(OK).entity(drools).build(); }, e -> { logger.debug(FETCH_DROOLS_FAILED, this, controllerName, e.getMessage(), e); @@ -778,7 +739,7 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA @GET @Path("engine/controllers/{controller}/drools/facts/{session}") public Response droolsFacts1(@PathParam("controller") String controllerName, - @PathParam("session") String sessionName) { + @PathParam("session") String sessionName) { return catchArgStateGenericEx(() -> { var drools = this.getDroolsController(controllerName); @@ -917,8 +878,8 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA }, e -> { logger.debug(FETCH_DROOLS_BY_PARAMS_FAILED, - this, controllerName, sessionName, queryName, queriedEntity, e.getMessage(), e); - return (controllerName + ":" + sessionName + ":" + queryName + queriedEntity); + this, controllerName, sessionName, queryName, queriedEntity, e.getMessage(), e.toString()); + return (controllerName + ":" + sessionName + ":" + queryName + ":" + queriedEntity); }); } @@ -931,7 +892,7 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA @POST @Path("engine/controllers/tools/coders/decoders/filters/rule") public Response rules(String expression) { - return Response.status(Status.OK).entity(new JsonProtocolFilter(expression)).build(); + return Response.status(OK).entity(new JsonProtocolFilter(expression)).build(); } /** @@ -949,8 +910,7 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA return EventProtocolCoderConstants.getManager().getDecoders(drools.getGroupId(), drools.getArtifactId()); }, e -> { - logger.debug(FETCH_DECODERS_BY_POLICY_FAILED, this, controllerName, - e.getMessage(), e); + logger.debug(FETCH_DECODERS_BY_POLICY_FAILED, this, controllerName, e.getMessage(), e); return (controllerName); }); } @@ -1013,11 +973,10 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA return catchArgStateGenericEx(() -> { var drools = this.getDroolsController(controllerName); - final ProtocolCoderToolset decoder = EventProtocolCoderConstants.getManager() + var decoder = EventProtocolCoderConstants.getManager() .getDecoders(drools.getGroupId(), drools.getArtifactId(), topic); if (decoder == null) { - return Response.status(Response.Status.BAD_REQUEST).entity(new Error(topic + DOES_NOT_EXIST_MSG)) - .build(); + return errorResponse(BAD_REQUEST, topic + DOES_NOT_EXIST_MSG); } else { return decoder.getCoders(); } @@ -1043,19 +1002,17 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA return catchArgStateGenericEx(() -> { var drools = this.getDroolsController(controllerName); - final ProtocolCoderToolset decoder = EventProtocolCoderConstants.getManager() + var decoder = EventProtocolCoderConstants.getManager() .getDecoders(drools.getGroupId(), drools.getArtifactId(), topic); - final CoderFilters filters = decoder.getCoder(factClass); + var filters = decoder.getCoder(factClass); if (filters == null) { - return Response.status(Response.Status.BAD_REQUEST) - .entity(new Error(topic + ":" + factClass + DOES_NOT_EXIST_MSG)).build(); + return errorResponse(BAD_REQUEST, topic + ":" + factClass + DOES_NOT_EXIST_MSG); } else { return filters; } }, e -> { - logger.debug(FETCH_DECODER_BY_TYPE_FAILED, this, - controllerName, topic, factClass, e.getMessage(), e); + logger.debug(FETCH_DECODER_BY_TYPE_FAILED, this, controllerName, topic, factClass, e.getMessage(), e); return (controllerName + ":" + topic + ":" + factClass); }); } @@ -1069,24 +1026,22 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA @PUT @Path("engine/controllers/{controller}/decoders/{topic}/filters/{factType}") public Response decoderFilter( - JsonProtocolFilter configFilters, - @PathParam("controller") String controllerName, - @PathParam("topic") String topic, - @PathParam("factType") String factClass) { + JsonProtocolFilter configFilters, + @PathParam("controller") String controllerName, + @PathParam("topic") String topic, + @PathParam("factType") String factClass) { if (configFilters == null) { - return Response.status(Response.Status.BAD_REQUEST).entity(new Error("Configuration Filters not provided")) - .build(); + return errorResponse(BAD_REQUEST, "Configuration Filters not provided"); } return catchArgStateGenericEx(() -> { var drools = this.getDroolsController(controllerName); - final ProtocolCoderToolset decoder = EventProtocolCoderConstants.getManager() + var decoder = EventProtocolCoderConstants.getManager() .getDecoders(drools.getGroupId(), drools.getArtifactId(), topic); - final CoderFilters filters = decoder.getCoder(factClass); + var filters = decoder.getCoder(factClass); if (filters == null) { - return Response.status(Response.Status.BAD_REQUEST) - .entity(new Error(topic + ":" + factClass + DOES_NOT_EXIST_MSG)).build(); + return errorResponse(BAD_REQUEST, topic + ":" + factClass + DOES_NOT_EXIST_MSG); } filters.setFilter(configFilters); return filters; @@ -1112,24 +1067,14 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA @PathParam("factType") String factClass) { return catchArgStateGenericEx(() -> { - var drools = this.getDroolsController(controllerName); - final ProtocolCoderToolset decoder = EventProtocolCoderConstants.getManager() - .getDecoders(drools.getGroupId(), drools.getArtifactId(), topic); - - final CoderFilters filters = decoder.getCoder(factClass); - if (filters == null) { - return Response.status(Response.Status.BAD_REQUEST) - .entity(new Error(controllerName + ":" + topic + ":" + factClass + DOES_NOT_EXIST_MSG)).build(); - } + var result = this.checkControllerDecoderAndFilter(controllerName, topic, factClass); - final JsonProtocolFilter filter = filters.getFilter(); - if (filter == null) { - return Response.status(Response.Status.BAD_REQUEST) - .entity(new Error(controllerName + ":" + topic + ":" + factClass + NO_FILTERS)).build(); + if (result instanceof Response) { + return result; + } else { + var filter = (JsonProtocolFilter) result; + return filter.getRule(); } - - return filter.getRule(); - }, e -> { logger.debug(FETCH_DECODER_BY_TYPE_FAILED, this, controllerName, topic, factClass, e.getMessage(), e); @@ -1151,25 +1096,17 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA @PathParam("factType") String factClass) { return catchArgStateGenericEx(() -> { - var drools = this.getDroolsController(controllerName); - final ProtocolCoderToolset decoder = EventProtocolCoderConstants.getManager() - .getDecoders(drools.getGroupId(), drools.getArtifactId(), topic); + var result = this.checkControllerDecoderAndFilter(controllerName, topic, factClass); - final CoderFilters filters = decoder.getCoder(factClass); - if (filters == null) { - return Response.status(Response.Status.BAD_REQUEST) - .entity(new Error(controllerName + ":" + topic + ":" + factClass + DOES_NOT_EXIST_MSG)).build(); - } + if (result instanceof Response) { + return result; + } else { + var filter = (JsonProtocolFilter) result; - final JsonProtocolFilter filter = filters.getFilter(); - if (filter == null) { - return Response.status(Response.Status.BAD_REQUEST) - .entity(new Error(controllerName + ":" + topic + ":" + factClass + NO_FILTERS)).build(); + filter.setRule(null); + return filter.getRule(); } - filter.setRule(null); - return filter.getRule(); - }, e -> { logger.debug(FETCH_DECODER_BY_TYPE_FAILED, this, controllerName, topic, factClass, e.getMessage(), e); @@ -1193,38 +1130,12 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA return catchArgStateGenericEx(() -> decoderFilterRule2(controllerName, topic, factClass, rule), e -> { logger.debug("{}: cannot access decoder filter rules for policy-controller {} " - + "topic {} type {} because of {}", + + "topic {} type {} because of {}", this, controllerName, topic, factClass, e.getMessage(), e); return (controllerName + ":" + topic + ":" + factClass); }); } - private Object decoderFilterRule2(String controllerName, String topic, String factClass, String rule) { - var drools = this.getDroolsController(controllerName); - final ProtocolCoderToolset decoder = EventProtocolCoderConstants.getManager() - .getDecoders(drools.getGroupId(), drools.getArtifactId(), topic); - - final CoderFilters filters = decoder.getCoder(factClass); - if (filters == null) { - return Response.status(Response.Status.BAD_REQUEST) - .entity(new Error(controllerName + ":" + topic + ":" + factClass + DOES_NOT_EXIST_MSG)).build(); - } - - final JsonProtocolFilter filter = filters.getFilter(); - if (filter == null) { - return Response.status(Response.Status.BAD_REQUEST) - .entity(new Error(controllerName + ":" + topic + ":" + factClass + NO_FILTERS)).build(); - } - - if (rule == null || rule.isEmpty()) { - return Response.status(Response.Status.BAD_REQUEST).entity(new Error(controllerName + ":" + topic + ":" - + factClass + " no filter rule provided")).build(); - } - - filter.setRule(rule); - return filter.getRule(); - } - /** * POST. * @@ -1239,30 +1150,15 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA @PathParam("topic") String topic, String json) { - if (!checkValidNameInput(controllerName)) { - return Response.status(Response.Status.NOT_ACCEPTABLE) - .entity(new Error("controllerName contains whitespaces " + NOT_ACCEPTABLE_MSG)).build(); + if (StringUtils.isBlank(controllerName)) { + return errorResponse(NOT_ACCEPTABLE, "controllerName contains whitespaces " + NOT_ACCEPTABLE_MSG); } - if (!checkValidNameInput(topic)) { - return Response.status(Response.Status.NOT_ACCEPTABLE) - .entity(new Error("topic contains whitespaces " + NOT_ACCEPTABLE_MSG)).build(); + if (StringUtils.isBlank(topic)) { + return errorResponse(NOT_ACCEPTABLE, "topic contains whitespaces " + NOT_ACCEPTABLE_MSG); } - PolicyController policyController; - try { - policyController = PolicyControllerConstants.getFactory().get(controllerName); - } catch (final IllegalArgumentException e) { - logger.debug(FETCH_DECODERS_BY_TOPIC_FAILED, this, - controllerName, topic, e.getMessage(), e); - return Response.status(Response.Status.NOT_FOUND) - .entity(new Error(controllerName + ":" + topic + ":" + NOT_FOUND_MSG)).build(); - } catch (final IllegalStateException e) { - logger.debug(FETCH_DECODERS_BY_TOPIC_FAILED, this, - controllerName, topic, e.getMessage(), e); - return Response.status(Response.Status.NOT_ACCEPTABLE) - .entity(new Error(controllerName + ":" + topic + ":" + NOT_ACCEPTABLE_MSG)).build(); - } + var drools = getDroolsController(controllerName); var result = new CodingResult(); result.setDecoding(false); @@ -1271,25 +1167,24 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA Object event; try { - event = EventProtocolCoderConstants.getManager().decode(policyController.getDrools().getGroupId(), - policyController.getDrools().getArtifactId(), topic, json); + event = EventProtocolCoderConstants.getManager() + .decode(drools.getGroupId(), drools.getArtifactId(), topic, json); result.setDecoding(true); } catch (final Exception e) { - logger.debug(FETCH_POLICY_BY_TOPIC_FAILED, this, controllerName, topic, - e.getMessage(), e); - return Response.status(Response.Status.BAD_REQUEST).entity(new Error(e.getMessage())).build(); + logger.debug(FETCH_POLICY_BY_TOPIC_FAILED, this, controllerName, topic, e.getMessage(), e); + return errorResponse(BAD_REQUEST, e.getMessage()); } try { result.setJsonEncoding(EventProtocolCoderConstants.getManager().encode(topic, event)); result.setEncoding(true); } catch (final Exception e) { - // continue so to propagate decoding results .. - logger.debug("{}: cannot encode for policy-controller {} topic {} because of {}", this, controllerName, - topic, e.getMessage(), e); + // continue so to propagate decoding results ... + logger.debug("{}: cannot encode for policy-controller {} topic {} because of {}", + this, controllerName, topic, e.getMessage(), e); } - return Response.status(Response.Status.OK).entity(result).build(); + return Response.status(OK).entity(result).build(); } /** @@ -1303,14 +1198,12 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA public Response encoderFilters(@PathParam("controller") String controllerName) { return catchArgStateGenericEx(() -> { - final PolicyController controller = PolicyControllerConstants.getFactory().get(controllerName); - var drools = controller.getDrools(); + var drools = getDroolsController(controllerName); return EventProtocolCoderConstants.getManager() .getEncoderFilters(drools.getGroupId(), drools.getArtifactId()); }, e -> { - logger.debug(FETCH_ENCODER_BY_FILTER_FAILED, this, controllerName, - e.getMessage(), e); + logger.debug(FETCH_ENCODER_BY_FILTER_FAILED, this, controllerName, e.getMessage(), e); return (controllerName); }); } @@ -1319,14 +1212,14 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA @GET @Path("engine/topics") public Response topics() { - return Response.status(Response.Status.OK).entity(TopicEndpointManager.getManager()).build(); + return Response.status(OK).entity(TopicEndpointManager.getManager()).build(); } @Override @GET @Path("engine/topics/switches") public Response topicSwitches() { - return Response.status(Response.Status.OK).entity(SWITCHES).build(); + return Response.status(OK).entity(SWITCHES).build(); } /** @@ -1338,11 +1231,10 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA @PUT @Path("engine/topics/switches/lock") public Response topicsLock() { - final boolean success = TopicEndpointManager.getManager().lock(); - if (success) { - return Response.status(Status.OK).entity(TopicEndpointManager.getManager()).build(); + if (TopicEndpointManager.getManager().lock()) { + return Response.status(OK).entity(TopicEndpointManager.getManager()).build(); } else { - return Response.status(Status.NOT_ACCEPTABLE).entity(new Error(CANNOT_PERFORM_OPERATION)).build(); + return errorResponse(NOT_ACCEPTABLE, CANNOT_PERFORM_OPERATION); } } @@ -1355,11 +1247,10 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA @DELETE @Path("engine/topics/switches/lock") public Response topicsUnlock() { - final boolean success = TopicEndpointManager.getManager().unlock(); - if (success) { - return Response.status(Status.OK).entity(TopicEndpointManager.getManager()).build(); + if (TopicEndpointManager.getManager().unlock()) { + return Response.status(OK).entity(TopicEndpointManager.getManager()).build(); } else { - return Response.status(Status.NOT_ACCEPTABLE).entity(new Error(CANNOT_PERFORM_OPERATION)).build(); + return errorResponse(NOT_ACCEPTABLE, CANNOT_PERFORM_OPERATION); } } @@ -1372,7 +1263,7 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA @GET @Path("engine/topics/sources") public Response sources() { - return Response.status(Response.Status.OK).entity(TopicEndpointManager.getManager().getTopicSources()).build(); + return Response.status(OK).entity(TopicEndpointManager.getManager().getTopicSources()).build(); } /** @@ -1384,7 +1275,7 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA @GET @Path("engine/topics/sinks") public Response sinks() { - return Response.status(Response.Status.OK).entity(TopicEndpointManager.getManager().getTopicSinks()).build(); + return Response.status(OK).entity(TopicEndpointManager.getManager().getTopicSinks()).build(); } /** @@ -1395,15 +1286,13 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA @Path("engine/topics/sources/{comm: kafka|noop}") public Response commSources( @PathParam("comm") String comm) { - if (!checkValidNameInput(comm)) { - return Response - .status(Response.Status.NOT_ACCEPTABLE) - .entity(new Error("source communication mechanism contains whitespaces " + NOT_ACCEPTABLE_MSG)) - .build(); + if (StringUtils.isBlank(comm)) { + return errorResponse(NOT_ACCEPTABLE, + "source communication mechanism contains whitespaces " + NOT_ACCEPTABLE_MSG); } List<TopicSource> sources = new ArrayList<>(); - var status = Status.OK; + var status = OK; switch (CommInfrastructure.valueOf(comm.toUpperCase())) { case NOOP: sources.addAll(TopicEndpointManager.getManager().getNoopTopicSources()); @@ -1412,8 +1301,8 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA sources.addAll(TopicEndpointManager.getManager().getKafkaTopicSources()); break; default: - status = Status.BAD_REQUEST; - logger.debug("Invalid communication mechanism"); + status = BAD_REQUEST; + logger.debug("{} is invalid communication mechanism", comm); break; } return Response.status(status).entity(sources).build(); @@ -1427,15 +1316,13 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA @Path("engine/topics/sinks/{comm: kafka|noop}") public Response commSinks( @PathParam("comm") String comm) { - if (!checkValidNameInput(comm)) { - return Response - .status(Response.Status.NOT_ACCEPTABLE) - .entity(new Error("sink communication mechanism contains whitespaces " + NOT_ACCEPTABLE_MSG)) - .build(); + if (StringUtils.isBlank(comm)) { + return errorResponse(NOT_ACCEPTABLE, + "sink communication mechanism contains whitespaces " + NOT_ACCEPTABLE_MSG); } List<TopicSink> sinks = new ArrayList<>(); - var status = Status.OK; + var status = OK; switch (CommInfrastructure.valueOf(comm.toUpperCase())) { case NOOP: sinks.addAll(TopicEndpointManager.getManager().getNoopTopicSinks()); @@ -1444,8 +1331,8 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA sinks.addAll(TopicEndpointManager.getManager().getKafkaTopicSinks()); break; default: - status = Status.BAD_REQUEST; - logger.debug("Invalid communication mechanism"); + status = BAD_REQUEST; + logger.debug("{} is invalid communication mechanism", comm); break; } return Response.status(status).entity(sinks).build(); @@ -1460,11 +1347,9 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA public Response sourceTopic( @PathParam("comm") String comm, @PathParam("topic") String topic) { - return Response - .status(Response.Status.OK) - .entity(TopicEndpointManager.getManager() - .getTopicSource(CommInfrastructure.valueOf(comm.toUpperCase()), topic)) - .build(); + var source = TopicEndpointManager.getManager() + .getTopicSource(CommInfrastructure.valueOf(comm.toUpperCase()), topic); + return Response.status(OK).entity(source).build(); } /** @@ -1476,11 +1361,9 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA public Response sinkTopic( @PathParam("comm") String comm, @PathParam("topic") String topic) { - return Response - .status(Response.Status.OK) - .entity(TopicEndpointManager.getManager() - .getTopicSink(CommInfrastructure.valueOf(comm.toUpperCase()), topic)) - .build(); + var sink = TopicEndpointManager.getManager() + .getTopicSink(CommInfrastructure.valueOf(comm.toUpperCase()), topic); + return Response.status(OK).entity(sink).build(); } /** @@ -1492,11 +1375,9 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA public Response sourceEvents( @PathParam("comm") String comm, @PathParam("topic") String topic) { - return Response.status(Status.OK) - .entity(Arrays.asList(TopicEndpointManager.getManager() - .getTopicSource(CommInfrastructure.valueOf(comm.toUpperCase()), topic) - .getRecentEvents())) - .build(); + var source = TopicEndpointManager.getManager() + .getTopicSource(CommInfrastructure.valueOf(comm.toUpperCase()), topic); + return Response.status(OK).entity(Arrays.asList(source.getRecentEvents())).build(); } /** @@ -1508,11 +1389,9 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA public Response sinkEvents( @PathParam("comm") String comm, @PathParam("topic") String topic) { - return Response.status(Status.OK) - .entity(Arrays.asList(TopicEndpointManager.getManager() - .getTopicSink(CommInfrastructure.valueOf(comm.toUpperCase()), topic) - .getRecentEvents())) - .build(); + var sink = TopicEndpointManager.getManager() + .getTopicSink(CommInfrastructure.valueOf(comm.toUpperCase()), topic); + return Response.status(OK).entity(Arrays.asList(sink.getRecentEvents())).build(); } /** @@ -1524,7 +1403,7 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA public Response commSourceTopicSwitches( @PathParam("comm") String comm, @PathParam("topic") String topic) { - return Response.status(Response.Status.OK).entity(SWITCHES).build(); + return Response.status(OK).entity(SWITCHES).build(); } /** @@ -1536,7 +1415,7 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA public Response commSinkTopicSwitches( @PathParam("comm") String comm, @PathParam("topic") String topic) { - return Response.status(Response.Status.OK).entity(SWITCHES).build(); + return Response.status(OK).entity(SWITCHES).build(); } /** @@ -1548,13 +1427,13 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA public Response commSourceTopicLock( @PathParam("comm") String comm, @PathParam("topic") String topic) { - var source = - TopicEndpointManager.getManager().getTopicSource(CommInfrastructure.valueOf(comm.toUpperCase()), topic); + var source = TopicEndpointManager.getManager() + .getTopicSource(CommInfrastructure.valueOf(comm.toUpperCase()), topic); return getResponse(topic, source.lock(), source); } /** - * DELETEs the lock on a topic. + * Deletes the lock on a topic. */ @Override @DELETE @@ -1562,8 +1441,8 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA public Response commSourceTopicUnlock( @PathParam("comm") String comm, @PathParam("topic") String topic) { - var source = - TopicEndpointManager.getManager().getTopicSource(CommInfrastructure.valueOf(comm.toUpperCase()), topic); + var source = TopicEndpointManager.getManager() + .getTopicSource(CommInfrastructure.valueOf(comm.toUpperCase()), topic); return getResponse(topic, source.unlock(), source); } @@ -1576,8 +1455,8 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA public Response commSourceTopicActivation( @PathParam("comm") String comm, @PathParam("topic") String topic) { - var source = - TopicEndpointManager.getManager().getTopicSource(CommInfrastructure.valueOf(comm.toUpperCase()), topic); + var source = TopicEndpointManager.getManager() + .getTopicSource(CommInfrastructure.valueOf(comm.toUpperCase()), topic); return getResponse(topic, source.start(), source); } @@ -1590,8 +1469,8 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA public Response commSourceTopicDeactivation( @PathParam("comm") String comm, @PathParam("topic") String topic) { - var source = - TopicEndpointManager.getManager().getTopicSource(CommInfrastructure.valueOf(comm.toUpperCase()), topic); + var source = TopicEndpointManager.getManager() + .getTopicSource(CommInfrastructure.valueOf(comm.toUpperCase()), topic); return getResponse(topic, source.stop(), source); } @@ -1604,13 +1483,13 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA public Response commSinkTopicLock( @PathParam("comm") String comm, @PathParam("topic") String topic) { - var sink = - TopicEndpointManager.getManager().getTopicSink(CommInfrastructure.valueOf(comm.toUpperCase()), topic); + var sink = TopicEndpointManager.getManager() + .getTopicSink(CommInfrastructure.valueOf(comm.toUpperCase()), topic); return getResponse(topic, sink.lock(), sink); } /** - * DELETEs the lock on a topic. + * Deletes the lock on a topic. */ @Override @DELETE @@ -1618,8 +1497,8 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA public Response commSinkTopicUnlock( @PathParam("comm") String comm, @PathParam("topic") String topic) { - var sink = - TopicEndpointManager.getManager().getTopicSink(CommInfrastructure.valueOf(comm.toUpperCase()), topic); + var sink = TopicEndpointManager.getManager() + .getTopicSink(CommInfrastructure.valueOf(comm.toUpperCase()), topic); return getResponse(topic, sink.unlock(), sink); } @@ -1632,8 +1511,8 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA public Response commSinkTopicActivation( @PathParam("comm") String comm, @PathParam("topic") String topic) { - var sink = - TopicEndpointManager.getManager().getTopicSink(CommInfrastructure.valueOf(comm.toUpperCase()), topic); + var sink = TopicEndpointManager.getManager() + .getTopicSink(CommInfrastructure.valueOf(comm.toUpperCase()), topic); return getResponse(topic, sink.start(), sink); } @@ -1646,23 +1525,11 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA public Response commSinkTopicDeactivation( @PathParam("comm") String comm, @PathParam("topic") String topic) { - var sink = - TopicEndpointManager.getManager().getTopicSink(CommInfrastructure.valueOf(comm.toUpperCase()), topic); + var sink = TopicEndpointManager.getManager() + .getTopicSink(CommInfrastructure.valueOf(comm.toUpperCase()), topic); return getResponse(topic, sink.stop(), sink); } - private Response getResponse(String topicName, boolean success, Topic topic) { - if (success) { - return Response.status(Status.OK).entity(topic).build(); - } else { - return Response.status(Status.NOT_ACCEPTABLE).entity(makeTopicOperError(topicName)).build(); - } - } - - private Error makeTopicOperError(String topic) { - return new Error("cannot perform operation on " + topic); - } - /** * Offers an event to a topic in a communication infrastructure. * @@ -1683,8 +1550,7 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA if (source.offer(json)) { return Arrays.asList(source.getRecentEvents()); } else { - return Response.status(Status.NOT_ACCEPTABLE).entity(new Error("Failure to inject event over " + topic)) - .build(); + return errorResponse(NOT_ACCEPTABLE, "Failure to inject event over " + topic); } }, e -> { @@ -1703,7 +1569,7 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA @Path("engine/tools/uuid") @Produces(MediaType.TEXT_PLAIN) public Response uuid() { - return Response.status(Status.OK).entity(UUID.randomUUID().toString()).build(); + return Response.status(OK).entity(UUID.randomUUID().toString()).build(); } /** @@ -1716,17 +1582,16 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA @Path("engine/tools/loggers") public Response loggers() { final List<String> names = new ArrayList<>(); - if (!(LoggerFactory.getILoggerFactory() instanceof LoggerContext)) { - logger.warn("The SLF4J logger factory is not configured for logback"); - return Response.status(Status.INTERNAL_SERVER_ERROR).entity(names).build(); + if (checkLoggerFactoryInstance()) { + return Response.status(INTERNAL_SERVER_ERROR).entity(names).build(); } - final LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); + var context = (LoggerContext) LoggerFactory.getILoggerFactory(); for (final Logger lgr : context.getLoggerList()) { names.add(lgr.getName()); } - return Response.status(Status.OK).entity(names).build(); + return Response.status(OK).entity(names).build(); } /** @@ -1739,19 +1604,18 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA @Path("engine/tools/loggers/{logger}") @Produces(MediaType.TEXT_PLAIN) public Response loggerName1(@PathParam("logger") String loggerName) { - if (!(LoggerFactory.getILoggerFactory() instanceof LoggerContext)) { - logger.warn("The SLF4J logger factory is not configured for logback"); - return Response.status(Status.INTERNAL_SERVER_ERROR).build(); + if (checkLoggerFactoryInstance()) { + return Response.status(INTERNAL_SERVER_ERROR).build(); } - final LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); + var context = (LoggerContext) LoggerFactory.getILoggerFactory(); var lgr = context.getLogger(loggerName); if (lgr == null) { - return Response.status(Status.NOT_FOUND).build(); + return Response.status(NOT_FOUND).build(); } final String loggerLevel = (lgr.getLevel() != null) ? lgr.getLevel().toString() : ""; - return Response.status(Status.OK).entity(loggerLevel).build(); + return Response.status(OK).entity(loggerLevel).build(); } /** @@ -1768,28 +1632,28 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA String newLevel; try { - if (!checkValidNameInput(loggerName)) { - return Response.status(Response.Status.NOT_ACCEPTABLE) - .entity(new Error("logger name: " + NOT_ACCEPTABLE_MSG)) - .build(); + if (StringUtils.isBlank(loggerName)) { + return errorResponse(NOT_ACCEPTABLE, "logger name:" + NOT_ACCEPTABLE_MSG); } if (!Pattern.matches("^[a-zA-Z]{3,5}$", loggerLevel)) { - return Response.status(Response.Status.NOT_ACCEPTABLE) - .entity(new Error("logger level: " + NOT_ACCEPTABLE_MSG)) - .build(); + return errorResponse(NOT_ACCEPTABLE, "logger level:" + NOT_ACCEPTABLE_MSG); } newLevel = LoggerUtils.setLevel(loggerName, loggerLevel); - } catch (final IllegalArgumentException e) { - logger.warn("{}: invalid operation for logger {} and level {}", this, loggerName, loggerLevel, e); - return Response.status(Status.NOT_FOUND).build(); - } catch (final IllegalStateException e) { + } catch (Exception e) { logger.warn("{}: logging framework unavailable for {} / {}", this, loggerName, loggerLevel, e); - return Response.status(Status.INTERNAL_SERVER_ERROR).build(); + return Response.status(INTERNAL_SERVER_ERROR).build(); } - return Response.status(Status.OK).entity(newLevel + return Response.status(OK).entity(newLevel).build(); + } - ).build(); + protected String getSwaggerContents() { + try (InputStream inputStream = getClass().getResourceAsStream(SWAGGER); + BufferedReader reader = new BufferedReader(new InputStreamReader(Objects.requireNonNull(inputStream)))) { + return reader.lines().collect(Collectors.joining(System.lineSeparator())); + } catch (IOException e) { + throw new PolicyDroolsPdpRuntimeException("Cannot read swagger.json", e); + } } /** @@ -1800,7 +1664,7 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA * @throws IllegalArgumentException if an invalid controller name has been passed in */ protected DroolsController getDroolsController(String controllerName) { - final PolicyController controller = PolicyControllerConstants.getFactory().get(controllerName); + var controller = PolicyControllerConstants.getFactory().get(controllerName); if (controller == null) { throw new IllegalArgumentException(controllerName + DOES_NOT_EXIST_MSG); } @@ -1818,37 +1682,88 @@ public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsA * illegal state, and generic runtime exceptions. * * @param responder function that will generate a response. If it returns a "Response" - * object, then that object is returned as-is. Otherwise, this method will - * return an "OK" Response, using the function's return value as the "entity" - * @param errorMsg function that will generate an error message prefix to be included - * in responses generated as a result of catching an exception + * object, then that object is returned as-is. Otherwise, this method will + * return an "OK" Response, using the function's return value as the "entity" + * @param errorMsg function that will generate an error message prefix to be included + * in responses generated as a result of catching an exception * @return a response */ - private Response catchArgStateGenericEx(Supplier<Object> responder, Function<Exception, String> errorMsg) { + protected Response catchArgStateGenericEx(Supplier<Object> responder, Function<Exception, String> errorMsg) { try { Object result = responder.get(); if (result instanceof Response) { return (Response) result; } - return Response.status(Response.Status.OK).entity(result).build(); + return Response.status(OK).entity(result).build(); } catch (final IllegalArgumentException e) { - return Response.status(Response.Status.NOT_FOUND).entity(new Error(errorMsg.apply(e) + NOT_FOUND_MSG)) - .build(); + return errorResponse(NOT_FOUND, errorMsg.apply(e) + NOT_FOUND_MSG); } catch (final IllegalStateException e) { - return Response.status(Response.Status.NOT_ACCEPTABLE) - .entity(new Error(errorMsg.apply(e) + NOT_ACCEPTABLE_MSG)).build(); + return errorResponse(NOT_ACCEPTABLE, errorMsg.apply(e) + NOT_ACCEPTABLE_MSG); } catch (final RuntimeException e) { errorMsg.apply(e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(new Error(e.getMessage())).build(); + return errorResponse(INTERNAL_SERVER_ERROR, e.getMessage()); + } + } + + protected Object decoderFilterRule2(String controllerName, String topic, String factClass, String rule) { + if (StringUtils.isBlank(rule)) { + var error = controllerName + ":" + topic + ":" + factClass + " no filter rule provided"; + return errorResponse(BAD_REQUEST, error); + } + + var result = this.checkControllerDecoderAndFilter(controllerName, topic, factClass); + + if (result instanceof Response) { + return result; + } else { + var filter = (JsonProtocolFilter) result; + filter.setRule(rule); + return filter.getRule(); + } + } + + protected Object checkControllerDecoderAndFilter(String controllerName, String topic, String factClass) { + var drools = this.getDroolsController(controllerName); + var decoder = EventProtocolCoderConstants.getManager() + .getDecoders(drools.getGroupId(), drools.getArtifactId(), topic); + + var filters = decoder.getCoder(factClass); + if (filters == null) { + var error = controllerName + ":" + topic + ":" + factClass + DOES_NOT_EXIST_MSG; + return errorResponse(BAD_REQUEST, error); + } + + var filter = filters.getFilter(); + if (filter == null) { + var error = controllerName + ":" + topic + ":" + factClass + NO_FILTERS; + return errorResponse(BAD_REQUEST, error); + } + return filter; + } + + private Response getResponse(String topicName, boolean success, Topic topic) { + if (success) { + return Response.status(OK).entity(topic).build(); + } else { + return errorResponse(NOT_ACCEPTABLE, "cannot perform operation on " + topicName); + } + } + + private static boolean checkLoggerFactoryInstance() { + if (!(LoggerFactory.getILoggerFactory() instanceof LoggerContext)) { + logger.warn("The SLF4J logger factory is not configured for logback"); + return true; } + return false; } - public static boolean checkValidNameInput(String test) { - return Pattern.matches("\\S+", test); + private Response errorResponse(Status status, String errorMessage) { + var error = new Error(errorMessage); + return Response.status(status).entity(error).build(); } /* diff --git a/policy-management/src/main/java/org/onap/policy/drools/system/PolicyEngineManager.java b/policy-management/src/main/java/org/onap/policy/drools/system/PolicyEngineManager.java index 0bc2318b..dbcb7917 100644 --- a/policy-management/src/main/java/org/onap/policy/drools/system/PolicyEngineManager.java +++ b/policy-management/src/main/java/org/onap/policy/drools/system/PolicyEngineManager.java @@ -98,7 +98,7 @@ import org.slf4j.LoggerFactory; * Policy Engine Manager Implementation. */ @ToString(onlyExplicitlyIncluded = true) -class PolicyEngineManager implements PolicyEngine { +public class PolicyEngineManager implements PolicyEngine { /** * String literals. */ @@ -342,7 +342,7 @@ class PolicyEngineManager implements PolicyEngine { private void createLockManager(Properties properties) { for (PolicyEngineFeatureApi feature : getEngineProviders()) { try { - this.lockManager = feature.beforeCreateLockManager(this, properties); + this.lockManager = feature.beforeCreateLockManager(); if (this.lockManager != null) { logger.info("overridden lock manager is {}", this.lockManager); return; @@ -843,8 +843,7 @@ class PolicyEngineManager implements PolicyEngine { public synchronized void shutdown() { /* - * shutdown activity even when underlying subcomponents (features, controllers, topics, etc - * ..) are stuck + * shutdown activity even when underlying subcomponents (features, controllers, topics, etc) are stuck */ var exitThread = makeShutdownThread(); @@ -884,7 +883,7 @@ class PolicyEngineManager implements PolicyEngine { logger.warn("{}: cannot shutdown lock manager because of {}", this, e.getMessage(), e); } - executorService.shutdownNow(); + getExecutorService().shutdownNow(); // Stop the JMX listener @@ -941,7 +940,7 @@ class PolicyEngineManager implements PolicyEngine { @Override public void run() { try { - doSleep(SHUTDOWN_MAX_GRACE_TIME); + doSleep(); logger.warn("{}: abnormal termination - shutdown graceful time period expiration", PolicyEngineManager.this); } catch (final InterruptedException e) { @@ -960,18 +959,18 @@ class PolicyEngineManager implements PolicyEngine { ex.getMessage(), ex)); logger.info("{}: exit", PolicyEngineManager.this); - doExit(0); + doExit(); } } // these may be overridden by junit tests - protected void doSleep(long sleepMs) throws InterruptedException { - Thread.sleep(sleepMs); + protected void doSleep() throws InterruptedException { + Thread.sleep(ShutdownThread.SHUTDOWN_MAX_GRACE_TIME); } - protected void doExit(int code) { - System.exit(code); + protected void doExit() { + System.exit(0); } } @@ -1329,11 +1328,11 @@ class PolicyEngineManager implements PolicyEngine { policyController.unlock(); policyController.start(); } catch (final Exception e) { - logger.error("{}: cannot activate of policy-controller {} because of {}", this, policyController, - e.getMessage(), e); + logger.error("{}: cannot activate of policy-controller {} because of {}", + this, policyController, e.getMessage(), e); } catch (final LinkageError e) { - logger.error("{}: cannot activate (rules compilation) of policy-controller {} because of {}", this, - policyController, e.getMessage(), e); + logger.error("{}: cannot activate (rules compilation) of policy-controller {} because of {}", + this, policyController, e.getMessage(), e); } } 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<T extends FeatureLockImpl> 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/main/server-gen/bin/db-migrator b/policy-management/src/main/server-gen/bin/db-migrator deleted file mode 100644 index 64d0fcf1..00000000 --- a/policy-management/src/main/server-gen/bin/db-migrator +++ /dev/null @@ -1,635 +0,0 @@ -#!/usr/bin/env sh - -# ============LICENSE_START======================================================= -# ONAP -# ================================================================================ -# Copyright (C) 2017-2022 AT&T Intellectual Property. All rights reserved. -# ================================================================================ -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ============LICENSE_END========================================================= - -# ##################################################################### -# -# Upgrade/Downgrade SQL File Name Format: -# -# <VERSION>-<pdp|feature-name>[-description](.upgrade|.downgrade).sql -# -# This tool operates on a migration working directory at -# -# $POLICY_HOME/etc/db/migration -# -# Upgrade/Downgrade files for each schema (aka database) names to be maintained -# by this tool are located at -# -# $POLICY_HOME/etc/db/migration/<schema-name>/sql -# -# The nature of the migration directories is dynamic. -# Other tooling aware of when migrations are needed are in charge to populate -# the migrations directory accordingly. -# -# One of these tools is the 'features' when a feature with DB requirements -# is 'enabled', the upgrade scripts will be made present in the migration directory. -# When a features is 'disabled' downgrade scripts will be made available in the -# migration directory. -# -# The 'policy' tool via its operations 'status' or 'start' will signal the -# need to perform upgrade or downgrade for a given schema. -# -# At any given time the following invariant must be preserved in any given -# $POLICY_HOME/etc/db/migration/<schema-name>/sql directory -# -# There is only upgrade scripts, or only downgrade scripts, or none. -# -# ##################################################################### - -source ${POLICY_HOME}/etc/profile.d/env.sh - -METADATA_DB=migration -METADATA_TABLE=${METADATA_DB}.metadata_versions -MIGRATION_DIR=${POLICY_HOME}/etc/db/migration -ZERO_VERSION="0" -UPGRADE_SQL_SUFFIX=".upgrade.sql" -DOWNGRADE_SQL_SUFFIX=".downgrade.sql" - -SQL_QUOTES="SET SESSION SQL_MODE=ANSI_QUOTES;" - -##################################################### -# usage -##################################################### - -function usage() { - echo - echo -e "syntax: $(basename "$0") " - echo -e "\t -s <schema-name> " - echo -e "\t [-b <migration-dir>] " - echo -e "\t [-f <from-version>]" - echo -e "\t [-t <target-version>]" - echo -e "\t -o <operations> " - echo - echo -e "\t where <operations>=upgrade|downgrade|auto|version|erase|report" - echo - echo - echo -e "Configuration Options:" - echo -e "\t -s|--schema|--database: schema to operate on ('ALL' to apply on all)" - echo -e "\t -b|--basedir: overrides base DB migration directory" - echo -e "\t -f|--from: overrides current release version for operations" - echo -e "\t -t|--target: overrides target release to upgrade/downgrade" - echo - echo -e "Operations:" - echo -e "\t upgrade: upgrade operation" - echo -e "\t downgrade: performs a downgrade operation" - echo -e "\t auto: autonomous operation, determines upgrade or downgrade" - echo -e "\t version: returns current version, and in conjunction if '-f' sets the current version" - echo -e "\t erase: erase all data related <schema> (use with care)" - echo -e "\t report: migration detailed report on an schema" - echo -e "\t ok: is the migration status valid" - echo - echo -} - -##################################################### -# ensure global metadata -##################################################### - -function ensure_metadata -{ - if [ "${DEBUG}" = "y" ]; then - echo "-- ensure_metadata --" - set -x - fi - - local sql rc - - sql="CREATE DATABASE IF NOT EXISTS ${METADATA_DB};" - ${MYSQL} --execute "${sql}" - rc=$? - if [ ${rc} -ne 0 ]; then - return ${rc} - fi - - sql="CREATE TABLE IF NOT EXISTS ${METADATA_TABLE} " - sql=${sql}"(name VARCHAR(60) NOT NULL, version VARCHAR(20), PRIMARY KEY(name));" - ${MYSQL} --execute "${sql}" - return $? -} - - -##################################################### -# ensure metadata on a per schema basis -##################################################### - -function ensure_metadata_schema -{ - if [ "${DEBUG}" = "y" ]; then - echo "-- ensure_metadata_schema --" - set -x - fi - - local sql rc - - sql="CREATE TABLE IF NOT EXISTS ${METADATA_HISTORY} " - sql=${sql}"(script VARCHAR(80) NOT NULL, operation VARCHAR(10), success VARCHAR(1), " - sql=${sql}"atTime TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " - sql=${sql}"PRIMARY KEY(script));" - ${MYSQL} --execute "${sql}" - rc=$? - if [ ${rc} -ne 0 ]; then - return ${rc} - fi - - sql="CREATE DATABASE IF NOT EXISTS ${SCHEMA_DB};" - ${MYSQL} --execute "${sql}" - return $? -} - - -##################################################### -# target_release -##################################################### - -function target_release -{ - if [ "${DEBUG}" = "y" ]; then - echo "-- target_release --" - set -x - fi - - local sql sqlName upgradeSqls downgradeSqls - - TARGET_UPGRADE_RELEASE=${ZERO_VERSION} - TARGET_DOWNGRADE_RELEASE=${ZERO_VERSION} - - upgradeSqls=$(ls -v -r "${UPGRADE_DIR}"/*"${UPGRADE_SQL_SUFFIX}" 2> /dev/null) - for sql in ${upgradeSqls}; do - sqlName=$(basename "${sql}") - TARGET_UPGRADE_RELEASE="${sqlName%-*}" - break - done - - # default unless overriden - TARGET_DOWNGRADE_RELEASE="${ZERO_VERSION}" -} - -##################################################### -# is_upgrade -##################################################### - -function is_upgrade -{ - if [ "${DEBUG}" = "y" ]; then - echo "-- is_upgrade --" - set -x - fi - - local upgradeSqls - - upgradeSqls=$(ls "${UPGRADE_DIR}"/*"${UPGRADE_SQL_SUFFIX}" 2> /dev/null) - if [ -z "${upgradeSqls}" ]; then - return 1 - else - return 0 - fi -} - - -##################################################### -# is_downgrade -##################################################### - -function is_downgrade -{ - if [ "${DEBUG}" = "y" ]; then - echo "-- is_downgrade --" - set -x - fi - - local downgradeSqls - - downgradeSqls=$(ls "${DOWNGRADE_DIR}"/*"${DOWNGRADE_SQL_SUFFIX}" 2> /dev/null) - if [ -z "${downgradeSqls}" ]; then - return 1 - else - return 0 - fi -} - - -##################################################### -# set_current_release -##################################################### - -function set_current_release -{ - if [ "${DEBUG}" = "y" ]; then - echo "-- set_current_release --" - set -x - fi - - CURRENT_RELEASE="${1}" - - local sql - sql="INSERT INTO ${METADATA_TABLE} (name, version) " - sql=${sql}"VALUES('${SCHEMA}', '${CURRENT_RELEASE}') " - sql=${sql}"ON DUPLICATE KEY UPDATE version='${CURRENT_RELEASE}';" - - ${MYSQL} --execute "${sql}" - return $? -} - -##################################################### -# current_release -##################################################### - -function current_release -{ - if [ "${DEBUG}" = "y" ]; then - echo "-- current_release --" - set -x - fi - - local rc - local query="SELECT version FROM ${METADATA_TABLE} WHERE name='${SCHEMA}'" - - CURRENT_RELEASE=$(${MYSQL} --skip-column-names --silent --execute "${query}") - if [ -z "${CURRENT_RELEASE}" ]; then - set_current_release "${ZERO_VERSION}" - return $? - fi - - return 0 -} - -##################################################### -# execute sql script history -##################################################### - -function track_script -{ - if [ "${DEBUG}" = "y" ]; then - echo "-- track_script $* --" - set -x - fi - - local script="${1}" operation="${2}" success="${3}" - local sql="INSERT INTO ${METADATA_HISTORY}(script,operation,success,atTime) " - sql=${sql}"VALUES ('${script}','${operation}','${success}',now()) " - sql=${sql}"ON DUPLICATE KEY UPDATE operation=values(operation), success=values(success), atTime=values(atTime);" - - ${MYSQL} --execute "${sql}" - return $? -} - - -##################################################### -# execute sql script -##################################################### - -function run_script -{ - if [ "${DEBUG}" == "y" ]; then - echo "-- run_script $* --" - set -x - fi - - local operation="${1}" script="${2}" scriptPath="${3}" - - echo - echo "> ${operation} ${script}" - - ${MYSQL} --verbose < "${scriptPath}" - local rc=$? - if [ ${rc} -ne 0 ]; then - success="0" - else - success="1" - fi - - track_script "${script}" "${operation}" "${success}" - - return ${rc} -} - -##################################################### -# upgrade -##################################################### - -function upgrade -{ - if [ "${DEBUG}" = "y" ]; then - echo "-- upgrade --" - set -x - fi - - local sqlName sqlFile schemaVersion upgradeSqls rc - - ${MYSQL} --execute "USE ${SCHEMA_DB}" - - echo "upgrade: ${CURRENT_RELEASE} -> ${TARGET_UPGRADE_RELEASE}" - - if [ ${CURRENT_RELEASE} \< ${TARGET_UPGRADE_RELEASE} ]; then - upgradeSqls=$(ls -v "${UPGRADE_DIR}"/*"${UPGRADE_SQL_SUFFIX}" 2> /dev/null) - for sqlFile in ${upgradeSqls}; do - sqlName=$(basename "${sqlFile}") - schemaVersion="${sqlName%-*}" - if [ "${schemaVersion}" -gt "${CURRENT_RELEASE}" ] && \ - [ "${schemaVersion}" -le "${TARGET_UPGRADE_RELEASE}" ]; then - run_script "upgrade" "${sqlName}" "${sqlFile}" - rc=$? - if [ ${rc} -ne 0 ]; then - echo "${SCHEMA}: upgrade aborted at ${schemaVersion} by script ${sqlName}" - set_current_release "${schemaVersion}" - return ${rc} - fi - fi - done - - set_current_release "${TARGET_UPGRADE_RELEASE}" - fi - - return 0 -} - -##################################################### -# downgrade -##################################################### - -function downgrade -{ - if [ "${DEBUG}" = "y" ]; then - echo "-- downgrade --" - set -x - fi - - local sqlName sqlFile schemaVersion downgradeSqls rc - - ${MYSQL} --execute "USE ${SCHEMA_DB}" - - echo "downgrade: ${CURRENT_RELEASE} -> ${TARGET_DOWNGRADE_RELEASE}" - - if [ ${CURRENT_RELEASE} \> ${TARGET_DOWNGRADE_RELEASE} ]; then - downgradeSqls=$(ls -v -r "${DOWNGRADE_DIR}"/*"${DOWNGRADE_SQL_SUFFIX}" 2> /dev/null) - for sqlFile in ${downgradeSqls}; do - sqlName=$(basename "${sqlFile}") - schemaVersion="${sqlName%-*}" - if [ "${schemaVersion}" -le "${CURRENT_RELEASE}" ] && \ - [ "${schemaVersion}" -gt "${TARGET_DOWNGRADE_RELEASE}" ]; then - run_script "downgrade" "${sqlName}" "${sqlFile}" - rc=$? - if [ ${rc} -ne 0 ]; then - echo "${SCHEMA}: downgrade aborted at ${schemaVersion} by script ${sqlName}" - set_current_release "${schemaVersion}" - return ${rc} - fi - fi - done - - set_current_release "${TARGET_DOWNGRADE_RELEASE}" - fi - - return 0 -} - -##################################################### -# erase -##################################################### - -function erase -{ - if [ "${DEBUG}" = "y" ]; then - echo "-- erase --" - set -x - fi - - local updateMetadata="UPDATE ${METADATA_TABLE} SET version='${ZERO_VERSION}';" - ${MYSQL} --execute "${updateMetadata}" - - local deleteHistory="DELETE FROM ${METADATA_HISTORY};" - ${MYSQL} --execute "${deleteHistory}" - - local dropDB="DROP DATABASE IF EXISTS ${SCHEMA_DB}"; - ${MYSQL} --execute "${dropDB}" -} - -##################################################### -# report -##################################################### - -function report -{ - if [ "${DEBUG}" = "y" ]; then - echo "-- report --" - set -x - fi - - local versionSql="SELECT * FROM ${METADATA_TABLE} WHERE name='${SCHEMA}';" - ${MYSQL} --execute "${versionSql}" - - local historySql="SELECT * FROM ${METADATA_HISTORY} ORDER BY atTime ASC;" - ${MYSQL} --execute "${historySql}" - - okay -} - -function okay -{ - if [ "${DEBUG}" = "y" ]; then - echo "-- okay --" - set -x - fi - - local rc=0 - if is_upgrade; then - if [ "${CURRENT_RELEASE}" = "${TARGET_UPGRADE_RELEASE}" ]; then - echo "${SCHEMA}: OK @ ${CURRENT_RELEASE}" - else - echo "${SCHEMA}: upgrade available: ${CURRENT_RELEASE} -> ${TARGET_UPGRADE_RELEASE}" - rc=1 - fi - else - if [ "${CURRENT_RELEASE}" = "${TARGET_DOWNGRADE_RELEASE}" ]; then - echo "${SCHEMA}: OK @ ${CURRENT_RELEASE}" - else - echo "${SCHEMA}: downgrade available: ${CURRENT_RELEASE} -> ${TARGET_DOWNGRADE_RELEASE}" - rc=1 - fi - fi - - return ${rc} -} - -##################################################### -# MAIN -##################################################### - -if [ "${DEBUG}" = "y" ]; then - echo "-- $0 $* --" - set -x -fi -until [ -z "$1" ]; do - case $1 in - -s|--schema|--database) shift - SCHEMA=$1 - ;; - -b|--basedir) shift - MIGRATION_DIR=$1 - ;; - -t|--target) shift - INPUT_TARGET_RELEASE=$1 - ;; - -f|--from) shift - INPUT_CURRENT_RELEASE=$1 - ;; - -o|--operation) shift - OPERATION=$1 - ;; - *) usage - exit 1 - ;; - esac - shift -done - -case ${OPERATION} in - upgrade) ;; - downgrade) ;; - auto) ;; - version) ;; - erase) ;; - report) ;; - ok) ;; - *) echo "error: invalid operation provided" - usage - exit 1 - ;; -esac - -if [ -z "${SCHEMA}" ]; then - echo "error: a database name must be provided" - usage - exit 2 -fi - -source "${POLICY_HOME}"/etc/profile.d/env.sh - -if [ -z "${SQL_HOST}" ] || [ -z "${SQL_USER}" ] || [ -z "${SQL_PASSWORD}" ]; then - echo "error: no database has been set up" - exit 4 -fi - -if [ -z "${SQL_PORT}" ]; then - export SQL_PORT=3306 -fi - -if [ -z "$MYSQL_CMD" ]; then - MYSQL_CMD="mysql" -fi - -MYSQL="${MYSQL_CMD} -u${SQL_USER} -p${SQL_PASSWORD} -h ${SQL_HOST} -P ${SQL_PORT}" - -if ! ${MYSQL} --execute "show databases;" > /dev/null 2>&1; then - echo "error: No DB connectivity to ${SQL_HOST} for ${SQL_USER}" - exit 5 -fi - -if [ "${SCHEMA}" = "ALL" ]; then - SCHEMA="*" -fi - -SCHEMA_S=$(ls -d "${MIGRATION_DIR}"/${SCHEMA}/ 2> /dev/null) -if [ -z "${SCHEMA_S}" ]; then - echo "error: no databases available" - exit 0 -fi - -if ! ensure_metadata; then - echo "error: migration metadata not accessible" - exit 7 -fi - -rc=0 -for dbPath in ${SCHEMA_S}; do - SCHEMA=$(basename "${dbPath}") - SCHEMA_DB="\`${SCHEMA}\`" - UPGRADE_DIR="${MIGRATION_DIR}"/"${SCHEMA}"/sql - DOWNGRADE_DIR=${UPGRADE_DIR} - METADATA_HISTORY="${METADATA_DB}.\`${SCHEMA}_history\`" - TARGET_RELEASE=${INPUT_TARGET_RELEASE} - CURRENT_RELEASE=${INPUT_CURRENT_RELEASE} - - if is_upgrade && is_downgrade; then - echo "${SCHEMA}: failure: invalid configuration: ${UPGRADE_SQL_SUFFIX} and "\ - "${DOWNGRADE_SQL_SUFFIX} exist under ${DOWNGRADE_DIR}" - rc=1 - continue - fi - - if [ "${operation}" = "auto" ]; then - if is_upgrade; then - operation=upgrade - else - operation=downgrade - fi - fi - - if ! ensure_metadata_schema; then - echo "${SCHEMA}: failure: metadata not accessible for this schema" - continue - fi - - if [ -z "${TARGET_RELEASE}" ]; then - target_release - else - # user asked to override - TARGET_UPGRADE_RELEASE="${TARGET_RELEASE}" - TARGET_DOWNGRADE_RELEASE="${TARGET_RELEASE}" - fi - - if [ -z "${CURRENT_RELEASE}" ]; then - if ! current_release; then - echo "${SCHEMA}: failure: cannot obtain current release" - continue - fi - else - if ! set_current_release "${CURRENT_RELEASE}"; then - echo "${SCHEMA}: failure: cannot set current release" - continue - fi - fi - - case ${OPERATION} in - upgrade) if upgrade; then - echo "${SCHEMA}: OK: upgrade (${CURRENT_RELEASE})" - else - rc=1 - echo "${SCHEMA}: failure: upgrade to release ${TARGET_UPGRADE_RELEASE} (${CURRENT_RELEASE})" - fi - ;; - downgrade) if downgrade; then - echo "${SCHEMA}: OK: downgrade (${CURRENT_RELEASE})" - else - rc=1 - echo "${SCHEMA}: failure: downgrade to release ${TARGET_DOWNGRADE_RELEASE} (${CURRENT_RELEASE})" - fi - ;; - version) echo "${SCHEMA}: ${CURRENT_RELEASE}" - ;; - erase) erase - ;; - report) report - ;; - ok) okay - ;; - esac - -done -exit $rc diff --git a/policy-management/src/main/server-gen/bin/features b/policy-management/src/main/server-gen/bin/features index 3343ffc4..01b77b1c 100644 --- a/policy-management/src/main/server-gen/bin/features +++ b/policy-management/src/main/server-gen/bin/features @@ -5,6 +5,7 @@ # ONAP POLICY # ================================================================================ # Copyright (C) 2017-2021 AT&T Intellectual Property. All rights reserved. +# Modifications Copyright (C) 2024 Nordix Foundation. # ================================================================================ # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -35,10 +36,6 @@ #    | | L─ <dependent-jar>+ #    │ L─ feature/ #    │ L─ <feature-jar> -#    L─ [db]/ -#    │  L─ <db-name>/+ -#    │ L─ sql/ -#    │ L─ <sql-scripts>* #    L─ [artifacts]/ #     L─ <artifact>+ #    L─ [install] @@ -60,16 +57,6 @@ # of pdp-d that are necessary for <feature-name> to operate # correctly. # lib/feature the single feature jar that implements the feature. -# [db] database directory, if the feature contains sql. -# [db]/<db-name> database to which underlying sql scripts should be applied against. -# ideally, <db-name> = <feature-name> so it is easily to associate -# the db data with a feature itself. Ideally, since a feature is -# a somewhat independent isolated unit of functionality,the <db-name> -# database ideally isolates all its data. -# [db]/<db-name>/sql directory with all the sql scripts. -# [db]/<db-name>/sql/<sql-scripts> for this feature sql scripts -# upgrade scripts should be suffixed with ".upgrade.sql" -# downgrade scripts should be suffixed with ".downgrade.sql" # [artifacts] maven artifacts to be deployed in a maven repository. # [artifacts]/<artifact> maven artifact with identifiable maven coordinates embedded # in the artifact. @@ -87,10 +74,10 @@ # Operations: # install: installs a feature # uninstall: uninstalls a feature -# enable : enables 1) dependencies, 2) configuration, 3) binaries 4) database, 5) artifacts, -# 6) feature, 7) customization. -# disable: disables 1) dependencies, 2) configuration, 3) binaries, 4) database, 5) feature, -# 6) customization +# enable : enables 1) dependencies, 2) configuration, 3) binaries 4) artifacts, +# 5) feature, 6) customization. +# disable: disables 1) dependencies, 2) configuration, 3) binaries, 4) feature, +# 5) customization # status : status of a feature # # 'enable' operation details: @@ -99,10 +86,8 @@ # 2. sets symbolic links to feature dependencies in pdp-d classpath ($POLICY_HOME/lib) # 3. sets symbolic links to feature configuration in pdp-d configuration directory ($POLICY_HOME/config) # 4. sets symbolic links to feature executables in pdp-d bin directory ($POLICY_HOME/bin) -# 5. sets symbolic links to feature upgrade scripts and removes links to downgrade scripts (if any) -# in the pdp-d migration directory ($POLICY_HOME/etc/db/migration). -# 6. deploys any maven artifacts in the maven repositories in use (if any) -# 7. cd to the feature 'install' directory an executes (if exists) the 'enable' script to allow for specific +# 5. deploys any maven artifacts in the maven repositories in use (if any) +# 6. cd to the feature 'install' directory an executes (if exists) the 'enable' script to allow for specific # customizations for this feature. # # 'disable' operation details: @@ -111,16 +96,9 @@ # 2. removes symbolic links to feature dependencies in pdp-d classpath ($POLICY_HOME/lib) # 3. removes symbolic links to feature configuration in pdp-d configuration directory ($POLICY_HOME/config) # 4. removes symbolic links to feature executables in pdp-d bin directory ($POLICY_HOME/bin) -# 5. removes symbolic links to feature upgrade scripts and sets links to downgrade scripts (if any) -# in the pdp-d migration directory ($POLICY_HOME/etc/db/migration). -# 6. cd to the feature 'install' directory an executes (if exists) the 'disable' script to allow for specific +# 5. cd to the feature 'install' directory an executes (if exists) the 'disable' script to allow for specific # customizations for this feature. # -# Notes for DB enabled features: -# A. Upgrade/Downgrade SQL File Name Format: -# <VERSION>-<pdp|feature-name>[-description](.upgrade|.downgrade).sql -# B. See related tooling: db-migrator, deploy-artifact, and policy -# # Example: # # POLICY_HOME/ @@ -155,7 +133,6 @@ fi LIB=${POLICY_HOME}/lib CONFIG=${POLICY_HOME}/config BIN=${POLICY_HOME}/bin -DB=${POLICY_HOME}/etc/db/migration FEATURES=${POLICY_HOME}/features if [ ! -d "${LIB}" ]; then @@ -171,10 +148,6 @@ fi # ensure that the directory exists mkdir -p "${FEATURES}" 2> /dev/null -if [ ! -d "${DB}" ]; then - mkdir -p "${DB}" -fi - # relative per Feature Directory Paths FEATURE_DEPS="lib/dependencies" @@ -183,11 +156,6 @@ FEATURE_CONFIG="config" FEATURE_BIN="bin" FEATURE_INSTALL="install" FEATURE_ARTIFACTS="artifacts" -FEATURE_DB="db" -FEATURE_SQL="sql" - -UPGRADE_SQL_SUFFIX=".upgrade.sql" -DOWNGRADE_SQL_SUFFIX=".downgrade.sql" featureJars=$(find "${FEATURES}" -name "feature-*.jar" -type f -exec basename {} \; 2> /dev/null) @@ -386,39 +354,6 @@ function enableBinAnalysis () } # ########################################################## -# enableDbAnalysis (featureName): -# reports on potential db access problems -# featureName: name of the feature -# ########################################################## -function enableDbAnalysis() -{ - if [ "${DEBUG}" = "y" ]; then - echo "-- enableDbAnalysis $* --" - set -x - fi - - local featureName="$1" - local featureSqls - - if [ -z "${featureName}" ]; then - echo "warning: no feature name" - return 1 - fi - - featureSqls=$(ls "${FEATURES}"/"${featureName}"/"${FEATURE_DB}"/*/${FEATURE_SQL}/*${UPGRADE_SQL_SUFFIX} 2> /dev/null) - if [ -z "${featureSqls}" ]; then - return 0 - fi - - source "${POLICY_HOME}"/etc/profile.d/env.sh - if [ -z "${SQL_HOST}" ] || [ -z "${SQL_USER}" ] || [ -z "${SQL_PASSWORD}" ]; then - echo "warning: DB server is not configured" - fi - - return 0 -} - -# ########################################################## # enableFeatureDeps(featureName): # enables feature dependencies # featureName: name of the feature @@ -500,95 +435,6 @@ function enableFeatureBin() } # ########################################################## -# enableFeatureDbSchema(featureName): -# enables feature DB Schema configuration -# featureName: name of the feature -# ########################################################## -function enableFeatureDbSchema() -{ - if [ "${DEBUG}" = "y" ]; then - echo "-- enableFeatureDbSchema $* --" - set -x - fi - - local featureName="$1" - local featureDbPath="$2" - local schemaName="$3" - - if [ -z "${featureName}" ]; then - echo "warning: no feature name" - return 1 - fi - - if [ -z "${featureDbPath}" ]; then - echo "warning: ${featureName} contains no DB path" - return 2 - fi - - if [ -z "${schemaName}" ]; then - echo "warning: feature ${featureName} contains no schema name" - return 3 - fi - - rc=0 - sqlUpgradeScripts=$(ls "${featureDbPath%/}"/${FEATURE_SQL}/*${UPGRADE_SQL_SUFFIX} 2> /dev/null) - for sqlUpgradeScript in ${sqlUpgradeScripts}; do - if [ ! -d "${DB}"/"${schemaName}"/${FEATURE_SQL} ]; then - mkdir -p "${DB}"/"${schemaName}"/${FEATURE_SQL} 2> /dev/null - fi - ln -s -f "${sqlUpgradeScript}" "${DB}"/"${schemaName}"/${FEATURE_SQL}/ - done - - sqlDowngradeScripts=$(ls "${featureDbPath%/}"/${FEATURE_SQL}/*${DOWNGRADE_SQL_SUFFIX} 2> /dev/null) - for sqlDowngradeScript in ${sqlDowngradeScripts}; do - if [ -d "${DB}"/"${schemaName}"/${FEATURE_SQL} ]; then - sqlName=$(basename "${sqlDowngradeScript}") - rm -f "${DB}"/"${schemaName}"/"${FEATURE_SQL}"/"${sqlName}" 2> /dev/null - else - echo "warning: feature ${featureName} only contains downgrade scripts" - rc=4 - break - fi - done - - if [ -n "${sqlUpgradeScripts}" ] || [ -n "${sqlDowngradeScripts}" ]; then - DEBUG=${DEBUG} db-migrator -s "${schemaName}" -o ok - fi - - return ${rc} -} - -# ########################################################## -# enableFeatureDb(featureName): -# enables DB feature configuration -# featureName: name of the feature -# ########################################################## -function enableFeatureDb() -{ - if [ "${DEBUG}" = "y" ]; then - echo "-- enableFeatureDb $* --" - set -x - fi - - local featureName="$1" - local featureDbs featureDbPath schemaName sqls - if [ -z "${featureName}" ]; then - echo "warning: no feature name" - return 1 - fi - - featureDbs=$(ls -d "${FEATURES}"/"${featureName}"/"${FEATURE_DB}"/*/ 2> /dev/null) - for featureDbPath in ${featureDbs}; do - sqls=$(ls "${featureDbPath%/}"/"${FEATURE_SQL}"/*.sql 2> /dev/null) - if [ -z "${sqls}" ]; then - continue - fi - schemaName=$(basename "${featureDbPath%/}") - enableFeatureDbSchema "${featureName}" "${featureDbPath%/}" "${schemaName}" - done -} - -# ########################################################## # enableFeatureArtifacts(featureName): # deploys maven artifacts # featureName: name of the feature @@ -686,10 +532,6 @@ function enableFeature() if ! enableBinAnalysis "${featureName}"; then return "$?" fi - - if ! enableDbAnalysis "${featureName}"; then - return "$?" - fi # enable feature itself @@ -707,10 +549,6 @@ function enableFeature() enableFeatureBin "${featureName}" - # enable db - - enableFeatureDb "${featureName}" - # enable feature artifacts enableFeatureArtifacts "${featureName}" @@ -839,97 +677,6 @@ function disableFeatureBin() } # ########################################################## -# disableFeatureDbSchema(featureName, featureDbPath, schemaName): -# disables feature db configuration for a schema -# featureName: name of the feature -# ########################################################## -function disableFeatureDbSchema() -{ - if [ "${DEBUG}" = "y" ]; then - echo "-- disableFeatureDbSchema $* --" - set -x - fi - - local featureName="$1" featureDbPath="$2" schemaName="$3" - local upgradeFeatureSqls downgradeFeatureSqls featureSql sqlDir sqlName schemaDir schemaName - - if [ -z "${featureName}" ]; then - echo "warning: no feature name" - return 1 - fi - - if [ -z "${featureDbPath}" ]; then - echo "warning: ${featureName} contains no DB path" - return 2 - fi - - if [ -z "${schemaName}" ]; then - echo "warning: feature ${featureName} contains no schema name" - return 3 - fi - - if [ -z "${featureName}" ]; then - echo "warning: no feature name" - return 1 - fi - - upgradeFeatureSqls=$(find "${FEATURES}"/"${featureName}"/"${FEATURE_DB}"/"${schemaName}"/"${FEATURE_SQL}"/*"${UPGRADE_SQL_SUFFIX}" -type f -maxdepth 1 2> /dev/null) - for featureSql in ${upgradeFeatureSqls}; do - sqlName=$(basename "${featureSql}") - sqlDir=$(dirname "${featureSql}") - schemaDir=$(dirname "${sqlDir}") - schemaName=$(basename "${schemaDir}") - rm -f "${DB}"/"${schemaName}"/"${FEATURE_SQL}"/"${sqlName}" 2> /dev/null - done - - downgradeFeatureSqls=$(find "${FEATURES}"/"${featureName}"/"${FEATURE_DB}"/"${schemaName}"/"${FEATURE_SQL}"/*"${DOWNGRADE_SQL_SUFFIX}" -type f -maxdepth 1 2> /dev/null) - for featureSql in ${downgradeFeatureSqls}; do - sqlName=$(basename "${featureSql}") - sqlDir=$(dirname "${featureSql}") - schemaDir=$(dirname "${sqlDir}") - schemaName=$(basename "${schemaDir}") - if [ ! -d "${DB}"/"${schemaName}"/${FEATURE_SQL} ]; then - mkdir -p "${DB}"/"${schemaName}"/${FEATURE_SQL} 2> /dev/null - fi - ln -s -f "${featureSql}" "${DB}"/"${schemaName}"/${FEATURE_SQL}/ - done - - if [ -n "${sqlUpgradeScripts}" ] || [ -n "${sqlDowngradeScripts}" ]; then - DEBUG=${DEBUG} db-migrator -s "${schemaName}" -o ok - fi -} - -# ########################################################## -# disableFeatureDb(featureName): -# disables feature db configuration -# featureName: name of the feature -# ########################################################## -function disableFeatureDb() -{ - if [ "${DEBUG}" = "y" ]; then - echo "-- disableFeatureDb $* --" - set -x - fi - - local featureName="$1" - local featureDbPath featureDbs schemaName - - if [ -z "${featureName}" ]; then - echo "warning: no feature name" - return 1 - fi - - featureDbs=$(ls -d "${FEATURES}"/"${featureName}"/"${FEATURE_DB}"/*/ 2> /dev/null) - for featureDbPath in ${featureDbs}; do - if [ -z "$(ls "${featureDbPath%/}"/"${FEATURE_SQL}"/*${UPGRADE_SQL_SUFFIX} 2> /dev/null)" ]; then - continue - fi - schemaName=$(basename "${featureDbPath%/}") - disableFeatureDbSchema "${featureName}" "${featureDbPath%/}" "${schemaName}" - done -} - -# ########################################################## # disableFeature(featureName): disables a feature # featureName: name of the feature # ########################################################## @@ -966,10 +713,6 @@ function disableFeature() disableFeatureBin "${featureName}" - # disable DB SQL scripts if any - - disableFeatureDb "${featureName}" - # run custom disable if any customOpScript "${featureName}" "disable" @@ -1080,47 +823,6 @@ function installFeatures fi } -# ########################################################## -# uninstallFeatureDb(featureName): -# uninstalls the feature db configuration -# featureName: name of the feature -# ########################################################## -function uninstallFeatureDb() -{ - if [ "${DEBUG}" = "y" ]; then - echo "-- uninstallFeatureDb $* --" - set -x - fi - - local featureName="$1" - local featureSqls sqlDir sqlName schemaDir schemaName schemaNames leftSqls - - if [ -z "${featureName}" ]; then - echo "warning: no feature name" - return 1 - fi - - featureSqls=$(find "${FEATURES}"/"${featureName}"/"${FEATURE_DB}"/*/${FEATURE_SQL}/*.sql -type f -maxdepth 1 2> /dev/null) - for featureSql in ${featureSqls}; do - sqlName=$(basename "${featureSql}") - sqlDir=$(dirname "${featureSql}") - schemaDir=$(dirname "${sqlDir}") - schemaName=$(basename "${schemaDir}") - schemaNames="${schemaNames} ${schemaName}" - rm -f "${DB}"/"${schemaName}"/"${FEATURE_SQL}"/"${sqlName}" 2> /dev/null - done - for schemaName in ${schemaNames}; - do - leftSqls=$(ls "${DB}"/"${schemaName}"/"${FEATURE_SQL}"/*.sql 2> /dev/null) - if [ -n "${leftSqls}" ]; then - if ! DEBUG=${DEBUG} db-migrator -s "${schemaName}" -o ok; then - echo -n "warning: ${featureName}: ${schemaName}: database data is leftover. " - echo -n "Consider cleaning left over data with 'db-migrator'." - fi - fi - done -} - ############################################################ # uninstallFeature <feature-name> ... ############################################################ @@ -1138,7 +840,6 @@ function uninstallFeature return fi disableFeature "${featureName}" - uninstallFeatureDb "${featureName}" customOpScript "${featureName}" "uninstall" if [ -n "${FEATURES}" ] && [ -n "${featureName}" ]; then diff --git a/policy-management/src/test/java/org/onap/policy/drools/controller/IndexedDroolsControllerFactoryTest.java b/policy-management/src/test/java/org/onap/policy/drools/controller/IndexedDroolsControllerFactoryTest.java new file mode 100644 index 00000000..39a03db3 --- /dev/null +++ b/policy-management/src/test/java/org/onap/policy/drools/controller/IndexedDroolsControllerFactoryTest.java @@ -0,0 +1,154 @@ +/*- + * ============LICENSE_START=============================================== + * ONAP + * ======================================================================== + * Copyright (C) 2024 Nordix Foundation. + * ======================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END================================================= + */ + +package org.onap.policy.drools.controller; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.doCallRealMethod; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.onap.policy.drools.protocol.coders.TopicCoderFilterConfiguration; +import org.springframework.test.util.ReflectionTestUtils; + +class IndexedDroolsControllerFactoryTest { + + IndexedDroolsControllerFactory factory; + static final String GROUP_ID = "groupId"; + static final String ARTIFACT_ID = "artifactId"; + static final String VERSION = "version"; + static final String OTHER_VERSION = "otherVersion"; + + @BeforeEach + void setUp() { + this.factory = new IndexedDroolsControllerFactory(); + } + + @Test + void build_EmptyArguments() { + var props = new Properties(); + List<TopicCoderFilterConfiguration> decoderConfigs = List.of(); + List<TopicCoderFilterConfiguration> encoderConfigs = List.of(); + + assertThatThrownBy(() -> factory.build(props, "", ARTIFACT_ID, VERSION, decoderConfigs, encoderConfigs)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Missing maven group-id coordinate"); + + assertThatThrownBy(() -> factory.build(props, GROUP_ID, "", VERSION, decoderConfigs, encoderConfigs)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Missing maven artifact-id coordinate"); + + assertThatThrownBy(() -> factory.build(props, GROUP_ID, ARTIFACT_ID, "", decoderConfigs, encoderConfigs)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Missing maven version coordinate"); + } + + @Test + void testBuild_CheckControllerCopy() { + var props = new Properties(); + List<TopicCoderFilterConfiguration> decoderConfigs = List.of(); + List<TopicCoderFilterConfiguration> encoderConfigs = List.of(); + + var mockFactory = mock(IndexedDroolsControllerFactory.class); + when(mockFactory.build(props, GROUP_ID, ARTIFACT_ID, VERSION, decoderConfigs, encoderConfigs)) + .thenCallRealMethod(); + + var controller = mock(DroolsController.class); + doNothing().when(controller).updateToVersion(GROUP_ID, ARTIFACT_ID, VERSION, decoderConfigs, encoderConfigs); + when(controller.getVersion()).thenReturn(OTHER_VERSION); + Map<String, DroolsController> controllers = new HashMap<>(); + controllers.put(GROUP_ID + ":" + ARTIFACT_ID, controller); + ReflectionTestUtils.setField(mockFactory, "droolsControllers", controllers); + + assertNotNull(mockFactory.build(props, GROUP_ID, ARTIFACT_ID, VERSION, decoderConfigs, encoderConfigs)); + } + + @Test + void unmanage() { + assertThatThrownBy(() -> factory.unmanage(null)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("No controller provided"); + + var mockController = mock(DroolsController.class); + when(mockController.isBrained()).thenReturn(false) + .thenReturn(true).thenReturn(true); + when(mockController.getGroupId()).thenReturn(GROUP_ID); + when(mockController.getArtifactId()).thenReturn(ARTIFACT_ID); + + var mockFactory = mock(IndexedDroolsControllerFactory.class); + doCallRealMethod().when(mockFactory).unmanage(mockController); + when(mockFactory.toString()).thenCallRealMethod(); + + Map<String, DroolsController> controllers = new HashMap<>(); + controllers.put(GROUP_ID + ":" + ARTIFACT_ID, mockController); + ReflectionTestUtils.setField(mockFactory, "droolsControllers", controllers); + + // should return after isBrained returns false + assertDoesNotThrow(() -> mockFactory.unmanage(mockController)); + assertFalse(mockFactory.droolsControllers.isEmpty()); + assertEquals("IndexedDroolsControllerFactory [#droolsControllers=1]", mockFactory.toString()); + + // should go ahead and remove controller from hash map + assertDoesNotThrow(() -> mockFactory.unmanage(mockController)); + assertTrue(mockFactory.droolsControllers.isEmpty()); + assertEquals("IndexedDroolsControllerFactory [#droolsControllers=0]", mockFactory.toString()); + + controllers.put("anotherKey", mockController); + ReflectionTestUtils.setField(mockFactory, "droolsControllers", controllers); + + // should return after comparing the key in the hash map (does not match) + assertDoesNotThrow(() -> mockFactory.unmanage(mockController)); + assertFalse(mockFactory.droolsControllers.isEmpty()); + assertEquals("IndexedDroolsControllerFactory [#droolsControllers=1]", mockFactory.toString()); + } + + @Test + void shutdown() { + var mockController = mock(DroolsController.class); + doNothing().when(mockController).shutdown(); + + var mockFactory = mock(IndexedDroolsControllerFactory.class); + doNothing().when(mockFactory).unmanage(mockController); + + assertDoesNotThrow(() -> mockFactory.shutdown(mockController)); + } + + @Test + void get_EmptyParameters() { + assertThatThrownBy(() -> factory.get("", ARTIFACT_ID, VERSION)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Missing maven coordinates"); + assertThatThrownBy(() -> factory.get(GROUP_ID, "", VERSION)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Missing maven coordinates"); + } +}
\ No newline at end of file diff --git a/policy-management/src/test/java/org/onap/policy/drools/controller/internal/MavenDroolsControllerUpgradesTest.java b/policy-management/src/test/java/org/onap/policy/drools/controller/internal/MavenDroolsControllerUpgradesTest.java index 38b38a8c..753296a8 100644 --- a/policy-management/src/test/java/org/onap/policy/drools/controller/internal/MavenDroolsControllerUpgradesTest.java +++ b/policy-management/src/test/java/org/onap/policy/drools/controller/internal/MavenDroolsControllerUpgradesTest.java @@ -88,7 +88,7 @@ public class MavenDroolsControllerUpgradesTest { KieUtils.installArtifact( Paths.get(DROOLS_RESOURCES_DIR + RULES_BASE + KMODULE_EXT).toFile(), Paths.get(DROOLS_RESOURCES_DIR + name + POM_EXT).toFile(), - DROOLS_KJAR_RESOURCES_DIR + KBNAME_RULES + "/" + KBPACKAGE_RULES + "/", + DROOLS_KJAR_RESOURCES_DIR + KBNAME_RULES + "/" + KBPACKAGE_RULES + "/", drls); } @@ -105,8 +105,8 @@ public class MavenDroolsControllerUpgradesTest { rulesDescriptor2 = install("rules2", Stream.of(path.toFile(), - Paths.get(DROOLS_RESOURCES_DIR + "rules2" + DRL_EXT).toFile()) - .collect(Collectors.toList())); + Paths.get(DROOLS_RESOURCES_DIR + "rules2" + DRL_EXT).toFile()) + .collect(Collectors.toList())); LoggerUtils.setLevel("ROOT", "WARN"); LoggerUtils.setLevel("org.onap.policy.drools.controller.internal", "INFO"); @@ -169,13 +169,13 @@ public class MavenDroolsControllerUpgradesTest { private void summary() { logger.info("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); - logger.info("Controller: " + controller.getGroupId() + ":" + controller.getArtifactId() - + ":" + controller.getVersion()); + logger.info("Controller: {}:{}:{}", controller.getGroupId(), controller.getArtifactId(), + controller.getVersion()); logger.info("....................................................................."); - logger.info("KIE-BASES: " + KieUtils.getBases(controller.getContainer().getKieContainer())); - logger.info("KIE-PACKAGE-NAMES: " + KieUtils.getPackageNames(controller.getContainer().getKieContainer())); - logger.info("KIE-RULE-NAMES: " + KieUtils.getRuleNames(controller.getContainer().getKieContainer())); - logger.info("FACTS: " + controller.facts(KBSESSION_RULES, Object.class)); + logger.info("KIE-BASES: {}", KieUtils.getBases(controller.getContainer().getKieContainer())); + logger.info("KIE-PACKAGE-NAMES: {}", KieUtils.getPackageNames(controller.getContainer().getKieContainer())); + logger.info("KIE-RULE-NAMES: {}", KieUtils.getRuleNames(controller.getContainer().getKieContainer())); + logger.info("FACTS: {}", controller.facts(KBSESSION_RULES, Object.class)); logger.info("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); } @@ -190,25 +190,25 @@ public class MavenDroolsControllerUpgradesTest { controller.getContainer() .getPolicySession(KBSESSION_RULES) .getKieSession() - .addEventListener(new RuleRuntimeEventListener() { - @Override - public void objectInserted(ObjectInsertedEvent objectInsertedEvent) { - logger.info("RULE {}: inserting {}", - objectInsertedEvent.getRule().getName(), objectInsertedEvent.getObject()); - } - - @Override - public void objectUpdated(ObjectUpdatedEvent objectUpdatedEvent) { - logger.info("RULE {}: updating {}", - objectUpdatedEvent.getRule().getName(), objectUpdatedEvent.getObject()); - } - - @Override - public void objectDeleted(ObjectDeletedEvent objectDeletedEvent) { - logger.info("RULE {}: deleting {}", - objectDeletedEvent.getRule().getName(), objectDeletedEvent.getOldObject()); - } - }); + .addEventListener(new RuleRuntimeEventListener() { + @Override + public void objectInserted(ObjectInsertedEvent objectInsertedEvent) { + logger.info("RULE {}: inserting {}", + objectInsertedEvent.getRule().getName(), objectInsertedEvent.getObject()); + } + + @Override + public void objectUpdated(ObjectUpdatedEvent objectUpdatedEvent) { + logger.info("RULE {}: updating {}", + objectUpdatedEvent.getRule().getName(), objectUpdatedEvent.getObject()); + } + + @Override + public void objectDeleted(ObjectDeletedEvent objectDeletedEvent) { + logger.info("RULE {}: deleting {}", + objectDeletedEvent.getRule().getName(), objectDeletedEvent.getOldObject()); + } + }); controller.getContainer() .getPolicySession(KBSESSION_RULES) diff --git a/policy-management/src/test/java/org/onap/policy/drools/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/features/DroolsControllerFeatureApiTest.java b/policy-management/src/test/java/org/onap/policy/drools/features/DroolsControllerFeatureApiTest.java new file mode 100644 index 00000000..83171dae --- /dev/null +++ b/policy-management/src/test/java/org/onap/policy/drools/features/DroolsControllerFeatureApiTest.java @@ -0,0 +1,83 @@ +/*- + * ============LICENSE_START=============================================== + * ONAP + * ======================================================================== + * Copyright (C) 2024 Nordix Foundation. + * ======================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END================================================= + */ + +package org.onap.policy.drools.features; + + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; + +import java.util.Collections; +import java.util.Properties; +import org.junit.jupiter.api.Test; +import org.onap.policy.common.endpoints.event.comm.TopicSink; +import org.onap.policy.drools.controller.DroolsController; + +/** + * DroolsControllerFeatureApi is implemented in other modules, therefore, coverage is not coming up in this module. + * This class has no intention of unit testing features, sole goal is raise coverage. + */ +class DroolsControllerFeatureApiTest { + + DroolsControllerFeatureApi testClass = new TestDroolsControllerFeatureApi(); + Properties props = new Properties(); + DroolsController controller; + TopicSink sink; + Object fact; + + @Test + void beforeInstance() { + assertNull(testClass.beforeInstance(props, "group", "artifact", "version", + Collections.emptyList(), Collections.emptyList())); + } + + @Test + void afterInstance() { + assertFalse(testClass.afterInstance(controller, props)); + } + + @Test + void beforeInsert() { + assertFalse(testClass.beforeInsert(controller, props)); + } + + @Test + void afterInsert() { + assertFalse(testClass.afterInsert(controller, fact, false)); + } + + @Test + void beforeDeliver() { + assertFalse(testClass.beforeDeliver(controller, sink, fact)); + } + + @Test + void afterDeliver() { + assertFalse(testClass.afterDeliver(controller, sink, fact, "json", false)); + } + + static class TestDroolsControllerFeatureApi implements DroolsControllerFeatureApi { + + @Override + public int getSequenceNumber() { + return 30; + } + } +}
\ No newline at end of file diff --git a/policy-management/src/test/java/org/onap/policy/drools/features/PolicyControllerFeatureApiTest.java b/policy-management/src/test/java/org/onap/policy/drools/features/PolicyControllerFeatureApiTest.java new file mode 100644 index 00000000..f48bf937 --- /dev/null +++ b/policy-management/src/test/java/org/onap/policy/drools/features/PolicyControllerFeatureApiTest.java @@ -0,0 +1,171 @@ +/*- + * ============LICENSE_START=============================================== + * ONAP + * ======================================================================== + * Copyright (C) 2024 Nordix Foundation. + * ======================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END================================================= + */ + +package org.onap.policy.drools.features; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure.NOOP; + +import java.util.Properties; +import org.junit.jupiter.api.Test; +import org.onap.policy.drools.protocol.configuration.DroolsConfiguration; +import org.onap.policy.drools.system.PolicyController; + +/** + * PolicyControllerFeatureApi is implemented in other modules, therefore, coverage is not coming up in this module. + * This class has no intention of unit testing features, sole goal is raise coverage. + */ +class PolicyControllerFeatureApiTest { + + PolicyControllerFeatureApi testClass = new TestPolicyControllerFeatureApi(); + Properties props = new Properties(); + PolicyController controller; + DroolsConfiguration configuration; + + + @Test + void beforeCreate() { + assertNull(testClass.beforeCreate("name", props)); + } + + @Test + void afterCreate() { + assertFalse(testClass.afterCreate(controller)); + } + + @Test + void beforeInstance() { + assertNull(testClass.beforeInstance("name", props)); + } + + @Test + void afterInstance() { + assertFalse(testClass.afterInstance(controller, props)); + } + + @Test + void beforeStart() { + assertFalse(testClass.beforeStart(controller)); + } + + @Test + void afterStart() { + assertFalse(testClass.afterStart(controller)); + } + + @Test + void beforeStop() { + assertFalse(testClass.beforeStop(controller)); + } + + @Test + void afterStop() { + assertFalse(testClass.afterStop(controller)); + } + + @Test + void beforePatch() { + assertFalse(testClass.beforePatch(controller, configuration, configuration)); + } + + @Test + void afterPatch() { + assertFalse(testClass.afterPatch(controller, configuration, configuration, true)); + } + + @Test + void beforeLock() { + assertFalse(testClass.beforeLock(controller)); + } + + @Test + void afterLock() { + assertFalse(testClass.afterLock(controller)); + } + + @Test + void beforeUnlock() { + assertFalse(testClass.beforeUnlock(controller)); + } + + @Test + void afterUnlock() { + assertFalse(testClass.afterUnlock(controller)); + } + + @Test + void beforeShutdown() { + assertFalse(testClass.beforeShutdown(controller)); + } + + @Test + void afterShutdown() { + assertFalse(testClass.afterShutdown(controller)); + } + + @Test + void beforeHalt() { + assertFalse(testClass.beforeHalt(controller)); + } + + @Test + void afterHalt() { + assertFalse(testClass.afterHalt(controller)); + } + + @Test + void beforeOffer() { + assertFalse(testClass.beforeOffer(controller, new Object())); + } + + @Test + void testBeforeOffer() { + assertFalse(testClass.beforeOffer(controller, NOOP, "topic", "event")); + } + + @Test + void afterOffer() { + assertFalse(testClass.afterOffer(controller, new Object(), true)); + } + + @Test + void testAfterOffer() { + assertFalse(testClass.afterOffer(controller, NOOP, "topic", "event", true)); + } + + @Test + void beforeDeliver() { + assertFalse(testClass.beforeDeliver(controller, NOOP, "topic", "event")); + } + + @Test + void afterDeliver() { + assertFalse(testClass.afterDeliver(controller, NOOP, "topic", "event", true)); + } + + static class TestPolicyControllerFeatureApi implements PolicyControllerFeatureApi { + + @Override + public int getSequenceNumber() { + return 20; + } + } +}
\ No newline at end of file diff --git a/policy-management/src/test/java/org/onap/policy/drools/features/PolicyEngineFeatureApiTest.java b/policy-management/src/test/java/org/onap/policy/drools/features/PolicyEngineFeatureApiTest.java new file mode 100644 index 00000000..90feeb20 --- /dev/null +++ b/policy-management/src/test/java/org/onap/policy/drools/features/PolicyEngineFeatureApiTest.java @@ -0,0 +1,174 @@ +/*- + * ============LICENSE_START=============================================== + * ONAP + * ======================================================================== + * Copyright (C) 2024 Nordix Foundation. + * ======================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END================================================= + */ + +package org.onap.policy.drools.features; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.mockito.Mockito.mock; + +import java.util.Properties; +import org.junit.jupiter.api.Test; +import org.onap.policy.common.endpoints.event.comm.Topic; +import org.onap.policy.drools.core.lock.PolicyResourceLockManager; +import org.onap.policy.drools.protocol.configuration.PdpdConfiguration; +import org.onap.policy.drools.system.PolicyEngine; + +/** + * PolicyEngineFeatureApi is implemented in other modules, therefore, coverage is not coming up in this module. + * This class has no intention of unit testing features, sole goal is raise coverage. + */ +class PolicyEngineFeatureApiTest { + + PolicyEngineFeatureApi testClass = new TestPolicyEngineFeatureApi(); + + PolicyEngine policyEngine = mock(PolicyEngine.class); + Properties props = new Properties(); + + @Test + void beforeBoot() { + assertFalse(testClass.beforeBoot(policyEngine, new String[] {"a", "b"})); + } + + @Test + void afterBoot() { + assertFalse(testClass.afterBoot(policyEngine)); + } + + @Test + void beforeConfigure() { + assertFalse(testClass.beforeConfigure(policyEngine, props)); + } + + @Test + void afterConfigure() { + assertFalse(testClass.afterConfigure(policyEngine)); + } + + @Test + void beforeActivate() { + assertFalse(testClass.beforeActivate(policyEngine)); + } + + @Test + void afterActivate() { + assertFalse(testClass.afterActivate(policyEngine)); + } + + @Test + void beforeDeactivate() { + assertFalse(testClass.beforeDeactivate(policyEngine)); + } + + @Test + void afterDeactivate() { + assertFalse(testClass.afterDeactivate(policyEngine)); + } + + @Test + void beforeStart() { + assertFalse(testClass.beforeStart(policyEngine)); + } + + @Test + void afterStart() { + assertFalse(testClass.afterStart(policyEngine)); + } + + @Test + void beforeStop() { + assertFalse(testClass.beforeStop(policyEngine)); + } + + @Test + void afterStop() { + assertFalse(testClass.afterStop(policyEngine)); + } + + @Test + void beforeLock() { + assertFalse(testClass.beforeLock(policyEngine)); + } + + @Test + void afterLock() { + assertFalse(testClass.afterLock(policyEngine)); + } + + @Test + void beforeUnlock() { + assertFalse(testClass.beforeUnlock(policyEngine)); + } + + @Test + void afterUnlock() { + assertFalse(testClass.afterUnlock(policyEngine)); + } + + @Test + void beforeShutdown() { + assertFalse(testClass.beforeShutdown(policyEngine)); + } + + @Test + void afterShutdown() { + assertFalse(testClass.afterShutdown(policyEngine)); + } + + @Test + void beforeOnTopicEvent() { + assertFalse(testClass.beforeOnTopicEvent(policyEngine, Topic.CommInfrastructure.NOOP, "topic", "event")); + } + + @Test + void afterOnTopicEvent() { + assertFalse(testClass.afterOnTopicEvent(policyEngine, mock(PdpdConfiguration.class), + Topic.CommInfrastructure.NOOP, "topic", "event")); + } + + @Test + void beforeOpen() { + assertFalse(testClass.beforeOpen(policyEngine)); + } + + @Test + void afterOpen() { + assertFalse(testClass.afterOpen(policyEngine)); + } + + @Test + void beforeCreateLockManager() { + assertNull(testClass.beforeCreateLockManager()); + } + + @Test + void afterCreateLockManager() { + assertFalse(testClass.afterCreateLockManager(policyEngine, props, mock(PolicyResourceLockManager.class))); + } + + static class TestPolicyEngineFeatureApi implements PolicyEngineFeatureApi { + + @Override + public int getSequenceNumber() { + return 10; + } + + } +}
\ No newline at end of file diff --git a/policy-management/src/test/java/org/onap/policy/drools/persistence/FileSystemPersistenceTest.java b/policy-management/src/test/java/org/onap/policy/drools/persistence/FileSystemPersistenceTest.java new file mode 100644 index 00000000..80a8dc6b --- /dev/null +++ b/policy-management/src/test/java/org/onap/policy/drools/persistence/FileSystemPersistenceTest.java @@ -0,0 +1,78 @@ +/*- + * ============LICENSE_START=============================================== + * ONAP + * ======================================================================== + * Copyright (C) 2024 Nordix Foundation. + * ======================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END================================================= + */ + +package org.onap.policy.drools.persistence; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.nio.file.Path; +import org.junit.jupiter.api.Test; + +class FileSystemPersistenceTest { + + FileSystemPersistence persistence = new FileSystemPersistence(); + + @Test + void testSetConfiguration_FileIsNotDirectory() { + persistence.configurationPath = Path.of("src/test/resources/echo.drl"); + assertThrows(IllegalStateException.class, () -> persistence.setConfigurationDir()); + assertThatThrownBy(() -> persistence.setConfigurationDir()) + .hasMessageContaining("config directory: src/test/resources/echo.drl is not a directory"); + } + + @Test + void testSetConfiguration_InvalidDir() { + persistence.configurationPath = Path.of("/opt/path"); // opt path needs sudo + assertThrows(IllegalStateException.class, () -> persistence.setConfigurationDir()); + assertThatThrownBy(() -> persistence.setConfigurationDir()) + .hasMessageContaining("cannot create /opt/path"); + } + + @Test + void testGetProperties_Exception() { + assertThatThrownBy(() -> persistence.getProperties("")) + .hasMessageContaining("properties name must be provided"); + + String propName = null; + assertThatThrownBy(() -> persistence.getProperties(propName)) // for code coverage + .hasMessageContaining("properties name must be provided"); + } + + @Test + void testGetEnvironmentProperties_Exception() { + assertThatThrownBy(() -> persistence.getEnvironmentProperties("")) + .hasMessageContaining("environment name must be provided"); + + String propName = null; + assertThatThrownBy(() -> persistence.getEnvironmentProperties(propName)) // for code coverage + .hasMessageContaining("environment name must be provided"); + } + + @Test + void testGetProperties_ByPathException() { + assertThatThrownBy(() -> persistence.getProperties(Path.of("/path/does/not/exist.properties"))) + .hasMessageContaining("properties for /path/does/not/exist.properties are not persisted."); + + Path pathProps = null; + assertThatThrownBy(() -> persistence.getProperties(pathProps)) // for code coverage + .hasMessageContaining("propertiesPath is marked non-null but is null"); + } +} diff --git a/policy-management/src/test/java/org/onap/policy/drools/protocol/coders/EventProtocolCoderTest.java b/policy-management/src/test/java/org/onap/policy/drools/protocol/coders/EventProtocolCoderTest.java index 6d461eef..c98467ea 100644 --- a/policy-management/src/test/java/org/onap/policy/drools/protocol/coders/EventProtocolCoderTest.java +++ b/policy-management/src/test/java/org/onap/policy/drools/protocol/coders/EventProtocolCoderTest.java @@ -22,6 +22,7 @@ package org.onap.policy.drools.protocol.coders; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.Properties; @@ -88,4 +89,30 @@ class EventProtocolCoderTest { EventProtocolCoderConstants.getManager().removeEncoders(ENCODER_GROUP, ENCODER_ARTIFACT, NOOP_TOPIC); } + + @Test + void test_extra() { + final Properties noopSinkProperties = new Properties(); + noopSinkProperties.put(PolicyEndPointProperties.PROPERTY_NOOP_SINK_TOPICS, NOOP_TOPIC); + + TopicEndpointManager.getManager().addTopicSinks(noopSinkProperties); + + var encoder = EventProtocolParams.builder().groupId(ENCODER_GROUP).artifactId(ENCODER_ARTIFACT) + .topic(NOOP_TOPIC).eventClass(DroolsConfiguration.class.getName()) + .protocolFilter(new JsonProtocolFilter()).customGsonCoder(null) + .modelClassLoaderHash(DroolsConfiguration.class.getName().hashCode()).build(); + + EventProtocolCoderConstants.getManager().addEncoder(encoder); + + final String json = EventProtocolCoderConstants.getManager().encode(NOOP_TOPIC, + new DroolsConfiguration(ENCODER_ARTIFACT, ENCODER_GROUP, ENCODER_VERSION)); + + assertTrue(json.contains(ENCODER_GROUP)); + assertTrue(json.contains(ENCODER_ARTIFACT)); + + // check if adding same encoder doesn't throw any exceptions as expected + assertDoesNotThrow(() -> EventProtocolCoderConstants.getManager().addEncoder(encoder)); + EventProtocolCoderConstants.getManager().removeEncoders(ENCODER_GROUP, ENCODER_ARTIFACT, NOOP_TOPIC); + EventProtocolCoderConstants.getManager().removeEncoders("NotExistentGroup", ENCODER_ARTIFACT, NOOP_TOPIC); + } } diff --git a/policy-management/src/test/java/org/onap/policy/drools/protocol/coders/GenericProtocolCoderTest.java b/policy-management/src/test/java/org/onap/policy/drools/protocol/coders/GenericProtocolCoderTest.java new file mode 100644 index 00000000..7a8be59e --- /dev/null +++ b/policy-management/src/test/java/org/onap/policy/drools/protocol/coders/GenericProtocolCoderTest.java @@ -0,0 +1,651 @@ +/*- + * ============LICENSE_START=============================================== + * ONAP + * ======================================================================== + * Copyright (C) 2024 Nordix Foundation. + * ======================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END================================================= + */ + +package org.onap.policy.drools.protocol.coders; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doCallRealMethod; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.onap.policy.drools.controller.DroolsController; +import org.onap.policy.drools.controller.DroolsControllerConstants; +import org.onap.policy.drools.controller.DroolsControllerFactory; +import org.onap.policy.drools.controller.internal.NullDroolsController; +import org.springframework.test.util.ReflectionTestUtils; + +class GenericProtocolCoderTest { + + EventProtocolEncoder encoder = new EventProtocolEncoder(); + EventProtocolDecoder decoder = new EventProtocolDecoder(); + + private static final String GROUP_ID = "groupId"; + private static final String ARTIFACT_ID = "artifactId"; + private static final String TOPIC = "topic"; + private static final String VALID_KEY = GROUP_ID + ":" + ARTIFACT_ID + ":" + TOPIC; + private static final String INVALID_KEY = "anotherKey"; + + @Test + void testAdd_ReverseCoder() { + var params = new EventProtocolParams(GROUP_ID, ARTIFACT_ID, TOPIC, "java.lang.Object", + mock(JsonProtocolFilter.class), mock(TopicCoderFilterConfiguration.CustomGsonCoder.class), 1); + + var myKey = "group:artifact:topic"; + + var mockEncoder = mock(EventProtocolEncoder.class); + // set the key to be returned when checking the hash maps + when(mockEncoder.codersKey(GROUP_ID, ARTIFACT_ID, TOPIC)).thenReturn(myKey); + when(mockEncoder.reverseCodersKey(GROUP_ID, "java.lang.Object")).thenReturn(myKey); + doCallRealMethod().when(mockEncoder).add(params); + + + // create the hash maps for coders/reverseCoders + var toolset = mock(ProtocolCoderToolset.class); + HashMap<String, ProtocolCoderToolset> coders = new HashMap<>(); + coders.put(myKey, toolset); + ReflectionTestUtils.setField(mockEncoder, "coders", coders); + HashMap<String, List<ProtocolCoderToolset>> reverseCoders = new HashMap<>(); + reverseCoders.put("group:javaClass", new ArrayList<>(List.of(toolset))); + ReflectionTestUtils.setField(mockEncoder, "reverseCoders", reverseCoders); + + assertDoesNotThrow(() -> mockEncoder.add(params)); + assertEquals(2, mockEncoder.reverseCoders.size()); + assertEquals(1, mockEncoder.coders.size()); + } + + @Test + void testAdd_InvalidParams_GroupId() { + var mockEventProtocolsParams = mock(EventProtocolParams.class); + when(mockEventProtocolsParams.getGroupId()).thenReturn(null); + + assertThatThrownBy(() -> encoder.add(mockEventProtocolsParams)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Invalid group id"); + + when(mockEventProtocolsParams.getGroupId()).thenReturn(""); + + assertThatThrownBy(() -> encoder.add(mockEventProtocolsParams)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Invalid group id"); + } + + @Test + void testAdd_InvalidParams_ArtifactId() { + var mockEventProtocolsParams = mock(EventProtocolParams.class); + when(mockEventProtocolsParams.getGroupId()).thenReturn(GROUP_ID); + when(mockEventProtocolsParams.getArtifactId()).thenReturn(null); + + assertThatThrownBy(() -> encoder.add(mockEventProtocolsParams)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Invalid artifact id"); + + when(mockEventProtocolsParams.getArtifactId()).thenReturn(""); + + assertThatThrownBy(() -> encoder.add(mockEventProtocolsParams)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Invalid artifact id"); + } + + @Test + void testAdd_InvalidParams_Topic() { + var mockEventProtocolsParams = mock(EventProtocolParams.class); + when(mockEventProtocolsParams.getGroupId()).thenReturn(GROUP_ID); + when(mockEventProtocolsParams.getArtifactId()).thenReturn(ARTIFACT_ID); + when(mockEventProtocolsParams.getTopic()).thenReturn(null); + + assertThatThrownBy(() -> encoder.add(mockEventProtocolsParams)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Invalid Topic"); + + when(mockEventProtocolsParams.getGroupId()).thenReturn(GROUP_ID); + when(mockEventProtocolsParams.getArtifactId()).thenReturn(ARTIFACT_ID); + when(mockEventProtocolsParams.getTopic()).thenReturn(""); + + assertThatThrownBy(() -> encoder.add(mockEventProtocolsParams)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Invalid Topic"); + } + + @Test + void testAdd_InvalidParams_EventClass() { + var mockEventProtocolsParams = mock(EventProtocolParams.class); + when(mockEventProtocolsParams.getGroupId()).thenReturn(GROUP_ID); + when(mockEventProtocolsParams.getArtifactId()).thenReturn(ARTIFACT_ID); + when(mockEventProtocolsParams.getTopic()).thenReturn(TOPIC); + when(mockEventProtocolsParams.getEventClass()).thenReturn(null); + + assertThatThrownBy(() -> encoder.add(mockEventProtocolsParams)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Invalid Event Class"); + } + + @Test + void testDecode_Exceptions() { + var mockDecoder = mock(EventProtocolDecoder.class); + when(mockDecoder.isCodingSupported(GROUP_ID, ARTIFACT_ID, TOPIC)) + .thenReturn(false); + when(mockDecoder.decode(GROUP_ID, ARTIFACT_ID, TOPIC, null)) + .thenCallRealMethod(); + when(mockDecoder.codersKey(GROUP_ID, ARTIFACT_ID, TOPIC)) + .thenCallRealMethod(); + + assertThatThrownBy(() -> mockDecoder.decode(GROUP_ID, ARTIFACT_ID, TOPIC, null)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Unsupported: groupId:artifactId:topic for encoding"); + } + + @Test + void testDecode_ExceptionCantDecode() { + var mockDecoder = mock(EventProtocolDecoder.class); + + HashMap<String, ProtocolCoderToolset> coders = new HashMap<>(); + var params = mock(EventProtocolParams.class); + coders.put("groupId:artifactId:topic", new GsonProtocolCoderToolset(params, "controllerId")); + ReflectionTestUtils.setField(mockDecoder, "coders", coders); + + when(mockDecoder.isCodingSupported(GROUP_ID, ARTIFACT_ID, TOPIC)) + .thenReturn(true); + when(mockDecoder.decode(GROUP_ID, ARTIFACT_ID, TOPIC, null)) + .thenCallRealMethod(); + when(mockDecoder.codersKey(GROUP_ID, ARTIFACT_ID, TOPIC)) + .thenCallRealMethod(); + + assertThatThrownBy(() -> mockDecoder.decode(GROUP_ID, ARTIFACT_ID, TOPIC, null)) + .isInstanceOf(UnsupportedOperationException.class) + .hasMessageContaining("Cannot decode with gson"); + } + + @Test + void testDecode_Decode() { + var mockDecoder = mock(EventProtocolDecoder.class); + var myKey = "groupId:artifactId:topic"; + var json = "{\"json\":\"true\"}"; + + HashMap<String, ProtocolCoderToolset> coders = new HashMap<>(); + var mockToolset = mock(ProtocolCoderToolset.class); + when(mockToolset.decode(json)) + .thenReturn(new Object()) // success case + .thenReturn(null); // failure case + + coders.put(myKey, mockToolset); + ReflectionTestUtils.setField(mockDecoder, "coders", coders); + + when(mockDecoder.isCodingSupported(GROUP_ID, ARTIFACT_ID, TOPIC)).thenReturn(true); + when(mockDecoder.codersKey(GROUP_ID, ARTIFACT_ID, TOPIC)).thenReturn(myKey); + when(mockDecoder.decode(GROUP_ID, ARTIFACT_ID, TOPIC, json)) + .thenCallRealMethod(); + + assertNotNull(mockDecoder.decode(GROUP_ID, ARTIFACT_ID, TOPIC, json)); + + assertThatThrownBy(() -> mockDecoder.decode(GROUP_ID, ARTIFACT_ID, TOPIC, json)) + .isInstanceOf(UnsupportedOperationException.class) + .hasMessageContaining("Cannot decode with gson"); + } + + @Test + void testEncode_WithGroupArtifactTopicAndEvent() { + var mockEncoder = mock(EventProtocolEncoder.class); + var event = new Object(); + when(mockEncoder.isCodingSupported(GROUP_ID, ARTIFACT_ID, TOPIC)) + .thenReturn(false); + when(mockEncoder.encode(GROUP_ID, ARTIFACT_ID, TOPIC, event)) + .thenCallRealMethod(); + when(mockEncoder.codersKey(GROUP_ID, ARTIFACT_ID, TOPIC)) + .thenCallRealMethod(); + + assertThatThrownBy(() -> mockEncoder.encode(GROUP_ID, ARTIFACT_ID, TOPIC, event)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Unsupported: groupId:artifactId:topic"); + + // test with event null + when(mockEncoder.isCodingSupported(GROUP_ID, ARTIFACT_ID, TOPIC)) + .thenReturn(true); + when(mockEncoder.codersKey(GROUP_ID, ARTIFACT_ID, TOPIC)) + .thenCallRealMethod(); + when(mockEncoder.encode(GROUP_ID, ARTIFACT_ID, TOPIC, null)) + .thenCallRealMethod(); + + assertThatThrownBy(() -> mockEncoder.encode(GROUP_ID, ARTIFACT_ID, TOPIC, null)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Event cannot be null or empty"); + } + + @Test + void testEncode_WithGroupArtifactTopicAndEvent_ReturnJson() { + var mockEncoder = mock(EventProtocolEncoder.class); + var event = new Object(); + var myKey = "group:artifact:topic"; + + // test with event null + when(mockEncoder.isCodingSupported(GROUP_ID, ARTIFACT_ID, TOPIC)).thenReturn(true); + when(mockEncoder.codersKey(GROUP_ID, ARTIFACT_ID, TOPIC)).thenReturn(myKey); + when(mockEncoder.encode(GROUP_ID, ARTIFACT_ID, TOPIC, event)).thenCallRealMethod(); + when(mockEncoder.encodeInternal(myKey, event)).thenCallRealMethod(); + + var mockToolset = mock(ProtocolCoderToolset.class); + when(mockToolset.encode(event)).thenReturn("{\"json\":\"true\"}"); + + HashMap<String, ProtocolCoderToolset> coders = new HashMap<>(); + coders.put(myKey, mockToolset); + ReflectionTestUtils.setField(mockEncoder, "coders", coders); + + var result = mockEncoder.encode(GROUP_ID, ARTIFACT_ID, TOPIC, event); + assertNotNull(result); + assertEquals("{\"json\":\"true\"}", result); + } + + @Test + void testEncode_WithTopicAndEvent() { + var event = new Object(); + + assertThatThrownBy(() -> encoder.encode(null, event)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Invalid Topic"); + + assertThatThrownBy(() -> encoder.encode("", event)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Invalid Topic"); + + assertThatThrownBy(() -> encoder.encode(TOPIC, null)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Event cannot be null or empty"); + + assertThatThrownBy(() -> encoder.encode(TOPIC, event)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("no reverse coder has been found"); + } + + @Test + void testEncode_WithTopicEncodedClassAndDroolsController() { + var encodedClass = new Object(); + var droolsController = new NullDroolsController(); + + assertThatThrownBy(() -> encoder.encode(null, encodedClass, droolsController)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Invalid Topic"); + + assertThatThrownBy(() -> encoder.encode("", encodedClass, droolsController)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Invalid Topic"); + + assertThatThrownBy(() -> encoder.encode(TOPIC, null, droolsController)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Invalid encoded class"); + + assertThatThrownBy(() -> encoder.encode(TOPIC, encodedClass, droolsController)) + .isInstanceOf(UnsupportedOperationException.class) + .hasMessageContaining("Cannot encode with gson"); + } + + @Test + void testEncode_WithTopicEncodedClassAndDroolsController_ReturnNullJson() { + var encodedClass = new Object(); + var droolsController = new NullDroolsController(); + var mockCoderTools = mock(ProtocolCoderToolset.class); + when(mockCoderTools.encode(encodedClass)).thenReturn(null); + + var mockEncoder = mock(EventProtocolEncoder.class); + when(mockEncoder.codersKey(anyString(), anyString(), anyString())).thenReturn("myKey"); + when(mockEncoder.encodeInternal("myKey", encodedClass)).thenCallRealMethod(); + when(mockEncoder.encode(TOPIC, encodedClass, droolsController)).thenCallRealMethod(); + + HashMap<String, ProtocolCoderToolset> coders = new HashMap<>(); + coders.put("myKey", mockCoderTools); + ReflectionTestUtils.setField(mockEncoder, "coders", coders); + + assertThatThrownBy(() -> mockEncoder.encode(TOPIC, encodedClass, droolsController)) + .isInstanceOf(UnsupportedOperationException.class) + .hasMessageContaining("Cannot encode with gson"); + } + + @Test + void droolsCreators() { + var encodedClass = new Object(); + assertTrue(encoder.droolsCreators(TOPIC, encodedClass).isEmpty()); + } + + @Test + void droolsCreators_ContainsReverseKey() { + var encodedClass = new Object(); + var mockDecoder = mock(EventProtocolDecoder.class); + when(mockDecoder.droolsCreators(TOPIC, encodedClass)).thenCallRealMethod(); + when(mockDecoder.reverseCodersKey(TOPIC, encodedClass.getClass().getName())) + .thenReturn("topic:java.lang.Object"); + + HashMap<String, List<ProtocolCoderToolset>> reverseCoders = new HashMap<>(); + reverseCoders.put("topic:java.lang.Object", List.of()); + ReflectionTestUtils.setField(mockDecoder, "reverseCoders", reverseCoders); + + assertThatThrownBy(() -> mockDecoder.droolsCreators(TOPIC, encodedClass)) + .isInstanceOf(IllegalStateException.class) + .hasMessageContaining("No Encoders toolsets available for topic:java.lang.Object"); + } + + @Test + void droolsCreators_ContainsReverseKey_ReturnControllers() { + var encodedClass = new Object(); + var mockDecoder = mock(EventProtocolDecoder.class); + when(mockDecoder.droolsCreators(TOPIC, encodedClass)).thenCallRealMethod(); + when(mockDecoder.reverseCodersKey(TOPIC, encodedClass.getClass().getName())) + .thenReturn("group:artifact:topic"); + + var toolset = mock(ProtocolCoderToolset.class); + when(toolset.getGroupId()).thenReturn(GROUP_ID); + when(toolset.getArtifactId()).thenReturn(ARTIFACT_ID); + + var mockCoders = mock(EventProtocolCoder.CoderFilters.class); + when(mockCoders.getFactClass()).thenReturn("java.lang.Object"); + when(mockCoders.getModelClassLoaderHash()).thenReturn(1); + when(toolset.getCoders()).thenReturn(List.of(mockCoders)); + + HashMap<String, List<ProtocolCoderToolset>> reverseCoders = new HashMap<>(); + var toolsetList = new ArrayList<ProtocolCoderToolset>(); + toolsetList.add(toolset); + reverseCoders.put("group:artifact:topic", toolsetList); + ReflectionTestUtils.setField(mockDecoder, "reverseCoders", reverseCoders); + + var mockDroolsController = mock(DroolsController.class); + when(mockDroolsController.ownsCoder(encodedClass.getClass(), 1)).thenReturn(true); + + var mockFactory = mock(DroolsControllerFactory.class); + when(mockFactory.get(GROUP_ID, ARTIFACT_ID, "")).thenReturn(mockDroolsController); + + try (MockedStatic<DroolsControllerConstants> factory = Mockito.mockStatic(DroolsControllerConstants.class)) { + factory.when(DroolsControllerConstants::getFactory).thenReturn(mockFactory); + assertEquals(mockFactory, DroolsControllerConstants.getFactory()); + assertFalse(mockDecoder.droolsCreators(TOPIC, encodedClass).isEmpty()); + } + } + + @Test + void testGetFilters_WithGroupArtifactAndTopic() { + assertThatThrownBy(() -> encoder.getFilters(GROUP_ID, ARTIFACT_ID, TOPIC)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Unsupported: groupId:artifactId:topic"); + + var mockEncoder = mock(EventProtocolEncoder.class); + when(mockEncoder.isCodingSupported(GROUP_ID, ARTIFACT_ID, TOPIC)).thenReturn(true); + when((mockEncoder.codersKey(GROUP_ID, ARTIFACT_ID, TOPIC))).thenCallRealMethod(); + when(mockEncoder.getFilters(GROUP_ID, ARTIFACT_ID, TOPIC)).thenCallRealMethod(); + + HashMap<String, ProtocolCoderToolset> coders = new HashMap<>(); + var mockCoderTools = mock(ProtocolCoderToolset.class); + when(mockCoderTools.getCoders()).thenReturn(List.of()); + coders.put(VALID_KEY, mockCoderTools); + ReflectionTestUtils.setField(mockEncoder, "coders", coders); + + assertTrue(mockEncoder.getFilters(GROUP_ID, ARTIFACT_ID, TOPIC).isEmpty()); + } + + @Test + void testGetFilters_WithGroupAndArtifact() { + assertTrue(encoder.getFilters(GROUP_ID, ARTIFACT_ID).isEmpty()); + + assertThatThrownBy(() -> encoder.getFilters("", ARTIFACT_ID)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Invalid group"); + + assertThatThrownBy(() -> encoder.getFilters(GROUP_ID, "")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Invalid artifact"); + } + + @Test + void testGetFilters_WithGroupArtifactTopicAndClassName() { + assertThatThrownBy(() -> encoder.getFilters(GROUP_ID, ARTIFACT_ID, TOPIC, "className")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Unsupported: groupId:artifactId:topic"); + } + + @Test + void testGetFilters_WithGroupArtifactTopicAndClassNameNull() { + var mockEncoder = mock(EventProtocolEncoder.class); + when(mockEncoder.isCodingSupported(GROUP_ID, ARTIFACT_ID, TOPIC)).thenReturn(true); + when(mockEncoder.getFilters(GROUP_ID, ARTIFACT_ID, TOPIC, "")) + .thenCallRealMethod(); + + assertThatThrownBy(() -> mockEncoder.getFilters(GROUP_ID, ARTIFACT_ID, TOPIC, "")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("classname must be provided"); + } + + @Test + void testGetFilters_WithGroupArtifactTopicAndClassName_ReturnValue() { + var mockEncoder = mock(EventProtocolEncoder.class); + when(mockEncoder.isCodingSupported(GROUP_ID, ARTIFACT_ID, TOPIC)).thenReturn(true); + when(mockEncoder.getFilters(GROUP_ID, ARTIFACT_ID, TOPIC, "className")) + .thenCallRealMethod(); + when((mockEncoder.codersKey(GROUP_ID, ARTIFACT_ID, TOPIC))).thenCallRealMethod(); + + HashMap<String, ProtocolCoderToolset> coders = new HashMap<>(); + var mockCoderTools = mock(ProtocolCoderToolset.class); + when(mockCoderTools.getCoder("className")).thenReturn(null); + coders.put(VALID_KEY, mockCoderTools); + ReflectionTestUtils.setField(mockEncoder, "coders", coders); + + assertNull(mockEncoder.getFilters(GROUP_ID, ARTIFACT_ID, TOPIC, "className")); + } + + @Test + void testGetCoders_ReturnObject() { + var mockEncoder = mock(EventProtocolEncoder.class); + when(mockEncoder.isCodingSupported(GROUP_ID, ARTIFACT_ID, TOPIC)).thenReturn(true); + when(mockEncoder.getCoders(GROUP_ID, ARTIFACT_ID, TOPIC)) + .thenCallRealMethod(); + HashMap<String, ProtocolCoderToolset> coders = new HashMap<>(); + ReflectionTestUtils.setField(mockEncoder, "coders", coders); + + assertNull(mockEncoder.getCoders(GROUP_ID, ARTIFACT_ID, TOPIC)); + } + + @Test + void testGetCoders_ReturnList() { + assertThatThrownBy(() -> encoder.getCoders("", ARTIFACT_ID)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Invalid group"); + + assertThatThrownBy(() -> encoder.getCoders(GROUP_ID, "")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Invalid artifact"); + + assertTrue(encoder.getCoders(GROUP_ID, ARTIFACT_ID).isEmpty()); + + // mock a successful return + var mockEncoder = mock(EventProtocolEncoder.class); + HashMap<String, ProtocolCoderToolset> coders = new HashMap<>(); + var params = mock(EventProtocolParams.class); + coders.put(VALID_KEY, new GsonProtocolCoderToolset(params, "controllerId")); + ReflectionTestUtils.setField(mockEncoder, "coders", coders); + when(mockEncoder.codersKey(GROUP_ID, ARTIFACT_ID, "")).thenCallRealMethod(); + when(mockEncoder.getCoders(GROUP_ID, ARTIFACT_ID)).thenCallRealMethod(); + + var resultList = mockEncoder.getCoders(GROUP_ID, ARTIFACT_ID); + assertFalse(resultList.isEmpty()); + assertEquals(1, resultList.size()); + + var emptyResult = mockEncoder.getCoders("group2", "artifact2"); + assertTrue(emptyResult.isEmpty()); + } + + @Test + void testGetReverseFilters() { + assertThatThrownBy(() -> decoder.getReverseFilters("", "codedClass")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Invalid Topic"); + + assertThatThrownBy(() -> decoder.getReverseFilters(TOPIC, "")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("class must be provided"); + + assertTrue(decoder.getReverseFilters(TOPIC, "codedClass").isEmpty()); + } + + @Test + void testGetReverseFilters_ReturnToolset() { + var mockDecoder = mock(EventProtocolDecoder.class); + + // mock a successful return + HashMap<String, List<ProtocolCoderToolset>> reverseCoders = new HashMap<>(); + var params = mock(EventProtocolParams.class); + var toolset = new GsonProtocolCoderToolset(params, "controllerId"); + reverseCoders.put("topic:codedClass", List.of(toolset)); + ReflectionTestUtils.setField(mockDecoder, "reverseCoders", reverseCoders); + + when(mockDecoder.reverseCodersKey(TOPIC, "codedClass")).thenReturn("topic:codedClass"); + when(mockDecoder.getReverseFilters(TOPIC, "codedClass")).thenCallRealMethod(); + + var resultList = mockDecoder.getReverseFilters(TOPIC, "codedClass"); + assertFalse(resultList.isEmpty()); + assertEquals(1, resultList.size()); + } + + @Test + void testGetDroolsController_Exception() { + var fact = new Object(); + assertThatThrownBy(() -> decoder.getDroolsController("", fact)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Invalid Topic"); + + assertThatThrownBy(() -> decoder.getDroolsController(TOPIC, null)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("class must be provided"); + + assertThatThrownBy(() -> decoder.getDroolsController(TOPIC, fact)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Unsupported topic topic and encodedClass class java.lang.Object"); + } + + @Test + void testGetDroolsController_ReturnObject() { + var mockDecoder = mock(EventProtocolDecoder.class); + var droolsController = new NullDroolsController(); + var droolsController2 = new NullDroolsController(); + var fact = new Object(); + + // mock first call to return only one controller, then second call should return 2 controllers + when(mockDecoder.getDroolsControllers(TOPIC, fact)) + .thenReturn(List.of(droolsController)) + .thenReturn(List.of(droolsController, droolsController2)); + when(mockDecoder.getDroolsController(TOPIC, fact)).thenCallRealMethod(); + + var result = mockDecoder.getDroolsController(TOPIC, fact); + assertNotNull(result); + + // second call supposed to return 2 controllers internally, but still return 1 item + var result2 = mockDecoder.getDroolsController(TOPIC, fact); + assertNotNull(result2); + } + + @Test + void testGetDroolsControllers_Exception() { + var fact = new Object(); + assertThatThrownBy(() -> decoder.getDroolsControllers("", fact)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Invalid Topic"); + + assertThatThrownBy(() -> decoder.getDroolsControllers(TOPIC, null)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("class must be provided"); + + assertTrue(decoder.getDroolsControllers(TOPIC, fact).isEmpty()); + } + + @Test + void testGetDroolsControllers_ReturnValues() { + var mockDecoder = mock(EventProtocolDecoder.class); + var droolsController = new NullDroolsController(); + var droolsController2 = new NullDroolsController(); + var fact = new Object(); + + // mock first call to return only one controller, then second call should return 2 controllers + when(mockDecoder.droolsCreators(TOPIC, fact)) + .thenReturn(List.of(droolsController)) + .thenReturn(List.of(droolsController, droolsController2)); + when(mockDecoder.getDroolsControllers(TOPIC, fact)).thenCallRealMethod(); + + var result = mockDecoder.getDroolsControllers(TOPIC, fact); + assertEquals(1, result.size()); + + // second call supposed to return 2 controllers + var result2 = mockDecoder.getDroolsControllers(TOPIC, fact); + assertEquals(2, result2.size()); + } + + @Test + void testRemove() { + var mockDecoder = mock(EventProtocolDecoder.class); + doCallRealMethod().when(mockDecoder).remove(GROUP_ID, ARTIFACT_ID, TOPIC); + when(mockDecoder.codersKey(GROUP_ID, ARTIFACT_ID, TOPIC)).thenCallRealMethod(); + when(mockDecoder.reverseCodersKey(TOPIC, "className")).thenReturn(INVALID_KEY); + + var toolset = mock(ProtocolCoderToolset.class); + var mockCoders = new EventProtocolCoder.CoderFilters("className", mock(JsonProtocolFilter.class), 1); + when(toolset.getCoders()).thenReturn(List.of(mockCoders)); + + HashMap<String, ProtocolCoderToolset> coders = new HashMap<>(); + coders.put(VALID_KEY, toolset); + ReflectionTestUtils.setField(mockDecoder, "coders", coders); + HashMap<String, List<ProtocolCoderToolset>> reverseCoders = new HashMap<>(); + reverseCoders.put(VALID_KEY, new ArrayList<>(List.of(toolset))); + ReflectionTestUtils.setField(mockDecoder, "reverseCoders", reverseCoders); + + assertDoesNotThrow(() -> mockDecoder.remove(GROUP_ID, ARTIFACT_ID, TOPIC)); + assertEquals(1, mockDecoder.reverseCoders.size()); + assertTrue(mockDecoder.coders.isEmpty()); + } + + @Test + void testRemove2() { + var myKey = "group:artifact:topic"; + var mockDecoder = mock(EventProtocolDecoder.class); + doCallRealMethod().when(mockDecoder).remove(GROUP_ID, ARTIFACT_ID, TOPIC); + when(mockDecoder.codersKey(GROUP_ID, ARTIFACT_ID, TOPIC)).thenReturn(myKey); + when(mockDecoder.reverseCodersKey(TOPIC, "className")).thenReturn(myKey); + + var toolset = mock(ProtocolCoderToolset.class); + var mockCoders = new EventProtocolCoder.CoderFilters("className", mock(JsonProtocolFilter.class), 1); + when(toolset.getCoders()).thenReturn(List.of(mockCoders)); + + HashMap<String, ProtocolCoderToolset> coders = new HashMap<>(); + coders.put(myKey, toolset); + ReflectionTestUtils.setField(mockDecoder, "coders", coders); + HashMap<String, List<ProtocolCoderToolset>> reverseCoders = new HashMap<>(); + reverseCoders.put(myKey, new ArrayList<>()); + ReflectionTestUtils.setField(mockDecoder, "reverseCoders", reverseCoders); + + assertDoesNotThrow(() -> mockDecoder.remove(GROUP_ID, ARTIFACT_ID, TOPIC)); + assertTrue(mockDecoder.reverseCoders.isEmpty()); + assertTrue(mockDecoder.coders.isEmpty()); + } + +}
\ No newline at end of file diff --git a/policy-management/src/test/java/org/onap/policy/drools/protocol/coders/GsonProtocolCoderToolsetTest.java b/policy-management/src/test/java/org/onap/policy/drools/protocol/coders/GsonProtocolCoderToolsetTest.java new file mode 100644 index 00000000..4bd2aab2 --- /dev/null +++ b/policy-management/src/test/java/org/onap/policy/drools/protocol/coders/GsonProtocolCoderToolsetTest.java @@ -0,0 +1,197 @@ +/*- + * ============LICENSE_START=============================================== + * ONAP + * ======================================================================== + * Copyright (C) 2024 Nordix Foundation. + * ======================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END================================================= + */ + +package org.onap.policy.drools.protocol.coders; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.mockito.Mockito.doCallRealMethod; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.google.gson.Gson; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonElement; +import com.google.gson.JsonIOException; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSyntaxException; +import java.lang.reflect.Type; +import java.time.Instant; +import java.time.ZonedDateTime; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.mockito.stubbing.Answer; +import org.onap.policy.drools.controller.DroolsControllerConstants; +import org.onap.policy.drools.controller.DroolsControllerFactory; +import org.onap.policy.drools.controller.internal.NullDroolsController; +import org.springframework.test.util.ReflectionTestUtils; + +class GsonProtocolCoderToolsetTest { + + @Test + void decode() { + var mockGsonToolset = mock(GsonProtocolCoderToolset.class); + ReflectionTestUtils.setField(mockGsonToolset, "groupId", "group"); + ReflectionTestUtils.setField(mockGsonToolset, "artifactId", "artifact"); + doCallRealMethod().when(mockGsonToolset).decode("json"); + + var decoderClass = ProtocolCoderToolsetTest.ThreeStrings.class; + var mockGson = mock(Gson.class); + when(mockGson.fromJson("json", decoderClass)).thenThrow(new JsonSyntaxException("error")); + when(mockGsonToolset.getDecoder()).thenReturn(mockGson); + + var mockCustomCoder = mock(TopicCoderFilterConfiguration.CustomCoder.class); + when(mockCustomCoder.getClassContainer()).thenReturn("classContainer"); + ReflectionTestUtils.setField(mockGsonToolset, "customCoder", mockCustomCoder); + + var mockFilter = mock(EventProtocolCoder.CoderFilters.class); + when(mockFilter.getFactClass()).thenReturn("someClassName"); + when(mockGsonToolset.filter("json")).thenReturn(mockFilter); + + var droolsController = mock(NullDroolsController.class); + when(droolsController.fetchModelClass("someClassName")) + .thenReturn(null) + .thenAnswer((Answer<Class<?>>) invocation -> decoderClass) + .thenAnswer((Answer<Class<?>>) invocation -> decoderClass); + when(droolsController.fetchModelClass("classContainer")).thenReturn(null); + + var mockFactory = mock(DroolsControllerFactory.class); + when(mockFactory.get("group", "artifact", "")) + .thenReturn(null) + .thenReturn(droolsController); + + try (MockedStatic<DroolsControllerConstants> factory = Mockito.mockStatic(DroolsControllerConstants.class)) { + factory.when(DroolsControllerConstants::getFactory).thenReturn(mockFactory); + assertEquals(mockFactory, DroolsControllerConstants.getFactory()); + + // first call to fail when droolsController returns null + assertThatThrownBy(() -> mockGsonToolset.decode("json")) + .isInstanceOf(IllegalStateException.class) + .hasMessageContaining("no drools-controller to process event"); + + // second call to fail when droolsController.fetchModelClass returns null + assertThatThrownBy(() -> mockGsonToolset.decode("json")) + .isInstanceOf(UnsupportedOperationException.class) + .hasMessageContaining("cannot fetch application class someClassName"); + + // third call to fail when droolsController.fetchModelClass returns null when using customCoder + assertThatThrownBy(() -> mockGsonToolset.decode("json")) + .isInstanceOf(UnsupportedOperationException.class) + .hasMessageContaining("cannot decode with customCoder: classContainer") + .hasMessageContaining("using application class someClassName"); + + // set customCoder to null to test default decoder + ReflectionTestUtils.setField(mockGsonToolset, "customCoder", null); + + // fourth call to fail when decoder can't parse json + assertThatThrownBy(() -> mockGsonToolset.decode("json")) + .isInstanceOf(UnsupportedOperationException.class) + .hasMessageContaining("cannot decode into"); + } + } + + @Test + void encode() { + var event = new Object(); + + var mockGsonToolset = mock(GsonProtocolCoderToolset.class); + ReflectionTestUtils.setField(mockGsonToolset, "groupId", "group"); + ReflectionTestUtils.setField(mockGsonToolset, "artifactId", "artifact"); + doCallRealMethod().when(mockGsonToolset).encode(event); + + var mockGson = mock(Gson.class); + when(mockGson.toJson(event)).thenThrow(new JsonIOException("error")); + when(mockGsonToolset.getEncoder()).thenReturn(mockGson); + + var mockCustomCoder = mock(TopicCoderFilterConfiguration.CustomCoder.class); + ReflectionTestUtils.setField(mockGsonToolset, "customCoder", mockCustomCoder); + + var mockFactory = mock(DroolsControllerFactory.class); + when(mockFactory.get("group", "artifact", "")).thenReturn(null); + + try (MockedStatic<DroolsControllerConstants> factory = Mockito.mockStatic(DroolsControllerConstants.class)) { + factory.when(DroolsControllerConstants::getFactory).thenReturn(mockFactory); + assertEquals(mockFactory, DroolsControllerConstants.getFactory()); + + // first call to encode fails with droolsController returning null, therefore, can't process event + assertThatThrownBy(() -> mockGsonToolset.encode(event)) + .isInstanceOf(UnsupportedOperationException.class) + .hasMessageContaining("event cannot be custom encoded"); + + // set customCoder to null to test default encoder + ReflectionTestUtils.setField(mockGsonToolset, "customCoder", null); + + // second call to encode fails when gson.toJson raises an exception + assertThatThrownBy(() -> mockGsonToolset.encode(event)) + .isInstanceOf(UnsupportedOperationException.class) + .hasMessageContaining("event cannot be encoded"); + } + } + + @Test + void test_GsonInstantAdapter() { + var instantAdapter = new GsonProtocolCoderToolset.GsonInstantAdapter(); + + var currentTime = System.currentTimeMillis(); + var json = mock(JsonElement.class); + when(json.getAsLong()).thenReturn(currentTime); + + var result = instantAdapter.deserialize(json, mock(Type.class), mock(JsonDeserializationContext.class)); + assertInstanceOf(Instant.class, result); + assertEquals(currentTime, result.toEpochMilli()); + + var jsonResult = instantAdapter.serialize(result, mock(Type.class), mock(JsonSerializationContext.class)); + assertInstanceOf(JsonElement.class, jsonResult); + assertEquals(currentTime, jsonResult.getAsLong()); + } + + @Test + void test_GsonUtcAdapter() { + var utcAdapter = new GsonProtocolCoderToolset.GsonUtcAdapter(); + + var currentZone = ZonedDateTime.now(); + var formattedCurrentZone = ZonedDateTime.now().format(GsonProtocolCoderToolset.format); + var json = mock(JsonElement.class); + when(json.getAsString()).thenReturn(formattedCurrentZone).thenReturn("invalid json"); + + var result = utcAdapter.deserialize(json, mock(Type.class), mock(JsonDeserializationContext.class)); + assertNotNull(result); + assertAll(() -> { + assertEquals(currentZone.getYear(), result.getYear()); + assertEquals(currentZone.getMonth(), result.getMonth()); + assertEquals(currentZone.getDayOfMonth(), result.getDayOfMonth()); + assertEquals(currentZone.getHour(), result.getHour()); + assertEquals(currentZone.getMinute(), result.getMinute()); + assertEquals(currentZone.getSecond(), result.getSecond()); + }); + + // when json.getAsString returns invalid json, should fail and return null + assertNull(utcAdapter.deserialize(json, mock(Type.class), mock(JsonDeserializationContext.class))); + + var result2 = utcAdapter.serialize(result, mock(Type.class), mock(JsonSerializationContext.class)); + assertNotNull(result2); + assertEquals(formattedCurrentZone, result2.getAsString()); + } +}
\ No newline at end of file diff --git a/policy-management/src/test/java/org/onap/policy/drools/protocol/coders/MultiplexorEventProtocolCoderTest.java b/policy-management/src/test/java/org/onap/policy/drools/protocol/coders/MultiplexorEventProtocolCoderTest.java new file mode 100644 index 00000000..c64e9bce --- /dev/null +++ b/policy-management/src/test/java/org/onap/policy/drools/protocol/coders/MultiplexorEventProtocolCoderTest.java @@ -0,0 +1,308 @@ +/*- + * ============LICENSE_START=============================================== + * ONAP + * ======================================================================== + * Copyright (C) 2024 Nordix Foundation. + * ======================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END================================================= + */ + +package org.onap.policy.drools.protocol.coders; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.HashMap; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.onap.policy.drools.controller.DroolsController; +import org.springframework.test.util.ReflectionTestUtils; + +class MultiplexorEventProtocolCoderTest { + + @Mock + EventProtocolEncoder encoder; + + @Mock + EventProtocolDecoder decoder; + + MultiplexorEventProtocolCoder coder = new MultiplexorEventProtocolCoder(); + + AutoCloseable closeable; + + private static final String GROUP_ID = "group"; + private static final String ARTIFACT_ID = "artifact"; + private static final String TOPIC = "topic"; + + @BeforeEach + void setUp() { + closeable = MockitoAnnotations.openMocks(this); + ReflectionTestUtils.setField(coder, "encoders", encoder); + ReflectionTestUtils.setField(coder, "decoders", decoder); + } + + @AfterEach + void tearDown() throws Exception { + closeable.close(); + } + + @Test + void addDecoder() { + var mockParams = mock(EventProtocolParams.class); + doNothing().when(decoder).add(mockParams); + + assertDoesNotThrow(() -> coder.addDecoder(mockParams)); + } + + @Test + void addEncoder() { + var mockParams = mock(EventProtocolParams.class); + doNothing().when(encoder).add(mockParams); + + assertDoesNotThrow(() -> coder.addEncoder(mockParams)); + } + + @Test + void removeDecoders() { + doNothing().when(decoder).remove(GROUP_ID, ARTIFACT_ID, TOPIC); + assertDoesNotThrow(() -> coder.removeDecoders(GROUP_ID, ARTIFACT_ID, TOPIC)); + } + + @Test + void removeEncoders() { + doNothing().when(encoder).remove(GROUP_ID, ARTIFACT_ID, TOPIC); + assertDoesNotThrow(() -> coder.removeEncoders(GROUP_ID, ARTIFACT_ID, TOPIC)); + } + + @Test + void isDecodingSupported() { + HashMap<String, ProtocolCoderToolset> coders = new HashMap<>(); + coders.put("otherGroup:artifact:topic", mock(ProtocolCoderToolset.class)); + ReflectionTestUtils.setField(decoder, "coders", coders); + when(decoder.codersKey(GROUP_ID, ARTIFACT_ID, TOPIC)).thenCallRealMethod(); + when(decoder.isCodingSupported(GROUP_ID, ARTIFACT_ID, TOPIC)) + .thenReturn(true) + .thenCallRealMethod(); + assertTrue(coder.isDecodingSupported(GROUP_ID, ARTIFACT_ID, TOPIC)); + assertFalse(coder.isDecodingSupported(GROUP_ID, ARTIFACT_ID, TOPIC)); + } + + @Test + void isEncodingSupported() { + HashMap<String, ProtocolCoderToolset> coders = new HashMap<>(); + coders.put("otherGroup:artifact:topic", mock(ProtocolCoderToolset.class)); + ReflectionTestUtils.setField(encoder, "coders", coders); + when(encoder.codersKey(GROUP_ID, ARTIFACT_ID, TOPIC)).thenCallRealMethod(); + when(encoder.isCodingSupported(GROUP_ID, ARTIFACT_ID, TOPIC)) + .thenReturn(true) + .thenCallRealMethod(); + assertTrue(coder.isEncodingSupported(GROUP_ID, ARTIFACT_ID, TOPIC)); + assertFalse(coder.isEncodingSupported(GROUP_ID, ARTIFACT_ID, TOPIC)); + } + + @Test + void decode() { + when(decoder.decode(GROUP_ID, ARTIFACT_ID, TOPIC, "{}")) + .thenReturn(new Object()) + .thenCallRealMethod(); + when(decoder.isCodingSupported(GROUP_ID, ARTIFACT_ID, TOPIC)).thenReturn(false); + + // first mock call to return directly new Object() + assertNotNull(coder.decode(GROUP_ID, ARTIFACT_ID, TOPIC, "{}")); + + // second mock call to check isCodingSupport return false, then throws exception + assertThrows(IllegalArgumentException.class, + () -> coder.decode(GROUP_ID, ARTIFACT_ID, TOPIC, "{}")); + } + + @Test + void encode() { + var event = new Object(); + when(encoder.encode(GROUP_ID, ARTIFACT_ID, TOPIC, event)) + .thenReturn("{}") + .thenCallRealMethod(); + when(encoder.isCodingSupported(GROUP_ID, ARTIFACT_ID, TOPIC)).thenReturn(false); + + // first mock call to return directly new Object() + assertNotNull(coder.encode(GROUP_ID, ARTIFACT_ID, TOPIC, event)); + + // second mock call to check isCodingSupport return false, then throws exception + assertThrows(IllegalArgumentException.class, + () -> coder.encode(GROUP_ID, ARTIFACT_ID, TOPIC, event)); + } + + @Test + void encode_WithTopicAndEvent() { + var event = new Object(); + when(encoder.encode(TOPIC, event)).thenReturn("{}"); + + var result = coder.encode(TOPIC, event); + assertNotNull(result); + assertInstanceOf(String.class, result); + } + + @Test + void encode_WithTopicEncodedClassAndController() { + var event = new Object(); + var controller = mock(DroolsController.class); + when(encoder.encode(TOPIC, event, controller)).thenReturn("{}"); + + var result = coder.encode(TOPIC, event, controller); + assertNotNull(result); + assertInstanceOf(String.class, result); + } + + @Test + void getDecoderFilters() { + when(decoder.getFilters(GROUP_ID, ARTIFACT_ID, TOPIC)) + .thenReturn(new ArrayList<>()) + .thenCallRealMethod(); + when(decoder.isCodingSupported(GROUP_ID, ARTIFACT_ID, TOPIC)).thenReturn(false); + + // first mock call return a list + var result = coder.getDecoderFilters(GROUP_ID, ARTIFACT_ID, TOPIC); + assertTrue(result.isEmpty()); + + // second call goes for real method, with isCodingSupported mocked to false, exception is thrown + assertThrows(IllegalArgumentException.class, + () -> coder.getDecoderFilters(GROUP_ID, ARTIFACT_ID, TOPIC)); + } + + @Test + void testGetDecoderFilters_WithGroupArtifactTopicAndClassName() { + when(decoder.getFilters(GROUP_ID, ARTIFACT_ID, TOPIC, "className")) + .thenReturn(mock(EventProtocolCoder.CoderFilters.class)) + .thenCallRealMethod(); + when(decoder.isCodingSupported(GROUP_ID, ARTIFACT_ID, TOPIC)).thenReturn(false); + + // first mock call return a mock object + assertNotNull(coder.getDecoderFilters(GROUP_ID, ARTIFACT_ID, TOPIC, "className")); + + // second call goes for real method, with isCodingSupported mocked to false, exception is thrown + assertThrows(IllegalArgumentException.class, + () -> coder.getDecoderFilters(GROUP_ID, ARTIFACT_ID, TOPIC, "className")); + } + + @Test + void testGetDecoderFilters_WithGroupAndArtifact() { + when(decoder.getFilters(GROUP_ID, ARTIFACT_ID)).thenReturn(new ArrayList<>()); + + assertThat(coder.getDecoderFilters(GROUP_ID, ARTIFACT_ID, TOPIC)).isEmpty(); + } + + @Test + void getDecoders() { + when(decoder.getCoders(GROUP_ID, ARTIFACT_ID, TOPIC)) + .thenReturn(mock(ProtocolCoderToolset.class)) + .thenCallRealMethod(); + when(decoder.isCodingSupported(GROUP_ID, ARTIFACT_ID, TOPIC)).thenReturn(false); + + assertNotNull(coder.getDecoders(GROUP_ID, ARTIFACT_ID, TOPIC)); + assertThrows(IllegalArgumentException.class, + () -> coder.getDecoders(GROUP_ID, ARTIFACT_ID, TOPIC)); + } + + @Test + void testGetDecoders_WithGroupAndArtifact() { + when(decoder.getCoders(GROUP_ID, ARTIFACT_ID)).thenReturn(new ArrayList<>()); + + assertThat(coder.getDecoders(GROUP_ID, ARTIFACT_ID)).isEmpty(); + } + + @Test + void getEncoderFilters() { + when(encoder.getFilters(GROUP_ID, ARTIFACT_ID, TOPIC)) + .thenReturn(new ArrayList<>()) + .thenCallRealMethod(); + when(encoder.isCodingSupported(GROUP_ID, ARTIFACT_ID, TOPIC)).thenReturn(false); + + // first mock call return a list + var result = coder.getEncoderFilters(GROUP_ID, ARTIFACT_ID, TOPIC); + assertTrue(result.isEmpty()); + + // second call goes for real method, with isCodingSupported mocked to false, exception is thrown + assertThrows(IllegalArgumentException.class, + () -> coder.getEncoderFilters(GROUP_ID, ARTIFACT_ID, TOPIC)); + } + + @Test + void testGetEncoderFilters_WithGroupArtifactTopicAndClassName() { + when(encoder.getFilters(GROUP_ID, ARTIFACT_ID, TOPIC, "className")) + .thenReturn(mock(EventProtocolCoder.CoderFilters.class)) + .thenCallRealMethod(); + when(encoder.isCodingSupported(GROUP_ID, ARTIFACT_ID, TOPIC)).thenReturn(false); + + // first mock call return a mock object + assertNotNull(coder.getEncoderFilters(GROUP_ID, ARTIFACT_ID, TOPIC, "className")); + + // second call goes for real method, with isCodingSupported mocked to false, exception is thrown + assertThrows(IllegalArgumentException.class, + () -> coder.getEncoderFilters(GROUP_ID, ARTIFACT_ID, TOPIC, "className")); + } + + @Test + void testGetEncoderFilters_WithGroupAndArtifact() { + when(encoder.getFilters(GROUP_ID, ARTIFACT_ID)).thenReturn(new ArrayList<>()); + + assertThat(coder.getEncoderFilters(GROUP_ID, ARTIFACT_ID, TOPIC)).isEmpty(); + } + + @Test + void getReverseEncoderFilters() { + when(encoder.getReverseFilters(TOPIC, "codedClass")).thenReturn(new ArrayList<>()); + assertThat(coder.getReverseEncoderFilters(TOPIC, "codedClass")).isEmpty(); + } + + @Test + void getDroolsController() { + var fact = new Object(); + // mock success + when(encoder.getDroolsController(TOPIC, fact)) + .thenReturn(mock(DroolsController.class)) + .thenCallRealMethod(); + // mock failure + when(encoder.getDroolsControllers(TOPIC, fact)).thenReturn(new ArrayList<>()); + + // first call gets mock DroolsController - pass + assertNotNull(coder.getDroolsController(TOPIC, fact)); + // second call goes through the method, then call inside method that returns empty list, throws an exception + assertThrows(IllegalArgumentException.class, () -> coder.getDroolsController(TOPIC, fact)); + } + + @Test + void getDroolsControllers() { + var fact = new Object(); + when(encoder.getDroolsControllers(TOPIC, fact)).thenReturn(new ArrayList<>()); + + assertThat(coder.getDroolsControllers(TOPIC, fact)).isEmpty(); + } + + @Test + void testToString() { + assertThat(coder.toString()) + .contains("MultiplexorEventProtocolCoder"); + } +}
\ No newline at end of file diff --git a/policy-management/src/test/java/org/onap/policy/drools/protocol/coders/ProtocolCoderToolsetTest.java b/policy-management/src/test/java/org/onap/policy/drools/protocol/coders/ProtocolCoderToolsetTest.java index 659965f8..cb4397c8 100644 --- a/policy-management/src/test/java/org/onap/policy/drools/protocol/coders/ProtocolCoderToolsetTest.java +++ b/policy-management/src/test/java/org/onap/policy/drools/protocol/coders/ProtocolCoderToolsetTest.java @@ -22,11 +22,19 @@ package org.onap.policy.drools.protocol.coders; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doCallRealMethod; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import com.google.gson.Gson; import com.google.gson.GsonBuilder; @@ -53,6 +61,7 @@ import org.onap.policy.drools.protocol.coders.TopicCoderFilterConfiguration.Cust import org.onap.policy.drools.util.KieUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.test.util.ReflectionTestUtils; /** * ProtocolCoder Toolset Junits. @@ -62,12 +71,12 @@ public class ProtocolCoderToolsetTest { private static final String JUNIT_PROTOCOL_CODER_TOPIC = JUNIT_PROTOCOL_CODER_ARTIFACT_ID; private static final String CONTROLLER_ID = "blah"; - private static final Logger logger = LoggerFactory.getLogger(ProtocolCoderToolset.class); + private static final Logger logger = LoggerFactory.getLogger(ProtocolCoderToolsetTest.class); private static volatile ReleaseId releaseId; // customCoder has to be public to be accessed in tests below - public static final Gson customCoder = new GsonBuilder().create(); + public static final Gson customCoder = new GsonBuilder().create(); // NOSONAR actually being used in the test private DroolsController controller; @@ -77,9 +86,9 @@ public class ProtocolCoderToolsetTest { @BeforeAll public static void setUpClass() throws IOException { releaseId = KieUtils.installArtifact(Paths.get(MavenDroolsControllerTest.JUNIT_ECHO_KMODULE_PATH).toFile(), - Paths.get(MavenDroolsControllerTest.JUNIT_ECHO_KMODULE_POM_PATH).toFile(), - MavenDroolsControllerTest.JUNIT_ECHO_KJAR_DRL_PATH, - Paths.get(MavenDroolsControllerTest.JUNIT_ECHO_KMODULE_DRL_PATH).toFile()); + Paths.get(MavenDroolsControllerTest.JUNIT_ECHO_KMODULE_POM_PATH).toFile(), + MavenDroolsControllerTest.JUNIT_ECHO_KJAR_DRL_PATH, + Paths.get(MavenDroolsControllerTest.JUNIT_ECHO_KMODULE_DRL_PATH).toFile()); } /** @@ -105,6 +114,55 @@ public class ProtocolCoderToolsetTest { testGsonToolset(createFilterSet()); } + @Test + void testExceptions() { + // should fail without params + assertThrows(IllegalArgumentException.class, + () -> new GsonProtocolCoderToolset(null, "controller")); + + // should fail without controller ID + assertThrows(IllegalArgumentException.class, + () -> new GsonProtocolCoderToolset(mock(EventProtocolParams.class), "")); + + // set mock under test - always call real method under test + var toolset = mock(GsonProtocolCoderToolset.class); + when(toolset.getCoder("")).thenCallRealMethod(); + + // should fail calling with empty classname + assertThatThrownBy(() -> toolset.getCoder("")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("no classname provided"); + + // should fail when trying to add coder with empty event class + doCallRealMethod().when(toolset).addCoder(anyString(), any(JsonProtocolFilter.class), anyInt()); + assertThatThrownBy(() -> toolset.addCoder("", mock(JsonProtocolFilter.class), 1)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("no event class provided"); + + // should fail when trying to remove coder with empty event + doCallRealMethod().when(toolset).removeCoders(anyString()); + assertThatThrownBy(() -> toolset.removeCoders("")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("no event class provided"); + + // set coders to empty list + when(toolset.filter(anyString())).thenCallRealMethod(); + ReflectionTestUtils.setField(toolset, "coders", List.of()); + + // should fail when trying to find a filter from an empty list + assertThatThrownBy(() -> toolset.filter("")) + .isInstanceOf(IllegalStateException.class) + .hasMessageContaining("No coders available"); + + // there is a coder in the list, but can't check if accepts json when coder doesn't have filter + var mockCoderFilter = mock(CoderFilters.class); + when(mockCoderFilter.getFilter()).thenReturn(null); + ReflectionTestUtils.setField(toolset, "coders", List.of(mockCoderFilter)); + + assertNull(toolset.filter("json")); + + } + /** * Test the Gson toolset. * @@ -112,10 +170,10 @@ public class ProtocolCoderToolsetTest { */ private void testGsonToolset(JsonProtocolFilter protocolFilter) { GsonProtocolCoderToolset gsonToolset = - new GsonProtocolCoderToolset(EventProtocolParams.builder().topic(JUNIT_PROTOCOL_CODER_TOPIC) - .groupId(releaseId.getGroupId()).artifactId(releaseId.getArtifactId()) - .eventClass(ThreeStrings.class.getName()).protocolFilter(protocolFilter) - .customGsonCoder(null).modelClassLoaderHash(12345678).build(), CONTROLLER_ID); + new GsonProtocolCoderToolset(EventProtocolParams.builder().topic(JUNIT_PROTOCOL_CODER_TOPIC) + .groupId(releaseId.getGroupId()).artifactId(releaseId.getArtifactId()) + .eventClass(ThreeStrings.class.getName()).protocolFilter(protocolFilter) + .customGsonCoder(null).modelClassLoaderHash(12345678).build(), CONTROLLER_ID); assertNotNull(gsonToolset.getEncoder()); assertNotNull(gsonToolset.getDecoder()); @@ -154,7 +212,7 @@ public class ProtocolCoderToolsetTest { } private void decode(JsonProtocolFilter protocolFilter, ProtocolCoderToolset coderToolset, - ThreeStrings triple, String tripleEncoded) { + ThreeStrings triple, String tripleEncoded) { try { coderToolset.decode(tripleEncoded); @@ -212,7 +270,7 @@ public class ProtocolCoderToolsetTest { assertNotNull(coderToolset.getCoder(ThreeStrings.class.getName()).getFilter().getRule()); assertEquals("[?($.third =~ /.*/)]", - coderToolset.getCoder(ThreeStrings.class.getName()).getFilter().getRule()); + coderToolset.getCoder(ThreeStrings.class.getName()).getFilter().getRule()); } private void validateInitialization(JsonProtocolFilter protocolFilter, ProtocolCoderToolset coderToolset) { @@ -241,16 +299,21 @@ public class ProtocolCoderToolsetTest { sinkConfig.put(PolicyEndPointProperties.PROPERTY_NOOP_SINK_TOPICS, JUNIT_PROTOCOL_CODER_TOPIC); final List<TopicSink> noopTopics = TopicEndpointManager.getManager().addTopicSinks(sinkConfig); + Properties droolsControllerConfig = getDroolsControllerConfig(); + + return DroolsControllerConstants.getFactory().build(droolsControllerConfig, null, noopTopics); + } + + private static Properties getDroolsControllerConfig() { Properties droolsControllerConfig = new Properties(); droolsControllerConfig.put(DroolsPropertyConstants.RULES_GROUPID, releaseId.getGroupId()); droolsControllerConfig.put(DroolsPropertyConstants.RULES_ARTIFACTID, releaseId.getArtifactId()); droolsControllerConfig.put(DroolsPropertyConstants.RULES_VERSION, releaseId.getVersion()); droolsControllerConfig.put( - PolicyEndPointProperties.PROPERTY_NOOP_SINK_TOPICS + "." + JUNIT_PROTOCOL_CODER_TOPIC - + PolicyEndPointProperties.PROPERTY_TOPIC_EVENTS_SUFFIX, - ThreeStrings.class.getName()); - - return DroolsControllerConstants.getFactory().build(droolsControllerConfig, null, noopTopics); + PolicyEndPointProperties.PROPERTY_NOOP_SINK_TOPICS + "." + JUNIT_PROTOCOL_CODER_TOPIC + + PolicyEndPointProperties.PROPERTY_TOPIC_EVENTS_SUFFIX, + ThreeStrings.class.getName()); + return droolsControllerConfig; } private JsonProtocolFilter createFilterSet() { diff --git a/policy-management/src/test/java/org/onap/policy/drools/protocol/coders/TopicCoderFilterConfigurationTest.java b/policy-management/src/test/java/org/onap/policy/drools/protocol/coders/TopicCoderFilterConfigurationTest.java new file mode 100644 index 00000000..5429a94e --- /dev/null +++ b/policy-management/src/test/java/org/onap/policy/drools/protocol/coders/TopicCoderFilterConfigurationTest.java @@ -0,0 +1,75 @@ +/*- + * ============LICENSE_START=============================================== + * ONAP + * ======================================================================== + * Copyright (C) 2024 Nordix Foundation. + * ======================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END================================================= + */ + +package org.onap.policy.drools.protocol.coders; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import java.util.List; +import org.junit.jupiter.api.Test; + +class TopicCoderFilterConfigurationTest { + + @Test + void setCustomGsonCoder() { + var topic = "topic"; + var decodeFilter = new TopicCoderFilterConfiguration + .PotentialCoderFilter("codedClass", new JsonProtocolFilter("rule")); + var customCoder = new TopicCoderFilterConfiguration + .CustomGsonCoder("className", "staticCoderField"); + var topicConfig = new TopicCoderFilterConfiguration(topic, List.of(decodeFilter), customCoder); + + assertNotNull(topicConfig); + assertNotNull(topicConfig.getCoderFilters()); + assertEquals("topic", topicConfig.getTopic()); + + assertEquals("className", topicConfig.getCustomGsonCoder().getClassContainer()); + + var customCoder2 = new TopicCoderFilterConfiguration.CustomGsonCoder("className2,staticCoderField2"); + topicConfig.setCustomGsonCoder(customCoder2); + + assertEquals("className2", topicConfig.getCustomGsonCoder().getClassContainer()); + } + + @Test + void setCustomCoder_Exceptions() { + assertThatThrownBy(() -> new TopicCoderFilterConfiguration.CustomGsonCoder("", "staticCoderField")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("No classname to create CustomCoder cannot be created"); + + assertThatThrownBy(() -> new TopicCoderFilterConfiguration.CustomGsonCoder("className", "")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("No staticCoderField to create CustomCoder cannot be created for class className"); + + assertThatThrownBy(() -> new TopicCoderFilterConfiguration.CustomGsonCoder(",staticCoderField")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("No classname to create CustomCoder cannot be created"); + + assertThatThrownBy(() -> new TopicCoderFilterConfiguration.CustomGsonCoder("className,")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("No staticCoderField to create CustomCoder cannot be created for class className"); + + assertThatThrownBy(() -> new TopicCoderFilterConfiguration.CustomGsonCoder("")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Constructor argument cannot be empty."); + } +}
\ No newline at end of file diff --git a/policy-management/src/test/java/org/onap/policy/drools/server/restful/RestManagerTest.java b/policy-management/src/test/java/org/onap/policy/drools/server/restful/RestManagerTest.java new file mode 100644 index 00000000..89cce098 --- /dev/null +++ b/policy-management/src/test/java/org/onap/policy/drools/server/restful/RestManagerTest.java @@ -0,0 +1,1221 @@ +/* + * ============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.server.restful; + +import static jakarta.ws.rs.core.Response.Status.BAD_REQUEST; +import static jakarta.ws.rs.core.Response.Status.CREATED; +import static jakarta.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR; +import static jakarta.ws.rs.core.Response.Status.NOT_ACCEPTABLE; +import static jakarta.ws.rs.core.Response.Status.NOT_FOUND; +import static jakarta.ws.rs.core.Response.Status.NOT_MODIFIED; +import static jakarta.ws.rs.core.Response.Status.OK; +import static jakarta.ws.rs.core.Response.Status.PARTIAL_CONTENT; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +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.doNothing; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.when; +import static org.onap.policy.drools.properties.DroolsPropertyConstants.PROPERTY_CONTROLLER_NAME; + +import jakarta.ws.rs.core.Response; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; +import java.util.concurrent.ScheduledExecutorService; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.MockitoAnnotations; +import org.onap.policy.common.endpoints.event.comm.TopicEndpoint; +import org.onap.policy.common.endpoints.event.comm.TopicEndpointManager; +import org.onap.policy.drools.controller.DroolsController; +import org.onap.policy.drools.controller.internal.NullDroolsController; +import org.onap.policy.drools.features.PolicyControllerFeatureApi; +import org.onap.policy.drools.features.PolicyEngineFeatureApi; +import org.onap.policy.drools.protocol.coders.EventProtocolCoder; +import org.onap.policy.drools.protocol.coders.EventProtocolCoderConstants; +import org.onap.policy.drools.protocol.coders.JsonProtocolFilter; +import org.onap.policy.drools.protocol.coders.ProtocolCoderToolset; +import org.onap.policy.drools.protocol.configuration.ControllerConfiguration; +import org.onap.policy.drools.protocol.configuration.PdpdConfiguration; +import org.onap.policy.drools.system.PolicyController; +import org.onap.policy.drools.system.PolicyControllerConstants; +import org.onap.policy.drools.system.PolicyControllerFactory; +import org.onap.policy.drools.system.PolicyDroolsPdpRuntimeException; +import org.onap.policy.drools.system.PolicyEngineConstants; +import org.onap.policy.drools.system.PolicyEngineManager; +import org.onap.policy.drools.system.internal.AggregatedPolicyController; +import org.onap.policy.drools.system.internal.LockManager; +import org.slf4j.ILoggerFactory; +import org.slf4j.LoggerFactory; +import org.springframework.test.util.ReflectionTestUtils; + +class RestManagerTest { + + private static final String CONTROLLER_NAME = "myControllerName"; + private static final String FACT_CLASS = "factClass"; + private static final String TOPIC = "topic"; + private static final String GROUP_ID = "group"; + private static final String ARTIFACT_ID = "artifact"; + + @Mock + RestManager restApi; + + @Mock + PolicyControllerFactory controllerFactory; + + @Mock + EventProtocolCoder coderManager; + + @Mock + TopicEndpoint topicManager; + + @Mock + PolicyEngineManager policyEngineManager; + + AutoCloseable closeable; + + @BeforeEach + void setUp() { + closeable = MockitoAnnotations.openMocks(this); + + try (MockedStatic<TopicEndpointManager> constants = mockStatic(TopicEndpointManager.class)) { + setupTopicEndpointManager(constants); + restApi = mock(RestManager.class); + } + } + + @AfterEach + void tearDown() throws Exception { + closeable.close(); + } + + @Test + void swagger() { + when(restApi.swagger()).thenCallRealMethod(); + var response = restApi.swagger(); + assertNotNull(response); + assertInstanceOf(Response.class, response); + assertEquals(OK.getStatusCode(), response.getStatus()); + + when(restApi.getSwaggerContents()).thenThrow(new PolicyDroolsPdpRuntimeException("exception")); + + response = restApi.swagger(); + assertNotNull(response); + assertInstanceOf(Response.class, response); + assertEquals(INTERNAL_SERVER_ERROR.getStatusCode(), response.getStatus()); + } + + @Test + void engineShutdown() { + try (MockedStatic<PolicyEngineConstants> constants = mockStatic(PolicyEngineConstants.class)) { + setupLockManagerAndExecutorService(); + + doNothing().doThrow(new IllegalStateException("should throw exception")) + .when(policyEngineManager).shutdown(); + + setupPolicyEngineManager(constants); + + restApi = mock(RestManager.class); + + when(restApi.engineShutdown()).thenCallRealMethod(); + + var response = restApi.engineShutdown(); + assertNotNull(response); + assertInstanceOf(Response.class, response); + assertEquals(OK.getStatusCode(), response.getStatus()); + + response = restApi.engineShutdown(); + assertEquals(BAD_REQUEST.getStatusCode(), response.getStatus()); + } + } + + @Test + void engineFeature() { + try (MockedStatic<PolicyEngineConstants> constants = mockStatic(PolicyEngineConstants.class)) { + setupLockManagerAndExecutorService(); + when(policyEngineManager.getFeatureProvider("testFeature")) + .thenReturn(mock(PolicyEngineFeatureApi.class)) + .thenThrow(new IllegalArgumentException("should throw exception")); + + setupPolicyEngineManager(constants); + + restApi = mock(RestManager.class); + when(restApi.engineFeature("testFeature")).thenCallRealMethod(); + + var response = restApi.engineFeature("testFeature"); + assertNotNull(response); + assertInstanceOf(Response.class, response); + assertEquals(OK.getStatusCode(), response.getStatus()); + + response = restApi.engineFeature("testFeature"); + assertEquals(NOT_FOUND.getStatusCode(), response.getStatus()); + assertEquals("should throw exception", ((RestManager.Error) response.getEntity()).getError()); + } + } + + @Test + void engineUpdate() { + try (MockedStatic<PolicyEngineConstants> constants = mockStatic(PolicyEngineConstants.class)) { + setupLockManagerAndExecutorService(); + var pdpdConfig = mock(PdpdConfiguration.class); + when(policyEngineManager.configure(pdpdConfig)) + .thenReturn(true) + .thenReturn(false) + .thenThrow(new IllegalArgumentException("should throw exception")); + + setupPolicyEngineManager(constants); + + restApi = mock(RestManager.class); + when(restApi.engineUpdate(pdpdConfig)).thenCallRealMethod(); + + var response = restApi.engineUpdate(pdpdConfig); + assertNotNull(response); + assertInstanceOf(Response.class, response); + assertEquals(OK.getStatusCode(), response.getStatus()); + + response = restApi.engineUpdate(pdpdConfig); + assertEquals(NOT_ACCEPTABLE.getStatusCode(), response.getStatus()); + + // call again, should be going on exception + response = restApi.engineUpdate(pdpdConfig); + assertEquals(NOT_ACCEPTABLE.getStatusCode(), response.getStatus()); + } + } + + @Test + void engineActivation() { + try (MockedStatic<PolicyEngineConstants> constants = mockStatic(PolicyEngineConstants.class)) { + setupLockManagerAndExecutorService(); + doNothing().doThrow(new IllegalStateException("should throw exception")) + .when(policyEngineManager).activate(); + + setupPolicyEngineManager(constants); + + restApi = mock(RestManager.class); + when(restApi.engineActivation()).thenCallRealMethod(); + + var response = restApi.engineActivation(); + assertNotNull(response); + assertInstanceOf(Response.class, response); + assertEquals(OK.getStatusCode(), response.getStatus()); + + response = restApi.engineActivation(); + assertEquals(NOT_ACCEPTABLE.getStatusCode(), response.getStatus()); + } + } + + @Test + void engineDeactivation() { + try (MockedStatic<PolicyEngineConstants> constants = mockStatic(PolicyEngineConstants.class)) { + setupLockManagerAndExecutorService(); + doNothing().doThrow(new IllegalStateException("should throw exception")) + .when(policyEngineManager).deactivate(); + + setupPolicyEngineManager(constants); + + restApi = mock(RestManager.class); + when(restApi.engineDeactivation()).thenCallRealMethod(); + + var response = restApi.engineDeactivation(); + assertNotNull(response); + assertInstanceOf(Response.class, response); + assertEquals(OK.getStatusCode(), response.getStatus()); + + response = restApi.engineDeactivation(); + assertEquals(NOT_ACCEPTABLE.getStatusCode(), response.getStatus()); + } + } + + @Test + void controllerAdd() { + try (MockedStatic<PolicyControllerConstants> controllerConst = mockStatic(PolicyControllerConstants.class)) { + try (MockedStatic<PolicyEngineConstants> engConst = mockStatic(PolicyEngineConstants.class)) { + setupLockManagerAndExecutorService(); + + when(controllerFactory.get(CONTROLLER_NAME)) + .thenReturn(mock(AggregatedPolicyController.class)) + .thenThrow(new IllegalStateException("exception to test fetch policy failed")) + .thenReturn(null); + + setupPolicyControllerFactory(controllerConst); + + var invalidProps = new Properties(); + invalidProps.setProperty(PROPERTY_CONTROLLER_NAME, ""); + + var properties = new Properties(); + properties.setProperty(PROPERTY_CONTROLLER_NAME, CONTROLLER_NAME); + + var policyController = mock(PolicyController.class); + when(policyController.start()) + .thenReturn(false) + .thenThrow(new IllegalStateException("exception when starting controller")) + .thenReturn(true); + + when(policyEngineManager.createPolicyController(CONTROLLER_NAME, properties)) + .thenThrow(new IllegalArgumentException("exception creating controller")) + .thenReturn(policyController); + + setupPolicyEngineManager(engConst); + + restApi = mock(RestManager.class); + + when(restApi.controllerAdd(null)).thenCallRealMethod(); + when(restApi.controllerAdd(invalidProps)).thenCallRealMethod(); + when(restApi.controllerAdd(properties)).thenCallRealMethod(); + + // first test - null properties config + var response = restApi.controllerAdd(null); + assertNotNull(response); + assertInstanceOf(Response.class, response); + assertEquals(BAD_REQUEST.getStatusCode(), response.getStatus()); + + // second test - controllerName is empty + response = restApi.controllerAdd(invalidProps); + assertEquals(BAD_REQUEST.getStatusCode(), response.getStatus()); + assertThat(((RestManager.Error) response.getEntity()).getError()) + .contains("Configuration must have an entry for controller.name"); + + // third test - controller exists + response = restApi.controllerAdd(properties); + assertEquals(NOT_MODIFIED.getStatusCode(), response.getStatus()); + + // fourth test - IllegalStateException + response = restApi.controllerAdd(properties); + assertEquals(NOT_ACCEPTABLE.getStatusCode(), response.getStatus()); + assertThat(((RestManager.Error) response.getEntity()).getError()) + .contains("myControllerName not found"); + + // fifth test - cannot create controller + response = restApi.controllerAdd(properties); + assertEquals(BAD_REQUEST.getStatusCode(), response.getStatus()); + assertThat(((RestManager.Error) response.getEntity()).getError()) + .contains("exception creating controller"); + + // sixth test - cannot start controller + response = restApi.controllerAdd(properties); + assertEquals(PARTIAL_CONTENT.getStatusCode(), response.getStatus()); + assertThat(((RestManager.Error) response.getEntity()).getError()) + .contains("myControllerName can't be started"); + + // seventh test - cannot start controller but Exception + response = restApi.controllerAdd(properties); + assertEquals(PARTIAL_CONTENT.getStatusCode(), response.getStatus()); + assertEquals(policyController, response.getEntity()); + + // final test - works + response = restApi.controllerAdd(properties); + assertEquals(CREATED.getStatusCode(), response.getStatus()); + assertEquals(policyController, response.getEntity()); + } + } + } + + @Test + void controllerFeature() { + try (MockedStatic<PolicyControllerConstants> controllerConst = mockStatic(PolicyControllerConstants.class)) { + var myFeature = mock(PolicyControllerFeatureApi.class); + when(controllerFactory.getFeatureProvider("myFeature")) + .thenReturn(myFeature) + .thenThrow(new IllegalArgumentException("exception when getting feature")); + setupPolicyControllerFactory(controllerConst); + + restApi = mock(RestManager.class); + when(restApi.controllerFeature("myFeature")).thenCallRealMethod(); + + var response = restApi.controllerFeature("myFeature"); + assertNotNull(response); + assertInstanceOf(Response.class, response); + assertEquals(OK.getStatusCode(), response.getStatus()); + assertEquals(myFeature, response.getEntity()); + + response = restApi.controllerFeature("myFeature"); + assertEquals(NOT_FOUND.getStatusCode(), response.getStatus()); + assertThat(((RestManager.Error) response.getEntity()).getError()) + .contains("exception when getting feature"); + } + } + + @Test + void controllerDelete() { + try (MockedStatic<PolicyControllerConstants> controllerConst = mockStatic(PolicyControllerConstants.class)) { + try (MockedStatic<PolicyEngineConstants> engConst = mockStatic(PolicyEngineConstants.class)) { + setupLockManagerAndExecutorService(); + + var policyController = mock(PolicyController.class); + + when(controllerFactory.get("nullController")) + .thenReturn(null); + when(controllerFactory.get("exceptionController")) + .thenThrow(new IllegalArgumentException("can't find the controller")) + .thenThrow(new IllegalStateException("exception to test fetch policy controller")); + when(controllerFactory.get("myValidController")).thenReturn(policyController); + + setupPolicyControllerFactory(controllerConst); + + doThrow(new IllegalStateException("exception when deleting controller")) + .doNothing() + .when(policyEngineManager).removePolicyController("myValidController"); + + setupPolicyEngineManager(engConst); + + restApi = mock(RestManager.class); + when(restApi.controllerDelete(anyString())).thenCallRealMethod(); + + // first test - controller returns null + var response = restApi.controllerDelete("nullController"); + assertNotNull(response); + assertInstanceOf(Response.class, response); + assertEquals(BAD_REQUEST.getStatusCode(), response.getStatus()); + assertThat(((RestManager.Error) response.getEntity()).getError()) + .contains("nullController does not exist"); + + // second test - getController throws IllegalArgExc + response = restApi.controllerDelete("exceptionController"); + assertEquals(BAD_REQUEST.getStatusCode(), response.getStatus()); + assertThat(((RestManager.Error) response.getEntity()).getError()) + .contains("can't find the controller"); + + // third test - getController throws IllegalStateExc + response = restApi.controllerDelete("exceptionController"); + assertEquals(NOT_ACCEPTABLE.getStatusCode(), response.getStatus()); + assertThat(((RestManager.Error) response.getEntity()).getError()) + .contains("exceptionController not acceptable"); + + // fourth test - gets controller but exception when removing + response = restApi.controllerDelete("myValidController"); + assertEquals(INTERNAL_SERVER_ERROR.getStatusCode(), response.getStatus()); + assertThat(((RestManager.Error) response.getEntity()).getError()) + .contains("exception when deleting controller"); + + // fifth test - gets controller and removes it from engine manager + response = restApi.controllerDelete("myValidController"); + assertEquals(OK.getStatusCode(), response.getStatus()); + assertEquals(policyController, response.getEntity()); + } + } + } + + @Test + void controllerUpdate() { + try (MockedStatic<PolicyEngineConstants> constants = mockStatic(PolicyEngineConstants.class)) { + setupLockManagerAndExecutorService(); + + var config = mock(ControllerConfiguration.class); + when(config.getName()).thenReturn(CONTROLLER_NAME); + + var policyController = mock(PolicyController.class); + when(policyEngineManager.updatePolicyController(config)) + .thenThrow(new IllegalArgumentException("exception to test fetch policy controller")) + .thenReturn(null) + .thenReturn(policyController); + + setupPolicyEngineManager(constants); + + restApi = mock(RestManager.class); + when(restApi.catchArgStateGenericEx(any(), any())).thenCallRealMethod(); + when(restApi.controllerUpdate(config, "invalidName")).thenCallRealMethod(); + when(restApi.controllerUpdate(config, CONTROLLER_NAME)).thenCallRealMethod(); + when(restApi.controllerUpdate(null, CONTROLLER_NAME)).thenCallRealMethod(); + when(restApi.controllerUpdate(config, "")).thenCallRealMethod(); + + // invalid controller name + var response = restApi.controllerUpdate(config, ""); + assertNotNull(response); + assertInstanceOf(Response.class, response); + assertEquals(BAD_REQUEST.getStatusCode(), response.getStatus()); + + // controller configuration is null + response = restApi.controllerUpdate(null, CONTROLLER_NAME); + assertEquals(BAD_REQUEST.getStatusCode(), response.getStatus()); + + // controller name doesn't match name in configuration + response = restApi.controllerUpdate(config, "invalidName"); + assertEquals(BAD_REQUEST.getStatusCode(), response.getStatus()); + + // IllegalArgException + response = restApi.controllerUpdate(config, CONTROLLER_NAME); + assertEquals(NOT_FOUND.getStatusCode(), response.getStatus()); + + // return null controller + response = restApi.controllerUpdate(config, CONTROLLER_NAME); + assertEquals(BAD_REQUEST.getStatusCode(), response.getStatus()); + + // return valid controller + response = restApi.controllerUpdate(config, CONTROLLER_NAME); + assertEquals(OK.getStatusCode(), response.getStatus()); + assertEquals(policyController, response.getEntity()); + } + } + + @Test + void controllerLock() { + try (MockedStatic<PolicyControllerConstants> controllerConst = mockStatic(PolicyControllerConstants.class)) { + var policyController = mock(PolicyController.class); + when(policyController.lock()) + .thenReturn(true) + .thenReturn(false); + + when(controllerFactory.get(CONTROLLER_NAME)).thenReturn(policyController); + + setupPolicyControllerFactory(controllerConst); + + restApi = mock(RestManager.class); + + when(restApi.controllerLock(CONTROLLER_NAME)).thenCallRealMethod(); + + // controller lock + var response = restApi.controllerLock(CONTROLLER_NAME); + assertNotNull(response); + assertInstanceOf(Response.class, response); + assertEquals(OK.getStatusCode(), response.getStatus()); + assertEquals(policyController, response.getEntity()); + + // controller fails to lock + response = restApi.controllerLock(CONTROLLER_NAME); + assertEquals(NOT_ACCEPTABLE.getStatusCode(), response.getStatus()); + assertThat(((RestManager.Error) response.getEntity()).getError()) + .contains("myControllerName cannot be locked"); + } + } + + @Test + void controllerUnlock() { + try (MockedStatic<PolicyControllerConstants> controllerConst = mockStatic(PolicyControllerConstants.class)) { + var policyController = mock(PolicyController.class); + when(policyController.unlock()) + .thenReturn(true) + .thenReturn(false); + + when(controllerFactory.get(CONTROLLER_NAME)).thenReturn(policyController); + + setupPolicyControllerFactory(controllerConst); + + restApi = mock(RestManager.class); + + when(restApi.controllerUnlock(CONTROLLER_NAME)).thenCallRealMethod(); + + // controller unlock + var response = restApi.controllerUnlock(CONTROLLER_NAME); + assertNotNull(response); + assertInstanceOf(Response.class, response); + assertEquals(OK.getStatusCode(), response.getStatus()); + assertEquals(policyController, response.getEntity()); + + // controller fails to unlock + response = restApi.controllerUnlock(CONTROLLER_NAME); + assertEquals(NOT_ACCEPTABLE.getStatusCode(), response.getStatus()); + assertThat(((RestManager.Error) response.getEntity()).getError()) + .contains("myControllerName cannot be unlocked"); + } + } + + @Test + void droolsFactsDelete() { + try (MockedStatic<PolicyControllerConstants> controllerConst = mockStatic(PolicyControllerConstants.class)) { + var sessionName = "sessionName"; + var queryName = "queryName"; + var queriedEntity = "queriedEntity"; + + var drools = mock(NullDroolsController.class); + when(drools.factQuery(sessionName, queryName, queriedEntity, true)) + .thenReturn(new ArrayList<>(List.of())); + var policyController = mock(PolicyController.class); + when(policyController.getDrools()).thenReturn(drools); + + var controllerWithoutDrools = mock(PolicyController.class); + when(controllerWithoutDrools.getDrools()).thenReturn(null); + + when(controllerFactory.get("nullController")).thenReturn(null); + when(controllerFactory.get("controllerWithoutDrools")).thenReturn(controllerWithoutDrools); + when(controllerFactory.get(CONTROLLER_NAME)).thenReturn(policyController); + + setupPolicyControllerFactory(controllerConst); + + restApi = mock(RestManager.class); + + when(restApi.catchArgStateGenericEx(any(), any())).thenCallRealMethod(); + when(restApi.getDroolsController(anyString())).thenCallRealMethod(); + when(restApi.droolsFactsDelete("nullController", sessionName, queryName, queriedEntity)) + .thenCallRealMethod(); + when(restApi.droolsFactsDelete("controllerWithoutDrools", sessionName, queryName, queriedEntity)) + .thenCallRealMethod(); + when(restApi.droolsFactsDelete(CONTROLLER_NAME, sessionName, queryName, queriedEntity)) + .thenCallRealMethod(); + + // controller is null + var response = restApi.droolsFactsDelete("nullController", sessionName, queryName, queriedEntity); + assertNotNull(response); + assertInstanceOf(Response.class, response); + assertEquals(NOT_FOUND.getStatusCode(), response.getStatus()); + assertEquals("nullController:sessionName:queryName:queriedEntity not found", + ((RestManager.Error) response.getEntity()).getError()); + + // controller has no drools + response = restApi.droolsFactsDelete("controllerWithoutDrools", sessionName, queryName, queriedEntity); + assertEquals(NOT_FOUND.getStatusCode(), response.getStatus()); + assertEquals("controllerWithoutDrools:sessionName:queryName:queriedEntity not found", + ((RestManager.Error) response.getEntity()).getError()); + + // delete works + response = restApi.droolsFactsDelete(CONTROLLER_NAME, sessionName, queryName, queriedEntity); + assertEquals(OK.getStatusCode(), response.getStatus()); + assertInstanceOf(List.class, response.getEntity()); + } + } + + @Test + void rules() { + when(restApi.rules(anyString())).thenCallRealMethod(); + var response = restApi.rules("expression"); + assertNotNull(response); + assertInstanceOf(Response.class, response); + assertEquals(OK.getStatusCode(), response.getStatus()); + } + + @Test + void decoderFilter2() { + try (MockedStatic<EventProtocolCoderConstants> constants = mockStatic(EventProtocolCoderConstants.class)) { + var decoder = mock(ProtocolCoderToolset.class); + when(decoder.getCoders()).thenReturn(new ArrayList<>(List.of())); + when(coderManager.getDecoders(GROUP_ID, ARTIFACT_ID, TOPIC)) + .thenReturn(decoder); + when(coderManager.getDecoders(GROUP_ID, ARTIFACT_ID, "invalidTopic")) + .thenReturn(null); + + setupEventProtocolManager(constants); + + var drools = getDroolsControllerWithGroupArtifact(); + restApi = mock(RestManager.class); + when(restApi.getDroolsController(CONTROLLER_NAME)).thenReturn(drools); + when(restApi.catchArgStateGenericEx(any(), any())).thenCallRealMethod(); + when(restApi.decoderFilter2(anyString(), anyString())).thenCallRealMethod(); + when(restApi.getDroolsController("noDecoderCtrl")).thenReturn(drools); + when(restApi.getDroolsController("exceptionCtrl")) + .thenThrow(new IllegalArgumentException("exceptionCtrl")); + + // should be ok + var response = restApi.decoderFilter2(CONTROLLER_NAME, TOPIC); + assertNotNull(response); + assertInstanceOf(Response.class, response); + assertEquals(OK.getStatusCode(), response.getStatus()); + assertInstanceOf(List.class, response.getEntity()); + + // controller has no decoder + response = restApi.decoderFilter2("noDecoderCtrl", "invalidTopic"); + assertNotNull(response); + assertInstanceOf(Response.class, response); + assertEquals(BAD_REQUEST.getStatusCode(), response.getStatus()); + + // can't get a controller + response = restApi.decoderFilter2("exceptionCtrl", TOPIC); + assertNotNull(response); + assertInstanceOf(Response.class, response); + assertEquals(NOT_FOUND.getStatusCode(), response.getStatus()); + } + } + + @Test + void decoderFilter1() { + try (MockedStatic<EventProtocolCoderConstants> constants = mockStatic(EventProtocolCoderConstants.class)) { + var decoder = mock(ProtocolCoderToolset.class); + when(decoder.getCoder(FACT_CLASS)).thenReturn(mock(EventProtocolCoder.CoderFilters.class)); + when(decoder.getCoder("invalidClass")).thenReturn(null); + + when(coderManager.getDecoders(GROUP_ID, ARTIFACT_ID, TOPIC)) + .thenReturn(decoder); + when(coderManager.getDecoders(GROUP_ID, ARTIFACT_ID, "invalidTopic")) + .thenThrow(new IllegalArgumentException("exception")); + + setupEventProtocolManager(constants); + + var drools = getDroolsControllerWithGroupArtifact(); + restApi = mock(RestManager.class); + when(restApi.getDroolsController(CONTROLLER_NAME)).thenReturn(drools); + when(restApi.catchArgStateGenericEx(any(), any())).thenCallRealMethod(); + when(restApi.decoderFilter1(anyString(), anyString(), anyString())).thenCallRealMethod(); + + // should be ok + var response = restApi.decoderFilter1(CONTROLLER_NAME, TOPIC, FACT_CLASS); + assertNotNull(response); + assertInstanceOf(Response.class, response); + assertEquals(OK.getStatusCode(), response.getStatus()); + assertInstanceOf(EventProtocolCoder.CoderFilters.class, response.getEntity()); + + // controller has no decoder + response = restApi.decoderFilter1(CONTROLLER_NAME, TOPIC, "invalidClass"); + assertNotNull(response); + assertInstanceOf(Response.class, response); + assertEquals(BAD_REQUEST.getStatusCode(), response.getStatus()); + + // can't get a controller + response = restApi.decoderFilter1(CONTROLLER_NAME, "invalidTopic", FACT_CLASS); + assertNotNull(response); + assertInstanceOf(Response.class, response); + assertEquals(NOT_FOUND.getStatusCode(), response.getStatus()); + } + } + + @Test + void decoderFilter() { + try (MockedStatic<EventProtocolCoderConstants> constants = mockStatic(EventProtocolCoderConstants.class)) { + var coderFilter = new EventProtocolCoder.CoderFilters(FACT_CLASS, new JsonProtocolFilter(), 1); + + var decoder = mock(ProtocolCoderToolset.class); + when(decoder.getCoder(FACT_CLASS)).thenReturn(coderFilter); + when(decoder.getCoder("invalidClass")).thenReturn(null); + + when(coderManager.getDecoders(GROUP_ID, ARTIFACT_ID, TOPIC)) + .thenReturn(decoder); + when(coderManager.getDecoders(GROUP_ID, ARTIFACT_ID, "invalidTopic")) + .thenThrow(new IllegalArgumentException("exception")); + + setupEventProtocolManager(constants); + + + restApi = mock(RestManager.class); + var configFilters = new JsonProtocolFilter(); + when(restApi.decoderFilter(eq(configFilters), eq(CONTROLLER_NAME), anyString(), + anyString())).thenCallRealMethod(); + when(restApi.catchArgStateGenericEx(any(), any())).thenCallRealMethod(); + when(restApi.decoderFilter(isNull(), eq(CONTROLLER_NAME), anyString(), anyString())).thenCallRealMethod(); + var drools = getDroolsControllerWithGroupArtifact(); + when(restApi.getDroolsController(CONTROLLER_NAME)).thenReturn(drools); + + // should be ok + var response = restApi.decoderFilter(configFilters, CONTROLLER_NAME, TOPIC, FACT_CLASS); + assertNotNull(response); + assertInstanceOf(Response.class, response); + assertEquals(OK.getStatusCode(), response.getStatus()); + if (response.getEntity() instanceof EventProtocolCoder.CoderFilters) { + var filters = (EventProtocolCoder.CoderFilters) response.getEntity(); + assertEquals(configFilters, filters.getFilter()); + } + + // controller has no decoder + response = restApi.decoderFilter(configFilters, CONTROLLER_NAME, TOPIC, "invalidClass"); + assertNotNull(response); + assertEquals(BAD_REQUEST.getStatusCode(), response.getStatus()); + + // can't get a controller + response = restApi.decoderFilter(configFilters, CONTROLLER_NAME, "invalidTopic", FACT_CLASS); + assertNotNull(response); + assertEquals(NOT_FOUND.getStatusCode(), response.getStatus()); + + // can't get a controller + response = restApi.decoderFilter(null, CONTROLLER_NAME, "invalidTopic", "invalidClass"); + assertNotNull(response); + assertEquals(BAD_REQUEST.getStatusCode(), response.getStatus()); + } + } + + @Test + void decoderFilterRules() { + when(restApi.catchArgStateGenericEx(any(), any())).thenCallRealMethod(); + when(restApi.decoderFilterRules(anyString(), anyString(), anyString())).thenCallRealMethod(); + + when(restApi.checkControllerDecoderAndFilter(CONTROLLER_NAME, TOPIC, FACT_CLASS)) + .thenReturn(new JsonProtocolFilter()); + when(restApi.checkControllerDecoderAndFilter(CONTROLLER_NAME, TOPIC, "invalidClass")) + .thenReturn(Response.status(BAD_REQUEST).build()); + // trying to trigger RuntimeException for code coverage - normally it wouldn't happen here + when(restApi.checkControllerDecoderAndFilter("invalidController", TOPIC, FACT_CLASS)) + .thenReturn(null); + + // should return a string rule + var response = restApi.decoderFilterRules(CONTROLLER_NAME, TOPIC, FACT_CLASS); + assertNotNull(response); + assertInstanceOf(Response.class, response); + assertEquals(OK.getStatusCode(), response.getStatus()); + assertInstanceOf(String.class, response.getEntity()); + + // checkControllerEtc... returned error response, so it just returns it to function + response = restApi.decoderFilterRules(CONTROLLER_NAME, TOPIC, "invalidClass"); + assertEquals(BAD_REQUEST.getStatusCode(), response.getStatus()); + + // the runtime exception + response = restApi.decoderFilterRules("invalidController", TOPIC, FACT_CLASS); + assertEquals(INTERNAL_SERVER_ERROR.getStatusCode(), response.getStatus()); + } + + @Test + void decoderFilterRuleDelete() { + when(restApi.catchArgStateGenericEx(any(), any())).thenCallRealMethod(); + when(restApi.decoderFilterRuleDelete(anyString(), anyString(), anyString())).thenCallRealMethod(); + + when(restApi.checkControllerDecoderAndFilter(CONTROLLER_NAME, TOPIC, FACT_CLASS)) + .thenReturn(new JsonProtocolFilter()); + when(restApi.checkControllerDecoderAndFilter(CONTROLLER_NAME, TOPIC, "invalidClass")) + .thenReturn(Response.status(BAD_REQUEST).build()); + + // should return a string rule + var response = restApi.decoderFilterRuleDelete(CONTROLLER_NAME, TOPIC, FACT_CLASS); + assertNotNull(response); + assertInstanceOf(Response.class, response); + assertEquals(OK.getStatusCode(), response.getStatus()); + assertInstanceOf(String.class, response.getEntity()); + + // checkControllerEtc... returned error response, so it just returns it to function + response = restApi.decoderFilterRuleDelete(CONTROLLER_NAME, TOPIC, "invalidClass"); + assertEquals(BAD_REQUEST.getStatusCode(), response.getStatus()); + } + + @Test + void decoderFilterRule() { + when(restApi.catchArgStateGenericEx(any(), any())).thenCallRealMethod(); + when(restApi.decoderFilterRule(anyString(), anyString(), anyString(), anyString())).thenCallRealMethod(); + + when(restApi.decoderFilterRule2(CONTROLLER_NAME, TOPIC, FACT_CLASS, "rule")) + .thenReturn(new JsonProtocolFilter().getRule()); + when(restApi.decoderFilterRule2(CONTROLLER_NAME, TOPIC, FACT_CLASS, "")) + .thenCallRealMethod(); + when(restApi.decoderFilterRule("invalidController", TOPIC, FACT_CLASS, "rule")) + .thenThrow(new IllegalArgumentException("invalid controller")); + + var response = restApi.decoderFilterRule(CONTROLLER_NAME, TOPIC, FACT_CLASS, "rule"); + assertNotNull(response); + assertInstanceOf(Response.class, response); + assertEquals(OK.getStatusCode(), response.getStatus()); + assertInstanceOf(String.class, response.getEntity()); + + response = restApi.decoderFilterRule(CONTROLLER_NAME, TOPIC, FACT_CLASS, ""); + assertEquals(BAD_REQUEST.getStatusCode(), response.getStatus()); + assertInstanceOf(RestManager.Error.class, response.getEntity()); + + response = restApi.decoderFilterRule("invalidController", TOPIC, FACT_CLASS, "rule"); + assertEquals(NOT_FOUND.getStatusCode(), response.getStatus()); + assertInstanceOf(RestManager.Error.class, response.getEntity()); + } + + @Test + void decode_EmptyParams() { + when(restApi.decode(anyString(), anyString(), anyString())).thenCallRealMethod(); + + var response = restApi.decode(CONTROLLER_NAME, "", "json"); + assertNotNull(response); + assertInstanceOf(Response.class, response); + assertEquals(NOT_ACCEPTABLE.getStatusCode(), response.getStatus()); + + response = restApi.decode("", TOPIC, "json"); + assertNotNull(response); + assertInstanceOf(Response.class, response); + assertEquals(NOT_ACCEPTABLE.getStatusCode(), response.getStatus()); + } + + @Test + void decode() { + try (MockedStatic<EventProtocolCoderConstants> constants = mockStatic(EventProtocolCoderConstants.class)) { + var event = new Object(); + when(coderManager.decode(GROUP_ID, ARTIFACT_ID, TOPIC, "json")).thenReturn(event); + when(coderManager.decode(GROUP_ID, ARTIFACT_ID, "otherTopic", "json")).thenReturn(event); + when(coderManager.decode(GROUP_ID, ARTIFACT_ID, TOPIC, "invalidJson")) + .thenThrow(new IllegalArgumentException("invalid json")); + + when(coderManager.encode(TOPIC, event)).thenReturn("json"); + when(coderManager.encode("otherTopic", event)) + .thenThrow(new IllegalArgumentException("invalid topic")); + + setupEventProtocolManager(constants); + + var drools = getDroolsControllerWithGroupArtifact(); + + restApi = mock(RestManager.class); + when(restApi.getDroolsController(CONTROLLER_NAME)).thenReturn(drools); + when(restApi.decode(anyString(), anyString(), anyString())).thenCallRealMethod(); + + // should work + var response = restApi.decode(CONTROLLER_NAME, TOPIC, "json"); + assertNotNull(response); + assertInstanceOf(Response.class, response); + assertEquals(OK.getStatusCode(), response.getStatus()); + assertNotNull(response.getEntity()); + if (response.getEntity() instanceof RestManager.CodingResult) { + var codingResult = (RestManager.CodingResult) response.getEntity(); + assertTrue(codingResult.getDecoding()); + assertTrue(codingResult.getEncoding()); + assertEquals("json", codingResult.getJsonEncoding()); + } + + // can't decode + response = restApi.decode(CONTROLLER_NAME, TOPIC, "invalidJson"); + assertEquals(BAD_REQUEST.getStatusCode(), response.getStatus()); + + // can't encode, but return decoded result + response = restApi.decode(CONTROLLER_NAME, "otherTopic", "json"); + assertEquals(OK.getStatusCode(), response.getStatus()); + assertNotNull(response.getEntity()); + if (response.getEntity() instanceof RestManager.CodingResult) { + var codingResult = (RestManager.CodingResult) response.getEntity(); + assertTrue(codingResult.getDecoding()); + assertFalse(codingResult.getEncoding()); + assertNull(codingResult.getJsonEncoding()); + } + } + } + + @Test + void encoderFilters() { + try (MockedStatic<EventProtocolCoderConstants> constants = mockStatic(EventProtocolCoderConstants.class)) { + when(coderManager.getEncoderFilters(GROUP_ID, ARTIFACT_ID)) + .thenReturn(new ArrayList<>(List.of())); + + setupEventProtocolManager(constants); + + var drools = getDroolsControllerWithGroupArtifact(); + when(restApi.getDroolsController(CONTROLLER_NAME)).thenReturn(drools); + when(restApi.getDroolsController("invalidController")) + .thenThrow(new IllegalArgumentException("invalid controller")); + when(restApi.catchArgStateGenericEx(any(), any())).thenCallRealMethod(); + when(restApi.encoderFilters(anyString())).thenCallRealMethod(); + + // should work + var response = restApi.encoderFilters(CONTROLLER_NAME); + assertNotNull(response); + assertInstanceOf(Response.class, response); + assertEquals(OK.getStatusCode(), response.getStatus()); + assertNotNull(response.getEntity()); + + // exceptions + response = restApi.encoderFilters("invalidController"); + assertEquals(NOT_FOUND.getStatusCode(), response.getStatus()); + } + } + + @Test + void topicsLock() { + try (MockedStatic<TopicEndpointManager> constants = mockStatic(TopicEndpointManager.class)) { + when(topicManager.lock()) + .thenReturn(true) + .thenReturn(false); + setupTopicEndpointManager(constants); + + restApi = mock(RestManager.class); + when(restApi.topicsLock()).thenCallRealMethod(); + + // should work and return ok + var response = restApi.topicsLock(); + assertNotNull(response); + assertInstanceOf(Response.class, response); + assertEquals(OK.getStatusCode(), response.getStatus()); + + // lock fails, return false + response = restApi.topicsLock(); + assertNotNull(response); + assertEquals(NOT_ACCEPTABLE.getStatusCode(), response.getStatus()); + } + } + + @Test + void topicsUnlock() { + try (MockedStatic<TopicEndpointManager> constants = mockStatic(TopicEndpointManager.class)) { + when(topicManager.unlock()) + .thenReturn(true) + .thenReturn(false); + setupTopicEndpointManager(constants); + + restApi = mock(RestManager.class); + when(restApi.topicsUnlock()).thenCallRealMethod(); + + // should work and return ok + var response = restApi.topicsUnlock(); + assertNotNull(response); + assertInstanceOf(Response.class, response); + assertEquals(OK.getStatusCode(), response.getStatus()); + + // lock fails, return false + response = restApi.topicsUnlock(); + assertNotNull(response); + assertEquals(NOT_ACCEPTABLE.getStatusCode(), response.getStatus()); + } + } + + @Test + void commSources() { + try (MockedStatic<TopicEndpointManager> constants = mockStatic(TopicEndpointManager.class)) { + when(topicManager.getNoopTopicSources()).thenReturn(new ArrayList<>(List.of())); + when(topicManager.getKafkaTopicSources()).thenReturn(new ArrayList<>(List.of())); + setupTopicEndpointManager(constants); + + restApi = mock(RestManager.class); + when(restApi.commSources(anyString())).thenCallRealMethod(); + + var response = restApi.commSources("noop"); + assertNotNull(response); + assertInstanceOf(Response.class, response); + assertEquals(OK.getStatusCode(), response.getStatus()); + + response = restApi.commSources("kafka"); + assertEquals(OK.getStatusCode(), response.getStatus()); + + // topic type rest valid not supported + response = restApi.commSources("rest"); + assertEquals(BAD_REQUEST.getStatusCode(), response.getStatus()); + + // empty topic type + response = restApi.commSources(""); + assertEquals(NOT_ACCEPTABLE.getStatusCode(), response.getStatus()); + } + } + + @Test + void commSinks() { + try (MockedStatic<TopicEndpointManager> constants = mockStatic(TopicEndpointManager.class)) { + when(topicManager.getNoopTopicSinks()).thenReturn(new ArrayList<>(List.of())); + when(topicManager.getKafkaTopicSinks()).thenReturn(new ArrayList<>(List.of())); + setupTopicEndpointManager(constants); + + restApi = mock(RestManager.class); + when(restApi.commSinks(anyString())).thenCallRealMethod(); + + var response = restApi.commSinks("noop"); + assertNotNull(response); + assertInstanceOf(Response.class, response); + assertEquals(OK.getStatusCode(), response.getStatus()); + + response = restApi.commSinks("kafka"); + assertEquals(OK.getStatusCode(), response.getStatus()); + + // topic type rest valid but not supported + response = restApi.commSinks("rest"); + assertEquals(BAD_REQUEST.getStatusCode(), response.getStatus()); + + // empty topic type + response = restApi.commSinks(""); + assertEquals(NOT_ACCEPTABLE.getStatusCode(), response.getStatus()); + } + } + + @Test + void loggers() { + try (MockedStatic<LoggerFactory> loggerFactory = mockStatic(LoggerFactory.class)) { + var mockFactory = mock(ILoggerFactory.class); + loggerFactory.when(LoggerFactory::getILoggerFactory).thenReturn(mockFactory); + + restApi = mock(RestManager.class); + when(restApi.loggers()).thenCallRealMethod(); + + var response = restApi.loggers(); + assertNotNull(response); + assertInstanceOf(Response.class, response); + assertEquals(INTERNAL_SERVER_ERROR.getStatusCode(), response.getStatus()); + } + } + + @Test + void loggerName1() { + try (MockedStatic<LoggerFactory> loggerFactory = mockStatic(LoggerFactory.class)) { + var mockFactory = mock(ILoggerFactory.class); + loggerFactory.when(LoggerFactory::getILoggerFactory).thenReturn(mockFactory); + + restApi = mock(RestManager.class); + when(restApi.loggerName1(anyString())).thenCallRealMethod(); + + var response = restApi.loggerName1("logger1"); + assertNotNull(response); + assertInstanceOf(Response.class, response); + assertEquals(INTERNAL_SERVER_ERROR.getStatusCode(), response.getStatus()); + } + } + + @Test + void loggerName_EmptyValues() { + when(restApi.loggerName(anyString(), anyString())).thenCallRealMethod(); + + var response = restApi.loggerName("", "info"); + assertNotNull(response); + assertInstanceOf(Response.class, response); + assertEquals(NOT_ACCEPTABLE.getStatusCode(), response.getStatus()); + assertThat(((RestManager.Error) response.getEntity()).getError()) + .contains("logger name: not acceptable"); + + response = restApi.loggerName("logger1", ""); + assertNotNull(response); + assertInstanceOf(Response.class, response); + assertEquals(NOT_ACCEPTABLE.getStatusCode(), response.getStatus()); + assertThat(((RestManager.Error) response.getEntity()).getError()) + .contains("logger level: not acceptable"); + } + + @Test + void testLoggerName_Exceptions() { + when(restApi.loggerName(anyString(), anyString())).thenCallRealMethod(); + + var response = restApi.loggerName("audit", "abc"); + assertNotNull(response); + assertInstanceOf(Response.class, response); + assertEquals(INTERNAL_SERVER_ERROR.getStatusCode(), response.getStatus()); + } + + @Test + void testCheckControllerDecoderAndFilter() { + try (MockedStatic<EventProtocolCoderConstants> constants = mockStatic(EventProtocolCoderConstants.class)) { + var coderFilter = new EventProtocolCoder.CoderFilters(FACT_CLASS, new JsonProtocolFilter(), 1); + var decoder = mock(ProtocolCoderToolset.class); + when(decoder.getCoder(FACT_CLASS)).thenReturn(coderFilter); + + when(coderManager.getDecoders(GROUP_ID, ARTIFACT_ID, TOPIC)) + .thenReturn(decoder); + + var decoderWithoutFactClass = mock(ProtocolCoderToolset.class); + when(decoderWithoutFactClass.getCoder("noFactClass")).thenReturn(null); + when(coderManager.getDecoders(GROUP_ID, ARTIFACT_ID, "topic2")) + .thenReturn(decoderWithoutFactClass); + + var coderFactClassWithoutFilter = mock(EventProtocolCoder.CoderFilters.class); + when(coderFactClassWithoutFilter.getFilter()).thenReturn(null); + var decoderWithoutFilter = mock(ProtocolCoderToolset.class); + when(decoderWithoutFilter.getCoder("noFilterClass")).thenReturn(coderFactClassWithoutFilter); + when(coderManager.getDecoders(GROUP_ID, ARTIFACT_ID, "topic3")) + .thenReturn(decoderWithoutFilter); + + setupEventProtocolManager(constants); + + restApi = mock(RestManager.class); + + var drools = getDroolsControllerWithGroupArtifact(); + when(restApi.getDroolsController(CONTROLLER_NAME)).thenReturn(drools); + when(restApi.getDroolsController("exceptionController")) + .thenThrow(new IllegalArgumentException("exception")); + when(restApi.catchArgStateGenericEx(any(), any())).thenCallRealMethod(); + when(restApi.checkControllerDecoderAndFilter(anyString(), anyString(), anyString())) + .thenCallRealMethod(); + + // should work fine and get back JsonProtocolFilter object + var result = restApi.checkControllerDecoderAndFilter(CONTROLLER_NAME, TOPIC, FACT_CLASS); + assertNotNull(result); + assertInstanceOf(JsonProtocolFilter.class, result); + + // decoder doesn't have coder based on noFactClass parameter + var response = restApi.checkControllerDecoderAndFilter(CONTROLLER_NAME, "topic2", "noFactClass"); + assertNotNull(response); + if (response instanceof Response) { + var actualResponse = (Response) response; + assertEquals(BAD_REQUEST.getStatusCode(), actualResponse.getStatus()); + assertThat(((RestManager.Error) actualResponse.getEntity()).getError()) + .contains("noFactClass does not exist"); + } + + // decoder has factClass, but factClass has no filter + response = restApi.checkControllerDecoderAndFilter(CONTROLLER_NAME, "topic3", "noFilterClass"); + assertNotNull(response); + if (response instanceof Response) { + var actualResponse = (Response) response; + assertEquals(BAD_REQUEST.getStatusCode(), actualResponse.getStatus()); + assertThat(((RestManager.Error) actualResponse.getEntity()).getError()) + .contains("noFilterClass has no filters"); + } + } + } + + @Test + void testDecoderFilterRule2() { + var filter = new JsonProtocolFilter(); + when(restApi.checkControllerDecoderAndFilter(CONTROLLER_NAME, TOPIC, FACT_CLASS)) + .thenReturn(filter); + when(restApi.checkControllerDecoderAndFilter(CONTROLLER_NAME, TOPIC, "invalidFactClass")) + .thenReturn(Response.status(BAD_REQUEST).build()); + + when(restApi.decoderFilterRule2(anyString(), anyString(), anyString(), anyString())) + .thenCallRealMethod(); + when(restApi.decoderFilterRule2(anyString(), anyString(), anyString(), isNull())) + .thenCallRealMethod(); + + // should work + var result = restApi.decoderFilterRule2(CONTROLLER_NAME, TOPIC, FACT_CLASS, "rule"); + assertNotNull(result); + assertInstanceOf(String.class, result); + + // rule is null + var response = restApi.decoderFilterRule2(CONTROLLER_NAME, TOPIC, FACT_CLASS, null); + assertNotNull(response); + if (response instanceof Response) { + var actualResponse = (Response) response; + assertEquals(BAD_REQUEST.getStatusCode(), actualResponse.getStatus()); + assertThat(((RestManager.Error) actualResponse.getEntity()).getError()) + .contains("no filter rule provided"); + } + + // rule is empty string + response = restApi.decoderFilterRule2(CONTROLLER_NAME, TOPIC, FACT_CLASS, ""); + assertNotNull(response); + if (response instanceof Response) { + var actualResponse = (Response) response; + assertEquals(BAD_REQUEST.getStatusCode(), actualResponse.getStatus()); + assertThat(((RestManager.Error) actualResponse.getEntity()).getError()) + .contains("no filter rule provided"); + } + + // checkControllerDecoderFilter returns error response + response = restApi.decoderFilterRule2(CONTROLLER_NAME, TOPIC, "invalidFactClass", "rule"); + assertNotNull(response); + assertEquals(BAD_REQUEST.getStatusCode(), ((Response) response).getStatus()); + } + + private void setupPolicyEngineManager(MockedStatic<PolicyEngineConstants> constants) { + constants.when(PolicyEngineConstants::getManager).thenReturn(policyEngineManager); + assertEquals(policyEngineManager, PolicyEngineConstants.getManager()); + } + + private void setupLockManagerAndExecutorService() { + var executorService = mock(ScheduledExecutorService.class); + when(executorService.shutdownNow()).thenReturn(new ArrayList<>()); + when(policyEngineManager.getExecutorService()).thenReturn(executorService); + + var lockManager = mock(LockManager.class); + doNothing().when(lockManager).shutdown(); + ReflectionTestUtils.setField(policyEngineManager, "lockManager", lockManager); + } + + private void setupPolicyControllerFactory(MockedStatic<PolicyControllerConstants> constants) { + constants.when(PolicyControllerConstants::getFactory).thenReturn(controllerFactory); + assertEquals(controllerFactory, PolicyControllerConstants.getFactory()); + } + + private void setupEventProtocolManager(MockedStatic<EventProtocolCoderConstants> constants) { + constants.when(EventProtocolCoderConstants::getManager).thenReturn(coderManager); + assertEquals(coderManager, EventProtocolCoderConstants.getManager()); + } + + private void setupTopicEndpointManager(MockedStatic<TopicEndpointManager> constants) { + constants.when(TopicEndpointManager::getManager).thenReturn(topicManager); + assertEquals(topicManager, TopicEndpointManager.getManager()); + } + + private static DroolsController getDroolsControllerWithGroupArtifact() { + var drools = mock(DroolsController.class); + when(drools.getGroupId()).thenReturn(GROUP_ID); + when(drools.getArtifactId()).thenReturn(ARTIFACT_ID); + return drools; + } +}
\ No newline at end of file diff --git a/policy-management/src/test/java/org/onap/policy/drools/server/restful/test/RestManagerTest.java b/policy-management/src/test/java/org/onap/policy/drools/server/restful/test/RestManagerTest.java index 6a17f269..1ceff3d0 100644 --- a/policy-management/src/test/java/org/onap/policy/drools/server/restful/test/RestManagerTest.java +++ b/policy-management/src/test/java/org/onap/policy/drools/server/restful/test/RestManagerTest.java @@ -127,7 +127,6 @@ public class RestManagerTest { Properties controllerProps = new Properties(); PolicyEngineConstants.getManager().createPolicyController(FOO_CONTROLLER, controllerProps); - // client = HttpClients.createDefault(); CredentialsProvider provider = new BasicCredentialsProvider(); UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(TELEMETRY_USER, TELEMETRY_PASSWORD); provider.setCredentials(AuthScope.ANY, credentials); @@ -249,7 +248,7 @@ public class RestManagerTest { private void requestTest(HttpRequestBase request, int statusCode) throws IOException { CloseableHttpResponse resp = client.execute(request); - logger.info(request.getRequestLine() + "response code: {}", resp.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", request.getRequestLine(), resp.getStatusLine().getStatusCode()); assertEquals(statusCode, resp.getStatusLine().getStatusCode()); request.releaseConnection(); } @@ -291,13 +290,13 @@ public class RestManagerTest { CloseableHttpResponse response; httpGet = new HttpGet(HOST_URL + "/engine/swagger"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); } @Test - void testGet() throws IOException { + void testGetEngine() throws IOException { HttpGet httpGet; CloseableHttpResponse response; @@ -306,45 +305,46 @@ public class RestManagerTest { * /engine/inputs /engine/properties /engine/environment /engine/switches * /engine/controllers */ + httpGet = new HttpGet(HOST_URL + "/engine"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); httpGet = new HttpGet(HOST_URL + "/engine/features"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); httpGet = new HttpGet(HOST_URL + "/engine/features/inventory"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); httpGet = new HttpGet(HOST_URL + "/engine/features/foobar"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(404, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); httpGet = new HttpGet(HOST_URL + "/engine/inputs"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); httpGet = new HttpGet(HOST_URL + "/engine/properties"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); httpGet = new HttpGet(HOST_URL + "/engine/environment"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); @@ -352,26 +352,32 @@ public class RestManagerTest { httpGet = new HttpGet(HOST_URL + "/engine/environment/foo"); response = client.execute(httpGet); String responseBody = this.getResponseBody(response); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); - logger.info(httpGet.getRequestLine() + " response body: {}", responseBody); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); + logger.info("{} response body: {}", httpGet.getRequestLine(), responseBody); assertEquals(200, response.getStatusLine().getStatusCode()); assertEquals("bar", responseBody); httpGet.releaseConnection(); httpGet = new HttpGet(HOST_URL + "/engine/switches"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); httpGet = new HttpGet(HOST_URL + "/engine/controllers"); response = client.execute(httpGet); responseBody = this.getResponseBody(response); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); - logger.info(httpGet.getRequestLine() + " response body: {}", responseBody); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); + logger.info("{} response body: {}", httpGet.getRequestLine(), responseBody); assertEquals(200, response.getStatusLine().getStatusCode()); assertEquals("[\"" + FOO_CONTROLLER + "\"]", responseBody); httpGet.releaseConnection(); + } + + @Test + void testGet_EngineControllers() throws IOException { + HttpGet httpGet; + CloseableHttpResponse response; /* * GET: /engine/controllers/inventory /engine/controllers/features @@ -381,39 +387,46 @@ public class RestManagerTest { */ httpGet = new HttpGet(HOST_URL + "/engine/controllers/inventory"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); httpGet = new HttpGet(HOST_URL + "/engine/controllers/features"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); httpGet = new HttpGet(HOST_URL + "/engine/controllers/features/inventory"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); httpGet = new HttpGet(HOST_URL + "/engine/controllers/features/dummy"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(404, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); httpGet = new HttpGet(HOST_URL + "/engine/controllers/" + FOO_CONTROLLER); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); httpGet = new HttpGet(HOST_URL + "/engine/controllers/nonexistantcontroller"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(404, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); + } + + @Test + void testGet() throws IOException { + HttpGet httpGet; + CloseableHttpResponse response; + String responseBody; /* * GET: /engine/controllers/controllerName/properties @@ -423,52 +436,45 @@ public class RestManagerTest { httpGet = new HttpGet(HOST_URL + "/engine/controllers/" + FOO_CONTROLLER + "/properties"); response = client.execute(httpGet); responseBody = this.getResponseBody(response); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); - logger.info(httpGet.getRequestLine() + " response code: {}", responseBody); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), responseBody); assertEquals(200, response.getStatusLine().getStatusCode()); assertEquals("{}", responseBody); httpGet.releaseConnection(); httpGet = new HttpGet(HOST_URL + "/engine/controllers/nonexistantcontroller/properties"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(404, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); httpGet = new HttpGet(HOST_URL + "/engine/controllers/" + FOO_CONTROLLER + "/inputs"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); httpGet = new HttpGet(HOST_URL + "/engine/controllers/" + FOO_CONTROLLER + "/switches"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); httpGet = new HttpGet(HOST_URL + "/engine/controllers/" + FOO_CONTROLLER + "/drools"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); httpGet = new HttpGet(HOST_URL + "/engine/controllers/nonexistantcontroller/drools"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(404, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); - - testGetDroolsControllers(); - - testGetControllersDecoders(); - - testGetTopics(); - - testGetEngineTools(); } - private static void testGetDroolsControllers() throws IOException { + @Test + void testGetDroolsControllers() throws IOException { CloseableHttpResponse response; HttpGet httpGet; /* @@ -480,43 +486,44 @@ public class RestManagerTest { */ httpGet = new HttpGet(HOST_URL + "/engine/controllers/" + FOO_CONTROLLER + "/drools/facts"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); httpGet = new HttpGet(HOST_URL + "/engine/controllers/nonexistantcontroller/drools/facts"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(404, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); httpGet = new HttpGet(HOST_URL + "/engine/controllers/" + FOO_CONTROLLER + "/drools/facts/session"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); httpGet = new HttpGet(HOST_URL + "/engine/controllers/" + FOO_CONTROLLER + "/drools/facts/session/factType"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); httpGet = new HttpGet( HOST_URL + "/engine/controllers/" + FOO_CONTROLLER + "/drools/facts/session/query/queriedEntity"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); httpGet = new HttpGet(HOST_URL + "/engine/controllers/dummy" + "/drools/facts/session/query/queriedEntity"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(404, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); } - private static void testGetEngineTools() throws IOException { + @Test + void testGetEngineTools() throws IOException { CloseableHttpResponse response; HttpGet httpGet; /* @@ -524,24 +531,25 @@ public class RestManagerTest { */ httpGet = new HttpGet(HOST_URL + "/engine/tools/uuid"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); httpGet = new HttpGet(HOST_URL + "/engine/tools/loggers"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); httpGet = new HttpGet(HOST_URL + "/engine/tools/loggers/ROOT"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); } - private static void testGetControllersDecoders() throws IOException { + @Test + void testGetControllersDecoders() throws IOException { HttpGet httpGet; CloseableHttpResponse response; /* @@ -556,68 +564,69 @@ public class RestManagerTest { */ httpGet = new HttpGet(HOST_URL + "/engine/controllers/" + FOO_CONTROLLER + "/decoders"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); httpGet = new HttpGet(HOST_URL + "/engine/controllers/nonexistantcontroller/decoders"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(404, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); httpGet = new HttpGet(HOST_URL + "/engine/controllers/" + FOO_CONTROLLER + "/decoders/filters"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); httpGet = new HttpGet(HOST_URL + "/engine/controllers/nonexistantcontroller/decoders/filters"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(404, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); httpGet = new HttpGet(HOST_URL + "/engine/controllers/" + FOO_CONTROLLER + "/decoders/topic"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(404, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); httpGet = new HttpGet(HOST_URL + "/engine/controllers/" + FOO_CONTROLLER + "/decoders/topic/filters"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(404, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); httpGet = new HttpGet(HOST_URL + "/engine/controllers/" + FOO_CONTROLLER + "/decoders/topic/filters/factType"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(404, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); httpGet = new HttpGet( HOST_URL + "/engine/controllers/" + FOO_CONTROLLER + "/decoders/topic/filters/factType/rules"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(404, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); httpGet = new HttpGet( HOST_URL + "/engine/controllers/" + FOO_CONTROLLER + "/decoders/topic/filters/factType/rules/ruleName"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(404, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); httpGet = new HttpGet(HOST_URL + "/engine/controllers/" + FOO_CONTROLLER + "/encoders"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); } - private static void testGetTopics() throws IOException { + @Test + void testGetKafkaTopics() throws IOException { CloseableHttpResponse response; HttpGet httpGet; /* @@ -635,169 +644,186 @@ public class RestManagerTest { */ httpGet = new HttpGet(HOST_URL + "/engine/topics"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); httpGet = new HttpGet(HOST_URL + "/engine/topics/switches"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); httpGet = new HttpGet(HOST_URL + "/engine/topics/sources"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); httpGet = new HttpGet(HOST_URL + "/engine/topics/sinks"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); httpGet = new HttpGet(HOST_URL + "/engine/topics/sources/kafka"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); httpGet = new HttpGet(HOST_URL + "/engine/topics/sinks/kafka"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); - httpGet = new HttpGet(HOST_URL + "/engine/topics/sources/noop"); + httpGet = new HttpGet(HOST_URL + "/engine/topics/sources/kafka/" + KAFKA_TOPIC); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); - httpGet = new HttpGet(HOST_URL + "/engine/topics/sinks/noop"); + httpGet = new HttpGet(HOST_URL + "/engine/topics/sources/kafka/foobar"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); - assertEquals(200, response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); + assertEquals(500, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); - httpGet = new HttpGet(HOST_URL + "/engine/topics/sources/kafka/" + KAFKA_TOPIC); + httpGet = new HttpGet(HOST_URL + "/engine/topics/sinks/kafka/" + KAFKA_TOPIC); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); - httpGet = new HttpGet(HOST_URL + "/engine/topics/sources/kafka/foobar"); + httpGet = new HttpGet(HOST_URL + "/engine/topics/sinks/kafka/foobar"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(500, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); - httpGet = new HttpGet(HOST_URL + "/engine/topics/sinks/kafka/" + KAFKA_TOPIC); + httpGet = new HttpGet(HOST_URL + "/engine/topics/sources/kafka/" + KAFKA_TOPIC + "/events"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); - httpGet = new HttpGet(HOST_URL + "/engine/topics/sinks/kafka/foobar"); + httpGet = new HttpGet(HOST_URL + "/engine/topics/sources/kafka/foobar/events"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(500, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); - httpGet = new HttpGet(HOST_URL + "/engine/topics/sources/noop/" + NOOP_TOPIC); + httpGet = new HttpGet(HOST_URL + "/engine/topics/sinks/kafka/" + KAFKA_TOPIC + "/events"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); - httpGet = new HttpGet(HOST_URL + "/engine/topics/sources/noop/foobar"); + httpGet = new HttpGet(HOST_URL + "/engine/topics/sinks/kafka/foobar/events"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(500, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); - httpGet = new HttpGet(HOST_URL + "/engine/topics/sinks/noop/" + NOOP_TOPIC); + httpGet = new HttpGet(HOST_URL + "/engine/topics/sources/kafka/" + KAFKA_TOPIC + "/switches"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); - httpGet = new HttpGet(HOST_URL + "/engine/topics/sinks/noop/foobar"); + httpGet = new HttpGet(HOST_URL + "/engine/topics/sinks/kafka/" + KAFKA_TOPIC + "/switches"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); - assertEquals(500, response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); + assertEquals(200, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); + } - httpGet = new HttpGet(HOST_URL + "/engine/topics/sources/kafka/" + KAFKA_TOPIC + "/events"); + @Test + void testGetNoopTopics() throws IOException { + CloseableHttpResponse response; + HttpGet httpGet; + /* + * GET: /engine/topics + * /engine/topics/sources/noop + * /engine/topics/sinks/noop + * /engine/topics/sources/noop/topic + * /engine/topics/sinks/noop/topic + * /engine/topics/sources/noop/topic/events + * /engine/topics/sinks/noop/topic/events + * /engine/topics/sources/noop/topic/switches + * /engine/topics/sinks/noop/topic/switches + */ + + httpGet = new HttpGet(HOST_URL + "/engine/topics/sources/noop"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); - httpGet = new HttpGet(HOST_URL + "/engine/topics/sources/kafka/foobar/events"); + httpGet = new HttpGet(HOST_URL + "/engine/topics/sinks/noop"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); - assertEquals(500, response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); + assertEquals(200, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); - httpGet = new HttpGet(HOST_URL + "/engine/topics/sinks/kafka/" + KAFKA_TOPIC + "/events"); + httpGet = new HttpGet(HOST_URL + "/engine/topics/sources/noop/" + NOOP_TOPIC); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); - httpGet = new HttpGet(HOST_URL + "/engine/topics/sinks/kafka/foobar/events"); + httpGet = new HttpGet(HOST_URL + "/engine/topics/sources/noop/foobar"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(500, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); - httpGet = new HttpGet(HOST_URL + "/engine/topics/sources/noop/" + NOOP_TOPIC + "/events"); + httpGet = new HttpGet(HOST_URL + "/engine/topics/sinks/noop/" + NOOP_TOPIC); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); - httpGet = new HttpGet(HOST_URL + "/engine/topics/sources/noop/foobar/events"); + httpGet = new HttpGet(HOST_URL + "/engine/topics/sinks/noop/foobar"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(500, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); - httpGet = new HttpGet(HOST_URL + "/engine/topics/sinks/noop/" + NOOP_TOPIC + "/events"); + httpGet = new HttpGet(HOST_URL + "/engine/topics/sources/noop/" + NOOP_TOPIC + "/events"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); - httpGet = new HttpGet(HOST_URL + "/engine/topics/sinks/noop/foobar/events"); + httpGet = new HttpGet(HOST_URL + "/engine/topics/sources/noop/foobar/events"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(500, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); - httpGet = new HttpGet(HOST_URL + "/engine/topics/sources/kafka/" + KAFKA_TOPIC + "/switches"); + httpGet = new HttpGet(HOST_URL + "/engine/topics/sinks/noop/" + NOOP_TOPIC + "/events"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); - httpGet = new HttpGet(HOST_URL + "/engine/topics/sources/noop/" + NOOP_TOPIC + "/switches"); + httpGet = new HttpGet(HOST_URL + "/engine/topics/sinks/noop/foobar/events"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); - assertEquals(200, response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); + assertEquals(500, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); - httpGet = new HttpGet(HOST_URL + "/engine/topics/sinks/kafka/" + KAFKA_TOPIC + "/switches"); + httpGet = new HttpGet(HOST_URL + "/engine/topics/sources/noop/" + NOOP_TOPIC + "/switches"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); httpGet = new HttpGet(HOST_URL + "/engine/topics/sinks/noop/" + NOOP_TOPIC + "/switches"); response = client.execute(httpGet); - logger.info(httpGet.getRequestLine() + " response code: {}", response.getStatusLine().getStatusCode()); + logger.info("{} response code: {}", httpGet.getRequestLine(), response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode()); httpGet.releaseConnection(); } diff --git a/policy-management/src/test/java/org/onap/policy/drools/stats/PolicyStatsManagerTest.java b/policy-management/src/test/java/org/onap/policy/drools/stats/PolicyStatsManagerTest.java index 118c4d7e..c13a4664 100644 --- a/policy-management/src/test/java/org/onap/policy/drools/stats/PolicyStatsManagerTest.java +++ b/policy-management/src/test/java/org/onap/policy/drools/stats/PolicyStatsManagerTest.java @@ -21,6 +21,7 @@ package org.onap.policy.drools.stats; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.Test; @@ -42,4 +43,17 @@ class PolicyStatsManagerTest { assertEquals(1, stats.getSubgroupStats().get("foo").getPolicyExecutedFailCount()); assertEquals(2, stats.getSubgroupStats().get("blah").getPolicyExecutedFailCount()); } + + @Test + void test_Exceptions() { + PolicyStatsManager stats = new PolicyStatsManager(); + assertThatThrownBy(() -> stats.stat("foo", null)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("transaction is marked non-null but is nul"); + + Metric trans = new Metric(); + assertThatThrownBy(() -> stats.stat(null, trans)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("subGroupName is marked non-null but is null"); + } }
\ No newline at end of file diff --git a/policy-management/src/test/java/org/onap/policy/drools/stats/PolicyStatsTest.java b/policy-management/src/test/java/org/onap/policy/drools/stats/PolicyStatsTest.java index 3f26e82e..6b76837d 100644 --- a/policy-management/src/test/java/org/onap/policy/drools/stats/PolicyStatsTest.java +++ b/policy-management/src/test/java/org/onap/policy/drools/stats/PolicyStatsTest.java @@ -22,6 +22,7 @@ package org.onap.policy.drools.stats; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.Test; @@ -74,6 +75,14 @@ class PolicyStatsTest { assertThat(stats.getBirthTime()).isLessThanOrEqualTo(trans2.getStartTime().toEpochMilli()); } + @Test + void test_Exception() { + PolicyStats stats = new PolicyStats(); + assertThatThrownBy(() -> stats.stat(null)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("trans is marked non-null but is null"); + } + private Metric createTrans() { Metric trans = new Metric(); trans.setStartTime(null); diff --git a/policy-management/src/test/java/org/onap/policy/drools/system/PolicyControllerFactoryTest.java b/policy-management/src/test/java/org/onap/policy/drools/system/PolicyControllerFactoryTest.java index 615ffe2b..8a388dfc 100644 --- a/policy-management/src/test/java/org/onap/policy/drools/system/PolicyControllerFactoryTest.java +++ b/policy-management/src/test/java/org/onap/policy/drools/system/PolicyControllerFactoryTest.java @@ -35,7 +35,6 @@ import static org.mockito.Mockito.when; import static org.onap.policy.drools.properties.DroolsPropertyConstants.PROPERTY_CONTROLLER_TYPE; import java.util.Arrays; -import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Properties; @@ -504,9 +503,9 @@ class PolicyControllerFactoryTest { @Override public DroolsController beforeInstance(Properties properties, - String groupId, String artifactId, String version, - List<TopicCoderFilterConfiguration> decoderConfigurations, - List<TopicCoderFilterConfiguration> encoderConfigurations) { + String groupId, String artifactId, String version, + List<TopicCoderFilterConfiguration> decoderConfigurations, + List<TopicCoderFilterConfiguration> encoderConfigurations) { if (POLICY_CONTROLLER_BUILDER_TAG.equals(properties.getProperty(PROPERTY_CONTROLLER_TYPE))) { return new NullDroolsController(); 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 4006c9ed..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; @@ -217,7 +217,7 @@ class PolicyEngineManagerTest { when(lockmgr.lock()).thenReturn(true); when(lockmgr.unlock()).thenReturn(true); - when(prov2.beforeCreateLockManager(any(), any())).thenReturn(lockmgr); + when(prov2.beforeCreateLockManager()).thenReturn(lockmgr); when(prov1.getName()).thenReturn(FEATURE1); when(prov2.getName()).thenReturn(FEATURE2); @@ -524,7 +524,7 @@ class PolicyEngineManagerTest { @Test void testCreateLockManagerHaveProvider() { // first provider throws an exception - when(prov1.beforeCreateLockManager(any(), any())).thenThrow(new RuntimeException(EXPECTED)); + when(prov1.beforeCreateLockManager()).thenThrow(new RuntimeException(EXPECTED)); mgr.configure(properties); assertSame(lockmgr, mgr.getLockManager()); @@ -535,7 +535,7 @@ class PolicyEngineManagerTest { */ @Test void testCreateLockManagerSimpleEx() { - when(prov2.beforeCreateLockManager(any(), any())).thenReturn(null); + when(prov2.beforeCreateLockManager()).thenReturn(null); // invalid property for SimpleLockManager properties.setProperty(SimpleLockProperties.EXPIRE_CHECK_SEC, "abc"); @@ -550,7 +550,7 @@ class PolicyEngineManagerTest { */ @Test void testCreateLockManagerSimple() { - when(prov2.beforeCreateLockManager(any(), any())).thenReturn(null); + when(prov2.beforeCreateLockManager()).thenReturn(null); mgr.configure(properties); assertInstanceOf(SimpleLockManager.class, mgr.getLockManager()); @@ -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(); @@ -731,7 +739,7 @@ class PolicyEngineManagerTest { } @Test - void testUpdatePolicyController() throws Exception { + void testUpdatePolicyController_Exceptions() throws Exception { assertEquals(controller3, mgr.updatePolicyController(config3)); verify(engine).createPolicyController(CONTROLLER3, properties); @@ -775,7 +783,10 @@ class PolicyEngineManagerTest { setUp(); when(persist.getControllerProperties(CONTROLLER3)).thenThrow(new LinkageError(EXPECTED)); assertThatIllegalStateException().isThrownBy(() -> mgr.updatePolicyController(config3)); + } + @Test + void testUpdatePolicyController() throws Exception { /* * For remaining tests, the factory will return the controller instead of creating * one. @@ -899,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 { @@ -954,14 +965,7 @@ class PolicyEngineManagerTest { assertTrue(mgr.stop()); verify(prov1).beforeStop(mgr); verify(prov2).beforeStop(mgr); - verify(controller, never()).stop(); - verify(source1, never()).stop(); - verify(sink1, never()).stop(); - verify(endpoint, never()).stop(); - verify(server1, never()).stop(); - verify(client1, never()).stop(); - verify(prov1, never()).afterStop(mgr); - verify(prov2, never()).afterStop(mgr); + verifyNeverCalled(); // controller fails to stop - still does everything testStop(false, () -> when(controller.stop()).thenReturn(false)); @@ -1008,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 { @@ -1215,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 { @@ -1291,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 { @@ -1415,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); @@ -1427,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); @@ -1557,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. @@ -1614,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(); @@ -1741,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); @@ -1749,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 @@ -1854,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<PolicyEngineFeatureApi, Boolean> setBefore, - BiConsumer<PolicyEngineFeatureApi, Boolean> setAfter, Runnable action, - Consumer<PolicyEngineFeatureApi> verifyBefore, Runnable verifyMiddle, - Consumer<PolicyEngineFeatureApi> verifyAfter) throws Exception { + BiConsumer<PolicyEngineFeatureApi, Boolean> setAfter, Runnable action, + Consumer<PolicyEngineFeatureApi> verifyBefore, Runnable verifyMiddle, + Consumer<PolicyEngineFeatureApi> verifyAfter) throws Exception { checkBeforeAfter_FalseFalse(setBefore, setAfter, action, verifyBefore, verifyMiddle, verifyAfter); checkBeforeAfter_FalseTrue(setBefore, setAfter, action, verifyBefore, verifyMiddle, verifyAfter); @@ -1879,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<PolicyEngineFeatureApi, Boolean> setBefore, - BiConsumer<PolicyEngineFeatureApi, Boolean> setAfter, Runnable action, - Consumer<PolicyEngineFeatureApi> verifyBefore, Runnable verifyMiddle, - Consumer<PolicyEngineFeatureApi> verifyAfter) throws Exception { + BiConsumer<PolicyEngineFeatureApi, Boolean> setAfter, Runnable action, + Consumer<PolicyEngineFeatureApi> verifyBefore, Runnable verifyMiddle, + Consumer<PolicyEngineFeatureApi> verifyAfter) throws Exception { setUp(); @@ -1920,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<PolicyEngineFeatureApi, Boolean> setBefore, - BiConsumer<PolicyEngineFeatureApi, Boolean> setAfter, Runnable action, - Consumer<PolicyEngineFeatureApi> verifyBefore, Runnable verifyMiddle, - Consumer<PolicyEngineFeatureApi> verifyAfter) throws Exception { + BiConsumer<PolicyEngineFeatureApi, Boolean> setAfter, Runnable action, + Consumer<PolicyEngineFeatureApi> verifyBefore, Runnable verifyMiddle, + Consumer<PolicyEngineFeatureApi> verifyAfter) throws Exception { setUp(); @@ -1961,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<PolicyEngineFeatureApi, Boolean> setBefore, - BiConsumer<PolicyEngineFeatureApi, Boolean> setAfter, Runnable action, - Consumer<PolicyEngineFeatureApi> verifyBefore, Runnable verifyMiddle, - Consumer<PolicyEngineFeatureApi> verifyAfter) throws Exception { + BiConsumer<PolicyEngineFeatureApi, Boolean> setAfter, Runnable action, + Consumer<PolicyEngineFeatureApi> verifyBefore, Runnable verifyMiddle, + Consumer<PolicyEngineFeatureApi> verifyAfter) throws Exception { setUp(); @@ -1999,6 +2003,17 @@ class PolicyEngineManagerTest { assertThatThrownBy(() -> verifyAfter.accept(prov2)).isInstanceOf(AssertionError.class); } + private void verifyNeverCalled() { + verify(controller, never()).stop(); + verify(source1, never()).stop(); + verify(sink1, never()).stop(); + verify(endpoint, never()).stop(); + verify(server1, never()).stop(); + verify(client1, never()).stop(); + verify(prov1, never()).afterStop(mgr); + verify(prov2, never()).afterStop(mgr); + } + /** * Manager with overrides. */ @@ -2086,8 +2101,8 @@ class PolicyEngineManagerTest { private class MyShutdown extends ShutdownThread { @Override - protected void doSleep(long sleepMs) throws InterruptedException { - threadSleepMs = sleepMs; + protected void doSleep() throws InterruptedException { + threadSleepMs = 300L; if (shouldInterrupt) { throw new InterruptedException(EXPECTED); @@ -2095,8 +2110,8 @@ class PolicyEngineManagerTest { } @Override - protected void doExit(int code) { - threadExitCode = code; + protected void doExit() { + threadExitCode = 0; } @Override diff --git a/policy-management/src/test/java/org/onap/policy/drools/system/PolicyEngineTest.java b/policy-management/src/test/java/org/onap/policy/drools/system/PolicyEngineTest.java index b4915ef4..a1b45de2 100644 --- a/policy-management/src/test/java/org/onap/policy/drools/system/PolicyEngineTest.java +++ b/policy-management/src/test/java/org/onap/policy/drools/system/PolicyEngineTest.java @@ -176,7 +176,7 @@ class PolicyEngineTest { @Test void test200Start() { - logger.info("enter"); + logger.info("enter test200Start"); PolicyEngineConstants.getManager().start(); @@ -188,7 +188,7 @@ class PolicyEngineTest { @Test void test300Lock() { - logger.info("enter"); + logger.info("enter test300Lock"); PolicyEngineConstants.getManager().lock(); @@ -200,7 +200,7 @@ class PolicyEngineTest { @Test void test301Unlock() { - logger.info("enter"); + logger.info("enter test301Unlock"); PolicyEngineConstants.getManager().unlock(); @@ -235,7 +235,7 @@ class PolicyEngineTest { @Test void test400ControllerAdd() { - logger.info("enter"); + logger.info("enter test400ControllerAdd"); final Properties controllerProperties = new Properties(); controllerProperties.put(DroolsPropertyConstants.PROPERTY_CONTROLLER_NAME, TEST_CONTROLLER_NAME); @@ -250,7 +250,7 @@ class PolicyEngineTest { @Test void test401ControllerVerify() { - logger.info("enter"); + logger.info("enter test401ControllerVerify"); final PolicyController testController = PolicyControllerConstants.getFactory().get(TEST_CONTROLLER_NAME); @@ -265,7 +265,7 @@ class PolicyEngineTest { @Test void test500Deactivate() { - logger.info("enter"); + logger.info("enter test500Deactivate"); PolicyEngineConstants.getManager().deactivate(); @@ -278,7 +278,7 @@ class PolicyEngineTest { @Test void test501Activate() { - logger.info("enter"); + logger.info("enter test501Activate"); PolicyEngineConstants.getManager().activate(); @@ -291,7 +291,7 @@ class PolicyEngineTest { @Test void test900ControllerRemove() { - logger.info("enter"); + logger.info("enter test900ControllerRemove"); PolicyEngineConstants.getManager().removePolicyController(TEST_CONTROLLER_NAME); assertTrue(PolicyControllerConstants.getFactory().inventory().isEmpty()); @@ -299,7 +299,7 @@ class PolicyEngineTest { @Test void test901Stop() { - logger.info("enter"); + logger.info("enter test901Stop"); /* Shutdown managed resources */ PolicyControllerConstants.getFactory().shutdown(); diff --git a/policy-management/src/test/java/org/onap/policy/drools/system/internal/FeatureLockImplTest.java b/policy-management/src/test/java/org/onap/policy/drools/system/internal/FeatureLockImplTest.java index 8a10c516..6d2380f0 100644 --- a/policy-management/src/test/java/org/onap/policy/drools/system/internal/FeatureLockImplTest.java +++ b/policy-management/src/test/java/org/onap/policy/drools/system/internal/FeatureLockImplTest.java @@ -213,22 +213,6 @@ class FeatureLockImplTest { verify(callback, never()).lockUnavailable(any()); } - /** - * Tests doNotify() when there is no session. - */ - @Test - void testDoNotifyNoSession() { - MyLock lock = new MyLock(LockState.WAITING, RESOURCE, OWNER_KEY, HOLD_SEC, callback); - lock.grant(); - - assertTrue(lock.isActive()); - assertEquals(1, lock.nupdates); - - invokeCallback(); - verify(callback).lockAvailable(any()); - verify(callback, never()).lockUnavailable(any()); - } - @Test void testFreeAllowed() { MyLock lock = new MyLock(LockState.WAITING, RESOURCE, OWNER_KEY, HOLD_SEC, callback); 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 @@ <groupId>net.jimblackler.jsonschemafriend</groupId> <artifactId>core</artifactId> </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-test</artifactId> + </dependency> </dependencies> </project> 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> T convertTo(@NonNull ToscaConceptIdentifier policyType, @NonNull String json, @NonNull Class<T> 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<String> 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<String>(Arrays.asList(new String[]{"p1", "p2", "p4"})), - returns[1]); - } } |