Repository: ambari Updated Branches: refs/heads/trunk 27d06a1bd -> 18449b5b8
AMBARI-15686 - Alert Dispatch Scheduling Changes to Support Repeat Tolerance (jonathanhurley) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/18449b5b Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/18449b5b Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/18449b5b Branch: refs/heads/trunk Commit: 18449b5b804790c15f0917ccb43b9a8be4bd5ca1 Parents: 27d06a1 Author: Jonathan Hurley <[email protected]> Authored: Mon Apr 4 11:33:36 2016 -0400 Committer: Jonathan Hurley <[email protected]> Committed: Mon Apr 4 15:49:42 2016 -0400 ---------------------------------------------------------------------- .../internal/AlertResourceProvider.java | 7 +- .../server/events/AlertStateChangeEvent.java | 7 +- .../alerts/AlertAggregateListener.java | 15 +- .../listeners/alerts/AlertReceivedListener.java | 157 +++++++++----- .../alerts/AlertStateChangedListener.java | 20 +- .../server/orm/entities/AlertCurrentEntity.java | 34 ++- .../org/apache/ambari/server/state/Alert.java | 106 +++++++--- .../ambari/server/state/AlertFirmness.java | 37 ++++ .../server/upgrade/UpgradeCatalog240.java | 10 +- .../main/resources/Ambari-DDL-Derby-CREATE.sql | 3 +- .../main/resources/Ambari-DDL-MySQL-CREATE.sql | 3 +- .../main/resources/Ambari-DDL-Oracle-CREATE.sql | 3 +- .../resources/Ambari-DDL-Postgres-CREATE.sql | 3 +- .../Ambari-DDL-Postgres-EMBEDDED-CREATE.sql | 3 +- .../resources/Ambari-DDL-SQLAnywhere-CREATE.sql | 3 +- .../resources/Ambari-DDL-SQLServer-CREATE.sql | 3 +- .../alerts/AggregateAlertListenerTest.java | 92 ++++++-- .../state/alerts/AlertReceivedListenerTest.java | 211 ++++++++++++++++++- .../alerts/AlertStateChangedEventTest.java | 102 +++++++-- .../state/alerts/InitialAlertEventTest.java | 21 +- .../server/upgrade/UpgradeCatalog240Test.java | 15 +- 21 files changed, 696 insertions(+), 159 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/18449b5b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertResourceProvider.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertResourceProvider.java index 5a985d6..4c20c6c 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertResourceProvider.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertResourceProvider.java @@ -77,6 +77,7 @@ public class AlertResourceProvider extends ReadOnlyResourceProvider implements protected static final String ALERT_REPEAT_TOLERANCE = "Alert/repeat_tolerance"; protected static final String ALERT_OCCURRENCES = "Alert/occurrences"; protected static final String ALERT_REPEAT_TOLERANCE_REMAINING = "Alert/repeat_tolerance_remaining"; + protected static final String ALERT_FIRMNESS = "Alert/firmness"; private static Set<String> pkPropertyIds = new HashSet<String>( Arrays.asList(ALERT_ID, ALERT_DEFINITION_NAME)); @@ -117,6 +118,7 @@ public class AlertResourceProvider extends ReadOnlyResourceProvider implements PROPERTY_IDS.add(ALERT_REPEAT_TOLERANCE); PROPERTY_IDS.add(ALERT_OCCURRENCES); PROPERTY_IDS.add(ALERT_REPEAT_TOLERANCE_REMAINING); + PROPERTY_IDS.add(ALERT_FIRMNESS); // keys KEY_PROPERTY_IDS.put(Resource.Type.Alert, ALERT_ID); @@ -264,8 +266,8 @@ public class AlertResourceProvider extends ReadOnlyResourceProvider implements // repeat tolerance values int repeatTolerance = definition.getRepeatTolerance(); - int occurrences = entity.getOccurrences(); - int remaining = (occurrences > repeatTolerance) ? 0 : (repeatTolerance - occurrences); + long occurrences = entity.getOccurrences(); + long remaining = (occurrences > repeatTolerance) ? 0 : (repeatTolerance - occurrences); // the OK state is special; when received, we ignore tolerance and notify if (history.getAlertState() == AlertState.OK) { @@ -275,6 +277,7 @@ public class AlertResourceProvider extends ReadOnlyResourceProvider implements setResourceProperty(resource, ALERT_REPEAT_TOLERANCE, repeatTolerance, requestedIds); setResourceProperty(resource, ALERT_OCCURRENCES, occurrences, requestedIds); setResourceProperty(resource, ALERT_REPEAT_TOLERANCE_REMAINING, remaining, requestedIds); + setResourceProperty(resource, ALERT_FIRMNESS, entity.getFirmness(), requestedIds); if (isCollection) { // !!! want name/id to be populated as if it were a PK when requesting the http://git-wip-us.apache.org/repos/asf/ambari/blob/18449b5b/ambari-server/src/main/java/org/apache/ambari/server/events/AlertStateChangeEvent.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/AlertStateChangeEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/events/AlertStateChangeEvent.java index 60dbec4..ac1eb8d 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/events/AlertStateChangeEvent.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/events/AlertStateChangeEvent.java @@ -20,11 +20,15 @@ package org.apache.ambari.server.events; import org.apache.ambari.server.orm.entities.AlertCurrentEntity; import org.apache.ambari.server.orm.entities.AlertHistoryEntity; import org.apache.ambari.server.state.Alert; +import org.apache.ambari.server.state.AlertFirmness; import org.apache.ambari.server.state.AlertState; /** * The {@link AlertStateChangeEvent} is fired when an {@link Alert} instance has - * its {@link AlertState} changed. + * its {@link AlertState} changed or has it's {@link AlertFirmness} changed. + * <p/> + * An {@link AlertState} change coupled with a {@link AlertFirmness#HARD} + * firmness is what would eventually trigger notifications to be created. */ public class AlertStateChangeEvent extends AlertEvent { @@ -93,6 +97,7 @@ public class AlertStateChangeEvent extends AlertEvent { StringBuilder buffer = new StringBuilder("AlertStateChangeEvent{"); buffer.append("cluserId=").append(m_clusterId); buffer.append(", fromState=").append(m_fromState); + buffer.append(", firmness=").append(m_currentAlert.getFirmness()); buffer.append(", alert=").append(m_alert); buffer.append("}"); http://git-wip-us.apache.org/repos/asf/ambari/blob/18449b5b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertAggregateListener.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertAggregateListener.java b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertAggregateListener.java index 0bcfa2f..950797c 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertAggregateListener.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertAggregateListener.java @@ -22,7 +22,6 @@ import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import com.google.inject.Provider; import org.apache.ambari.server.AmbariException; import org.apache.ambari.server.EagerSingleton; import org.apache.ambari.server.events.AggregateAlertRecalculateEvent; @@ -32,7 +31,9 @@ import org.apache.ambari.server.events.InitialAlertEvent; import org.apache.ambari.server.events.publishers.AlertEventPublisher; import org.apache.ambari.server.orm.dao.AlertSummaryDTO; import org.apache.ambari.server.orm.dao.AlertsDAO; +import org.apache.ambari.server.orm.entities.AlertCurrentEntity; import org.apache.ambari.server.state.Alert; +import org.apache.ambari.server.state.AlertFirmness; import org.apache.ambari.server.state.AlertState; import org.apache.ambari.server.state.Clusters; import org.apache.ambari.server.state.alert.AggregateDefinitionMapping; @@ -47,6 +48,7 @@ import org.slf4j.LoggerFactory; import com.google.common.eventbus.AllowConcurrentEvents; import com.google.common.eventbus.Subscribe; import com.google.inject.Inject; +import com.google.inject.Provider; import com.google.inject.Singleton; /** @@ -56,7 +58,10 @@ import com.google.inject.Singleton; * <p/> * This listener is only needed on state changes as aggregation of alerts is * only performed against the state of an alert and not the values that - * contributed to that state. + * contributed to that state. However, this listener should only be concerned + * with {@link AlertFirmness#HARD} events as they represent a true change in the + * state of an alert. Calculations should never be performed on + * {@link AlertFirmness#SOFT} alerts since they may be false positives. */ @Singleton @EagerSingleton @@ -118,6 +123,12 @@ public class AlertAggregateListener { public void onAlertStateChangeEvent(AlertStateChangeEvent event) { LOG.debug("Received event {}", event); + // do not recalculate on SOFT events + AlertCurrentEntity currentEntity = event.getCurrentAlert(); + if (currentEntity.getFirmness() == AlertFirmness.SOFT) { + return; + } + onAlertEvent(event.getClusterId(), event.getAlert().getName()); } http://git-wip-us.apache.org/repos/asf/ambari/blob/18449b5b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertReceivedListener.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertReceivedListener.java b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertReceivedListener.java index fbd5c12..2800ac6 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertReceivedListener.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertReceivedListener.java @@ -17,9 +17,8 @@ */ package org.apache.ambari.server.events.listeners.alerts; -import java.util.HashMap; +import java.util.ArrayList; import java.util.List; -import java.util.Map; import org.apache.ambari.server.AmbariException; import org.apache.ambari.server.EagerSingleton; @@ -39,10 +38,12 @@ import org.apache.ambari.server.orm.entities.AlertCurrentEntity; import org.apache.ambari.server.orm.entities.AlertDefinitionEntity; import org.apache.ambari.server.orm.entities.AlertHistoryEntity; import org.apache.ambari.server.state.Alert; +import org.apache.ambari.server.state.AlertFirmness; import org.apache.ambari.server.state.AlertState; import org.apache.ambari.server.state.Cluster; import org.apache.ambari.server.state.Clusters; import org.apache.ambari.server.state.MaintenanceState; +import org.apache.ambari.server.state.alert.SourceType; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -122,13 +123,15 @@ public class AlertReceivedListener { LOG.debug(event.toString()); } - //play around too many commits + // process the list of alerts inside of a single transaction to prevent too + // many transactions/commits List<Alert> alerts = event.getAlerts(); - Map<Alert, AlertCurrentEntity> toCreate = new HashMap<Alert, AlertCurrentEntity>(); - Map<Alert, AlertCurrentEntity> toMerge = new HashMap<Alert, AlertCurrentEntity>(); - Map<Alert, AlertCurrentEntity> toCreateHistoryAndMerge = new HashMap<Alert, AlertCurrentEntity>(); - Map<Alert, AlertState> oldStates = new HashMap<Alert, AlertState>(); + List<AlertCurrentEntity> toCreate = new ArrayList<>(); + List<AlertCurrentEntity> toMerge = new ArrayList<>(); + List<AlertCurrentEntity> toCreateHistoryAndMerge = new ArrayList<>(); + + List<AlertEvent> alertEvents = new ArrayList<>(20); for (Alert alert : alerts) { // jobs that were running when a service/component/host was changed @@ -139,7 +142,7 @@ public class AlertReceivedListener { Long clusterId = getClusterIdByName(alert.getCluster()); if (clusterId == null) { - //check event + // check event clusterId = event.getClusterId(); } @@ -199,21 +202,45 @@ public class AlertReceivedListener { current.setLatestTimestamp(alert.getTimestamp()); current.setOriginalTimestamp(alert.getTimestamp()); - toCreate.put(alert, current); + // brand new alert instances being received are always HARD + current.setFirmness(AlertFirmness.HARD); + + // store the entity for creation later + toCreate.add(current); + + // create the event to fire later + alertEvents.add(new InitialAlertEvent(clusterId, alert, current)); } else if (alertState == current.getAlertHistory().getAlertState() || alertState == AlertState.SKIPPED) { - // update the timestamp + // update the timestamp no matter what current.setLatestTimestamp(alert.getTimestamp()); - // only update some fields if the alert isn't being skipped + // only update some fields if the alert isn't SKIPPED if (alertState != AlertState.SKIPPED) { current.setLatestText(alert.getText()); - current.setOccurrences(current.getOccurrences() + 1); + + // ++ the occurrences (should be safe enough since we should ever only + // be handling unique alert events concurrently + long occurrences = current.getOccurrences() + 1; + current.setOccurrences(occurrences); + + // ensure that if we've met the repeat tolerance and the alert is + // still SOFT, then we transition it to HARD - we also need to fire an + // event + AlertFirmness currentFirmness = current.getFirmness(); + int repeatTolerance = definition.getRepeatTolerance(); + if (currentFirmness == AlertFirmness.SOFT && occurrences >= repeatTolerance) { + current.setFirmness(AlertFirmness.HARD); + + // create the event to fire later + alertEvents.add(new AlertStateChangeEvent(clusterId, alert, current, alertState)); + } } - toMerge.put(alert, current); + // store the entity for merging later + toMerge.add(current); } else { if (LOG.isDebugEnabled()) { LOG.debug( @@ -258,8 +285,17 @@ public class AlertReceivedListener { break; } - toCreateHistoryAndMerge.put(alert, current); - oldStates.put(alert, oldState); + // set the firmness of the new alert state based on the state & type + AlertFirmness firmness = calculateFirmnessForStateChange(definition, alertState, + current.getOccurrences()); + + current.setFirmness(firmness); + + // store the entity for merging later + toCreateHistoryAndMerge.add(current); + + // create the event to fire later + alertEvents.add(new AlertStateChangeEvent(clusterId, alert, current, oldState)); } } @@ -268,38 +304,8 @@ public class AlertReceivedListener { saveEntities(toCreate, toMerge, toCreateHistoryAndMerge); // broadcast events - for (Map.Entry<Alert, AlertCurrentEntity> entry : toCreate.entrySet()) { - Alert alert = entry.getKey(); - AlertCurrentEntity entity = entry.getValue(); - Long clusterId = getClusterIdByName(alert.getCluster()); - if (clusterId == null) { - //super rare case, cluster was removed after isValid() check - LOG.error("Unable to process alert {} for an invalid cluster named {}", - alert.getName(), alert.getCluster()); - continue; - } - - InitialAlertEvent initialAlertEvent = new InitialAlertEvent( - clusterId, alert, entity); - - m_alertEventPublisher.publish(initialAlertEvent); - } - - for (Map.Entry<Alert, AlertCurrentEntity> entry : toCreateHistoryAndMerge.entrySet()) { - Alert alert = entry.getKey(); - AlertCurrentEntity entity = entry.getValue(); - Long clusterId = getClusterIdByName(alert.getCluster()); - if (clusterId == null) { - //super rare case, cluster was removed after isValid() check - LOG.error("Unable to process alert {} for an invalid cluster named {}", - alert.getName(), alert.getCluster()); - continue; - } - - AlertStateChangeEvent alertChangedEvent = new AlertStateChangeEvent(clusterId, alert, entity, - oldStates.get(alert)); - - m_alertEventPublisher.publish(alertChangedEvent); + for (AlertEvent eventToFire : alertEvents) { + m_alertEventPublisher.publish(eventToFire); } } @@ -325,20 +331,17 @@ public class AlertReceivedListener { * @param toCreateHistoryAndMerge - create new history, merge alert */ @Transactional - void saveEntities(Map<Alert, AlertCurrentEntity> toCreate, - Map<Alert, AlertCurrentEntity> toMerge, - Map<Alert, AlertCurrentEntity> toCreateHistoryAndMerge) { - for (Map.Entry<Alert, AlertCurrentEntity> entry : toCreate.entrySet()) { - AlertCurrentEntity entity = entry.getValue(); + void saveEntities(List<AlertCurrentEntity> toCreate, List<AlertCurrentEntity> toMerge, + List<AlertCurrentEntity> toCreateHistoryAndMerge) { + for (AlertCurrentEntity entity : toCreate) { m_alertsDao.create(entity); } - for (AlertCurrentEntity entity : toMerge.values()) { + for (AlertCurrentEntity entity : toMerge) { m_alertsDao.merge(entity, m_configuration.isAlertCacheEnabled()); } - for (Map.Entry<Alert, AlertCurrentEntity> entry : toCreateHistoryAndMerge.entrySet()) { - AlertCurrentEntity entity = entry.getValue(); + for (AlertCurrentEntity entity : toCreateHistoryAndMerge) { m_alertsDao.create(entity.getAlertHistory()); m_alertsDao.merge(entity); @@ -480,7 +483,7 @@ public class AlertReceivedListener { } /** - * Convenience to create a new alert. + * Convenience method to create a new historical alert. * * @param clusterId * the cluster id @@ -512,4 +515,46 @@ public class AlertReceivedListener { return history; } + + /** + * Gets the firmness for an {@link AlertCurrentEntity}. The following rules + * apply: + * <ul> + * <li>If an alert is {@link AlertState#OK}, then the firmness is always + * {@link AlertFirmness#HARD}.</li> + * <li>If an alert is {@link SourceType#AGGREGATE}, then the firmness is + * always {@link AlertFirmness#HARD}.</li> + * <li>Otherwise, the firmness will be {@link AlertFirmness#SOFT} unless the + * repeat tolerance has been met.</li> + * </ul> + * + * @param definition + * the definition to read any repeat tolerance overrides from. + * @param state + * the state of the {@link AlertCurrentEntity}. + * @param the + * occurrences of the alert in the current state (used for + * calculation firmness when moving between non-OK states) + * @return + */ + private AlertFirmness calculateFirmnessForStateChange(AlertDefinitionEntity definition, + AlertState state, long occurrences) { + if (state == AlertState.OK) { + return AlertFirmness.HARD; + } + + if (definition.getSourceType() == SourceType.AGGREGATE) { + return AlertFirmness.HARD; + } + + if (definition.getRepeatTolerance() <= 1) { + return AlertFirmness.HARD; + } + + if (definition.getRepeatTolerance() <= occurrences) { + return AlertFirmness.HARD; + } + + return AlertFirmness.SOFT; + } } http://git-wip-us.apache.org/repos/asf/ambari/blob/18449b5b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertStateChangedListener.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertStateChangedListener.java b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertStateChangedListener.java index 08563e3..73c2f1b 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertStateChangedListener.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertStateChangedListener.java @@ -33,6 +33,7 @@ import org.apache.ambari.server.orm.entities.AlertHistoryEntity; import org.apache.ambari.server.orm.entities.AlertNoticeEntity; import org.apache.ambari.server.orm.entities.AlertTargetEntity; import org.apache.ambari.server.state.Alert; +import org.apache.ambari.server.state.AlertFirmness; import org.apache.ambari.server.state.AlertState; import org.apache.ambari.server.state.MaintenanceState; import org.apache.ambari.server.state.NotificationState; @@ -48,6 +49,9 @@ import com.google.inject.Singleton; * The {@link AlertStateChangedListener} class response to * {@link AlertStateChangeEvent} and updates {@link AlertNoticeEntity} instances * in the database. + * <p/> + * {@link AlertNoticeEntity} instances will only be updated if the firmness of + * the alert is {@link AlertFirmness#HARD}. */ @Singleton @EagerSingleton @@ -65,10 +69,10 @@ public class AlertStateChangedListener { private static final Logger ALERT_LOG = LoggerFactory.getLogger("alerts"); /** - * [CRITICAL] [HDFS] [namenode_hdfs_blocks_health] (NameNode Blocks Health) - * Total Blocks:[100], Missing Blocks:[6] + * [CRITICAL] [HARD] [HDFS] [namenode_hdfs_blocks_health] (NameNode Blocks + * Health) Total Blocks:[100], Missing Blocks:[6] */ - private static final String ALERT_LOG_MESSAGE = "[{}] [{}] [{}] ({}) {}"; + private static final String ALERT_LOG_MESSAGE = "[{}] [{}] [{}] [{}] ({}) {}"; /** * Used for looking up groups and targets. @@ -100,18 +104,19 @@ public class AlertStateChangedListener { LOG.debug("Received event {}", event); Alert alert = event.getAlert(); + AlertCurrentEntity current = event.getCurrentAlert(); AlertHistoryEntity history = event.getNewHistoricalEntry(); AlertDefinitionEntity definition = history.getAlertDefinition(); // log to the alert audit log so there is physical record even if // definitions and historical enties are removed - ALERT_LOG.info(ALERT_LOG_MESSAGE, alert.getState(), + ALERT_LOG.info(ALERT_LOG_MESSAGE, alert.getState(), current.getFirmness(), definition.getServiceName(), definition.getDefinitionName(), definition.getLabel(), alert.getText()); - // normal logging for Ambari - if (LOG.isDebugEnabled()) { - LOG.debug("An alert has changed state: {}", event); + // do nothing if the firmness is SOFT + if (current.getFirmness() == AlertFirmness.SOFT) { + return; } // don't create any outbound alert notices if in MM @@ -144,6 +149,7 @@ public class AlertStateChangedListener { notices.add(notice); } } + m_alertsDispatchDao.createNotices(notices); } http://git-wip-us.apache.org/repos/asf/ambari/blob/18449b5b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertCurrentEntity.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertCurrentEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertCurrentEntity.java index 31f2154..8b6dc45 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertCurrentEntity.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertCurrentEntity.java @@ -33,6 +33,7 @@ import javax.persistence.OneToOne; import javax.persistence.Table; import javax.persistence.TableGenerator; +import org.apache.ambari.server.state.AlertFirmness; import org.apache.ambari.server.state.AlertState; import org.apache.ambari.server.state.MaintenanceState; @@ -92,7 +93,11 @@ public class AlertCurrentEntity { * */ @Column(name="occurrences", nullable=false) - private Integer occurrences = Integer.valueOf(1); + private Long occurrences = Long.valueOf(1); + + @Column(name = "firmness", nullable = false) + @Enumerated(value = EnumType.STRING) + private AlertFirmness firmness = AlertFirmness.HARD; /** * Unidirectional one-to-one association to {@link AlertHistoryEntity} @@ -221,7 +226,7 @@ public class AlertCurrentEntity { * * @return the number of occurrences. */ - public Integer getOccurrences() { + public Long getOccurrences() { return occurrences; } @@ -233,7 +238,7 @@ public class AlertCurrentEntity { * @see #getOccurrences() * */ - public void setOccurrences(int occurrences) { + public void setOccurrences(long occurrences) { this.occurrences = occurrences; } @@ -241,11 +246,32 @@ public class AlertCurrentEntity { * @param occurrences * the occurrences to set */ - public void setOccurrences(Integer occurrences) { + public void setOccurrences(Long occurrences) { this.occurrences = occurrences; } /** + * Gets the firmness of the alert, indicating whether or not it could be a + * potential false positive. + * + * @return the alert firmness. + */ + public AlertFirmness getFirmness() { + return firmness; + } + + /** + * Sets the firmness of the alert, indicating whether or not it could be a + * potential false positive. + * + * @param firmness + * the firmness (not {@code null}). + */ + public void setFirmness(AlertFirmness firmness) { + this.firmness = firmness; + } + + /** * Gets the associated {@link AlertHistoryEntity} entry for this current alert * instance. * http://git-wip-us.apache.org/repos/asf/ambari/blob/18449b5b/ambari-server/src/main/java/org/apache/ambari/server/state/Alert.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/Alert.java b/ambari-server/src/main/java/org/apache/ambari/server/state/Alert.java index f91d372..8252e0d 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/Alert.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/Alert.java @@ -188,50 +188,96 @@ public class Alert { this.cluster = cluster; } + /** + * {@inheritDoc} + */ @Override public int hashCode() { - int result = alertHashCode(); - - result += 31 * result + (null != instance ? instance.hashCode() : 0); - + final int prime = 31; + int result = 1; + result = prime * result + ((state == null) ? 0 : state.hashCode()); + result = prime * result + ((name == null) ? 0 : name.hashCode()); + result = prime * result + ((service == null) ? 0 : service.hashCode()); + result = prime * result + ((component == null) ? 0 : component.hashCode()); + result = prime * result + ((hostName == null) ? 0 : hostName.hashCode()); + result = prime * result + ((cluster == null) ? 0 : cluster.hashCode()); + result = prime * result + ((instance == null) ? 0 : instance.hashCode()); return result; } /** - * An alert's uniqueness comes from a combination of name, instance, service, - * component and host. + * {@inheritDoc} */ @Override - public boolean equals(Object o) { - if (null == o || !Alert.class.isInstance(o)) { + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null) { return false; } - return hashCode() == o.hashCode(); - } + if (getClass() != obj.getClass()) { + return false; + } - /** - * @return the hashcode of the alert without instance info - */ - private int alertHashCode() { - int result = (null != name) ? name.hashCode() : 0; - result += 31 * result + (null != service ? service.hashCode() : 0); - result += 31 * result + (null != component ? component.hashCode() : 0); - result += 31 * result + (null != hostName ? hostName.hashCode() : 0); + Alert other = (Alert) obj; - return result; - } + if (state != other.state) { + return false; + } - /** - * Checks equality with another alert, not taking into account instance info - * - * @param that - * the other alert to compare against - * @return <code>true</code> when the alert is equal in every way except the - * instance info - */ - public boolean almostEquals(Alert that) { - return alertHashCode() == that.alertHashCode(); + if (name == null) { + if (other.name != null) { + return false; + } + } else if (!name.equals(other.name)) { + return false; + } + + if (service == null) { + if (other.service != null) { + return false; + } + } else if (!service.equals(other.service)) { + return false; + } + + if (component == null) { + if (other.component != null) { + return false; + } + } else if (!component.equals(other.component)) { + return false; + } + + if (hostName == null) { + if (other.hostName != null) { + return false; + } + } else if (!hostName.equals(other.hostName)) { + return false; + } + + if (cluster == null) { + if (other.cluster != null) { + return false; + } + } else if (!cluster.equals(other.cluster)) { + return false; + } + + if (instance == null) { + if (other.instance != null) { + return false; + } + } else if (!instance.equals(other.instance)) { + return false; + } + + + return true; } @Override http://git-wip-us.apache.org/repos/asf/ambari/blob/18449b5b/ambari-server/src/main/java/org/apache/ambari/server/state/AlertFirmness.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/AlertFirmness.java b/ambari-server/src/main/java/org/apache/ambari/server/state/AlertFirmness.java new file mode 100644 index 0000000..a996f52 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/AlertFirmness.java @@ -0,0 +1,37 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ +package org.apache.ambari.server.state; + +/** + * The {@link AlertFirmness} enum is used to represent whether an alert should + * be considered as a real alert or whether it could still potentially be a + * false positive. Alerts which are {@link #SOFT} must have more occurrences in + * order to rule out the possibility of a false positive. + */ +public enum AlertFirmness { + /** + * The alert is a potential false positive and needs more instances to be + * confirmed. + */ + SOFT, + + /** + * The alert is not a potential false-positive. + */ + HARD; +} http://git-wip-us.apache.org/repos/asf/ambari/blob/18449b5b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog240.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog240.java b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog240.java index f4a0b8c..b3241e0 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog240.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog240.java @@ -41,6 +41,7 @@ import org.apache.ambari.server.orm.dao.RoleAuthorizationDAO; import org.apache.ambari.server.orm.entities.AlertDefinitionEntity; import org.apache.ambari.server.orm.entities.PermissionEntity; import org.apache.ambari.server.orm.entities.RoleAuthorizationEntity; +import org.apache.ambari.server.state.AlertFirmness; import org.apache.ambari.server.state.Cluster; import org.apache.ambari.server.state.Clusters; import org.apache.ambari.server.state.Config; @@ -69,6 +70,7 @@ public class UpgradeCatalog240 extends AbstractUpgradeCatalog { protected static final String ALERT_DEFINITION_TABLE = "alert_definition"; protected static final String ALERT_CURRENT_TABLE = "alert_current"; protected static final String ALERT_CURRENT_OCCURRENCES_COLUMN = "occurrences"; + protected static final String ALERT_CURRENT_FIRMNESS_COLUMN = "firmness"; protected static final String HELP_URL_COLUMN = "help_url"; protected static final String REPEAT_TOLERANCE_COLUMN = "repeat_tolerance"; protected static final String REPEAT_TOLERANCE_ENABLED_COLUMN = "repeat_tolerance_enabled"; @@ -482,14 +484,18 @@ public class UpgradeCatalog240 extends AbstractUpgradeCatalog { /** * Updates the {@value #ALERT_CURRENT_TABLE} in the following ways: * <ul> - * <li>Craetes the {@value #ALERT_CURRENT_OCCURRENCES_COLUMN} column</li> + * <li>Creates the {@value #ALERT_CURRENT_OCCURRENCES_COLUMN} column</li> + * <li>Creates the {@value #ALERT_CURRENT_FIRMNESS_COLUMN} column</li> * </ul> * * @throws SQLException */ protected void updateAlertCurrentTable() throws SQLException { dbAccessor.addColumn(ALERT_CURRENT_TABLE, - new DBColumnInfo(ALERT_CURRENT_OCCURRENCES_COLUMN, Integer.class, null, 1, false)); + new DBColumnInfo(ALERT_CURRENT_OCCURRENCES_COLUMN, Long.class, null, 1, false)); + + dbAccessor.addColumn(ALERT_CURRENT_TABLE, new DBColumnInfo(ALERT_CURRENT_FIRMNESS_COLUMN, + String.class, 255, AlertFirmness.HARD.name(), false)); } protected void setRoleSortOrder() throws SQLException { http://git-wip-us.apache.org/repos/asf/ambari/blob/18449b5b/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql index 2fb2195..81b97bb 100644 --- a/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql +++ b/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql @@ -918,7 +918,8 @@ CREATE TABLE alert_current ( original_timestamp BIGINT NOT NULL, latest_timestamp BIGINT NOT NULL, latest_text VARCHAR(3000), - occurrences INTEGER NOT NULL DEFAULT 1, + occurrences BIGINT NOT NULL DEFAULT 1, + firmness VARCHAR(255) NOT NULL DEFAULT 'HARD', PRIMARY KEY (alert_id), FOREIGN KEY (definition_id) REFERENCES alert_definition(definition_id), FOREIGN KEY (history_id) REFERENCES alert_history(alert_id) http://git-wip-us.apache.org/repos/asf/ambari/blob/18449b5b/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql index 6a3712e..021d2b8 100644 --- a/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql +++ b/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql @@ -931,7 +931,8 @@ CREATE TABLE alert_current ( original_timestamp BIGINT NOT NULL, latest_timestamp BIGINT NOT NULL, latest_text TEXT, - occurrences INTEGER NOT NULL DEFAULT 1, + occurrences BIGINT NOT NULL DEFAULT 1, + firmness VARCHAR(255) NOT NULL DEFAULT 'HARD', PRIMARY KEY (alert_id), FOREIGN KEY (definition_id) REFERENCES alert_definition(definition_id), FOREIGN KEY (history_id) REFERENCES alert_history(alert_id) http://git-wip-us.apache.org/repos/asf/ambari/blob/18449b5b/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql index 964941f..0320178 100644 --- a/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql +++ b/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql @@ -921,7 +921,8 @@ CREATE TABLE alert_current ( original_timestamp NUMBER(19) NOT NULL, latest_timestamp NUMBER(19) NOT NULL, latest_text CLOB, - occurrences INTEGER DEFAULT 1 NOT NULL + occurrences NUMBER(19) DEFAULT 1 NOT NULL, + firmness VARCHAR2(255) DEFAULT 'HARD' NOT NULL, PRIMARY KEY (alert_id), FOREIGN KEY (definition_id) REFERENCES alert_definition(definition_id), FOREIGN KEY (history_id) REFERENCES alert_history(alert_id) http://git-wip-us.apache.org/repos/asf/ambari/blob/18449b5b/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql index 366bbeb..585cdce 100644 --- a/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql +++ b/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql @@ -925,7 +925,8 @@ CREATE TABLE alert_current ( original_timestamp BIGINT NOT NULL, latest_timestamp BIGINT NOT NULL, latest_text TEXT, - occurrences INTEGER NOT NULL DEFAULT 1, + occurrences BIGINT NOT NULL DEFAULT 1, + firmness VARCHAR(255) NOT NULL DEFAULT 'HARD', PRIMARY KEY (alert_id), FOREIGN KEY (definition_id) REFERENCES alert_definition(definition_id), FOREIGN KEY (history_id) REFERENCES alert_history(alert_id) http://git-wip-us.apache.org/repos/asf/ambari/blob/18449b5b/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql index f7e7262..b546865 100644 --- a/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql +++ b/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql @@ -1012,7 +1012,8 @@ CREATE TABLE ambari.alert_current ( original_timestamp BIGINT NOT NULL, latest_timestamp BIGINT NOT NULL, latest_text TEXT, - occurrences INTEGER NOT NULL DEFAULT 1, + occurrences BIGINT NOT NULL DEFAULT 1, + firmness VARCHAR(255) NOT NULL DEFAULT 'HARD', PRIMARY KEY (alert_id), FOREIGN KEY (definition_id) REFERENCES ambari.alert_definition(definition_id), FOREIGN KEY (history_id) REFERENCES ambari.alert_history(alert_id) http://git-wip-us.apache.org/repos/asf/ambari/blob/18449b5b/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql index bdb6843..8bfd9dd 100644 --- a/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql +++ b/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql @@ -920,7 +920,8 @@ CREATE TABLE alert_current ( original_timestamp NUMERIC(19) NOT NULL, latest_timestamp NUMERIC(19) NOT NULL, latest_text TEXT, - occurrences INTEGER NOT NULL DEFAULT 1, + occurrences NUMERIC(19) NOT NULL DEFAULT 1, + firmness VARCHAR(255) NOT NULL DEFAULT 'HARD', PRIMARY KEY (alert_id), FOREIGN KEY (definition_id) REFERENCES alert_definition(definition_id), FOREIGN KEY (history_id) REFERENCES alert_history(alert_id) http://git-wip-us.apache.org/repos/asf/ambari/blob/18449b5b/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql index c6df84a..57ab922 100644 --- a/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql +++ b/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql @@ -1032,7 +1032,8 @@ CREATE TABLE alert_current ( original_timestamp BIGINT NOT NULL, latest_timestamp BIGINT NOT NULL, latest_text TEXT, - occurrences INTEGER NOT NULL DEFAULT 1, + occurrences BIGINT NOT NULL DEFAULT 1, + firmness VARCHAR(255) NOT NULL DEFAULT 'HARD', PRIMARY KEY CLUSTERED (alert_id), FOREIGN KEY (definition_id) REFERENCES alert_definition(definition_id), FOREIGN KEY (history_id) REFERENCES alert_history(alert_id) http://git-wip-us.apache.org/repos/asf/ambari/blob/18449b5b/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AggregateAlertListenerTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AggregateAlertListenerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AggregateAlertListenerTest.java index 29969d6..64ee936 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AggregateAlertListenerTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AggregateAlertListenerTest.java @@ -17,8 +17,6 @@ */ package org.apache.ambari.server.state.alerts; -import junit.framework.Assert; - import org.apache.ambari.server.events.AlertReceivedEvent; import org.apache.ambari.server.events.AlertStateChangeEvent; import org.apache.ambari.server.events.MockEventListener; @@ -28,7 +26,9 @@ import org.apache.ambari.server.orm.InMemoryDefaultTestModule; import org.apache.ambari.server.orm.dao.AlertSummaryDTO; import org.apache.ambari.server.orm.dao.AlertsDAO; import org.apache.ambari.server.orm.entities.AlertCurrentEntity; +import org.apache.ambari.server.orm.entities.AlertHistoryEntity; import org.apache.ambari.server.state.Alert; +import org.apache.ambari.server.state.AlertFirmness; import org.apache.ambari.server.state.alert.AggregateDefinitionMapping; import org.apache.ambari.server.state.alert.AggregateSource; import org.apache.ambari.server.state.alert.AlertDefinition; @@ -47,6 +47,8 @@ import com.google.inject.Module; import com.google.inject.persist.PersistService; import com.google.inject.util.Modules; +import junit.framework.Assert; + /** * Tests the {@link AlertAggregateListener}. */ @@ -92,24 +94,11 @@ public class AggregateAlertListenerTest { */ @Test public void testAlertNoticeCreationFromEvent() throws Exception { + AlertDefinition aggregateDefinition = getAggregateAlertDefinition(); AlertCurrentEntity currentEntityMock = EasyMock.createNiceMock(AlertCurrentEntity.class); + AlertHistoryEntity historyEntityMock = EasyMock.createNiceMock(AlertHistoryEntity.class); - // setup the mocks for the aggregate definition to avoid NPEs - AlertDefinition aggregateDefinition = new AlertDefinition(); - aggregateDefinition.setName("mock-aggregate-alert"); - AggregateSource aggregateSource = new AggregateSource(); - aggregateSource.setAlertName("mock-aggregate-alert"); - Reporting reporting = new Reporting(); - ReportTemplate criticalTemplate = new ReportTemplate(); - ReportTemplate okTemplate = new ReportTemplate(); - criticalTemplate.setValue(.05); - criticalTemplate.setText("CRITICAL"); - okTemplate.setText("OK"); - reporting.setCritical(criticalTemplate); - reporting.setWarning(criticalTemplate); - reporting.setOk(okTemplate); - aggregateSource.setReporting(reporting); - aggregateDefinition.setSource(aggregateSource); + EasyMock.expect(currentEntityMock.getAlertHistory()).andReturn(historyEntityMock).atLeastOnce(); EasyMock.expect( m_aggregateMapping.getAggregateDefinition(EasyMock.anyLong(), EasyMock.eq("mock-alert"))).andReturn( @@ -120,7 +109,7 @@ public class AggregateAlertListenerTest { m_alertsDao.findAggregateCounts(EasyMock.anyLong(), EasyMock.eq("mock-aggregate-alert"))).andReturn( summaryDTO).atLeastOnce(); - EasyMock.replay(m_alertsDao, m_aggregateMapping); + EasyMock.replay(m_alertsDao, m_aggregateMapping, currentEntityMock); // check that we're starting at 0 Assert.assertEquals(0, m_listener.getAlertEventReceivedCount(AlertReceivedEvent.class)); @@ -150,6 +139,71 @@ public class AggregateAlertListenerTest { } /** + * Tests that the {@link AlertAggregateListener} disregards + * {@link AlertFirmness#SOFT} alerts. + * + * @throws Exception + */ + @Test + public void testNoAggregateCalculationOnSoftAlert() throws Exception { + AlertDefinition aggregateDefinition = getAggregateAlertDefinition(); + AlertCurrentEntity currentEntityMock = EasyMock.createNiceMock(AlertCurrentEntity.class); + AlertHistoryEntity historyEntityMock = EasyMock.createNiceMock(AlertHistoryEntity.class); + + EasyMock.expect(currentEntityMock.getAlertHistory()).andReturn(historyEntityMock).atLeastOnce(); + EasyMock.expect(currentEntityMock.getFirmness()).andReturn(AlertFirmness.SOFT).atLeastOnce(); + + EasyMock.expect(m_aggregateMapping.getAggregateDefinition(EasyMock.anyLong(), + EasyMock.eq("mock-alert"))).andReturn(aggregateDefinition).atLeastOnce(); + + AlertSummaryDTO summaryDTO = new AlertSummaryDTO(5, 0, 0, 0, 0); + EasyMock.expect(m_alertsDao.findAggregateCounts(EasyMock.anyLong(), + EasyMock.eq("mock-aggregate-alert"))).andReturn(summaryDTO).atLeastOnce(); + + EasyMock.replay(m_alertsDao, m_aggregateMapping, currentEntityMock); + + // check that we're starting at 0 + Assert.assertEquals(0, m_listener.getAlertEventReceivedCount(AlertReceivedEvent.class)); + + // trigger an alert which would normally trigger the aggregate, except that + // the alert will be SOFT and should not cause a recalculation + Alert alert = new Alert("mock-alert", null, null, null, null, null); + AlertAggregateListener aggregateListener = m_injector.getInstance(AlertAggregateListener.class); + AlertStateChangeEvent event = new AlertStateChangeEvent(0, alert, currentEntityMock, null); + aggregateListener.onAlertStateChangeEvent(event); + + // ensure that the aggregate listener did not trigger an alert in response + // to the SOFT alert + Assert.assertEquals(0, m_listener.getAlertEventReceivedCount(AlertReceivedEvent.class)); + } + + /** + * Gets a mocked {@link AlertDefinition}. + * + * @return + */ + private AlertDefinition getAggregateAlertDefinition() { + // setup the mocks for the aggregate definition to avoid NPEs + AlertDefinition aggregateDefinition = new AlertDefinition(); + aggregateDefinition.setName("mock-aggregate-alert"); + AggregateSource aggregateSource = new AggregateSource(); + aggregateSource.setAlertName("mock-aggregate-alert"); + Reporting reporting = new Reporting(); + ReportTemplate criticalTemplate = new ReportTemplate(); + ReportTemplate okTemplate = new ReportTemplate(); + criticalTemplate.setValue(.05); + criticalTemplate.setText("CRITICAL"); + okTemplate.setText("OK"); + reporting.setCritical(criticalTemplate); + reporting.setWarning(criticalTemplate); + reporting.setOk(okTemplate); + aggregateSource.setReporting(reporting); + aggregateDefinition.setSource(aggregateSource); + + return aggregateDefinition; + } + + /** * */ private class MockModule implements Module { http://git-wip-us.apache.org/repos/asf/ambari/blob/18449b5b/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertReceivedListenerTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertReceivedListenerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertReceivedListenerTest.java index 7d6c691..f8a1f64 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertReceivedListenerTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertReceivedListenerTest.java @@ -25,6 +25,7 @@ import java.util.UUID; import org.apache.ambari.server.controller.RootServiceResponseFactory.Components; import org.apache.ambari.server.controller.RootServiceResponseFactory.Services; import org.apache.ambari.server.events.AlertReceivedEvent; +import org.apache.ambari.server.events.AlertStateChangeEvent; import org.apache.ambari.server.events.listeners.alerts.AlertReceivedListener; import org.apache.ambari.server.orm.GuiceJpaInitializer; import org.apache.ambari.server.orm.InMemoryDefaultTestModule; @@ -34,6 +35,7 @@ import org.apache.ambari.server.orm.dao.AlertsDAO; import org.apache.ambari.server.orm.entities.AlertCurrentEntity; import org.apache.ambari.server.orm.entities.AlertDefinitionEntity; import org.apache.ambari.server.state.Alert; +import org.apache.ambari.server.state.AlertFirmness; import org.apache.ambari.server.state.AlertState; import org.apache.ambari.server.state.Cluster; import org.apache.ambari.server.state.Clusters; @@ -528,29 +530,228 @@ public class AlertReceivedListenerTest { assertEquals(1, allCurrent.size()); // check occurrences (should be 1 since it's the first) - assertEquals(1, (int) allCurrent.get(0).getOccurrences()); + assertEquals(1, (long) allCurrent.get(0).getOccurrences()); // send OK again, then check that the value incremented listener.onAlertEvent(event); allCurrent = m_dao.findCurrent(); - assertEquals(2, (int) allCurrent.get(0).getOccurrences()); + assertEquals(2, (long) allCurrent.get(0).getOccurrences()); // now change to WARNING and check that it reset the counter alert.setState(AlertState.WARNING); listener.onAlertEvent(event); allCurrent = m_dao.findCurrent(); - assertEquals(1, (int) allCurrent.get(0).getOccurrences()); + assertEquals(1, (long) allCurrent.get(0).getOccurrences()); // send another WARNING listener.onAlertEvent(event); allCurrent = m_dao.findCurrent(); - assertEquals(2, (int) allCurrent.get(0).getOccurrences()); + assertEquals(2, (long) allCurrent.get(0).getOccurrences()); // now change from WARNING to CRITICAL; because they are both non-OK states, // the counter should continue alert.setState(AlertState.CRITICAL); listener.onAlertEvent(event); allCurrent = m_dao.findCurrent(); - assertEquals(3, (int) allCurrent.get(0).getOccurrences()); + assertEquals(3, (long) allCurrent.get(0).getOccurrences()); + } + + /** + * Tests that we correctly record alert firmness depending on several factors, + * such as {@link AlertState} and {@link SourceType}. + */ + @Test + public void testAlertFirmness() throws Exception { + String definitionName = ALERT_DEFINITION + "1"; + String serviceName = "HDFS"; + String componentName = "NAMENODE"; + String text = serviceName + " " + componentName + " is OK"; + + // start out with a critical alert to verify that all new alerts are always + // HARD + Alert alert = new Alert(definitionName, null, serviceName, componentName, HOST1, + AlertState.CRITICAL); + + alert.setCluster(m_cluster.getClusterName()); + alert.setLabel(ALERT_LABEL); + alert.setText(text); + alert.setTimestamp(1L); + + // fire the alert, and check that the new entry was created with the right + // timestamp + AlertReceivedListener listener = m_injector.getInstance(AlertReceivedListener.class); + AlertReceivedEvent event = new AlertReceivedEvent(m_cluster.getClusterId(), alert); + listener.onAlertEvent(event); + + List<AlertCurrentEntity> allCurrent = m_dao.findCurrent(); + assertEquals(1, allCurrent.size()); + + // check occurrences (should be 1 since it's the first) + assertEquals(1, (long) allCurrent.get(0).getOccurrences()); + + // check that the state is HARD since it's the first alert + assertEquals(AlertFirmness.HARD, allCurrent.get(0).getFirmness()); + + // move the repeat tolerance to 2 to test out SOFT alerts + AlertDefinitionEntity definition = allCurrent.get(0).getAlertHistory().getAlertDefinition(); + definition.setRepeatTolerance(2); + definition.setRepeatToleranceEnabled(true); + + m_definitionDao.merge(definition); + + // change state to OK, and ensure that all OK alerts are hard + alert.setState(AlertState.OK); + listener.onAlertEvent(event); + allCurrent = m_dao.findCurrent(); + assertEquals(1, (long) allCurrent.get(0).getOccurrences()); + assertEquals(AlertFirmness.HARD, allCurrent.get(0).getFirmness()); + + // change state to CRITICAL and verify we are soft with 1 occurrence + alert.setState(AlertState.CRITICAL); + listener.onAlertEvent(event); + allCurrent = m_dao.findCurrent(); + assertEquals(1, (long) allCurrent.get(0).getOccurrences()); + assertEquals(AlertFirmness.SOFT, allCurrent.get(0).getFirmness()); + + // send a 2nd CRITICAL and made sure the occurrences are 2 and the firmness + // is HARD + listener.onAlertEvent(event); + allCurrent = m_dao.findCurrent(); + assertEquals(2, (long) allCurrent.get(0).getOccurrences()); + assertEquals(AlertFirmness.HARD, allCurrent.get(0).getFirmness()); + } + + /** + * Tests that we correctly record alert firmness when an alert moves back and + * forth between non-OK states (such as between {@link AlertState#WARNING} and + * {@link AlertState#CRITICAL}). These are technically alert state changes and + * will fire {@link AlertStateChangeEvent}s but we only want to handle them + * when they are HARD. + */ + @Test + public void testAlertFirmnessWithinNonOKStates() throws Exception { + String definitionName = ALERT_DEFINITION + "1"; + String serviceName = "HDFS"; + String componentName = "NAMENODE"; + String text = serviceName + " " + componentName + " is OK"; + + Alert alert = new Alert(definitionName, null, serviceName, componentName, HOST1, AlertState.OK); + alert.setCluster(m_cluster.getClusterName()); + alert.setLabel(ALERT_LABEL); + alert.setText(text); + alert.setTimestamp(1L); + + // fire the alert, and check that the new entry was created correctly + AlertReceivedListener listener = m_injector.getInstance(AlertReceivedListener.class); + AlertReceivedEvent event = new AlertReceivedEvent(m_cluster.getClusterId(), alert); + listener.onAlertEvent(event); + + List<AlertCurrentEntity> allCurrent = m_dao.findCurrent(); + assertEquals(1, allCurrent.size()); + + // check occurrences (should be 1 since it's the first) and state (HARD) + assertEquals(1, (long) allCurrent.get(0).getOccurrences()); + assertEquals(AlertFirmness.HARD, allCurrent.get(0).getFirmness()); + + // move the repeat tolerance to 4 to test out SOFT alerts between states + AlertDefinitionEntity definition = allCurrent.get(0).getAlertHistory().getAlertDefinition(); + definition.setRepeatTolerance(4); + definition.setRepeatToleranceEnabled(true); + m_definitionDao.merge(definition); + + // change state to WARNING, should still be SOFT + alert.setState(AlertState.WARNING); + listener.onAlertEvent(event); + allCurrent = m_dao.findCurrent(); + assertEquals(1, (long) allCurrent.get(0).getOccurrences()); + assertEquals(AlertFirmness.SOFT, allCurrent.get(0).getFirmness()); + assertEquals(AlertState.WARNING, allCurrent.get(0).getAlertHistory().getAlertState()); + + // change state to CRITICAL, should still be SOFT, but occurrences of non-OK + // increases to 2 + alert.setState(AlertState.CRITICAL); + listener.onAlertEvent(event); + allCurrent = m_dao.findCurrent(); + assertEquals(2, (long) allCurrent.get(0).getOccurrences()); + assertEquals(AlertFirmness.SOFT, allCurrent.get(0).getFirmness()); + assertEquals(AlertState.CRITICAL, allCurrent.get(0).getAlertHistory().getAlertState()); + + // change state to WARNING, should still be SOFT, but occurrences of non-OK + // increases to 3 + alert.setState(AlertState.WARNING); + listener.onAlertEvent(event); + allCurrent = m_dao.findCurrent(); + assertEquals(3, (long) allCurrent.get(0).getOccurrences()); + assertEquals(AlertFirmness.SOFT, allCurrent.get(0).getFirmness()); + assertEquals(AlertState.WARNING, allCurrent.get(0).getAlertHistory().getAlertState()); + + // change state to CRITICAL, occurrences is not met, should be HARD + alert.setState(AlertState.CRITICAL); + listener.onAlertEvent(event); + allCurrent = m_dao.findCurrent(); + assertEquals(4, (long) allCurrent.get(0).getOccurrences()); + assertEquals(AlertFirmness.HARD, allCurrent.get(0).getFirmness()); + assertEquals(AlertState.CRITICAL, allCurrent.get(0).getAlertHistory().getAlertState()); + } + + /** + * Tests that {@link SourceType#AGGREGATE} alerts are always HARD. + */ + @Test + public void testAggregateAlertFirmness() throws Exception { + AlertDefinitionEntity definition = new AlertDefinitionEntity(); + definition.setDefinitionName("aggregate-alert-firmness-test"); + definition.setServiceName("HDFS"); + definition.setComponentName("NAMENODE"); + definition.setClusterId(m_cluster.getClusterId()); + definition.setHash(UUID.randomUUID().toString()); + definition.setScheduleInterval(Integer.valueOf(60)); + definition.setScope(Scope.SERVICE); + definition.setSource("{\"type\" : \"AGGREGATE\"}"); + definition.setSourceType(SourceType.AGGREGATE); + + // turn this up way high to ensure that we correctly short-circuit these + // types of alerts and always consider them HARD + definition.setRepeatTolerance(100); + definition.setRepeatToleranceEnabled(true); + + m_definitionDao.create(definition); + + Alert alert = new Alert(definition.getDefinitionName(), null, definition.getServiceName(), + definition.getComponentName(), HOST1, AlertState.OK); + + alert.setCluster(m_cluster.getClusterName()); + alert.setLabel(ALERT_LABEL); + alert.setText("Aggregate alerts are always HARD"); + alert.setTimestamp(1L); + + // fire the alert, and check that the new entry was created + AlertReceivedListener listener = m_injector.getInstance(AlertReceivedListener.class); + AlertReceivedEvent event = new AlertReceivedEvent(m_cluster.getClusterId(), alert); + listener.onAlertEvent(event); + + List<AlertCurrentEntity> allCurrent = m_dao.findCurrent(); + assertEquals(AlertFirmness.HARD, allCurrent.get(0).getFirmness()); + + // change state + alert.setState(AlertState.CRITICAL); + listener.onAlertEvent(event); + allCurrent = m_dao.findCurrent(); + assertEquals(1, (long) allCurrent.get(0).getOccurrences()); + assertEquals(AlertFirmness.HARD, allCurrent.get(0).getFirmness()); + + // change state + alert.setState(AlertState.WARNING); + listener.onAlertEvent(event); + allCurrent = m_dao.findCurrent(); + assertEquals(2, (long) allCurrent.get(0).getOccurrences()); + assertEquals(AlertFirmness.HARD, allCurrent.get(0).getFirmness()); + + // change state + alert.setState(AlertState.OK); + listener.onAlertEvent(event); + allCurrent = m_dao.findCurrent(); + assertEquals(1, (long) allCurrent.get(0).getOccurrences()); + assertEquals(AlertFirmness.HARD, allCurrent.get(0).getFirmness()); } } http://git-wip-us.apache.org/repos/asf/ambari/blob/18449b5b/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertStateChangedEventTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertStateChangedEventTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertStateChangedEventTest.java index e42e1a7..dad1008 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertStateChangedEventTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertStateChangedEventTest.java @@ -23,8 +23,6 @@ import java.util.HashSet; import java.util.List; import java.util.Set; -import junit.framework.Assert; - import org.apache.ambari.server.events.AggregateAlertRecalculateEvent; import org.apache.ambari.server.events.AlertEvent; import org.apache.ambari.server.events.AlertStateChangeEvent; @@ -34,13 +32,16 @@ import org.apache.ambari.server.orm.GuiceJpaInitializer; import org.apache.ambari.server.orm.InMemoryDefaultTestModule; import org.apache.ambari.server.orm.dao.AlertDispatchDAO; import org.apache.ambari.server.orm.dao.AlertsDAO; +import org.apache.ambari.server.orm.entities.AlertCurrentEntity; import org.apache.ambari.server.orm.entities.AlertDefinitionEntity; import org.apache.ambari.server.orm.entities.AlertGroupEntity; import org.apache.ambari.server.orm.entities.AlertHistoryEntity; import org.apache.ambari.server.orm.entities.AlertNoticeEntity; import org.apache.ambari.server.orm.entities.AlertTargetEntity; import org.apache.ambari.server.state.Alert; +import org.apache.ambari.server.state.AlertFirmness; import org.apache.ambari.server.state.AlertState; +import org.apache.ambari.server.state.MaintenanceState; import org.apache.ambari.server.utils.EventBusSynchronizer; import org.easymock.EasyMock; import org.junit.After; @@ -54,9 +55,13 @@ import com.google.inject.Module; import com.google.inject.persist.PersistService; import com.google.inject.util.Modules; +import junit.framework.Assert; + /** * Tests that {@link AlertStateChangeEvent} instances cause - * {@link AlertNoticeEntity} instances to be created. + * {@link AlertNoticeEntity} instances to be created. Outbound notifications + * should only be created when received alerts which have a firmness of + * {@link AlertFirmness#HARD}. */ public class AlertStateChangedEventTest { @@ -123,28 +128,28 @@ public class AlertStateChangedEventTest { EasyMock.replay(alertTarget, alertGroup, dispatchDao); - AlertDefinitionEntity definition = EasyMock.createNiceMock(AlertDefinitionEntity.class); - EasyMock.expect(definition.getDefinitionId()).andReturn(1L); - EasyMock.expect(definition.getServiceName()).andReturn("HDFS"); - EasyMock.expect(definition.getLabel()).andReturn("hdfs-foo-alert"); - EasyMock.expect(definition.getDescription()).andReturn("HDFS Foo Alert"); + AlertDefinitionEntity definition = getMockAlertDefinition(); + AlertCurrentEntity current = getMockedAlertCurrentEntity(); AlertHistoryEntity history = EasyMock.createNiceMock(AlertHistoryEntity.class); AlertStateChangeEvent event = EasyMock.createNiceMock(AlertStateChangeEvent.class); Alert alert = EasyMock.createNiceMock(Alert.class); + EasyMock.expect(current.getAlertHistory()).andReturn(history).anyTimes(); + EasyMock.expect(current.getFirmness()).andReturn(AlertFirmness.HARD).atLeastOnce(); EasyMock.expect(history.getAlertState()).andReturn(AlertState.CRITICAL).atLeastOnce(); EasyMock.expect(history.getAlertDefinition()).andReturn(definition).atLeastOnce(); EasyMock.expect(alert.getText()).andReturn("The HDFS Foo Alert Is Not Good").atLeastOnce(); EasyMock.expect(alert.getState()).andReturn(AlertState.CRITICAL).atLeastOnce(); + EasyMock.expect(event.getCurrentAlert()).andReturn(current).atLeastOnce(); EasyMock.expect(event.getNewHistoricalEntry()).andReturn(history).atLeastOnce(); EasyMock.expect(event.getAlert()).andReturn(alert).atLeastOnce(); - EasyMock.replay(definition, history, event, alert); + EasyMock.replay(definition, current, history, event, alert); // async publishing eventPublisher.publish(event); - EasyMock.verify(dispatchDao, history, event); + EasyMock.verify(dispatchDao, current, history, event); } /** @@ -177,16 +182,16 @@ public class AlertStateChangedEventTest { // that the create alert notice method was not called EasyMock.replay(alertTarget, alertGroup, dispatchDao); - AlertDefinitionEntity definition = EasyMock.createNiceMock(AlertDefinitionEntity.class); - EasyMock.expect(definition.getDefinitionId()).andReturn(1L); - EasyMock.expect(definition.getServiceName()).andReturn("HDFS"); - EasyMock.expect(definition.getLabel()).andReturn("hdfs-foo-alert"); - EasyMock.expect(definition.getDescription()).andReturn("HDFS Foo Alert"); + AlertDefinitionEntity definition = getMockAlertDefinition(); + AlertCurrentEntity current = getMockedAlertCurrentEntity(); AlertHistoryEntity history = EasyMock.createNiceMock(AlertHistoryEntity.class); AlertStateChangeEvent event = EasyMock.createNiceMock(AlertStateChangeEvent.class); Alert alert = EasyMock.createNiceMock(Alert.class); + EasyMock.expect(current.getAlertHistory()).andReturn(history).anyTimes(); + EasyMock.expect(current.getFirmness()).andReturn(AlertFirmness.HARD).atLeastOnce(); + // use WARNING to ensure that the target (which only cares about OK/CRIT) // does not receive the alert notice EasyMock.expect(history.getAlertState()).andReturn(AlertState.WARNING).atLeastOnce(); @@ -194,14 +199,77 @@ public class AlertStateChangedEventTest { EasyMock.expect(history.getAlertDefinition()).andReturn(definition).atLeastOnce(); EasyMock.expect(alert.getText()).andReturn("The HDFS Foo Alert Is Not Good").atLeastOnce(); EasyMock.expect(alert.getState()).andReturn(AlertState.WARNING).atLeastOnce(); + EasyMock.expect(event.getCurrentAlert()).andReturn(current).atLeastOnce(); EasyMock.expect(event.getNewHistoricalEntry()).andReturn(history).atLeastOnce(); EasyMock.expect(event.getAlert()).andReturn(alert).atLeastOnce(); - EasyMock.replay(definition, history, event, alert); + EasyMock.replay(definition, current, history, event, alert); // async publishing eventPublisher.publish(event); - EasyMock.verify(dispatchDao, history, event); + EasyMock.verify(dispatchDao, current, history, event); + } + + /** + * Tests that an alert with a firmness of {@link AlertFirmness#SOFT} does not + * trigger any notifications. + * + * @throws Exception + */ + @Test + public void testSoftAlertDoesNotCreateNotifications() throws Exception { + EasyMock.replay(dispatchDao); + + AlertDefinitionEntity definition = getMockAlertDefinition(); + + AlertCurrentEntity current = getMockedAlertCurrentEntity(); + AlertHistoryEntity history = EasyMock.createNiceMock(AlertHistoryEntity.class); + AlertStateChangeEvent event = EasyMock.createNiceMock(AlertStateChangeEvent.class); + Alert alert = EasyMock.createNiceMock(Alert.class); + + // make the alert SOFT so that no notifications are sent + EasyMock.expect(current.getAlertHistory()).andReturn(history).anyTimes(); + EasyMock.expect(current.getFirmness()).andReturn(AlertFirmness.SOFT).atLeastOnce(); + + + EasyMock.expect(history.getAlertDefinition()).andReturn(definition).atLeastOnce(); + EasyMock.expect(alert.getText()).andReturn("The HDFS Foo Alert Is Not Good").atLeastOnce(); + EasyMock.expect(alert.getState()).andReturn(AlertState.CRITICAL).atLeastOnce(); + EasyMock.expect(event.getCurrentAlert()).andReturn(current).atLeastOnce(); + EasyMock.expect(event.getNewHistoricalEntry()).andReturn(history).atLeastOnce(); + EasyMock.expect(event.getAlert()).andReturn(alert).atLeastOnce(); + + EasyMock.replay(definition, current, history, event, alert); + + // async publishing + eventPublisher.publish(event); + EasyMock.verify(dispatchDao, current, history, event); + } + + /** + * Gets an {@link AlertDefinitionEntity} with some mocked calls expected. + * + * @return + */ + private AlertDefinitionEntity getMockAlertDefinition() { + AlertDefinitionEntity definition = EasyMock.createNiceMock(AlertDefinitionEntity.class); + EasyMock.expect(definition.getDefinitionId()).andReturn(1L); + EasyMock.expect(definition.getServiceName()).andReturn("HDFS"); + EasyMock.expect(definition.getLabel()).andReturn("hdfs-foo-alert"); + EasyMock.expect(definition.getDescription()).andReturn("HDFS Foo Alert"); + + return definition; + } + + /** + * Gets an {@link AlertCurrentEntity} with some mocked calls expected. + * + * @return + */ + private AlertCurrentEntity getMockedAlertCurrentEntity() { + AlertCurrentEntity current = EasyMock.createNiceMock(AlertCurrentEntity.class); + EasyMock.expect(current.getMaintenanceState()).andReturn(MaintenanceState.OFF).anyTimes(); + return current; } /** http://git-wip-us.apache.org/repos/asf/ambari/blob/18449b5b/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/InitialAlertEventTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/InitialAlertEventTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/InitialAlertEventTest.java index 3ddeb2a..1875ba6 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/InitialAlertEventTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/InitialAlertEventTest.java @@ -17,7 +17,7 @@ */ package org.apache.ambari.server.state.alerts; -import junit.framework.Assert; +import java.util.List; import org.apache.ambari.server.events.AlertReceivedEvent; import org.apache.ambari.server.events.InitialAlertEvent; @@ -27,8 +27,10 @@ import org.apache.ambari.server.orm.GuiceJpaInitializer; import org.apache.ambari.server.orm.InMemoryDefaultTestModule; import org.apache.ambari.server.orm.dao.AlertDefinitionDAO; import org.apache.ambari.server.orm.dao.AlertsDAO; +import org.apache.ambari.server.orm.entities.AlertCurrentEntity; import org.apache.ambari.server.orm.entities.AlertDefinitionEntity; import org.apache.ambari.server.state.Alert; +import org.apache.ambari.server.state.AlertFirmness; import org.apache.ambari.server.state.AlertState; import org.apache.ambari.server.state.Cluster; import org.apache.ambari.server.state.Clusters; @@ -48,6 +50,8 @@ import com.google.inject.Module; import com.google.inject.persist.PersistService; import com.google.inject.util.Modules; +import junit.framework.Assert; + /** * Tests that {@link InitialAlertEventTest} instances are fired correctly. */ @@ -130,17 +134,24 @@ public class InitialAlertEventTest { // create the "first" alert Alert alert = new Alert(definition.getDefinitionName(), null, definition.getServiceName(), definition.getComponentName(), null, - AlertState.OK); + AlertState.CRITICAL); + alert.setCluster(m_clusterName); - AlertReceivedEvent event = new AlertReceivedEvent(m_cluster.getClusterId(), - alert); + AlertReceivedEvent event = new AlertReceivedEvent(m_cluster.getClusterId(), alert); // public the received event m_eventPublisher.publish(event); - // ensure we now have a history item + // ensure we now have a history item and a current Assert.assertEquals(1, m_alertsDao.findAll().size()); + List<AlertCurrentEntity> currentAlerts = m_alertsDao.findCurrent(); + Assert.assertEquals(1, currentAlerts.size()); + + // verify that that initial alert is HARD + Assert.assertEquals(AlertFirmness.HARD, currentAlerts.get(0).getFirmness()); + Assert.assertEquals(AlertState.CRITICAL, + currentAlerts.get(0).getAlertHistory().getAlertState()); // verify that the initial alert event was triggered Assert.assertEquals(1, http://git-wip-us.apache.org/repos/asf/ambari/blob/18449b5b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog240Test.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog240Test.java b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog240Test.java index 3723ff8..ea0547b 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog240Test.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog240Test.java @@ -53,6 +53,7 @@ import org.apache.ambari.server.orm.DBAccessor; import org.apache.ambari.server.orm.GuiceJpaInitializer; import org.apache.ambari.server.orm.InMemoryDefaultTestModule; import org.apache.ambari.server.orm.dao.StackDAO; +import org.apache.ambari.server.state.AlertFirmness; import org.apache.ambari.server.state.stack.OsFamily; import org.easymock.Capture; import org.easymock.CaptureType; @@ -170,10 +171,13 @@ public class UpgradeCatalog240Test { Capture<DBAccessor.DBColumnInfo> capturedRepeatToleranceColumnInfo = newCapture(); Capture<DBAccessor.DBColumnInfo> capturedRepeatToleranceEnabledColumnInfo = newCapture(); Capture<DBAccessor.DBColumnInfo> capturedOccurrencesColumnInfo = newCapture(); + Capture<DBAccessor.DBColumnInfo> capturedFirmnessColumnInfo = newCapture(); + dbAccessor.addColumn(eq(UpgradeCatalog240.ALERT_DEFINITION_TABLE), capture(capturedHelpURLColumnInfo)); dbAccessor.addColumn(eq(UpgradeCatalog240.ALERT_DEFINITION_TABLE), capture(capturedRepeatToleranceColumnInfo)); dbAccessor.addColumn(eq(UpgradeCatalog240.ALERT_DEFINITION_TABLE), capture(capturedRepeatToleranceEnabledColumnInfo)); dbAccessor.addColumn(eq(UpgradeCatalog240.ALERT_CURRENT_TABLE), capture(capturedOccurrencesColumnInfo)); + dbAccessor.addColumn(eq(UpgradeCatalog240.ALERT_CURRENT_TABLE), capture(capturedFirmnessColumnInfo)); // Test creation of blueprint_setting table Capture<List<DBAccessor.DBColumnInfo>> capturedBlueprintSettingColumns = EasyMock.newCapture(); @@ -289,9 +293,16 @@ public class UpgradeCatalog240Test { DBAccessor.DBColumnInfo columnOccurrencesInfo = capturedOccurrencesColumnInfo.getValue(); Assert.assertNotNull(columnOccurrencesInfo); Assert.assertEquals(UpgradeCatalog240.ALERT_CURRENT_OCCURRENCES_COLUMN, columnOccurrencesInfo.getName()); - Assert.assertEquals(Integer.class, columnOccurrencesInfo.getType()); + Assert.assertEquals(Long.class, columnOccurrencesInfo.getType()); Assert.assertEquals(1, columnOccurrencesInfo.getDefaultValue()); - Assert.assertEquals(false, columnOccurrencesInfo.isNullable()); + Assert.assertEquals(false, columnOccurrencesInfo.isNullable()); + + DBAccessor.DBColumnInfo columnFirmnessInfo = capturedFirmnessColumnInfo.getValue(); + Assert.assertNotNull(columnFirmnessInfo); + Assert.assertEquals(UpgradeCatalog240.ALERT_CURRENT_FIRMNESS_COLUMN, columnFirmnessInfo.getName()); + Assert.assertEquals(String.class, columnFirmnessInfo.getType()); + Assert.assertEquals(AlertFirmness.HARD.name(), columnFirmnessInfo.getDefaultValue()); + Assert.assertEquals(false, columnFirmnessInfo.isNullable()); assertEquals(expectedCaptures, actualCaptures);
