/*
* 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 com.addthis.hydra.util;
import java.util.concurrent.TimeUnit;
import com.addthis.bundle.util.AutoField;
import com.addthis.bundle.util.map.MapBundle;
import com.addthis.hydra.task.output.TaskDataOutput;
import com.yammer.metrics.core.Counter;
import com.yammer.metrics.core.Gauge;
import com.yammer.metrics.core.Histogram;
import com.yammer.metrics.core.Meter;
import com.yammer.metrics.core.MetricName;
import com.yammer.metrics.core.Timer;
import com.yammer.metrics.stats.Snapshot;
import org.junit.Before;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import static com.addthis.bundle.util.map.MapBundle.decode;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class BundleReporterTest {
TaskDataOutput output;
AutoField name;
AutoField value;
AutoField group;
AutoField units;
long period;
BundleReporter reporter;
@Before
public void stubBundleCreation() {
output = mock(TaskDataOutput.class);
name = AutoField.newAutoField("name");
value = AutoField.newAutoField("value");
group = AutoField.newAutoField("group");
units = AutoField.newAutoField("units");
period = TimeUnit.SECONDS.toNanos(60);
reporter = new BundleReporter(output, name, value, group, units, period);
when(output.createBundle()).thenAnswer(invocation -> new MapBundle());
}
@Test
public void reportsStringGaugeValues() throws Exception {
reporter.processGauge(name("gauge"), gauge("value"), null);
verify(output).send(decode("name = t.test.gauge, value = value, group = gauge, units = \"\""));
}
@Test
public void escapeSlashesInMetricNames() throws Exception {
reporter.processGauge(name("gauge_with\\slashes"), gauge("value"), null);
verify(output).send(decode("name = t.test.gauge_with_slashes, value = value, group = gauge, units = \"\""));
}
@Test
public void reportsIntegerGaugeValues() throws Exception {
reporter.processGauge(name("gauge"), gauge(1), null);
verify(output).send(decode("name = t.test.gauge, value = 1, group = gauge, units = \"\""));
}
@Test
public void reportsLongGaugeValues() throws Exception {
reporter.processGauge(name("gauge"), gauge(1L), null);
verify(output).send(decode("name = t.test.gauge, value = 1, group = gauge, units = \"\""));
}
@Test
public void reportsDoubleGaugeValues() throws Exception {
reporter.processGauge(name("gauge"), gauge(1.1), null);
verify(output).send(decode("name = t.test.gauge, value = 1.1, group = gauge, units = \"\""));
}
@Test
public void reportsCounterValues() throws Exception {
final Counter counter = mock(Counter.class);
when(counter.count()).thenReturn(100L);
reporter.processCounter(name("counter"), counter, null);
verify(output).send(decode("name = t.test.counter, value = 100, group = counter, units = \"\""));
}
@Test
public void reportsHistogramValues() throws Exception {
final Histogram histogram = mock(Histogram.class);
when(histogram.count()).thenReturn(1L);
when(histogram.max()).thenReturn(2.0);
when(histogram.mean()).thenReturn(3.0);
when(histogram.min()).thenReturn(4.0);
when(histogram.stdDev()).thenReturn(5.0);
final Snapshot snapshot = mock(Snapshot.class);
when(snapshot.getMedian()).thenReturn(6.0);
when(snapshot.get75thPercentile()).thenReturn(7.0);
when(snapshot.get95thPercentile()).thenReturn(8.0);
when(snapshot.get98thPercentile()).thenReturn(9.0);
when(snapshot.get99thPercentile()).thenReturn(10.0);
when(snapshot.get999thPercentile()).thenReturn(11.0);
when(histogram.getSnapshot()).thenReturn(snapshot);
reporter.processHistogram(name("histogram"), histogram, null);
verify(output).send(decode("name = t.test.histogram.max, value = 2, group = histo, units = \"\""));
verify(output).send(decode("name = t.test.histogram.mean, value = 3.0, group = histo, units = \"\""));
verify(output).send(decode("name = t.test.histogram.min, value = 4, group = histo, units = \"\""));
verify(output).send(decode("name = t.test.histogram.stddev, value = 5.0, group = histo, units = \"\""));
verify(output).send(decode("name = t.test.histogram.median, value = 6.0, group = histo, units = \"\""));
verify(output).send(decode("name = t.test.histogram.75percentile, value = 7.0, group = histo, units = \"\""));
verify(output).send(decode("name = t.test.histogram.95percentile, value = 8.0, group = histo, units = \"\""));
verify(output).send(decode("name = t.test.histogram.98percentile, value = 9.0, group = histo, units = \"\""));
verify(output).send(decode("name = t.test.histogram.99percentile, value = 10.0, group = histo, units = \"\""));
verify(output).send(decode("name = t.test.histogram.999percentile, value = 11.0, group = histo, units = \"\""));
}
@Test
public void reportsMeterValues() throws Exception {
final Meter meter = mock(Meter.class);
when(meter.eventType()).thenReturn("events");
when(meter.rateUnit()).thenReturn(TimeUnit.SECONDS);
when(meter.count()).thenReturn(1L);
when(meter.meanRate()).thenReturn(2.0);
when(meter.oneMinuteRate()).thenReturn(3.0);
when(meter.fiveMinuteRate()).thenReturn(4.0);
when(meter.fifteenMinuteRate()).thenReturn(5.0);
reporter.processMeter(name("meter"), meter, null);
verify(output).send(decode("name = t.test.meter.count, value = 1, group = metered, units = events"));
verify(output).send(decode("name = t.test.meter.meanRate, value = 2.0, group = metered, units = events/second"));
verify(output).send(decode("name = t.test.meter.1MinuteRate, value = 3.0, group = metered, units = events/second"));
verify(output).send(decode("name = t.test.meter.5MinuteRate, value = 4.0, group = metered, units = events/second"));
verify(output).send(decode("name = t.test.meter.15MinuteRate, value = 5.0, group = metered, units = events/second"));
}
@Test
public void reportsTimerValues() throws Exception {
final Timer timer = mock(Timer.class);
when(timer.eventType()).thenReturn("events");
when(timer.durationUnit()).thenReturn(TimeUnit.MILLISECONDS);
when(timer.rateUnit()).thenReturn(TimeUnit.SECONDS);
when(timer.count()).thenReturn(1L);
when(timer.meanRate()).thenReturn(2.0);
when(timer.oneMinuteRate()).thenReturn(3.0);
when(timer.fiveMinuteRate()).thenReturn(4.0);
when(timer.fifteenMinuteRate()).thenReturn(5.0);
when(timer.max()).thenReturn(2.0);
when(timer.mean()).thenReturn(3.0);
when(timer.min()).thenReturn(4.0);
when(timer.stdDev()).thenReturn(5.0);
final Snapshot snapshot = mock(Snapshot.class);
when(snapshot.getMedian()).thenReturn((double) 500);
when(snapshot.get75thPercentile()).thenReturn((double) 600);
when(snapshot.get95thPercentile()).thenReturn((double) 700);
when(snapshot.get98thPercentile()).thenReturn((double) 800);
when(snapshot.get99thPercentile()).thenReturn((double) 900);
when(snapshot.get999thPercentile()).thenReturn((double) 1000);
when(timer.getSnapshot()).thenReturn(snapshot);
reporter.processTimer(name("another.timer"), timer, null);
verify(output).send(decode("name = t.test.another.timer.max, value = 2.0, group = timer, units = MILLISECONDS"));
verify(output).send(decode("name = t.test.another.timer.mean, value = 3.0, group = timer, units = MILLISECONDS"));
verify(output).send(decode("name = t.test.another.timer.min, value = 4.0, group = timer, units = MILLISECONDS"));
verify(output).send(decode("name = t.test.another.timer.stddev, value = 5.0, group = timer, units = MILLISECONDS"));
verify(output).send(decode("name = t.test.another.timer.median, value = 500.0, group = timer, units = MILLISECONDS"));
verify(output).send(decode("name = t.test.another.timer.75percentile, value = 600.0, group = timer, units = MILLISECONDS"));
verify(output).send(decode("name = t.test.another.timer.95percentile, value = 700.0, group = timer, units = MILLISECONDS"));
verify(output).send(decode("name = t.test.another.timer.98percentile, value = 800.0, group = timer, units = MILLISECONDS"));
verify(output).send(decode("name = t.test.another.timer.99percentile, value = 900.0, group = timer, units = MILLISECONDS"));
verify(output).send(decode("name = t.test.another.timer.999percentile, value = 1000.0, group = timer, units = MILLISECONDS"));
verify(output).send(decode("name = t.test.another.timer.count, value = 1, group = metered, units = events"));
verify(output).send(decode("name = t.test.another.timer.meanRate, value = 2.0, group = metered, units = events/second"));
verify(output).send(decode("name = t.test.another.timer.1MinuteRate, value = 3.0, group = metered, units = events/second"));
verify(output).send(decode("name = t.test.another.timer.5MinuteRate, value = 4.0, group = metered, units = events/second"));
verify(output).send(decode("name = t.test.another.timer.15MinuteRate, value = 5.0, group = metered, units = events/second"));
}
private <T> Gauge gauge(T value) {
final Gauge gauge = mock(Gauge.class);
when(gauge.value()).thenReturn(value);
return gauge;
}
private MetricName name(String simpleName) {
return new MetricName("t", "test", simpleName);
}
}