gt:       if (i == 0) {
context: // This file is part of OpenTSDB.
  // Copyright (C) 2013  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.assertNotNull;
  import static org.junit.Assert.assertNull;
  import static org.junit.Assert.assertTrue;
  import static org.mockito.Matchers.any;
  import static org.mockito.Matchers.anyString;
  import static org.mockito.Mockito.when;
  import static org.mockito.Mockito.verify;
  import static org.powermock.api.mockito.PowerMockito.mock;
  
  import java.lang.reflect.Field;
  import java.util.HashMap;
  import java.util.Map;
  
  import net.opentsdb.utils.DateTime;
  
  import org.mockito.invocation.InvocationOnMock;
  import org.mockito.stubbing.Answer;
  import org.powermock.api.mockito.PowerMockito;
  
  import com.stumbleupon.async.Deferred;
  import net.opentsdb.uid.NoSuchUniqueName;
  import org.junit.Before;
  
  import net.opentsdb.storage.MockBase;
  
  import net.opentsdb.meta.Annotation;
  import net.opentsdb.uid.UniqueId;
  import net.opentsdb.utils.Config;
  import org.apache.zookeeper.proto.DeleteRequest;
  import org.hbase.async.GetRequest;
  import org.hbase.async.HBaseClient;
  import org.hbase.async.KeyValue;
  import org.hbase.async.PutRequest;
  import org.hbase.async.Scanner;
  import org.junit.Test;
  import org.junit.runner.RunWith;
  import org.powermock.core.classloader.annotations.PowerMockIgnore;
  import org.powermock.core.classloader.annotations.PrepareForTest;
  import org.powermock.modules.junit4.PowerMockRunner;
  
  /**
   * Tests downsampling with query.
   */
  @RunWith(PowerMockRunner.class)
  @PowerMockIgnore({"javax.management.*", "javax.xml.*",
    "ch.qos.*", "org.slf4j.*",
    "com.sum.*", "org.xml.*"})
  @PrepareForTest({TSDB.class, Config.class, UniqueId.class, HBaseClient.class,
    CompactionQueue.class, GetRequest.class, PutRequest.class, KeyValue.class,
    Scanner.class, TsdbQuery.class, DeleteRequest.class, Annotation.class,
    RowKey.class, Span.class, SpanGroup.class, IncomingDataPoints.class })
  public class TestTsdbQueryDownsample {
  
    private TSDB tsdb = null;
    private HBaseClient client = mock(HBaseClient.class);
    private UniqueId metrics = mock(UniqueId.class);
    private UniqueId tag_names = mock(UniqueId.class);
    private UniqueId tag_values = mock(UniqueId.class);
    private TsdbQuery query = null;
    private MockBase storage = null;
  
    @Before
    public void before() throws Exception {
      tsdb = TSDB.newTsdbForTest(client);
      query = new TsdbQuery(tsdb);
  
      // replace the "real" field objects with mocks
      Field met = tsdb.getClass().getDeclaredField("metrics");
      met.setAccessible(true);
      met.set(tsdb, metrics);
  
      Field tagk = tsdb.getClass().getDeclaredField("tag_names");
      tagk.setAccessible(true);
      tagk.set(tsdb, tag_names);
  
      Field tagv = tsdb.getClass().getDeclaredField("tag_values");
      tagv.setAccessible(true);
      tagv.set(tsdb, tag_values);
  
      // mock UniqueId
      when(metrics.getId("sys.cpu.user")).thenReturn(new byte[] { 0, 0, 1 });
      when(metrics.getNameAsync(new byte[] { 0, 0, 1 }))
        .thenReturn(Deferred.fromResult("sys.cpu.user"));
      when(metrics.getId("sys.cpu.system"))
        .thenThrow(new NoSuchUniqueName("sys.cpu.system", "metric"));
      when(metrics.getId("sys.cpu.nice")).thenReturn(new byte[] { 0, 0, 2 });
      when(metrics.getNameAsync(new byte[] { 0, 0, 2 }))
        .thenReturn(Deferred.fromResult("sys.cpu.nice"));
      when(tag_names.getId("host")).thenReturn(new byte[] { 0, 0, 1 });
      when(tag_names.getIdAsync("host")).thenReturn(
          Deferred.fromResult(new byte[] { 0, 0, 1 }));
      when(tag_names.getNameAsync(new byte[] { 0, 0, 1 }))
        .thenReturn(Deferred.fromResult("host"));
      when(tag_names.getOrCreateIdAsync("host")).thenReturn(
          Deferred.fromResult(new byte[] { 0, 0, 1 }));
      when(tag_names.getIdAsync("dc"))
        .thenThrow(new NoSuchUniqueName("dc", "metric"));
      when(tag_values.getId("web01")).thenReturn(new byte[] { 0, 0, 1 });
      when(tag_values.getIdAsync("web01")).thenReturn(
          Deferred.fromResult(new byte[] { 0, 0, 1 }));
      when(tag_values.getNameAsync(new byte[] { 0, 0, 1 }))
        .thenReturn(Deferred.fromResult("web01"));
      when(tag_values.getOrCreateIdAsync("web01")).thenReturn(
          Deferred.fromResult(new byte[] { 0, 0, 1 }));
      when(tag_values.getId("web02")).thenReturn(new byte[] { 0, 0, 2 });
      when(tag_values.getIdAsync("web02")).thenReturn(
          Deferred.fromResult(new byte[] { 0, 0, 2 }));
      when(tag_values.getNameAsync(new byte[] { 0, 0, 2 }))
        .thenReturn(Deferred.fromResult("web02"));
      when(tag_values.getOrCreateIdAsync("web02")).thenReturn(
          Deferred.fromResult(new byte[] { 0, 0, 2 }));
      when(tag_values.getId("web03"))
        .thenThrow(new NoSuchUniqueName("web03", "metric"));
  
      when(metrics.width()).thenReturn((short)3);
      when(tag_names.width()).thenReturn((short)3);
      when(tag_values.width()).thenReturn((short)3);
    }
  
    @Test
    public void downsample() throws Exception {
      int downsampleInterval = (int)DateTime.parseDuration("60s");
      query.downsample(downsampleInterval, Aggregators.SUM);
      query.setStartTime(1356998400);
      query.setEndTime(1357041600);
      assertEquals(60000, TsdbQuery.ForTesting.getDownsampleIntervalMs(query));
      long scanStartTime = 1356998400 - downsampleInterval / 1000 -
                           Const.MAX_TIMESPAN_SECS;
      assertEquals(scanStartTime,
                   TsdbQuery.ForTesting.getScanStartTimeSeconds(query));
      long hbaseScanStartTime = scanStartTime - Const.MAX_TIMESPAN_SECS + 1;
      assertEquals(hbaseScanStartTime,
                   TsdbQuery.ForTesting.getHBaseScanStartTimeSeconds(query));
      long scanEndTime = 1357041600 + downsampleInterval / 1000 +
                         Const.MAX_TIMESPAN_SECS;
      assertEquals(scanEndTime,
                   TsdbQuery.ForTesting.getScanEndTimeSeconds(query));
    }
  
    @Test
    public void downsampleMilliseconds() throws Exception {
      int downsampleInterval = (int)DateTime.parseDuration("60s");
      query.downsample(downsampleInterval, Aggregators.SUM);
      query.setStartTime(2356998400000L);
      query.setEndTime(2357041600000L);
      assertEquals(60000, TsdbQuery.ForTesting.getDownsampleIntervalMs(query));
      long scanStartTime = 2356998400L - downsampleInterval / 1000 -
                           Const.MAX_TIMESPAN_SECS;
      assertEquals(scanStartTime,
                   TsdbQuery.ForTesting.getScanStartTimeSeconds(query));
      long hbaseScanStartTime = scanStartTime - Const.MAX_TIMESPAN_SECS + 1;
      assertEquals(hbaseScanStartTime,
                   TsdbQuery.ForTesting.getHBaseScanStartTimeSeconds(query));
      long scanEndTime = 2357041600L + downsampleInterval / 1000 +
                         Const.MAX_TIMESPAN_SECS;
      assertEquals(scanEndTime,
                   TsdbQuery.ForTesting.getScanEndTimeSeconds(query));
    }
  
    @Test
    public void testScanTime_bigDownsampleTime() throws Exception {
      query.setInterpolationWindow(DateTime.parseDuration("110s"));
      int downsampleInterval = (int)DateTime.parseDuration("200s");
      query.downsample(downsampleInterval, Aggregators.SUM);
      query.setStartTime(1356998400);
      query.setEndTime(1357041600);
      assertEquals(200000, TsdbQuery.ForTesting.getDownsampleIntervalMs(query));
      long scanStartTime = 1356998400 - downsampleInterval / 1000 -
                           DateTime.parseDuration("110s") / 1000;
      assertEquals(scanStartTime,
          TsdbQuery.ForTesting.getScanStartTimeSeconds(query));
      long hbaseScanStartTime = scanStartTime - Const.MAX_TIMESPAN_SECS + 1;
      assertEquals(hbaseScanStartTime,
                   TsdbQuery.ForTesting.getHBaseScanStartTimeSeconds(query));
      long scanEndTime = 1357041600 + downsampleInterval / 1000 +
                         DateTime.parseDuration("110s") / 1000;
      assertEquals(scanEndTime,
                   TsdbQuery.ForTesting.getScanEndTimeSeconds(query));
    }
  
    @Test
    public void testScanTime_customerOverride() throws Exception {
      query.setInterpolationWindow(DateTime.parseDuration("110s"));
      query.setHbaseTimeStartExtensionMillis(DateTime.parseDuration("17s"));
      query.setHbaseTimeEndExtensionMillis(DateTime.parseDuration("37s"));
      int downsampleInterval = (int)DateTime.parseDuration("200s");
      query.downsample(downsampleInterval, Aggregators.SUM);
      query.setStartTime(1356998400);
      query.setEndTime(1357041600);
      assertEquals(200000, TsdbQuery.ForTesting.getDownsampleIntervalMs(query));
      long scanStartTime = 1356998400 - 17;
      assertEquals(scanStartTime,
                   TsdbQuery.ForTesting.getScanStartTimeSeconds(query));
      long hbaseScanStartTime = scanStartTime - Const.MAX_TIMESPAN_SECS + 1;
      assertEquals(hbaseScanStartTime,
                   TsdbQuery.ForTesting.getHBaseScanStartTimeSeconds(query));
      long scanEndTime = 1357041600 + 37;
      assertEquals(scanEndTime,
                   TsdbQuery.ForTesting.getScanEndTimeSeconds(query));
    }
  
    @Test (expected = NullPointerException.class)
    public void downsampleNullAgg() throws Exception {
      query.downsample(60, null);
    }
  
    @Test (expected = IllegalArgumentException.class)
    public void downsampleInvalidInterval() throws Exception {
      query.downsample(0, Aggregators.SUM);
    }
  
    @Test
    public void runLongSingleTSDownsample() throws Exception {
      storeLongTimeSeriesSeconds(true, false);;
      HashMap<String, String> tags = new HashMap<String, String>(1);
      tags.put("host", "web01");
      query.setStartTime(1356998400);
      query.setEndTime(1357041600);
      query.downsample(60000, Aggregators.AVG);
      query.setTimeSeries("sys.cpu.user", tags, Aggregators.SUM, false);
      final DataPoints[] dps = query.run();
      assertNotNull(dps);
      assertEquals("sys.cpu.user", dps[0].metricName());
      assertTrue(dps[0].getAggregatedTags().isEmpty());
      assertNull(dps[0].getAnnotations());
      assertEquals("web01", dps[0].getTags().get("host"));
  
      // Timeseries in intervals: (1), (2, 3), (4, 5), ... (298, 299), (300)
      int i = 0;
      for (DataPoint dp : dps[0]) {
        // Downsampler outputs just doubles.
        assertFalse(dp.isInteger());
  