// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.metrics.simple;
import static org.junit.Assert.*;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Handler;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import java.util.Set;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.google.common.collect.ImmutableMap;
import com.yahoo.metrics.simple.UntypedMetric.AssumedType;
/**
* Functional tests for the value buckets, as implemented in the class Bucket,
* and by extension the value store itself, UntypedValue.
*
* @author Steinar Knutsen
*/
public class BucketTest {
private Bucket bucket;
@Before
public void setUp() throws Exception {
bucket = new Bucket();
}
@After
public void tearDown() throws Exception {
bucket = null;
}
@Test
public final void testEntrySet() {
assertEquals(0, bucket.entrySet().size());
for (int i = 0; i < 4; ++i) {
bucket.put(new Sample(new Measurement(i), new Identifier("nalle_" + i, null), AssumedType.GAUGE));
}
assertEquals(4, bucket.entrySet().size());
for (int i = 0; i < 4; ++i) {
bucket.put(new Sample(new Measurement(i), new Identifier("nalle",
new Point(new ImmutableMap.Builder().put("dim", Integer.valueOf(i)).build())),
AssumedType.GAUGE));
}
assertEquals(8, bucket.entrySet().size());
int nalle = 0, nalle0 = 0, nalle1 = 0, nalle2 = 0, nalle3 = 0;
for (Entry x : bucket.entrySet()) {
String metricName = x.getKey().getName();
switch (metricName) {
case "nalle":
++nalle;
break;
case "nalle_0":
++nalle0;
break;
case "nalle_1":
++nalle1;
break;
case "nalle_2":
++nalle2;
break;
case "nalle_3":
++nalle3;
break;
default:
throw new IllegalStateException();
}
}
assertEquals(4, nalle);
assertEquals(1, nalle0);
assertEquals(1, nalle1);
assertEquals(1, nalle2);
assertEquals(1, nalle3);
}
@Test
public final void testPutSampleWithUnsupportedType() {
boolean caughtIt = false;
try {
bucket.put(new Sample(new Measurement(1), new Identifier("nalle", null), AssumedType.NONE));
} catch (Exception e) {
caughtIt = true;
}
assertTrue(caughtIt);
}
@Test
public final void testPutIdentifierUntypedValue() {
UntypedMetric v = new UntypedMetric(null);
v.add(2);
bucket.put(new Sample(new Measurement(3), new Identifier("nalle", null), AssumedType.GAUGE));
bucket.put(new Identifier("nalle", null), v);
assertEquals(1, bucket.entrySet().size());
// check raw overwriting
Entry stored = bucket.entrySet().iterator().next();
assertEquals(new Identifier("nalle", null), stored.getKey());
assertTrue(stored.getValue().isCounter());
}
@Test
public final void testHasIdentifier() {
for (int i = 0; i < 4; ++i) {
bucket.put(new Sample(new Measurement(i), new Identifier("nalle_" + i, new Point(
new ImmutableMap.Builder().put(String.valueOf(i), Integer.valueOf(i)).build())),
AssumedType.GAUGE));
}
for (int i = 0; i < 4; ++i) {
assertTrue(bucket.hasIdentifier(new Identifier("nalle_" + i, new Point(new ImmutableMap.Builder().put(
String.valueOf(i), Integer.valueOf(i)).build()))));
}
}
@Test
public final void testOkMerge() {
bucket.put(new Sample(new Measurement(2), new Identifier("nalle", null), AssumedType.GAUGE));
Bucket otherNew = new Bucket();
otherNew.put(new Sample(new Measurement(3), new Identifier("nalle", null), AssumedType.GAUGE));
Bucket otherOld = new Bucket();
otherOld.put(new Sample(new Measurement(5), new Identifier("nalle", null), AssumedType.GAUGE));
bucket.merge(otherNew, true);
bucket.merge(otherOld, false);
Set> entries = bucket.entrySet();
assertEquals(1, entries.size());
Entry entry = entries.iterator().next();
assertEquals(10, entry.getValue().getSum(), 0.0);
assertEquals(3, entry.getValue().getLast(), 0.0);
assertEquals(2, entry.getValue().getMin(), 0.0);
assertEquals(5, entry.getValue().getMax(), 0.0);
assertEquals(3, entry.getValue().getCount());
}
@Test
public final void testMergeDifferentMetrics() {
bucket.put(new Sample(new Measurement(2), new Identifier("nalle", null), AssumedType.GAUGE));
Bucket otherNew = new Bucket();
otherNew.put(new Sample(new Measurement(3), new Identifier("other", null), AssumedType.GAUGE));
bucket.merge(otherNew, true);
Set> entries = bucket.entrySet();
assertEquals(2, entries.size());
Collection> nalle_values = bucket.getValuesForMetric("nalle");
assertEquals(1, nalle_values.size());
Collection> other_values = bucket.getValuesForMetric("other");
assertEquals(1, other_values.size());
UntypedMetric nalle_v = nalle_values.iterator().next().getValue();
assertEquals(1, nalle_v.getCount());
assertEquals(2, nalle_v.getSum(), 0.0);
assertEquals(2, nalle_v.getLast(), 0.0);
assertEquals(2, nalle_v.getMin(), 0.0);
assertEquals(2, nalle_v.getMax(), 0.0);
UntypedMetric other_v = other_values.iterator().next().getValue();
assertEquals(1, other_v.getCount());
assertEquals(3, other_v.getSum(), 0.0);
assertEquals(3, other_v.getLast(), 0.0);
assertEquals(3, other_v.getMax(), 0.0);
assertEquals(3, other_v.getMin(), 0.0);
}
private static class CheckThatItWasLogged extends Handler {
final boolean[] loggingMarker;
public CheckThatItWasLogged(boolean[] loggingMarker) {
this.loggingMarker = loggingMarker;
}
@Override
public void publish(LogRecord record) {
loggingMarker[0] = true;
}
@Override
public void flush() {
}
@Override
public void close() throws SecurityException {
}
}
@Test
public final void testMismatchedMerge() {
Logger log = Logger.getLogger(Bucket.class.getName());
boolean[] loggingMarker = new boolean[1];
loggingMarker[0] = false;
log.setUseParentHandlers(false);
Handler logHandler = new CheckThatItWasLogged(loggingMarker);
log.addHandler(logHandler);
Bucket other = new Bucket();
bucket.put(new Sample(new Measurement(2), new Identifier("nalle", null), AssumedType.GAUGE));
other.put(new Sample(new Measurement(3), new Identifier("nalle", null), AssumedType.COUNTER));
bucket.merge(other, true);
assertTrue(loggingMarker[0]);
log.removeHandler(logHandler);
log.setUseParentHandlers(true);
}
@Test
public final void testGetAllMetricNames() {
twoMetricsUniqueDimensions();
Collection names = bucket.getAllMetricNames();
assertEquals(2, names.size());
assertTrue(names.contains("nalle"));
assertTrue(names.contains("nalle2"));
}
@Test
public final void testGetValuesForMetric() {
twoMetricsUniqueDimensions();
Collection> values = bucket.getValuesForMetric("nalle");
assertEquals(4, values.size());
}
private void twoMetricsUniqueDimensions() {
for (int i = 0; i < 4; ++i) {
bucket.put(new Sample(new Measurement(i), new Identifier("nalle", new Point(new ImmutableMap.Builder()
.put(String.valueOf(i), Integer.valueOf(i)).build())), AssumedType.GAUGE));
bucket.put(new Sample(new Measurement(i), new Identifier("nalle2", new Point(
new ImmutableMap.Builder().put(String.valueOf(i), Integer.valueOf(i)).build())),
AssumedType.GAUGE));
}
}
@Test
public final void testGetValuesByMetricName() {
twoMetricsUniqueDimensions();
Map>> values = bucket.getValuesByMetricName();
assertEquals(2, values.size());
assertEquals(4, values.get("nalle").size());
assertEquals(4, values.get("nalle2").size());
}
}