blob: a7024c5ef9faf118d4095401238fa4893624da19 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.hadoop.test;
import static com.google.common.base.Preconditions.*;
import org.hamcrest.Description;
import org.junit.Assert;
import static org.mockito.AdditionalMatchers.geq;
import static org.mockito.Mockito.*;
import org.mockito.stubbing.Answer;
import org.mockito.internal.matchers.GreaterThan;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatcher;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.metrics2.MetricsInfo;
import org.apache.hadoop.metrics2.MetricsCollector;
import org.apache.hadoop.metrics2.MetricsSource;
import org.apache.hadoop.metrics2.MetricsRecordBuilder;
import org.apache.hadoop.metrics2.MetricsSystem;
import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem;
import org.apache.hadoop.metrics2.lib.MutableQuantiles;
import org.apache.hadoop.metrics2.util.Quantile;
import static org.apache.hadoop.metrics2.lib.Interns.*;
/**
* Helpers for metrics source tests
*/
public class MetricsAsserts {
final static Log LOG = LogFactory.getLog(MetricsAsserts.class);
private static final double EPSILON = 0.00001;
public static MetricsSystem mockMetricsSystem() {
MetricsSystem ms = mock(MetricsSystem.class);
DefaultMetricsSystem.setInstance(ms);
return ms;
}
public static MetricsRecordBuilder mockMetricsRecordBuilder() {
final MetricsCollector mc = mock(MetricsCollector.class);
MetricsRecordBuilder rb = mock(MetricsRecordBuilder.class,
new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
StringBuilder sb = new StringBuilder();
for (Object o : args) {
if (sb.length() > 0) sb.append(", ");
sb.append(String.valueOf(o));
}
String methodName = invocation.getMethod().getName();
LOG.debug(methodName +": "+ sb);
return methodName.equals("parent") || methodName.equals("endRecord") ?
mc : invocation.getMock();
}
});
when(mc.addRecord(anyString())).thenReturn(rb);
when(mc.addRecord(anyInfo())).thenReturn(rb);
return rb;
}
/**
* Call getMetrics on source and get a record builder mock to verify
* @param source the metrics source
* @param all if true, return all metrics even if not changed
* @return the record builder mock to verify
*/
public static MetricsRecordBuilder getMetrics(MetricsSource source,
boolean all) {
MetricsRecordBuilder rb = mockMetricsRecordBuilder();
MetricsCollector mc = rb.parent();
source.getMetrics(mc, all);
return rb;
}
public static MetricsRecordBuilder getMetrics(String name) {
return getMetrics(DefaultMetricsSystem.instance().getSource(name));
}
public static MetricsRecordBuilder getMetrics(MetricsSource source) {
return getMetrics(source, true);
}
private static class InfoWithSameName extends ArgumentMatcher<MetricsInfo> {
private final String expected;
InfoWithSameName(MetricsInfo info) {
expected = checkNotNull(info.name(), "info name");
}
@Override public boolean matches(Object info) {
return expected.equals(((MetricsInfo)info).name());
}
@Override public void describeTo(Description desc) {
desc.appendText("Info with name="+ expected);
}
}
/**
* MetricInfo with the same name
* @param info to match
* @return <code>null</code>
*/
public static MetricsInfo eqName(MetricsInfo info) {
return argThat(new InfoWithSameName(info));
}
private static class AnyInfo extends ArgumentMatcher<MetricsInfo> {
@Override public boolean matches(Object info) {
return info instanceof MetricsInfo; // not null as well
}
}
public static MetricsInfo anyInfo() {
return argThat(new AnyInfo());
}
/**
* Assert an int gauge metric as expected
* @param name of the metric
* @param expected value of the metric
* @param rb the record builder mock used to getMetrics
*/
public static void assertGauge(String name, int expected,
MetricsRecordBuilder rb) {
Assert.assertEquals("Bad value for metric " + name,
expected, getIntGauge(name, rb));
}
public static int getIntGauge(String name, MetricsRecordBuilder rb) {
ArgumentCaptor<Integer> captor = ArgumentCaptor.forClass(Integer.class);
verify(rb, atLeast(0)).addGauge(eqName(info(name, "")), captor.capture());
checkCaptured(captor, name);
return captor.getValue();
}
/**
* Assert an int counter metric as expected
* @param name of the metric
* @param expected value of the metric
* @param rb the record builder mock used to getMetrics
*/
public static void assertCounter(String name, int expected,
MetricsRecordBuilder rb) {
Assert.assertEquals("Bad value for metric " + name,
expected, getIntCounter(name, rb));
}
public static int getIntCounter(String name, MetricsRecordBuilder rb) {
ArgumentCaptor<Integer> captor = ArgumentCaptor.forClass(
Integer.class);
verify(rb, atLeast(0)).addCounter(eqName(info(name, "")), captor.capture());
checkCaptured(captor, name);
return captor.getValue();
}
/**
* Assert a long gauge metric as expected
* @param name of the metric
* @param expected value of the metric
* @param rb the record builder mock used to getMetrics
*/
public static void assertGauge(String name, long expected,
MetricsRecordBuilder rb) {
Assert.assertEquals("Bad value for metric " + name,
expected, getLongGauge(name, rb));
}
public static long getLongGauge(String name, MetricsRecordBuilder rb) {
ArgumentCaptor<Long> captor = ArgumentCaptor.forClass(Long.class);
verify(rb, atLeast(0)).addGauge(eqName(info(name, "")), captor.capture());
checkCaptured(captor, name);
return captor.getValue();
}
/**
* Assert a double gauge metric as expected
* @param name of the metric
* @param expected value of the metric
* @param rb the record builder mock used to getMetrics
*/
public static void assertGauge(String name, double expected,
MetricsRecordBuilder rb) {
Assert.assertEquals("Bad value for metric " + name,
expected, getDoubleGauge(name, rb), EPSILON);
}
public static double getDoubleGauge(String name, MetricsRecordBuilder rb) {
ArgumentCaptor<Double> captor = ArgumentCaptor.forClass(Double.class);
verify(rb, atLeast(0)).addGauge(eqName(info(name, "")), captor.capture());
checkCaptured(captor, name);
return captor.getValue();
}
/**
* Assert a long counter metric as expected
* @param name of the metric
* @param expected value of the metric
* @param rb the record builder mock used to getMetrics
*/
public static void assertCounter(String name, long expected,
MetricsRecordBuilder rb) {
Assert.assertEquals("Bad value for metric " + name,
expected, getLongCounter(name, rb));
}
public static long getLongCounter(String name, MetricsRecordBuilder rb) {
ArgumentCaptor<Long> captor = ArgumentCaptor.forClass(Long.class);
verify(rb, atLeast(0)).addCounter(eqName(info(name, "")), captor.capture());
checkCaptured(captor, name);
return captor.getValue();
}
/**
* Check that this metric was captured exactly once.
*/
private static void checkCaptured(ArgumentCaptor<?> captor, String name) {
Assert.assertEquals("Expected exactly one metric for name " + name,
1, captor.getAllValues().size());
}
/**
* Assert an int gauge metric as expected
* @param name of the metric
* @param expected value of the metric
* @param source to get metrics from
*/
public static void assertGauge(String name, int expected,
MetricsSource source) {
assertGauge(name, expected, getMetrics(source));
}
/**
* Assert an int counter metric as expected
* @param name of the metric
* @param expected value of the metric
* @param source to get metrics from
*/
public static void assertCounter(String name, int expected,
MetricsSource source) {
assertCounter(name, expected, getMetrics(source));
}
/**
* Assert a long gauge metric as expected
* @param name of the metric
* @param expected value of the metric
* @param source to get metrics from
*/
public static void assertGauge(String name, long expected,
MetricsSource source) {
assertGauge(name, expected, getMetrics(source));
}
/**
* Assert a long counter metric as expected
* @param name of the metric
* @param expected value of the metric
* @param source to get metrics from
*/
public static void assertCounter(String name, long expected,
MetricsSource source) {
assertCounter(name, expected, getMetrics(source));
}
/**
* Assert that a long counter metric is greater than a value
* @param name of the metric
* @param greater value of the metric should be greater than this
* @param rb the record builder mock used to getMetrics
*/
public static void assertCounterGt(String name, long greater,
MetricsRecordBuilder rb) {
Assert.assertThat("Bad value for metric " + name, getLongCounter(name, rb),
new GreaterThan<Long>(greater));
}
/**
* Assert that a long counter metric is greater than a value
* @param name of the metric
* @param greater value of the metric should be greater than this
* @param source the metrics source
*/
public static void assertCounterGt(String name, long greater,
MetricsSource source) {
assertCounterGt(name, greater, getMetrics(source));
}
/**
* Assert that a double gauge metric is greater than a value
* @param name of the metric
* @param greater value of the metric should be greater than this
* @param rb the record builder mock used to getMetrics
*/
public static void assertGaugeGt(String name, double greater,
MetricsRecordBuilder rb) {
Assert.assertThat("Bad value for metric " + name, getDoubleGauge(name, rb),
new GreaterThan<Double>(greater));
}
/**
* Assert that a double gauge metric is greater than a value
* @param name of the metric
* @param greater value of the metric should be greater than this
* @param source the metrics source
*/
public static void assertGaugeGt(String name, double greater,
MetricsSource source) {
assertGaugeGt(name, greater, getMetrics(source));
}
/**
* Asserts that the NumOps and quantiles for a metric have been changed at
* some point to a non-zero value.
*
* @param prefix of the metric
* @param rb MetricsRecordBuilder with the metric
*/
public static void assertQuantileGauges(String prefix,
MetricsRecordBuilder rb) {
verify(rb).addGauge(eqName(info(prefix + "NumOps", "")), geq(0l));
for (Quantile q : MutableQuantiles.quantiles) {
String nameTemplate = prefix + "%dthPercentileLatency";
int percentile = (int) (100 * q.quantile);
verify(rb).addGauge(
eqName(info(String.format(nameTemplate, percentile), "")),
geq(0l));
}
}
}