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;
019
020import static org.junit.jupiter.api.Assertions.assertEquals;
021import static org.junit.jupiter.api.Assertions.assertNotNull;
022import static org.junit.jupiter.api.Assertions.assertTrue;
023import static org.junit.jupiter.api.Assertions.fail;
024
025import java.io.IOException;
026import java.security.PrivilegedAction;
027import java.util.EnumSet;
028import java.util.List;
029import java.util.Map;
030import java.util.Optional;
031import java.util.concurrent.CompletableFuture;
032import java.util.concurrent.atomic.AtomicInteger;
033import org.apache.hadoop.conf.Configuration;
034import org.apache.hadoop.hbase.ClusterMetrics.Option;
035import org.apache.hadoop.hbase.Waiter.Predicate;
036import org.apache.hadoop.hbase.client.Admin;
037import org.apache.hadoop.hbase.client.AsyncAdmin;
038import org.apache.hadoop.hbase.client.AsyncConnection;
039import org.apache.hadoop.hbase.client.ClusterConnectionFactory;
040import org.apache.hadoop.hbase.client.Connection;
041import org.apache.hadoop.hbase.client.ConnectionFactory;
042import org.apache.hadoop.hbase.client.Get;
043import org.apache.hadoop.hbase.client.Put;
044import org.apache.hadoop.hbase.client.RegionInfoBuilder;
045import org.apache.hadoop.hbase.client.RegionStatesCount;
046import org.apache.hadoop.hbase.client.Result;
047import org.apache.hadoop.hbase.client.Scan;
048import org.apache.hadoop.hbase.client.Table;
049import org.apache.hadoop.hbase.coprocessor.CoprocessorHost;
050import org.apache.hadoop.hbase.coprocessor.MasterCoprocessor;
051import org.apache.hadoop.hbase.coprocessor.MasterCoprocessorEnvironment;
052import org.apache.hadoop.hbase.coprocessor.MasterObserver;
053import org.apache.hadoop.hbase.coprocessor.ObserverContext;
054import org.apache.hadoop.hbase.filter.FilterAllFilter;
055import org.apache.hadoop.hbase.master.HMaster;
056import org.apache.hadoop.hbase.monitoring.TaskMonitor;
057import org.apache.hadoop.hbase.regionserver.HRegionServer;
058import org.apache.hadoop.hbase.regionserver.MetricsUserAggregateFactory;
059import org.apache.hadoop.hbase.security.User;
060import org.apache.hadoop.hbase.security.UserProvider;
061import org.apache.hadoop.hbase.testclassification.MediumTests;
062import org.apache.hadoop.hbase.util.Bytes;
063import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
064import org.apache.hadoop.hbase.util.JVMClusterUtil.MasterThread;
065import org.apache.hadoop.hbase.util.JVMClusterUtil.RegionServerThread;
066import org.junit.jupiter.api.AfterAll;
067import org.junit.jupiter.api.BeforeAll;
068import org.junit.jupiter.api.Tag;
069import org.junit.jupiter.api.Test;
070
071@Tag(MediumTests.TAG)
072public class TestClientClusterMetrics {
073
074  private static HBaseTestingUtil UTIL;
075  private static Admin ADMIN;
076  private final static int SLAVES = 5;
077  private final static int MASTERS = 3;
078  private static SingleProcessHBaseCluster CLUSTER;
079  private static HRegionServer DEAD;
080  private static final TableName TABLE_NAME = TableName.valueOf("test");
081  private static final byte[] CF = Bytes.toBytes("cf");
082
083  // We need to promote the visibility of tryRegionServerReport for this test
084  public static class MyRegionServer
085    extends SingleProcessHBaseCluster.MiniHBaseClusterRegionServer {
086    public MyRegionServer(Configuration conf) throws IOException, InterruptedException {
087      super(conf);
088    }
089
090    @Override
091    public void tryRegionServerReport(long reportStartTime, long reportEndTime) throws IOException {
092      super.tryRegionServerReport(reportStartTime, reportEndTime);
093    }
094  }
095
096  @BeforeAll
097  public static void setUpBeforeClass() throws Exception {
098    Configuration conf = HBaseConfiguration.create();
099    conf.set(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY, MyObserver.class.getName());
100    UTIL = new HBaseTestingUtil(conf);
101    StartTestingClusterOption option =
102      StartTestingClusterOption.builder().rsClass(TestClientClusterMetrics.MyRegionServer.class)
103        .numMasters(MASTERS).numRegionServers(SLAVES).numDataNodes(SLAVES).build();
104    UTIL.startMiniCluster(option);
105    CLUSTER = UTIL.getHBaseCluster();
106    CLUSTER.waitForActiveAndReadyMaster();
107    ADMIN = UTIL.getAdmin();
108    // Kill one region server
109    List<RegionServerThread> rsts = CLUSTER.getLiveRegionServerThreads();
110    RegionServerThread rst = rsts.get(rsts.size() - 1);
111    DEAD = rst.getRegionServer();
112    DEAD.stop("Test dead servers metrics");
113    while (rst.isAlive()) {
114      Thread.sleep(500);
115    }
116  }
117
118  @Test
119  public void testDefaults() throws Exception {
120    ClusterMetrics origin = ADMIN.getClusterMetrics();
121    ClusterMetrics defaults = ADMIN.getClusterMetrics(EnumSet.allOf(Option.class));
122    assertEquals(origin.getHBaseVersion(), defaults.getHBaseVersion());
123    assertEquals(origin.getClusterId(), defaults.getClusterId());
124    assertEquals(origin.getAverageLoad(), defaults.getAverageLoad(), 0);
125    assertEquals(origin.getBackupMasterNames().size(), defaults.getBackupMasterNames().size());
126    assertEquals(origin.getDeadServerNames().size(), defaults.getDeadServerNames().size());
127    assertEquals(origin.getRegionCount(), defaults.getRegionCount());
128    assertEquals(origin.getLiveServerMetrics().size(), defaults.getLiveServerMetrics().size());
129    assertEquals(origin.getMasterInfoPort(), defaults.getMasterInfoPort());
130    assertEquals(origin.getServersName().size(), defaults.getServersName().size());
131    assertEquals(ADMIN.getRegionServers().size(), defaults.getServersName().size());
132    // We decommission the first online region server and verify the metrics.
133    List<ServerName> serverNames = origin.getServersName().subList(0, 1);
134    ADMIN.decommissionRegionServers(serverNames, false);
135    assertEquals(1, ADMIN.getClusterMetrics().getDecommissionedServerNames().size());
136    assertEquals(ADMIN.getClusterMetrics().getDecommissionedServerNames().get(0),
137      serverNames.get(0));
138  }
139
140  @Test
141  public void testAsyncClient() throws Exception {
142    try (AsyncConnection asyncConnect =
143      ConnectionFactory.createAsyncConnection(UTIL.getConfiguration()).get()) {
144      AsyncAdmin asyncAdmin = asyncConnect.getAdmin();
145      CompletableFuture<ClusterMetrics> originFuture = asyncAdmin.getClusterMetrics();
146      CompletableFuture<ClusterMetrics> defaultsFuture =
147        asyncAdmin.getClusterMetrics(EnumSet.allOf(Option.class));
148      ClusterMetrics origin = originFuture.get();
149      ClusterMetrics defaults = defaultsFuture.get();
150      assertEquals(origin.getHBaseVersion(), defaults.getHBaseVersion());
151      assertEquals(origin.getClusterId(), defaults.getClusterId());
152      assertEquals(origin.getHBaseVersion(), defaults.getHBaseVersion());
153      assertEquals(origin.getClusterId(), defaults.getClusterId());
154      assertEquals(origin.getAverageLoad(), defaults.getAverageLoad(), 0);
155      assertEquals(origin.getBackupMasterNames().size(), defaults.getBackupMasterNames().size());
156      assertEquals(origin.getDeadServerNames().size(), defaults.getDeadServerNames().size());
157      assertEquals(origin.getRegionCount(), defaults.getRegionCount());
158      assertEquals(origin.getLiveServerMetrics().size(), defaults.getLiveServerMetrics().size());
159      assertEquals(origin.getMasterInfoPort(), defaults.getMasterInfoPort());
160      assertEquals(origin.getServersName().size(), defaults.getServersName().size());
161      origin.getTableRegionStatesCount().forEach(((tableName, regionStatesCount) -> {
162        RegionStatesCount defaultRegionStatesCount =
163          defaults.getTableRegionStatesCount().get(tableName);
164        assertEquals(defaultRegionStatesCount, regionStatesCount);
165      }));
166    }
167  }
168
169  @Test
170  public void testLiveAndDeadServersStatus() throws Exception {
171    // Count the number of live regionservers
172    List<RegionServerThread> regionserverThreads = CLUSTER.getLiveRegionServerThreads();
173    int numRs = 0;
174    int len = regionserverThreads.size();
175    for (int i = 0; i < len; i++) {
176      if (regionserverThreads.get(i).isAlive()) {
177        numRs++;
178      }
179    }
180    // Depending on the (random) order of unit execution we may run this unit before the
181    // minicluster is fully up and recovered from the RS shutdown done during test init.
182    Waiter.waitFor(CLUSTER.getConfiguration(), 10 * 1000, 100, new Predicate<Exception>() {
183      @Override
184      public boolean evaluate() throws Exception {
185        ClusterMetrics metrics = ADMIN.getClusterMetrics(EnumSet.of(Option.LIVE_SERVERS));
186        assertNotNull(metrics);
187        return metrics.getRegionCount() > 0;
188      }
189    });
190    // Retrieve live servers and dead servers info.
191    EnumSet<Option> options =
192      EnumSet.of(Option.LIVE_SERVERS, Option.DEAD_SERVERS, Option.SERVERS_NAME);
193    ClusterMetrics metrics = ADMIN.getClusterMetrics(options);
194    assertNotNull(metrics);
195    // exclude a dead region server
196    assertEquals(SLAVES - 1, numRs);
197    // live servers = nums of regionservers
198    // By default, HMaster don't carry any regions so it won't report its load.
199    // Hence, it won't be in the server list.
200    assertEquals(numRs, metrics.getLiveServerMetrics().size());
201    assertTrue(metrics.getRegionCount() > 0);
202    assertNotNull(metrics.getDeadServerNames());
203    assertEquals(1, metrics.getDeadServerNames().size());
204    ServerName deadServerName = metrics.getDeadServerNames().iterator().next();
205    assertEquals(DEAD.getServerName(), deadServerName);
206    assertNotNull(metrics.getServersName());
207    assertEquals(numRs, metrics.getServersName().size());
208  }
209
210  @Test
211  public void testRegionStatesCount() throws Exception {
212    Table table = UTIL.createTable(TABLE_NAME, CF);
213    table.put(new Put(Bytes.toBytes("k1")).addColumn(CF, Bytes.toBytes("q1"), Bytes.toBytes("v1")));
214    table.put(new Put(Bytes.toBytes("k2")).addColumn(CF, Bytes.toBytes("q2"), Bytes.toBytes("v2")));
215    table.put(new Put(Bytes.toBytes("k3")).addColumn(CF, Bytes.toBytes("q3"), Bytes.toBytes("v3")));
216
217    ClusterMetrics metrics = ADMIN.getClusterMetrics();
218    assertEquals(metrics.getTableRegionStatesCount().size(), 2);
219    assertEquals(
220      metrics.getTableRegionStatesCount().get(TableName.META_TABLE_NAME).getRegionsInTransition(),
221      0);
222    assertEquals(
223      metrics.getTableRegionStatesCount().get(TableName.META_TABLE_NAME).getOpenRegions(), 1);
224    assertEquals(
225      metrics.getTableRegionStatesCount().get(TableName.META_TABLE_NAME).getTotalRegions(), 1);
226    assertEquals(
227      metrics.getTableRegionStatesCount().get(TableName.META_TABLE_NAME).getClosedRegions(), 0);
228    assertEquals(
229      metrics.getTableRegionStatesCount().get(TableName.META_TABLE_NAME).getSplitRegions(), 0);
230    assertEquals(metrics.getTableRegionStatesCount().get(TABLE_NAME).getRegionsInTransition(), 0);
231    assertEquals(metrics.getTableRegionStatesCount().get(TABLE_NAME).getOpenRegions(), 1);
232    assertEquals(metrics.getTableRegionStatesCount().get(TABLE_NAME).getTotalRegions(), 1);
233
234    UTIL.deleteTable(TABLE_NAME);
235  }
236
237  @Test
238  public void testRegionStatesWithSplit() throws Exception {
239    int startRowNum = 20;
240    int rowCount = 80;
241    Table table = UTIL.createTable(TABLE_NAME, CF);
242    table.put(new Put(Bytes.toBytes("k1")).addColumn(CF, Bytes.toBytes("q1"), Bytes.toBytes("v1")));
243    table.put(new Put(Bytes.toBytes("k2")).addColumn(CF, Bytes.toBytes("q2"), Bytes.toBytes("v2")));
244
245    insertData(TABLE_NAME, startRowNum, rowCount);
246
247    ClusterMetrics metrics = ADMIN.getClusterMetrics();
248    assertEquals(metrics.getTableRegionStatesCount().size(), 2);
249    assertEquals(
250      metrics.getTableRegionStatesCount().get(TableName.META_TABLE_NAME).getRegionsInTransition(),
251      0);
252    assertEquals(
253      metrics.getTableRegionStatesCount().get(TableName.META_TABLE_NAME).getOpenRegions(), 1);
254    assertEquals(
255      metrics.getTableRegionStatesCount().get(TableName.META_TABLE_NAME).getTotalRegions(), 1);
256    assertEquals(metrics.getTableRegionStatesCount().get(TABLE_NAME).getRegionsInTransition(), 0);
257    assertEquals(metrics.getTableRegionStatesCount().get(TABLE_NAME).getOpenRegions(), 1);
258    assertEquals(metrics.getTableRegionStatesCount().get(TABLE_NAME).getTotalRegions(), 1);
259
260    int splitRowNum = startRowNum + rowCount / 2;
261    byte[] splitKey = Bytes.toBytes("" + splitRowNum);
262
263    // Split region of the table
264    ADMIN.split(TABLE_NAME, splitKey);
265
266    metrics = ADMIN.getClusterMetrics();
267    assertEquals(metrics.getTableRegionStatesCount().size(), 2);
268    assertEquals(
269      metrics.getTableRegionStatesCount().get(TableName.META_TABLE_NAME).getRegionsInTransition(),
270      0);
271    assertEquals(
272      metrics.getTableRegionStatesCount().get(TableName.META_TABLE_NAME).getOpenRegions(), 1);
273    assertEquals(
274      metrics.getTableRegionStatesCount().get(TableName.META_TABLE_NAME).getTotalRegions(), 1);
275    assertEquals(metrics.getTableRegionStatesCount().get(TABLE_NAME).getRegionsInTransition(), 0);
276    assertEquals(metrics.getTableRegionStatesCount().get(TABLE_NAME).getOpenRegions(), 2);
277    assertEquals(metrics.getTableRegionStatesCount().get(TABLE_NAME).getTotalRegions(), 3);
278    assertEquals(metrics.getTableRegionStatesCount().get(TABLE_NAME).getSplitRegions(), 1);
279    assertEquals(metrics.getTableRegionStatesCount().get(TABLE_NAME).getClosedRegions(), 0);
280
281    UTIL.deleteTable(TABLE_NAME);
282  }
283
284  @Test
285  public void testMasterAndBackupMastersStatus() throws Exception {
286    // get all the master threads
287    List<MasterThread> masterThreads = CLUSTER.getMasterThreads();
288    int numActive = 0;
289    int activeIndex = 0;
290    ServerName activeName = null;
291    HMaster active = null;
292    for (int i = 0; i < masterThreads.size(); i++) {
293      if (masterThreads.get(i).getMaster().isActiveMaster()) {
294        numActive++;
295        activeIndex = i;
296        active = masterThreads.get(activeIndex).getMaster();
297        activeName = active.getServerName();
298      }
299    }
300    assertNotNull(active);
301    assertEquals(1, numActive);
302    assertEquals(MASTERS, masterThreads.size());
303    // Retrieve master and backup masters infos only.
304    EnumSet<Option> options = EnumSet.of(Option.MASTER, Option.BACKUP_MASTERS);
305    ClusterMetrics metrics = ADMIN.getClusterMetrics(options);
306    assertTrue(metrics.getMasterName().equals(activeName));
307    assertEquals(MASTERS - 1, metrics.getBackupMasterNames().size());
308  }
309
310  @Test
311  public void testUserMetrics() throws Exception {
312    Configuration conf = UTIL.getConfiguration();
313    // If metrics for users is not enabled, this test doesn't make sense.
314    if (
315      !conf.getBoolean(MetricsUserAggregateFactory.METRIC_USER_ENABLED_CONF,
316        MetricsUserAggregateFactory.DEFAULT_METRIC_USER_ENABLED_CONF)
317    ) {
318      return;
319    }
320    User userFoo = User.createUserForTesting(conf, "FOO_USER_METRIC_TEST", new String[0]);
321    User userBar = User.createUserForTesting(conf, "BAR_USER_METRIC_TEST", new String[0]);
322    User userTest = User.createUserForTesting(conf, "TEST_USER_METRIC_TEST", new String[0]);
323    UTIL.createTable(TABLE_NAME, CF);
324    waitForUsersMetrics(0);
325    long writeMetaMetricBeforeNextuser = getMetaMetrics().getWriteRequestCount();
326    userFoo.runAs(new PrivilegedAction<Void>() {
327      @Override
328      public Void run() {
329        try {
330          doPut();
331        } catch (IOException e) {
332          fail("Exception:" + e.getMessage());
333        }
334        return null;
335      }
336    });
337    waitForUsersMetrics(1);
338    long writeMetaMetricForUserFoo =
339      getMetaMetrics().getWriteRequestCount() - writeMetaMetricBeforeNextuser;
340    long readMetaMetricBeforeNextuser = getMetaMetrics().getReadRequestCount();
341    userBar.runAs(new PrivilegedAction<Void>() {
342      @Override
343      public Void run() {
344        try {
345          doGet();
346        } catch (IOException e) {
347          fail("Exception:" + e.getMessage());
348        }
349        return null;
350      }
351    });
352    waitForUsersMetrics(2);
353    long readMetaMetricForUserBar =
354      getMetaMetrics().getReadRequestCount() - readMetaMetricBeforeNextuser;
355    long filteredMetaReqeust = getMetaMetrics().getFilteredReadRequestCount();
356    userTest.runAs(new PrivilegedAction<Void>() {
357      @Override
358      public Void run() {
359        try {
360          Table table = createConnection(UTIL.getConfiguration()).getTable(TABLE_NAME);
361          for (Result result : table.getScanner(new Scan().setFilter(new FilterAllFilter()))) {
362            fail("Should have filtered all rows");
363          }
364        } catch (IOException e) {
365          fail("Exception:" + e.getMessage());
366        }
367        return null;
368      }
369    });
370    waitForUsersMetrics(3);
371    long filteredMetaReqeustForTestUser =
372      getMetaMetrics().getFilteredReadRequestCount() - filteredMetaReqeust;
373    Map<byte[], UserMetrics> userMap = ADMIN.getClusterMetrics(EnumSet.of(Option.LIVE_SERVERS))
374      .getLiveServerMetrics().values().iterator().next().getUserMetrics();
375    for (byte[] user : userMap.keySet()) {
376      switch (Bytes.toString(user)) {
377        case "FOO_USER_METRIC_TEST":
378          assertEquals(1, userMap.get(user).getWriteRequestCount() - writeMetaMetricForUserFoo);
379          break;
380        case "BAR_USER_METRIC_TEST":
381          assertEquals(1, userMap.get(user).getReadRequestCount() - readMetaMetricForUserBar);
382          assertEquals(0, userMap.get(user).getWriteRequestCount());
383          break;
384        case "TEST_USER_METRIC_TEST":
385          assertEquals(1,
386            userMap.get(user).getFilteredReadRequests() - filteredMetaReqeustForTestUser);
387          assertEquals(0, userMap.get(user).getWriteRequestCount());
388          break;
389        default:
390          // current user
391          assertEquals(UserProvider.instantiate(conf).getCurrent().getName(), Bytes.toString(user));
392          // Read/write count because of Meta operations
393          assertTrue(userMap.get(user).getReadRequestCount() > 1);
394          break;
395      }
396    }
397    UTIL.deleteTable(TABLE_NAME);
398  }
399
400  @Test
401  public void testServerTasks() throws Exception {
402    // TaskMonitor is a singleton per VM, so will be shared among all minicluster "servers",
403    // so we only need to look at the first live server's results to find it.
404    final String testTaskName = "TEST TASK";
405    TaskMonitor.get().createStatus(testTaskName).setStatus("Testing 1... 2... 3...");
406    // Of course, first we must trigger regionserver reports.
407    final long now = EnvironmentEdgeManager.currentTime();
408    final long last = now - 1000; // fake a period, or someone might div by zero
409    for (RegionServerThread rs : CLUSTER.getRegionServerThreads()) {
410      ((MyRegionServer) rs.getRegionServer()).tryRegionServerReport(last, now);
411    }
412    // Get status now
413    ClusterMetrics clusterMetrics = ADMIN.getClusterMetrics(EnumSet.of(Option.TASKS));
414    // The test task will be in the master metrics list
415    boolean found = false;
416    for (ServerTask task : clusterMetrics.getMasterTasks()) {
417      if (testTaskName.equals(task.getDescription())) {
418        // Found it
419        found = true;
420        break;
421      }
422    }
423    assertTrue(found, "Expected task not found in master task list");
424    // Get the tasks information (carried in server metrics)
425    found = false;
426    for (ServerMetrics serverMetrics : clusterMetrics.getLiveServerMetrics().values()) {
427      if (serverMetrics.getTasks() != null) {
428        for (ServerTask task : serverMetrics.getTasks()) {
429          if (testTaskName.equals(task.getDescription())) {
430            // Found it
431            found = true;
432            break;
433          }
434        }
435      }
436    }
437    // We will fall through here if getClusterMetrics(TASKS) did not correctly process the
438    // task list.
439    assertTrue(found, "Expected task not found in server load");
440  }
441
442  private RegionMetrics getMetaMetrics() throws IOException {
443    for (ServerMetrics serverMetrics : ADMIN.getClusterMetrics(EnumSet.of(Option.LIVE_SERVERS))
444      .getLiveServerMetrics().values()) {
445      RegionMetrics metaMetrics = serverMetrics.getRegionMetrics()
446        .get(RegionInfoBuilder.FIRST_META_REGIONINFO.getRegionName());
447      if (metaMetrics != null) {
448        return metaMetrics;
449      }
450    }
451    fail("Should have find meta metrics");
452    return null;
453  }
454
455  private void waitForUsersMetrics(int noOfUsers) throws Exception {
456    // Sleep for metrics to get updated on master
457    Thread.sleep(5000);
458    Waiter.waitFor(CLUSTER.getConfiguration(), 10 * 1000, 100, new Predicate<Exception>() {
459      @Override
460      public boolean evaluate() throws Exception {
461        Map<byte[], UserMetrics> metrics = ADMIN.getClusterMetrics(EnumSet.of(Option.LIVE_SERVERS))
462          .getLiveServerMetrics().values().iterator().next().getUserMetrics();
463        assertNotNull(metrics);
464        // including current user + noOfUsers
465        return metrics.keySet().size() > noOfUsers;
466      }
467    });
468  }
469
470  private void doPut() throws IOException {
471    Table table = createConnection(UTIL.getConfiguration()).getTable(TABLE_NAME);
472    table.put(new Put(Bytes.toBytes("a")).addColumn(CF, Bytes.toBytes("col1"), Bytes.toBytes("1")));
473
474  }
475
476  private void doGet() throws IOException {
477    Table table = createConnection(UTIL.getConfiguration()).getTable(TABLE_NAME);
478    table.get(new Get(Bytes.toBytes("a")).addColumn(CF, Bytes.toBytes("col1")));
479
480  }
481
482  private Connection createConnection(Configuration conf) throws IOException {
483    User user = UserProvider.instantiate(conf).getCurrent();
484    return ClusterConnectionFactory.createAsyncClusterConnection(conf, null, user).toConnection();
485  }
486
487  @Test
488  public void testOtherStatusInfos() throws Exception {
489    EnumSet<Option> options = EnumSet.of(Option.MASTER_COPROCESSORS, Option.HBASE_VERSION,
490      Option.CLUSTER_ID, Option.BALANCER_ON);
491    ClusterMetrics metrics = ADMIN.getClusterMetrics(options);
492    assertEquals(1, metrics.getMasterCoprocessorNames().size());
493    assertNotNull(metrics.getHBaseVersion());
494    assertNotNull(metrics.getClusterId());
495    assertTrue(metrics.getAverageLoad() == 0.0);
496    assertNotNull(metrics.getBalancerOn());
497  }
498
499  @AfterAll
500  public static void tearDownAfterClass() throws Exception {
501    if (ADMIN != null) {
502      ADMIN.close();
503    }
504    UTIL.shutdownMiniCluster();
505  }
506
507  @Test
508  public void testObserver() throws IOException {
509    int preCount = MyObserver.PRE_COUNT.get();
510    int postCount = MyObserver.POST_COUNT.get();
511    assertTrue(ADMIN.getClusterMetrics().getMasterCoprocessorNames().stream()
512      .anyMatch(s -> s.equals(MyObserver.class.getSimpleName())));
513    assertEquals(preCount + 1, MyObserver.PRE_COUNT.get());
514    assertEquals(postCount + 1, MyObserver.POST_COUNT.get());
515  }
516
517  private static void insertData(final TableName tableName, int startRow, int rowCount)
518    throws IOException {
519    Table t = UTIL.getConnection().getTable(tableName);
520    Put p;
521    for (int i = 0; i < rowCount; i++) {
522      p = new Put(Bytes.toBytes("" + (startRow + i)));
523      p.addColumn(CF, Bytes.toBytes("val1"), Bytes.toBytes(i));
524      t.put(p);
525    }
526  }
527
528  public static class MyObserver implements MasterCoprocessor, MasterObserver {
529    private static final AtomicInteger PRE_COUNT = new AtomicInteger(0);
530    private static final AtomicInteger POST_COUNT = new AtomicInteger(0);
531
532    @Override
533    public Optional<MasterObserver> getMasterObserver() {
534      return Optional.of(this);
535    }
536
537    @Override
538    public void preGetClusterMetrics(ObserverContext<MasterCoprocessorEnvironment> ctx)
539      throws IOException {
540      PRE_COUNT.incrementAndGet();
541    }
542
543    @Override
544    public void postGetClusterMetrics(ObserverContext<MasterCoprocessorEnvironment> ctx,
545      ClusterMetrics metrics) throws IOException {
546      POST_COUNT.incrementAndGet();
547    }
548  }
549}