// 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.expression;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import net.opentsdb.core.FillPolicy;
import net.opentsdb.core.IllegalDataException;
import net.opentsdb.query.expression.VariableIterator.SetOperator;
import org.apache.commons.jexl2.JexlException;
import org.hbase.async.Bytes;
import org.junit.Test;
public class TestExpressionIterator extends BaseTimeSyncedIteratorTest {
@Test
public void ctor() throws Exception {
final ExpressionIterator exp = new ExpressionIterator("ei", "a + b",
SetOperator.INTERSECTION, false, false);
assertEquals(2, exp.getVariableNames().size());
assertTrue(exp.getVariableNames().contains("a"));
assertTrue(exp.getVariableNames().contains("b"));
assertFalse(exp.getVariableNames().contains("+")); // I'm not a variable :(
assertNull(exp.values());
}
@Test (expected = IllegalArgumentException.class)
public void ctorNoVariables() throws Exception {
new ExpressionIterator("ei", "1 + 1", SetOperator.INTERSECTION, false, false);
}
@Test (expected = IllegalArgumentException.class)
public void ctorNullExpression() throws Exception {
new ExpressionIterator("ei", null, SetOperator.INTERSECTION, false, false);
}
@Test (expected = JexlException.class)
public void ctorBadExpression() throws Exception {
new ExpressionIterator("ei", " a / ", SetOperator.INTERSECTION, false, false);
}
@Test (expected = IllegalArgumentException.class)
public void ctorEmptyExpression() throws Exception {
new ExpressionIterator("ei", "", SetOperator.INTERSECTION, false, false);
}
@Test (expected = IllegalArgumentException.class)
public void ctorNullOperator() throws Exception {
new ExpressionIterator("ei", "a + b", null, false, false);
}
@Test
public void aPlusBWithTwoSeries() throws Exception {
oneExtraSameE();
queryAB_Dstar();
remapResults();
ExpressionIterator exp = new ExpressionIterator("ei", "a + b",
SetOperator.INTERSECTION, false, false);
exp.addResults("a", iterators.get("a"));
exp.addResults("b", iterators.get("b"));
exp.compile();
final ExpressionDataPoint[] dps = exp.values();
assertEquals(2, dps.length);
validateMeta(dps, true);
long ts = 1431561600000L;
double[] values = new double[] { 12, 18 };
long its = exp.nextTimestamp();
while (exp.hasNext()) {
exp.next(its);
assertEquals(ts, dps[0].timestamp());
assertEquals(ts, dps[1].timestamp());
assertEquals(values[0], dps[0].toDouble(), 0.0001);
assertEquals(values[1], dps[1].toDouble(), 0.0001);
values[0] += 2;
values[1] += 2;
ts += 60000;
its = exp.nextTimestamp();
}
for (int i = 0; i < dps.length; i++) {
assertEquals(2, dps[i].tags().size());
assertTrue(dps[i].aggregatedTags().isEmpty());
}
assertArrayEquals(TAGV_UIDS.get("D"), dps[0].tags().get(TAGV_UIDS.get("D")));
assertArrayEquals(TAGV_UIDS.get("F"), dps[1].tags().get(TAGV_UIDS.get("D")));
}
@Test
public void aMinusBWithTwoSeries() throws Exception {
oneExtraSameE();
queryAB_Dstar();
remapResults();
ExpressionIterator exp = new ExpressionIterator("ei", "a - b",
SetOperator.INTERSECTION, false, false);
exp.addResults("a", iterators.get("a"));
exp.addResults("b", iterators.get("b"));
exp.compile();
final ExpressionDataPoint[] dps = exp.values();
assertEquals(2, dps.length);
validateMeta(dps, true);
long ts = 1431561600000L;
long its = exp.nextTimestamp();
while (exp.hasNext()) {
exp.next(its);
assertEquals(ts, dps[0].timestamp());
assertEquals(ts, dps[1].timestamp());
assertEquals(-10, dps[0].toDouble(), 0.0001);
assertEquals(-10, dps[1].toDouble(), 0.0001);
ts += 60000;
its = exp.nextTimestamp();
}
for (int i = 0; i < dps.length; i++) {
assertEquals(2, dps[i].tags().size());
assertTrue(dps[i].aggregatedTags().isEmpty());
}
assertArrayEquals(TAGV_UIDS.get("D"), dps[0].tags().get(TAGV_UIDS.get("D")));
assertArrayEquals(TAGV_UIDS.get("F"), dps[1].tags().get(TAGV_UIDS.get("D")));
}
@Test
public void aTimesBWithTwoSeries() throws Exception {
oneExtraSameE();
queryAB_Dstar();
remapResults();
ExpressionIterator exp = new ExpressionIterator("ei", "a * b",
SetOperator.INTERSECTION, false, false);
exp.addResults("a", iterators.get("a"));
exp.addResults("b", iterators.get("b"));
exp.compile();
final ExpressionDataPoint[] dps = exp.values();
assertEquals(2, dps.length);
validateMeta(dps, true);
long ts = 1431561600000L;
long its = exp.nextTimestamp();
exp.next(its);
assertEquals(ts, dps[0].timestamp());
assertEquals(ts, dps[1].timestamp());
assertEquals(11, dps[0].toDouble(), 0.0001);
assertEquals(56, dps[1].toDouble(), 0.0001);
ts += 60000;
its = exp.nextTimestamp();
exp.next(its);
assertEquals(ts, dps[0].timestamp());
assertEquals(ts, dps[1].timestamp());
assertEquals(24, dps[0].toDouble(), 0.0001);
assertEquals(75, dps[1].toDouble(), 0.0001);
ts += 60000;
its = exp.nextTimestamp();
exp.next(its);
assertEquals(ts, dps[0].timestamp());
assertEquals(ts, dps[1].timestamp());
assertEquals(39, dps[0].toDouble(), 0.0001);
assertEquals(96, dps[1].toDouble(), 0.0001);
assertFalse(exp.hasNext());
for (int i = 0; i < dps.length; i++) {
assertEquals(2, dps[i].tags().size());
assertTrue(dps[i].aggregatedTags().isEmpty());
}
assertArrayEquals(TAGV_UIDS.get("D"), dps[0].tags().get(TAGV_UIDS.get("D")));
assertArrayEquals(TAGV_UIDS.get("F"), dps[1].tags().get(TAGV_UIDS.get("D")));
}
@Test
public void aDivideBWithTwoSeries() throws Exception {
oneExtraSameE();
queryAB_Dstar();
remapResults();
ExpressionIterator exp = new ExpressionIterator("ei", "a / b",
SetOperator.INTERSECTION, false, false);
exp.addResults("a", iterators.get("a"));
exp.addResults("b", iterators.get("b"));
exp.compile();
final ExpressionDataPoint[] dps = exp.values();
assertEquals(2, dps.length);
validateMeta(dps, true);
long ts = 1431561600000L;
long its = exp.nextTimestamp();
exp.next(its);
assertEquals(ts, dps[0].timestamp());
assertEquals(ts, dps[1].timestamp());
assertEquals(0.0909, dps[0].toDouble(), 0.0001);
assertEquals(0.2857, dps[1].toDouble(), 0.0001);
ts += 60000;
its = exp.nextTimestamp();
exp.next(its);
assertEquals(ts, dps[0].timestamp());
assertEquals(ts, dps[1].timestamp());
assertEquals(0.1666, dps[0].toDouble(), 0.0001);
assertEquals(0.3333, dps[1].toDouble(), 0.0001);
ts += 60000;
its = exp.nextTimestamp();
exp.next(its);
assertEquals(ts, dps[0].timestamp());
assertEquals(ts, dps[1].timestamp());
assertEquals(0.2307, dps[0].toDouble(), 0.0001);
assertEquals(0.375, dps[1].toDouble(), 0.0001);
assertFalse(exp.hasNext());
for (int i = 0; i < dps.length; i++) {
assertEquals(2, dps[i].tags().size());
assertTrue(dps[i].aggregatedTags().isEmpty());
}
assertArrayEquals(TAGV_UIDS.get("D"), dps[0].tags().get(TAGV_UIDS.get("D")));
assertArrayEquals(TAGV_UIDS.get("F"), dps[1].tags().get(TAGV_UIDS.get("D")));
}
@Test
public void aModBWithTwoSeries() throws Exception {
oneExtraSameE();
queryAB_Dstar();
remapResults();
ExpressionIterator exp = new ExpressionIterator("ei", "a % b",
SetOperator.INTERSECTION, false, false);
exp.addResults("a", iterators.get("a"));
exp.addResults("b", iterators.get("b"));
exp.compile();
final ExpressionDataPoint[] dps = exp.values();
assertEquals(2, dps.length);
validateMeta(dps, true);
long ts = 1431561600000L;
long its = exp.nextTimestamp();
double[] values = new double[] { 1, 4 };
while (exp.hasNext()) {
exp.next(its);
assertEquals(ts, dps[0].timestamp());
assertEquals(ts, dps[1].timestamp());
assertEquals(values[0]++, dps[0].toDouble(), 0.0001);
assertEquals(values[1]++, dps[1].toDouble(), 0.0001);
ts += 60000;
its = exp.nextTimestamp();
}
for (int i = 0; i < dps.length; i++) {
assertEquals(2, dps[i].tags().size());
assertTrue(dps[i].aggregatedTags().isEmpty());
}
assertArrayEquals(TAGV_UIDS.get("D"), dps[0].tags().get(TAGV_UIDS.get("D")));
assertArrayEquals(TAGV_UIDS.get("F"), dps[1].tags().get(TAGV_UIDS.get("D")));
}
@Test
public void aDivideByZeroWithTwoSeries() throws Exception {
oneExtraSameE();
queryAB_Dstar();
remapResults();
// Jexl apparently happily allows this, just emits a zero
ExpressionIterator exp = new ExpressionIterator("ei", "a / 0",
SetOperator.INTERSECTION, false, false);
exp.addResults("a", iterators.get("a"));
exp.addResults("b", iterators.get("b"));
exp.compile();
final ExpressionDataPoint[] dps = exp.values();
assertEquals(2, dps.length);
validateMeta(dps, true);
long ts = 1431561600000L;
long its = exp.nextTimestamp();
while (exp.hasNext()) {
exp.next(its);
assertEquals(ts, dps[0].timestamp());
assertEquals(ts, dps[1].timestamp());
assertEquals(0, dps[0].toDouble(), 0.0001);
assertEquals(0, dps[1].toDouble(), 0.0001);
ts += 60000;
its = exp.nextTimestamp();
}
for (int i = 0; i < dps.length; i++) {
assertEquals(2, dps[i].tags().size());
assertTrue(dps[i].aggregatedTags().isEmpty());
}
assertArrayEquals(TAGV_UIDS.get("D"), dps[0].tags().get(TAGV_UIDS.get("D")));
assertArrayEquals(TAGV_UIDS.get("F"), dps[1].tags().get(TAGV_UIDS.get("D")));
}
@Test
public void doubleVariableAndPrecedence() throws Exception {
oneExtraSameE();
queryAB_Dstar();
remapResults();
ExpressionIterator exp = new ExpressionIterator("ei", "a + (b * b)",
SetOperator.INTERSECTION, false, false);
exp.addResults("a", iterators.get("a"));
exp.addResults("b", iterators.get("b"));
exp.compile();
final ExpressionDataPoint[] dps = exp.values();
assertEquals(2, dps.length);
validateMeta(dps, true);
long ts = 1431561600000L;
long its = exp.nextTimestamp();
exp.next(its);
assertEquals(ts, dps[0].timestamp());
assertEquals(ts, dps[1].timestamp());
assertEquals(122, dps[0].toDouble(), 0.0001);
assertEquals(200, dps[1].toDouble(), 0.0001);
ts += 60000;
its = exp.nextTimestamp();
exp.next(its);
assertEquals(ts, dps[0].timestamp());
assertEquals(ts, dps[1].timestamp());
assertEquals(146, dps[0].toDouble(), 0.0001);
assertEquals(230, dps[1].toDouble(), 0.0001);
ts += 60000;
its = exp.nextTimestamp();
exp.next(its);
assertEquals(ts, dps[0].timestamp());
assertEquals(ts, dps[1].timestamp());
assertEquals(172, dps[0].toDouble(), 0.0001);
assertEquals(262, dps[1].toDouble(), 0.0001);
assertFalse(exp.hasNext());
for (int i = 0; i < dps.length; i++) {
assertEquals(2, dps[i].tags().size());
assertTrue(dps[i].aggregatedTags().isEmpty());
}
assertArrayEquals(TAGV_UIDS.get("D"), dps[0].tags().get(TAGV_UIDS.get("D")));
assertArrayEquals(TAGV_UIDS.get("F"), dps[1].tags().get(TAGV_UIDS.get("D")));
}
@Test
public void doubleVariableAndPrecedenceChanged() throws Exception {
oneExtraSameE();
queryAB_Dstar();
remapResults();
ExpressionIterator exp = new ExpressionIterator("ei", "(a + b) * b",
SetOperator.INTERSECTION, false, false);
exp.addResults("a", iterators.get("a"));
exp.addResults("b", iterators.get("b"));
exp.compile();
final ExpressionDataPoint[] dps = exp.values();
assertEquals(2, dps.length);
validateMeta(dps, true);
long ts = 1431561600000L;
long its = exp.nextTimestamp();
exp.next(its);
assertEquals(ts, dps[0].timestamp());
assertEquals(ts, dps[1].timestamp());
assertEquals(132, dps[0].toDouble(), 0.0001);
assertEquals(252, dps[1].toDouble(), 0.0001);
ts += 60000;
its = exp.nextTimestamp();
exp.next(its);
assertEquals(ts, dps[0].timestamp());
assertEquals(ts, dps[1].timestamp());
assertEquals(168, dps[0].toDouble(), 0.0001);
assertEquals(300, dps[1].toDouble(), 0.0001);
ts += 60000;
its = exp.nextTimestamp();
exp.next(its);
assertEquals(ts, dps[0].timestamp());
assertEquals(ts, dps[1].timestamp());
assertEquals(208, dps[0].toDouble(), 0.0001);
assertEquals(352, dps[1].toDouble(), 0.0001);
assertFalse(exp.hasNext());
for (int i = 0; i < dps.length; i++) {
assertEquals(2, dps[i].tags().size());
assertTrue(dps[i].aggregatedTags().isEmpty());
}
assertArrayEquals(TAGV_UIDS.get("D"), dps[0].tags().get(TAGV_UIDS.get("D")));
assertArrayEquals(TAGV_UIDS.get("F"), dps[1].tags().get(TAGV_UIDS.get("D")));
}
@Test
public void aPlusScalarDropB() throws Exception {
oneExtraSameE();
queryAB_Dstar();
remapResults();
ExpressionIterator exp = new ExpressionIterator("ei", "a + 1",
SetOperator.INTERSECTION, false, false);
exp.addResults("a", iterators.get("a"));
exp.addResults("b", iterators.get("b"));
exp.compile();
final ExpressionDataPoint[] dps = exp.values();
assertEquals(2, dps.length);
validateMeta(dps, true);
long ts = 1431561600000L;
double[] values = new double[] { 2, 5 };
long its = exp.nextTimestamp();
while (exp.hasNext()) {
exp.next(its);
assertEquals(ts, dps[0].timestamp());
assertEquals(ts, dps[1].timestamp());
assertEquals(values[0]++, dps[0].toDouble(), 0.0001);
assertEquals(values[1]++, dps[1].toDouble(), 0.0001);
ts += 60000;
its = exp.nextTimestamp();
}
for (int i = 0; i < dps.length; i++) {
assertEquals(2, dps[i].tags().size());
assertTrue(dps[i].aggregatedTags().isEmpty());
}
assertArrayEquals(TAGV_UIDS.get("D"), dps[0].tags().get(TAGV_UIDS.get("D")));
assertArrayEquals(TAGV_UIDS.get("F"), dps[1].tags().get(TAGV_UIDS.get("D")));
}
@Test (expected = IllegalArgumentException.class)
public void missingRequiredVariable() throws Exception {
oneExtraSameE();
queryAB_Dstar();
remapResults();
ExpressionIterator exp = new ExpressionIterator("ei", "a + b + c",
SetOperator.INTERSECTION, false, false);
exp.addResults("a", iterators.get("a"));
exp.addResults("b", iterators.get("b"));
exp.compile();
}
@Test
public void aPlusBMissingPointsDefaultFillZero() throws Exception {
threeSameEGaps();
queryAB_Dstar();
remapResults();
ExpressionIterator exp = new ExpressionIterator("ei", "a + b",
SetOperator.INTERSECTION, false, false);
exp.addResults("a", iterators.get("a"));
exp.addResults("b", iterators.get("b"));
exp.compile();
final ExpressionDataPoint[] dps = exp.values();
assertEquals(3, dps.length);
validateMeta(dps, true);
long ts = 1431561600000L;
long its = exp.nextTimestamp();
exp.next(its);
assertEquals(ts, dps[0].timestamp());
assertEquals(ts, dps[1].timestamp());
assertEquals(ts, dps[2].timestamp());
assertEquals(1, dps[0].toDouble(), 0.0001);
assertEquals(4, dps[1].toDouble(), 0.0001);
assertEquals(0, dps[2].toDouble(), 0.0001);
ts += 60000;
its = exp.nextTimestamp();
exp.next(its);
assertEquals(ts, dps[0].timestamp());
assertEquals(ts, dps[1].timestamp());
assertEquals(ts, dps[2].timestamp());
assertEquals(0, dps[0].toDouble(), 0.0001);
assertEquals(20, dps[1].toDouble(), 0.0001);
assertEquals(8, dps[2].toDouble(), 0.0001);
ts += 60000;
its = exp.nextTimestamp();
exp.next(its);
assertEquals(ts, dps[0].timestamp());
assertEquals(ts, dps[1].timestamp());
assertEquals(ts, dps[2].timestamp());
assertEquals(16, dps[0].toDouble(), 0.0001);
assertEquals(0, dps[1].toDouble(), 0.0001);
assertEquals(28, dps[2].toDouble(), 0.0001);
assertFalse(exp.hasNext());
for (int i = 0; i < dps.length; i++) {
assertEquals(2, dps[i].tags().size());
assertTrue(dps[i].aggregatedTags().isEmpty());
}
assertArrayEquals(TAGV_UIDS.get("D"), dps[0].tags().get(TAGV_UIDS.get("D")));
assertArrayEquals(TAGV_UIDS.get("F"), dps[1].tags().get(TAGV_UIDS.get("D")));
assertArrayEquals(TAGV_UIDS.get("G"), dps[2].tags().get(TAGV_UIDS.get("D")));
}
@Test
public void aPlusBMissingPointsFillOne() throws Exception {
threeSameEGaps();
queryAB_Dstar();
remapResults();
ExpressionIterator exp = new ExpressionIterator("ei", "a + b",
SetOperator.INTERSECTION, false, false);
exp.addResults("a", iterators.get("a"));
exp.addResults("b", iterators.get("b"));
iterators.get("a").setFillPolicy(new NumericFillPolicy(FillPolicy.SCALAR, 1));
iterators.get("b").setFillPolicy(new NumericFillPolicy(FillPolicy.SCALAR, 1));
exp.compile();
final ExpressionDataPoint[] dps = exp.values();
assertEquals(3, dps.length);
validateMeta(dps, true);
long ts = 1431561600000L;
long its = exp.nextTimestamp();
exp.next(its);
assertEquals(ts, dps[0].timestamp());
assertEquals(ts, dps[1].timestamp());
assertEquals(ts, dps[2].timestamp());
assertEquals(2, dps[0].toDouble(), 0.0001);
assertEquals(5, dps[1].toDouble(), 0.0001);
assertEquals(2, dps[2].toDouble(), 0.0001);
ts += 60000;
its = exp.nextTimestamp();
exp.next(its);
assertEquals(ts, dps[0].timestamp());
assertEquals(ts, dps[1].timestamp());
assertEquals(ts, dps[2].timestamp());
assertEquals(2, dps[0].toDouble(), 0.0001);
assertEquals(20, dps[1].toDouble(), 0.0001);
assertEquals(9, dps[2].toDouble(), 0.0001);
ts += 60000;
its = exp.nextTimestamp();
exp.next(its);
assertEquals(ts, dps[0].timestamp());
assertEquals(ts, dps[1].timestamp());
assertEquals(ts, dps[2].timestamp());
assertEquals(16, dps[0].toDouble(), 0.0001);
assertEquals(2, dps[1].toDouble(), 0.0001);
assertEquals(28, dps[2].toDouble(), 0.0001);
assertFalse(exp.hasNext());
for (int i = 0; i < dps.length; i++) {
assertEquals(2, dps[i].tags().size());
assertTrue(dps[i].aggregatedTags().isEmpty());
}
assertArrayEquals(TAGV_UIDS.get("D"), dps[0].tags().get(TAGV_UIDS.get("D")));
assertArrayEquals(TAGV_UIDS.get("F"), dps[1].tags().get(TAGV_UIDS.get("D")));
assertArrayEquals(TAGV_UIDS.get("G"), dps[2].tags().get(TAGV_UIDS.get("D")));
}
@Test
public void aPlusBMissingPointsFillInfectiousNaN() throws Exception {
threeSameEGaps();
queryAB_Dstar();
remapResults();
ExpressionIterator exp = new ExpressionIterator("ei", "a + b",
SetOperator.INTERSECTION, false, false);
exp.addResults("a", iterators.get("a"));
exp.addResults("b", iterators.get("b"));
iterators.get("a").setFillPolicy(
new NumericFillPolicy(FillPolicy.NOT_A_NUMBER, Double.NaN));
iterators.get("b").setFillPolicy(
new NumericFillPolicy(FillPolicy.NOT_A_NUMBER, Double.NaN));
exp.compile();
final ExpressionDataPoint[] dps = exp.values();
assertEquals(3, dps.length);
validateMeta(dps, true);
long ts = 1431561600000L;
long its = exp.nextTimestamp();
exp.next(its);
assertEquals(ts, dps[0].timestamp());
assertEquals(ts, dps[1].timestamp());
assertEquals(ts, dps[2].timestamp());
assertTrue(Double.isNaN(dps[0].toDouble()));
assertTrue(Double.isNaN(dps[1].toDouble()));
assertTrue(Double.isNaN(dps[2].toDouble()));
ts += 60000;
its = exp.nextTimestamp();
exp.next(its);
assertEquals(ts, dps[0].timestamp());
assertEquals(ts, dps[1].timestamp());
assertEquals(ts, dps[2].timestamp());
assertTrue(Double.isNaN(dps[0].toDouble()));
assertEquals(20, dps[1].toDouble(), 0.0001);
assertTrue(Double.isNaN(dps[2].toDouble()));
ts += 60000;
its = exp.nextTimestamp();
exp.next(its);
assertEquals(ts, dps[0].timestamp());
assertEquals(ts, dps[1].timestamp());
assertEquals(ts, dps[2].timestamp());
assertEquals(16, dps[0].toDouble(), 0.0001);
assertTrue(Double.isNaN(dps[1].toDouble()));
assertEquals(28, dps[2].toDouble(), 0.0001);
assertFalse(exp.hasNext());
for (int i = 0; i < dps.length; i++) {
assertEquals(2, dps[i].tags().size());
assertTrue(dps[i].aggregatedTags().isEmpty());
}
assertArrayEquals(TAGV_UIDS.get("D"), dps[0].tags().get(TAGV_UIDS.get("D")));
assertArrayEquals(TAGV_UIDS.get("F"), dps[1].tags().get(TAGV_UIDS.get("D")));
assertArrayEquals(TAGV_UIDS.get("G"), dps[2].tags().get(TAGV_UIDS.get("D")));
}
@Test
public void aPlusBResultsOffsetDefaultFill() throws Exception {
timeOffset();
queryAB_Dstar();
remapResults();
ExpressionIterator exp = new ExpressionIterator("ei", "a + b",
SetOperator.INTERSECTION, false, false);
exp.addResults("a", iterators.get("a"));
exp.addResults("b", iterators.get("b"));
exp.compile();
final ExpressionDataPoint[] dps = exp.values();
assertEquals(2, dps.length);
validateMeta(dps, true);
long ts = 1431561600000L;
long its = exp.nextTimestamp();
exp.next(its);
assertEquals(ts, dps[0].timestamp());
assertEquals(ts, dps[1].timestamp());
assertEquals(1, dps[0].toDouble(), 0.0001);
assertEquals(4, dps[1].toDouble(), 0.0001);
ts += 60000;
its = exp.nextTimestamp();
exp.next(its);
assertEquals(ts, dps[0].timestamp());
assertEquals(ts, dps[1].timestamp());
assertEquals(2, dps[0].toDouble(), 0.0001);
assertEquals(5, dps[1].toDouble(), 0.0001);
ts += 60000;
its = exp.nextTimestamp();
exp.next(its);
assertEquals(ts, dps[0].timestamp());
assertEquals(ts, dps[1].timestamp());
assertEquals(13, dps[0].toDouble(), 0.0001);
assertEquals(16, dps[1].toDouble(), 0.0001);
ts += 60000;
its = exp.nextTimestamp();
exp.next(its);
assertEquals(ts, dps[0].timestamp());
assertEquals(ts, dps[1].timestamp());
assertEquals(14, dps[0].toDouble(), 0.0001);
assertEquals(17, dps[1].toDouble(), 0.0001);
assertFalse(exp.hasNext());
for (int i = 0; i < dps.length; i++) {
assertEquals(2, dps[i].tags().size());
assertTrue(dps[i].aggregatedTags().isEmpty());
}
assertArrayEquals(TAGV_UIDS.get("D"), dps[0].tags().get(TAGV_UIDS.get("D")));
assertArrayEquals(TAGV_UIDS.get("F"), dps[1].tags().get(TAGV_UIDS.get("D")));
}
@Test
public void aPlusBOneAggedOneTaggedUseQueryTagsWoutQueryTags() throws Exception {
oneAggedTheOtherTagged();
queryAB_AggAll();
remapResults();
ExpressionIterator exp = new ExpressionIterator("ei", "a + b",
SetOperator.INTERSECTION, true, false);
exp.addResults("a", iterators.get("a"));
exp.addResults("b", iterators.get("b"));
exp.compile();
final ExpressionDataPoint[] dps = exp.values();
assertEquals(1, dps.length);
// TODO - fix the TODO in the set operators to join tags
//validateMeta(dps, true);
long ts = 1431561600000L;
double value = 13;
long its = exp.nextTimestamp();
while (exp.hasNext()) {
exp.next(its);
assertEquals(ts, dps[0].timestamp());
assertEquals(value, dps[0].toDouble(), 0.0001);
value += 3;
ts += 60000;
its = exp.nextTimestamp();
}
// TODO - fix the TODO in the set operators to join tags
//assertEquals(0, dps[0].tags().size());
assertEquals(2, dps[0].aggregatedTags().size());
assertTrue(dps[0].aggregatedTags().contains(TAGV_UIDS.get("D")));
assertTrue(dps[0].aggregatedTags().contains(TAGV_UIDS.get("E")));
// TODO - make sure the tags are empty once the expression data does it's
// thing
//assertTrue(dps[0].tags().isEmpty());
}
@Test
public void singleNestedExpression() throws Exception {
oneExtraSameE();
queryAB_Dstar();
remapResults();
ExpressionIterator ei = new ExpressionIterator("ei", "a + b",
SetOperator.INTERSECTION, false, false);
ei.addResults("a", iterators.get("a"));
ei.addResults("b", iterators.get("b"));
ei.compile();
ExpressionIterator exp = new ExpressionIterator("ei", "x * 2",
SetOperator.INTERSECTION, false, false);
exp.addResults("x", ei);
exp.compile();
final ExpressionDataPoint[] dps = exp.values();
assertEquals(2, dps.length);
validateMeta(dps, true);
long ts = 1431561600000L;
double[] values = new double[] { 24, 36 };
long its = exp.nextTimestamp();
while (exp.hasNext()) {
exp.next(its);
assertEquals(ts, dps[0].timestamp());
assertEquals(ts, dps[1].timestamp());
assertEquals(values[0], dps[0].toDouble(), 0.0001);
assertEquals(values[1], dps[1].toDouble(), 0.0001);
values[0] += 4;
values[1] += 4;
ts += 60000;
its = exp.nextTimestamp();
}
for (int i = 0; i < dps.length; i++) {
assertEquals(2, dps[i].tags().size());
assertTrue(dps[i].aggregatedTags().isEmpty());
}
assertArrayEquals(TAGV_UIDS.get("D"), dps[0].tags().get(TAGV_UIDS.get("D")));
assertArrayEquals(TAGV_UIDS.get("F"), dps[1].tags().get(TAGV_UIDS.get("D")));
}
@Test
public void doubleNestedExpression() throws Exception {
oneExtraSameE();
queryAB_Dstar();
remapResults();
ExpressionIterator e1 = new ExpressionIterator("e1", "a + b",
SetOperator.INTERSECTION, false, false);
e1.addResults("a", iterators.get("a"));
e1.addResults("b", iterators.get("b"));
e1.compile();
ExpressionIterator e2 = new ExpressionIterator("e2", "e1 * 2",
SetOperator.INTERSECTION, false, false);
e2.addResults("e1", e1);
e2.compile();
ExpressionIterator e3 = new ExpressionIterator("e3", "e2 * 2",
SetOperator.INTERSECTION, false, false);
e3.addResults("e2", e2);
e3.compile();
final ExpressionDataPoint[] dps = e3.values();
assertEquals(2, dps.length);
validateMeta(dps, true);
long ts = 1431561600000L;
double[] values = new double[] { 48, 72 };
long its = e3.nextTimestamp();
while (e3.hasNext()) {
e3.next(its);
assertEquals(ts, dps[0].timestamp());
assertEquals(ts, dps[1].timestamp());
assertEquals(values[0], dps[0].toDouble(), 0.0001);
assertEquals(values[1], dps[1].toDouble(), 0.0001);
values[0] += 8;
values[1] += 8;
ts += 60000;
its = e3.nextTimestamp();
}
for (int i = 0; i < dps.length; i++) {
assertEquals(2, dps[i].tags().size());
assertTrue(dps[i].aggregatedTags().isEmpty());
}
assertArrayEquals(TAGV_UIDS.get("D"), dps[0].tags().get(TAGV_UIDS.get("D")));
assertArrayEquals(TAGV_UIDS.get("F"), dps[1].tags().get(TAGV_UIDS.get("D")));
}
@Test (expected = IllegalDataException.class)
public void noIntersectionFound() throws Exception {
threeDifE();
queryAB_Dstar();
remapResults();
ExpressionIterator exp = new ExpressionIterator("ei", "a + b",
SetOperator.INTERSECTION, false, false);
exp.addResults("a", iterators.get("a"));
exp.addResults("b", iterators.get("b"));
exp.compile();
}
@Test (expected = IllegalArgumentException.class)
public void addResultsMissingId() throws Exception {
oneExtraSameE();
queryAB_Dstar();
ExpressionIterator exp = new ExpressionIterator("ei", "a + b + c",
SetOperator.INTERSECTION, false, false);
exp.addResults("a", iterators.get("a"));
}
@Test (expected = IllegalArgumentException.class)
public void addResultsMissingSubQuery() throws Exception {
oneExtraSameE();
queryAB_Dstar();
ExpressionIterator exp = new ExpressionIterator("ei", "a + b + c",
SetOperator.INTERSECTION, false, false);
exp.addResults("a", iterators.get("a"));
}
@Test (expected = IllegalArgumentException.class)
public void addResultsMissingResults() throws Exception {
oneExtraSameE();
queryAB_Dstar();
ExpressionIterator exp = new ExpressionIterator("ei", "a + b + c",
SetOperator.INTERSECTION, false, false);
exp.addResults("a", iterators.get("a"));
}
@Test
public void unionOneExtraSeries() throws Exception {
oneExtraSameE();
queryAB_Dstar();
remapResults();
ExpressionIterator exp = new ExpressionIterator("ei", "a + b",
SetOperator.UNION, false, false);
exp.addResults("a", iterators.get("a"));
exp.addResults("b", iterators.get("b"));
exp.compile();
final ExpressionDataPoint[] dps = exp.values();
assertEquals(3, dps.length);
// TODO - fix the TODO in the set operators to join tags
//validateMeta(dps, true);
long ts = 1431561600000L;
double[] values = new double[] { 12, 18, 17 };
long its = exp.nextTimestamp();
while (exp.hasNext()) {
exp.next(its);
assertEquals(ts, dps[0].timestamp());
assertEquals(ts, dps[1].timestamp());
assertEquals(ts, dps[2].timestamp());
assertEquals(values[0], dps[0].toDouble(), 0.0001);
assertEquals(values[1], dps[1].toDouble(), 0.0001);
assertEquals(values[2], dps[2].toDouble(), 0.0001);
values[0] += 2;
values[1] += 2;
values[2] += 1;
ts += 60000;
its = exp.nextTimestamp();
}
for (int i = 0; i < dps.length; i++) {
// TODO - fix the TODO in the set operators to join tags
//assertEquals(2, dps[i].tags().size());
assertTrue(dps[i].aggregatedTags().isEmpty());
}
assertArrayEquals(TAGV_UIDS.get("D"), dps[0].tags().get(TAGV_UIDS.get("D")));
assertArrayEquals(TAGV_UIDS.get("F"), dps[1].tags().get(TAGV_UIDS.get("D")));
}
@Test
public void unionOffset() throws Exception {
timeOffset();
queryAB_Dstar();
remapResults();
ExpressionIterator exp = new ExpressionIterator("ei", "a + b",
SetOperator.UNION, false, false);
exp.addResults("a", iterators.get("a"));
exp.addResults("b", iterators.get("b"));
exp.compile();
final ExpressionDataPoint[] dps = exp.values();
assertEquals(2, dps.length);
validateMeta(dps, true);
long ts = 1431561600000L;
long its = exp.nextTimestamp();
exp.next(its);
assertEquals(ts, dps[0].timestamp());
assertEquals(ts, dps[1].timestamp());
assertEquals(1, dps[0].toDouble(), 0.0001);
assertEquals(4, dps[1].toDouble(), 0.0001);
ts += 60000;
its = exp.nextTimestamp();
exp.next(its);
assertEquals(ts, dps[0].timestamp());
assertEquals(ts, dps[1].timestamp());
assertEquals(2, dps[0].toDouble(), 0.0001);
assertEquals(5, dps[1].toDouble(), 0.0001);
ts += 60000;
its = exp.nextTimestamp();
exp.next(its);
assertEquals(ts, dps[0].timestamp());
assertEquals(ts, dps[1].timestamp());
assertEquals(13, dps[0].toDouble(), 0.0001);
assertEquals(16, dps[1].toDouble(), 0.0001);
ts += 60000;
its = exp.nextTimestamp();
exp.next(its);
assertEquals(ts, dps[0].timestamp());
assertEquals(ts, dps[1].timestamp());
assertEquals(14, dps[0].toDouble(), 0.0001);
assertEquals(17, dps[1].toDouble(), 0.0001);
assertFalse(exp.hasNext());
for (int i = 0; i < dps.length; i++) {
assertEquals(2, dps[i].tags().size());
assertTrue(dps[i].aggregatedTags().isEmpty());
}
assertArrayEquals(TAGV_UIDS.get("D"), dps[0].tags().get(TAGV_UIDS.get("D")));
assertArrayEquals(TAGV_UIDS.get("F"), dps[1].tags().get(TAGV_UIDS.get("D")));
}
@Test
public void unionNoIntersection() throws Exception {
threeDifE();
queryAB_Dstar();
remapResults();
ExpressionIterator exp = new ExpressionIterator("ei", "a + b",
SetOperator.UNION, false, false);
exp.addResults("a", iterators.get("a"));
exp.addResults("b", iterators.get("b"));
exp.compile();
final ExpressionDataPoint[] dps = exp.values();
assertEquals(6, dps.length);
validateMeta(dps, false);
long ts = 1431561600000L;
double[] values = new double[] { 1, 11, 4, 14, 7, 17 };
long its = exp.nextTimestamp();
while (exp.hasNext()) {
exp.next(its);
for (int i = 0; i < values.length; i++) {
assertEquals(ts, dps[i].timestamp());
assertEquals(values[i], dps[i].toDouble(), 0.0001);
++values[i];
}
ts += 60000;
its = exp.nextTimestamp();
}
}
@Test
public void unionSingleSeriesIteration() throws Exception {
oneExtraSameE();
queryAB_Dstar();
remapResults();
ExpressionIterator exp = new ExpressionIterator("ei", "a + b",
SetOperator.UNION, false, false);
exp.addResults("a", iterators.get("a"));
exp.addResults("b", iterators.get("b"));
exp.compile();
final ExpressionDataPoint[] dps = exp.values();
double[] values = new double[] { 12, 18, 17 };
for (int i = 0; i < dps.length; i++) {
long ts = 1431561600000L;
while (exp.hasNext(i)) {
exp.next(i);
assertEquals(ts, dps[i].timestamp());
assertEquals(values[i], dps[i].toDouble(), 0.001);
ts += 60000;
if (i < dps.length - 1) {
values[i] += 2;
} else {
values[i]++;
}
}
}
}
@Test
public void intersectionSingleSeriesIteration() throws Exception {
oneExtraSameE();
queryAB_Dstar();
remapResults();
ExpressionIterator exp = new ExpressionIterator("ei", "a + b",
SetOperator.INTERSECTION, false, false);
exp.addResults("a", iterators.get("a"));
exp.addResults("b", iterators.get("b"));
exp.compile();
final ExpressionDataPoint[] dps = exp.values();
double[] values = new double[] { 12, 18 };
for (int i = 0; i < dps.length; i++) {
long ts = 1431561600000L;
while (exp.hasNext(i)) {
exp.next(i);
assertEquals(ts, dps[i].timestamp());
assertEquals(values[i], dps[i].toDouble(), 0.001);
ts += 60000;
values[i] += 2;
}
}
}
@Test
public void aGreaterThanb() throws Exception {
oneExtraSameE();
queryAB_Dstar();
remapResults();
ExpressionIterator exp = new ExpressionIterator("ei", "a > b",
SetOperator.INTERSECTION, false, false);
exp.addResults("a", iterators.get("a"));
exp.addResults("b", iterators.get("b"));
exp.compile();
final ExpressionDataPoint[] dps = exp.values();
assertEquals(2, dps.length);
validateMeta(dps, true);
long ts = 1431561600000L;
double[] values = new double[] { 0, 0 };
long its = exp.nextTimestamp();
while (exp.hasNext()) {
exp.next(its);
assertEquals(ts, dps[0].timestamp());
assertEquals(ts, dps[1].timestamp());
assertEquals(values[0], dps[0].toDouble(), 0.0001);
assertEquals(values[1], dps[1].toDouble(), 0.0001);
ts += 60000;
its = exp.nextTimestamp();
}
for (int i = 0; i < dps.length; i++) {
assertEquals(2, dps[i].tags().size());
assertTrue(dps[i].aggregatedTags().isEmpty());
}
}
@Test
public void aLessThanb() throws Exception {
oneExtraSameE();
queryAB_Dstar();
remapResults();
ExpressionIterator exp = new ExpressionIterator("ei", "a < b",
SetOperator.INTERSECTION, false, false);
exp.addResults("a", iterators.get("a"));
exp.addResults("b", iterators.get("b"));
exp.compile();
final ExpressionDataPoint[] dps = exp.values();
assertEquals(2, dps.length);
validateMeta(dps, true);
long ts = 1431561600000L;
double[] values = new double[] { 1, 1 };
long its = exp.nextTimestamp();
while (exp.hasNext()) {
exp.next(its);
assertEquals(ts, dps[0].timestamp());
assertEquals(ts, dps[1].timestamp());
assertEquals(values[0], dps[0].toDouble(), 0.0001);
assertEquals(values[1], dps[1].toDouble(), 0.0001);
ts += 60000;
its = exp.nextTimestamp();
}
for (int i = 0; i < dps.length; i++) {
assertEquals(2, dps[i].tags().size());
assertTrue(dps[i].aggregatedTags().isEmpty());
}
}
/**
* Makes sure the series contain both metrics
* @param dps The results to validate
* @param common_e The common e
*/
private void validateMeta(final ExpressionDataPoint[] dps,
final boolean common_e) {
for (int i = 0; i < dps.length; i++) {
// TODO - change this guy to a byteset :( Since it's a bloody list we
// can't do a "contains" because it checks for the address of the byte
// arrays
boolean found = false;
for (final byte[] metric : dps[i].metricUIDs()) {
if (Bytes.memcmp(TAGV_UIDS.get("A"), metric) == 0) {
found = true;
} else if (Bytes.memcmp(TAGV_UIDS.get("B"), metric) == 0) {
found = true;
break;
}
}
if (!found) {
fail("Missing a metric");
}
if (common_e) {
assertArrayEquals(TAGV_UIDS.get("E"), dps[i].tags().get(TAGV_UIDS.get("E")));
}
}
}
private void remapResults() {
iterators.clear();
iterators.put("a", new TimeSyncedIterator("a",
query.getQueries().get(0).getFilterTagKs(), results.get("0").getValue()));
iterators.put("b", new TimeSyncedIterator("b",
query.getQueries().get(1).getFilterTagKs(), results.get("1").getValue()));
}
}