001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.test;
019
020import static org.junit.Assert.assertEquals;
021import static org.junit.Assert.assertNotNull;
022import static org.junit.Assert.assertTrue;
023
024import java.util.HashMap;
025import java.util.Locale;
026import java.util.Map;
027import org.apache.hadoop.hbase.metrics.BaseSource;
028import org.apache.hadoop.metrics2.AbstractMetric;
029import org.apache.hadoop.metrics2.MetricsCollector;
030import org.apache.hadoop.metrics2.MetricsInfo;
031import org.apache.hadoop.metrics2.MetricsRecordBuilder;
032import org.apache.hadoop.metrics2.MetricsSource;
033import org.apache.hadoop.metrics2.MetricsTag;
034import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem;
035
036/**
037 * A helper class that will allow tests to get into hadoop2's metrics2 values.
038 */
039public class MetricsAssertHelperImpl implements MetricsAssertHelper {
040  private Map<String, String> tags = new HashMap<>();
041  private Map<String, Number> gauges = new HashMap<>();
042  private Map<String, Long> counters = new HashMap<>();
043
044  public class MockMetricsBuilder implements MetricsCollector {
045
046    @Override
047    public MetricsRecordBuilder addRecord(String s) {
048      return new MockRecordBuilder(this);
049    }
050
051    @Override
052    public MetricsRecordBuilder addRecord(MetricsInfo metricsInfo) {
053      return new MockRecordBuilder(this);
054    }
055  }
056
057  public class MockRecordBuilder extends MetricsRecordBuilder {
058
059    private final MetricsCollector mockMetricsBuilder;
060
061    public MockRecordBuilder(MetricsCollector mockMetricsBuilder) {
062
063      this.mockMetricsBuilder = mockMetricsBuilder;
064    }
065
066    @Override
067    public MetricsRecordBuilder tag(MetricsInfo metricsInfo, String s) {
068
069      tags.put(canonicalizeMetricName(metricsInfo.name()), s);
070      return this;
071    }
072
073    @Override
074    public MetricsRecordBuilder add(MetricsTag metricsTag) {
075      tags.put(canonicalizeMetricName(metricsTag.name()), metricsTag.value());
076      return this;
077    }
078
079    @Override
080    public MetricsRecordBuilder add(AbstractMetric abstractMetric) {
081      gauges.put(canonicalizeMetricName(abstractMetric.name()), abstractMetric.value());
082      return this;
083    }
084
085    @Override
086    public MetricsRecordBuilder setContext(String s) {
087      return this;
088    }
089
090    @Override
091    public MetricsRecordBuilder addCounter(MetricsInfo metricsInfo, int i) {
092      counters.put(canonicalizeMetricName(metricsInfo.name()), Long.valueOf(i));
093      return this;
094    }
095
096    @Override
097    public MetricsRecordBuilder addCounter(MetricsInfo metricsInfo, long l) {
098      counters.put(canonicalizeMetricName(metricsInfo.name()), Long.valueOf(l));
099      return this;
100    }
101
102    @Override
103    public MetricsRecordBuilder addGauge(MetricsInfo metricsInfo, int i) {
104      gauges.put(canonicalizeMetricName(metricsInfo.name()), Long.valueOf(i));
105      return this;
106    }
107
108    @Override
109    public MetricsRecordBuilder addGauge(MetricsInfo metricsInfo, long l) {
110      gauges.put(canonicalizeMetricName(metricsInfo.name()), Long.valueOf(l));
111      return this;
112    }
113
114    @Override
115    public MetricsRecordBuilder addGauge(MetricsInfo metricsInfo, float v) {
116      gauges.put(canonicalizeMetricName(metricsInfo.name()), Double.valueOf(v));
117      return this;
118    }
119
120    @Override
121    public MetricsRecordBuilder addGauge(MetricsInfo metricsInfo, double v) {
122      gauges.put(canonicalizeMetricName(metricsInfo.name()), Double.valueOf(v));
123      return this;
124    }
125
126    @Override
127    public MetricsCollector parent() {
128      return mockMetricsBuilder;
129    }
130  }
131
132  @Override
133  public void init() {
134    // Make sure that the metrics system doesn't throw an exception when
135    // registering a source with the same name
136    DefaultMetricsSystem.setMiniClusterMode(true);
137  }
138
139  @Override
140  public void assertTag(String name, String expected, BaseSource source) {
141    getMetrics(source);
142    String cName = canonicalizeMetricName(name);
143    assertEquals("Tags should be equal", expected, tags.get(cName));
144  }
145
146  @Override
147  public void assertGauge(String name, long expected, BaseSource source) {
148    long found = getGaugeLong(name, source);
149    assertEquals("Metrics Should be equal", (long) Long.valueOf(expected), found);
150  }
151
152  @Override
153  public void assertGaugeGt(String name, long expected, BaseSource source) {
154    double found = getGaugeDouble(name, source);
155    assertTrue(name + " (" + found + ") should be greater than " + expected, found > expected);
156  }
157
158  @Override
159  public void assertGaugeLt(String name, long expected, BaseSource source) {
160    double found = getGaugeDouble(name, source);
161    assertTrue(name + "(" + found + ") should be less than " + expected, found < expected);
162  }
163
164  @Override
165  public void assertGauge(String name, double expected, BaseSource source) {
166    double found = getGaugeDouble(name, source);
167    assertEquals("Metrics Should be equal", (double) Double.valueOf(expected), found, 0.01);
168  }
169
170  @Override
171  public void assertGaugeGt(String name, double expected, BaseSource source) {
172    double found = getGaugeDouble(name, source);
173    assertTrue(name + "(" + found + ") should be greater than " + expected, found > expected);
174  }
175
176  @Override
177  public void assertGaugeLt(String name, double expected, BaseSource source) {
178    double found = getGaugeDouble(name, source);
179    assertTrue(name + "(" + found + ") should be less than " + expected, found < expected);
180  }
181
182  @Override
183  public void assertCounter(String name, long expected, BaseSource source) {
184    long found = getCounter(name, source);
185    assertEquals(name + "(" + found + ") should be equal", (long) Long.valueOf(expected), found);
186  }
187
188  @Override
189  public void assertCounterGt(String name, long expected, BaseSource source) {
190    long found = getCounter(name, source);
191    assertTrue(name + " (" + found + ") should be greater than " + expected, found > expected);
192  }
193
194  @Override
195  public void assertCounterLt(String name, long expected, BaseSource source) {
196    long found = getCounter(name, source);
197    assertTrue(name + "(" + found + ") should be less than " + expected, found < expected);
198  }
199
200  @Override
201  public long getCounter(String name, BaseSource source) {
202    getMetrics(source);
203    String cName = canonicalizeMetricName(name);
204    assertNotNull("Should get counter " + cName + " but did not", counters.get(cName));
205    return counters.get(cName).longValue();
206  }
207
208  @Override
209  public boolean checkCounterExists(String name, BaseSource source) {
210    getMetrics(source);
211    String cName = canonicalizeMetricName(name);
212    return counters.get(cName) != null;
213  }
214
215  @Override
216  public boolean checkGaugeExists(String name, BaseSource source) {
217    getMetrics(source);
218    String cName = canonicalizeMetricName(name);
219    return gauges.get(cName) != null;
220  }
221
222  @Override
223  public double getGaugeDouble(String name, BaseSource source) {
224    getMetrics(source);
225    String cName = canonicalizeMetricName(name);
226    assertNotNull("Should get gauge " + cName + " but did not", gauges.get(cName));
227    return gauges.get(cName).doubleValue();
228  }
229
230  @Override
231  public long getGaugeLong(String name, BaseSource source) {
232    getMetrics(source);
233    String cName = canonicalizeMetricName(name);
234    assertNotNull("Should get gauge " + cName + " but did not", gauges.get(cName));
235    return gauges.get(cName).longValue();
236  }
237
238  @Override
239  public String toDebugString(BaseSource source) {
240    getMetrics(source);
241    StringBuilder sb = new StringBuilder();
242    sb.append("Tags=").append(tags).append(", Counters=").append(counters);
243    return sb.append(", Gauges=").append(gauges).toString();
244  }
245
246  private void reset() {
247    tags.clear();
248    gauges.clear();
249    counters.clear();
250  }
251
252  private void getMetrics(BaseSource source) {
253    reset();
254    if (!(source instanceof MetricsSource)) {
255      assertTrue("The Source passed must be a MetricsSource", false);
256    }
257    MetricsSource impl = (MetricsSource) source;
258
259    impl.getMetrics(new MockMetricsBuilder(), true);
260
261  }
262
263  private String canonicalizeMetricName(String in) {
264    return in.toLowerCase(Locale.ROOT).replaceAll("[^A-Za-z0-9 ]", "");
265  }
266}