// This file is part of OpenTSDB. // Copyright (C) 2014 The OpenTSDB Authors. // // This program 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 2.1 of the License, or (at your // option) any later version. This program 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 this program. If not, // see <http://www.gnu.org/licenses/>. package net.opentsdb.core; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import java.util.Calendar; import java.util.List; import java.util.TimeZone; import com.google.common.collect.Lists; import net.opentsdb.core.SeekableViewsForTest.MockSeekableView; import net.opentsdb.utils.DateTime; import org.junit.Before; import org.junit.Test; /** Tests {@link Downsampler}. */ public class TestDownsampler { private static final long BASE_TIME = 1356998400000L; private static final DataPoint[] DATA_POINTS = new DataPoint[] { // timestamp = 1,356,998,400,000 ms MutableDataPoint.ofLongValue(BASE_TIME, 40), // timestamp = 1,357,000,400,000 ms MutableDataPoint.ofLongValue(BASE_TIME + 2000000, 50), // timestamp = 1,357,002,000,000 ms MutableDataPoint.ofLongValue(BASE_TIME + 3600000, 40), // timestamp = 1,357,002,005,000 ms MutableDataPoint.ofLongValue(BASE_TIME + 3605000, 50), // timestamp = 1,357,005,600,000 ms MutableDataPoint.ofLongValue(BASE_TIME + 7200000, 40), // timestamp = 1,357,007,600,000 ms MutableDataPoint.ofLongValue(BASE_TIME + 9200000, 50) }; private static final int THOUSAND_SEC_INTERVAL = (int)DateTime.parseDuration("1000s"); private static final int TEN_SEC_INTERVAL = (int)DateTime.parseDuration("10s"); private static final Aggregator AVG = Aggregators.get("avg"); private static final Aggregator SUM = Aggregators.get("sum"); private static final TimeZone EST_TIME_ZONE = DateTime.timezones.get("EST"); //30 minute offset final static TimeZone AF = DateTime.timezones.get("Asia/Kabul"); // 12h offset w/o DST final static TimeZone TV = DateTime.timezones.get("Pacific/Funafuti"); // 12h offset w DST final static TimeZone FJ = DateTime.timezones.get("Pacific/Fiji"); // Tue, 15 Dec 2015 04:02:25.123 UTC final static long DST_TS = 1450137600000L; private SeekableView source; private Downsampler downsampler; private DownsamplingSpecification specification; @Before public void before() { source = spy(SeekableViewsForTest.fromArray(DATA_POINTS)); } @Test public void testDownsampler() { specification = new DownsamplingSpecification("1000s-avg"); downsampler = new Downsampler(source, specification, 0, Long.MAX_VALUE); verify(source, never()).next(); List<Double> values = Lists.newArrayList(); List<Long> timestamps_in_millis = Lists.newArrayList(); while (downsampler.hasNext()) { DataPoint dp = downsampler.next(); assertFalse(dp.isInteger()); values.add(dp.doubleValue()); timestamps_in_millis.add(dp.timestamp()); } assertEquals(5, values.size()); assertEquals(40, values.get(0), 0.0000001); assertEquals(BASE_TIME - 400000L, timestamps_in_millis.get(0).longValue()); assertEquals(50, values.get(1), 0.0000001); assertEquals(BASE_TIME + 1600000, timestamps_in_millis.get(1).longValue()); assertEquals(45, values.get(2), 0.0000001); assertEquals(BASE_TIME + 3600000L, timestamps_in_millis.get(2).longValue()); assertEquals(40, values.get(3), 0.0000001); assertEquals(BASE_TIME + 6600000L, timestamps_in_millis.get(3).longValue()); assertEquals(50, values.get(4), 0.0000001); assertEquals(BASE_TIME + 8600000L, timestamps_in_millis.get(4).longValue()); } @Test public void testDownsamplerDeprecated_10seconds() { source = spy(SeekableViewsForTest.fromArray(new DataPoint[] { MutableDataPoint.ofDoubleValue(BASE_TIME + 5000L * 0, 1), MutableDataPoint.ofDoubleValue(BASE_TIME + 5000L * 1, 2), MutableDataPoint.ofDoubleValue(BASE_TIME + 5000L * 2, 4), MutableDataPoint.ofDoubleValue(BASE_TIME + 5000L * 3, 8), MutableDataPoint.ofDoubleValue(BASE_TIME + 5000L * 4, 16), MutableDataPoint.ofDoubleValue(BASE_TIME + 5000L * 5, 32), MutableDataPoint.ofDoubleValue(BASE_TIME + 5000L * 6, 64), MutableDataPoint.ofDoubleValue(BASE_TIME + 5000L * 7, 128), MutableDataPoint.ofDoubleValue(BASE_TIME + 5000L * 8, 256), MutableDataPoint.ofDoubleValue(BASE_TIME + 5000L * 9, 512), MutableDataPoint.ofDoubleValue(BASE_TIME + 5000L * 10, 1024) })); downsampler = new Downsampler(source, 10000, SUM); verify(source, never()).next(); List<Double> values = Lists.newArrayList(); List<Long> timestamps_in_millis = Lists.newArrayList(); while (downsampler.hasNext()) { DataPoint dp = downsampler.next(); assertFalse(dp.isInteger()); values.add(dp.doubleValue()); timestamps_in_millis.add(dp.timestamp()); } assertEquals(6, values.size()); assertEquals(3, values.get(0), 0.0000001); assertEquals(BASE_TIME + 00000L, timestamps_in_millis.get(0).longValue()); assertEquals(12, values.get(1), 0.0000001); assertEquals(BASE_TIME + 10000L, timestamps_in_millis.get(1).longValue()); assertEquals(48, values.get(2), 0.0000001); assertEquals(BASE_TIME + 20000L, timestamps_in_millis.get(2).longValue()); assertEquals(192, values.get(3), 0.0000001); assertEquals(BASE_TIME + 30000L, timestamps_in_millis.get(3).longValue()); assertEquals(768, values.get(4), 0.0000001); assertEquals(BASE_TIME + 40000L, timestamps_in_millis.get(4).longValue()); assertEquals(1024, values.get(5), 0.0000001); assertEquals(BASE_TIME + 50000L, timestamps_in_millis.get(5).longValue()); } @Test public void testDownsampler_10seconds() { source = spy(SeekableViewsForTest.fromArray(new DataPoint[] { MutableDataPoint.ofDoubleValue(BASE_TIME + 5000L * 0, 1), MutableDataPoint.ofDoubleValue(BASE_TIME + 5000L * 1, 2), MutableDataPoint.ofDoubleValue(BASE_TIME + 5000L * 2, 4), MutableDataPoint.ofDoubleValue(BASE_TIME + 5000L * 3, 8), MutableDataPoint.ofDoubleValue(BASE_TIME + 5000L * 4, 16), MutableDataPoint.ofDoubleValue(BASE_TIME + 5000L * 5, 32), MutableDataPoint.ofDoubleValue(BASE_TIME + 5000L * 6, 64), MutableDataPoint.ofDoubleValue(BASE_TIME + 5000L * 7, 128), MutableDataPoint.ofDoubleValue(BASE_TIME + 5000L * 8, 256), MutableDataPoint.ofDoubleValue(BASE_TIME + 5000L * 9, 512), MutableDataPoint.ofDoubleValue(BASE_TIME + 5000L * 10, 1024) })); specification = new DownsamplingSpecification("10s-sum"); downsampler = new Downsampler(source, specification, 0, Long.MAX_VALUE); verify(source, never()).next(); List<Double> values = Lists.newArrayList(); List<Long> timestamps_in_millis = Lists.newArrayList(); while (downsampler.hasNext()) { DataPoint dp = downsampler.next(); assertFalse(dp.isInteger()); values.add(dp.doubleValue()); timestamps_in_millis.add(dp.timestamp()); } assertEquals(6, values.size()); assertEquals(3, values.get(0), 0.0000001); assertEquals(BASE_TIME + 00000L, timestamps_in_millis.get(0).longValue()); assertEquals(12, values.get(1), 0.0000001); assertEquals(BASE_TIME + 10000L, timestamps_in_millis.get(1).longValue()); assertEquals(48, values.get(2), 0.0000001); assertEquals(BASE_TIME + 20000L, timestamps_in_millis.get(2).longValue()); assertEquals(192, values.get(3), 0.0000001); assertEquals(BASE_TIME + 30000L, timestamps_in_millis.get(3).longValue()); assertEquals(768, values.get(4), 0.0000001); assertEquals(BASE_TIME + 40000L, timestamps_in_millis.get(4).longValue()); assertEquals(1024, values.get(5), 0.0000001); assertEquals(BASE_TIME + 50000L, timestamps_in_millis.get(5).longValue()); } @Test public void testDownsamplerDeprecated_15seconds() { source = spy(SeekableViewsForTest.fromArray(new DataPoint[] { MutableDataPoint.ofLongValue(BASE_TIME + 5000L, 1), MutableDataPoint.ofLongValue(BASE_TIME + 15000L, 2), MutableDataPoint.ofLongValue(BASE_TIME + 25000L, 4), MutableDataPoint.ofLongValue(BASE_TIME + 35000L, 8), MutableDataPoint.ofLongValue(BASE_TIME + 45000L, 16), MutableDataPoint.ofLongValue(BASE_TIME + 55000L, 32) })); downsampler = new Downsampler(source, 15000, SUM); verify(source, never()).next(); List<Double> values = Lists.newArrayList(); List<Long> timestamps_in_millis = Lists.newArrayList(); while (downsampler.hasNext()) { DataPoint dp = downsampler.next(); assertFalse(dp.isInteger()); values.add(dp.doubleValue()); timestamps_in_millis.add(dp.timestamp()); } assertEquals(4, values.size()); assertEquals(1, values.get(0), 0.0000001); assertEquals(BASE_TIME + 00000L, timestamps_in_millis.get(0).longValue()); assertEquals(6, values.get(1), 0.0000001); assertEquals(BASE_TIME + 15000L, timestamps_in_millis.get(1).longValue()); assertEquals(8, values.get(2), 0.0000001); assertEquals(BASE_TIME + 30000L, timestamps_in_millis.get(2).longValue()); assertEquals(48, values.get(3), 0.0000001); assertEquals(BASE_TIME + 45000L, timestamps_in_millis.get(3).longValue()); } @Test public void testDownsampler_15seconds() { source = spy(SeekableViewsForTest.fromArray(new DataPoint[] { MutableDataPoint.ofLongValue(BASE_TIME + 5000L, 1), MutableDataPoint.ofLongValue(BASE_TIME + 15000L, 2), MutableDataPoint.ofLongValue(BASE_TIME + 25000L, 4), MutableDataPoint.ofLongValue(BASE_TIME + 35000L, 8), MutableDataPoint.ofLongValue(BASE_TIME + 45000L, 16), MutableDataPoint.ofLongValue(BASE_TIME + 55000L, 32) })); specification = new DownsamplingSpecification("15s-sum"); downsampler = new Downsampler(source, specification, 0, Long.MAX_VALUE); verify(source, never()).next(); List<Double> values = Lists.newArrayList(); List<Long> timestamps_in_millis = Lists.newArrayList(); while (downsampler.hasNext()) { DataPoint dp = downsampler.next(); assertFalse(dp.isInteger()); values.add(dp.doubleValue()); timestamps_in_millis.add(dp.timestamp()); } assertEquals(4, values.size()); assertEquals(1, values.get(0), 0.0000001); assertEquals(BASE_TIME + 00000L, timestamps_in_millis.get(0).longValue()); assertEquals(6, values.get(1), 0.0000001); assertEquals(BASE_TIME + 15000L, timestamps_in_millis.get(1).longValue()); assertEquals(8, values.get(2), 0.0000001); assertEquals(BASE_TIME + 30000L, timestamps_in_millis.get(2).longValue()); assertEquals(48, values.get(3), 0.0000001); assertEquals(BASE_TIME + 45000L, timestamps_in_millis.get(3).longValue()); } @Test public void testDownsampler_allFullRange() { source = spy(SeekableViewsForTest.fromArray(new DataPoint[] { MutableDataPoint.ofLongValue(BASE_TIME + 5000L, 1), MutableDataPoint.ofLongValue(BASE_TIME + 15000L, 2), MutableDataPoint.ofLongValue(BASE_TIME + 25000L, 4), MutableDataPoint.ofLongValue(BASE_TIME + 35000L, 8), MutableDataPoint.ofLongValue(BASE_TIME + 45000L, 16), MutableDataPoint.ofLongValue(BASE_TIME + 55000L, 32) })); specification = new DownsamplingSpecification("0all-sum"); downsampler = new Downsampler(source, specification, 0, Long.MAX_VALUE); verify(source, never()).next(); List<Double> values = Lists.newArrayList(); List<Long> timestamps_in_millis = Lists.newArrayList(); while (downsampler.hasNext()) { DataPoint dp = downsampler.next(); assertFalse(dp.isInteger()); values.add(dp.doubleValue()); timestamps_in_millis.add(dp.timestamp()); } assertEquals(1, values.size()); assertEquals(63, values.get(0), 0.0000001); assertEquals(0L, timestamps_in_millis.get(0).longValue()); } @Test public void testDownsampler_allFilterOnQuery() { source = spy(SeekableViewsForTest.fromArray(new DataPoint[] { MutableDataPoint.ofLongValue(BASE_TIME + 5000L, 1), MutableDataPoint.ofLongValue(BASE_TIME + 15000L, 2), MutableDataPoint.ofLongValue(BASE_TIME + 25000L, 4), MutableDataPoint.ofLongValue(BASE_TIME + 35000L, 8), MutableDataPoint.ofLongValue(BASE_TIME + 45000L, 16), MutableDataPoint.ofLongValue(BASE_TIME + 55000L, 32) })); specification = new DownsamplingSpecification("0all-sum"); downsampler = new Downsampler(source, specification, BASE_TIME + 15000L, BASE_TIME + 45000L); verify(source, never()).next(); List<Double> values = Lists.newArrayList(); List<Long> timestamps_in_millis = Lists.newArrayList(); while (downsampler.hasNext()) { DataPoint dp = downsampler.next(); assertFalse(dp.isInteger()); values.add(dp.doubleValue()); timestamps_in_millis.add(dp.timestamp()); } assertEquals(1, values.size()); assertEquals(14, values.get(0), 0.0000001); assertEquals(BASE_TIME + 15000L, timestamps_in_millis.get(0).longValue()); } @Test public void testDownsampler_allFilterOnQueryOutOfRangeEarly() { source = spy(SeekableViewsForTest.fromArray(new DataPoint[] { MutableDataPoint.ofLongValue(BASE_TIME + 5000L, 1), MutableDataPoint.ofLongValue(BASE_TIME + 15000L, 2), MutableDataPoint.ofLongValue(BASE_TIME + 25000L, 4), MutableDataPoint.ofLongValue(BASE_TIME + 35000L, 8), MutableDataPoint.ofLongValue(BASE_TIME + 45000L, 16), MutableDataPoint.ofLongValue(BASE_TIME + 55000L, 32) })); specification = new DownsamplingSpecification("0all-sum"); downsampler = new Downsampler(source, specification, BASE_TIME + 65000L, BASE_TIME + 75000L); verify(source, never()).next(); List<Double> values = Lists.newArrayList(); List<Long> timestamps_in_millis = Lists.newArrayList(); while (downsampler.hasNext()) { DataPoint dp = downsampler.next(); assertFalse(dp.isInteger()); values.add(dp.doubleValue()); timestamps_in_millis.add(dp.timestamp()); } assertEquals(0, values.size()); } @Test public void testDownsampler_allFilterOnQueryOutOfRangeLate() { source = spy(SeekableViewsForTest.fromArray(new DataPoint[] { MutableDataPoint.ofLongValue(BASE_TIME + 5000L, 1), MutableDataPoint.ofLongValue(BASE_TIME + 15000L, 2), MutableDataPoint.ofLongValue(BASE_TIME + 25000L, 4), MutableDataPoint.ofLongValue(BASE_TIME + 35000L, 8), MutableDataPoint.ofLongValue(BASE_TIME + 45000L, 16), MutableDataPoint.ofLongValue(BASE_TIME + 55000L, 32) })); specification = new DownsamplingSpecification("0all-sum"); downsampler = new Downsampler(source, specification, BASE_TIME - 15000L, BASE_TIME - 5000L); verify(source, never()).next(); List<Double> values = Lists.newArrayList(); List<Long> timestamps_in_millis = Lists.newArrayList(); while (downsampler.hasNext()) { DataPoint dp = downsampler.next(); assertFalse(dp.isInteger()); values.add(dp.doubleValue()); timestamps_in_millis.add(dp.timestamp()); } assertEquals(0, values.size()); } @Test public void testDownsampler_calendar() { source = spy(SeekableViewsForTest.fromArray(new DataPoint[] { MutableDataPoint.ofLongValue(BASE_TIME + 5000L, 1), MutableDataPoint.ofLongValue(BASE_TIME + 15000L, 2), MutableDataPoint.ofLongValue(BASE_TIME + 25000L, 4), MutableDataPoint.ofLongValue(BASE_TIME + 35000L, 8), MutableDataPoint.ofLongValue(BASE_TIME + 45000L, 16), MutableDataPoint.ofLongValue(BASE_TIME + 55000L, 32) })); specification = new DownsamplingSpecification("1dc-sum"); specification.setTimezone(DateTime.timezones.get("America/Denver")); downsampler = new Downsampler(source, specification, 0, Long.MAX_VALUE); verify(source, never()).next(); List<Double> values = Lists.newArrayList(); List<Long> timestamps_in_millis = Lists.newArrayList(); while (downsampler.hasNext()) { DataPoint dp = downsampler.next(); assertFalse(dp.isInteger()); values.add(dp.doubleValue()); timestamps_in_millis.add(dp.timestamp()); } assertEquals(1, values.size()); assertEquals(63, values.get(0), 0.0000001); assertEquals(1356937200000L, timestamps_in_millis.get(0).longValue()); } @Test public void testDownsampler_calendarHour() { source = spy(SeekableViewsForTest.fromArray(new DataPoint[] { MutableDataPoint.ofLongValue(BASE_TIME, 1), MutableDataPoint.ofLongValue(BASE_TIME + 1800000, 2), MutableDataPoint.ofLongValue(BASE_TIME + 3599000L, 3), MutableDataPoint.ofLongValue(BASE_TIME + 3600000L, 4), MutableDataPoint.ofLongValue(BASE_TIME + 5400000L, 5), MutableDataPoint.ofLongValue(BASE_TIME + 7199000L, 6) })); specification = new DownsamplingSpecification("1hc-sum"); specification.setTimezone(TV); downsampler = new Downsampler(source, specification, 0, Long.MAX_VALUE); long ts = BASE_TIME; double value = 6; while (downsampler.hasNext()) { DataPoint dp = downsampler.next(); assertFalse(dp.isInteger()); assertEquals(ts, dp.timestamp()); assertEquals(value, dp.doubleValue(), 0.001); ts += 3600000; value = 15; } // hour offset by 30m ((MockSeekableView)source).resetIndex(); specification = new DownsamplingSpecification("1hc-sum"); specification.setTimezone(AF); downsampler = new Downsampler(source, specification, 0, Long.MAX_VALUE); ts = 1356996600000L; value = 1; while (downsampler.hasNext()) { DataPoint dp = downsampler.next(); assertFalse(dp.isInteger()); assertEquals(ts, dp.timestamp()); assertEquals(value, dp.doubleValue(), 0.001); ts += 3600000; if (value == 1) { value = 9; } else { value = 11; } } // multiple hours ((MockSeekableView)source).resetIndex(); specification = new DownsamplingSpecification("4hc-sum"); specification.setTimezone(AF); downsampler = new Downsampler(source, specification, 0, Long.MAX_VALUE); ts = 1356996600000L; value = 21; while (downsampler.hasNext()) { DataPoint dp = downsampler.next(); assertFalse(dp.isInteger()); assertEquals(ts, dp.timestamp()); assertEquals(value, dp.doubleValue(), 0.001); } } @Test public void testDownsampler_calendarDay() { source = spy(SeekableViewsForTest.fromArray(new DataPoint[] { MutableDataPoint.ofLongValue(DST_TS, 1), MutableDataPoint.ofLongValue(DST_TS + 86399000, 2), MutableDataPoint.ofLongValue(DST_TS + 126001000L, 3), // falls to the next in FJ MutableDataPoint.ofLongValue(DST_TS + 172799000L, 4), MutableDataPoint.ofLongValue(DST_TS + 172800000L, 5), MutableDataPoint.ofLongValue(DST_TS + 242999000L, 6) // falls within 30m offset })); // control specification = new DownsamplingSpecification("1dc-sum"); downsampler = new Downsampler(source, specification, 0, Long.MAX_VALUE); long ts = DST_TS; double value = 3; while (downsampler.hasNext()) { DataPoint dp = downsampler.next(); assertFalse(dp.isInteger()); assertEquals(ts, dp.timestamp()); assertEquals(value, dp.doubleValue(), 0.001); ts += 86400000; if (value == 3) { value = 7; } else if (value == 7) { value = 11; } } // 12 hour offset from UTC ((MockSeekableView)source).resetIndex(); specification = new DownsamplingSpecification("1dc-sum"); specification.setTimezone(TV); downsampler = new Downsampler(source, specification, 0, Long.MAX_VALUE); ts = 1450094400000L; value = 1; while (downsampler.hasNext()) { DataPoint dp = downsampler.next(); assertFalse(dp.isInteger()); assertEquals(ts, dp.timestamp()); assertEquals(value, dp.doubleValue(), 0.001); ts += 86400000; if (value == 1) { value = 5; } else if (value == 5) { value = 9; } else { value = 6; } } // 11 hour offset from UTC ((MockSeekableView)source).resetIndex(); specification = new DownsamplingSpecification("1dc-sum"); specification.setTimezone(FJ); downsampler = new Downsampler(source, specification, 0, Long.MAX_VALUE); ts = 1450090800000L; value = 1; while (downsampler.hasNext()) { DataPoint dp = downsampler.next(); assertFalse(dp.isInteger()); assertEquals(ts, dp.timestamp()); assertEquals(value, dp.doubleValue(), 0.001); ts += 86400000; if (value == 1) { value = 2; } else if (value == 2) { value = 12; } else { value = 6; } } // 30m offset ((MockSeekableView)source).resetIndex(); specification = new DownsamplingSpecification("1dc-sum"); specification.setTimezone(AF); downsampler = new Downsampler(source, specification, 0, Long.MAX_VALUE); ts = 1450121400000L; value = 1; while (downsampler.hasNext()) { DataPoint dp = downsampler.next(); assertFalse(dp.isInteger()); assertEquals(ts, dp.timestamp()); assertEquals(value, dp.doubleValue(), 0.001); ts += 86400000; if (value == 1) { value = 5; } else if (value == 5) { value = 15; } } // multiple days ((MockSeekableView)source).resetIndex(); specification = new DownsamplingSpecification("3dc-sum"); specification.setTimezone(AF); downsampler = new Downsampler(source, specification, 0, Long.MAX_VALUE); ts = 1450121400000L; value = 21; while (downsampler.hasNext()) { DataPoint dp = downsampler.next(); assertFalse(dp.isInteger()); assertEquals(ts, dp.timestamp()); assertEquals(value, dp.doubleValue(), 0.001); } } @Test public void testDownsampler_calendarWeek() { source = SeekableViewsForTest.fromArray(new DataPoint[] { MutableDataPoint.ofLongValue(DST_TS, 1), // a Tuesday in UTC land MutableDataPoint.ofLongValue(DST_TS + (86400000L * 7), 2), MutableDataPoint.ofLongValue(1451129400000L, 3), // falls to the next in FJ MutableDataPoint.ofLongValue(DST_TS + (86400000L * 21), 4), MutableDataPoint.ofLongValue(1452367799000L, 5) // falls within 30m offset }); // control specification = new DownsamplingSpecification("1wc-sum"); downsampler = new Downsampler(source, specification, 0, Long.MAX_VALUE); long ts = 1449964800000L; double value = 1; while (downsampler.hasNext()) { DataPoint dp = downsampler.next(); assertFalse(dp.isInteger()); assertEquals(ts, dp.timestamp()); assertEquals(value, dp.doubleValue(), 0.001); if (ts == 1450569600000L) { ts = 1451779200000L; // skips a week } else { ts += 86400000L * 7; } if (value == 1) { value = 5; } else { value = 9; } } // 12 hour offset from UTC ((MockSeekableView)source).resetIndex(); specification = new DownsamplingSpecification("1wc-sum"); specification.setTimezone(TV); downsampler = new Downsampler(source, specification, 0, Long.MAX_VALUE); ts = 1449921600000L; value = 1; while (downsampler.hasNext()) { DataPoint dp = downsampler.next(); assertFalse(dp.isInteger()); assertEquals(ts, dp.timestamp()); assertEquals(value, dp.doubleValue(), 0.001); if (ts == 1450526400000L) { ts = 1451736000000L; // skip a week } else { ts += 86400000L * 7; } if (value == 1) { value = 5; } else if (value == 5) { value = 4; } else { value = 5; } } // 11 hour offset from UTC ((MockSeekableView)source).resetIndex(); specification = new DownsamplingSpecification("1wc-sum"); specification.setTimezone(FJ); downsampler = new Downsampler(source, specification, 0, Long.MAX_VALUE); ts = 1449918000000L; value = 1; while (downsampler.hasNext()) { DataPoint dp = downsampler.next(); assertFalse(dp.isInteger()); assertEquals(ts, dp.timestamp()); assertEquals(value, dp.doubleValue(), 0.001); ts += 86400000L * 7; value++; } // 30m offset ((MockSeekableView)source).resetIndex(); specification = new DownsamplingSpecification("1wc-sum"); specification.setTimezone(AF); downsampler = new Downsampler(source, specification, 0, Long.MAX_VALUE); ts = 1449948600000L; value = 1; while (downsampler.hasNext()) { DataPoint dp = downsampler.next(); assertFalse(dp.isInteger()); assertEquals(ts, dp.timestamp()); assertEquals(value, dp.doubleValue(), 0.001); if (ts == 1449948600000L) { ts = 1450553400000L; } else { ts = 1451763000000L; } if (value == 1) { value = 5; } else { value = 9; } } // multiple weeks ((MockSeekableView)source).resetIndex(); specification = new DownsamplingSpecification("2wc-sum"); specification.setTimezone(AF); downsampler = new Downsampler(source, specification, 0, Long.MAX_VALUE); ts = 1449948600000L; value = 6; while (downsampler.hasNext()) { DataPoint dp = downsampler.next(); assertFalse(dp.isInteger()); assertEquals(ts, dp.timestamp()); assertEquals(value, dp.doubleValue(), 0.001); ts = 1451158200000L; value = 9; } } @Test public void testDownsampler_calendarMonth() { final long dec_1st = 1448928000000L; source = spy(SeekableViewsForTest.fromArray(new DataPoint[] { MutableDataPoint.ofLongValue(dec_1st, 1), MutableDataPoint.ofLongValue(1451559600000L, 2), // falls to the next in FJ MutableDataPoint.ofLongValue(1451606400000L, 3), // jan 1st MutableDataPoint.ofLongValue(1454284800000L, 4), // feb 1st MutableDataPoint.ofLongValue(1456704000000L, 5), // feb 29th (leap year) MutableDataPoint.ofLongValue(1456772400000L, 6) // falls within 30m offset AF })); // control specification = new DownsamplingSpecification("1nc-sum"); downsampler = new Downsampler(source, specification, 0, Long.MAX_VALUE); long ts = dec_1st; double value = 3; while (downsampler.hasNext()) { DataPoint dp = downsampler.next(); assertFalse(dp.isInteger()); assertEquals(ts, dp.timestamp()); assertEquals(value, dp.doubleValue(), 0.001); if (ts == 1448928000000L) { ts = 1451606400000L; } else { ts = 1454284800000L; value = 15; } } // 12h offset ((MockSeekableView)source).resetIndex(); specification = new DownsamplingSpecification("1nc-sum"); specification.setTimezone(TV); downsampler = new Downsampler(source, specification, 0, Long.MAX_VALUE); ts = 1448884800000L; value = 3; while (downsampler.hasNext()) { DataPoint dp = downsampler.next(); assertFalse(dp.isInteger()); assertEquals(ts, dp.timestamp()); assertEquals(value, dp.doubleValue(), 0.001); if (ts == 1448884800000L) { ts = 1451563200000L; } else if (ts == 1451563200000L) { value = 9; ts = 1454241600000L; } else { ts = 1456747200000L; value = 6; } } // 11h offset ((MockSeekableView)source).resetIndex(); specification = new DownsamplingSpecification("1nc-sum"); specification.setTimezone(FJ); downsampler = new Downsampler(source, specification, 0, Long.MAX_VALUE); ts = 1448881200000L; value = 1; while (downsampler.hasNext()) { DataPoint dp = downsampler.next(); assertFalse(dp.isInteger()); assertEquals(ts, dp.timestamp()); if (ts == 1448881200000L) { ts = 1451559600000L; value = 5; } else if (ts == 1451559600000L) { ts = 1454241600000L; value = 9; } else { ts = 1456747200000L; value = 6; } } // 30m offset ((MockSeekableView)source).resetIndex(); specification = new DownsamplingSpecification("1nc-sum"); specification.setTimezone(AF); downsampler = new Downsampler(source, specification, 0, Long.MAX_VALUE); ts = 1448911800000L; value = 3; while (downsampler.hasNext()) { DataPoint dp = downsampler.next(); assertFalse(dp.isInteger()); assertEquals(ts, dp.timestamp()); assertEquals(value, dp.doubleValue(), 0.001); if (ts == 1448911800000L) { ts = 1451590200000L; } else { ts = 1454268600000L; value = 15; } } // multiple months ((MockSeekableView)source).resetIndex(); specification = new DownsamplingSpecification("3nc-sum"); specification.setTimezone(TV); downsampler = new Downsampler(source, specification, 0, Long.MAX_VALUE); ts = 1443614400000L; value = 3; while (downsampler.hasNext()) { DataPoint dp = downsampler.next(); assertFalse(dp.isInteger()); assertEquals(ts, dp.timestamp()); assertEquals(value, dp.doubleValue(), 0.001); ts = 1451563200000L; value = 18; } } @Test public void testDownsampler_noData() { source = spy(SeekableViewsForTest.fromArray(new DataPoint[] { })); specification = new DownsamplingSpecification("1d-sum"); downsampler = new Downsampler(source, specification, 0, Long.MAX_VALUE); verify(source, never()).next(); assertFalse(downsampler.hasNext()); } @Test public void testDownsampler_noDataCalendar() { source = spy(SeekableViewsForTest.fromArray(new DataPoint[] { })); specification = new DownsamplingSpecification("1mc-sum"); downsampler = new Downsampler(source, specification, 0, Long.MAX_VALUE); verify(source, never()).next(); assertFalse(downsampler.hasNext()); } @Test public void testDownsampler_1day() { source = spy(SeekableViewsForTest.fromArray(new DataPoint[] { MutableDataPoint.ofLongValue(BASE_TIME, 1), MutableDataPoint.ofLongValue(BASE_TIME + 43200000L, 2), MutableDataPoint.ofLongValue(BASE_TIME + 86400000L, 4), MutableDataPoint.ofLongValue(BASE_TIME + 129600000L, 8) })); downsampler = new Downsampler(source, 86400000, SUM); verify(source, never()).next(); long timestamp = BASE_TIME; double value = 3; while (downsampler.hasNext()) { DataPoint dp = downsampler.next(); assertFalse(dp.isInteger()); assertEquals(timestamp, dp.timestamp()); assertEquals(value, dp.doubleValue(), 0.000001); timestamp = 1357084800000L; value = 12; } } @Test public void testDownsampler_1day_timezone() { source = spy(SeekableViewsForTest.fromArray(new DataPoint[] { MutableDataPoint.ofLongValue(1357016400000L, 1), MutableDataPoint.ofLongValue(1357059600000L, 2), MutableDataPoint.ofLongValue(1357102800000L, 4), MutableDataPoint.ofLongValue(1357146000000L, 8) })); specification = new DownsamplingSpecification("1dc-sum"); specification.setTimezone(EST_TIME_ZONE); downsampler = new Downsampler(source, specification, 0, Long.MAX_VALUE); verify(source, never()).next(); long timestamp = 1357016400000L; double value = 3; while (downsampler.hasNext()) { DataPoint dp = downsampler.next(); assertFalse(dp.isInteger()); assertEquals(timestamp, dp.timestamp()); assertEquals(value, dp.doubleValue(), 0.000001); timestamp = 1357102800000L; value = 12; } } @Test public void testDownsampler_1week() { source = spy(SeekableViewsForTest.fromArray(new DataPoint[] { MutableDataPoint.ofLongValue(1356825600000L, 1), MutableDataPoint.ofLongValue(1357128000000L, 2), MutableDataPoint.ofLongValue(1357430400000L, 4), MutableDataPoint.ofLongValue(1357732800000L, 8) })); specification = new DownsamplingSpecification("1wc-sum"); downsampler = new Downsampler(source, specification, 0, Long.MAX_VALUE); verify(source, never()).next(); long timestamp = 1356825600000L; double value = 3; while (downsampler.hasNext()) { DataPoint dp = downsampler.next(); assertFalse(dp.isInteger()); assertEquals(timestamp, dp.timestamp()); assertEquals(value, dp.doubleValue(), 0.000001); timestamp = 1357430400000L; value = 12; } } @Test public void testDownsampler_1week_timezone() { source = spy(SeekableViewsForTest.fromArray(new DataPoint[] { MutableDataPoint.ofLongValue(1356843600000L, 1), MutableDataPoint.ofLongValue(1357146000000L, 2), MutableDataPoint.ofLongValue(1357448400000L, 4), MutableDataPoint.ofLongValue(1357750800000L, 8) })); specification = new DownsamplingSpecification("1wc-sum"); specification.setTimezone(EST_TIME_ZONE); downsampler = new Downsampler(source, specification, 0, Long.MAX_VALUE); verify(source, never()).next(); long timestamp = 1356843600000L; double value = 3; while (downsampler.hasNext()) { DataPoint dp = downsampler.next(); assertFalse(dp.isInteger()); assertEquals(timestamp, dp.timestamp()); assertEquals(value, dp.doubleValue(), 0.000001); timestamp = 1357448400000L; value = 12; } } @Test public void testDownsampler_1month() { final int field = DateTime.unitsToCalendarType("n"); final DataPoint [] data_points = new DataPoint[24]; Calendar c = DateTime.previousInterval(BASE_TIME, 1, field); //long timestamp = DateTime.toStartOfMonth(BASE_TIME, UTC_TIME_ZONE); long timestamp = c.getTimeInMillis(); for (int i = 0; i < data_points.length; i++) { long value = 1 << i; data_points[i] = MutableDataPoint.ofLongValue(timestamp, value); i += 1; c.add(field, 1); long startOfNextInterval = c.getTimeInMillis() + 1; timestamp = timestamp + (startOfNextInterval - timestamp) / 2; value = 1 << i; data_points[i] = MutableDataPoint.ofLongValue(timestamp, value); timestamp = startOfNextInterval; } source = spy(SeekableViewsForTest.fromArray(data_points)); specification = new DownsamplingSpecification("1nc-sum"); downsampler = new Downsampler(source, specification, 0, Long.MAX_VALUE); verify(source, never()).next(); c = DateTime.previousInterval(BASE_TIME, 1, field); int j = 0; while (downsampler.hasNext()) { DataPoint dp = downsampler.next(); assertFalse(dp.isInteger()); assertEquals((1 << j++) + (1 << j++), dp.doubleValue(), 0.0000001); assertEquals(c.getTimeInMillis(), dp.timestamp()); c.add(field, 1); } } @Test public void testDownsampler_1month_alt() { /* 1380600000 -> 2013-10-01T04:00:00Z 1383278400 -> 2013-11-01T04:00:00Z 1385874000 -> 2013-12-01T05:00:00Z 1388552400 -> 2014-01-01T05:00:00Z 1391230800 -> 2014-02-01T05:00:00Z 1393650000 -> 2014-03-01T05:00:00Z 1396324800 -> 2014-04-01T04:00:00Z 1398916800 -> 2014-05-01T04:00:00Z 1401595200 -> 2014-06-01T04:00:00Z 1404187200 -> 2014-07-01T04:00:00Z 1406865600 -> 2014-08-01T04:00:00Z 1409544000 -> 2014-09-01T04:00:00Z */ int value = 1; final DataPoint [] data_points = new DataPoint[] { MutableDataPoint.ofLongValue(1380600000000L, value), MutableDataPoint.ofLongValue(1383278400000L, value), MutableDataPoint.ofLongValue(1385874000000L, value), MutableDataPoint.ofLongValue(1388552400000L, value), MutableDataPoint.ofLongValue(1391230800000L, value), MutableDataPoint.ofLongValue(1393650000000L, value), MutableDataPoint.ofLongValue(1396324800000L, value), MutableDataPoint.ofLongValue(1398916800000L, value), MutableDataPoint.ofLongValue(1401595200000L, value), MutableDataPoint.ofLongValue(1404187200000L, value), MutableDataPoint.ofLongValue(1406865600000L, value), MutableDataPoint.ofLongValue(1409544000000L, value), }; source = spy(SeekableViewsForTest.fromArray(data_points)); specification = new DownsamplingSpecification("1dc-sum"); downsampler = new Downsampler(source, specification, 0, Long.MAX_VALUE); verify(source, never()).next(); final int field = DateTime.unitsToCalendarType("n"); final Calendar c = DateTime.previousInterval(1380585600000L, 1, field); long timestamp = c.getTimeInMillis(); while (downsampler.hasNext()) { DataPoint dp = downsampler.next(); assertFalse(dp.isInteger()); assertEquals(1, dp.doubleValue(), 0.0000001); assertEquals(timestamp, dp.timestamp()); c.add(field, 1); timestamp = c.getTimeInMillis(); } } @Test public void testDownsampler_2months() { final int field = DateTime.unitsToCalendarType("n"); final DataPoint [] data_points = new DataPoint[24]; Calendar c = DateTime.previousInterval(BASE_TIME, 1, field); long timestamp = c.getTimeInMillis(); for (int i = 0; i < data_points.length; i++) { long value = 1 << i; data_points[i] = MutableDataPoint.ofLongValue(timestamp, value); i += 1; c.add(field, 1); long startOfNextInterval = c.getTimeInMillis(); timestamp = timestamp + (startOfNextInterval - timestamp) / 2; value = 1 << i; data_points[i] = MutableDataPoint.ofLongValue(timestamp, value); timestamp = startOfNextInterval; } source = spy(SeekableViewsForTest.fromArray(data_points)); specification = new DownsamplingSpecification("2nc-sum"); downsampler = new Downsampler(source, specification, 0, Long.MAX_VALUE); verify(source, never()).next(); int j = 0; c = DateTime.previousInterval(BASE_TIME, 1, field); while (downsampler.hasNext()) { DataPoint dp = downsampler.next(); assertFalse(dp.isInteger()); long value = 0; for (int k = 0; k < 4; k++) { value += (1 << j++); } assertEquals(value, dp.doubleValue(), 0.0000001); assertEquals(c.getTimeInMillis(), dp.timestamp()); c.add(field, 2); } } @Test public void testDownsampler_1month_timezone() { final int field = DateTime.unitsToCalendarType("n"); final DataPoint [] data_points = new DataPoint[24]; Calendar c = DateTime.previousInterval(1357016400000L, 1, field, EST_TIME_ZONE); long timestamp = c.getTimeInMillis(); for (int i = 0; i < data_points.length; i++) { long value = 1 << i; data_points[i] = MutableDataPoint.ofLongValue(timestamp, value); i += 1; c.add(field, 1); long startOfNextInterval = c.getTimeInMillis(); timestamp = timestamp + (startOfNextInterval - timestamp) / 2; value = 1 << i; data_points[i] = MutableDataPoint.ofLongValue(timestamp, value); timestamp = startOfNextInterval; } source = spy(SeekableViewsForTest.fromArray(data_points)); specification = new DownsamplingSpecification("1nc-sum"); specification.setTimezone(EST_TIME_ZONE); downsampler = new Downsampler(source, specification, 0, Long.MAX_VALUE); verify(source, never()).next(); int j = 0; c = DateTime.previousInterval(1357016400000L, 1, field, EST_TIME_ZONE); while (downsampler.hasNext()) { DataPoint dp = downsampler.next(); assertFalse(dp.isInteger()); assertEquals((1 << j++) + (1 << j++), dp.doubleValue(), 0.0000001); assertEquals(c.getTimeInMillis(), dp.timestamp()); c.add(field, 1); } } @Test public void testDownsampler_1year() { final int field = DateTime.unitsToCalendarType("y"); final DataPoint [] data_points = new DataPoint[4]; Calendar c = DateTime.previousInterval(BASE_TIME, 1, field); long timestamp = c.getTimeInMillis(); for (int i = 0; i < data_points.length; i++) { long value = 1 << i; data_points[i] = MutableDataPoint.ofLongValue(timestamp, value); i += 1; c.add(field, 1); long startOfNextInterval = c.getTimeInMillis(); timestamp = timestamp + (startOfNextInterval - timestamp) / 2; value = 1 << i; data_points[i] = MutableDataPoint.ofLongValue(timestamp, value); timestamp = startOfNextInterval; } source = spy(SeekableViewsForTest.fromArray(data_points)); specification = new DownsamplingSpecification("1yc-sum"); downsampler = new Downsampler(source, specification, 0, Long.MAX_VALUE); verify(source, never()).next(); int j = 0; c = DateTime.previousInterval(BASE_TIME, 1, field); while (downsampler.hasNext()) { DataPoint dp = downsampler.next(); assertFalse(dp.isInteger()); assertEquals((1 << j++) + (1 << j++), dp.doubleValue(), 0.0000001); assertEquals(c.getTimeInMillis(), dp.timestamp()); c.add(field, 1); } } @Test public void testDownsampler_1year_timezone() { final int field = DateTime.unitsToCalendarType("y"); final DataPoint [] data_points = new DataPoint[4]; Calendar c = DateTime.previousInterval(1357016400000L, 1, field, EST_TIME_ZONE); long timestamp = c.getTimeInMillis(); for (int i = 0; i < data_points.length; i++) { long value = 1 << i; data_points[i] = MutableDataPoint.ofLongValue(timestamp, value); i += 1; c.add(field, 1); long startOfNextInterval = c.getTimeInMillis(); timestamp = timestamp + (startOfNextInterval - timestamp) / 2; value = 1 << i; data_points[i] = MutableDataPoint.ofLongValue(timestamp, value); timestamp = startOfNextInterval; } source = spy(SeekableViewsForTest.fromArray(data_points)); specification = new DownsamplingSpecification("1yc-sum"); specification.setTimezone(EST_TIME_ZONE); downsampler = new Downsampler(source, specification, 0, Long.MAX_VALUE); verify(source, never()).next(); int j = 0; c = DateTime.previousInterval(1357016400000L, 1, field, EST_TIME_ZONE); while (downsampler.hasNext()) { DataPoint dp = downsampler.next(); assertFalse(dp.isInteger()); assertEquals((1 << j++) + (1 << j++), dp.doubleValue(), 0.0000001); assertEquals(c.getTimeInMillis(), dp.timestamp()); c.add(field, 1); } } @Test(expected = UnsupportedOperationException.class) public void testRemove() { new Downsampler(source, THOUSAND_SEC_INTERVAL, AVG).remove(); } @Test public void testSeek() { downsampler = new Downsampler(source, THOUSAND_SEC_INTERVAL, AVG); downsampler.seek(BASE_TIME + 3600000L); verify(source, never()).next(); List<Double> values = Lists.newArrayList(); List<Long> timestamps_in_millis = Lists.newArrayList(); while (downsampler.hasNext()) { DataPoint dp = downsampler.next(); assertFalse(dp.isInteger()); values.add(dp.doubleValue()); timestamps_in_millis.add(dp.timestamp()); } assertEquals(3, values.size()); assertEquals(45, values.get(0), 0.0000001); assertEquals(BASE_TIME + 3600000L, timestamps_in_millis.get(0).longValue()); assertEquals(40, values.get(1), 0.0000001); assertEquals(BASE_TIME + 6600000L, timestamps_in_millis.get(1).longValue()); assertEquals(50, values.get(2), 0.0000001); assertEquals(BASE_TIME + 8600000L, timestamps_in_millis.get(2).longValue()); } @Test public void testSeek_useCalendar() { source = spy(SeekableViewsForTest.fromArray(new DataPoint[] { MutableDataPoint.ofLongValue(1356998400000L, 1), MutableDataPoint.ofLongValue(1388534400000L, 2), MutableDataPoint.ofLongValue(1420070400000L, 4), MutableDataPoint.ofLongValue(1451606400000L, 8) })); specification = new DownsamplingSpecification("1y-sum"); specification.setUseCalendar(true); downsampler = new Downsampler(source, specification, 0, Long.MAX_VALUE); downsampler.seek(1420070400000L); verify(source, never()).next(); long timestamp = 1420070400000L; double value = 4; while (downsampler.hasNext()) { DataPoint dp = downsampler.next(); assertFalse(dp.isInteger()); assertEquals(timestamp, dp.timestamp()); assertEquals(value, dp.doubleValue(), 0.0000001); timestamp = 1451606400000L; value = 8; } ((MockSeekableView)source).resetIndex(); specification = new DownsamplingSpecification("1yc-sum"); downsampler = new Downsampler(source, specification, 0, Long.MAX_VALUE); downsampler.seek(1420070400001L); while (downsampler.hasNext()) { DataPoint dp = downsampler.next(); assertFalse(dp.isInteger()); assertEquals(timestamp, dp.timestamp()); assertEquals(value, dp.doubleValue(), 0.0000001); } } @Test public void testSeek_skipPartialInterval() { downsampler = new Downsampler(source, THOUSAND_SEC_INTERVAL, AVG); downsampler.seek(BASE_TIME + 3800000L); verify(source, never()).next(); List<Double> values = Lists.newArrayList(); List<Long> timestamps_in_millis = Lists.newArrayList(); while (downsampler.hasNext()) { DataPoint dp = downsampler.next(); assertFalse(dp.isInteger()); values.add(dp.doubleValue()); timestamps_in_millis.add(dp.timestamp()); } // seek timestamp was BASE_TIME + 3800000L or 1,357,002,200,000 ms. // The interval that has the timestamp began at 1,357,002,000,000 ms. It // had two data points but was abandoned because the requested timestamp // was not aligned. The next two intervals at 1,357,003,000,000 and // at 1,357,004,000,000 did not have data points. The first interval that // had a data point began at 1,357,002,005,000 ms or BASE_TIME + 6600000L. assertEquals(2, values.size()); assertEquals(40, values.get(0), 0.0000001); assertEquals(BASE_TIME + 6600000L, timestamps_in_millis.get(0).longValue()); assertEquals(50, values.get(1), 0.0000001); assertEquals(BASE_TIME + 8600000L, timestamps_in_millis.get(1).longValue()); } @Test public void testSeek_doubleIteration() { downsampler = new Downsampler(source, THOUSAND_SEC_INTERVAL, AVG); while (downsampler.hasNext()) { downsampler.next(); } downsampler.seek(BASE_TIME + 3600000L); List<Double> values = Lists.newArrayList(); List<Long> timestamps_in_millis = Lists.newArrayList(); while (downsampler.hasNext()) { DataPoint dp = downsampler.next(); assertFalse(dp.isInteger()); values.add(dp.doubleValue()); timestamps_in_millis.add(dp.timestamp()); } assertEquals(3, values.size()); assertEquals(45, values.get(0), 0.0000001); assertEquals(BASE_TIME + 3600000L, timestamps_in_millis.get(0).longValue()); assertEquals(40, values.get(1), 0.0000001); assertEquals(BASE_TIME + 6600000L, timestamps_in_millis.get(1).longValue()); assertEquals(50, values.get(2), 0.0000001); assertEquals(BASE_TIME + 8600000L, timestamps_in_millis.get(2).longValue()); } @Test public void testSeek_abandoningIncompleteInterval() { source = SeekableViewsForTest.fromArray(new DataPoint[] { MutableDataPoint.ofLongValue(BASE_TIME + 100L, 40), MutableDataPoint.ofLongValue(BASE_TIME + 1100L, 40), MutableDataPoint.ofLongValue(BASE_TIME + 2100L, 40), MutableDataPoint.ofLongValue(BASE_TIME + 3100L, 40), MutableDataPoint.ofLongValue(BASE_TIME + 4100L, 40), MutableDataPoint.ofLongValue(BASE_TIME + 5100L, 40), MutableDataPoint.ofLongValue(BASE_TIME + 6100L, 40), MutableDataPoint.ofLongValue(BASE_TIME + 7100L, 40), MutableDataPoint.ofLongValue(BASE_TIME + 8100L, 40), MutableDataPoint.ofLongValue(BASE_TIME + 9100L, 40), MutableDataPoint.ofLongValue(BASE_TIME + 10100L, 40) }); downsampler = new Downsampler(source, TEN_SEC_INTERVAL, SUM); // The seek is aligned by the downsampling window. downsampler.seek(BASE_TIME); assertTrue("seek(BASE_TIME)", downsampler.hasNext()); DataPoint first_dp = downsampler.next(); assertEquals("seek(1356998400000)", BASE_TIME, first_dp.timestamp()); assertEquals("seek(1356998400000)", 400, first_dp.doubleValue(), 0.0000001); // No seeks but the last one is aligned by the downsampling window. for (long seek_timestamp = BASE_TIME + 1000L; seek_timestamp < BASE_TIME + 10100L; seek_timestamp += 1000) { downsampler.seek(seek_timestamp); assertTrue("ts = " + seek_timestamp, downsampler.hasNext()); DataPoint dp = downsampler.next(); // Timestamp should be greater than or equal to the seek timestamp. assertTrue(String.format("%d >= %d", dp.timestamp(), seek_timestamp), dp.timestamp() >= seek_timestamp); assertEquals(String.format("seek(%d)", seek_timestamp), BASE_TIME + 10000L, dp.timestamp()); assertEquals(String.format("seek(%d)", seek_timestamp), 40, dp.doubleValue(), 0.0000001); } } @Test public void testToString() { downsampler = new Downsampler(source, THOUSAND_SEC_INTERVAL, AVG); DataPoint dp = downsampler.next(); assertTrue(downsampler.toString().contains(dp.toString())); } }