/** * 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.alerts; import static junit.framework.Assert.assertEquals; import static org.easymock.EasyMock.createNiceMock; import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.replay; import static org.easymock.EasyMock.reset; import static org.easymock.EasyMock.verify; import java.lang.management.ManagementFactory; import java.lang.management.RuntimeMXBean; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.persistence.EntityManager; import org.apache.ambari.server.events.AlertEvent; import org.apache.ambari.server.events.AlertReceivedEvent; import org.apache.ambari.server.events.MockEventListener; import org.apache.ambari.server.events.publishers.AlertEventPublisher; import org.apache.ambari.server.orm.DBAccessor; 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.orm.entities.AlertHistoryEntity; import org.apache.ambari.server.state.Alert; 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.stack.OsFamily; import org.easymock.EasyMock; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.api.easymock.PowerMock; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import com.google.common.eventbus.EventBus; import com.google.inject.Binder; import com.google.inject.Guice; import com.google.inject.Injector; import com.google.inject.Module; /** * Tests {@link StaleAlertRunnableTest}. */ @RunWith(PowerMockRunner.class) @PrepareForTest({ StaleAlertRunnable.class, ManagementFactory.class }) public class StaleAlertRunnableTest { private final static long CLUSTER_ID = 1; private final static String CLUSTER_NAME = "c1"; private final static String DEFINITION_NAME = "ambari_server_stale_alerts"; private final static String DEFINITION_SERVICE = "AMBARI"; private final static String DEFINITION_COMPONENT = "AMBARI_SERVER"; private final static String DEFINITION_LABEL = "Mock Definition"; private final static int DEFINITION_INTERVAL = 1; private Clusters m_clusters; private Cluster m_cluster; private Injector m_injector; private AlertsDAO m_alertsDao; private AlertDefinitionDAO m_definitionDao; private AlertDefinitionEntity m_definition; private List<AlertCurrentEntity> m_currentAlerts = new ArrayList<>(); private MockEventListener m_listener; private AlertEventPublisher m_eventPublisher; private EventBus m_synchronizedBus; private RuntimeMXBean m_runtimeMXBean; /** * */ @Before public void setup() throws Exception { m_injector = Guice.createInjector(new MockModule()); m_alertsDao = m_injector.getInstance(AlertsDAO.class); m_definitionDao = m_injector.getInstance(AlertDefinitionDAO.class); m_clusters = m_injector.getInstance(Clusters.class); m_cluster = m_injector.getInstance(Cluster.class); m_eventPublisher = m_injector.getInstance(AlertEventPublisher.class); m_listener = m_injector.getInstance(MockEventListener.class); m_definition = EasyMock.createNiceMock(AlertDefinitionEntity.class); // !!! need a synchronous op for testing m_synchronizedBus = new EventBus(); Field field = AlertEventPublisher.class.getDeclaredField("m_eventBus"); field.setAccessible(true); field.set(m_eventPublisher, m_synchronizedBus); // register mock listener m_synchronizedBus.register(m_listener); // create the cluster map Map<String,Cluster> clusterMap = new HashMap<>(); clusterMap.put(CLUSTER_NAME, m_cluster); // mock the definition for the alert expect(m_definition.getDefinitionId()).andReturn(1L).atLeastOnce(); expect(m_definition.getDefinitionName()).andReturn(DEFINITION_NAME).atLeastOnce(); expect(m_definition.getServiceName()).andReturn(DEFINITION_SERVICE).atLeastOnce(); expect(m_definition.getComponentName()).andReturn(DEFINITION_COMPONENT).atLeastOnce(); expect(m_definition.getLabel()).andReturn(DEFINITION_LABEL).atLeastOnce(); expect(m_definition.getEnabled()).andReturn(true).atLeastOnce(); expect(m_definition.getScheduleInterval()).andReturn(DEFINITION_INTERVAL).atLeastOnce(); expect(m_definition.getClusterId()).andReturn(CLUSTER_ID).atLeastOnce(); expect(m_definition.getSource()).andReturn("{\"type\" : \"SERVER\"}").anyTimes(); // mock the cluster expect(m_cluster.getClusterId()).andReturn(CLUSTER_ID).atLeastOnce(); // mock clusters expect(m_clusters.getClusters()).andReturn(clusterMap).atLeastOnce(); // mock the definition DAO expect(m_definitionDao.findByName(CLUSTER_ID, DEFINITION_NAME)).andReturn( m_definition).atLeastOnce(); // mock the current dao expect(m_alertsDao.findCurrentByCluster(CLUSTER_ID)).andReturn( m_currentAlerts).atLeastOnce(); // mock out the uptime to be a while (since most tests are not testing // system uptime) m_runtimeMXBean = EasyMock.createNiceMock(RuntimeMXBean.class); PowerMock.mockStatic(ManagementFactory.class); expect(ManagementFactory.getRuntimeMXBean()).andReturn(m_runtimeMXBean).atLeastOnce(); PowerMock.replay(ManagementFactory.class); expect(m_runtimeMXBean.getUptime()).andReturn(360000L); replay(m_definition, m_cluster, m_clusters, m_definitionDao, m_alertsDao, m_runtimeMXBean); } /** * @throws Exception */ @After public void teardown() throws Exception { } /** * Tests that the event is triggerd with a status of OK. */ @Test public void testAllAlertsAreCurrent() { // create current alerts that are not stale AlertDefinitionEntity definition = new AlertDefinitionEntity(); definition.setClusterId(CLUSTER_ID); definition.setDefinitionName("foo-definition"); definition.setServiceName("HDFS"); definition.setComponentName("NAMENODE"); definition.setEnabled(true); definition.setScheduleInterval(1); AlertCurrentEntity current1 = createNiceMock(AlertCurrentEntity.class); AlertHistoryEntity history1 = createNiceMock(AlertHistoryEntity.class); expect(current1.getAlertHistory()).andReturn(history1).atLeastOnce(); expect(history1.getAlertDefinition()).andReturn(definition).atLeastOnce(); expect(current1.getMaintenanceState()).andReturn(MaintenanceState.OFF).atLeastOnce(); expect(current1.getLatestTimestamp()).andReturn(System.currentTimeMillis()).atLeastOnce(); replay(current1, history1); m_currentAlerts.add(current1); // precondition that no events were fired assertEquals(0, m_listener.getAlertEventReceivedCount(AlertReceivedEvent.class)); // instantiate and inject mocks StaleAlertRunnable runnable = new StaleAlertRunnable(m_definition.getDefinitionName()); m_injector.injectMembers(runnable); // run the alert runnable.run(); assertEquals(1, m_listener.getAlertEventReceivedCount(AlertReceivedEvent.class)); List<AlertEvent> events = m_listener.getAlertEventInstances(AlertReceivedEvent.class); assertEquals(1, events.size()); AlertReceivedEvent event = (AlertReceivedEvent) events.get(0); Alert alert = event.getAlert(); assertEquals("AMBARI", alert.getService()); assertEquals("AMBARI_SERVER", alert.getComponent()); assertEquals(AlertState.OK, alert.getState()); assertEquals(DEFINITION_NAME, alert.getName()); verify(m_cluster, m_clusters, m_definitionDao); } /** * Tests that a stale alert triggers the event with a status of CRITICAL. */ @Test public void testStaleAlert() { // create current alerts that are not stale AlertDefinitionEntity definition = new AlertDefinitionEntity(); definition.setClusterId(CLUSTER_ID); definition.setDefinitionName("foo-definition"); definition.setServiceName("HDFS"); definition.setComponentName("NAMENODE"); definition.setEnabled(true); definition.setScheduleInterval(1); // create current alerts that are stale AlertCurrentEntity current1 = createNiceMock(AlertCurrentEntity.class); AlertHistoryEntity history1 = createNiceMock(AlertHistoryEntity.class); expect(current1.getAlertHistory()).andReturn(history1).atLeastOnce(); expect(history1.getAlertDefinition()).andReturn(definition).atLeastOnce(); // a really old timestampt to trigger the alert expect(current1.getMaintenanceState()).andReturn(MaintenanceState.OFF).atLeastOnce(); expect(current1.getLatestTimestamp()).andReturn(1L).atLeastOnce(); replay(current1, history1); m_currentAlerts.add(current1); // precondition that no events were fired assertEquals(0, m_listener.getAlertEventReceivedCount(AlertReceivedEvent.class)); // instantiate and inject mocks StaleAlertRunnable runnable = new StaleAlertRunnable(m_definition.getDefinitionName()); m_injector.injectMembers(runnable); // run the alert runnable.run(); assertEquals(1, m_listener.getAlertEventReceivedCount(AlertReceivedEvent.class)); List<AlertEvent> events = m_listener.getAlertEventInstances(AlertReceivedEvent.class); assertEquals(1, events.size()); AlertReceivedEvent event = (AlertReceivedEvent) events.get(0); Alert alert = event.getAlert(); assertEquals("AMBARI", alert.getService()); assertEquals("AMBARI_SERVER", alert.getComponent()); assertEquals(AlertState.CRITICAL, alert.getState()); assertEquals(DEFINITION_NAME, alert.getName()); verify(m_cluster, m_clusters, m_definitionDao); } /** * Tests that a stale alert in maintenance mode doesn't trigger the event. */ @Test public void testStaleAlertInMaintenaceMode() { // create current alerts that are stale AlertDefinitionEntity definition = new AlertDefinitionEntity(); definition.setClusterId(CLUSTER_ID); definition.setDefinitionName("foo-definition"); definition.setServiceName("HDFS"); definition.setComponentName("NAMENODE"); definition.setEnabled(true); definition.setScheduleInterval(1); // create current alerts where 1 is stale but in maintence mode AlertCurrentEntity current1 = createNiceMock(AlertCurrentEntity.class); AlertHistoryEntity history1 = createNiceMock(AlertHistoryEntity.class); AlertCurrentEntity current2 = createNiceMock(AlertCurrentEntity.class); AlertHistoryEntity history2 = createNiceMock(AlertHistoryEntity.class); expect(current1.getAlertHistory()).andReturn(history1).atLeastOnce(); expect(history1.getAlertDefinition()).andReturn(definition).atLeastOnce(); expect(current2.getAlertHistory()).andReturn(history2).atLeastOnce(); expect(history2.getAlertDefinition()).andReturn(definition).atLeastOnce(); // maintenance mode with a really old timestamp expect(current1.getMaintenanceState()).andReturn(MaintenanceState.ON).atLeastOnce(); expect(current1.getLatestTimestamp()).andReturn(1L).atLeastOnce(); // an that that is not stale expect(current2.getMaintenanceState()).andReturn(MaintenanceState.OFF).atLeastOnce(); expect(current2.getLatestTimestamp()).andReturn(System.currentTimeMillis()).atLeastOnce(); replay(current1, history1, current2, history2); m_currentAlerts.add(current1); m_currentAlerts.add(current2); // precondition that no events were fired assertEquals(0, m_listener.getAlertEventReceivedCount(AlertReceivedEvent.class)); // instantiate and inject mocks StaleAlertRunnable runnable = new StaleAlertRunnable(m_definition.getDefinitionName()); m_injector.injectMembers(runnable); // run the alert runnable.run(); assertEquals(1, m_listener.getAlertEventReceivedCount(AlertReceivedEvent.class)); List<AlertEvent> events = m_listener.getAlertEventInstances(AlertReceivedEvent.class); assertEquals(1, events.size()); AlertReceivedEvent event = (AlertReceivedEvent) events.get(0); Alert alert = event.getAlert(); assertEquals("AMBARI", alert.getService()); assertEquals("AMBARI_SERVER", alert.getComponent()); assertEquals(AlertState.OK, alert.getState()); assertEquals(DEFINITION_NAME, alert.getName()); verify(m_cluster, m_clusters, m_definitionDao); } /** * Tests that stale alerts are not reported if the server has not be running * long enough. */ @Test public void testStaleAlertWithServerUptime() { // reset the Runtime MX bean to a low value reset(m_runtimeMXBean); expect(m_runtimeMXBean.getUptime()).andReturn(1000L); replay(m_runtimeMXBean); // create current alerts that are stale (5 minute interval) AlertDefinitionEntity definition = new AlertDefinitionEntity(); definition.setClusterId(CLUSTER_ID); definition.setDefinitionName("foo-definition"); definition.setServiceName("HDFS"); definition.setComponentName("NAMENODE"); definition.setEnabled(true); definition.setScheduleInterval(5); // create current alerts that are stale AlertCurrentEntity current1 = createNiceMock(AlertCurrentEntity.class); AlertHistoryEntity history1 = createNiceMock(AlertHistoryEntity.class); expect(current1.getAlertHistory()).andReturn(history1).atLeastOnce(); expect(history1.getAlertDefinition()).andReturn(definition).atLeastOnce(); // use a timestamp that would trigger the alert, say 3x the interval ago (so // 15 minutes ago) long now = System.currentTimeMillis(); long staleTime = now - (definition.getScheduleInterval() * 60 * 1000 * 3); expect(current1.getMaintenanceState()).andReturn(MaintenanceState.OFF).atLeastOnce(); expect(current1.getLatestTimestamp()).andReturn(staleTime).atLeastOnce(); replay(current1, history1); m_currentAlerts.add(current1); // precondition that no events were fired assertEquals(0, m_listener.getAlertEventReceivedCount(AlertReceivedEvent.class)); // instantiate and inject mocks StaleAlertRunnable runnable = new StaleAlertRunnable(m_definition.getDefinitionName()); m_injector.injectMembers(runnable); // run the alert runnable.run(); // ensure that our mock MX bean was used verify(m_runtimeMXBean); // verify that our uptime was too short so nothing should have been // triggered assertEquals(1, m_listener.getAlertEventReceivedCount(AlertReceivedEvent.class)); List<AlertEvent> events = m_listener.getAlertEventInstances(AlertReceivedEvent.class); assertEquals(1, events.size()); AlertReceivedEvent event = (AlertReceivedEvent) events.get(0); Alert alert = event.getAlert(); assertEquals("AMBARI", alert.getService()); assertEquals("AMBARI_SERVER", alert.getComponent()); assertEquals(AlertState.OK, alert.getState()); assertEquals(DEFINITION_NAME, alert.getName()); // now reset the mocks to indicate that Ambari has been up long enough m_listener.reset(); long uptime = definition.getScheduleInterval() * 60 * 1000 * 4; reset(m_runtimeMXBean); expect(m_runtimeMXBean.getUptime()).andReturn(uptime); replay(m_runtimeMXBean); // run the alert again and verify that the same stale alert caused a // CRITICAL runnable.run(); // recheck for the stale alert events = m_listener.getAlertEventInstances(AlertReceivedEvent.class); assertEquals(1, events.size()); event = (AlertReceivedEvent) events.get(0); alert = event.getAlert(); assertEquals("AMBARI", alert.getService()); assertEquals("AMBARI_SERVER", alert.getComponent()); assertEquals(AlertState.CRITICAL, alert.getState()); assertEquals(DEFINITION_NAME, alert.getName()); assertEquals(1, m_listener.getAlertEventReceivedCount(AlertReceivedEvent.class)); } /** * */ private class MockModule implements Module { /** * */ @Override public void configure(Binder binder) { Cluster cluster = EasyMock.createNiceMock(Cluster.class); binder.bind(Clusters.class).toInstance(createNiceMock(Clusters.class)); binder.bind(OsFamily.class).toInstance(createNiceMock(OsFamily.class)); binder.bind(DBAccessor.class).toInstance(createNiceMock(DBAccessor.class)); binder.bind(Cluster.class).toInstance(cluster); binder.bind(AlertDefinitionDAO.class).toInstance(createNiceMock(AlertDefinitionDAO.class)); binder.bind(AlertsDAO.class).toInstance(createNiceMock(AlertsDAO.class)); binder.bind(EntityManager.class).toInstance(createNiceMock(EntityManager.class)); } } }