Java tutorial
/* * Copyright (C) 2005-2014 Alfresco Software Limited. * * This file is part of Alfresco * * Alfresco is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Alfresco is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Alfresco. If not, see <http://www.gnu.org/licenses/>. */ package org.alfresco.bm.event.mongo; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import org.alfresco.bm.event.Event; import org.alfresco.bm.event.EventRecord; import org.alfresco.bm.event.ResultService; import org.alfresco.bm.event.ResultService.ResultHandler; import org.alfresco.mongo.MongoDBForTestsFactory; import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import com.mongodb.BasicDBObject; import com.mongodb.BasicDBObjectBuilder; import com.mongodb.DB; import com.mongodb.DBCollection; import com.mongodb.DBObject; /** * @see MongoResultService * * @author Derek Hulley * @since 2.0 */ @RunWith(JUnit4.class) public class MongoResultServiceTest { private MongoDBForTestsFactory mongoFactory; private MongoResultService resultService; private DB db; private DBCollection rs; /** * make sure the system name is NOT contained as from 3.2 on * * @param collection * (Set<String>) collection to check * @return */ private Set<String> removeSystemValues(Set<String> collection) { if (null != collection) { // make sure the system name is NOT contained as from 3.2 on if (collection.contains("system.indexes")) { collection.remove("system.indexes"); } } return collection; } @Before public void setUp() throws Exception { mongoFactory = new MongoDBForTestsFactory(); db = mongoFactory.getObject(); resultService = new MongoResultService(db, "rs"); resultService.start(); rs = db.getCollection("rs"); } @After public void tearDown() throws Exception { resultService.stop(); mongoFactory.destroy(); } @Test public void basic() { assertNotNull(db); assertNotNull(rs); Set<String> collectionNames = new HashSet<String>(); collectionNames.add("rs"); assertEquals(collectionNames, removeSystemValues(db.getCollectionNames())); // Check indexes (includes implicit '_id_' index) List<DBObject> indexes = rs.getIndexInfo(); assertEquals("Incorrect indexes: " + indexes, 5, indexes.size()); } @Test public void empty() { assertEquals(0, resultService.countResults()); assertEquals(0, resultService.countResultsByFailure()); assertEquals(0, resultService.countResultsBySuccess()); assertEquals(0, resultService.countResultsByEventName("e.1")); assertEquals(0, resultService.getResults("e.1", 0, 5).size()); assertEquals(0, resultService.getResults(0L, Long.MAX_VALUE, false, 0, 5).size()); resultService.getResults(new ResultHandler() { @Override public boolean processResult(long fromTime, long toTime, Map<String, DescriptiveStatistics> statsByEventName, Map<String, Integer> failuresByEventName) throws Throwable { fail("Should not have any results"); return true; } }, 0L, 1000L, 100L, false); } /** * Attempt to record bad results */ @Test public void recordBadResults() { EventRecord record = null; // Null record try { resultService.recordResult(record); fail("Null should be checked."); } catch (IllegalArgumentException e) { // Expected } } /** * Create a sample set of results */ public static final EventRecord createEventRecord(long eventStartTime) { Event event = MongoEventServiceTest.createEvent(); String driver = "DRIVER" + (int) (Math.random() * 10); boolean success = Math.random() >= 0.5; long startTime = eventStartTime; long time = (long) (Math.random() * 1000.0); boolean chart = Math.random() > 0.5; long startDelay = (long) (Math.random() * 100.0); boolean warn = time > 900L; DBObject data = BasicDBObjectBuilder.start().get(); for (int i = 0; i < 10; i++) { String dataKey = "D-" + i; Integer dataValue = i; data.put(dataKey, dataValue); } EventRecord eventRecord = new EventRecord(driver, success, startTime, time, data, event); eventRecord.setChart(chart); eventRecord.setStartDelay(startDelay); if (warn) { eventRecord.setWarning("Execution time was greater than 900ms"); } // Record a random processor eventRecord.setProcessedBy("someTestProcessor"); // Done return eventRecord; } @Test public synchronized void persistenceAndSearchOfNonSerializableEventData() throws Exception { Event event = new Event("eventX", this); EventRecord eventRecord = new EventRecord("DRIVERID", true, 0L, 50L, "{data:x}", event); resultService.recordResult(eventRecord); List<EventRecord> results = resultService.getResults("eventX", 0, 1); assertEquals(1, results.size()); EventRecord eventRecordOut = results.get(0); assertNull("Expect the event data to be left null.", eventRecordOut.getEvent().getData()); } @Test public synchronized void persistenceAndSearchOfDBObject() throws Exception { EventRecord eventRecord = createEventRecord(System.currentTimeMillis()); resultService.recordResult(eventRecord); // Check that we can find it using the data keys DBObject findObj = new BasicDBObject("data.D-1", Integer.valueOf(1)); DBObject foundObj = rs.findOne(findObj); assertNotNull("Did not find result with DBObject data.", foundObj); // Check that we can find it using the data keys findObj = new BasicDBObject("event.data.D-1", Integer.valueOf(1)); foundObj = rs.findOne(findObj); assertNotNull("Did not find result with DBObject data.", foundObj); } /** * Push N number of event records into the {@link ResultService}. * The first event will be now and there will be one every 10ms. */ private void pumpRecords(int n) { long testStartTime = System.currentTimeMillis(); for (int i = 0; i < n; i++) { EventRecord eventRecord = createEventRecord(testStartTime + i * 10L); resultService.recordResult(eventRecord); } } @Test public void countEventsBySuccessAndFailure() { pumpRecords(100); assertEquals(100, resultService.countResults()); assertEquals(100, resultService.countResultsByFailure() + resultService.countResultsBySuccess()); } @Test public void countEventsByName() { pumpRecords(100); List<String> names = resultService.getEventNames(); long total = 0L; for (String name : names) { long count = resultService.countResultsByEventName(name); total += count; } assertEquals(100, total); } @Test public void getResultsPagedAll() { pumpRecords(100); long total = 0L; int skip = 0; int limit = 5; while (true) { List<EventRecord> records = resultService.getResults(null, skip, limit); for (EventRecord record : records) { assertTrue(record.getEvent().getData() instanceof DBObject); assertTrue(record.getData() instanceof DBObject); if (record.getTime() > 900L) { assertTrue("Warning not tracked", record.getWarning() != null); } else { assertTrue("Unexpected warning", record.getWarning() == null); } assertNotNull(record.getId()); } total += records.size(); // Do we keep paging? if (records.size() < limit) { break; } else { skip += limit; } } assertEquals(100, total); } @Test public void getResultsPagedByEventName() { pumpRecords(100); List<String> names = resultService.getEventNames(); long total = 0L; for (String name : names) { int skip = 0; int limit = 5; while (true) { List<EventRecord> records = resultService.getResults(name, skip, limit); for (EventRecord record : records) { assertEquals("Incorrect event name", name, record.getEvent().getName()); // Check that we record and retrieve the 'processedBy' field assertEquals("someTestProcessor", record.getProcessedBy()); } total += records.size(); // Do we keep paging? if (records.size() < limit) { break; } else { skip += limit; } } } assertEquals(100, total); // Check that invalid event name returns nothing assertEquals(0, resultService.getResults("BOB", 0, 1).size()); } @Test public void getResultsAfterTime() { long before = System.currentTimeMillis() - 10L; // The start time is set back when the record is created pumpRecords(100); long after = before + 100 * 10L + 10L; // Extra 10ms to Adjust for JVM accuracy int totalA = 0; // before, future, all int totalB = 0; // after, future, all int totalC = 0; // before, future, chart-only int limit = 5; for (int skip = 0; skip < 100; skip += limit) { totalA += resultService.getResults(before, Long.MAX_VALUE, false, skip, limit).size(); totalB += resultService.getResults(after, Long.MAX_VALUE, false, skip, limit).size(); totalC += resultService.getResults(before, Long.MAX_VALUE, false, skip, limit).size(); } assertEquals(100, totalA); assertEquals(000, totalB); assertEquals(100, totalC); } /** * Create some results but then search for something that does not match */ @Test public void getZeroResultsUsingHandler() { pumpRecords(10); long after = resultService.getLastResult().getStartTime() + TimeUnit.HOURS.toMillis(1); // Make sure the query window is out of range final AtomicInteger count = new AtomicInteger(); resultService.getResults(new ResultHandler() { @Override public boolean processResult(long fromTime, long toTime, Map<String, DescriptiveStatistics> statsByEventName, Map<String, Integer> failuresByEventName) throws Throwable { // Check that we have a failure count for each event if (failuresByEventName.size() != statsByEventName.size()) { throw new RuntimeException("Didn't have a failure count matching stats count."); } // Increment count.incrementAndGet(); return true; } }, after, 20L, 10L, false); // Check assertEquals(0, count.get()); } /** * Test the case where the reporting period is smaller than the stats window */ @Test public void getResultsUsingHandler() { pumpRecords(10); final long firstEventTime = resultService.getFirstResult().getStartTime(); final long lastEventTime = resultService.getLastResult().getStartTime(); final AtomicInteger count = new AtomicInteger(); final Set<String> names = new HashSet<String>(17); resultService.getResults(new ResultHandler() { @Override public boolean processResult(long fromTime, long toTime, Map<String, DescriptiveStatistics> statsByEventName, Map<String, Integer> failuresByEventName) throws Throwable { if (toTime <= firstEventTime) { fail("The window is before the first event."); } if (fromTime > lastEventTime) { fail("The window is past the last event."); } assertEquals("Window not rebased. ", 0L, fromTime % 10L); // Rebased on reporting period assertEquals("Window size incorrect", 20L, toTime - fromTime); // Record all the event names we got names.addAll(statsByEventName.keySet()); // Increment count.incrementAndGet(); return true; } }, 0L, 20L, 10L, false); // Check assertEquals(10, count.get()); assertEquals(resultService.getEventNames().size(), names.size()); } /** * Test the case where the reporting period is smaller than the stats window */ @Test public void getCheckedResultsUsingHandler() { pumpRecords(10); final AtomicInteger count = new AtomicInteger(); final Map<String, DescriptiveStatistics> lastStatsByEventName = new HashMap<String, DescriptiveStatistics>( 17); resultService.getResults(new ResultHandler() { @Override public boolean processResult(long fromTime, long toTime, Map<String, DescriptiveStatistics> statsByEventName, Map<String, Integer> failuresByEventName) throws Throwable { // Always keep the last stats lastStatsByEventName.clear(); lastStatsByEventName.putAll(statsByEventName); count.incrementAndGet(); return true; } }, 0L, 200L, 10L, false); // Check assertEquals(10, count.get()); // Now go through the last stats received // Check it against the last window size List<String> names = resultService.getEventNames(); for (String eventName : names) { List<EventRecord> eventResults = resultService.getResults(eventName, 0, 1000); DescriptiveStatistics eventStats = new DescriptiveStatistics(); for (EventRecord eventRecord : eventResults) { eventStats.addValue(eventRecord.getTime()); } DescriptiveStatistics lastEventStats = lastStatsByEventName.get(eventName); assertNotNull("No last report for event '" + eventName + "'.", lastEventStats); // Now check that this matched the last report exactly assertEquals("Mean for '" + eventName + "' was not correct. ", (long) Math.floor(eventStats.getMean()), (long) Math.floor(lastStatsByEventName.get(eventName).getMean())); } } }