package io.pcp.parfait.dropwizard; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.util.SortedMap; import java.util.concurrent.TimeUnit; import com.codahale.metrics.Counter; import com.codahale.metrics.Gauge; import com.codahale.metrics.Histogram; import com.codahale.metrics.Meter; import com.codahale.metrics.Metric; import com.codahale.metrics.MetricFilter; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; import io.pcp.parfait.Monitorable; import io.pcp.parfait.MonitorableRegistry; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; @RunWith(MockitoJUnitRunner.class) public class ParfaitReporterTest { private static final String TIMER_METRIC = "timerMetric"; private static final String METER_METRIC = "meterMetric"; private static final String HISTOGRAM_METRIC = "histogramMetric"; private static final String COUNTER_METRIC = "counterMetric"; private static final String GAUGE_METRIC = "gaugeMetric"; private static final String METRIC_NAME_PREFIX = "bim.codahale"; private ParfaitReporter parfaitReporter; @Mock private MetricFilter metricFilter; @Mock private TimeUnit durationUnit; @Mock private TimeUnit rateUnit; @Mock private MetricAdapterFactory metricAdapterFactory; @Mock private MetricAdapter metricAdapter; @Mock private Monitorable monitorable; @Mock private MonitorableRegistry monitorableRegistry; @Mock private MetricRegistry metricRegistry; @Mock private Gauge gauge; @Mock private Counter counter; @Mock private Histogram histogram; @Mock private Meter meter; @Mock private Timer timer; @Before public void setUp() { when(metricAdapter.getMonitorables()).thenReturn(Sets.newHashSet(monitorable)); parfaitReporter = new ParfaitReporter(metricRegistry, monitorableRegistry, metricAdapterFactory, rateUnit, durationUnit, metricFilter, METRIC_NAME_PREFIX); } @Test @SuppressWarnings("unchecked") public void shouldAttemptToPublishAllMetricsDuringReport() { when(metricAdapterFactory.createMetricAdapterFor(anyString(), any(Metric.class))).thenReturn(metricAdapter); parfaitReporter.report(generateGauges(), generateCounters(), generateHistogram(), generateMeters(), generateTimers()); verify(metricAdapterFactory).createMetricAdapterFor(METRIC_NAME_PREFIX + "." + TIMER_METRIC, timer); verify(metricAdapterFactory).createMetricAdapterFor(METRIC_NAME_PREFIX + "." + METER_METRIC, meter); verify(metricAdapterFactory).createMetricAdapterFor(METRIC_NAME_PREFIX + "." + HISTOGRAM_METRIC, histogram); verify(metricAdapterFactory).createMetricAdapterFor(METRIC_NAME_PREFIX + "." + COUNTER_METRIC, counter); verify(metricAdapterFactory).createMetricAdapterFor(METRIC_NAME_PREFIX + "." + GAUGE_METRIC, gauge); verify(monitorableRegistry, times(5)).register(monitorable); } @Test @SuppressWarnings("unchecked") public void shouldOnlyPublishOnlyPreviouslyUnseenMetricsDuringReport() { when(metricAdapterFactory.createMetricAdapterFor(anyString(), any(Metric.class))).thenReturn(metricAdapter); parfaitReporter.report(generateGauges(), generateCounters(), generateHistogram(), generateMeters(), generateTimers()); parfaitReporter.report(generateGauges(), generateCounters(), generateHistogram(), generateMeters(), generateTimers()); verify(monitorableRegistry, times(5)).register(any(Monitorable.class)); // Add a new gauge for this report call SortedMap<String, Gauge> gauges = generateGauges(); gauges.put("newGaugeMetric", mock(Gauge.class)); parfaitReporter.report(gauges, generateCounters(), generateHistogram(), generateMeters(), generateTimers()); verify(monitorableRegistry, times(6)).register(monitorable); } private SortedMap<String, Timer> generateTimers() { return newSortedMapContainingItem(TIMER_METRIC, timer); } private SortedMap<String, Meter> generateMeters() { return newSortedMapContainingItem(METER_METRIC, meter); } private SortedMap<String, Histogram> generateHistogram() { return newSortedMapContainingItem(HISTOGRAM_METRIC, histogram); } private SortedMap<String, Counter> generateCounters() { return newSortedMapContainingItem(COUNTER_METRIC, counter); } private SortedMap<String, Gauge> generateGauges() { return newSortedMapContainingItem(GAUGE_METRIC, gauge); } private <T> SortedMap<String, T> newSortedMapContainingItem(String key, T item) { SortedMap<String, T> newMap = Maps.newTreeMap(); newMap.put(key, item); return newMap; } }