/*
* -----------------------------------------------------------------------\
* PerfCake
*
* Copyright (C) 2010 - 2016 the original author or authors.
*
* 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 org.perfcake.reporting.reporter;
import org.perfcake.RunInfo;
import org.perfcake.common.Period;
import org.perfcake.common.PeriodType;
import org.perfcake.reporting.FakeMeasurementUnit;
import org.perfcake.reporting.Measurement;
import org.perfcake.reporting.ReportManager;
import org.perfcake.reporting.destination.DummyDestination;
import org.perfcake.util.ObjectFactory;
import org.HdrHistogram.Histogram;
import org.HdrHistogram.HistogramIterationValue;
import org.HdrHistogram.PercentileIterator;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.testng.Assert;
import org.testng.annotations.Test;
import java.lang.ref.Reference;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.SortedMap;
import java.util.TreeMap;
import io.vertx.core.json.JsonObject;
/**
* @author <a href="mailto:marvenec@gmail.com">Martin Večeřa</a>
*/
@Test(groups = { "unit" })
public class ResponseTimeHistogramTest {
private static final Logger log = LogManager.getLogger(ResponseTimeHistogramTest.class);
private void display(Histogram histogram, long avg) {
String valueFormatString = "%12.3f";
String percentileFormatString = "%d";
PercentileIterator pi = new PercentileIterator(histogram.copyCorrectedForCoordinatedOmission(avg), 1);
pi.reset(2);
JsonObject o = new JsonObject();
while (pi.hasNext()) {
HistogramIterationValue val = pi.next();
String key = String.format(Locale.US, percentileFormatString, val.getPercentileLevelIteratedTo() / 100d);
String value = String.format(Locale.US, valueFormatString, val.getValueIteratedTo());
o.put(key, value);
}
System.out.println(o.toString());
}
@Test
public void offModeTest() throws Exception {
final Properties props = new Properties();
props.setProperty("correctionMode", "off");
props.setProperty("precision", "3");
props.setProperty("prefix", "p");
Measurement m = runTest(props);
final List<Long> res = new ArrayList<>();
m.getAll().forEach((k, v) -> {
if (k.startsWith("p0.998") || k.startsWith("p0.999") || k.startsWith("p1.000")) {
res.add(Long.valueOf((String) v));
}
});
Assert.assertEquals((long) res.get(0), 2L);
Assert.assertEquals((long) res.get(1), 2L);
Assert.assertEquals((long) res.get(2), 100L);
Assert.assertEquals((long) res.get(3), 100L);
}
@Test
public void autoModeTest() throws Exception {
final Properties props = new Properties();
props.setProperty("correctionMode", "auto");
props.setProperty("precision", "2");
props.setProperty("prefix", "p");
Measurement m = runTest(props);
final List<Long> res = new ArrayList<>();
m.getAll().forEach((k, v) -> {
if (k.startsWith("p0.953") || k.startsWith("p0.968") || k.startsWith("p0.976") || k.startsWith("p0.999")) {
res.add(Long.valueOf((String) v));
}
});
Assert.assertEquals((long) res.get(0), 2L);
Assert.assertEquals((long) res.get(1), 36L);
Assert.assertEquals((long) res.get(2), 52L);
Assert.assertEquals((long) res.get(3), 98L);
Assert.assertEquals((long) res.get(4), 100L);
}
@Test
public void maxExpectedTest() throws Exception {
final Properties props = new Properties();
props.setProperty("correctionMode", "auto");
props.setProperty("precision", "1");
props.setProperty("detail", "1");
props.setProperty("prefix", "p");
props.setProperty("maxExpectedValue", "1000");
Measurement m = runTest(props);
final List<Long> res = new ArrayList<>();
m.getAll().forEach((k, v) -> {
if (k.startsWith("p0.937") || k.startsWith("p0.968") || k.startsWith("p0.984") || k.startsWith("p0.992") || k.startsWith("p0.996") || k.startsWith("p0.998") || k.startsWith("p0.999")) {
res.add(Long.valueOf((String) v));
}
});
int i = 0;
Assert.assertEquals((long) res.get(i++), 2L);
Assert.assertEquals((long) res.get(i++), 39L);
Assert.assertEquals((long) res.get(i++), 71L);
Assert.assertEquals((long) res.get(i++), 87L);
Assert.assertEquals((long) res.get(i++), 95L);
Assert.assertEquals((long) res.get(i++), 99L);
Assert.assertEquals((long) res.get(i), 103L);
}
@Test
public void userModeTest() throws Exception {
final Properties props = new Properties();
props.setProperty("correctionMode", "user");
props.setProperty("correction", "1.5");
props.setProperty("precision", "2");
props.setProperty("detail", "1");
props.setProperty("prefix", "p");
Measurement m = runTest(props);
final List<Long> res = new ArrayList<>();
m.getAll().forEach((k, v) -> {
if (k.startsWith("p0.937") || k.startsWith("p0.968") || k.startsWith("p0.984") || k.startsWith("p0.992") || k.startsWith("p0.999")) {
res.add(Long.valueOf((String) v));
}
});
Assert.assertEquals((long) res.get(0), 2);
Assert.assertEquals((long) res.get(1), 35);
Assert.assertEquals((long) res.get(2), 68);
Assert.assertEquals((long) res.get(3), 84);
Assert.assertEquals((long) res.get(4), 98);
Assert.assertEquals((long) res.get(5), 99);
Assert.assertEquals((long) res.get(6), 100);
}
@Test(enabled = false)
public void testResultFiltering() {
final SortedMap<String, String> results = new TreeMap<>();
results.put("perc0.000000000000", "2");
results.put("perc0.500000000000", "2");
results.put("perc0.750000000000", "2");
results.put("perc0.875000000000", "2");
results.put("perc0.937500000000", "2");
results.put("perc0.968750000000", "2");
results.put("perc0.984375000000", "2");
results.put("perc0.992187500000", "2");
results.put("perc0.996093750000", "2");
results.put("perc0.998046875000", "3");
results.put("perc0.999023437500", "3");
results.put("perc0.999511718750", "4");
results.put("perc0.999755859375", "5");
results.put("perc0.999877929688", "5");
results.put("perc0.999938964844", "6");
results.put("perc1.000000000000", "6");
String lastKey = null;
String lastValue = null;
SortedMap<String, String> output = new TreeMap<>();
for (Map.Entry<String, String> entry : results.entrySet()) {
if (lastValue != null) {
if (!entry.getValue().equals(lastValue)) {
output.put(lastKey, lastValue);
} else if (entry.getKey() == results.lastKey()) {
output.put(entry.getKey(), entry.getValue());
}
}
lastKey = entry.getKey();
lastValue = entry.getValue();
}
System.out.println(output);
}
private Measurement runTest(final Properties props) throws Exception {
final ReportManager rm = new ReportManager();
final RunInfo ri = new RunInfo(new Period(PeriodType.ITERATION, 1000));
final Reporter r = (Reporter) ObjectFactory.summonInstance("org.perfcake.reporting.reporter.ResponseTimeHistogramReporter", props);
final DummyDestination d = new DummyDestination();
rm.setRunInfo(ri);
rm.registerReporter(r);
r.registerDestination(d, new Period(PeriodType.ITERATION, 1000));
rm.start();
for (int i = 0; i < 1000; i++) {
FakeMeasurementUnit mu = new FakeMeasurementUnit(i);
mu.setTime(i == 999 ? 100 : 2);
rm.newMeasurementUnit(); // just to increase counter in RunInfo and make the test progress
mu.startMeasure();
mu.stopMeasure();
rm.report(mu);
}
rm.stop();
Thread.sleep(500);
Measurement m = d.getLastMeasurement();
if (log.isDebugEnabled()) {
m.getAll().forEach((k, v) -> {
log.debug(k + ": " + v);
});
}
return m;
}
}