/**
* 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.alerts;
import static org.junit.Assert.assertEquals;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import javax.persistence.EntityManager;
import org.apache.ambari.server.AmbariException;
import org.apache.ambari.server.H2DatabaseCleaner;
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;
import org.apache.ambari.server.orm.OrmTestHelper;
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;
import org.apache.ambari.server.state.Config;
import org.apache.ambari.server.state.ConfigFactory;
import org.apache.ambari.server.state.ConfigHelper;
import org.apache.ambari.server.state.MaintenanceState;
import org.apache.ambari.server.state.ServiceComponentFactory;
import org.apache.ambari.server.state.ServiceComponentHostFactory;
import org.apache.ambari.server.state.ServiceFactory;
import org.apache.ambari.server.state.alert.Scope;
import org.apache.ambari.server.state.alert.SourceType;
import org.apache.ambari.server.utils.EventBusSynchronizer;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.persist.UnitOfWork;
/**
* Tests the {@link AlertReceivedListener}.
*/
@Category({ category.AlertTest.class})
public class AlertReceivedListenerTest {
private static final String ALERT_DEFINITION = "alert_definition_";
private static final String HOST1 = "h1";
private static final String ALERT_LABEL = "My Label";
private Injector m_injector;
private AlertsDAO m_dao;
private AlertDefinitionDAO m_definitionDao;
private Clusters m_clusters;
private Cluster m_cluster;
private OrmTestHelper m_helper;
private ServiceFactory m_serviceFactory;
private ServiceComponentFactory m_componentFactory;
private ServiceComponentHostFactory m_schFactory;
@Before
public void setup() throws Exception {
m_injector = Guice.createInjector(new InMemoryDefaultTestModule());
m_injector.getInstance(GuiceJpaInitializer.class);
m_injector.getInstance(UnitOfWork.class).begin();
m_helper = m_injector.getInstance(OrmTestHelper.class);
m_clusters = m_injector.getInstance(Clusters.class);
m_serviceFactory = m_injector.getInstance(ServiceFactory.class);
m_componentFactory = m_injector.getInstance(ServiceComponentFactory.class);
m_schFactory = m_injector.getInstance(ServiceComponentHostFactory.class);
m_dao = m_injector.getInstance(AlertsDAO.class);
m_definitionDao = m_injector.getInstance(AlertDefinitionDAO.class);
EventBusSynchronizer.synchronizeAlertEventPublisher(m_injector);
EventBusSynchronizer.synchronizeAmbariEventPublisher(m_injector);
// install YARN so there is at least 1 service installed and no
// unexpected alerts since the test YARN service doesn't have any alerts
m_cluster = m_helper.buildNewCluster(m_clusters, m_serviceFactory, m_componentFactory,
m_schFactory, HOST1);
// create 5 definitions, some with HDFS and some with YARN
for (int i = 0; i < 5; i++) {
String serviceName = "HDFS";
String componentName = "DATANODE";
if (i >= 3) {
serviceName = "YARN";
componentName = "RESOURCEMANAGER";
}
AlertDefinitionEntity definition = new AlertDefinitionEntity();
definition.setDefinitionName(ALERT_DEFINITION + i);
definition.setServiceName(serviceName);
definition.setComponentName(componentName);
definition.setClusterId(m_cluster.getClusterId());
definition.setHash(UUID.randomUUID().toString());
definition.setScheduleInterval(Integer.valueOf(60));
definition.setScope(Scope.SERVICE);
definition.setSource("{\"type\" : \"SCRIPT\"}");
definition.setSourceType(SourceType.SCRIPT);
m_definitionDao.create(definition);
}
}
@After
public void teardown() throws AmbariException, SQLException {
m_injector.getInstance(UnitOfWork.class).end();
H2DatabaseCleaner.clearDatabase(m_injector.getProvider(EntityManager.class).get());
m_injector = null;
}
/**
* Tests that a disabled definition doesn't record alert events.
*/
@Test
public void testDisabledAlert() {
String definitionName = ALERT_DEFINITION + "1";
String componentName = "DATANODE";
Alert alert1 = new Alert(definitionName, null, "HDFS", componentName,
HOST1, AlertState.OK);
alert1.setCluster(m_cluster.getClusterName());
alert1.setLabel(ALERT_LABEL);
alert1.setText("HDFS " + componentName + " is OK");
alert1.setTimestamp(1L);
// verify that the listener works with a regular alert
AlertReceivedListener listener = m_injector.getInstance(AlertReceivedListener.class);
AlertReceivedEvent event1 = new AlertReceivedEvent(
m_cluster.getClusterId(), alert1);
listener.onAlertEvent(event1);
List<AlertCurrentEntity> allCurrent = m_dao.findCurrent();
assertEquals(1, allCurrent.size());
// disable definition
AlertDefinitionEntity definition = m_definitionDao.findByName(
m_cluster.getClusterId(), definitionName);
definition.setEnabled(false);
m_definitionDao.merge(definition);
// remove disabled
m_dao.removeCurrentDisabledAlerts();
allCurrent = m_dao.findCurrent();
assertEquals(0, allCurrent.size());
// verify no new alerts for disabled
listener.onAlertEvent(event1);
allCurrent = m_dao.findCurrent();
assertEquals(0, allCurrent.size());
}
/**
* Tests an invalid host is being reported in an alert.
*/
@Test
public void testInvalidHost() {
String definitionName = ALERT_DEFINITION + "1";
String componentName = "DATANODE";
Alert alert = new Alert(definitionName, null, "HDFS", componentName,
HOST1, AlertState.OK);
alert.setCluster(m_cluster.getClusterName());
alert.setLabel(ALERT_LABEL);
alert.setText("HDFS " + componentName + " is OK");
alert.setTimestamp(1L);
// verify that the listener works with a regular alert
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());
// invalid host
alert.setHostName("INVALID");
// remove all
m_dao.removeCurrentByHost(HOST1);
allCurrent = m_dao.findCurrent();
assertEquals(0, allCurrent.size());
// verify no new alerts for disabled
listener.onAlertEvent(event);
allCurrent = m_dao.findCurrent();
assertEquals(0, allCurrent.size());
}
/**
* Tests that a disabled definition doesn't record alert events.
*/
@Test
public void testInvalidAlertDefinition() {
String componentName = "DATANODE";
Alert alert = new Alert("missing_alert_definition_name", null, "HDFS",
componentName, HOST1, AlertState.OK);
alert.setLabel(ALERT_LABEL);
alert.setText("HDFS " + componentName + " is OK");
alert.setTimestamp(1L);
// bad alert definition name means no current alerts
AlertReceivedListener listener = m_injector.getInstance(AlertReceivedListener.class);
AlertReceivedEvent event1 = new AlertReceivedEvent(
m_cluster.getClusterId(), alert);
listener.onAlertEvent(event1);
List<AlertCurrentEntity> allCurrent = m_dao.findCurrent();
assertEquals(0, allCurrent.size());
}
/**
* Tests an invalid pairing of component to host.
*/
@Test
public void testInvalidServiceComponentHost() {
String definitionName = ALERT_DEFINITION + "1";
String componentName = "DATANODE";
Alert alert = new Alert(definitionName, null, "HDFS", componentName,
HOST1, AlertState.OK);
alert.setCluster(m_cluster.getClusterName());
alert.setLabel(ALERT_LABEL);
alert.setText("HDFS " + componentName + " is OK");
alert.setTimestamp(1L);
// verify that the listener works with a regular alert
AlertReceivedListener listener = m_injector.getInstance(AlertReceivedListener.class);
AlertReceivedEvent event1 = new AlertReceivedEvent(
m_cluster.getClusterId(), alert);
listener.onAlertEvent(event1);
List<AlertCurrentEntity> allCurrent = m_dao.findCurrent();
assertEquals(1, allCurrent.size());
// invalid host
alert.setComponent("INVALID");
// remove all
m_dao.removeCurrentByHost(HOST1);
allCurrent = m_dao.findCurrent();
assertEquals(0, allCurrent.size());
// verify no new alerts for disabled
listener.onAlertEvent(event1);
allCurrent = m_dao.findCurrent();
assertEquals(0, allCurrent.size());
}
/**
* Tests that a disabled definition doesn't record alert events.
*/
@Test
public void testMaintenanceModeSet() throws Exception {
String definitionName = ALERT_DEFINITION + "1";
String componentName = "DATANODE";
Alert alert1 = new Alert(definitionName, null, "HDFS", componentName, HOST1,
AlertState.CRITICAL);
alert1.setCluster(m_cluster.getClusterName());
alert1.setLabel(ALERT_LABEL);
alert1.setText("HDFS " + componentName + " is OK");
alert1.setTimestamp(1L);
// verify that the listener works with a regular alert
AlertReceivedListener listener = m_injector.getInstance(AlertReceivedListener.class);
AlertReceivedEvent event = new AlertReceivedEvent(m_cluster.getClusterId(), alert1);
listener.onAlertEvent(event);
List<AlertCurrentEntity> allCurrent = m_dao.findCurrent();
assertEquals(1, allCurrent.size());
AlertCurrentEntity current = allCurrent.get(0);
assertEquals(MaintenanceState.OFF, current.getMaintenanceState());
// remove it
m_dao.removeCurrentByService(m_cluster.getClusterId(), "HDFS");
allCurrent = m_dao.findCurrent();
assertEquals(0, allCurrent.size());
// set maintenance mode on the service
m_cluster.getService("HDFS").setMaintenanceState(MaintenanceState.ON);
// verify that the listener handles the event and creates the current alert
// with the correct MM
listener.onAlertEvent(event);
allCurrent = m_dao.findCurrent();
assertEquals(1, allCurrent.size());
current = allCurrent.get(0);
assertEquals(MaintenanceState.ON, current.getMaintenanceState());
}
/**
* Tests that an invalid host from a host-level agent alert is rejected.
*/
@Test
public void testAgentAlertFromInvalidHost() {
String definitionName = ALERT_DEFINITION + "1";
String serviceName = Services.AMBARI.name();
String componentName = Components.AMBARI_AGENT.name();
Alert alert = new Alert(definitionName, null, serviceName, componentName, HOST1,
AlertState.OK);
alert.setCluster(m_cluster.getClusterName());
alert.setLabel(ALERT_LABEL);
alert.setText(serviceName + " " + componentName + " is OK");
alert.setTimestamp(1L);
// verify that the listener works with a regular alert
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());
// invalid host
alert.setHostName("INVALID");
// remove all
m_dao.removeCurrentByHost(HOST1);
allCurrent = m_dao.findCurrent();
assertEquals(0, allCurrent.size());
// verify no new alerts received
listener.onAlertEvent(event);
allCurrent = m_dao.findCurrent();
assertEquals(0, allCurrent.size());
}
/**
* Tests that an alert for AMBARI/AMBARI_SERVER is always valid.
*/
@Test
public void testAmbariServerValidAlerts() {
String definitionName = ALERT_DEFINITION + "1";
String serviceName = Services.AMBARI.name();
String componentName = Components.AMBARI_SERVER.name();
Alert alert = new Alert(definitionName, null, serviceName, componentName, HOST1,
AlertState.OK);
alert.setCluster(m_cluster.getClusterName());
alert.setLabel(ALERT_LABEL);
alert.setText(serviceName + " " + componentName + " is OK");
alert.setTimestamp(1L);
// verify that the listener works with a regular alert
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());
// invalid host, invalid cluster
alert.setHostName("INVALID");
alert.setCluster("INVALID");
// remove all
m_dao.removeCurrentByHost(HOST1);
allCurrent = m_dao.findCurrent();
assertEquals(0, allCurrent.size());
// verify that the alert was still received
listener.onAlertEvent(event);
allCurrent = m_dao.findCurrent();
assertEquals(1, allCurrent.size());
}
/**
* Tests that an invalid host from an invalid cluster does not trigger an
* alert.
*/
@Test
public void testMissingClusterAndInvalidHost() {
String definitionName = ALERT_DEFINITION + "1";
String serviceName = Services.AMBARI.name();
String componentName = Components.AMBARI_AGENT.name();
Alert alert1 = new Alert(definitionName, null, serviceName, componentName, HOST1,
AlertState.OK);
alert1.setCluster(m_cluster.getClusterName());
alert1.setLabel(ALERT_LABEL);
alert1.setText(serviceName + " " + componentName + " is OK");
alert1.setTimestamp(1L);
// verify that the listener works with a regular alert
AlertReceivedListener listener = m_injector.getInstance(AlertReceivedListener.class);
AlertReceivedEvent event = new AlertReceivedEvent(m_cluster.getClusterId(), alert1);
listener.onAlertEvent(event);
List<AlertCurrentEntity> allCurrent = m_dao.findCurrent();
assertEquals(1, allCurrent.size());
// missing cluster, invalid host
alert1.setCluster(null);
alert1.setHostName("INVALID");
// remove all
m_dao.removeCurrentByHost(HOST1);
allCurrent = m_dao.findCurrent();
assertEquals(0, allCurrent.size());
// verify no new alerts received
listener.onAlertEvent(event);
allCurrent = m_dao.findCurrent();
assertEquals(0, allCurrent.size());
}
/**
* Tests that receiving and alert with {@link AlertState#SKIPPED} does not create an entry
* if there is currently no current alert.
*/
@Test
public void testSkippedAlertWithNoCurrentAlert() {
String definitionName = ALERT_DEFINITION + "1";
String serviceName = "HDFS";
String componentName = "NAMENODE";
Alert alert = new Alert(definitionName, null, serviceName, componentName, HOST1, AlertState.SKIPPED);
alert.setCluster(m_cluster.getClusterName());
alert.setLabel(ALERT_LABEL);
alert.setText(serviceName + " " + componentName + " is OK");
alert.setTimestamp(1L);
// fire the alert, and check that nothing gets 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(0, allCurrent.size());
}
/**
* Tests that receiving and alert with {@link AlertState#SKIPPED} does not
* create an entry if there is currently no current alert.
*/
@Test
public void testSkippedAlertUpdatesTimestampAndText() {
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 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 timestamp
assertEquals(1L, (long) allCurrent.get(0).getOriginalTimestamp());
assertEquals(1L, (long) allCurrent.get(0).getLatestTimestamp());
// update the timestamp and the state
alert.setState(AlertState.SKIPPED);
alert.setTimestamp(2L);
// we should allow updating the text if the text is provided
text = text + " Updated";
alert.setText(text);
// get the current make sure the fields were updated
listener.onAlertEvent(event);
allCurrent = m_dao.findCurrent();
assertEquals(1L, (long) allCurrent.get(0).getOriginalTimestamp());
assertEquals(2L, (long) allCurrent.get(0).getLatestTimestamp());
assertEquals(text, allCurrent.get(0).getLatestText());
// verify that blank text does not update
alert.setText("");
alert.setTimestamp(3L);
// get the current make sure the text was not updated
listener.onAlertEvent(event);
allCurrent = m_dao.findCurrent();
assertEquals(1L, (long) allCurrent.get(0).getOriginalTimestamp());
assertEquals(3L, (long) allCurrent.get(0).getLatestTimestamp());
assertEquals(text, allCurrent.get(0).getLatestText());
}
/**
* Tests that we correctly record alert occurance information.
*/
@Test
public void testAlertOccurrences() {
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 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());
// send OK again, then check that the value incremented
listener.onAlertEvent(event);
allCurrent = m_dao.findCurrent();
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, (long) allCurrent.get(0).getOccurrences());
// send another WARNING
listener.onAlertEvent(event);
allCurrent = m_dao.findCurrent();
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, (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());
}
/**
* Tests that we correctly record alert firmness, using the global value if
* the definition does not override it.
*/
@Test
public void testAlertFirmnessUsingGlobalValue() 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
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());
assertEquals(AlertFirmness.HARD, allCurrent.get(0).getFirmness());
// move the repeat tolerance to 2 on the definition, but leave it disabled
// so that we still use the global
AlertDefinitionEntity definition = allCurrent.get(0).getAlertHistory().getAlertDefinition();
definition.setRepeatTolerance(2);
definition.setRepeatToleranceEnabled(false);
m_definitionDao.merge(definition);
// change state to CRITICAL; this should make a HARD alert since the global
// value is in use
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());
}
/**
* Tests that we correctly record alert firmness, using the global value if
* the definition does not override it.
*/
@Test
@SuppressWarnings("serial")
public void testAlertFirmnessUsingGlobalValueHigherThanOverride() throws Exception {
ConfigFactory cf = m_injector.getInstance(ConfigFactory.class);
Config config = cf.createNew(m_cluster, ConfigHelper.CLUSTER_ENV, "version2",
new HashMap<String, String>() {
{
put(ConfigHelper.CLUSTER_ENV_ALERT_REPEAT_TOLERANCE, "3");
}
}, new HashMap<String, Map<String, String>>());
m_cluster.addDesiredConfig("user", Collections.singleton(config));
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
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());
assertEquals(AlertFirmness.HARD, allCurrent.get(0).getFirmness());
// change state to CRITICAL; this should make a SOFT alert since the global
// value is 3
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());
listener.onAlertEvent(event);
allCurrent = m_dao.findCurrent();
assertEquals(2, (long) allCurrent.get(0).getOccurrences());
assertEquals(AlertFirmness.SOFT, allCurrent.get(0).getFirmness());
// on the 3rd time, we transition to HARD
listener.onAlertEvent(event);
allCurrent = m_dao.findCurrent();
assertEquals(3, (long) allCurrent.get(0).getOccurrences());
assertEquals(AlertFirmness.HARD, allCurrent.get(0).getFirmness());
}
/**
* Tests that multiple threads can't create duplicate new alerts. This will
* spawn several threads, each one trying to create the same alert.
*/
@Test
public void testMultipleNewAlertEvents() throws Exception {
assertEquals(0, m_dao.findCurrent().size());
final String definitionName = ALERT_DEFINITION + "1";
List<Thread> threads = new ArrayList<>();
final AlertReceivedListener listener = m_injector.getInstance(AlertReceivedListener.class);
// spawn a bunch of concurrent threasd which will try to create teh same
// alert over and over
for (int i = 0; i < 10; i++) {
Thread thread = new Thread() {
/**
* {@inheritDoc}
*/
@Override
public void run() {
Alert alert = new Alert(definitionName, null, "HDFS", null, HOST1, AlertState.OK);
alert.setCluster(m_cluster.getClusterName());
alert.setLabel(ALERT_LABEL);
alert.setText("HDFS is OK ");
alert.setTimestamp(System.currentTimeMillis());
final AlertReceivedEvent event = new AlertReceivedEvent(m_cluster.getClusterId(), alert);
listener.onAlertEvent(event);
}
};
threads.add(thread);
thread.start();
}
// wait for threads
for (Thread thread : threads) {
thread.join();
}
assertEquals(1, m_dao.findCurrent().size());
}
}