package io.prometheus.client;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import static java.util.Arrays.asList;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class SummaryTest {
CollectorRegistry registry;
Summary noLabels, labels, labelsAndQuantiles, noLabelsAndQuantiles;
@Before
public void setUp() {
registry = new CollectorRegistry();
noLabels = Summary.build().name("nolabels").help("help").register(registry);
labels = Summary.build().name("labels").help("help").labelNames("l").register(registry);
noLabelsAndQuantiles = Summary.build()
.quantile(0.5, 0.05)
.quantile(0.9, 0.01)
.quantile(0.99, 0.001)
.name("no_labels_and_quantiles").help("help").register(registry);
labelsAndQuantiles = Summary.build()
.quantile(0.5, 0.05)
.quantile(0.9, 0.01)
.quantile(0.99, 0.001)
.labelNames("l")
.name("labels_and_quantiles").help("help").register(registry);
}
@After
public void tearDown() {
SimpleTimer.defaultTimeProvider = new SimpleTimer.TimeProvider();
}
private double getCount() {
return registry.getSampleValue("nolabels_count").doubleValue();
}
private double getSum() {
return registry.getSampleValue("nolabels_sum").doubleValue();
}
private double getNoLabelQuantile(double q) {
return registry.getSampleValue("no_labels_and_quantiles", new String[]{"quantile"}, new String[]{Collector.doubleToGoString(q)}).doubleValue();
}
private double getLabeledQuantile(String labelValue, double q) {
return registry.getSampleValue("labels_and_quantiles", new String[]{"l", "quantile"}, new String[]{labelValue, Collector.doubleToGoString(q)}).doubleValue();
}
@Test
public void testObserve() {
noLabels.observe(2);
assertEquals(1.0, getCount(), .001);
assertEquals(2.0, getSum(), .001);
assertEquals(1.0, noLabels.get().count, .001);
assertEquals(2.0, noLabels.get().sum, .001);
noLabels.labels().observe(4);
assertEquals(2.0, getCount(), .001);
assertEquals(6.0, getSum(), .001);
assertEquals(2.0, noLabels.get().count, .001);
assertEquals(6.0, noLabels.get().sum, .001);
}
@Test
public void testQuantiles() {
int nSamples = 1000000; // simulate one million samples
for (int i=1; i<=nSamples; i++) {
// In this test, we observe the numbers from 1 to nSamples,
// because that makes it easy to verify if the quantiles are correct.
labelsAndQuantiles.labels("a").observe(i);
noLabelsAndQuantiles.observe(i);
}
assertEquals(getNoLabelQuantile(0.5), 0.5 * nSamples, 0.05 * nSamples);
assertEquals(getNoLabelQuantile(0.9), 0.9 * nSamples, 0.01 * nSamples);
assertEquals(getNoLabelQuantile(0.99), 0.99 * nSamples, 0.001 * nSamples);
assertEquals(getLabeledQuantile("a", 0.5), 0.5 * nSamples, 0.05 * nSamples);
assertEquals(getLabeledQuantile("a", 0.9), 0.9 * nSamples, 0.01 * nSamples);
assertEquals(getLabeledQuantile("a", 0.99), 0.99 * nSamples, 0.001 * nSamples);
}
@Test
public void testMaxAge() throws InterruptedException {
Summary summary = Summary.build()
.quantile(0.99, 0.001)
.maxAgeSeconds(1) // After 1s, all observations will be discarded.
.ageBuckets(2) // We got 2 buckets, so we discard one bucket every 500ms.
.name("short_attention_span").help("help").register(registry);
summary.observe(8.0);
double val = registry.getSampleValue("short_attention_span", new String[]{"quantile"}, new String[]{Collector.doubleToGoString(0.99)}).doubleValue();
assertEquals(8.0, val, 0.0); // From bucket 1.
Thread.sleep(600);
val = registry.getSampleValue("short_attention_span", new String[]{"quantile"}, new String[]{Collector.doubleToGoString(0.99)}).doubleValue();
assertEquals(8.0, val, 0.0); // From bucket 2.
Thread.sleep(600);
val = registry.getSampleValue("short_attention_span", new String[]{"quantile"}, new String[]{Collector.doubleToGoString(0.99)}).doubleValue();
assertEquals(Double.NaN, val, 0.0); // Bucket 1 again, now it is empty.
}
@Test
public void testTimer() {
SimpleTimer.defaultTimeProvider = new SimpleTimer.TimeProvider() {
long value = (long)(30 * 1e9);
long nanoTime() {
value += (long)(10 * 1e9);
return value;
}
};
double elapsed = noLabels.time(new Runnable() {
@Override
public void run() {
//no op
}
});
assertEquals(10, elapsed, .001);
Summary.Timer timer = noLabels.startTimer();
elapsed = timer.observeDuration();
assertEquals(2, getCount(), .001);
assertEquals(20, getSum(), .001);
assertEquals(10, elapsed, .001);
}
@Test
public void noLabelsDefaultZeroValue() {
assertEquals(0.0, getCount(), .001);
assertEquals(0.0, getSum(), .001);
}
private Double getLabelsCount(String labelValue) {
return registry.getSampleValue("labels_count", new String[]{"l"}, new String[]{labelValue});
}
private Double getLabelsSum(String labelValue) {
return registry.getSampleValue("labels_sum", new String[]{"l"}, new String[]{labelValue});
}
@Test
public void testLabels() {
assertEquals(null, getLabelsCount("a"));
assertEquals(null, getLabelsSum("a"));
assertEquals(null, getLabelsCount("b"));
assertEquals(null, getLabelsSum("b"));
labels.labels("a").observe(2);
assertEquals(1.0, getLabelsCount("a").doubleValue(), .001);
assertEquals(2.0, getLabelsSum("a").doubleValue(), .001);
assertEquals(null, getLabelsCount("b"));
assertEquals(null, getLabelsSum("b"));
labels.labels("b").observe(3);
assertEquals(1.0, getLabelsCount("a").doubleValue(), .001);
assertEquals(2.0, getLabelsSum("a").doubleValue(), .001);
assertEquals(1.0, getLabelsCount("b").doubleValue(), .001);
assertEquals(3.0, getLabelsSum("b").doubleValue(), .001);
}
@Test
public void testCollect() {
labels.labels("a").observe(2);
List<Collector.MetricFamilySamples> mfs = labels.collect();
ArrayList<Collector.MetricFamilySamples.Sample> samples = new ArrayList<Collector.MetricFamilySamples.Sample>();
ArrayList<String> labelNames = new ArrayList<String>();
labelNames.add("l");
ArrayList<String> labelValues = new ArrayList<String>();
labelValues.add("a");
samples.add(new Collector.MetricFamilySamples.Sample("labels_count", labelNames, labelValues, 1.0));
samples.add(new Collector.MetricFamilySamples.Sample("labels_sum", labelNames, labelValues, 2.0));
Collector.MetricFamilySamples mfsFixture = new Collector.MetricFamilySamples("labels", Collector.Type.SUMMARY, "help", samples);
assertEquals(1, mfs.size());
assertEquals(mfsFixture, mfs.get(0));
}
@Test
public void testCollectWithQuantiles() {
labelsAndQuantiles.labels("a").observe(2);
List<Collector.MetricFamilySamples> mfs = labelsAndQuantiles.collect();
ArrayList<Collector.MetricFamilySamples.Sample> samples = new ArrayList<Collector.MetricFamilySamples.Sample>();
samples.add(new Collector.MetricFamilySamples.Sample("labels_and_quantiles", asList("l", "quantile"), asList("a", "0.5"), 2.0));
samples.add(new Collector.MetricFamilySamples.Sample("labels_and_quantiles", asList("l", "quantile"), asList("a", "0.9"), 2.0));
samples.add(new Collector.MetricFamilySamples.Sample("labels_and_quantiles", asList("l", "quantile"), asList("a", "0.99"), 2.0));
samples.add(new Collector.MetricFamilySamples.Sample("labels_and_quantiles_count", asList("l"), asList("a"), 1.0));
samples.add(new Collector.MetricFamilySamples.Sample("labels_and_quantiles_sum", asList("l"), asList("a"), 2.0));
Collector.MetricFamilySamples mfsFixture = new Collector.MetricFamilySamples("labels_and_quantiles", Collector.Type.SUMMARY, "help", samples);
assertEquals(1, mfs.size());
assertEquals(mfsFixture, mfs.get(0));
}
@Test
public void testChildAndValuePublicApi() throws Exception {
assertTrue(Modifier.isPublic(Summary.Child.class.getModifiers()));
final Method getMethod = Summary.Child.class.getMethod("get");
assertTrue(Modifier.isPublic(getMethod.getModifiers()));
assertEquals(Summary.Child.Value.class, getMethod.getReturnType());
assertTrue(Modifier.isPublic(Summary.Child.Value.class.getModifiers()));
assertTrue(Modifier.isPublic(Summary.Child.Value.class.getField("count").getModifiers()));
assertTrue(Modifier.isPublic(Summary.Child.Value.class.getField("sum").getModifiers()));
assertTrue(Modifier.isPublic(Summary.Child.Value.class.getField("quantiles").getModifiers()));
}
}