/*
* Copyright © 2014 Cask Data, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package co.cask.cdap.data2.dataset2.lib.timeseries;
import co.cask.cdap.api.common.Bytes;
import co.cask.cdap.api.dataset.lib.cube.DimensionValue;
import co.cask.cdap.api.dataset.lib.cube.MeasureType;
import co.cask.cdap.api.dataset.lib.cube.Measurement;
import co.cask.cdap.api.dataset.lib.cube.TimeValue;
import co.cask.cdap.api.dataset.table.Row;
import co.cask.cdap.api.dataset.table.Scanner;
import co.cask.cdap.data2.dataset2.lib.table.inmemory.InMemoryMetricsTable;
import co.cask.cdap.data2.dataset2.lib.table.inmemory.InMemoryTableService;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.collect.Table;
import org.junit.Assert;
import org.junit.Test;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Test base for {@link co.cask.cdap.data2.dataset2.lib.timeseries.FactTable}.
*/
public class FactTableTest {
@Test
public void testBasics() throws Exception {
InMemoryTableService.create("EntityTable");
InMemoryTableService.create("DataTable");
int resolution = 10;
int rollTimebaseInterval = 2;
FactTable table = new FactTable(new InMemoryMetricsTable("DataTable"),
new EntityTable(new InMemoryMetricsTable("EntityTable")),
resolution, rollTimebaseInterval);
// aligned to start of resolution bucket
// "/1000" because time is expected to be in seconds
long ts = ((System.currentTimeMillis() / 1000) / resolution) * resolution;
// testing encoding with multiple dims
List<DimensionValue> dimensionValues = ImmutableList.of(new DimensionValue("dim1", "value1"),
new DimensionValue("dim2", "value2"),
new DimensionValue("dim3", "value3"));
// trying adding one by one, in same (first) time resolution bucket
for (int i = 0; i < 5; i++) {
for (int k = 1; k < 4; k++) {
// note: "+i" here and below doesn't affect results, just to confirm
// that data points are rounded to the resolution
table.add(ImmutableList.of(new Fact(ts + i, dimensionValues,
new Measurement("metric" + k, MeasureType.COUNTER, k))));
}
}
// trying adding one by one, in different time resolution buckets
for (int i = 0; i < 3; i++) {
for (int k = 1; k < 4; k++) {
table.add(ImmutableList.of(new Fact(ts + resolution * i + i, dimensionValues,
new Measurement("metric" + k, MeasureType.COUNTER, 2 * k))));
}
}
// trying adding as list
// first incs in same (second) time resolution bucket
List<Fact> aggs = Lists.newArrayList();
for (int i = 0; i < 7; i++) {
for (int k = 1; k < 4; k++) {
aggs.add(new Fact(ts + resolution, dimensionValues, new Measurement("metric" + k, MeasureType.COUNTER, 3 * k)));
}
}
// then incs in different time resolution buckets
for (int i = 0; i < 3; i++) {
for (int k = 1; k < 4; k++) {
aggs.add(new Fact(ts + resolution * i, dimensionValues,
new Measurement("metric" + k, MeasureType.COUNTER, 4 * k)));
}
}
table.add(aggs);
// verify each metric
for (int k = 1; k < 4; k++) {
FactScan scan = new FactScan(ts - 2 * resolution, ts + 3 * resolution, "metric" + k, dimensionValues);
Table<String, List<DimensionValue>, List<TimeValue>> expected = HashBasedTable.create();
expected.put("metric" + k, dimensionValues, ImmutableList.of(new TimeValue(ts, 11 * k),
new TimeValue(ts + resolution, 27 * k),
new TimeValue(ts + 2 * resolution, 6 * k)));
assertScan(table, expected, scan);
}
// verify each metric within a single timeBase
for (int k = 1; k < 4; k++) {
FactScan scan = new FactScan(ts, ts + resolution - 1, "metric" + k, dimensionValues);
Table<String, List<DimensionValue>, List<TimeValue>> expected = HashBasedTable.create();
expected.put("metric" + k, dimensionValues, ImmutableList.of(new TimeValue(ts, 11 * k)));
assertScan(table, expected, scan);
}
// verify all metrics with fuzzy metric in scan
Table<String, List<DimensionValue>, List<TimeValue>> expected = HashBasedTable.create();
for (int k = 1; k < 4; k++) {
expected.put("metric" + k, dimensionValues, ImmutableList.of(new TimeValue(ts, 11 * k),
new TimeValue(ts + resolution, 27 * k),
new TimeValue(ts + 2 * resolution, 6 * k)));
}
// metric = null means "all"
FactScan scan = new FactScan(ts - 2 * resolution, ts + 3 * resolution, dimensionValues);
assertScan(table, expected, scan);
// delete metric test
expected.clear();
// delete the metrics data at (timestamp + 20) resolution
scan = new FactScan(ts + resolution * 2, ts + resolution * 3, dimensionValues);
table.delete(scan);
for (int k = 1; k < 4; k++) {
expected.put("metric" + k, dimensionValues, ImmutableList.of(new TimeValue(ts, 11 * k),
new TimeValue(ts + resolution, 27 * k)));
}
// verify deletion
scan = new FactScan(ts - 2 * resolution, ts + 3 * resolution, dimensionValues);
assertScan(table, expected, scan);
// delete metrics for "metric1" at ts0 and verify deletion
scan = new FactScan(ts, ts + 1, "metric1", dimensionValues);
table.delete(scan);
expected.clear();
expected.put("metric1", dimensionValues, ImmutableList.of(new TimeValue(ts + resolution, 27)));
scan = new FactScan(ts - 2 * resolution, ts + 3 * resolution, "metric1", dimensionValues);
assertScan(table, expected, scan);
// verify the next dims search
Collection<DimensionValue> nextTags =
table.findSingleDimensionValue(ImmutableList.of("dim1", "dim2", "dim3"),
ImmutableMap.of("dim1", "value1"), ts, ts + 1);
Assert.assertEquals(ImmutableSet.of(new DimensionValue("dim2", "value2")), nextTags);
Map<String, String> slice = Maps.newHashMap();
slice.put("dim1", null);
nextTags = table.findSingleDimensionValue(ImmutableList.of("dim1", "dim2", "dim3"), slice, ts, ts + 1);
Assert.assertEquals(ImmutableSet.of(new DimensionValue("dim2", "value2")), nextTags);
nextTags = table.findSingleDimensionValue(ImmutableList.of("dim1", "dim2", "dim3"),
ImmutableMap.of("dim1", "value1", "dim2", "value2"), ts, ts + 3);
Assert.assertEquals(ImmutableSet.of(new DimensionValue("dim3", "value3")), nextTags);
// add new dim values
dimensionValues = ImmutableList.of(new DimensionValue("dim1", "value1"),
new DimensionValue("dim2", "value5"),
new DimensionValue("dim3", null));
table.add(ImmutableList.of(new Fact(ts, dimensionValues, new Measurement("metric", MeasureType.COUNTER, 10))));
dimensionValues = ImmutableList.of(new DimensionValue("dim1", "value1"),
new DimensionValue("dim2", null),
new DimensionValue("dim3", "value3"));
table.add(ImmutableList.of(new Fact(ts, dimensionValues, new Measurement("metric", MeasureType.COUNTER, 10))));
nextTags = table.findSingleDimensionValue(ImmutableList.of("dim1", "dim2", "dim3"),
ImmutableMap.of("dim1", "value1"), ts, ts + 1);
Assert.assertEquals(ImmutableSet.of(new DimensionValue("dim2", "value2"),
new DimensionValue("dim2", "value5"),
new DimensionValue("dim3", "value3")), nextTags);
// search for metric names given dims list and verify
Collection<String> metricNames =
table.findMeasureNames(ImmutableList.of("dim1", "dim2", "dim3"),
ImmutableMap.of("dim1", "value1", "dim2", "value2", "dim3", "value3"), ts, ts + 1);
Assert.assertEquals(ImmutableSet.of("metric2", "metric3"), metricNames);
metricNames = table.findMeasureNames(ImmutableList.of("dim1", "dim2", "dim3"),
ImmutableMap.of("dim1", "value1"), ts, ts + 1);
Assert.assertEquals(ImmutableSet.of("metric", "metric2", "metric3"), metricNames);
metricNames = table.findMeasureNames(ImmutableList.of("dim1", "dim2", "dim3"),
ImmutableMap.of("dim2", "value2"), ts, ts + 1);
Assert.assertEquals(ImmutableSet.of("metric2", "metric3"), metricNames);
metricNames = table.findMeasureNames(ImmutableList.of("dim1", "dim2", "dim3"),
slice, ts, ts + 1);
Assert.assertEquals(ImmutableSet.of("metric", "metric2", "metric3"), metricNames);
}
@Test
public void testSearch() throws Exception {
InMemoryTableService.create("SearchEntityTable");
InMemoryTableService.create("SearchDataTable");
int resolution = Integer.MAX_VALUE;
int rollTimebaseInterval = 2;
FactTable table = new FactTable(new InMemoryMetricsTable("SearchDataTable"),
new EntityTable(new InMemoryMetricsTable("SearchEntityTable")),
resolution, rollTimebaseInterval);
// aligned to start of resolution bucket
// "/1000" because time is expected to be in seconds
long ts = ((System.currentTimeMillis() / 1000) / resolution) * resolution;
List<String> aggregationList = ImmutableList.of("dim1", "dim2", "dim3", "dim4");
for (int i = 0; i < 2; i++) {
writeInc(table, "metric-a" + i, ts + i, i,
"dim1", "value1", "dim2", "value2", "dim3", "value3", "dim4", "value4");
writeInc(table, "metric-b" + i, ts + i, i,
"dim1", "value2", "dim2", "value2", "dim3", "x3", "dim4", "x4");
writeInc(table, "metric-c" + i, ts + i, i,
"dim1", "value2", "dim2", "value2", "dim3", null, "dim4", "y4");
writeInc(table, "metric-d" + i, ts + i, i,
"dim1", "value1", "dim2", "value3", "dim3", "y3", "dim4", null);
}
Map<String, String> slice = Maps.newHashMap();
slice.put("dim1", "value2");
slice.put("dim2", "value2");
slice.put("dim3", null);
// verify search dims
testTagSearch(table, aggregationList, ImmutableMap.of("dim2", "value2"),
ImmutableSet.of(new DimensionValue("dim1", "value1"), new DimensionValue("dim1", "value2")));
testTagSearch(table, aggregationList, ImmutableMap.of("dim1", "value1"),
ImmutableSet.of(new DimensionValue("dim2", "value2"), new DimensionValue("dim2", "value3")));
testTagSearch(table, aggregationList, ImmutableMap.<String, String>of(),
ImmutableSet.of(new DimensionValue("dim1", "value1"), new DimensionValue("dim1", "value2")));
testTagSearch(table, aggregationList, ImmutableMap.of("dim1", "value2", "dim2", "value2"),
ImmutableSet.of(new DimensionValue("dim3", "x3"), new DimensionValue("dim4", "y4")));
testTagSearch(table, aggregationList, slice,
ImmutableSet.of(new DimensionValue("dim4", "x4"), new DimensionValue("dim4", "y4")));
testTagSearch(table, aggregationList, ImmutableMap.of("dim1", "value2", "dim2", "value3", "dim3", "y3"),
ImmutableSet.<DimensionValue>of());
// verify search metrics
testMetricNamesSearch(table, aggregationList, ImmutableMap.of("dim1", "value1", "dim2", "value2", "dim3", "value3"),
ImmutableSet.<String>of("metric-a0", "metric-a1"));
testMetricNamesSearch(table, aggregationList, ImmutableMap.of("dim2", "value2"),
ImmutableSet.<String>of("metric-a0", "metric-a1", "metric-b0", "metric-b1",
"metric-c0", "metric-c1"));
testMetricNamesSearch(table, aggregationList, slice, ImmutableSet.of("metric-b0", "metric-b1",
"metric-c0", "metric-c1"));
}
private void testMetricNamesSearch(FactTable table, List<String> aggregationList ,
Map<String, String> sliceBy,
ImmutableSet<String> expectedResuls) throws Exception {
Collection<String> metricNames =
table.findMeasureNames(aggregationList, sliceBy, 0, 1);
Assert.assertEquals(expectedResuls, metricNames);
}
private void testTagSearch(FactTable table, List<String> aggregation, Map<String, String> sliceBy,
Set<DimensionValue> expectedResult) throws Exception {
// using 0, 1 as start and endTs as resolution is INT_MAX
Collection<DimensionValue> nextTags =
table.findSingleDimensionValue(aggregation, sliceBy, 0, 1);
Assert.assertEquals(expectedResult, nextTags);
}
@Test
public void testQuery() throws Exception {
InMemoryTableService.create("QueryEntityTable");
InMemoryTableService.create("QueryDataTable");
int resolution = 10;
int rollTimebaseInterval = 2;
FactTable table = new FactTable(new InMemoryMetricsTable("QueryDataTable"),
new EntityTable(new InMemoryMetricsTable("QueryEntityTable")),
resolution, rollTimebaseInterval);
// aligned to start of resolution bucket
// "/1000" because time is expected to be in seconds
long ts = ((System.currentTimeMillis() / 1000) / resolution) * resolution;
for (int i = 0; i < 3; i++) {
for (int k = 1; k < 3; k++) {
// note: "+i" to ts here and below doesn't affect results, just to confirm
// that data points are rounded to the resolution
writeInc(table, "metric" + k, ts + i * resolution + i, k + i, "dim1", "value1", "dim2", "value2");
writeInc(table, "metric" + k, ts + i * resolution + i, 2 * k + i, "dim1", "value2", "dim2", "value2");
writeInc(table, "metric" + k, ts + i * resolution + i, 3 * k + i, "dim1", "value2", "dim2", "value1");
writeInc(table, "metric" + k, ts + i * resolution + i, 4 * k + i, "dim1", "value1", "dim2", "value3");
// null value in dim matches only fuzzy ("any")
writeInc(table, "metric" + k, ts + i * resolution + i, 5 * k + i, "dim1", null, "dim2", "value3");
}
}
Table<String, List<DimensionValue>, List<TimeValue>> expected;
FactScan scan;
// simple single metric scan
for (int i = 1; i < 3; i++) {
// all time points
scan = new FactScan(ts - resolution, ts + 3 * resolution,
"metric" + i, dimValues("dim1", "value1", "dim2", "value2"));
expected = HashBasedTable.create();
expected.put("metric" + i, dimValues("dim1", "value1", "dim2", "value2"),
timeValues(ts, resolution, i, i + 1, i + 2));
assertScan(table, expected, scan);
// time points since second interval
scan = new FactScan(ts + resolution, ts + 3 * resolution,
"metric" + i, dimValues("dim1", "value1", "dim2", "value2"));
expected = HashBasedTable.create();
expected.put("metric" + i, dimValues("dim1", "value1", "dim2", "value2"),
timeValues(ts + resolution, resolution, i + 1, i + 2));
assertScan(table, expected, scan);
// time points before third interval
scan = new FactScan(ts - resolution, ts + resolution,
"metric" + i, dimValues("dim1", "value1", "dim2", "value2"));
expected = HashBasedTable.create();
expected.put("metric" + i, dimValues("dim1", "value1", "dim2", "value2"),
timeValues(ts, resolution, i, i + 1));
assertScan(table, expected, scan);
// time points for fuzzy dim2 since second interval
scan = new FactScan(ts + resolution, ts + 3 * resolution,
// null stands for any
"metric" + i, dimValues("dim1", "value1", "dim2", null));
expected = HashBasedTable.create();
expected.put("metric" + i, dimValues("dim1", "value1", "dim2", "value2"),
timeValues(ts + resolution, resolution, i + 1, i + 2));
expected.put("metric" + i, dimValues("dim1", "value1", "dim2", "value3"),
timeValues(ts + resolution, resolution, 4 * i + 1, 4 * i + 2));
assertScan(table, expected, scan);
// time points for fuzzy dim1 before third interval
scan = new FactScan(ts - resolution, ts + resolution,
// null stands for any
"metric" + i, dimValues("dim1", null, "dim2", "value3"));
expected = HashBasedTable.create();
expected.put("metric" + i, dimValues("dim1", "value1", "dim2", "value3"),
timeValues(ts, resolution, 4 * i, 4 * i + 1));
expected.put("metric" + i, dimValues("dim1", null, "dim2", "value3"),
timeValues(ts, resolution, 5 * i, 5 * i + 1));
assertScan(table, expected, scan);
// time points for both fuzzy dims before third interval
scan = new FactScan(ts - resolution, ts + resolution,
// null stands for any
"metric" + i, dimValues("dim1", null, "dim2", null));
expected = HashBasedTable.create();
expected.put("metric" + i, dimValues("dim1", "value1", "dim2", "value2"),
timeValues(ts, resolution, i, i + 1));
expected.put("metric" + i, dimValues("dim1", "value2", "dim2", "value1"),
timeValues(ts, resolution, 3 * i, 3 * i + 1));
expected.put("metric" + i, dimValues("dim1", "value2", "dim2", "value2"),
timeValues(ts, resolution, 2 * i, 2 * i + 1));
expected.put("metric" + i, dimValues("dim1", "value1", "dim2", "value3"),
timeValues(ts, resolution, 4 * i, 4 * i + 1));
expected.put("metric" + i, dimValues("dim1", null, "dim2", "value3"),
timeValues(ts, resolution, 5 * i, 5 * i + 1));
assertScan(table, expected, scan);
// time points for both fuzzy dims since third interval
scan = new FactScan(ts + resolution, ts + 3 * resolution,
// null stands for any
"metric" + i, dimValues("dim1", null, "dim2", null));
expected = HashBasedTable.create();
expected.put("metric" + i, dimValues("dim1", "value1", "dim2", "value2"),
timeValues(ts + resolution, resolution, i + 1, i + 2));
expected.put("metric" + i, dimValues("dim1", "value2", "dim2", "value1"),
timeValues(ts + resolution, resolution, 3 * i + 1, 3 * i + 2));
expected.put("metric" + i, dimValues("dim1", "value2", "dim2", "value2"),
timeValues(ts + resolution, resolution, 2 * i + 1, 2 * i + 2));
expected.put("metric" + i, dimValues("dim1", "value1", "dim2", "value3"),
timeValues(ts + resolution, resolution, 4 * i + 1, 4 * i + 2));
expected.put("metric" + i, dimValues("dim1", null, "dim2", "value3"),
timeValues(ts + resolution, resolution, 5 * i + 1, 5 * i + 2));
assertScan(table, expected, scan);
}
// all time points
scan = new FactScan(ts - resolution, ts + 3 * resolution, dimValues("dim1", "value1", "dim2", "value2"));
expected = HashBasedTable.create();
for (int i = 1; i < 3; i++) {
expected.put("metric" + i, dimValues("dim1", "value1", "dim2", "value2"),
timeValues(ts, resolution, i, i + 1, i + 2));
}
assertScan(table, expected, scan);
// time points since second interval
scan = new FactScan(ts + resolution, ts + 3 * resolution, dimValues("dim1", "value1", "dim2", "value2"));
expected = HashBasedTable.create();
for (int i = 1; i < 3; i++) {
expected.put("metric" + i, dimValues("dim1", "value1", "dim2", "value2"),
timeValues(ts + resolution, resolution, i + 1, i + 2));
}
assertScan(table, expected, scan);
// time points before third interval
scan = new FactScan(ts - resolution, ts + resolution, dimValues("dim1", "value1", "dim2", "value2"));
expected = HashBasedTable.create();
for (int i = 1; i < 3; i++) {
expected.put("metric" + i, dimValues("dim1", "value1", "dim2", "value2"),
timeValues(ts, resolution, i, i + 1));
}
assertScan(table, expected, scan);
// time points for fuzzy dim2 since second interval
scan = new FactScan(ts + resolution, ts + 3 * resolution, dimValues("dim1", "value1", "dim2", null));
expected = HashBasedTable.create();
for (int i = 1; i < 3; i++) {
expected.put("metric" + i, dimValues("dim1", "value1", "dim2", "value2"),
timeValues(ts + resolution, resolution, i + 1, i + 2));
expected.put("metric" + i, dimValues("dim1", "value1", "dim2", "value3"),
timeValues(ts + resolution, resolution, 4 * i + 1, 4 * i + 2));
}
assertScan(table, expected, scan);
// time points for fuzzy dim1 before third interval (very important case - caught some bugs)
scan = new FactScan(ts - resolution, ts + resolution, dimValues("dim1", null, "dim2", "value3"));
expected = HashBasedTable.create();
for (int i = 1; i < 3; i++) {
expected.put("metric" + i, dimValues("dim1", "value1", "dim2", "value3"),
timeValues(ts, resolution, 4 * i, 4 * i + 1));
expected.put("metric" + i, dimValues("dim1", null, "dim2", "value3"),
timeValues(ts, resolution, 5 * i, 5 * i + 1));
}
assertScan(table, expected, scan);
}
@Test
public void testMaxResolution() throws Exception {
// we use Integer.MAX_VALUE as resolution to compute all-time total values
InMemoryTableService.create("TotalsEntityTable");
InMemoryTableService.create("TotalsDataTable");
int resolution = Integer.MAX_VALUE;
// should not matter when resolution is max
int rollTimebaseInterval = 3600;
FactTable table = new FactTable(new InMemoryMetricsTable("TotalsDataTable"),
new EntityTable(new InMemoryMetricsTable("TotalsEntityTable")),
resolution, rollTimebaseInterval);
// ts is expected in seconds
long ts = System.currentTimeMillis() / 1000;
int count = 1000;
for (int i = 0; i < count; i++) {
for (int k = 0; k < 10; k++) {
// shift one day
writeInc(table, "metric" + k, ts + i * 60 * 60 * 24, i * k, "dim" + k, "value" + k);
}
}
for (int k = 0; k < 10; k++) {
// 0, 0 should match timestamp of all data points
FactScan scan = new FactScan(0, 0, "metric" + k, dimValues("dim" + k, "value" + k));
Table<String, List<DimensionValue>, List<TimeValue>> expected = HashBasedTable.create();
expected.put("metric" + k, dimValues("dim" + k, "value" + k),
ImmutableList.of(new TimeValue(0, k * count * (count - 1) / 2)));
assertScan(table, expected, scan);
}
}
@Test
public void testPreSplits() throws Exception {
InMemoryTableService.create("presplitEntityTable");
InMemoryTableService.create("presplitDataTable");
int resolution = 10;
int rollTimebaseInterval = 2;
InMemoryMetricsTable metricsTable = new InMemoryMetricsTable("presplitDataTable");
FactTable table = new FactTable(metricsTable,
new EntityTable(new InMemoryMetricsTable("presplitEntityTable")),
resolution, rollTimebaseInterval);
byte[][] splits = FactTable.getSplits(3);
long ts = System.currentTimeMillis() / 1000;
DimensionValue dimVal1 = new DimensionValue("dim1", "value1");
DimensionValue dimVal2 = new DimensionValue("dim2", "value2");
DimensionValue dimVal3 = new DimensionValue("dim3", "value3");
// first agg view: dim1
table.add(ImmutableList.of(new Fact(ts, ImmutableList.of(dimVal1),
new Measurement("metric1", MeasureType.COUNTER, 1))));
// second agg view: dim1 & dim2
table.add(ImmutableList.of(new Fact(ts, ImmutableList.of(dimVal1, dimVal2),
new Measurement("metric1", MeasureType.COUNTER, 1))));
// third agg view: dim3
table.add(ImmutableList.of(new Fact(ts, ImmutableList.of(dimVal3),
new Measurement("metric1", MeasureType.COUNTER, 1))));
// Verify all written records are spread across splits
Scanner scanner = metricsTable.scan(null, null, null);
Row row;
Set<Integer> splitsWithRows = Sets.newHashSet();
while ((row = scanner.next()) != null) {
boolean added = false;
for (int i = 0; i < splits.length; i++) {
if (Bytes.compareTo(row.getRow(), splits[i]) < 0) {
splitsWithRows.add(i);
added = true;
break;
}
}
if (!added) {
// falls into last split
splitsWithRows.add(splits.length);
}
}
Assert.assertEquals(3, splitsWithRows.size());
}
private List<TimeValue> timeValues(long ts, int resolution, long... values) {
List<TimeValue> timeValues = Lists.newArrayList();
for (int i = 0; i < values.length; i++) {
timeValues.add(new TimeValue(ts + i * resolution, values[i]));
}
return timeValues;
}
private void writeInc(FactTable table, String metric, long ts, int value, String... dims)
throws Exception {
table.add(ImmutableList.of(new Fact(ts, dimValues(dims), new Measurement(metric, MeasureType.COUNTER, value))));
}
private List<DimensionValue> dimValues(String... dims) {
List<DimensionValue> dimensionValues = Lists.newArrayList();
for (int i = 0; i < dims.length; i += 2) {
dimensionValues.add(new DimensionValue(dims[i], dims[i + 1]));
}
return dimensionValues;
}
private void assertScan(FactTable table, Table<String, List<DimensionValue>, List<TimeValue>> expected,
FactScan scan) throws Exception {
Table<String, List<DimensionValue>, List<TimeValue>> resultTable = HashBasedTable.create();
FactScanner scanner = table.scan(scan);
try {
while (scanner.hasNext()) {
FactScanResult result = scanner.next();
List<TimeValue> timeValues = resultTable.get(result.getMeasureName(), result.getDimensionValues());
if (timeValues == null) {
timeValues = Lists.newArrayList();
resultTable.put(result.getMeasureName(), result.getDimensionValues(), timeValues);
}
timeValues.addAll(Lists.newArrayList(result.iterator()));
}
} finally {
scanner.close();
}
Assert.assertEquals(expected, resultTable);
}
}