// 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.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import net.opentsdb.core.TsdbQuery.ForTesting;
import net.opentsdb.query.filter.TagVFilter;
import net.opentsdb.query.filter.TagVWildcardFilter;
import net.opentsdb.storage.MockBase;
import net.opentsdb.uid.NoSuchUniqueName;
import net.opentsdb.utils.DateTime;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import com.stumbleupon.async.DeferredGroupException;
/**
* This class is for unit testing the TsdbQuery class. Pretty much making sure
* the various ctors and methods function as expected. For actually running the
* queries and validating the group by and aggregation logic, see
* {@link TestTsdbQueryQueries}
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({ DateTime.class })
public final class TestTsdbQuery extends BaseTsdbTest {
private TsdbQuery query = null;
@Before
public void beforeLocal() throws Exception {
query = new TsdbQuery(tsdb);
}
@Test
public void setStartTime() throws Exception {
query.setStartTime(1356998400L);
assertEquals(1356998400L, query.getStartTime());
}
@Test
public void setStartTimeZero() throws Exception {
query.setStartTime(0L);
}
@Test (expected = IllegalArgumentException.class)
public void setStartTimeInvalidNegative() throws Exception {
query.setStartTime(-1L);
}
@Test (expected = IllegalArgumentException.class)
public void setStartTimeInvalidTooBig() throws Exception {
query.setStartTime(17592186044416L);
}
@Test (expected = IllegalArgumentException.class)
public void setStartTimeEqualtoEndTime() throws Exception {
query.setEndTime(1356998400L);
query.setStartTime(1356998400L);
}
@Test (expected = IllegalArgumentException.class)
public void setStartTimeGreaterThanEndTime() throws Exception {
query.setEndTime(1356998400L);
query.setStartTime(1356998460L);
}
@Test
public void setEndTime() throws Exception {
query.setEndTime(1356998400L);
assertEquals(1356998400L, query.getEndTime());
}
@Test (expected = IllegalStateException.class)
public void getStartTimeNotSet() throws Exception {
query.getStartTime();
}
@Test (expected = IllegalArgumentException.class)
public void setEndTimeInvalidNegative() throws Exception {
query.setEndTime(-1L);
}
@Test (expected = IllegalArgumentException.class)
public void setEndTimeInvalidTooBig() throws Exception {
query.setEndTime(17592186044416L);
}
@Test (expected = IllegalArgumentException.class)
public void setEndTimeEqualtoEndTime() throws Exception {
query.setStartTime(1356998400L);
query.setEndTime(1356998400L);
}
@Test (expected = IllegalArgumentException.class)
public void setEndTimeGreaterThanEndTime() throws Exception {
query.setStartTime(1356998460L);
query.setEndTime(1356998400L);
}
@Test
public void getEndTimeNotSet() throws Exception {
PowerMockito.mockStatic(DateTime.class);
PowerMockito.when(DateTime.currentTimeMillis()).thenReturn(1357300800000L);
assertEquals(1357300800000L, query.getEndTime());
}
@Test
public void setTimeSeries() throws Exception {
query.setTimeSeries(METRIC_STRING, tags, Aggregators.SUM, false);
assertNotNull(query);
assertArrayEquals(METRIC_BYTES, ForTesting.getMetric(query));
assertEquals(1, ForTesting.getFilters(query).size());
assertEquals(1, ForTesting.getGroupBys(query).size());
assertArrayEquals(TAGK_BYTES, ForTesting.getGroupBys(query).get(0));
assertEquals(1, ForTesting.getRowKeyLiterals(query).size());
assertEquals(1, ForTesting.getRowKeyLiterals(query).get(TAGV_BYTES).length);
assertArrayEquals(TAGV_BYTES,
ForTesting.getRowKeyLiterals(query).get(TAGV_BYTES)[0]);
}
@Test (expected = NullPointerException.class)
public void setTimeSeriesNullTags() throws Exception {
query.setTimeSeries(METRIC_STRING, null, Aggregators.SUM, false);
}
@Test
public void setTimeSeriesEmptyTags() throws Exception {
tags.clear();
query.setTimeSeries(METRIC_STRING, tags, Aggregators.SUM, false);
assertNotNull(query);
}
@Test (expected = NoSuchUniqueName.class)
public void setTimeSeriesNosuchMetric() throws Exception {
query.setTimeSeries(NSUN_METRIC, tags, Aggregators.SUM, false);
}
@Test (expected = NoSuchUniqueName.class)
public void setTimeSeriesNosuchTagk() throws Exception {
tags.clear();
tags.put(NSUN_TAGK, TAGV_STRING);
query.setTimeSeries(METRIC_STRING, tags, Aggregators.SUM, false);
}
@Test (expected = NoSuchUniqueName.class)
public void setTimeSeriesNosuchTagv() throws Exception {
tags.put(TAGK_STRING, NSUN_TAGV);
query.setTimeSeries(METRIC_STRING, tags, Aggregators.SUM, false);
}
@Test
public void setTimeSeriesTS() throws Exception {
final List<String> tsuids = new ArrayList<String>(2);
tsuids.add("000001000001000001");
tsuids.add("000001000001000002");
query.setTimeSeries(tsuids, Aggregators.SUM, false);
assertNotNull(query);
}
@Test (expected = IllegalArgumentException.class)
public void setTimeSeriesTSNullList() throws Exception {
query.setTimeSeries(null, Aggregators.SUM, false);
}
@Test (expected = IllegalArgumentException.class)
public void setTimeSeriesTSEmptyList() throws Exception {
final List<String> tsuids = new ArrayList<String>();
query.setTimeSeries(tsuids, Aggregators.SUM, false);
}
@Test (expected = IllegalArgumentException.class)
public void setTimeSeriesTSDifferentMetrics() throws Exception {
final List<String> tsuids = new ArrayList<String>(2);
tsuids.add("000001000001000001");
tsuids.add("000002000001000002");
query.setTimeSeries(tsuids, Aggregators.SUM, false);
}
@Test
public void configureFromQuery() throws Exception {
setDataPointStorage();
final TSQuery ts_query = getTSQuery();
ts_query.validateAndSetQuery();
query = new TsdbQuery(tsdb);
query.configureFromQuery(ts_query, 0).joinUninterruptibly();
assertArrayEquals(METRIC_BYTES, ForTesting.getMetric(query));
assertEquals(1, ForTesting.getFilters(query).size());
assertArrayEquals(TAGK_BYTES, ForTesting.getGroupBys(query).get(0));
assertEquals(1, ForTesting.getGroupBys(query).size());
assertNotNull(ForTesting.getRateOptions(query));
}
@Test
public void configureFromQueryWithRate() throws Exception {
setDataPointStorage();
final TSQuery ts_query = getTSQuery();
final RateOptions rate_options = new RateOptions();
rate_options.setResetValue(1024);
ts_query.getQueries().get(0).setRateOptions(rate_options);
ts_query.validateAndSetQuery();
query = new TsdbQuery(tsdb);
query.configureFromQuery(ts_query, 0).joinUninterruptibly();
assertArrayEquals(METRIC_BYTES, ForTesting.getMetric(query));
assertEquals(1, ForTesting.getFilters(query).size());
assertArrayEquals(TAGK_BYTES, ForTesting.getGroupBys(query).get(0));
assertEquals(1, ForTesting.getGroupBys(query).size());
assertTrue(rate_options == ForTesting.getRateOptions(query));
}
@Test
public void configureFromQueryNoTags() throws Exception {
setDataPointStorage();
final TSQuery ts_query = getTSQuery();
ts_query.getQueries().get(0).setTags(Collections.EMPTY_MAP);
ts_query.validateAndSetQuery();
query = new TsdbQuery(tsdb);
query.configureFromQuery(ts_query, 0).joinUninterruptibly();
assertArrayEquals(METRIC_BYTES, ForTesting.getMetric(query));
assertEquals(0, ForTesting.getFilters(query).size());
assertNull(ForTesting.getGroupBys(query));
assertNull(ForTesting.getRowKeyLiterals(query));
}
@Test
public void configureFromQueryGroupByAll() throws Exception {
setDataPointStorage();
final TSQuery ts_query = getTSQuery();
tags.clear();
tags.put(TAGK_STRING, "*");
ts_query.getQueries().get(0).setTags(tags);
ts_query.validateAndSetQuery();
query = new TsdbQuery(tsdb);
query.configureFromQuery(ts_query, 0).joinUninterruptibly();
assertArrayEquals(METRIC_BYTES, ForTesting.getMetric(query));
assertEquals(1, ForTesting.getFilters(query).size());
assertEquals(1, ForTesting.getGroupBys(query).size());
assertArrayEquals(TAGK_BYTES,
ForTesting.getGroupBys(query).get(0));
assertEquals(1, ForTesting.getRowKeyLiterals(query).size());
assertNull(ForTesting.getRowKeyLiterals(query).get(TAGV_BYTES));
}
@Test
public void configureFromQueryGroupByPipe() throws Exception {
setDataPointStorage();
final TSQuery ts_query = getTSQuery();
tags.clear();
tags.put(TAGK_STRING, TAGV_STRING + "|" + TAGV_B_STRING);
ts_query.getQueries().get(0).setTags(tags);
ts_query.validateAndSetQuery();
query = new TsdbQuery(tsdb);
query.configureFromQuery(ts_query, 0).joinUninterruptibly();
assertArrayEquals(METRIC_BYTES, ForTesting.getMetric(query));
assertEquals(1, ForTesting.getFilters(query).size());
assertEquals(1, ForTesting.getGroupBys(query).size());
assertArrayEquals(TAGK_BYTES, ForTesting.getGroupBys(query).get(0));
assertEquals(1, ForTesting.getRowKeyLiterals(query).size());
assertEquals(2, ForTesting.getRowKeyLiterals(query).get(TAGV_BYTES).length);
assertArrayEquals(TAGV_BYTES,
ForTesting.getRowKeyLiterals(query).get(TAGV_BYTES)[0]);
assertArrayEquals(TAGV_B_BYTES,
ForTesting.getRowKeyLiterals(query).get(TAGV_BYTES)[1]);
}
@Test
public void configureFromQueryWithGroupByFilter() throws Exception {
setDataPointStorage();
final TSQuery ts_query = getTSQuery();
tags.clear();
tags.put("host", TagVWildcardFilter.FILTER_NAME + "(*imes)");
ts_query.getQueries().get(0).setTags(tags);
ts_query.validateAndSetQuery();
query = new TsdbQuery(tsdb);
query.configureFromQuery(ts_query, 0).joinUninterruptibly();
assertArrayEquals(METRIC_BYTES, ForTesting.getMetric(query));
assertEquals(1, ForTesting.getFilters(query).size());
assertEquals(1, ForTesting.getGroupBys(query).size());
assertArrayEquals(TAGK_BYTES, ForTesting.getGroupBys(query).get(0));
assertEquals(1, ForTesting.getRowKeyLiterals(query).size());
assertNull(ForTesting.getRowKeyLiterals(query).get(TAGV_BYTES));
assertNotNull(ForTesting.getRateOptions(query));
}
@Test
public void configureFromQueryWithFilter() throws Exception {
setDataPointStorage();
final TSQuery ts_query = getTSQuery();
final List<TagVFilter> filters = new ArrayList<TagVFilter>(1);
filters.add(new TagVWildcardFilter("host", "*imes"));
ts_query.getQueries().get(0).setFilters(filters);
ts_query.validateAndSetQuery();
query = new TsdbQuery(tsdb);
query.configureFromQuery(ts_query, 0).joinUninterruptibly();
assertArrayEquals(METRIC_BYTES, ForTesting.getMetric(query));
assertEquals(1, ForTesting.getFilters(query).size());
assertNull(ForTesting.getGroupBys(query));
assertEquals(1, ForTesting.getRowKeyLiterals(query).size());
assertNull(ForTesting.getRowKeyLiterals(query).get(TAGV_BYTES));
assertNotNull(ForTesting.getRateOptions(query));
}
@Test
public void configureFromQueryWithGroupByAndRegularFilters() throws Exception {
setDataPointStorage();
final TSQuery ts_query = getTSQuery();
final List<TagVFilter> filters = new ArrayList<TagVFilter>(1);
filters.add(new TagVWildcardFilter("host", "*imes"));
filters.add(TagVFilter.Builder().setFilter("*").setTagk("host")
.setType("wildcard").setGroupBy(true).build());
ts_query.getQueries().get(0).setFilters(filters);
ts_query.validateAndSetQuery();
query = new TsdbQuery(tsdb);
query.configureFromQuery(ts_query, 0).joinUninterruptibly();
assertArrayEquals(METRIC_BYTES, ForTesting.getMetric(query));
assertEquals(2, ForTesting.getFilters(query).size());
assertEquals(1, ForTesting.getGroupBys(query).size());
assertArrayEquals(TAGK_BYTES, ForTesting.getGroupBys(query).get(0));
assertEquals(1, ForTesting.getRowKeyLiterals(query).size());
assertNull(ForTesting.getRowKeyLiterals(query).get(TAGK_BYTES));
assertNotNull(ForTesting.getRateOptions(query));
}
@Test (expected = IllegalArgumentException.class)
public void configureFromQueryNullSubs() throws Exception {
final TSQuery ts_query = new TSQuery();
new TsdbQuery(tsdb).configureFromQuery(ts_query, 0);
}
@Test (expected = IllegalArgumentException.class)
public void configureFromQueryEmptySubs() throws Exception {
final TSQuery ts_query = new TSQuery();
ts_query.setQueries(new ArrayList<TSSubQuery>(0));
new TsdbQuery(tsdb).configureFromQuery(ts_query, 0);
}
@Test (expected = IllegalArgumentException.class)
public void configureFromQueryNegativeIndex() throws Exception {
final TSQuery ts_query = getTSQuery();
new TsdbQuery(tsdb).configureFromQuery(ts_query, -1);
}
@Test (expected = IllegalArgumentException.class)
public void configureFromQueryIndexOutOfBounds() throws Exception {
final TSQuery ts_query = getTSQuery();
new TsdbQuery(tsdb).configureFromQuery(ts_query, 2);
}
@Test (expected = NoSuchUniqueName.class)
public void configureFromQueryNSUMetric() throws Exception {
setDataPointStorage();
final TSQuery ts_query = getTSQuery();
ts_query.getQueries().get(0).setMetric(NSUN_METRIC);
ts_query.validateAndSetQuery();
query = new TsdbQuery(tsdb);
query.configureFromQuery(ts_query, 0).joinUninterruptibly();
}
@Test (expected = DeferredGroupException.class)
public void configureFromQueryNSUTagk() throws Exception {
setDataPointStorage();
final TSQuery ts_query = getTSQuery();
tags.clear();
tags.put(NSUN_TAGK, TAGV_STRING);
ts_query.getQueries().get(0).setTags(tags);
ts_query.validateAndSetQuery();
query = new TsdbQuery(tsdb);
query.configureFromQuery(ts_query, 0).joinUninterruptibly();
}
@Test (expected = DeferredGroupException.class)
public void configureFromQueryNSUTagv() throws Exception {
setDataPointStorage();
final TSQuery ts_query = getTSQuery();
tags.clear();
tags.put(TAGK_STRING, NSUN_TAGV);
ts_query.getQueries().get(0).setTags(tags);
ts_query.validateAndSetQuery();
query = new TsdbQuery(tsdb);
query.configureFromQuery(ts_query, 0).joinUninterruptibly();
}
@Test (expected = DeferredGroupException.class)
public void configureFromQueryGroupByPipeNSUTagk() throws Exception {
setDataPointStorage();
final TSQuery ts_query = getTSQuery();
tags.clear();
tags.put(NSUN_TAGK, TAGV_STRING + "|" + TAGV_B_STRING);
ts_query.getQueries().get(0).setTags(tags);
ts_query.validateAndSetQuery();
query = new TsdbQuery(tsdb);
query.configureFromQuery(ts_query, 0).joinUninterruptibly();
}
@Test (expected = DeferredGroupException.class)
public void configureFromQueryGroupByPipeNSUTagv() throws Exception {
setDataPointStorage();
final TSQuery ts_query = getTSQuery();
tags.clear();
tags.put(TAGK_STRING, TAGV_STRING + "|" + NSUN_TAGV);
ts_query.getQueries().get(0).setTags(tags);
ts_query.validateAndSetQuery();
query = new TsdbQuery(tsdb);
query.configureFromQuery(ts_query, 0).joinUninterruptibly();
}
@Test
public void configureFromQueryGroupByPipeNSUTagvSkipUnresolved()
throws Exception {
config.overrideConfig("tsd.query.skip_unresolved_tagvs", "true");
setDataPointStorage();
final TSQuery ts_query = getTSQuery();
tags.clear();
tags.put(TAGK_STRING, TAGV_STRING + "|" + NSUN_TAGV);
ts_query.getQueries().get(0).setTags(tags);
ts_query.validateAndSetQuery();
query = new TsdbQuery(tsdb);
query.configureFromQuery(ts_query, 0).joinUninterruptibly();
assertArrayEquals(METRIC_BYTES, ForTesting.getMetric(query));
assertEquals(1, ForTesting.getFilters(query).size());
assertEquals(1, ForTesting.getGroupBys(query).size());
assertArrayEquals(TAGK_BYTES,
ForTesting.getGroupBys(query).get(0));
}
@Test
public void deleteDatapoints() throws Exception {
setDataPointStorage();
tsdb.addPoint(METRIC_STRING, 1356998400, 42, tags).joinUninterruptibly();
query.setStartTime(1356998400);
query.setTimeSeries(METRIC_STRING, tags, Aggregators.SUM, false);
query.setDelete(true);
final DataPoints[] dps1 = query.run();
assertEquals(1, dps1.length);
// second run should be empty
final DataPoints[] dps2 = query.run();
assertEquals(0, dps2.length);
}
@Test
public void scannerException() throws Exception {
storeLongTimeSeriesSeconds(true, false);
final RuntimeException ex = new RuntimeException("Boo!");
storage.throwException(MockBase.stringToBytes(
"00000150E22700000001000001"), ex, true);
storage.dumpToSystemOut();
query.setStartTime(1356998400);
query.setEndTime(1357041600);
query.setTimeSeries(METRIC_STRING, tags, Aggregators.SUM, false);
try {
query.run();
fail("Expected a RuntimeException");
} catch (RuntimeException e) {
assertSame(ex, e);
}
}
/** @return a simple TSQuery object for testing */
private TSQuery getTSQuery() {
final TSQuery ts_query = new TSQuery();
ts_query.setStart("1356998400");
final TSSubQuery sub_query = new TSSubQuery();
sub_query.setMetric(METRIC_STRING);
sub_query.setAggregator("sum");
sub_query.setTags(tags);
final ArrayList<TSSubQuery> sub_queries = new ArrayList<TSSubQuery>(1);
sub_queries.add(sub_query);
ts_query.setQueries(sub_queries);
return ts_query;
}
}