Mercurial > hg > thermostat-ng > agent
changeset 2480:e2e5b4797c2a
[Byteman] Add tests for GraphDataset.
Reviewed-by: aazores
Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2016-October/021296.html
author | Severin Gehwolf <sgehwolf@redhat.com> |
---|---|
date | Tue, 20 Sep 2016 19:07:51 +0200 |
parents | 81cdf24da562 |
children | bcf729e138c8 |
files | vm-byteman/client-swing/src/main/java/com/redhat/thermostat/vm/byteman/client/swing/internal/GraphDataset.java vm-byteman/client-swing/src/main/java/com/redhat/thermostat/vm/byteman/client/swing/internal/LocaleResources.java vm-byteman/client-swing/src/main/java/com/redhat/thermostat/vm/byteman/client/swing/internal/SwingVmBytemanView.java vm-byteman/client-swing/src/main/resources/com/redhat/thermostat/vm/byteman/client/swing/internal/strings.properties vm-byteman/client-swing/src/test/java/com/redhat/thermostat/vm/byteman/client/swing/internal/GraphDatasetTest.java |
diffstat | 5 files changed, 695 insertions(+), 8 deletions(-) [+] |
line wrap: on
line diff
--- a/vm-byteman/client-swing/src/main/java/com/redhat/thermostat/vm/byteman/client/swing/internal/GraphDataset.java Tue Oct 18 18:34:05 2016 +0200 +++ b/vm-byteman/client-swing/src/main/java/com/redhat/thermostat/vm/byteman/client/swing/internal/GraphDataset.java Tue Sep 20 19:07:51 2016 +0200 @@ -51,10 +51,13 @@ import org.jfree.data.xy.XYSeriesCollection; import com.redhat.thermostat.common.Pair; +import com.redhat.thermostat.shared.locale.Translate; import com.redhat.thermostat.vm.byteman.common.BytemanMetric; class GraphDataset { + private static final Translate<LocaleResources> t = LocaleResources.createLocalizer(); + enum CoordinateType { INTEGRAL, REAL, @@ -192,11 +195,14 @@ switch (ytype) { case REAL: y = y.doubleValue() + y1.doubleValue(); + break; default: y = y.longValue() + y1.longValue(); } + xyseries.updateByIndex(idx, y); + } else { + xyseries.add(x, y); } - xyseries.add(x, y); } XYSeriesCollection xycollection = new XYSeriesCollection(); xycollection.addSeries(xyseries); @@ -233,7 +239,7 @@ String first = p.getFirst().toString(); String second = ""; double increment = ((Number) p.getSecond()).doubleValue(); - if(dataset.getRowKeys().contains(first)) { + if (dataset.getRowKeys().contains(first)) { dataset.incrementValue(increment, first, second); } else { dataset.addValue(increment, first, second); @@ -281,7 +287,7 @@ // set with a range axis which displays the numeric // values symbolically. - XYSeries xyseries = new XYSeries(ykey + " against " + xkey); + XYSeries xyseries = new XYSeries(t.localize(LocaleResources.X_AGAINST_Y, xkey, ykey).getContents()); int count = 0; HashMap<String, Number> tickmap = new HashMap<String, Number>(); @@ -379,6 +385,10 @@ updateCType = true; } } + if (value instanceof Double || value.getClass() == double.class) { + ctype = CoordinateType.REAL; + updateCType = true; + } if (updateCType) { if (isX) { xtype = ctype;
--- a/vm-byteman/client-swing/src/main/java/com/redhat/thermostat/vm/byteman/client/swing/internal/LocaleResources.java Tue Oct 18 18:34:05 2016 +0200 +++ b/vm-byteman/client-swing/src/main/java/com/redhat/thermostat/vm/byteman/client/swing/internal/LocaleResources.java Tue Sep 20 19:07:51 2016 +0200 @@ -59,7 +59,8 @@ FILTER_VALUE_LABEL, NO_FILTER_NAME, X_COORD, - Y_COORD + Y_COORD, + X_AGAINST_Y, ; static final String RESOURCE_BUNDLE = LocaleResources.class.getPackage().getName() + ".strings";
--- a/vm-byteman/client-swing/src/main/java/com/redhat/thermostat/vm/byteman/client/swing/internal/SwingVmBytemanView.java Tue Oct 18 18:34:05 2016 +0200 +++ b/vm-byteman/client-swing/src/main/java/com/redhat/thermostat/vm/byteman/client/swing/internal/SwingVmBytemanView.java Tue Sep 20 19:07:51 2016 +0200 @@ -928,7 +928,7 @@ JFreeChart graph = null; switch (xtype) { case CATEGORY: - if(ytype == CoordinateType.CATEGORY) { + if (ytype == CoordinateType.CATEGORY) { // use a bar chart with multiple bars per category 1 value // where each bar counts the frequency for the second category CategoryDataset categoryDataset = dataset.getCategoryDataset(); @@ -951,7 +951,7 @@ } break; case TIME: - if(ytype == CoordinateType.CATEGORY) { + if (ytype == CoordinateType.CATEGORY) { // we need to draw a graph of category (state) value against time // with step transitions between states // @@ -974,7 +974,7 @@ break; case INTEGRAL: case REAL: - if(ytype == CoordinateType.CATEGORY) { + if (ytype == CoordinateType.CATEGORY) { // we could treat the numeric values as category values (or ranges?) // and draw this as a bar chart CategoryDataset categoryDataset = dataset.getCategoryDataset(); @@ -982,7 +982,7 @@ categoryDataset, PlotOrientation.VERTICAL, true, true, false); // for now draw an empty graph - } else if(ytype == CoordinateType.TIME) { + } else if (ytype == CoordinateType.TIME) { // we could group the time values as time ranges // and draw this as a bar chart //
--- a/vm-byteman/client-swing/src/main/resources/com/redhat/thermostat/vm/byteman/client/swing/internal/strings.properties Tue Oct 18 18:34:05 2016 +0200 +++ b/vm-byteman/client-swing/src/main/resources/com/redhat/thermostat/vm/byteman/client/swing/internal/strings.properties Tue Sep 20 19:07:51 2016 +0200 @@ -18,3 +18,4 @@ NO_FILTER_NAME = <No Filter> X_COORD = x: Y_COORD = y: +X_AGAINST_Y = {0} against {1}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-byteman/client-swing/src/test/java/com/redhat/thermostat/vm/byteman/client/swing/internal/GraphDatasetTest.java Tue Sep 20 19:07:51 2016 +0200 @@ -0,0 +1,675 @@ +/* + * Copyright 2012-2016 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.vm.byteman.client.swing.internal; + +import static org.junit.Assert.assertEquals; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.jfree.data.category.CategoryDataset; +import org.jfree.data.xy.XYDataset; +import org.junit.Test; + +import com.redhat.thermostat.common.Pair; +import com.redhat.thermostat.vm.byteman.client.swing.internal.GraphDataset.CoordinateType; +import com.redhat.thermostat.vm.byteman.common.BytemanMetric; + +public class GraphDatasetTest { + + private static final double DELTA = 0.001; + private static final String TEST_WRITER_ID = "test-writerId"; + private static final String COUNT_FIELD = "count"; + private static final String TEST_VM_ID = "test-vmId"; + + private static List<BytemanMetric> buildMetrics(MetricConfig config) { + List<BytemanMetric> mList = new ArrayList<>(); + for (int i = 0; i < config.getNumMetrics(); i++) { + BytemanMetric m = new BytemanMetric(TEST_WRITER_ID); + m.setVmId(TEST_VM_ID); + m.setData(config.produceDataJson(i)); + m.setMarker(config.produceMarker(i)); + m.setTimeStamp(config.produceTimeStamp(i)); + mList.add(m); + } + return mList; + } + + @Test + public void testEmptyXYDataSet() { + final List<BytemanMetric> empty = Collections.emptyList(); + // x => marker + GraphDataset dataset = new GraphDataset(empty, GraphDataset.MARKER_KEY, GraphDataset.TIMESTAMP_KEY, null, null); + XYDataset actualDataset = dataset.getXYDataset(); + assertEquals(0, actualDataset.getSeriesCount()); + + // y => marker + dataset = new GraphDataset(empty, GraphDataset.TIMESTAMP_KEY, GraphDataset.MARKER_KEY, null, null); + actualDataset = dataset.getXYDataset(); + assertEquals(0, actualDataset.getSeriesCount()); + } + + @Test + public void testXYDataSetBasic() { + List<BytemanMetric> mList = buildMetrics(new DefaultMetricConfig() { + @Override + public String produceDataJson(int i) { + return new DataJsonBuilder() + .addKeyValue(COUNT_FIELD, new Long(i)) + .addKeyValue("foobar", "baz" + i) // extra fields shouldn't matter + .build(); + } + }); + // plots (x, y) where (x_i, y_i) == (i, i) + GraphDataset dataSet = new GraphDataset(mList, GraphDataset.TIMESTAMP_KEY, COUNT_FIELD, null, null); + XYDataset xyDataSet = dataSet.getXYDataset(); + assertEquals(1, xyDataSet.getSeriesCount()); + assertEquals(DefaultMetricConfig.DEFAULT_NUM, xyDataSet.getItemCount(0)); + + // sanity check some values + assertEquals(0L, xyDataSet.getX(0, 0)); + assertEquals(0.0, xyDataSet.getY(0, 0)); + assertEquals(1L, xyDataSet.getX(0, 1)); + assertEquals(1.0, xyDataSet.getY(0, 1)); + assertEquals(99L, xyDataSet.getX(0, 99)); + assertEquals(99.0, xyDataSet.getY(0, 99)); + } + + @Test + public void testXYDataSetFiltered() { + final String filterKey = "foo"; + final String filterValue = "bar"; + // Produce metrics so we filter every other metric + List<BytemanMetric> mList = buildMetrics(new DefaultMetricConfig() { + @Override + public String produceDataJson(int i) { + if (i % 2 == 0) { + return new DataJsonBuilder() + .addKeyValue(COUNT_FIELD, new Long(i)) + .build(); + } else { + return new DataJsonBuilder() + .addKeyValue(COUNT_FIELD, new Long(i)) + .addKeyValue(filterKey, filterValue) + .build(); + } + } + }); + GraphDataset dataSet = new GraphDataset(mList, GraphDataset.TIMESTAMP_KEY, COUNT_FIELD, filterKey, filterValue); + XYDataset xyDataSet = dataSet.getXYDataset(); + assertEquals(1, xyDataSet.getSeriesCount()); + assertEquals(DefaultMetricConfig.DEFAULT_NUM/2, xyDataSet.getItemCount(0)); + + // sanity check some values + assertEquals(1L, xyDataSet.getX(0, 0)); + assertEquals(1.0, xyDataSet.getY(0, 0)); + assertEquals(3L, xyDataSet.getX(0, 1)); + assertEquals(3.0, xyDataSet.getY(0, 1)); + assertEquals(99L, xyDataSet.getX(0, 49)); + assertEquals(99.0, xyDataSet.getY(0, 49)); + } + + /** + * When there is a repeated x value in our data the corresponding y values + * contain the running sum. That is for a series x_i = a, y_i = 0.i for all + * n values, then the x_n == sum(y_0,y_n). So for n == 4 + * we have: x_4 = (0.0 + 0.1 + 0.2 + 0.3). + */ + @Test + public void testXYDataSetXRepeatDoubleSingleKey() { + final long timeStamp = 322L; // constant numeric x coordinate + List<BytemanMetric> mList = buildMetrics(new DefaultMetricConfig() { + @Override + public String produceDataJson(int i) { + String dStringVal = String.format("0.%d", i); + Double dVal = Double.parseDouble(dStringVal); + return new DataJsonBuilder() + .addKeyValue(COUNT_FIELD, dVal) + .build(); + } + + @Override + public int getNumMetrics() { + return 4; + } + + @Override + public long produceTimeStamp(int i) { + return timeStamp; // same timestamp for all metrics + } + }); + GraphDataset dataSet = new GraphDataset(mList, GraphDataset.TIMESTAMP_KEY, COUNT_FIELD, null, null); + XYDataset xyDataSet = dataSet.getXYDataset(); + assertEquals(1, xyDataSet.getSeriesCount()); + assertEquals(1, xyDataSet.getItemCount(0)); + assertEquals(0.6, xyDataSet.getYValue(0, 0), DELTA); + assertEquals(timeStamp, (long)xyDataSet.getXValue(0, 0)); + } + + @Test + public void testXYDataSetXRepeatLongMultipleRepeatedKeys() { + final int repeatAmount = 3; + final long timestamps[] = new long[] { + 322L, 300L, -1L + }; + List<BytemanMetric> mList = buildMetrics(new DefaultMetricConfig() { + @Override + public String produceDataJson(int i) { + Long lVal = Long.valueOf(i); + return new DataJsonBuilder() + .addKeyValue(COUNT_FIELD, lVal) + .build(); + } + + @Override + public int getNumMetrics() { + // x key repeats repeatAmount times + return timestamps.length * repeatAmount; + } + + @Override + public long produceTimeStamp(int i) { + int idx = (i % repeatAmount); + return timestamps[idx]; // same timestamp every repeatAmount times + } + }); + GraphDataset dataSet = new GraphDataset(mList, GraphDataset.TIMESTAMP_KEY, COUNT_FIELD, null, null); + XYDataset xyDataSet = dataSet.getXYDataset(); + assertEquals(1, xyDataSet.getSeriesCount()); + assertEquals(repeatAmount, xyDataSet.getItemCount(0)); + // added coordinates are sorted by x (ascending) + assertEquals(timestamps[2], (long)xyDataSet.getXValue(0, 0)); + assertEquals(timestamps[1], (long)xyDataSet.getXValue(0, 1)); + assertEquals(timestamps[0], (long)xyDataSet.getXValue(0, 2)); + assertEquals("0 + 3 + 6 = 9", 9.0, xyDataSet.getYValue(0, 2), DELTA); + assertEquals("1 + 4 + 7 = 12", 12.0, xyDataSet.getYValue(0, 1), DELTA); + assertEquals("2 + 5 + 8 = 15", 15.0, xyDataSet.getYValue(0, 0), DELTA); + } + + /** + * Special case of testXYDataSetXRepeatLongMultipleRepeatedKeys where + * y_i = 1 for all i. + */ + @Test + public void testXYDataSetXRepeatLongMultipleRepeatedKeysFrequency() { + final int repeatAmount = 3; + final long timestamps[] = new long[] { + 322L, 300L, -1L + }; + List<BytemanMetric> mList = buildMetrics(new DefaultMetricConfig() { + @Override + public String produceDataJson(int i) { + Long lVal = Long.valueOf(1); + return new DataJsonBuilder() + .addKeyValue(COUNT_FIELD, lVal) + .build(); + } + + @Override + public int getNumMetrics() { + // x key repeats repeatAmount times + return timestamps.length * repeatAmount; + } + + @Override + public long produceTimeStamp(int i) { + int idx = (i % repeatAmount); + return timestamps[idx]; // same timestamp every repeatAmount times + } + }); + GraphDataset dataSet = new GraphDataset(mList, GraphDataset.TIMESTAMP_KEY, COUNT_FIELD, null, null); + XYDataset xyDataSet = dataSet.getXYDataset(); + assertEquals(1, xyDataSet.getSeriesCount()); + assertEquals(repeatAmount, xyDataSet.getItemCount(0)); + // added coordinates are sorted by x (ascending) + assertEquals(timestamps[2], (long)xyDataSet.getXValue(0, 0)); + assertEquals(timestamps[1], (long)xyDataSet.getXValue(0, 1)); + assertEquals(timestamps[0], (long)xyDataSet.getXValue(0, 2)); + assertEquals(timestamps[2] + " occurred 3 times in the data set", 3.0, xyDataSet.getYValue(0, 2), DELTA); + assertEquals(timestamps[1] + " occurred 3 times in the data set", 3.0, xyDataSet.getYValue(0, 1), DELTA); + assertEquals(timestamps[2] + " occurred 3 times in the data set", 3.0, xyDataSet.getYValue(0, 0), DELTA); + } + + @Test + public void testCategoryDatasetEmpty() { + final List<BytemanMetric> empty = Collections.emptyList(); + GraphDataset dataSet = new GraphDataset(empty /* no matter */, GraphDataset.TIMESTAMP_KEY, COUNT_FIELD, null, null); + CategoryDataset actualSet = dataSet.getCategoryDataset(); + assertEquals(0, actualSet.getColumnCount()); + assertEquals(0, actualSet.getRowCount()); + } + + /** + * Category data plot for x = category, y = numeric. In that case + * expect the y value (per category) to be the sum of all y values with + * category x. + */ + @Test + public void testCategoryDatasetYNumeric() { + final String evenMarker = "even_marker"; + final String oddMarker = "odd_marker"; + List<BytemanMetric> mList = buildMetrics(new DefaultMetricConfig() { + + @Override + public String produceMarker(int i) { + if (i % 2 == 0) { + // even + return evenMarker; + } else { + // odd + return oddMarker; + } + } + + @Override + public String produceDataJson(int i) { + Long iLong = Long.valueOf(i); + return new DataJsonBuilder() + .addKeyValue(COUNT_FIELD, iLong) + .build(); + } + + @Override + public int getNumMetrics() { + return 12; + } + }); + GraphDataset dataSet = new GraphDataset(mList, GraphDataset.MARKER_KEY, COUNT_FIELD, null, null); + CategoryDataset actualSet = dataSet.getCategoryDataset(); + assertEquals("two different markers", 2, actualSet.getRowCount()); + assertEquals("one value per marker", 1, actualSet.getColumnCount()); + String actualEvenMarker = (String)actualSet.getRowKey(0); + String actualOddMarker = (String)actualSet.getRowKey(1); + assertEquals(evenMarker, actualEvenMarker); + assertEquals(oddMarker, actualOddMarker); + double oddSum = 1.0 + 3.0 + 5 + 7 + 9 + 11; // odd numbers in range [0,12) + double evenSum = 2.0 + 4 + 6 + 8 + 10; // even numbers in range [0, 12) + Comparable<?> columnKey = actualSet.getColumnKey(0); + assertEquals(oddSum, (double)actualSet.getValue(oddMarker, columnKey), DELTA); + assertEquals(evenSum, (double)actualSet.getValue(evenMarker, columnKey), DELTA); + } + + /** + * Category data plot for x = category, y = category. In that case + * expect the y value to be the frequency of category x. + */ + @Test + public void testCategoryDatasetYCategory() { + final String evenMarker = "even_marker"; + final String oddMarker = "odd_marker"; + List<BytemanMetric> mList = buildMetrics(new DefaultMetricConfig() { + + @Override + public String produceMarker(int i) { + if (i % 2 == 0) { + // even + return evenMarker; + } else { + // odd + return oddMarker; + } + } + + @Override + public int getNumMetrics() { + // pick an odd number so as to have uneven frequency spread between odd/even numbers + return 100 - 1; + } + }); + GraphDataset dataSet = new GraphDataset(mList, GraphDataset.MARKER_KEY, GraphDataset.MARKER_KEY, null, null); + CategoryDataset actualSet = dataSet.getCategoryDataset(); + assertEquals("two different markers", 2, actualSet.getRowCount()); + assertEquals(2, actualSet.getColumnCount()); + String actualEvenMarker = (String)actualSet.getRowKey(0); + String actualOddMarker = (String)actualSet.getRowKey(1); + assertEquals(evenMarker, actualEvenMarker); + assertEquals(oddMarker, actualOddMarker); + String evenKey = (String)actualSet.getColumnKey(0); + String oddKey = (String)actualSet.getColumnKey(1); + assertEquals("100/2 = 50. i.e. frequency of even/odd numbers.", + 49.0, (double)actualSet.getValue(oddMarker, oddKey), DELTA); + assertEquals("100/2 = 49. i.e. frequency of even/odd numbers.", + 50.0, (double)actualSet.getValue(evenMarker, evenKey), DELTA); + } + + @Test + public void testEmptyCategoryTimePlot() { + final List<BytemanMetric> empty = Collections.emptyList(); + // x => marker + GraphDataset dataset = new GraphDataset(empty, GraphDataset.MARKER_KEY, GraphDataset.TIMESTAMP_KEY, null, null); + XYDataset actualDataset = dataset.getCategoryTimePlot(new String[][] { {""} }); + assertEquals(0, actualDataset.getSeriesCount()); + + // y => timestamp + dataset = new GraphDataset(empty, GraphDataset.TIMESTAMP_KEY, GraphDataset.TIMESTAMP_KEY, null, null); + actualDataset = dataset.getCategoryTimePlot(new String[][] { {""} }); + assertEquals(0, actualDataset.getSeriesCount()); + } + + @Test + public void testCategoryTimePlotBasic() { + final String[][] retvals = new String[][] { {""} }; + final String evenMarker = "even_marker"; + final String oddMarker = "odd_marker"; + final int numMetrics = 5; + List<BytemanMetric> mList = buildMetrics(new DefaultMetricConfig() { + + @Override + public String produceMarker(int i) { + if (i % 2 == 0) { + // even + return evenMarker; + } else { + // odd + return oddMarker; + } + } + + @Override + public int getNumMetrics() { + return numMetrics; + } + + @Override + public long produceTimeStamp(int i) { + return i * 2; + } + + }); + GraphDataset dataset = new GraphDataset(mList, GraphDataset.TIMESTAMP_KEY, GraphDataset.MARKER_KEY, null, null); + XYDataset actualDataset = dataset.getCategoryTimePlot(retvals); + assertEquals("Expected one series, exactly", 1, actualDataset.getSeriesCount()); + assertEquals(5, actualDataset.getItemCount(0)); + for (int i = 0; i < numMetrics; i++) { + double retval = actualDataset.getXValue(0, i); + double expectedVal = Double.valueOf(i * 2); + assertEquals(expectedVal, retval, DELTA); + } + // Y-values are unique numbers per marker. I.e. 0 and 1 in this case + for (int i = 0; i < numMetrics; i++) { + double yVal = actualDataset.getYValue(0, i); + double expectedVal; + if (i %2 == 0) { + expectedVal = 0.0; + } else { + expectedVal = 1.0; + } + assertEquals(expectedVal, yVal, DELTA); + } + + // verify correct return values have been set + List<String> retvalList = Arrays.asList(retvals[0]); + Collections.sort(retvalList); + assertEquals(evenMarker, retvalList.get(0)); + assertEquals(oddMarker, retvalList.get(1)); + } + + @Test + public void testXType() { + List<BytemanMetric> mList = buildMetrics(new DefaultMetricConfig()); + GraphDataset dataSet = new GraphDataset(mList, GraphDataset.MARKER_KEY, GraphDataset.TIMESTAMP_KEY, null, null); + assertEquals(CoordinateType.CATEGORY, dataSet.getXType()); + dataSet = new GraphDataset(mList, GraphDataset.TIMESTAMP_KEY, GraphDataset.MARKER_KEY, null, null); + assertEquals(CoordinateType.TIME, dataSet.getXType()); + dataSet = new GraphDataset(mList, GraphDataset.FREQUENCY_KEY, GraphDataset.MARKER_KEY, null, null); + assertEquals(CoordinateType.INTEGRAL, dataSet.getXType()); + mList = buildMetrics(new DefaultMetricConfig() { + @Override + public String produceDataJson(int i) { + Long iLong = Long.valueOf(i); + return new DataJsonBuilder() + .addKeyValue(COUNT_FIELD, iLong) + .build(); + } + }); + dataSet = new GraphDataset(mList, COUNT_FIELD, GraphDataset.MARKER_KEY, null, null); + assertEquals(CoordinateType.REAL, dataSet.getXType()); + } + + @Test + public void testXLabel() { + List<BytemanMetric> mList = buildMetrics(new DefaultMetricConfig()); + GraphDataset dataSet = new GraphDataset(mList, GraphDataset.MARKER_KEY, GraphDataset.TIMESTAMP_KEY, null, null); + assertEquals(GraphDataset.MARKER_KEY, dataSet.getXLabel()); + dataSet = new GraphDataset(mList, GraphDataset.TIMESTAMP_KEY, GraphDataset.MARKER_KEY, null, null); + assertEquals(GraphDataset.TIMESTAMP_KEY, dataSet.getXLabel()); + dataSet = new GraphDataset(mList, GraphDataset.FREQUENCY_KEY, GraphDataset.MARKER_KEY, null, null); + assertEquals(GraphDataset.FREQUENCY_KEY, dataSet.getXLabel()); + + mList = buildMetrics(new DefaultMetricConfig() { + @Override + public String produceDataJson(int i) { + Long iLong = Long.valueOf(i); + return new DataJsonBuilder() + .addKeyValue(COUNT_FIELD, iLong) + .build(); + } + }); + dataSet = new GraphDataset(mList, COUNT_FIELD, GraphDataset.MARKER_KEY, null, null); + assertEquals(COUNT_FIELD, dataSet.getXLabel()); + } + + @Test + public void testYType() { + List<BytemanMetric> mList = buildMetrics(new DefaultMetricConfig()); + GraphDataset dataSet = new GraphDataset(mList, GraphDataset.TIMESTAMP_KEY, GraphDataset.MARKER_KEY, null, null); + assertEquals(CoordinateType.CATEGORY, dataSet.getYType()); + dataSet = new GraphDataset(mList, GraphDataset.TIMESTAMP_KEY, GraphDataset.TIMESTAMP_KEY, null, null); + assertEquals(CoordinateType.TIME, dataSet.getYType()); + dataSet = new GraphDataset(mList, GraphDataset.TIMESTAMP_KEY, GraphDataset.FREQUENCY_KEY, null, null); + assertEquals(CoordinateType.INTEGRAL, dataSet.getYType()); + mList = buildMetrics(new DefaultMetricConfig() { + @Override + public String produceDataJson(int i) { + Long iLong = Long.valueOf(i); + return new DataJsonBuilder() + .addKeyValue(COUNT_FIELD, iLong) + .build(); + } + }); + dataSet = new GraphDataset(mList, GraphDataset.TIMESTAMP_KEY, COUNT_FIELD, null, null); + assertEquals(CoordinateType.REAL, dataSet.getYType()); + } + + @Test + public void testYLabel() { + List<BytemanMetric> mList = buildMetrics(new DefaultMetricConfig()); + GraphDataset dataSet = new GraphDataset(mList, GraphDataset.TIMESTAMP_KEY, GraphDataset.MARKER_KEY, null, null); + assertEquals(GraphDataset.MARKER_KEY, dataSet.getYLabel()); + dataSet = new GraphDataset(mList, GraphDataset.TIMESTAMP_KEY, GraphDataset.TIMESTAMP_KEY, null, null); + assertEquals(GraphDataset.TIMESTAMP_KEY, dataSet.getYLabel()); + dataSet = new GraphDataset(mList, GraphDataset.TIMESTAMP_KEY, GraphDataset.FREQUENCY_KEY, null, null); + assertEquals(GraphDataset.FREQUENCY_KEY, dataSet.getYLabel()); + mList = buildMetrics(new DefaultMetricConfig() { + @Override + public String produceDataJson(int i) { + Long iLong = Long.valueOf(i); + return new DataJsonBuilder() + .addKeyValue(COUNT_FIELD, iLong) + .build(); + } + }); + dataSet = new GraphDataset(mList, GraphDataset.TIMESTAMP_KEY, COUNT_FIELD, null, null); + assertEquals(COUNT_FIELD, dataSet.getYLabel()); + } + + @Test + public void testSize() { + List<BytemanMetric> mList = buildMetrics(new DefaultMetricConfig()); + GraphDataset dataSet = new GraphDataset(mList, GraphDataset.TIMESTAMP_KEY, GraphDataset.MARKER_KEY, null, null); + assertEquals(DefaultMetricConfig.DEFAULT_NUM, dataSet.size()); + final int numMetrics = 10; + mList = buildMetrics(new DefaultMetricConfig() { + @Override + public int getNumMetrics() { + return numMetrics; + } + + @Override + public String produceDataJson(int i) { + Long iLong = Long.valueOf(i); + return new DataJsonBuilder() + .addKeyValue(COUNT_FIELD, iLong) + .build(); + } + }); + dataSet = new GraphDataset(mList, GraphDataset.TIMESTAMP_KEY, COUNT_FIELD, null, null); + assertEquals(numMetrics, dataSet.size()); + + // some metrics are filtered (implicitly) so should not add to the data + // set + mList = buildMetrics(new DefaultMetricConfig() { + @Override + public String produceDataJson(int i) { + if (i % 2 == 0) { + Long iLong = Long.valueOf(i); + return new DataJsonBuilder() + .addKeyValue(COUNT_FIELD, iLong) + .build(); + } else { + return new DataJsonBuilder().build(); + } + } + }); + dataSet = new GraphDataset(mList, GraphDataset.TIMESTAMP_KEY, COUNT_FIELD, null, null); + assertEquals(DefaultMetricConfig.DEFAULT_NUM/2, dataSet.size()); + + // explicit filtering + final double fooValue = 3000.0; + final String fooKey = "foo-key"; + mList = buildMetrics(new DefaultMetricConfig() { + @Override + public String produceDataJson(int i) { + if (i % 30 == 0) { + Long iLong = Long.valueOf(i); + return new DataJsonBuilder() + .addKeyValue(COUNT_FIELD, iLong) + .addKeyValue(fooKey, Double.valueOf(fooValue)) + .build(); + } else { + Long iLong = Long.valueOf(i); + return new DataJsonBuilder() + .addKeyValue(COUNT_FIELD, iLong) + .build(); + } + } + }); + dataSet = new GraphDataset(mList, GraphDataset.TIMESTAMP_KEY, COUNT_FIELD, fooKey, String.valueOf(fooValue)); + assertEquals("0, 30, 60, 90 => 4", 4, dataSet.size()); + } + + static interface MetricConfig { + + String produceDataJson(int i); + + String produceMarker(int i); + + long produceTimeStamp(int i); + + int getNumMetrics(); + } + + static class DefaultMetricConfig implements MetricConfig { + + private static final int DEFAULT_NUM = 100; + + @Override + public String produceDataJson(int i) { + return "{\"key\": \"value\"}"; + } + + @Override + public String produceMarker(int i) { + return "marker-value"; + } + + @Override + public long produceTimeStamp(int i) { + return i; + } + + @Override + public int getNumMetrics() { + return DEFAULT_NUM; + } + + } + + static class DataJsonBuilder { + + private final List<Pair<String, Object>> keyValues = new ArrayList<>(); + + DataJsonBuilder addKeyValue(String key, Object value) { + keyValues.add(new Pair<>(key, value)); + return this; + } + + String build() { + StringBuilder builder = new StringBuilder(); + builder.append("{"); + int i = 0; + for (Pair<String, Object> pair: keyValues) { + builder.append("\"" + pair.getFirst() + "\": "); + Object val = pair.getSecond(); + if (val instanceof Long) { + Long lVal = (Long)val; + builder.append(lVal); + } else if (val instanceof Double) { + Double dVal = (Double)val; + builder.append(dVal); + } else if (val instanceof Boolean) { + Boolean bVal = (Boolean)val; + builder.append(bVal); + } else { + if (!(val instanceof String)) { + throw new AssertionError("Unexpected value type: " + val.getClass()); + } + String sVal = (String)val; + builder.append("\"" + sVal + "\""); + } + if (i != keyValues.size() - 1) { + builder.append(",\n"); + } + i++; + } + builder.append("}"); + return builder.toString(); + } + } +}