package org.kairosdb.rollup; import com.google.common.collect.ImmutableSortedMap; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.kairosdb.core.DataPoint; import org.kairosdb.core.DataPointListener; import org.kairosdb.core.TestDataPointFactory; import org.kairosdb.core.aggregator.*; import org.kairosdb.core.datapoints.DoubleDataPoint; import org.kairosdb.core.datapoints.DoubleDataPointFactory; import org.kairosdb.core.datastore.*; import org.kairosdb.core.exception.DatastoreException; import org.kairosdb.testing.ListDataPointGroup; import java.io.IOException; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.*; import static org.hamcrest.CoreMatchers.equalTo; import static org.junit.Assert.assertThat; import static org.mockito.Mockito.mock; public class RollUpJobTest { private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss.SS",Locale.ENGLISH); @Rule public ExpectedException expectedException = ExpectedException.none(); private long lastTimeStamp; private KairosDatastore datastore; private TestDatastore testDataStore; @Before public void setup() throws ParseException, DatastoreException { lastTimeStamp = dateFormat.parse("2013-JAN-18 4:55:12.22").getTime(); testDataStore = new TestDatastore(); datastore = new KairosDatastore(testDataStore, new QueryQueuingManager(1, "hostname"), Collections.<DataPointListener>emptyList(), new TestDataPointFactory(), false); } @Test public void test_getLastSampling() { Sampling sampling1 = new Sampling(1, TimeUnit.DAYS); Sampling sampling2 = new Sampling(2, TimeUnit.MINUTES); DoubleDataPointFactory dataPointFactory = mock(DoubleDataPointFactory.class); MinAggregator minAggregator = new MinAggregator(dataPointFactory); minAggregator.setSampling(sampling1); MaxAggregator maxAggregator = new MaxAggregator(dataPointFactory); maxAggregator.setSampling(sampling2); List<Aggregator> aggregators = new ArrayList<Aggregator>(); aggregators.add(minAggregator); aggregators.add(maxAggregator); aggregators.add(new DivideAggregator(dataPointFactory)); aggregators.add(new DiffAggregator(dataPointFactory)); Sampling lastSampling = RollUpJob.getLastSampling(aggregators); assertThat(lastSampling, equalTo(sampling2)); aggregators = new ArrayList<Aggregator>(); aggregators.add(maxAggregator); aggregators.add(new DivideAggregator(dataPointFactory)); aggregators.add(new DiffAggregator(dataPointFactory)); aggregators.add(minAggregator); lastSampling = RollUpJob.getLastSampling(aggregators); assertThat(lastSampling, equalTo(sampling1)); } @Test public void test_getLastSampling_no_sampling() { DoubleDataPointFactory dataPointFactory = mock(DoubleDataPointFactory.class); List<Aggregator> aggregators = new ArrayList<Aggregator>(); aggregators.add(new DivideAggregator(dataPointFactory)); aggregators.add(new DiffAggregator(dataPointFactory)); Sampling lastSampling = RollUpJob.getLastSampling(aggregators); assertThat(lastSampling, equalTo(null)); } @Test public void test_getLastRollupDataPoint() throws ParseException, DatastoreException { long now = dateFormat.parse("2013-Jan-18 4:59:12.22").getTime(); String metricName = "foo"; ImmutableSortedMap<String, String> localHostTags = ImmutableSortedMap.of("host", "localhost"); List<DataPoint> localhostDataPoints = new ArrayList<DataPoint>(); localhostDataPoints.add(new DoubleDataPoint(lastTimeStamp + 1, 10)); localhostDataPoints.add(new DoubleDataPoint(lastTimeStamp + 2, 11)); localhostDataPoints.add(new DoubleDataPoint(lastTimeStamp + 3, 12)); localhostDataPoints.add(new DoubleDataPoint(lastTimeStamp + 4, 13)); localhostDataPoints.add(new DoubleDataPoint(lastTimeStamp + 5, 14)); ImmutableSortedMap<String, String> remoteTags = ImmutableSortedMap.of("host", "remote"); List<DataPoint> remoteDataPoints = new ArrayList<DataPoint>(); remoteDataPoints.add(new DoubleDataPoint(lastTimeStamp + 1, 10)); remoteDataPoints.add(new DoubleDataPoint(lastTimeStamp + 2, 11)); testDataStore.clear(); testDataStore.putDataPoints(metricName, localHostTags, localhostDataPoints); testDataStore.putDataPoints(metricName, remoteTags, remoteDataPoints); DataPoint lastDataPoint = RollUpJob.getLastRollupDataPoint(datastore, metricName, now); // Look back from now and find last data point [4] assertThat(lastDataPoint, equalTo(localhostDataPoints.get(4))); } @Test public void test_getLastRollupDataPoint_noDataPoints() throws ParseException, DatastoreException { long now = dateFormat.parse("2013-Jan-18 4:59:12.22").getTime(); String metricName = "foo"; testDataStore.clear(); DataPoint lastDataPoint = RollUpJob.getLastRollupDataPoint(datastore, metricName, now); assertThat(lastDataPoint, equalTo(null)); } @Test public void test_getgetFutureDataPoint() throws ParseException, DatastoreException { long now = dateFormat.parse("2013-Jan-18 4:59:12.22").getTime(); String metricName = "foo"; ImmutableSortedMap<String, String> localHostTags = ImmutableSortedMap.of("host", "localhost"); List<DataPoint> localhostDataPoints = new ArrayList<DataPoint>(); localhostDataPoints.add(new DoubleDataPoint(lastTimeStamp + 1, 10)); localhostDataPoints.add(new DoubleDataPoint(lastTimeStamp + 2, 11)); localhostDataPoints.add(new DoubleDataPoint(lastTimeStamp + 3, 12)); localhostDataPoints.add(new DoubleDataPoint(lastTimeStamp + 4, 13)); localhostDataPoints.add(new DoubleDataPoint(lastTimeStamp + 5, 14)); ImmutableSortedMap<String, String> remoteTags = ImmutableSortedMap.of("host", "remote"); List<DataPoint> remoteDataPoints = new ArrayList<DataPoint>(); remoteDataPoints.add(new DoubleDataPoint(lastTimeStamp + 1, 10)); remoteDataPoints.add(new DoubleDataPoint(lastTimeStamp + 2, 11)); testDataStore.clear(); testDataStore.putDataPoints(metricName, localHostTags, localhostDataPoints); testDataStore.putDataPoints(metricName, remoteTags, remoteDataPoints); // Look from data point [1] forward and return [2] DataPoint futureDataPoint = RollUpJob.getFutureDataPoint(datastore, metricName, now, localhostDataPoints.get(1)); assertThat(futureDataPoint, equalTo(localhostDataPoints.get(2))); } @Test public void test_calculatStartTime_datapointTime() { Sampling sampling = new Sampling(); DoubleDataPoint dataPoint = new DoubleDataPoint(123456L, 10); long time = RollUpJob.calculateStartTime(dataPoint, sampling, System.currentTimeMillis()); assertThat(time, equalTo(123456L)); } @Test public void test_calculatStartTime_samplingTime() throws ParseException { long now = dateFormat.parse("2013-Jan-18 4:59:12.22").getTime(); Sampling sampling = new Sampling(1, TimeUnit.HOURS); long time = RollUpJob.calculateStartTime(null, sampling, now); assertThat(time, equalTo(dateFormat.parse("2013-Jan-18 3:59:12.22").getTime())); } @Test(expected = NullPointerException.class) public void test_calculatStartTime_samplingNull_invalid() { DoubleDataPoint dataPoint = new DoubleDataPoint(123456L, 10); RollUpJob.calculateStartTime(dataPoint, null, System.currentTimeMillis()); } @Test public void test_calculatEndTime_datapoint_null() { long now = System.currentTimeMillis(); Duration executionInterval = new Duration(); long time = RollUpJob.calculateEndTime(null, executionInterval, now); assertThat(time, equalTo(now)); } @Test public void test_calculatEndTime_datapointNotNull_recentTime() throws ParseException { long now = System.currentTimeMillis(); Duration executionInterval = new Duration(); DoubleDataPoint dataPoint = new DoubleDataPoint(now - 2000, 10); long time = RollUpJob.calculateEndTime(dataPoint, executionInterval, now); assertThat(time, equalTo(dataPoint.getTimestamp())); } @Test public void test_calculatEndTime_datapointNotNull_tooOld() throws ParseException { long datapointTime = dateFormat.parse("2013-Jan-18 4:59:12.22").getTime(); long now = System.currentTimeMillis(); Duration executionInterval = new Duration(1, TimeUnit.DAYS); DoubleDataPoint dataPoint = new DoubleDataPoint(datapointTime, 10); long time = RollUpJob.calculateEndTime(dataPoint, executionInterval, now); assertThat(time, equalTo(dateFormat.parse("2013-Jan-22 4:59:12.22").getTime())); } public static class TestDatastore implements Datastore { List<ListDataPointGroup> dataPointGroups = new ArrayList<ListDataPointGroup>(); public void clear() { dataPointGroups = new ArrayList<ListDataPointGroup>(); } @Override public void close() throws InterruptedException, DatastoreException { } public void putDataPoints(String metricName, ImmutableSortedMap<String, String> tags, List<DataPoint> dataPoints) throws DatastoreException { ListDataPointGroup dataPointGroup = new ListDataPointGroup(metricName); for (Map.Entry<String, String> tag : tags.entrySet()) { dataPointGroup.addTag(tag.getKey(), tag.getValue()); } for (DataPoint dataPoint : dataPoints) { dataPointGroup.addDataPoint(dataPoint); } dataPointGroups.add(dataPointGroup); } @Override public void putDataPoint(String metricName, ImmutableSortedMap<String, String> tags, DataPoint dataPoint, int ttl) throws DatastoreException { ListDataPointGroup dataPointGroup = new ListDataPointGroup(metricName); dataPointGroup.addDataPoint(dataPoint); for (Map.Entry<String, String> tag : tags.entrySet()) { dataPointGroup.addTag(tag.getKey(), tag.getValue()); } dataPointGroups.add(dataPointGroup); } @Override public Iterable<String> getMetricNames() throws DatastoreException { throw new UnsupportedOperationException(); } @Override public Iterable<String> getTagNames() throws DatastoreException { throw new UnsupportedOperationException(); } @Override public Iterable<String> getTagValues() throws DatastoreException { throw new UnsupportedOperationException(); } @Override public void queryDatabase(DatastoreMetricQuery query, QueryCallback queryCallback) throws DatastoreException { for (ListDataPointGroup dataPointGroup : dataPointGroups) { try { dataPointGroup.sort(query.getOrder()); Map<String, String> tags = new HashMap<String, String>(); for (String tagName : dataPointGroup.getTagNames()) { tags.put(tagName, dataPointGroup.getTagValues(tagName).iterator().next()); } DataPoint dataPoint = getNext(dataPointGroup, query); if (dataPoint != null) { queryCallback.startDataPointSet(dataPoint.getDataStoreDataType(), tags); queryCallback.addDataPoint(dataPoint); while (dataPointGroup.hasNext()) { DataPoint next = getNext(dataPointGroup, query); if (next != null) { queryCallback.addDataPoint(next); } } queryCallback.endDataPoints(); } } catch (IOException e) { throw new DatastoreException(e); } } } private DataPoint getNext(DataPointGroup group, DatastoreMetricQuery query) { DataPoint dataPoint = null; while (group.hasNext()) { DataPoint dp = group.next(); if (dp.getTimestamp() >= query.getStartTime()) { dataPoint = dp; break; } } return dataPoint; } @Override public void deleteDataPoints(DatastoreMetricQuery deleteQuery) throws DatastoreException { throw new UnsupportedOperationException(); } @Override public TagSet queryMetricTags(DatastoreMetricQuery query) throws DatastoreException { throw new UnsupportedOperationException(); } } }