From bcb522a96d60e6b50383645f870100a72ee11db7 Mon Sep 17 00:00:00 2001 From: Jim Hahn Date: Wed, 23 Jun 2021 10:11:14 -0400 Subject: Remove expired PDPs Added code to remove PDPs for which no message has been received for a while. Added a max-age field to the request-map parameters, changing the parameters class to use a Builder, in the process. Deleted the PdpTracker class, as its functionality was replaced by the expiration checker. Changed port numbers in some tests, due to collisions in junit tests. Issue-ID: POLICY-3407 Change-Id: Ifbfbc03b833a4f11ee5e910e256ee42e21a0afab Signed-off-by: Jim Hahn --- .../org/onap/policy/pap/main/PapConstants.java | 3 +- .../policy/pap/main/comm/PdpModifyRequestMap.java | 133 +++++------- .../pap/main/comm/PdpStatusMessageHandler.java | 10 - .../org/onap/policy/pap/main/comm/PdpTracker.java | 153 -------------- .../policy/pap/main/comm/msgdata/RequestImpl.java | 4 +- .../pap/main/comm/msgdata/RequestListener.java | 6 +- .../main/parameters/PdpModifyRequestMapParams.java | 49 +---- .../policy/pap/main/startstop/PapActivator.java | 53 +++-- .../policy/pap/main/comm/CommonRequestBase.java | 14 +- .../pap/main/comm/PdpModifyRequestMapTest.java | 234 ++++++--------------- .../onap/policy/pap/main/comm/PdpTrackerTest.java | 212 ------------------- .../pap/main/comm/msgdata/RequestImplTest.java | 4 +- .../parameters/TestPdpModifyRequestMapParams.java | 47 +++-- .../onap/policy/pap/main/startstop/TestMain.java | 39 +++- .../pap/main/startstop/TestPapActivator.java | 34 ++- .../resources/parameters/MinimumParameters.json | 4 +- .../resources/parameters/PapConfigParameters.json | 2 +- .../PapConfigParameters_InvalidName.json | 2 +- .../parameters/PapConfigParameters_sim.json | 42 ---- 19 files changed, 271 insertions(+), 774 deletions(-) delete mode 100644 main/src/main/java/org/onap/policy/pap/main/comm/PdpTracker.java delete mode 100644 main/src/test/java/org/onap/policy/pap/main/comm/PdpTrackerTest.java delete mode 100644 main/src/test/resources/parameters/PapConfigParameters_sim.json diff --git a/main/src/main/java/org/onap/policy/pap/main/PapConstants.java b/main/src/main/java/org/onap/policy/pap/main/PapConstants.java index 2acf3e72..b51e85cc 100644 --- a/main/src/main/java/org/onap/policy/pap/main/PapConstants.java +++ b/main/src/main/java/org/onap/policy/pap/main/PapConstants.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * ONAP PAP * ================================================================================ - * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2019, 2021 AT&T Intellectual Property. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,7 +30,6 @@ public class PapConstants { public static final String REG_STATISTICS_MANAGER = "object:manager/statistics"; public static final String REG_PDP_MODIFY_LOCK = "lock:pdp"; public static final String REG_PDP_MODIFY_MAP = "object:pdp/modify/map"; - public static final String REG_PDP_TRACKER = "object:pdp/tracker"; public static final String REG_POLICY_NOTIFIER = "object:policy/notifier"; public static final String REG_PAP_DAO_FACTORY = "object:pap/dao/factory"; diff --git a/main/src/main/java/org/onap/policy/pap/main/comm/PdpModifyRequestMap.java b/main/src/main/java/org/onap/policy/pap/main/comm/PdpModifyRequestMap.java index e00eadaa..087aa577 100644 --- a/main/src/main/java/org/onap/policy/pap/main/comm/PdpModifyRequestMap.java +++ b/main/src/main/java/org/onap/policy/pap/main/comm/PdpModifyRequestMap.java @@ -21,13 +21,16 @@ package org.onap.policy.pap.main.comm; +import java.time.Instant; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; import lombok.Setter; import org.onap.policy.models.base.PfModelException; import org.onap.policy.models.pap.concepts.PolicyNotification; @@ -170,10 +173,11 @@ public class PdpModifyRequestMap { * Adds an UPDATE request to the map. * * @param update the UPDATE request or {@code null} + * @return the new request (this should only be used by junit tests) */ - public void addRequest(PdpUpdate update) { + public Request addRequest(PdpUpdate update) { if (update == null) { - return; + return null; } if (isBroadcast(update)) { @@ -193,16 +197,18 @@ public class PdpModifyRequestMap { var request = new UpdateReq(reqparams, name, update); addSingleton(request); + return request; } /** * Adds a STATE-CHANGE request to the map. * * @param stateChange the STATE-CHANGE request or {@code null} + * @return the new request (this should only be used by junit tests) */ - public void addRequest(PdpStateChange stateChange) { + public Request addRequest(PdpStateChange stateChange) { if (stateChange == null) { - return; + return null; } if (isBroadcast(stateChange)) { @@ -222,6 +228,7 @@ public class PdpModifyRequestMap { var request = new StateChangeReq(reqparams, name, stateChange); addSingleton(request); + return request; } /** @@ -251,90 +258,86 @@ public class PdpModifyRequestMap { } /** - * Removes a PDP from all active groups. - * - * @param pdpName name of the PDP to be removed - * @return {@code true} if the PDP was removed from a group, {@code false} if it was - * not assigned to a group - * @throws PfModelException if an error occurred + * Removes expired PDPs from all active groups. */ - public boolean removeFromGroups(String pdpName) throws PfModelException { + public void removeExpiredPdps() { - try (PolicyModelsProvider dao = daoFactory.create()) { + synchronized (modifyLock) { + logger.info("check for PDP records older than {}ms", params.getMaxPdpAgeMs()); - PdpGroupFilter filter = PdpGroupFilter.builder().groupState(PdpState.ACTIVE).build(); - List groups = dao.getFilteredPdpGroups(filter); - List updates = new ArrayList<>(1); + try (PolicyModelsProvider dao = daoFactory.create()) { - var status = new DeploymentStatus(dao); + PdpGroupFilter filter = PdpGroupFilter.builder().groupState(PdpState.ACTIVE).build(); + List groups = dao.getFilteredPdpGroups(filter); + List updates = new ArrayList<>(1); - for (PdpGroup group : groups) { - if (removeFromGroup(pdpName, group)) { - updates.add(group); - status.loadByGroup(group.getName()); - status.deleteDeployment(pdpName); - } - } + var status = new DeploymentStatus(dao); - if (updates.isEmpty()) { - return false; + Instant minAge = Instant.now().minusMillis(params.getMaxPdpAgeMs()); - } else { - dao.updatePdpGroups(updates); + for (PdpGroup group : groups) { + Set pdps = removeFromGroup(minAge, group); + if (!pdps.isEmpty()) { + updates.add(group); + status.loadByGroup(group.getName()); + pdps.forEach(status::deleteDeployment); + } + } - var notification = new PolicyNotification(); - status.flush(notification); + if (!updates.isEmpty()) { + dao.updatePdpGroups(updates); - policyNotifier.publish(notification); + var notification = new PolicyNotification(); + status.flush(notification); - return true; + policyNotifier.publish(notification); + } + + } catch (PfModelException e) { + logger.warn("failed to remove expired PDPs", e); } } } /** - * Removes a PDP from a group. + * Removes expired PDPs from a group. * - * @param pdpName name of the PDP to be removed - * @param group group from which it should be removed - * @return {@code true} if the PDP was removed from the group, {@code false} if it was - * not assigned to the group + * @param minAge minimum age for active PDPs + * @param group group from which expired PDPs should be removed + * @return the expired PDPs */ - private boolean removeFromGroup(String pdpName, PdpGroup group) { + private Set removeFromGroup(Instant minAge, PdpGroup group) { + Set pdps = new HashSet<>(); for (PdpSubGroup subgrp : group.getPdpSubgroups()) { - if (removeFromSubgroup(pdpName, group, subgrp)) { - return true; - } + removeFromSubgroup(minAge, group, subgrp, pdps); } - return false; + return pdps; } /** - * Removes a PDP from a subgroup. + * Removes expired PDPs from a subgroup. * - * @param pdpName name of the PDP to be removed + * @param minAge minimum age for active PDPs * @param group group from which to attempt to remove the PDP * @param subgrp subgroup from which to attempt to remove the PDP - * @return {@code true} if the PDP was removed, {@code false} if the PDP was not in - * the group + * @param pdps where to place the expired PDPs */ - private boolean removeFromSubgroup(String pdpName, PdpGroup group, PdpSubGroup subgrp) { + private void removeFromSubgroup(Instant minAge, PdpGroup group, PdpSubGroup subgrp, Set pdps) { Iterator iter = subgrp.getPdpInstances().iterator(); while (iter.hasNext()) { Pdp instance = iter.next(); - if (pdpName.equals(instance.getInstanceId())) { + if (instance.getLastUpdate().isBefore(minAge)) { + String pdpName = instance.getInstanceId(); logger.info("removed {} from group={} subgroup={}", pdpName, group.getName(), subgrp.getPdpType()); iter.remove(); subgrp.setCurrentInstanceCount(subgrp.getPdpInstances().size()); - return true; + pdps.add(pdpName); } } - - return false; } /** @@ -430,8 +433,11 @@ public class PdpModifyRequestMap { } @Override - public void retryCountExhausted() { - removePdp(); + public void retryCountExhausted(Request request) { + if (pdp2requests.get(pdpName) == requests) { + requests.stopPublishing(); + startNextRequest(request); + } } /** @@ -444,28 +450,5 @@ public class PdpModifyRequestMap { pdp2requests.remove(pdpName, requests); } } - - /** - * Removes a PDP from its subgroup. - */ - private void removePdp() { - requests.stopPublishing(); - - // remove the requests from the map - if (!pdp2requests.remove(pdpName, requests)) { - // wasn't in the map - the requests must be old - logger.warn("discarding old requests for {}", pdpName); - return; - } - - logger.warn("removing {}", pdpName); - - // remove the PDP from all groups - try { - removeFromGroups(pdpName); - } catch (PfModelException e) { - logger.info("unable to remove PDP {} from subgroup", pdpName, e); - } - } } } diff --git a/main/src/main/java/org/onap/policy/pap/main/comm/PdpStatusMessageHandler.java b/main/src/main/java/org/onap/policy/pap/main/comm/PdpStatusMessageHandler.java index adbc554d..897a0049 100644 --- a/main/src/main/java/org/onap/policy/pap/main/comm/PdpStatusMessageHandler.java +++ b/main/src/main/java/org/onap/policy/pap/main/comm/PdpStatusMessageHandler.java @@ -32,7 +32,6 @@ import java.util.Optional; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import org.apache.commons.lang3.builder.EqualsBuilder; -import org.onap.policy.common.utils.services.Registry; import org.onap.policy.models.base.PfModelException; import org.onap.policy.models.pdp.concepts.Pdp; import org.onap.policy.models.pdp.concepts.PdpGroup; @@ -44,7 +43,6 @@ import org.onap.policy.models.pdp.enums.PdpState; import org.onap.policy.models.provider.PolicyModelsProvider; import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy; -import org.onap.policy.pap.main.PapConstants; import org.onap.policy.pap.main.PolicyPapException; import org.onap.policy.pap.main.parameters.PdpParameters; import org.slf4j.Logger; @@ -106,14 +104,6 @@ public class PdpStatusMessageHandler extends PdpMessageGenerator { } else { handlePdpHeartbeat(message, databaseProvider); } - /* - * Indicate that a heart beat was received from the PDP. This is invoked only if handleXxx() does not - * throw an exception. - */ - if (message.getName() != null) { - final var pdpTracker = (PdpTracker) Registry.get(PapConstants.REG_PDP_TRACKER); - pdpTracker.add(message.getName()); - } } catch (final PolicyPapException exp) { LOGGER.error("Operation Failed", exp); } catch (final Exception exp) { diff --git a/main/src/main/java/org/onap/policy/pap/main/comm/PdpTracker.java b/main/src/main/java/org/onap/policy/pap/main/comm/PdpTracker.java deleted file mode 100644 index 53dcf65b..00000000 --- a/main/src/main/java/org/onap/policy/pap/main/comm/PdpTracker.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * ONAP PAP - * ================================================================================ - * Copyright (C) 2019-2021 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ - -package org.onap.policy.pap.main.comm; - -import java.util.HashMap; -import java.util.Map; -import lombok.Builder; -import lombok.NonNull; -import org.onap.policy.models.base.PfModelException; -import org.onap.policy.models.pdp.concepts.Pdp; -import org.onap.policy.models.pdp.concepts.PdpGroup; -import org.onap.policy.models.pdp.concepts.PdpSubGroup; -import org.onap.policy.models.provider.PolicyModelsProvider; -import org.onap.policy.pap.main.PolicyModelsProviderFactoryWrapper; -import org.onap.policy.pap.main.PolicyPapRuntimeException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Tracks PDPs. When a PDP is added to the tracker, a timer is started. If the PDP is not - * re-added to the tracker before the timer expires, then - * {@link PdpModifyRequestMap#removeFromGroups(String)} is called. - */ -public class PdpTracker { - private static final Logger logger = LoggerFactory.getLogger(PdpTracker.class); - - /** - * PDP expiration timers. - */ - private final TimerManager timers; - - /** - * Maps a PDP name to its expiration timer. - */ - private final Map pdp2timer = new HashMap<>(); - - /** - * PDP modification lock. - */ - private final Object modifyLock; - - /** - * Used to remove a PDP from its group/subgroup. - */ - private final PdpModifyRequestMap requestMap; - - - /** - * Constructs the object. Loads the list of PDPs to be tracked, from the DB. - * - * @param requestMap map used to remove a PDP from its group/subgroup - * @param modifyLock object to be locked while data structures are updated - * @param timers timers used to detect missed heart beats - * @param daoFactory DAO factory - */ - @Builder - public PdpTracker(@NonNull PdpModifyRequestMap requestMap, @NonNull Object modifyLock, @NonNull TimerManager timers, - @NonNull PolicyModelsProviderFactoryWrapper daoFactory) { - - this.requestMap = requestMap; - this.modifyLock = modifyLock; - this.timers = timers; - - loadPdps(daoFactory); - } - - /** - * Loads the PDPs from the DB. - * - * @param daoFactory DAO factory - */ - private void loadPdps(PolicyModelsProviderFactoryWrapper daoFactory) { - synchronized (modifyLock) { - try (PolicyModelsProvider dao = daoFactory.create()) { - for (PdpGroup group : dao.getPdpGroups(null)) { - loadPdpsFromGroup(group); - } - - } catch (PfModelException e) { - throw new PolicyPapRuntimeException("cannot load PDPs from the DB", e); - } - } - } - - /** - * Loads the PDPs appearing within a group. - * - * @param group group whose PDPs are to be loaded - */ - private void loadPdpsFromGroup(PdpGroup group) { - for (PdpSubGroup subgrp : group.getPdpSubgroups()) { - for (Pdp pdp : subgrp.getPdpInstances()) { - add(pdp.getInstanceId()); - } - } - } - - /** - * Adds a PDP to the tracker and starts its timer. If a timer is already running, the - * old timer is cancelled. - * - * @param pdpName name of the PDP - */ - public void add(String pdpName) { - synchronized (modifyLock) { - var timer = pdp2timer.remove(pdpName); - if (timer != null) { - timer.cancel(); - } - - timer = timers.register(pdpName, this::handleTimeout); - pdp2timer.put(pdpName, timer); - } - } - - /** - * Handles a timeout. Removes the PDP from {@link #pdp2timer}. - * - * @param pdpName name of the PDP whose timer has expired - */ - private void handleTimeout(String pdpName) { - synchronized (modifyLock) { - // remove timer - no need to cancel it, as TimerManager does that - logger.warn("missed heart beats - removing PDP {}", pdpName); - pdp2timer.remove(pdpName); - - try { - requestMap.removeFromGroups(pdpName); - - } catch (PfModelException e) { - logger.warn("unable to remove PDP {} from its group/subgroup", pdpName, e); - } - } - } -} diff --git a/main/src/main/java/org/onap/policy/pap/main/comm/msgdata/RequestImpl.java b/main/src/main/java/org/onap/policy/pap/main/comm/msgdata/RequestImpl.java index 9a1184b8..31b2df02 100644 --- a/main/src/main/java/org/onap/policy/pap/main/comm/msgdata/RequestImpl.java +++ b/main/src/main/java/org/onap/policy/pap/main/comm/msgdata/RequestImpl.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * ONAP PAP * ================================================================================ - * Copyright (C) 2019-2020 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2019-2021 AT&T Intellectual Property. All rights reserved. * Modifications Copyright (C) 2020 Bell Canada. All rights reserved. * Modifications Copyright (C) 2021 Nordix Foundation. * ================================================================================ @@ -293,7 +293,7 @@ public abstract class RequestImpl implements Request { if (!bumpRetryCount()) { logger.info("{} timeout {} - retry count {} exhausted", getName(), timerName, retryCount); - listener.retryCountExhausted(); + listener.retryCountExhausted(this); return; } diff --git a/main/src/main/java/org/onap/policy/pap/main/comm/msgdata/RequestListener.java b/main/src/main/java/org/onap/policy/pap/main/comm/msgdata/RequestListener.java index 4c53bd64..13ebfe3c 100644 --- a/main/src/main/java/org/onap/policy/pap/main/comm/msgdata/RequestListener.java +++ b/main/src/main/java/org/onap/policy/pap/main/comm/msgdata/RequestListener.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * ONAP PAP * ================================================================================ - * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2019, 2021 AT&T Intellectual Property. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -42,6 +42,8 @@ public interface RequestListener { /** * Indicates that the retry count was exhausted. + * + * @param request request whose count was exhausted */ - public void retryCountExhausted(); + public void retryCountExhausted(Request request); } diff --git a/main/src/main/java/org/onap/policy/pap/main/parameters/PdpModifyRequestMapParams.java b/main/src/main/java/org/onap/policy/pap/main/parameters/PdpModifyRequestMapParams.java index 9a3e7a45..65e3dc11 100644 --- a/main/src/main/java/org/onap/policy/pap/main/parameters/PdpModifyRequestMapParams.java +++ b/main/src/main/java/org/onap/policy/pap/main/parameters/PdpModifyRequestMapParams.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * ONAP PAP * ================================================================================ - * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2019, 2021 AT&T Intellectual Property. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ package org.onap.policy.pap.main.parameters; +import lombok.Builder; import lombok.Getter; import org.onap.policy.common.endpoints.listeners.RequestIdDispatcher; import org.onap.policy.models.pdp.concepts.PdpMessage; @@ -34,7 +35,9 @@ import org.onap.policy.pap.main.notification.PolicyNotifier; * Parameters needed to create a {@link PdpModifyRequestMapParams}. */ @Getter +@Builder public class PdpModifyRequestMapParams { + private long maxPdpAgeMs; private Publisher pdpPublisher; private RequestIdDispatcher responseDispatcher; private Object modifyLock; @@ -44,50 +47,14 @@ public class PdpModifyRequestMapParams { private PolicyModelsProviderFactoryWrapper daoFactory; private PolicyNotifier policyNotifier; - public PdpModifyRequestMapParams setParams(PdpParameters params) { - this.params = params; - return this; - } - - public PdpModifyRequestMapParams setUpdateTimers(TimerManager updateTimers) { - this.updateTimers = updateTimers; - return this; - } - - public PdpModifyRequestMapParams setStateChangeTimers(TimerManager stateChangeTimers) { - this.stateChangeTimers = stateChangeTimers; - return this; - } - - public PdpModifyRequestMapParams setDaoFactory(PolicyModelsProviderFactoryWrapper daoFactory) { - this.daoFactory = daoFactory; - return this; - } - - public PdpModifyRequestMapParams setPolicyNotifier(PolicyNotifier policyNotifier) { - this.policyNotifier = policyNotifier; - return this; - } - - public PdpModifyRequestMapParams setPdpPublisher(Publisher pdpPublisher) { - this.pdpPublisher = pdpPublisher; - return this; - } - - public PdpModifyRequestMapParams setResponseDispatcher(RequestIdDispatcher responseDispatcher) { - this.responseDispatcher = responseDispatcher; - return this; - } - - public PdpModifyRequestMapParams setModifyLock(Object modifyLock) { - this.modifyLock = modifyLock; - return this; - } - /** * Validates the parameters. */ public void validate() { + if (maxPdpAgeMs < 1) { + throw new IllegalArgumentException("maxPdpAgeMs must be >= 1"); + } + if (pdpPublisher == null) { throw new IllegalArgumentException("missing publisher"); } diff --git a/main/src/main/java/org/onap/policy/pap/main/startstop/PapActivator.java b/main/src/main/java/org/onap/policy/pap/main/startstop/PapActivator.java index 5c942341..78a301f6 100644 --- a/main/src/main/java/org/onap/policy/pap/main/startstop/PapActivator.java +++ b/main/src/main/java/org/onap/policy/pap/main/startstop/PapActivator.java @@ -22,6 +22,9 @@ package org.onap.policy.pap.main.startstop; import java.util.Arrays; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import org.onap.policy.common.endpoints.event.comm.TopicEndpointManager; import org.onap.policy.common.endpoints.event.comm.TopicSource; @@ -41,7 +44,6 @@ import org.onap.policy.pap.main.PolicyModelsProviderFactoryWrapper; import org.onap.policy.pap.main.PolicyPapRuntimeException; import org.onap.policy.pap.main.comm.PdpHeartbeatListener; import org.onap.policy.pap.main.comm.PdpModifyRequestMap; -import org.onap.policy.pap.main.comm.PdpTracker; import org.onap.policy.pap.main.comm.Publisher; import org.onap.policy.pap.main.comm.TimerManager; import org.onap.policy.pap.main.notification.PolicyNotifier; @@ -124,7 +126,7 @@ public class PapActivator extends ServiceManagerContainer { final AtomicReference> notifyPub = new AtomicReference<>(); final AtomicReference pdpUpdTimers = new AtomicReference<>(); final AtomicReference pdpStChgTimers = new AtomicReference<>(); - final AtomicReference heartBeatTimers = new AtomicReference<>(); + final AtomicReference pdpExpirationTimer = new AtomicReference<>(); final AtomicReference daoFactory = new AtomicReference<>(); final AtomicReference requestMap = new AtomicReference<>(); final AtomicReference restServer = new AtomicReference<>(); @@ -183,14 +185,6 @@ public class PapActivator extends ServiceManagerContainer { () -> Registry.register(PapConstants.REG_POLICY_NOTIFIER, notifier.get()), () -> Registry.unregister(PapConstants.REG_POLICY_NOTIFIER)); - addAction("PDP heart beat timers", - () -> { - long maxWaitHeartBeatMs = MAX_MISSED_HEARTBEATS * pdpParams.getHeartBeatMs(); - heartBeatTimers.set(new TimerManager("heart beat", maxWaitHeartBeatMs)); - startThread(heartBeatTimers.get()); - }, - () -> heartBeatTimers.get().stop()); - addAction("PDP update timers", () -> { pdpUpdTimers.set(new TimerManager("update", pdpParams.getUpdateParameters().getMaxWaitMs())); @@ -212,15 +206,17 @@ public class PapActivator extends ServiceManagerContainer { addAction("PDP modification requests", () -> { requestMap.set(new PdpModifyRequestMap( - new PdpModifyRequestMapParams() - .setDaoFactory(daoFactory.get()) - .setModifyLock(pdpUpdateLock) - .setParams(pdpParams) - .setPolicyNotifier(notifier.get()) - .setPdpPublisher(pdpPub.get()) - .setResponseDispatcher(reqIdDispatcher) - .setStateChangeTimers(pdpStChgTimers.get()) - .setUpdateTimers(pdpUpdTimers.get()))); + PdpModifyRequestMapParams.builder() + .maxPdpAgeMs(MAX_MISSED_HEARTBEATS * pdpParams.getHeartBeatMs()) + .daoFactory(daoFactory.get()) + .modifyLock(pdpUpdateLock) + .params(pdpParams) + .policyNotifier(notifier.get()) + .pdpPublisher(pdpPub.get()) + .responseDispatcher(reqIdDispatcher) + .stateChangeTimers(pdpStChgTimers.get()) + .updateTimers(pdpUpdTimers.get()) + .build())); Registry.register(PapConstants.REG_PDP_MODIFY_MAP, requestMap.get()); // now that it's registered, we can attach a "policy undeploy" provider @@ -228,14 +224,17 @@ public class PapActivator extends ServiceManagerContainer { }, () -> Registry.unregister(PapConstants.REG_PDP_MODIFY_MAP)); - addAction("PDP heart beat tracker", - () -> Registry.register(PapConstants.REG_PDP_TRACKER, PdpTracker.builder() - .daoFactory(daoFactory.get()) - .timers(heartBeatTimers.get()) - .modifyLock(pdpUpdateLock) - .requestMap(requestMap.get()) - .build()), - () -> Registry.unregister(PapConstants.REG_PDP_TRACKER)); + addAction("PDP expiration timer", + () -> { + long frequencyMs = pdpParams.getHeartBeatMs(); + pdpExpirationTimer.set(Executors.newScheduledThreadPool(1)); + pdpExpirationTimer.get().scheduleWithFixedDelay( + requestMap.get()::removeExpiredPdps, + frequencyMs, + frequencyMs, + TimeUnit.MILLISECONDS); + }, + () -> pdpExpirationTimer.get().shutdownNow()); addAction("PAP client executor", () -> diff --git a/main/src/test/java/org/onap/policy/pap/main/comm/CommonRequestBase.java b/main/src/test/java/org/onap/policy/pap/main/comm/CommonRequestBase.java index 45c278c5..0dc6636b 100644 --- a/main/src/test/java/org/onap/policy/pap/main/comm/CommonRequestBase.java +++ b/main/src/test/java/org/onap/policy/pap/main/comm/CommonRequestBase.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * ONAP PAP * ================================================================================ - * Copyright (C) 2019-2020 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2019-2021 AT&T Intellectual Property. All rights reserved. * Modifications Copyright (C) 2021 Nordix Foundation. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); @@ -62,10 +62,15 @@ import org.onap.policy.pap.main.parameters.RequestParams; */ public class CommonRequestBase { protected static final String PDP1 = "pdp_1"; + protected static final String PDP2 = "pdp_2"; + protected static final String PDP3 = "pdp_3"; + protected static final String PDP4 = "pdp_4"; protected static final String MY_REQ_NAME = "my-request"; protected static final String DIFFERENT = "different-value"; protected static final String MY_GROUP = "my-group"; + protected static final String MY_GROUP2 = "my-group-2"; protected static final String MY_SUBGROUP = "my-subgroup"; + protected static final String MY_SUBGROUP2 = "my-subgroup-2"; protected static final String MY_NAME = "my-name"; protected static final PdpState MY_STATE = PdpState.SAFE; protected static final PdpState DIFF_STATE = PdpState.TERMINATED; @@ -128,9 +133,10 @@ public class CommonRequestBase { reqParams = new RequestParams().setMaxRetryCount(RETRIES).setModifyLock(lock).setPdpPublisher(publisher) .setResponseDispatcher(dispatcher).setTimers(timers); - mapParams = new PdpModifyRequestMapParams().setModifyLock(lock).setPdpPublisher(publisher) - .setPolicyNotifier(notifier).setResponseDispatcher(dispatcher).setDaoFactory(daoFactory) - .setUpdateTimers(timers).setStateChangeTimers(timers).setParams(pdpParams); + mapParams = PdpModifyRequestMapParams.builder().modifyLock(lock).pdpPublisher(publisher) + .policyNotifier(notifier).responseDispatcher(dispatcher).daoFactory(daoFactory) + .updateTimers(timers).stateChangeTimers(timers).params(pdpParams) + .maxPdpAgeMs(100).build(); } /** diff --git a/main/src/test/java/org/onap/policy/pap/main/comm/PdpModifyRequestMapTest.java b/main/src/test/java/org/onap/policy/pap/main/comm/PdpModifyRequestMapTest.java index df036d25..0e9be09f 100644 --- a/main/src/test/java/org/onap/policy/pap/main/comm/PdpModifyRequestMapTest.java +++ b/main/src/test/java/org/onap/policy/pap/main/comm/PdpModifyRequestMapTest.java @@ -22,6 +22,7 @@ package org.onap.policy.pap.main.comm; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -37,10 +38,12 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.Iterator; import java.util.List; import java.util.stream.Collectors; import javax.ws.rs.core.Response.Status; @@ -53,13 +56,9 @@ import org.mockito.Captor; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import org.onap.policy.models.base.PfModelException; -import org.onap.policy.models.pap.concepts.PolicyNotification; -import org.onap.policy.models.pap.concepts.PolicyStatus; import org.onap.policy.models.pdp.concepts.Pdp; import org.onap.policy.models.pdp.concepts.PdpGroup; import org.onap.policy.models.pdp.concepts.PdpMessage; -import org.onap.policy.models.pdp.concepts.PdpPolicyStatus; -import org.onap.policy.models.pdp.concepts.PdpPolicyStatus.State; import org.onap.policy.models.pdp.concepts.PdpStateChange; import org.onap.policy.models.pdp.concepts.PdpStatus; import org.onap.policy.models.pdp.concepts.PdpSubGroup; @@ -75,6 +74,7 @@ import org.powermock.reflect.Whitebox; @RunWith(MockitoJUnitRunner.class) public class PdpModifyRequestMapTest extends CommonRequestBase { private static final String MY_REASON = "my reason"; + private static final int EXPIRED_SECONDS = 100; /** * Used to capture input to dao.createPdpGroups(). @@ -89,9 +89,6 @@ public class PdpModifyRequestMapTest extends CommonRequestBase { @Captor private ArgumentCaptor> updateCaptor; - @Captor - private ArgumentCaptor notificationCaptor; - /** * Used to capture input to undeployer.undeploy(). */ @@ -361,191 +358,93 @@ public class PdpModifyRequestMapTest extends CommonRequestBase { } @Test - public void testRemovePdp() throws Exception { - map.addRequest(update); + public void testRemoveExpiredPdps() throws Exception { + PdpGroup group1 = makeGroup(MY_GROUP); + group1.setPdpSubgroups(List.of(makeSubGroup(MY_SUBGROUP, PDP1))); - // put the PDP in a group - PdpGroup group = makeGroup(MY_GROUP); - group.setPdpSubgroups(Arrays.asList(makeSubGroup(MY_SUBGROUP, PDP1))); - - final ToscaConceptIdentifier policy1 = new ToscaConceptIdentifier("MyPolicy", "10.20.30"); - final ToscaConceptIdentifier policyType = new ToscaConceptIdentifier("MyPolicyType", "10.20.30"); - - // @formatter:off - when(dao.getFilteredPdpGroups(any())).thenReturn(Arrays.asList(group)); - when(dao.getGroupPolicyStatus(any())).thenReturn(Arrays.asList( - PdpPolicyStatus.builder() - .pdpGroup(MY_GROUP) - .pdpType(MY_SUBGROUP) - .pdpId(PDP1) - .policy(policy1) - .policyType(policyType) - .deploy(true) - .state(State.SUCCESS) - .build())); - // @formatter:on - - // indicate retries exhausted - invokeLastRetryHandler(1); - - // should have stopped publishing - verify(requests).stopPublishing(); + PdpGroup group2 = makeGroup(MY_GROUP2); + group2.setPdpSubgroups(List.of(makeSubGroup(MY_SUBGROUP, PDP2, PDP3), makeSubGroup(MY_SUBGROUP2, PDP4))); + + // expire all items in group2's first subgroup + Instant expired = Instant.now().minusSeconds(EXPIRED_SECONDS); + group2.getPdpSubgroups().get(0).getPdpInstances().forEach(pdp -> pdp.setLastUpdate(expired)); - // should have generated a notification; yes, it should go into the "added" set - verify(notifier).publish(notificationCaptor.capture()); - assertThat(notificationCaptor.getValue().getDeleted()).isEmpty(); - assertThat(notificationCaptor.getValue().getAdded()).hasSize(1); + when(dao.getFilteredPdpGroups(any())).thenReturn(List.of(group1, group2)); - PolicyStatus status = notificationCaptor.getValue().getAdded().get(0); - assertThat(status.getPolicy()).isEqualTo(policy1); - assertThat(status.getPolicyType()).isEqualTo(policyType); - assertThat(status.getFailureCount()).isZero(); - assertThat(status.getIncompleteCount()).isZero(); - assertThat(status.getSuccessCount()).isZero(); + // run it + map.removeExpiredPdps(); // should have removed from the group List groups = getGroupUpdates(); - assertEquals(1, groups.size()); - assertSame(group, groups.get(0)); - assertEquals(0, group.getPdpSubgroups().get(0).getCurrentInstanceCount()); - } - - @Test - public void testRemovePdp_NotInGroup() throws PfModelException { - map.addRequest(update); + assertThat(groups).hasSize(1); + assertThat(groups.get(0)).isSameAs(group2); + assertThat(group2.getPdpSubgroups()).hasSize(2); - // indicate retries exhausted - invokeLastRetryHandler(1); + final Iterator iter = group2.getPdpSubgroups().iterator(); - // should have stopped publishing - verify(requests).stopPublishing(); + PdpSubGroup subgrp = iter.next(); + assertThat(subgrp.getPdpInstances()).hasSize(0); + assertThat(subgrp.getCurrentInstanceCount()).isEqualTo(0); - // should not have done any updates - verify(dao, never()).updatePdpGroups(any()); - - // and no publishes - verify(notifier, never()).publish(any()); + subgrp = iter.next(); + assertThat(subgrp.getPdpInstances()).hasSize(1); + assertThat(subgrp.getCurrentInstanceCount()).isEqualTo(1); + assertThat(subgrp.getPdpInstances().get(0).getInstanceId()).isEqualTo(PDP4); } @Test - public void testRemovePdp_AlreadyRemovedFromMap() throws PfModelException { - map.addRequest(change); - map.stopPublishing(PDP1); + public void testRemoveExpiredPdps_NothingExpired() throws Exception { + PdpGroup group1 = makeGroup(MY_GROUP); + group1.setPdpSubgroups(List.of(makeSubGroup(MY_SUBGROUP, PDP1))); - // put the PDP in a group - PdpGroup group = makeGroup(MY_GROUP); - group.setPdpSubgroups(Arrays.asList(makeSubGroup(MY_SUBGROUP, PDP1))); + when(dao.getFilteredPdpGroups(any())).thenReturn(List.of(group1)); - invokeLastRetryHandler(1); - - // should have stopped publishing a second time - verify(requests, times(2)).stopPublishing(); + // run it + map.removeExpiredPdps(); - // should NOT have done any updates verify(dao, never()).updatePdpGroups(any()); + verify(publisher, never()).enqueue(any()); } @Test - public void testRemovePdp_NoGroup() throws PfModelException { - map.addRequest(change); - - invokeLastRetryHandler(1); - - // should not have stopped publishing - verify(requests).stopPublishing(); + public void testRemoveExpiredPdps_DaoEx() throws Exception { + when(dao.getFilteredPdpGroups(any())).thenThrow(makeException()); - // should not have done any updates - verify(dao, never()).updatePdpGroups(any()); + assertThatCode(map::removeExpiredPdps).doesNotThrowAnyException(); } @Test - public void testRemoveFromGroup() throws Exception { - map.addRequest(change); - + public void testRemoveFromSubgroup() throws Exception { PdpGroup group = makeGroup(MY_GROUP); - group.setPdpSubgroups(Arrays.asList(makeSubGroup(MY_SUBGROUP + "a", PDP1 + "a"), - makeSubGroup(MY_SUBGROUP, PDP1), makeSubGroup(MY_SUBGROUP + "c", PDP1 + "c"))); - - when(dao.getFilteredPdpGroups(any())).thenReturn(Arrays.asList(group)); + group.setPdpSubgroups(List.of(makeSubGroup(MY_SUBGROUP, PDP1, PDP2, PDP3))); - invokeLastRetryHandler(1); + // expire pdp1 and pdp3 + Instant expired = Instant.now().minusSeconds(EXPIRED_SECONDS); + List pdps = group.getPdpSubgroups().get(0).getPdpInstances(); + pdps.get(0).setLastUpdate(expired); + pdps.get(2).setLastUpdate(expired); - // verify that the PDP was removed from the subgroup - List groups = getGroupUpdates(); - assertEquals(1, groups.size()); - assertSame(group, groups.get(0)); - - List subgroups = group.getPdpSubgroups(); - assertEquals(3, subgroups.size()); - assertEquals("[pdp_1a]", getPdpNames(subgroups.get(0))); - assertEquals("[]", getPdpNames(subgroups.get(1))); - assertEquals("[pdp_1c]", getPdpNames(subgroups.get(2))); - } - - @Test - public void testRemoveFromGroup_DaoEx() throws Exception { - map.addRequest(change); - - when(dao.getFilteredPdpGroups(any())).thenThrow(makeException()); + when(dao.getFilteredPdpGroups(any())).thenReturn(List.of(group)); - invokeLastRetryHandler(1); + // run it + map.removeExpiredPdps(); - // should still stop publishing - verify(requests).stopPublishing(); + // should have removed from the group + List groups = getGroupUpdates(); + assertThat(groups).hasSize(1); + assertThat(groups.get(0)).isSameAs(group); + assertThat(group.getPdpSubgroups()).hasSize(1); + assertThat(group.getPdpSubgroups().get(0).getCurrentInstanceCount()).isEqualTo(1); - // requests should have been removed from the map so this should allocate another - map.addRequest(update); - assertEquals(2, map.nalloc); + pdps = group.getPdpSubgroups().get(0).getPdpInstances(); + assertThat(pdps).hasSize(1); + assertThat(pdps.get(0).getInstanceId()).isEqualTo(PDP2); } protected PfModelException makeException() { return new PfModelException(Status.BAD_REQUEST, "expected exception"); } - @Test - public void testRemoveFromGroup_NoGroups() throws Exception { - map.addRequest(change); - - invokeLastRetryHandler(1); - - verify(dao, never()).updatePdpGroups(any()); - } - - @Test - public void testRemoveFromGroup_NoMatchingSubgroup() throws Exception { - map.addRequest(change); - - PdpGroup group = makeGroup(MY_GROUP); - group.setPdpSubgroups(Arrays.asList(makeSubGroup(MY_SUBGROUP, DIFFERENT))); - - when(dao.getFilteredPdpGroups(any())).thenReturn(Arrays.asList(group)); - - invokeLastRetryHandler(1); - - verify(dao, never()).updatePdpGroups(any()); - } - - @Test - public void testRemoveFromSubgroup() throws Exception { - map.addRequest(change); - - PdpGroup group = makeGroup(MY_GROUP); - group.setPdpSubgroups(Arrays.asList(makeSubGroup(MY_SUBGROUP, PDP1, PDP1 + "x", PDP1 + "y"))); - - when(dao.getFilteredPdpGroups(any())).thenReturn(Arrays.asList(group)); - - invokeLastRetryHandler(1); - - // verify that the PDP was removed from the subgroup - List groups = getGroupUpdates(); - assertEquals(1, groups.size()); - assertSame(group, groups.get(0)); - - PdpSubGroup subgroup = group.getPdpSubgroups().get(0); - assertEquals(2, subgroup.getCurrentInstanceCount()); - assertEquals("[pdp_1x, pdp_1y]", getPdpNames(subgroup)); - } - @Test public void testMakePdpRequests() { // this should invoke the real method without throwing an exception @@ -740,10 +639,10 @@ public class PdpModifyRequestMapTest extends CommonRequestBase { @Test public void testSingletonListenerRetryCountExhausted() throws Exception { - map.addRequest(change); + final var request = map.addRequest(change); // invoke the method - invokeLastRetryHandler(1); + invokeLastRetryHandler(1, request); verify(requests).stopPublishing(); } @@ -771,19 +670,10 @@ public class PdpModifyRequestMapTest extends CommonRequestBase { * Invokes the first request's listener.retryCountExhausted() method. * * @param count expected number of requests + * @param request request whose count was exhausted */ - private void invokeLastRetryHandler(int count) { - getListener(getSingletons(count).get(0)).retryCountExhausted(); - } - - /** - * Gets the name of the PDPs contained within a subgroup. - * - * @param subgroup subgroup of interest - * @return the name of the PDPs contained within the subgroup - */ - private String getPdpNames(PdpSubGroup subgroup) { - return subgroup.getPdpInstances().stream().map(Pdp::getInstanceId).collect(Collectors.toList()).toString(); + private void invokeLastRetryHandler(int count, Request request) { + getListener(getSingletons(count).get(0)).retryCountExhausted(request); } /** @@ -821,6 +711,7 @@ public class PdpModifyRequestMapTest extends CommonRequestBase { PdpSubGroup subgroup = new PdpSubGroup(); subgroup.setPdpType(pdpType); + subgroup.setCurrentInstanceCount(pdpNames.length); subgroup.setPdpInstances(Arrays.asList(pdpNames).stream().map(this::makePdp).collect(Collectors.toList())); return subgroup; @@ -829,6 +720,7 @@ public class PdpModifyRequestMapTest extends CommonRequestBase { private Pdp makePdp(String pdpName) { Pdp pdp = new Pdp(); pdp.setInstanceId(pdpName); + pdp.setLastUpdate(Instant.now()); return pdp; } diff --git a/main/src/test/java/org/onap/policy/pap/main/comm/PdpTrackerTest.java b/main/src/test/java/org/onap/policy/pap/main/comm/PdpTrackerTest.java deleted file mode 100644 index ddfed87d..00000000 --- a/main/src/test/java/org/onap/policy/pap/main/comm/PdpTrackerTest.java +++ /dev/null @@ -1,212 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * ONAP PAP - * ================================================================================ - * Copyright (C) 2019-2021 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ - -package org.onap.policy.pap.main.comm; - -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.junit.Assert.assertNotNull; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.Collections; -import java.util.List; -import java.util.function.Consumer; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; -import org.onap.policy.common.utils.coder.StandardCoder; -import org.onap.policy.common.utils.resources.ResourceUtils; -import org.onap.policy.models.base.PfModelException; -import org.onap.policy.models.pdp.concepts.PdpGroup; -import org.onap.policy.models.pdp.concepts.PdpGroups; -import org.onap.policy.models.provider.PolicyModelsProvider; -import org.onap.policy.pap.main.PolicyModelsProviderFactoryWrapper; -import org.onap.policy.pap.main.PolicyPapRuntimeException; -import org.onap.policy.pap.main.comm.TimerManager.Timer; - -@RunWith(MockitoJUnitRunner.class) -public class PdpTrackerTest { - private static final String PDP1 = "pdp1"; - private static final String PDP2 = "pdp2"; - - private PdpTracker tracker; - private PdpTracker.PdpTrackerBuilder builder; - - private Object modifyLock; - - @Captor - private ArgumentCaptor> handlerCaptor; - - @Mock - private PdpModifyRequestMap requestMap; - - @Mock - private TimerManager timers; - - @Mock - private PolicyModelsProviderFactoryWrapper daoFactory; - - @Mock - private PolicyModelsProvider dao; - - @Mock - private Timer timer1; - - @Mock - private Timer timer2; - - /** - * Sets up. - * - * @throws Exception if an error occurs - */ - @Before - public void setUp() throws Exception { - modifyLock = new Object(); - - builder = PdpTracker.builder().daoFactory(daoFactory).modifyLock(modifyLock).requestMap(requestMap) - .timers(timers); - - when(daoFactory.create()).thenReturn(dao); - - when(dao.getPdpGroups(null)).thenReturn(Collections.emptyList()); - - when(timers.register(eq(PDP1), any())).thenReturn(timer1); - when(timers.register(eq(PDP2), any())).thenReturn(timer2); - - tracker = builder.build(); - } - - @Test - public void testPdpTracker() throws Exception { - // verify that PDPs were loaded - verify(dao).getPdpGroups(null); - } - - @Test - public void testBuilderToString() throws Exception { - assertNotNull(builder.toString()); - } - - @Test - public void testPdpTracker_MissingRequestMap() throws Exception { - assertThatThrownBy(() -> builder.requestMap(null)).isInstanceOf(NullPointerException.class); - } - - @Test - public void testPdpTracker_MissingModifyLock() throws Exception { - assertThatThrownBy(() -> builder.modifyLock(null)).isInstanceOf(NullPointerException.class); - } - - @Test - public void testPdpTracker_MissingTimers() throws Exception { - assertThatThrownBy(() -> builder.timers(null)).isInstanceOf(NullPointerException.class); - } - - @Test - public void testPdpTracker_MissingDaoFactory() throws Exception { - assertThatThrownBy(() -> builder.daoFactory(null)).isInstanceOf(NullPointerException.class); - } - - @Test - public void testLoadPdps_testLoadPdpsFromGroup() throws Exception { - // arrange for DAO to return a couple of groups - String groupsJson = ResourceUtils.getResourceAsString("comm/PdpTracker.json"); - List groups = new StandardCoder().decode(groupsJson, PdpGroups.class).getGroups(); - when(dao.getPdpGroups(null)).thenReturn(groups); - - tracker = builder.build(); - - // verify that all PDPs were registered - verify(timers).register(eq("pdp-A"), any()); - verify(timers).register(eq("pdp-B"), any()); - verify(timers).register(eq("pdp-C"), any()); - verify(timers).register(eq("pdp-D"), any()); - } - - @Test - public void testLoadPdps_DaoException() throws Exception { - // arrange for DAO to throw an exception - PfModelException ex = mock(PfModelException.class); - when(daoFactory.create()).thenThrow(ex); - - assertThatThrownBy(() -> builder.build()).isInstanceOf(PolicyPapRuntimeException.class).hasCause(ex); - } - - @Test - public void testAdd() { - tracker.add(PDP1); - verify(timers).register(eq(PDP1), any()); - verify(timer1, never()).cancel(); - - tracker.add(PDP2); - verify(timers).register(eq(PDP2), any()); - verify(timer1, never()).cancel(); - verify(timer2, never()).cancel(); - - // re-add PDP1 - old timer should be canceled and a new timer added - Timer timer3 = mock(Timer.class); - when(timers.register(eq(PDP1), any())).thenReturn(timer3); - tracker.add(PDP1); - verify(timer1).cancel(); - verify(timer2, never()).cancel(); - verify(timer3, never()).cancel(); - } - - @Test - public void testHandleTimeout() throws Exception { - tracker.add(PDP1); - tracker.add(PDP2); - - verify(timers).register(eq(PDP1), handlerCaptor.capture()); - - handlerCaptor.getValue().accept(PDP1); - - verify(requestMap).removeFromGroups(PDP1); - - // now we'll re-add PDP1 - the original timer should not be canceled - Timer timer3 = mock(Timer.class); - when(timers.register(eq(PDP1), any())).thenReturn(timer3); - tracker.add(PDP1); - verify(timer1, never()).cancel(); - } - - @Test - public void testHandleTimeout_MapException() throws Exception { - tracker.add(PDP1); - - verify(timers).register(eq(PDP1), handlerCaptor.capture()); - - // arrange for request map to throw an exception - PfModelException ex = mock(PfModelException.class); - when(requestMap.removeFromGroups(PDP1)).thenThrow(ex); - - // exception should be caught, but not re-thrown - handlerCaptor.getValue().accept(PDP1); - } -} diff --git a/main/src/test/java/org/onap/policy/pap/main/comm/msgdata/RequestImplTest.java b/main/src/test/java/org/onap/policy/pap/main/comm/msgdata/RequestImplTest.java index 36209ead..abce7eb3 100644 --- a/main/src/test/java/org/onap/policy/pap/main/comm/msgdata/RequestImplTest.java +++ b/main/src/test/java/org/onap/policy/pap/main/comm/msgdata/RequestImplTest.java @@ -361,7 +361,7 @@ public class RequestImplTest extends CommonRequestBase { // should NOT have invoked startPublishing() a second time verify(dispatcher, times(1)).register(eq(msg.getRequestId()), any()); - verify(listener, never()).retryCountExhausted(); + verify(listener, never()).retryCountExhausted(any()); } @Test @@ -381,7 +381,7 @@ public class RequestImplTest extends CommonRequestBase { // should NOT have invoked startPublishing() a second time verify(dispatcher, times(1)).register(eq(msg.getRequestId()), any()); - verify(listener).retryCountExhausted(); + verify(listener).retryCountExhausted(req); } @Test diff --git a/main/src/test/java/org/onap/policy/pap/main/parameters/TestPdpModifyRequestMapParams.java b/main/src/test/java/org/onap/policy/pap/main/parameters/TestPdpModifyRequestMapParams.java index 629cf24c..b77c5544 100644 --- a/main/src/test/java/org/onap/policy/pap/main/parameters/TestPdpModifyRequestMapParams.java +++ b/main/src/test/java/org/onap/policy/pap/main/parameters/TestPdpModifyRequestMapParams.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * ONAP PAP * ================================================================================ - * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2019, 2021 AT&T Intellectual Property. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,8 @@ package org.onap.policy.pap.main.parameters; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.junit.Assert.assertSame; import static org.mockito.Mockito.mock; @@ -33,9 +35,11 @@ import org.onap.policy.pap.main.PolicyModelsProviderFactoryWrapper; import org.onap.policy.pap.main.comm.Publisher; import org.onap.policy.pap.main.comm.TimerManager; import org.onap.policy.pap.main.notification.PolicyNotifier; +import org.onap.policy.pap.main.parameters.PdpModifyRequestMapParams.PdpModifyRequestMapParamsBuilder; public class TestPdpModifyRequestMapParams { - private PdpModifyRequestMapParams params; + private static final long MAX_PDP_AGE_MS = 100; + private PdpModifyRequestMapParamsBuilder builder; private Publisher pub; private RequestIdDispatcher disp; private Object lock; @@ -46,7 +50,7 @@ public class TestPdpModifyRequestMapParams { private PolicyNotifier notifier; /** - * Sets up the objects and creates an empty {@link #params}. + * Sets up the objects and creates an empty {@link #builder}. */ @Before @SuppressWarnings("unchecked") @@ -60,13 +64,15 @@ public class TestPdpModifyRequestMapParams { dao = mock(PolicyModelsProviderFactoryWrapper.class); notifier = mock(PolicyNotifier.class); - params = new PdpModifyRequestMapParams().setModifyLock(lock).setPdpPublisher(pub).setResponseDispatcher(disp) - .setParams(pdpParams).setStateChangeTimers(stateTimers).setUpdateTimers(updTimers) - .setDaoFactory(dao).setPolicyNotifier(notifier); + builder = PdpModifyRequestMapParams.builder().modifyLock(lock).pdpPublisher(pub).responseDispatcher(disp) + .params(pdpParams).stateChangeTimers(stateTimers).updateTimers(updTimers) + .daoFactory(dao).policyNotifier(notifier).maxPdpAgeMs(MAX_PDP_AGE_MS); } @Test public void testGettersSetters() { + PdpModifyRequestMapParams params = builder.build(); + assertThat(params.getMaxPdpAgeMs()).isEqualTo(MAX_PDP_AGE_MS); assertSame(pub, params.getPdpPublisher()); assertSame(disp, params.getResponseDispatcher()); assertSame(lock, params.getModifyLock()); @@ -79,55 +85,64 @@ public class TestPdpModifyRequestMapParams { @Test public void testValidate() { - // no exception - params.validate(); + assertThatCode(builder.build()::validate).doesNotThrowAnyException(); + } + + @Test + public void testValidate_InvalidMaxPdpAge() { + assertThatIllegalArgumentException().isThrownBy(() -> builder.maxPdpAgeMs(0).build().validate()) + .withMessageContaining("maxPdpAgeMs"); + assertThatIllegalArgumentException().isThrownBy(() -> builder.maxPdpAgeMs(-1).build().validate()) + .withMessageContaining("maxPdpAgeMs"); + + assertThatCode(builder.maxPdpAgeMs(1).build()::validate).doesNotThrowAnyException(); } @Test public void testValidate_MissingPublisher() { - assertThatIllegalArgumentException().isThrownBy(() -> params.setPdpPublisher(null).validate()) + assertThatIllegalArgumentException().isThrownBy(() -> builder.pdpPublisher(null).build().validate()) .withMessageContaining("publisher"); } @Test public void testValidate_MissingDispatcher() { - assertThatIllegalArgumentException().isThrownBy(() -> params.setResponseDispatcher(null).validate()) + assertThatIllegalArgumentException().isThrownBy(() -> builder.responseDispatcher(null).build().validate()) .withMessageContaining("Dispatch"); } @Test public void testValidate_MissingLock() { - assertThatIllegalArgumentException().isThrownBy(() -> params.setModifyLock(null).validate()) + assertThatIllegalArgumentException().isThrownBy(() -> builder.modifyLock(null).build().validate()) .withMessageContaining("Lock"); } @Test public void testValidate_MissingPdpParams() { - assertThatIllegalArgumentException().isThrownBy(() -> params.setParams(null).validate()) + assertThatIllegalArgumentException().isThrownBy(() -> builder.params(null).build().validate()) .withMessageContaining("PDP param"); } @Test public void testValidate_MissingStateChangeTimers() { - assertThatIllegalArgumentException().isThrownBy(() -> params.setStateChangeTimers(null).validate()) + assertThatIllegalArgumentException().isThrownBy(() -> builder.stateChangeTimers(null).build().validate()) .withMessageContaining("state"); } @Test public void testValidate_MissingUpdateTimers() { - assertThatIllegalArgumentException().isThrownBy(() -> params.setUpdateTimers(null).validate()) + assertThatIllegalArgumentException().isThrownBy(() -> builder.updateTimers(null).build().validate()) .withMessageContaining("update"); } @Test public void testValidate_MissingDaoFactory() { - assertThatIllegalArgumentException().isThrownBy(() -> params.setDaoFactory(null).validate()) + assertThatIllegalArgumentException().isThrownBy(() -> builder.daoFactory(null).build().validate()) .withMessageContaining("DAO"); } @Test public void testValidate_MissingNotifier() { - assertThatIllegalArgumentException().isThrownBy(() -> params.setPolicyNotifier(null).validate()) + assertThatIllegalArgumentException().isThrownBy(() -> builder.policyNotifier(null).build().validate()) .withMessageContaining("notifier"); } } diff --git a/main/src/test/java/org/onap/policy/pap/main/startstop/TestMain.java b/main/src/test/java/org/onap/policy/pap/main/startstop/TestMain.java index 12f740b4..a83be4fb 100644 --- a/main/src/test/java/org/onap/policy/pap/main/startstop/TestMain.java +++ b/main/src/test/java/org/onap/policy/pap/main/startstop/TestMain.java @@ -1,7 +1,7 @@ /* * ============LICENSE_START======================================================= * Copyright (C) 2019-2020 Nordix Foundation. - * Modifications Copyright (C) 2019 AT&T Intellectual Property. + * Modifications Copyright (C) 2019, 2021 AT&T Intellectual Property. * Modifications Copyright (C) 2020 Bell Canada. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); @@ -28,10 +28,15 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import java.io.File; +import java.io.FileOutputStream; +import java.nio.charset.StandardCharsets; import org.junit.After; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; import org.onap.policy.common.endpoints.http.server.HttpServletServerFactoryInstance; +import org.onap.policy.common.utils.network.NetworkUtil; import org.onap.policy.common.utils.resources.MessageConstants; import org.onap.policy.common.utils.services.Registry; import org.onap.policy.pap.main.PapConstants; @@ -44,13 +49,35 @@ import org.onap.policy.pap.main.parameters.CommonTestData; * @author Ram Krishna Verma (ram.krishna.verma@est.tech) */ public class TestMain { + private static final String CONFIG_FILE = "src/test/resources/parameters/TestConfigParams.json"; + + private static int port; + private Main main; + /** + * Allocates a new DB name, server port, and creates a config file. + */ + @BeforeClass + public static void setUpBeforeClass() throws Exception { + CommonTestData.newDb(); + port = NetworkUtil.allocPort(); + + String json = new CommonTestData().getPapParameterGroupAsString(port); + + File file = new File(CONFIG_FILE); + file.deleteOnExit(); + + try (FileOutputStream output = new FileOutputStream(file)) { + output.write(json.getBytes(StandardCharsets.UTF_8)); + } + } + /** * Set up. */ @Before - public void setUp() { + public void setUp() throws Exception { Registry.newRegistry(); HttpServletServerFactoryInstance.getServerFactory().destroy(); } @@ -80,7 +107,7 @@ public class TestMain { @Test public void testMain() { - final String[] papConfigParameters = {"-c", "parameters/PapConfigParameters.json"}; + final String[] papConfigParameters = {"-c", CONFIG_FILE}; testMainBody(papConfigParameters); } @@ -88,7 +115,7 @@ public class TestMain { public void testMainCustomGroup() { final String[] papConfigParameters = { "-c", - "parameters/PapConfigParameters.json", + CONFIG_FILE, "-g", "parameters/PapDbGroup1.json" }; @@ -99,7 +126,7 @@ public class TestMain { public void testMainPapDb() { final String[] papConfigParameters = { "-c", - "parameters/PapConfigParameters.json", + CONFIG_FILE, "-g", "PapDb.json" }; @@ -115,7 +142,7 @@ public class TestMain { @Test public void testMain_InvalidArguments() { - final String[] papConfigParameters = {"parameters/PapConfigParameters.json"}; + final String[] papConfigParameters = {CONFIG_FILE}; assertThatThrownBy(() -> new Main(papConfigParameters)).isInstanceOf(PolicyPapRuntimeException.class) .hasMessage(String.format(MessageConstants.START_FAILURE_MSG, MessageConstants.POLICY_PAP)); } diff --git a/main/src/test/java/org/onap/policy/pap/main/startstop/TestPapActivator.java b/main/src/test/java/org/onap/policy/pap/main/startstop/TestPapActivator.java index 19668b31..63ca52a8 100644 --- a/main/src/test/java/org/onap/policy/pap/main/startstop/TestPapActivator.java +++ b/main/src/test/java/org/onap/policy/pap/main/startstop/TestPapActivator.java @@ -1,7 +1,7 @@ /*- * ============LICENSE_START======================================================= * Copyright (C) 2019 Nordix Foundation. - * Modifications Copyright (C) 2019 AT&T Intellectual Property. + * Modifications Copyright (C) 2019, 2021 AT&T Intellectual Property. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,15 +28,19 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import java.io.File; +import java.io.FileOutputStream; +import java.nio.charset.StandardCharsets; import org.junit.After; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; import org.onap.policy.common.endpoints.http.server.HttpServletServerFactoryInstance; +import org.onap.policy.common.utils.network.NetworkUtil; import org.onap.policy.common.utils.services.Registry; import org.onap.policy.pap.main.PapConstants; import org.onap.policy.pap.main.PolicyPapException; import org.onap.policy.pap.main.comm.PdpModifyRequestMap; -import org.onap.policy.pap.main.comm.PdpTracker; import org.onap.policy.pap.main.notification.PolicyNotifier; import org.onap.policy.pap.main.parameters.CommonTestData; import org.onap.policy.pap.main.parameters.PapParameterGroup; @@ -50,9 +54,20 @@ import org.onap.policy.pap.main.rest.PapStatisticsManager; * @author Ram Krishna Verma (ram.krishna.verma@est.tech) */ public class TestPapActivator { + private static final String CONFIG_FILE = "src/test/resources/parameters/TestConfigParams.json"; + + private static int port; private PapActivator activator; + /** + * Allocates a new DB name, server port, and creates a config file. + */ + @BeforeClass + public static void setUpBeforeClass() throws Exception { + CommonTestData.newDb(); + } + /** * Initializes an activator. * @@ -63,7 +78,18 @@ public class TestPapActivator { Registry.newRegistry(); HttpServletServerFactoryInstance.getServerFactory().destroy(); - final String[] papConfigParameters = {"-c", "parameters/PapConfigParameters.json"}; + port = NetworkUtil.allocPort(); + + String json = new CommonTestData().getPapParameterGroupAsString(port); + + File file = new File(CONFIG_FILE); + file.deleteOnExit(); + + try (FileOutputStream output = new FileOutputStream(file)) { + output.write(json.getBytes(StandardCharsets.UTF_8)); + } + + final String[] papConfigParameters = {"-c", CONFIG_FILE}; final PapCommandLineArguments arguments = new PapCommandLineArguments(papConfigParameters); final PapParameterGroup parGroup = new PapParameterHandler().getParameters(arguments); @@ -94,7 +120,6 @@ public class TestPapActivator { assertNotNull(Registry.get(PapConstants.REG_PDP_MODIFY_LOCK, Object.class)); assertNotNull(Registry.get(PapConstants.REG_STATISTICS_MANAGER, PapStatisticsManager.class)); assertNotNull(Registry.get(PapConstants.REG_PDP_MODIFY_MAP, PdpModifyRequestMap.class)); - assertNotNull(Registry.get(PapConstants.REG_PDP_TRACKER, PdpTracker.class)); assertNotNull(Registry.get(PapConstants.REG_POLICY_NOTIFIER, PolicyNotifier.class)); // repeat - should throw an exception @@ -113,7 +138,6 @@ public class TestPapActivator { assertNull(Registry.getOrDefault(PapConstants.REG_PDP_MODIFY_LOCK, Object.class, null)); assertNull(Registry.getOrDefault(PapConstants.REG_STATISTICS_MANAGER, PapStatisticsManager.class, null)); assertNull(Registry.getOrDefault(PapConstants.REG_PDP_MODIFY_MAP, PdpModifyRequestMap.class, null)); - assertNull(Registry.getOrDefault(PapConstants.REG_PDP_TRACKER, PdpTracker.class, null)); assertNull(Registry.getOrDefault(PapConstants.REG_POLICY_NOTIFIER, PolicyNotifier.class, null)); // repeat - should throw an exception diff --git a/main/src/test/resources/parameters/MinimumParameters.json b/main/src/test/resources/parameters/MinimumParameters.json index 69492e9b..0c23006c 100644 --- a/main/src/test/resources/parameters/MinimumParameters.json +++ b/main/src/test/resources/parameters/MinimumParameters.json @@ -1,8 +1,8 @@ -{ +{ "name":"PapGroup", "restServerParameters":{ "host":"0.0.0.0", - "port":6969, + "port":6901, "userName":"healthcheck", "password":"zb!XztG34" }, diff --git a/main/src/test/resources/parameters/PapConfigParameters.json b/main/src/test/resources/parameters/PapConfigParameters.json index 111a6352..c9eb3a3a 100644 --- a/main/src/test/resources/parameters/PapConfigParameters.json +++ b/main/src/test/resources/parameters/PapConfigParameters.json @@ -2,7 +2,7 @@ "name": "PapGroup", "restServerParameters": { "host": "0.0.0.0", - "port": 6969, + "port": 6903, "userName": "healthcheck", "password": "zb!XztG34", "https": true diff --git a/main/src/test/resources/parameters/PapConfigParameters_InvalidName.json b/main/src/test/resources/parameters/PapConfigParameters_InvalidName.json index 15e608ba..3e812459 100644 --- a/main/src/test/resources/parameters/PapConfigParameters_InvalidName.json +++ b/main/src/test/resources/parameters/PapConfigParameters_InvalidName.json @@ -2,7 +2,7 @@ "name":" ", "restServerParameters":{ "host":"0.0.0.0", - "port":6969, + "port":6902, "userName":"healthcheck", "password":"zb!XztG34" }, diff --git a/main/src/test/resources/parameters/PapConfigParameters_sim.json b/main/src/test/resources/parameters/PapConfigParameters_sim.json deleted file mode 100644 index 84b88e31..00000000 --- a/main/src/test/resources/parameters/PapConfigParameters_sim.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "name": "PapGroup", - "restServerParameters": { - "host": "0.0.0.0", - "port": 6969, - "userName": "healthcheck", - "password": "zb!XztG34", - "https": true - }, - "pdpParameters": { - "heartBeatMs": 10, - "updateParameters": { - "maxRetryCount": 1, - "maxWaitMs": 30000 - }, - "stateChangeParameters": { - "maxRetryCount": 1, - "maxWaitMs": 30000 - } - }, - "databaseProviderParameters": { - "name": "PolicyProviderParameterGroup", - "implementation": "org.onap.policy.models.provider.impl.DatabasePolicyModelsProviderImpl", - "databaseDriver": "org.mariadb.jdbc.Driver", - "databaseUrl": "jdbc:mariadb://localhost:3306/policyadmin", - "databaseUser": "policy", - "databasePassword": "UDAxaWNZ", - "persistenceUnit": "PolicyMariaDb" - }, - "topicParameterGroup": { - "topicSources" : [{ - "topic" : "POLICY-PDP-PAP", - "servers" : [ "localhost:6845" ], - "topicCommInfrastructure" : "dmaap" - }], - "topicSinks" : [{ - "topic" : "POLICY-PDP-PAP", - "servers" : [ "localhost:6845" ], - "topicCommInfrastructure" : "dmaap" - }] - } -} -- cgit 1.2.3-korg