1   /*
2    * Copyright 2011 The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   * http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  
21  package org.apache.hadoop.hbase.regionserver;
22  
23  import static org.junit.Assert.assertTrue;
24  
25  import java.io.IOException;
26  import java.util.HashMap;
27  import java.util.Map;
28  
29  import org.apache.commons.logging.Log;
30  import org.apache.commons.logging.LogFactory;
31  import org.apache.hadoop.conf.Configuration;
32  import org.apache.hadoop.hbase.HBaseTestingUtility;
33  import org.apache.hadoop.hbase.MediumTests;
34  import org.apache.hadoop.hbase.ipc.HBaseRpcMetrics;
35  import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
36  import org.apache.hadoop.metrics.ContextFactory;
37  import org.apache.hadoop.metrics.MetricsContext;
38  import org.apache.hadoop.metrics.MetricsUtil;
39  import org.apache.hadoop.metrics.spi.AbstractMetricsContext;
40  import org.apache.hadoop.metrics.spi.OutputRecord;
41  import org.junit.AfterClass;
42  import org.junit.BeforeClass;
43  import org.junit.Test;
44  import org.junit.experimental.categories.Category;
45  
46  @Category(MediumTests.class)
47  public class TestRpcMetrics {
48    /**
49     * Defines test methods to register with HBaseRpcMetrics
50     */
51    public interface TestMetrics {
52      public void test();
53    }
54  
55    /**
56     * HRegionServer sub-class to register custom metrics
57     */
58    public static class TestRegionServer extends HRegionServer {
59  
60      public TestRegionServer(Configuration conf)
61          throws IOException, InterruptedException {
62        super(conf);
63  
64        // register custom metrics interface
65        getRpcMetrics().createMetrics(new Class[]{TestMetrics.class}, true);
66      }
67  
68      public void incTest(int amt) {
69        HBaseRpcMetrics metrics = getRpcMetrics();
70        // force an increment so we have something to check for
71        metrics.inc(metrics.getMetricName(TestMetrics.class, "test"), amt);
72      }
73    }
74  
75    /**
76     * Dummy metrics context to allow retrieval of values
77     */
78    public static class MockMetricsContext extends AbstractMetricsContext {
79  
80      public MockMetricsContext() {
81        // update every 1 sec.
82        setPeriod(1);
83      }
84  
85      @Override
86      protected void emitRecord(String contextName, String recordName,
87          OutputRecord outputRecord) throws IOException {
88        for (String name : outputRecord.getMetricNames()) {
89          Number val = outputRecord.getMetric(name);
90          if (val != null && val.intValue() > 0) {
91            METRICS.put(name, Boolean.TRUE);
92            LOG.debug("Set metric "+name+" to "+val);
93          }
94        }
95      }
96    }
97    private static Map<String,Boolean> METRICS = new HashMap<String,Boolean>();
98  
99    private static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
100   private static Log LOG = LogFactory.getLog(TestRpcMetrics.class);
101 
102   @BeforeClass
103   public static void setupBeforeClass() throws Exception {
104     // set custom metrics context
105     ContextFactory factory = ContextFactory.getFactory();
106     factory.setAttribute("rpc.class", MockMetricsContext.class.getName());
107     // make sure metrics context is setup, otherwise updating won't start
108     MetricsContext ctx = MetricsUtil.getContext("rpc");
109     assertTrue("Wrong MetricContext implementation class",
110         (ctx instanceof MockMetricsContext));
111 
112     TEST_UTIL.startMiniZKCluster();
113   }
114 
115   @AfterClass
116   public static void tearDownAfterClass() throws Exception {
117     TEST_UTIL.shutdownMiniZKCluster();
118   }
119 
120   @Test
121   public void testCustomMetrics() throws Exception {
122     TEST_UTIL.getConfiguration().setInt("hbase.regionserver.port", 0);
123     TestRegionServer rs = new TestRegionServer(TEST_UTIL.getConfiguration());
124     rs.incTest(5);
125 
126     String metricName = HBaseRpcMetrics.getMetricName(TestMetrics.class, "test");
127     long start = EnvironmentEdgeManager.currentTimeMillis();
128     while (!wasSet(metricName + "_num_ops")) {
129       if (EnvironmentEdgeManager.currentTimeMillis() - start > 60000) {
130         assertTrue("Metric should have set incremented for "+metricName,
131           wasSet(metricName + "_num_ops"));
132       }
133       Thread.sleep(200);
134     }
135   }
136 
137   public boolean wasSet(String name) {
138     return METRICS.get(name) != null ? METRICS.get(name) : false;
139   }
140 
141   @org.junit.Rule
142   public org.apache.hadoop.hbase.ResourceCheckerJUnitRule cu =
143     new org.apache.hadoop.hbase.ResourceCheckerJUnitRule();
144 }
145