// This file is part of OpenTSDB. // Copyright (C) 2015 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.query.pojo; import net.opentsdb.core.FillPolicy; import net.opentsdb.query.expression.NumericFillPolicy; import net.opentsdb.query.expression.VariableIterator.SetOperator; import net.opentsdb.query.filter.TagVFilter; import net.opentsdb.utils.JSON; import org.junit.Before; import org.junit.Test; import java.util.Arrays; import java.util.Collections; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; public class TestQuery { Timespan time; TagVFilter tag; Filter filter; Metric metric; Expression expression; Output output; String json = "{" + " \"time\":{" + " \"start\":\"3h-ago\"," + " \"end\":\"1h-ago\"," + " \"timezone\":\"UTC\"," + " \"aggregator\":\"avg\"," + " \"downsampler\":{\"interval\":\"15m\"," + " \"aggregator\":\"avg\"," + " \"fillPolicy\":{\"policy\":\"nan\"}}" + " }," + " \"filters\":[" + " {" + " \"id\":\"f1\"," + " \"tags\":[" + " {" + " \"tagk\":\"host\"," + " \"filter\":\"*\"," + " \"type\":\"iwildcard\"," + " \"groupBy\":false" + " }" + " ]" + " }" + " ]," + " \"metrics\":[" + " {" + " \"metric\":\"YAMAS.cpu.idle\"," + " \"id\":\"m1\"," + " \"filter\":\"f1\"," + " \"aggregator\":\"sum\"," + " \"timeOffset\":\"0\"" + " }" + " ]," + " \"expressions\":[" + " {" + " \"id\":\"e1\"," + " \"expr\":\"m1 * 1024\"" + " }" + " ]," + " \"outputs\":[" + " {" + " \"id\":\"m1\"," + " \"alias\":\"CPU Idle EAST DC\"" + " }" + " ]" + "}"; @Before public void setup() { time = Timespan.Builder().setStart("3h-ago").setAggregator("avg") .setEnd("1h-ago").setTimezone("UTC").setDownsampler( Downsampler.Builder().setInterval("15m").setAggregator("avg") .setFillPolicy(new NumericFillPolicy(FillPolicy.NOT_A_NUMBER)).build()) .build(); TagVFilter tag = new TagVFilter.Builder().setFilter("*").setGroupBy( false) .setTagk("host").setType("iwildcard").build(); filter = Filter.Builder().setId("f1").setTags(Arrays.asList(tag)).build(); metric = Metric.Builder().setMetric("YAMAS.cpu.idle") .setId("m1").setFilter("f1").setTimeOffset("0") .setAggregator("sum").build(); expression = Expression.Builder().setId("e1") .setExpression("m1 * 1024").setJoin( Join.Builder().setOperator(SetOperator.UNION).build()).build(); output = Output.Builder().setId("m1").setAlias("CPU Idle EAST DC") .build(); } @Test(expected = IllegalArgumentException.class) public void validationErrorWhenTimeIsNull() throws Exception { Query query = getDefaultQueryBuilder().setTime(null).build(); query.validate(); } @Test(expected = IllegalArgumentException.class) public void invalidTime() throws Exception { Timespan invalidTime = Timespan.Builder().build(); Query query = getDefaultQueryBuilder().setTime(invalidTime).build(); query.validate(); } @Test(expected = IllegalArgumentException.class) public void metricsIsNull() throws Exception { Query query = getDefaultQueryBuilder().setMetrics(null).build(); query.validate(); } @Test(expected = IllegalArgumentException.class) public void metricsIsEmpty() throws Exception { Query query = getDefaultQueryBuilder().setMetrics( Collections.<Metric>emptyList()).build(); query.validate(); } @Test(expected = IllegalArgumentException.class) public void invalidMetric() throws Exception { Metric invalidMetric = Metric.Builder().build(); Query query = getDefaultQueryBuilder() .setMetrics(Arrays.asList(invalidMetric)).build(); query.validate(); } @Test(expected = IllegalArgumentException.class) public void invalidFilter() throws Exception { Filter invalidFilter = Filter.Builder().build(); Query query = getDefaultQueryBuilder() .setFilters(Arrays.asList(invalidFilter)).build(); query.validate(); } @Test(expected = IllegalArgumentException.class) public void invalidExpression() throws Exception { Expression invalidExpression = Expression.Builder().build(); Query query = getDefaultQueryBuilder() .setExpressions(Arrays.asList(invalidExpression)).build(); query.validate(); } @Test(expected = IllegalArgumentException.class) public void noSuchFilterIdInMetric() throws Exception { Metric invalid_metric = Metric.Builder().setMetric("YAMAS.cpu.idle") .setId("m2").setFilter("f2").setTimeOffset("0").build(); Query query = getDefaultQueryBuilder().setMetrics( Arrays.asList(invalid_metric, metric)).build(); query.validate(); } @Test public void deserialize() throws Exception { Query query = JSON.parseToObject(json, Query.class); query.validate(); Query expected = Query.Builder().setExpressions(Arrays.asList(expression)) .setFilters(Arrays.asList(filter)).setMetrics(Arrays.asList(metric)) .setTime(time).setOutputs(Arrays.asList(output)).build(); assertEquals(expected, query); } @Test(expected = IllegalArgumentException.class) public void duplicatedFilterId() throws Exception { Query query = getDefaultQueryBuilder().setFilters( Arrays.asList(filter, filter)).build(); query.validate(); } @Test(expected = IllegalArgumentException.class) public void duplicatedExpressionId() throws Exception { Query query = getDefaultQueryBuilder().setExpressions( Arrays.asList(expression, expression)).build(); query.validate(); } @Test(expected = IllegalArgumentException.class) public void duplicatedMetricId() throws Exception { Query query = getDefaultQueryBuilder().setMetrics( Arrays.asList(metric, metric)).build(); query.validate(); } @Test public void serialize() throws Exception { Query query = Query.Builder().setExpressions(Arrays.asList(expression)) .setFilters(Arrays.asList(filter)).setMetrics(Arrays.asList(metric)) .setName("q1").setTime(time).setOutputs(Arrays.asList(output)).build(); String actual = JSON.serializeToString(query); // String expected = "{\"name\":\"q1\",\"time\":{\"start\":\"3h-ago\"," // + "\"end\":\"1h-ago\",\"timezone\":\"UTC\",\"downsample\":\"15m-avg-nan\"," // + "\"interpolation\":\"LERP\"},\"filters\":[{\"id\":\"f1\"," // + "\"tags\":[{\"tagk\":\"host\",\"filter\":\"*\",\"group_by\":false," // + "\"type\":\"iwildcard\"}],\"aggregator\":\"sum\"}]," // + "\"metrics\":[{\"metric\":\"YAMAS.cpu.idle\"," // + "\"id\":\"m1\",\"filter\":\"f1\",\"time_offset\":\"0\"}]," // + "\"expressions\":[{\"id\":\"e1\",\"expr\":\"a + b + c\"}]," // + "\"outputs\":[{\"var\":\"q1.m1\",\"alias\":\"CPU Idle EAST DC\"}]}"; assertTrue(actual.contains("\"name\":\"q1\"")); assertTrue(actual.contains("\"start\":\"3h-ago\"")); assertTrue(actual.contains("\"end\":\"1h-ago\"")); assertTrue(actual.contains("\"timezone\":\"UTC\"")); // TODO - finish the assertions } private Query.Builder getDefaultQueryBuilder() { return Query.Builder().setExpressions(Arrays.asList(expression)) .setFilters(Arrays.asList(filter)).setMetrics(Arrays.asList(metric)) .setName("q1").setTime(time).setOutputs(Arrays.asList(output)); } }