// 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.assertTrue;
import static org.junit.Assert.assertFalse;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.when;
import static org.powermock.api.mockito.PowerMockito.mock;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import net.opentsdb.uid.UniqueId;
import net.opentsdb.utils.Config;
import org.hbase.async.HBaseClient;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import com.stumbleupon.async.Deferred;
@RunWith(PowerMockRunner.class)
@PrepareForTest({ TSDB.class, Config.class, UniqueId.class, HBaseClient.class,
IncomingDataPoints.class })
public class TestBatchedDataPoints {
private static Config config;
private static 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 BatchedDataPoints bdp = null;
@SuppressWarnings("unchecked")
@Before
public void before() throws Exception {
config = new Config(false);
tsdb = new TSDB(client, config);
// 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);
when(metrics.width()).thenReturn((short) 3);
when(tag_names.width()).thenReturn((short) 3);
when(tag_values.width()).thenReturn((short) 3);
when(metrics.getId("foo")).thenReturn(new byte[] { 0, 0, 1 });
when(metrics.getNameAsync(new byte[] { 0, 0, 1 })).thenReturn(
Deferred.fromResult("foo"));
PowerMockito.mockStatic(IncomingDataPoints.class);
final byte[] row = new byte[] { 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1 };
PowerMockito.doAnswer(new Answer<byte[]>() {
public byte[] answer(final InvocationOnMock unused) throws Exception {
return row;
}
}).when(IncomingDataPoints.class, "rowKeyTemplate", (TSDB) any(),
anyString(), (Map<String, String>) any());
Map<String, String> tags = new HashMap<String, String>();
tags.put("host", "web01");
bdp = new BatchedDataPoints(tsdb, "foo", tags);
}
@Test
public void timestamp() {
bdp.addPoint(1388534400L, 1);
bdp.addPoint(1388534400500L, 2);
bdp.addPoint(1388534400750L, 2);
assertEquals(1388534400000L, bdp.timestamp(0));
assertEquals(1388534400500L, bdp.timestamp(1));
assertEquals(1388534400750L, bdp.timestamp(2));
}
@Test
public void isInteger() {
bdp.addPoint(1388534400L, 1);
bdp.addPoint(1388534400500L, Short.MIN_VALUE);
bdp.addPoint(1388534401L, Integer.MIN_VALUE);
bdp.addPoint(1388534401750L, 2.0f);
assertTrue(bdp.isInteger(0));
assertTrue(bdp.isInteger(1));
assertTrue(bdp.isInteger(2));
assertFalse(bdp.isInteger(3));
}
@Test
public void longValue() {
bdp.addPoint(1388534400L, 1);
bdp.addPoint(1388534400500L, Short.MIN_VALUE);
bdp.addPoint(1388534401L, Integer.MIN_VALUE);
bdp.addPoint(1388534401750L, 2.0f);
assertEquals(1, bdp.longValue(0));
assertEquals(Short.MIN_VALUE, bdp.longValue(1));
assertEquals(Integer.MIN_VALUE, bdp.longValue(2));
}
@Test
public void doubleValue() {
bdp.addPoint(1388534400L, 1);
bdp.addPoint(1388534400500L, Short.MIN_VALUE);
bdp.addPoint(1388534401L, Integer.MIN_VALUE);
bdp.addPoint(1388534401750L, 2.0f);
Assert.assertEquals(2.0f, bdp.doubleValue(3), 0.00001f);
}
@Test
public void inBounds() {
long timestamp = 1388534400L;
long base_time = (timestamp - (timestamp % Const.MAX_TIMESPAN));
// test that the limit values are fine
bdp.addPoint(base_time, 2);
bdp.addPoint(base_time + Const.MAX_TIMESPAN - 1, 3);
}
@Test(expected = IllegalArgumentException.class)
public void addPrevTimestamp() {
bdp.addPoint(1388534400L, 1);
bdp.addPoint(1388534350L, 2);
}
@Test(expected = IllegalDataException.class)
public void outOfBounds() {
long timestamp = 1388534400L;
long base_time = (timestamp - (timestamp % Const.MAX_TIMESPAN));
bdp.addPoint(timestamp, 1); // this set's the batch's baseTime
// outside the limits addPoint throws an IllegalArgumentException
bdp.addPoint(base_time + Const.MAX_TIMESPAN, 2);
}
@Test
public void fullLoad() {
long timestamp = 1388534400L;
long base_time = (timestamp - (timestamp % Const.MAX_TIMESPAN));
for (int i = 0; i < Const.MAX_TIMESPAN; i++) {
bdp.addPoint(base_time + i, i);
}
}
@Test
public void fullLoadMs() {
long timestamp = 1388534400L;
long base_time = (timestamp - (timestamp % Const.MAX_TIMESPAN));
for (long i = 0; i < Const.MAX_TIMESPAN * 1000; i++) {
bdp.addPoint(base_time * 1000 + i, i);
}
}
}