/*****************************************************************************
*
* Copyright (C) Zenoss, Inc. 2011, 2014 all rights reserved.
*
* This content is made available according to terms specified in
* License.zenoss under the directory where your Zenoss product is installed.
*
****************************************************************************/
package org.zenoss.zep.dao.impl;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;
import org.zenoss.protobufs.zep.Zep.Event;
import org.zenoss.protobufs.zep.Zep.EventNote;
import org.zenoss.protobufs.zep.Zep.EventStatus;
import org.zenoss.protobufs.zep.Zep.EventSummary;
import org.zenoss.zep.ZepException;
import org.zenoss.zep.dao.EventArchiveDao;
import org.zenoss.zep.dao.EventIndexHandler;
import org.zenoss.zep.dao.EventIndexQueueDao;
import org.zenoss.zep.dao.EventSummaryBaseDao;
import org.zenoss.zep.dao.EventSummaryDao;
import org.zenoss.zep.dao.IndexQueueID;
import org.zenoss.zep.dao.impl.compat.DatabaseCompatibility;
import org.zenoss.zep.dao.impl.compat.TypeConverter;
import org.zenoss.zep.impl.EventPreCreateContextImpl;
import org.zenoss.zep.index.EventIndexDao;
import org.zenoss.zep.index.impl.MultiBackendEventIndexDao;
import org.zenoss.zep.index.impl.RedisWorkQueue;
import org.zenoss.zep.index.impl.lucene.LuceneEventIndexBackend;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;
import static org.junit.Assert.*;
/**
* Integration tests for EventIndexQueueDao.
*/
@ContextConfiguration({"classpath:zep-config.xml"})
public class EventIndexQueueDaoImplIT extends AbstractTransactionalJUnit4SpringContextTests {
@Autowired
public RedisWorkQueue workQueue;
@Autowired
public EventSummaryDao eventSummaryDao;
@Autowired
public EventArchiveDao eventArchiveDao;
@Autowired
@Qualifier("summary")
public EventIndexDao eventSummaryIndexDao;
@Autowired
@Qualifier("summary")
public LuceneEventIndexBackend eventSummaryLuceneIndexBackend;
@Autowired
@Qualifier("archive")
public EventIndexDao eventArchiveIndexDao;
@Autowired
@Qualifier("archive")
public LuceneEventIndexBackend eventArchiveLuceneIndexBackend;
@Autowired
@Qualifier("summary")
public EventIndexQueueDao eventSummaryIndexQueueDao;
@Autowired
@Qualifier("archive")
public EventIndexQueueDao eventArchiveIndexQueueDao;
@Autowired
public DatabaseCompatibility databaseCompatibility;
@Before
public void setup() throws ZepException {
((MultiBackendEventIndexDao) eventSummaryIndexDao).disableRebuilders();
((MultiBackendEventIndexDao) eventArchiveIndexDao).disableRebuilders();
((MultiBackendEventIndexDao) eventSummaryIndexDao).disableAsyncProcessing();
((MultiBackendEventIndexDao) eventArchiveIndexDao).disableAsyncProcessing();
eventSummaryIndexDao.clear();
eventArchiveIndexDao.clear();
eventSummaryLuceneIndexBackend.setReaderReopenInterval(0);
eventArchiveLuceneIndexBackend.setReaderReopenInterval(0);
eventSummaryDao.setTxSynchronizedQueue(false);
this.workQueue.clearAll();
this.simpleJdbcTemplate.update("TRUNCATE TABLE event_archive_index_queue");
}
private EventSummary create(EventSummaryBaseDao eventSummaryBaseDao, boolean archive) throws ZepException {
Event event = EventTestUtils.createSampleEvent();
if (archive) {
event = Event.newBuilder(event).setStatus(EventStatus.STATUS_CLOSED).build();
}
String uuid = eventSummaryBaseDao.create(event, new EventPreCreateContextImpl());
return eventSummaryBaseDao.findByUuid(uuid);
}
private static class TestEventIndexHandler implements EventIndexHandler {
private List<EventSummary> indexed = new ArrayList<EventSummary>();
private List<String> deleted = new ArrayList<String>();
private AtomicBoolean completed = new AtomicBoolean(false);
@Override
public void prepareToHandle(Collection<EventSummary> events) throws Exception {
//noop
}
@Override
public void handle(EventSummary event) throws Exception {
this.indexed.add(event);
}
@Override
public void handleDeleted(String uuid) throws Exception {
this.deleted.add(uuid);
}
@Override
public void handleComplete() throws Exception {
if (!completed.compareAndSet(false, true)) {
throw new IllegalStateException("handleComplete should only be called once");
}
}
}
private EventSummary testCreate(EventSummaryBaseDao eventSummaryBaseDao, EventIndexQueueDao eventIndexQueueDao,
boolean archive) throws ZepException {
EventSummary eventSummary = create(eventSummaryBaseDao, archive);
TestEventIndexHandler handler = new TestEventIndexHandler();
List<IndexQueueID> indexQueueIds = eventIndexQueueDao.indexEvents(handler, 1000);
assertEquals(1, indexQueueIds.size());
assertTrue(handler.completed.get());
assertEquals(1, handler.indexed.size());
assertEquals(removeIsArchiveDetail(eventSummary), removeIsArchiveDetail(handler.indexed.get(0)));
assertTrue(handler.deleted.isEmpty());
eventIndexQueueDao.deleteIndexQueueIds(indexQueueIds);
/* Run it again and verify that the event has been deleted */
handler = new TestEventIndexHandler();
assertEquals(0, eventIndexQueueDao.indexEvents(handler, 1000).size());
assertFalse(handler.completed.get());
assertTrue(handler.indexed.isEmpty());
assertTrue(handler.deleted.isEmpty());
return eventSummary;
}
public static EventSummary removeIsArchiveDetail(EventSummary input) {
for (int i = 0; i < input.getOccurrence(0).getDetailsCount(); i++) {
if ("is_archive".equals(input.getOccurrence(0).getDetails(i).getName())) {
EventSummary.Builder builder = EventSummary.newBuilder(input);
Event.Builder eventBuilder = builder.getOccurrenceBuilder(0);
eventBuilder.removeDetails(i);
return builder.build();
}
}
return input;
}
@Test
public void testIndexCreatedEvents() throws ZepException {
testCreate(eventSummaryDao, eventSummaryIndexQueueDao, false);
testCreate(eventArchiveDao, eventArchiveIndexQueueDao, true);
}
private void testModify(EventSummaryBaseDao eventSummaryBaseDao, EventIndexQueueDao eventIndexQueueDao,
boolean archive) throws ZepException {
EventSummary summary = testCreate(eventSummaryBaseDao, eventIndexQueueDao, archive);
EventNote note = EventNote.newBuilder().setCreatedTime(System.currentTimeMillis())
.setMessage("My note").setUserName("pkw").setUserUuid(UUID.randomUUID().toString())
.setUuid(UUID.randomUUID().toString()).build();
eventSummaryBaseDao.addNote(summary.getUuid(), note);
EventSummary summaryWithNote = eventSummaryBaseDao.findByUuid(summary.getUuid());
TestEventIndexHandler handler = new TestEventIndexHandler();
List<IndexQueueID> indexQueueIds = eventIndexQueueDao.indexEvents(handler, 1000);
assertEquals(1, indexQueueIds.size());
assertTrue(handler.completed.get());
assertEquals(1, handler.indexed.size());
assertEquals(removeIsArchiveDetail(summaryWithNote), removeIsArchiveDetail(handler.indexed.get(0)));
assertTrue(handler.deleted.isEmpty());
eventIndexQueueDao.deleteIndexQueueIds(indexQueueIds);
/* Run it again and verify that the event has been deleted */
handler = new TestEventIndexHandler();
assertEquals(0, eventIndexQueueDao.indexEvents(handler, 1000).size());
assertFalse(handler.completed.get());
assertTrue(handler.indexed.isEmpty());
assertTrue(handler.deleted.isEmpty());
}
@Test
public void testIndexModifiedEvents() throws ZepException {
testModify(eventSummaryDao, eventSummaryIndexQueueDao, false);
testModify(eventArchiveDao, eventArchiveIndexQueueDao, true);
}
private void testDelete(EventSummaryBaseDao eventSummaryBaseDao, EventIndexQueueDao eventIndexQueueDao,
boolean archive) throws ZepException {
TypeConverter<String> uuidConverter = databaseCompatibility.getUUIDConverter();
EventSummary summary = testCreate(eventSummaryBaseDao, eventIndexQueueDao, archive);
String tableName = (archive) ? EventConstants.TABLE_EVENT_ARCHIVE : EventConstants.TABLE_EVENT_SUMMARY;
// event_summary triggers were dropped after adding the percona external tool for optimize
// emulating the old event_summary triggers...
if (!archive) {
int closed = eventSummaryDao.close(Collections.singletonList(summary.getUuid()), UUID.randomUUID().toString(), "test");
assertEquals(1, closed);
TestEventIndexHandler handler = new TestEventIndexHandler();
List<IndexQueueID> indexQueueIds = eventIndexQueueDao.indexEvents(handler, 1000);
assertEquals(1, indexQueueIds.size());
assertTrue(handler.completed.get());
assertEquals(1, handler.indexed.size());
assertTrue(handler.deleted.isEmpty());
int archived = eventSummaryDao.archive(Collections.singletonList(summary.getUuid()));
assertEquals(1, archived);
} else {
int numDeleted = this.simpleJdbcTemplate.update("DELETE FROM " + tableName + " WHERE uuid=?",
uuidConverter.toDatabaseType(summary.getUuid()));
assertEquals(1, numDeleted);
}
TestEventIndexHandler handler = new TestEventIndexHandler();
List<IndexQueueID> indexQueueIds = eventIndexQueueDao.indexEvents(handler, 1000);
assertEquals(1, indexQueueIds.size());
assertTrue(handler.completed.get());
assertTrue(handler.indexed.isEmpty());
assertEquals(1, handler.deleted.size());
assertEquals(summary.getUuid(), handler.deleted.get(0));
eventIndexQueueDao.deleteIndexQueueIds(indexQueueIds);
/* Run it again and verify that the event has been deleted */
handler = new TestEventIndexHandler();
assertEquals(0, eventIndexQueueDao.indexEvents(handler, 1000).size());
assertFalse(handler.completed.get());
assertTrue(handler.indexed.isEmpty());
assertTrue(handler.deleted.isEmpty());
}
@Test
public void testIndexDeletedEvents() throws ZepException {
testDelete(eventSummaryDao, eventSummaryIndexQueueDao, false);
}
@Test
public void testIndexArchiveDeletedEvents() throws ZepException {
testDelete(eventArchiveDao, eventArchiveIndexQueueDao, true);
}
@Test
public void testSummaryQueueLength() throws ZepException {
eventSummaryIndexQueueDao.getQueueLength();
}
@Test
public void testArchiveQueueLength() throws ZepException {
long actual = eventSummaryIndexQueueDao.getQueueLength();
assertEquals(0L, actual);
}
@Test
public void testIndexGrouping() throws ZepException {
// Verifies that during indexing, we will only process the same event once.
// Create one event 500 times
Event event = EventTestUtils.createSampleEvent();
for (int i = 0; i < 500; i++) {
eventSummaryDao.create(event, new EventPreCreateContextImpl());
}
TestEventIndexHandler handler = new TestEventIndexHandler();
List<IndexQueueID> indexQueueIds = eventSummaryIndexQueueDao.indexEvents(handler, 1000);
// The number of queue ids should be 500
assertEquals(500, indexQueueIds.size());
assertEquals(1, handler.indexed.size());
assertEquals(0, handler.deleted.size());
assertTrue(handler.completed.get());
}
}