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