package mil.nga.giat.geowave.core.geotime.index.dimension; import java.util.Calendar; import java.util.TimeZone; import mil.nga.giat.geowave.core.geotime.index.dimension.TemporalBinningStrategy.Unit; import mil.nga.giat.geowave.core.index.dimension.bin.BinRange; import mil.nga.giat.geowave.core.index.sfc.data.NumericRange; import org.junit.Assert; import org.junit.Before; import org.junit.Test; public class TemporalBinningStrategyTest { @Before public void setTimezoneToGMT() { TimeZone.setDefault(TimeZone.getTimeZone("GMT")); } @Test public void testLargeNumberOfDayBins() { internalTestBinsMatchExpectedCount( 250000, Unit.DAY, 123456789876L); } @Test public void testLargeNumberOfMonthBins() { internalTestBinsMatchExpectedCount( 250000, Unit.MONTH, 9876543210L); } @Test public void testLargeNumberOfYearBins() { // for years, use 250,000 to keep milli time values less than max long internalTestBinsMatchExpectedCount( 250000, Unit.YEAR, 0L); } @Test public void testLargeNumberOfHourBins() { internalTestBinsMatchExpectedCount( 250000, Unit.HOUR, 0L); } @Test public void testLargeNumberOfMinuteBins() { internalTestBinsMatchExpectedCount( 250000, Unit.MINUTE, 0L); } private void internalTestBinsMatchExpectedCount( final int binCount, final Unit unit, final long arbitraryTime ) { final BinRange[] ranges = getBinRangesUsingFullExtents( binCount, unit, arbitraryTime); Assert.assertEquals( binCount, ranges.length); } private BinRange[] getBinRangesUsingFullExtents( final int binCount, final Unit unit, final long arbitraryTime ) { final Calendar startCal = Calendar.getInstance(); final long time = arbitraryTime; // hopefully these approaches work for // any arbitrary time, but allow a // caller to set the specific time // so tests are all entirely // reproducible startCal.setTimeInMillis(time); final Calendar endCal = Calendar.getInstance(); endCal.setTimeInMillis(time); final TemporalBinningStrategy binStrategy = new TemporalBinningStrategy( unit); binStrategy.setToEpoch(startCal); binStrategy.setToEpoch(endCal); endCal.add( unit.toCalendarEnum(), binCount); return binStrategy.getNormalizedRanges(new NumericRange( startCal.getTimeInMillis(), (double) endCal.getTimeInMillis() - 1)); } @Test public void testFullExtentOnSingleBin() { final BinRange[] ranges = getBinRangesUsingFullExtents( 1, Unit.MONTH, 543210987654321L); Assert.assertEquals( 1, ranges.length); Assert.assertTrue(ranges[0].isFullExtent()); } @Test public void testFullExtentOnMultipleBins() { final Calendar startCal = Calendar.getInstance(); final long time = 3456789012345L; startCal.setTimeInMillis(time); final Calendar endCal = Calendar.getInstance(); // theoretically should get 3 bins back the first and last not having // full extent and the middle one being full extent endCal.setTimeInMillis(time + (TemporalBinningStrategy.MILLIS_PER_DAY * 2)); final TemporalBinningStrategy binStrategy = new TemporalBinningStrategy( Unit.DAY); BinRange[] ranges = binStrategy.getNormalizedRanges(new NumericRange( startCal.getTimeInMillis(), endCal.getTimeInMillis())); Assert.assertEquals( 3, ranges.length); Assert.assertTrue(!ranges[0].isFullExtent()); Assert.assertTrue(ranges[1].isFullExtent()); Assert.assertTrue(!ranges[2].isFullExtent()); final Calendar startCalOnEpoch = Calendar.getInstance(); startCalOnEpoch.setTimeInMillis(time); binStrategy.setToEpoch(startCalOnEpoch); ranges = binStrategy.getNormalizedRanges(new NumericRange( startCalOnEpoch.getTimeInMillis(), endCal.getTimeInMillis())); Assert.assertEquals( 3, ranges.length); // now the first element should be full extent Assert.assertTrue(ranges[0].isFullExtent()); Assert.assertTrue(ranges[1].isFullExtent()); Assert.assertTrue(!ranges[2].isFullExtent()); final Calendar endCalOnMax = Calendar.getInstance(); // theoretically should get 3 bins back the first and last not having // full extent and the middle one being full extent endCalOnMax.setTimeInMillis(time + (TemporalBinningStrategy.MILLIS_PER_DAY * 3)); binStrategy.setToEpoch(endCalOnMax); endCalOnMax.add( Calendar.MILLISECOND, -1); ranges = binStrategy.getNormalizedRanges(new NumericRange( startCal.getTimeInMillis(), endCalOnMax.getTimeInMillis())); Assert.assertEquals( 3, ranges.length); Assert.assertTrue(!ranges[0].isFullExtent()); Assert.assertTrue(ranges[1].isFullExtent()); // now the last element should be full extent Assert.assertTrue(ranges[2].isFullExtent()); } @Test public void testStartOnEpochMinusOneAndEndOnEpoch() { final Calendar startCal = Calendar.getInstance(); // final long time = 675849302912837456L; //this value would cause it to // fail because we lose precision in coverting to a double (the mantissa // of a double value is 52 bits and therefore the max long that it can // accurately represent is 2^52 before the ulp of the double becomes // greater than 1) final long time = 6758493029128L; startCal.setTimeInMillis(time); startCal.set( Calendar.MONTH, 0);// make sure its a month after one with 31 days final TemporalBinningStrategy binStrategy = new TemporalBinningStrategy( Unit.MONTH); binStrategy.setToEpoch(startCal); final Calendar endCal = Calendar.getInstance(); endCal.setTimeInMillis(time); endCal.set( Calendar.MONTH, 0);// make sure its a month after one with 31 days binStrategy.setToEpoch(endCal); final BinRange[] ranges = binStrategy.getNormalizedRanges(new NumericRange( startCal.getTimeInMillis() - 1, endCal.getTimeInMillis())); Assert.assertEquals( 2, ranges.length); // the first range should be the max possible value and both the min and // max of the range should be equal Assert.assertTrue(ranges[0].getNormalizedMax() == binStrategy.getBinMax()); Assert.assertTrue(ranges[0].getNormalizedMin() == ranges[0].getNormalizedMax()); // the second range should be the min possible value and both the min // and max of the range should be equal Assert.assertTrue(ranges[1].getNormalizedMin() == binStrategy.getBinMin()); Assert.assertTrue(ranges[0].getNormalizedMax() == ranges[0].getNormalizedMin()); } @Test public void testStartAndEndEqual() { final long time = 123987564019283L; final TemporalBinningStrategy binStrategy = new TemporalBinningStrategy( Unit.YEAR); final BinRange[] ranges = binStrategy.getNormalizedRanges(new NumericRange( time, time)); Assert.assertEquals( 1, ranges.length); // both the min and max of the range should be equal Assert.assertTrue(ranges[0].getNormalizedMin() == ranges[0].getNormalizedMax()); } @Test public void testEndLessThanStart() { final long time = 123987564019283L; final TemporalBinningStrategy binStrategy = new TemporalBinningStrategy( Unit.YEAR); final BinRange[] ranges = binStrategy.getNormalizedRanges(new NumericRange( time, time - 1)); Assert.assertEquals( 0, ranges.length); } @Test public void testFeb28ToMarch1NonLeapYear() { final long time = 47920164930285667L; final Calendar startCal = Calendar.getInstance(); startCal.setTimeInMillis(time); startCal.set( Calendar.MONTH, 1); startCal.set( Calendar.YEAR, 2015); startCal.set( Calendar.DAY_OF_MONTH, 28); final Calendar endCal = Calendar.getInstance(); endCal.setTimeInMillis(time); endCal.set( Calendar.MONTH, 2); endCal.set( Calendar.YEAR, 2015); endCal.set( Calendar.DAY_OF_MONTH, 1); // test the day boundaries first - going from feb28 to march 1 should // give 2 bins TemporalBinningStrategy binStrategy = new TemporalBinningStrategy( Unit.DAY); BinRange[] ranges = binStrategy.getNormalizedRanges(new NumericRange( startCal.getTimeInMillis(), endCal.getTimeInMillis())); Assert.assertEquals( 2, ranges.length); // now test the month boundaries - adding a day to feb28 for the end // time should give 2 bins binStrategy = new TemporalBinningStrategy( Unit.MONTH); ranges = binStrategy.getNormalizedRanges(new NumericRange( startCal.getTimeInMillis(), startCal.getTimeInMillis() + (TemporalBinningStrategy.MILLIS_PER_DAY))); Assert.assertEquals( 2, ranges.length); } @Test public void testFeb28ToMarch1LeapYear() { final long time = 29374659120374656L; final Calendar startCal = Calendar.getInstance(); startCal.setTimeInMillis(time); startCal.set( Calendar.MONTH, 1); startCal.set( Calendar.YEAR, 2016); startCal.set( Calendar.DAY_OF_MONTH, 28); final Calendar endCal = Calendar.getInstance(); endCal.setTimeInMillis(time); endCal.set( Calendar.MONTH, 2); endCal.set( Calendar.YEAR, 2016); endCal.set( Calendar.DAY_OF_MONTH, 1); // test the day boundaries first - going from feb28 to march 1 should // give 3 bins TemporalBinningStrategy binStrategy = new TemporalBinningStrategy( Unit.DAY); BinRange[] ranges = binStrategy.getNormalizedRanges(new NumericRange( startCal.getTimeInMillis(), endCal.getTimeInMillis())); Assert.assertEquals( 3, ranges.length); // now test the month boundaries - adding a day to feb28 for the end // time should give 1 bin, adding 2 days should give 2 bins binStrategy = new TemporalBinningStrategy( Unit.MONTH); ranges = binStrategy.getNormalizedRanges(new NumericRange( startCal.getTimeInMillis(), startCal.getTimeInMillis() + (TemporalBinningStrategy.MILLIS_PER_DAY))); Assert.assertEquals( 1, ranges.length); // add 2 days and now we should end up with 2 bins ranges = binStrategy.getNormalizedRanges(new NumericRange( startCal.getTimeInMillis(), startCal.getTimeInMillis() + (TemporalBinningStrategy.MILLIS_PER_DAY * 2))); Assert.assertEquals( 2, ranges.length); } @Test public void testNonLeapYear() { final long time = 75470203439504394L; final TemporalBinningStrategy binStrategy = new TemporalBinningStrategy( Unit.YEAR); final Calendar startCal = Calendar.getInstance(); startCal.setTimeInMillis(time); startCal.set( Calendar.YEAR, 2015); binStrategy.setToEpoch(startCal); // if we add 365 days to this we should get 2 year bins final BinRange[] ranges = binStrategy.getNormalizedRanges(new NumericRange( startCal.getTimeInMillis(), startCal.getTimeInMillis() + (TemporalBinningStrategy.MILLIS_PER_DAY * 365))); Assert.assertEquals( 2, ranges.length); } @Test public void testLeapYear() { final long time = 94823024856598633L; final TemporalBinningStrategy binStrategy = new TemporalBinningStrategy( Unit.YEAR); final Calendar startCal = Calendar.getInstance(); startCal.setTimeInMillis(time); startCal.set( Calendar.YEAR, 2016); binStrategy.setToEpoch(startCal); // if we add 365 days to this we should get 1 year bin BinRange[] ranges = binStrategy.getNormalizedRanges(new NumericRange( startCal.getTimeInMillis(), startCal.getTimeInMillis() + (TemporalBinningStrategy.MILLIS_PER_DAY * 365))); Assert.assertEquals( 1, ranges.length); // if we add 366 days to this we should get 2 year bins, and the second // bin should be the epoch ranges = binStrategy.getNormalizedRanges(new NumericRange( startCal.getTimeInMillis(), startCal.getTimeInMillis() + (TemporalBinningStrategy.MILLIS_PER_DAY * 366))); Assert.assertEquals( 2, ranges.length); // the second bin should just contain the epoch Assert.assertTrue(ranges[1].getNormalizedMin() == ranges[1].getNormalizedMax()); Assert.assertTrue(ranges[1].getNormalizedMin() == binStrategy.getBinMin()); } }