/** * 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.orm.dao; import java.util.List; import javax.persistence.EntityManager; import javax.persistence.TypedQuery; import org.apache.ambari.server.configuration.Configuration; import org.apache.ambari.server.orm.DBAccessor; 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.Cluster; import org.apache.ambari.server.state.Clusters; import org.apache.ambari.server.state.stack.OsFamily; import org.easymock.EasyMock; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import com.google.common.collect.Lists; import com.google.inject.Binder; import com.google.inject.Guice; import com.google.inject.Injector; import com.google.inject.Module; /** * Tests cached alerts are merged correct with the set from JPA. */ public class AlertsDAOCachedTest { private static final String HOST = "c6401.ambari.apache.org"; private Injector m_injector; private enum CachedAlertTestArea { FIND_ALL { @Override List<AlertCurrentEntity> execute(AlertsDAO alertsDAO) throws Exception { return alertsDAO.findCurrent(); } @Override String getNamedQuery() { return "AlertCurrentEntity.findAll"; } }, FIND_BY_DEFINITION_ID { @Override List<AlertCurrentEntity> execute(AlertsDAO alertsDAO) throws Exception { return alertsDAO.findCurrentByDefinitionId(0L); } @Override String getNamedQuery() { return "AlertCurrentEntity.findByDefinitionId"; } }, FIND_BY_CLUSTER_ID { @Override List<AlertCurrentEntity> execute(AlertsDAO alertsDAO) throws Exception { return alertsDAO.findCurrentByCluster(0L); } @Override String getNamedQuery() { return "AlertCurrentEntity.findByCluster"; } }, FIND_BY_SERVICE { @Override List<AlertCurrentEntity> execute(AlertsDAO alertsDAO) throws Exception { return alertsDAO.findCurrentByService(0L, HOST); } @Override String getNamedQuery() { return "AlertCurrentEntity.findByService"; } }; abstract List<AlertCurrentEntity> execute(AlertsDAO alertsDAO) throws Exception; abstract String getNamedQuery(); } @Before public void before() { // create an injector which will inject the mocks m_injector = Guice.createInjector(new MockModule()); } /** * Tests that finding all alerts supplements with the cache. * * @throws Exception */ @Test public void testFindAll() throws Exception { testFindUsesCache(CachedAlertTestArea.FIND_ALL); } /** * Tests that finding alerts by cluster ID supplements with the cache. * * @throws Exception */ @Test public void testFindByClusterId() throws Exception { testFindUsesCache(CachedAlertTestArea.FIND_BY_CLUSTER_ID); } /** * Tests that finding alerts by definition ID supplements with the cache. * * @throws Exception */ @Test public void testFindByDefinitionId() throws Exception { testFindUsesCache(CachedAlertTestArea.FIND_BY_DEFINITION_ID); } /** * Tests that finding alerts by service supplements with the cache. * * @throws Exception */ @Test public void testFindByService() throws Exception { testFindUsesCache(CachedAlertTestArea.FIND_BY_SERVICE); } @Test @SuppressWarnings("unchecked") public void testMergeIntoCacheOnly() throws Exception { EntityManager entityManager = m_injector.getInstance(EntityManager.class); DaoUtils daoUtils = m_injector.getInstance(DaoUtils.class); AlertHistoryEntity history = EasyMock.createNiceMock(AlertHistoryEntity.class); AlertDefinitionEntity definition = EasyMock.createNiceMock(AlertDefinitionEntity.class); mock(definition, history); AlertCurrentEntity jpaCurrent = new AlertCurrentEntity(); jpaCurrent.setAlertHistory(history); jpaCurrent.setOriginalTimestamp(1L); jpaCurrent.setLatestTimestamp(2L); AlertCurrentEntity memoryCurrent = new AlertCurrentEntity(); memoryCurrent.setAlertHistory(history); memoryCurrent.setOriginalTimestamp(1L); memoryCurrent.setLatestTimestamp(3L); // mock the EM; notice we do not mock merge since this should not call merge TypedQuery<AlertCurrentEntity> typedQuery = EasyMock.createNiceMock(TypedQuery.class); EasyMock.expect(entityManager.createNamedQuery(CachedAlertTestArea.FIND_ALL.getNamedQuery(), AlertCurrentEntity.class)).andReturn(typedQuery).atLeastOnce(); // create the data to return from mocked JPA List<AlertCurrentEntity> jpaCurrentAlerts = Lists.newArrayList(jpaCurrent); EasyMock.expect(daoUtils.selectList(typedQuery)).andReturn(jpaCurrentAlerts).atLeastOnce(); EasyMock.replay(entityManager, daoUtils, typedQuery); // invoke merge on our in-memory current entity AlertsDAO alertsDAO = m_injector.getInstance(AlertsDAO.class); alertsDAO.merge(memoryCurrent, true); List<AlertCurrentEntity> testCurrentAlerts = alertsDAO.findCurrent(); // verify that the stale JPA data is augemented with the cached data Assert.assertEquals(1, testCurrentAlerts.size()); Assert.assertEquals(Long.valueOf(3), testCurrentAlerts.get(0).getLatestTimestamp()); EasyMock.verify(definition, history, entityManager, daoUtils); } @SuppressWarnings("unchecked") private void testFindUsesCache(CachedAlertTestArea testArea) throws Exception { EntityManager entityManager = m_injector.getInstance(EntityManager.class); DaoUtils daoUtils = m_injector.getInstance(DaoUtils.class); AlertHistoryEntity history = EasyMock.createNiceMock(AlertHistoryEntity.class); AlertDefinitionEntity definition = EasyMock.createNiceMock(AlertDefinitionEntity.class); mock(definition, history); AlertCurrentEntity jpaCurrent = new AlertCurrentEntity(); jpaCurrent.setAlertHistory(history); jpaCurrent.setOriginalTimestamp(1L); jpaCurrent.setLatestTimestamp(2L); AlertCurrentEntity memoryCurrent = new AlertCurrentEntity(); memoryCurrent.setAlertHistory(history); memoryCurrent.setOriginalTimestamp(1L); memoryCurrent.setLatestTimestamp(3L); // mock the call to merge EasyMock.expect(entityManager.merge(memoryCurrent)).andReturn(memoryCurrent).atLeastOnce(); // create the data to return from mocked JPA TypedQuery<AlertCurrentEntity> typedQuery = EasyMock.createNiceMock(TypedQuery.class); // mock the call to find alerts from JPA EasyMock.expect( entityManager.createNamedQuery(testArea.getNamedQuery(), AlertCurrentEntity.class)).andReturn( typedQuery).atLeastOnce(); List<AlertCurrentEntity> jpaCurrentAlerts = Lists.newArrayList(jpaCurrent); EasyMock.expect(daoUtils.selectList(typedQuery)).andReturn( jpaCurrentAlerts).atLeastOnce(); EasyMock.replay(entityManager, daoUtils, typedQuery); // invoke merge on our in-memory current entity AlertsDAO alertsDAO = m_injector.getInstance(AlertsDAO.class); alertsDAO.merge(memoryCurrent); List<AlertCurrentEntity> testCurrentAlerts = testArea.execute(alertsDAO); // verify that the stale JPA data is augemented with the cached data Assert.assertEquals(1, testCurrentAlerts.size()); Assert.assertEquals(Long.valueOf(3), testCurrentAlerts.get(0).getLatestTimestamp()); EasyMock.verify(definition, history, entityManager, daoUtils); } /** * Mocks and replays the mocked definition and history * * @param definition * @param history */ private void mock(AlertDefinitionEntity definition, AlertHistoryEntity history) { EasyMock.expect(definition.getDefinitionName()).andReturn("definitionName").atLeastOnce(); EasyMock.expect(history.getClusterId()).andReturn(1L).atLeastOnce(); EasyMock.expect(history.getHostName()).andReturn(HOST).atLeastOnce(); EasyMock.expect(history.getAlertDefinition()).andReturn(definition).atLeastOnce(); EasyMock.expect(history.getAlertDefinitionId()).andReturn(1L).atLeastOnce(); EasyMock.expect(history.getAlertId()).andReturn(1L).atLeastOnce(); EasyMock.expect(history.getAlertText()).andReturn("alertText").atLeastOnce(); EasyMock.replay(definition, history); } /** * */ private class MockModule implements Module { /** * {@inheritDoc} */ @Override public void configure(Binder binder) { Cluster cluster = EasyMock.createNiceMock(Cluster.class); // required for since the configuration is being mocked Configuration configuration = EasyMock.createNiceMock(Configuration.class); EasyMock.expect(configuration.getAlertEventPublisherCorePoolSize()).andReturn(Integer.valueOf(Configuration.ALERTS_EXECUTION_SCHEDULER_THREADS_CORE_SIZE.getDefaultValue())).anyTimes(); EasyMock.expect(configuration.getAlertEventPublisherMaxPoolSize()).andReturn(Integer.valueOf(Configuration.ALERTS_EXECUTION_SCHEDULER_THREADS_MAX_SIZE.getDefaultValue())).anyTimes(); EasyMock.expect(configuration.getAlertEventPublisherWorkerQueueSize()).andReturn(Integer.valueOf(Configuration.ALERTS_EXECUTION_SCHEDULER_WORKER_QUEUE_SIZE.getDefaultValue())).anyTimes(); EasyMock.expect(configuration.isAlertCacheEnabled()).andReturn(Boolean.TRUE).anyTimes(); EasyMock.expect(configuration.getAlertCacheSize()).andReturn(100).anyTimes(); EasyMock.replay(configuration); binder.bind(Configuration.class).toInstance(configuration); binder.bind(Clusters.class).toInstance(EasyMock.createNiceMock(Clusters.class)); binder.bind(OsFamily.class).toInstance(EasyMock.createNiceMock(OsFamily.class)); binder.bind(DBAccessor.class).toInstance(EasyMock.createNiceMock(DBAccessor.class)); binder.bind(Cluster.class).toInstance(cluster); binder.bind(AlertDefinitionDAO.class).toInstance(EasyMock.createNiceMock(AlertDefinitionDAO.class)); binder.bind(EntityManager.class).toInstance(EasyMock.createNiceMock(EntityManager.class)); binder.bind(DaoUtils.class).toInstance(EasyMock.createNiceMock(DaoUtils.class)); } } }