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.client;
019
020import static org.junit.Assert.assertEquals;
021import static org.junit.Assert.assertFalse;
022import static org.junit.Assert.assertTrue;
023import static org.junit.Assert.fail;
024
025import java.io.IOException;
026import java.util.ArrayList;
027import java.util.EnumSet;
028import java.util.HashMap;
029import java.util.List;
030import java.util.Random;
031import java.util.concurrent.atomic.AtomicInteger;
032import java.util.stream.Collectors;
033import org.apache.hadoop.conf.Configuration;
034import org.apache.hadoop.hbase.ClusterMetrics.Option;
035import org.apache.hadoop.hbase.HBaseClassTestRule;
036import org.apache.hadoop.hbase.HBaseTestingUtility;
037import org.apache.hadoop.hbase.HColumnDescriptor;
038import org.apache.hadoop.hbase.HConstants;
039import org.apache.hadoop.hbase.HRegionLocation;
040import org.apache.hadoop.hbase.HTableDescriptor;
041import org.apache.hadoop.hbase.MiniHBaseCluster;
042import org.apache.hadoop.hbase.ServerName;
043import org.apache.hadoop.hbase.TableExistsException;
044import org.apache.hadoop.hbase.TableName;
045import org.apache.hadoop.hbase.TableNotDisabledException;
046import org.apache.hadoop.hbase.TableNotEnabledException;
047import org.apache.hadoop.hbase.TableNotFoundException;
048import org.apache.hadoop.hbase.UnknownRegionException;
049import org.apache.hadoop.hbase.ZooKeeperConnectionException;
050import org.apache.hadoop.hbase.constraint.ConstraintException;
051import org.apache.hadoop.hbase.ipc.RpcScheduler;
052import org.apache.hadoop.hbase.master.HMaster;
053import org.apache.hadoop.hbase.master.assignment.AssignmentManager;
054import org.apache.hadoop.hbase.regionserver.HRegion;
055import org.apache.hadoop.hbase.regionserver.HRegionServer;
056import org.apache.hadoop.hbase.testclassification.ClientTests;
057import org.apache.hadoop.hbase.testclassification.LargeTests;
058import org.apache.hadoop.hbase.util.Bytes;
059import org.apache.hadoop.hbase.util.Pair;
060import org.apache.hadoop.hbase.wal.AbstractFSWALProvider;
061import org.junit.After;
062import org.junit.AfterClass;
063import org.junit.Before;
064import org.junit.BeforeClass;
065import org.junit.ClassRule;
066import org.junit.Rule;
067import org.junit.Test;
068import org.junit.experimental.categories.Category;
069import org.junit.rules.TestName;
070import org.slf4j.Logger;
071import org.slf4j.LoggerFactory;
072
073import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
074
075/**
076 * Class to test HBaseAdmin.
077 * Spins up the minicluster once at test start and then takes it down afterward.
078 * Add any testing of HBaseAdmin functionality here.
079 */
080@Category({LargeTests.class, ClientTests.class})
081public class TestAdmin2 {
082
083  @ClassRule
084  public static final HBaseClassTestRule CLASS_RULE =
085      HBaseClassTestRule.forClass(TestAdmin2.class);
086
087  private static final Logger LOG = LoggerFactory.getLogger(TestAdmin2.class);
088  private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
089  private Admin admin;
090
091  @Rule
092  public TestName name = new TestName();
093
094  @BeforeClass
095  public static void setUpBeforeClass() throws Exception {
096    TEST_UTIL.getConfiguration().setInt("hbase.regionserver.msginterval", 100);
097    TEST_UTIL.getConfiguration().setInt("hbase.client.pause", 250);
098    TEST_UTIL.getConfiguration().setInt("hbase.client.retries.number", 6);
099    TEST_UTIL.getConfiguration().setInt(HConstants.REGION_SERVER_HIGH_PRIORITY_HANDLER_COUNT, 30);
100    TEST_UTIL.getConfiguration().setInt(HConstants.REGION_SERVER_HANDLER_COUNT, 30);
101    TEST_UTIL.getConfiguration().setBoolean("hbase.master.enabletable.roundrobin", true);
102    TEST_UTIL.startMiniCluster(3);
103  }
104
105  @AfterClass
106  public static void tearDownAfterClass() throws Exception {
107    TEST_UTIL.shutdownMiniCluster();
108  }
109
110  @Before
111  public void setUp() throws Exception {
112    this.admin = TEST_UTIL.getHBaseAdmin();
113  }
114
115  @After
116  public void tearDown() throws Exception {
117    for (HTableDescriptor htd : this.admin.listTables()) {
118      TEST_UTIL.deleteTable(htd.getTableName());
119    }
120  }
121
122  @Test
123  public void testCreateBadTables() throws IOException {
124    String msg = null;
125    try {
126      this.admin.createTable(new HTableDescriptor(TableName.META_TABLE_NAME));
127    } catch(TableExistsException e) {
128      msg = e.toString();
129    }
130    assertTrue("Unexcepted exception message " + msg, msg != null &&
131      msg.startsWith(TableExistsException.class.getName()) &&
132      msg.contains(TableName.META_TABLE_NAME.getNameAsString()));
133
134    // Now try and do concurrent creation with a bunch of threads.
135    final HTableDescriptor threadDesc = new HTableDescriptor(TableName.valueOf(name.getMethodName()));
136    threadDesc.addFamily(new HColumnDescriptor(HConstants.CATALOG_FAMILY));
137    int count = 10;
138    Thread [] threads = new Thread [count];
139    final AtomicInteger successes = new AtomicInteger(0);
140    final AtomicInteger failures = new AtomicInteger(0);
141    final Admin localAdmin = this.admin;
142    for (int i = 0; i < count; i++) {
143      threads[i] = new Thread(Integer.toString(i)) {
144        @Override
145        public void run() {
146          try {
147            localAdmin.createTable(threadDesc);
148            successes.incrementAndGet();
149          } catch (TableExistsException e) {
150            failures.incrementAndGet();
151          } catch (IOException e) {
152            throw new RuntimeException("Failed threaded create" + getName(), e);
153          }
154        }
155      };
156    }
157    for (int i = 0; i < count; i++) {
158      threads[i].start();
159    }
160    for (int i = 0; i < count; i++) {
161      while(threads[i].isAlive()) {
162        try {
163          Thread.sleep(100);
164        } catch (InterruptedException e) {
165          // continue
166        }
167      }
168    }
169    // All threads are now dead.  Count up how many tables were created and
170    // how many failed w/ appropriate exception.
171    assertEquals(1, successes.get());
172    assertEquals(count - 1, failures.get());
173  }
174
175  /**
176   * Test for hadoop-1581 'HBASE: Unopenable tablename bug'.
177   * @throws Exception
178   */
179  @Test
180  public void testTableNameClash() throws Exception {
181    final String name = this.name.getMethodName();
182    HTableDescriptor htd1 = new HTableDescriptor(TableName.valueOf(name + "SOMEUPPERCASE"));
183    HTableDescriptor htd2 = new HTableDescriptor(TableName.valueOf(name));
184    htd1.addFamily(new HColumnDescriptor(HConstants.CATALOG_FAMILY));
185    htd2.addFamily(new HColumnDescriptor(HConstants.CATALOG_FAMILY));
186    admin.createTable(htd1);
187    admin.createTable(htd2);
188    // Before fix, below would fail throwing a NoServerForRegionException.
189    TEST_UTIL.getConnection().getTable(htd2.getTableName()).close();
190  }
191
192  /***
193   * HMaster.createTable used to be kind of synchronous call
194   * Thus creating of table with lots of regions can cause RPC timeout
195   * After the fix to make createTable truly async, RPC timeout shouldn't be an
196   * issue anymore
197   * @throws Exception
198   */
199  @Test
200  public void testCreateTableRPCTimeOut() throws Exception {
201    final String name = this.name.getMethodName();
202    int oldTimeout = TEST_UTIL.getConfiguration().
203      getInt(HConstants.HBASE_RPC_TIMEOUT_KEY, HConstants.DEFAULT_HBASE_RPC_TIMEOUT);
204    TEST_UTIL.getConfiguration().setInt(HConstants.HBASE_RPC_TIMEOUT_KEY, 1500);
205    try {
206      int expectedRegions = 100;
207      // Use 80 bit numbers to make sure we aren't limited
208      byte [] startKey = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
209      byte [] endKey =   { 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 };
210      Admin hbaseadmin = TEST_UTIL.getHBaseAdmin();
211      HTableDescriptor htd = new HTableDescriptor(TableName.valueOf(name));
212      htd.addFamily(new HColumnDescriptor(HConstants.CATALOG_FAMILY));
213      hbaseadmin.createTable(htd, startKey, endKey, expectedRegions);
214    } finally {
215      TEST_UTIL.getConfiguration().setInt(HConstants.HBASE_RPC_TIMEOUT_KEY, oldTimeout);
216    }
217  }
218
219  /**
220   * Test read only tables
221   * @throws Exception
222   */
223  @Test
224  public void testReadOnlyTable() throws Exception {
225    final TableName name = TableName.valueOf(this.name.getMethodName());
226    Table table = TEST_UTIL.createTable(name, HConstants.CATALOG_FAMILY);
227    byte[] value = Bytes.toBytes("somedata");
228    // This used to use an empty row... That must have been a bug
229    Put put = new Put(value);
230    put.addColumn(HConstants.CATALOG_FAMILY, HConstants.CATALOG_FAMILY, value);
231    table.put(put);
232    table.close();
233  }
234
235  /**
236   * Test that user table names can contain '-' and '.' so long as they do not
237   * start with same. HBASE-771
238   * @throws IOException
239   */
240  @Test
241  public void testTableNames() throws IOException {
242    byte[][] illegalNames = new byte[][] {
243        Bytes.toBytes("-bad"),
244        Bytes.toBytes(".bad")
245    };
246    for (byte[] illegalName : illegalNames) {
247      try {
248        new HTableDescriptor(TableName.valueOf(illegalName));
249        throw new IOException("Did not detect '" +
250            Bytes.toString(illegalName) + "' as an illegal user table name");
251      } catch (IllegalArgumentException e) {
252        // expected
253      }
254    }
255    byte[] legalName = Bytes.toBytes("g-oo.d");
256    try {
257      new HTableDescriptor(TableName.valueOf(legalName));
258    } catch (IllegalArgumentException e) {
259      throw new IOException("Legal user table name: '" +
260        Bytes.toString(legalName) + "' caused IllegalArgumentException: " +
261        e.getMessage());
262    }
263  }
264
265  /**
266   * For HADOOP-2579
267   * @throws IOException
268   */
269  @Test (expected=TableExistsException.class)
270  public void testTableExistsExceptionWithATable() throws IOException {
271    final TableName name = TableName.valueOf(this.name.getMethodName());
272    TEST_UTIL.createTable(name, HConstants.CATALOG_FAMILY).close();
273    TEST_UTIL.createTable(name, HConstants.CATALOG_FAMILY);
274  }
275
276  /**
277   * Can't disable a table if the table isn't in enabled state
278   * @throws IOException
279   */
280  @Test (expected=TableNotEnabledException.class)
281  public void testTableNotEnabledExceptionWithATable() throws IOException {
282    final TableName name = TableName.valueOf(this.name.getMethodName());
283    TEST_UTIL.createTable(name, HConstants.CATALOG_FAMILY).close();
284    this.admin.disableTable(name);
285    this.admin.disableTable(name);
286  }
287
288  /**
289   * Can't enable a table if the table isn't in disabled state
290   * @throws IOException
291   */
292  @Test (expected=TableNotDisabledException.class)
293  public void testTableNotDisabledExceptionWithATable() throws IOException {
294    final TableName name = TableName.valueOf(this.name.getMethodName());
295    Table t = TEST_UTIL.createTable(name, HConstants.CATALOG_FAMILY);
296    try {
297    this.admin.enableTable(name);
298    }finally {
299       t.close();
300    }
301  }
302
303  /**
304   * For HADOOP-2579
305   * @throws IOException
306   */
307  @Test (expected=TableNotFoundException.class)
308  public void testTableNotFoundExceptionWithoutAnyTables() throws IOException {
309    TableName tableName = TableName
310        .valueOf("testTableNotFoundExceptionWithoutAnyTables");
311    Table ht = TEST_UTIL.getConnection().getTable(tableName);
312    ht.get(new Get(Bytes.toBytes("e")));
313  }
314
315  @Test
316  public void testShouldUnassignTheRegion() throws Exception {
317    final TableName tableName = TableName.valueOf(name.getMethodName());
318    createTableWithDefaultConf(tableName);
319
320    RegionInfo info = null;
321    HRegionServer rs = TEST_UTIL.getRSForFirstRegionInTable(tableName);
322    List<RegionInfo> onlineRegions = ProtobufUtil.getOnlineRegions(rs.getRSRpcServices());
323    for (RegionInfo regionInfo : onlineRegions) {
324      if (!regionInfo.getTable().isSystemTable()) {
325        info = regionInfo;
326        admin.unassign(regionInfo.getRegionName(), true);
327      }
328    }
329    boolean isInList = ProtobufUtil.getOnlineRegions(
330      rs.getRSRpcServices()).contains(info);
331    long timeout = System.currentTimeMillis() + 10000;
332    while ((System.currentTimeMillis() < timeout) && (isInList)) {
333      Thread.sleep(100);
334      isInList = ProtobufUtil.getOnlineRegions(
335        rs.getRSRpcServices()).contains(info);
336    }
337
338    assertFalse("The region should not be present in online regions list.",
339      isInList);
340  }
341
342  @Test
343  public void testCloseRegionIfInvalidRegionNameIsPassed() throws Exception {
344    final String name = this.name.getMethodName();
345    byte[] tableName = Bytes.toBytes(name);
346    createTableWithDefaultConf(tableName);
347
348    RegionInfo info = null;
349    HRegionServer rs = TEST_UTIL.getRSForFirstRegionInTable(TableName.valueOf(tableName));
350    List<RegionInfo> onlineRegions = ProtobufUtil.getOnlineRegions(rs.getRSRpcServices());
351    for (RegionInfo regionInfo : onlineRegions) {
352      if (!regionInfo.isMetaRegion()) {
353        if (regionInfo.getRegionNameAsString().contains(name)) {
354          info = regionInfo;
355          try {
356            admin.unassign(Bytes.toBytes("sample"), true);
357          } catch (UnknownRegionException nsre) {
358            // expected, ignore it
359          }
360        }
361      }
362    }
363    onlineRegions = ProtobufUtil.getOnlineRegions(rs.getRSRpcServices());
364    assertTrue("The region should be present in online regions list.",
365        onlineRegions.contains(info));
366  }
367
368  @Test
369  public void testCloseRegionThatFetchesTheHRIFromMeta() throws Exception {
370    final TableName tableName = TableName.valueOf(name.getMethodName());
371    createTableWithDefaultConf(tableName);
372
373    RegionInfo info = null;
374    HRegionServer rs = TEST_UTIL.getRSForFirstRegionInTable(tableName);
375    List<RegionInfo> onlineRegions = ProtobufUtil.getOnlineRegions(rs.getRSRpcServices());
376    for (RegionInfo regionInfo : onlineRegions) {
377      if (!regionInfo.isMetaRegion()) {
378        if (regionInfo.getRegionNameAsString().contains("TestHBACloseRegion2")) {
379          info = regionInfo;
380          admin.unassign(regionInfo.getRegionName(), true);
381        }
382      }
383    }
384
385    boolean isInList = ProtobufUtil.getOnlineRegions(
386      rs.getRSRpcServices()).contains(info);
387    long timeout = System.currentTimeMillis() + 10000;
388    while ((System.currentTimeMillis() < timeout) && (isInList)) {
389      Thread.sleep(100);
390      isInList = ProtobufUtil.getOnlineRegions(
391        rs.getRSRpcServices()).contains(info);
392    }
393
394    assertFalse("The region should not be present in online regions list.",
395      isInList);
396  }
397
398  private HBaseAdmin createTable(TableName tableName) throws IOException {
399    HBaseAdmin admin = TEST_UTIL.getHBaseAdmin();
400
401    HTableDescriptor htd = new HTableDescriptor(tableName);
402    HColumnDescriptor hcd = new HColumnDescriptor("value");
403
404    htd.addFamily(hcd);
405    admin.createTable(htd, null);
406    return admin;
407  }
408
409  private void createTableWithDefaultConf(byte[] TABLENAME) throws IOException {
410    createTableWithDefaultConf(TableName.valueOf(TABLENAME));
411  }
412
413  private void createTableWithDefaultConf(TableName TABLENAME) throws IOException {
414    HTableDescriptor htd = new HTableDescriptor(TABLENAME);
415    HColumnDescriptor hcd = new HColumnDescriptor("value");
416    htd.addFamily(hcd);
417
418    admin.createTable(htd, null);
419  }
420
421  /**
422   * For HBASE-2556
423   * @throws IOException
424   */
425  @Test
426  public void testGetTableRegions() throws IOException {
427    final TableName tableName = TableName.valueOf(name.getMethodName());
428
429    int expectedRegions = 10;
430
431    // Use 80 bit numbers to make sure we aren't limited
432    byte [] startKey = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
433    byte [] endKey =   { 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 };
434
435
436    HTableDescriptor desc = new HTableDescriptor(tableName);
437    desc.addFamily(new HColumnDescriptor(HConstants.CATALOG_FAMILY));
438    admin.createTable(desc, startKey, endKey, expectedRegions);
439
440    List<RegionInfo> RegionInfos = admin.getRegions(tableName);
441
442    assertEquals("Tried to create " + expectedRegions + " regions " +
443        "but only found " + RegionInfos.size(),
444        expectedRegions, RegionInfos.size());
445 }
446
447  @Test
448  public void testMoveToPreviouslyAssignedRS() throws IOException, InterruptedException {
449    MiniHBaseCluster cluster = TEST_UTIL.getHBaseCluster();
450    HMaster master = cluster.getMaster();
451    final TableName tableName = TableName.valueOf(name.getMethodName());
452    Admin localAdmin = createTable(tableName);
453    List<RegionInfo> tableRegions = localAdmin.getRegions(tableName);
454    RegionInfo hri = tableRegions.get(0);
455    AssignmentManager am = master.getAssignmentManager();
456    ServerName server = am.getRegionStates().getRegionServerOfRegion(hri);
457    localAdmin.move(hri.getEncodedNameAsBytes(), Bytes.toBytes(server.getServerName()));
458    assertEquals("Current region server and region server before move should be same.", server,
459      am.getRegionStates().getRegionServerOfRegion(hri));
460  }
461
462  @Test
463  public void testWALRollWriting() throws Exception {
464    setUpforLogRolling();
465    String className = this.getClass().getName();
466    StringBuilder v = new StringBuilder(className);
467    while (v.length() < 1000) {
468      v.append(className);
469    }
470    byte[] value = Bytes.toBytes(v.toString());
471    HRegionServer regionServer = startAndWriteData(TableName.valueOf(name.getMethodName()), value);
472    LOG.info("after writing there are "
473        + AbstractFSWALProvider.getNumRolledLogFiles(regionServer.getWAL(null)) + " log files");
474
475    // flush all regions
476    for (HRegion r : regionServer.getOnlineRegionsLocalContext()) {
477      r.flush(true);
478    }
479    admin.rollWALWriter(regionServer.getServerName());
480    int count = AbstractFSWALProvider.getNumRolledLogFiles(regionServer.getWAL(null));
481    LOG.info("after flushing all regions and rolling logs there are " +
482        count + " log files");
483    assertTrue(("actual count: " + count), count <= 2);
484  }
485
486  private void setUpforLogRolling() {
487    // Force a region split after every 768KB
488    TEST_UTIL.getConfiguration().setLong(HConstants.HREGION_MAX_FILESIZE,
489        768L * 1024L);
490
491    // We roll the log after every 32 writes
492    TEST_UTIL.getConfiguration().setInt("hbase.regionserver.maxlogentries", 32);
493
494    TEST_UTIL.getConfiguration().setInt(
495        "hbase.regionserver.logroll.errors.tolerated", 2);
496    TEST_UTIL.getConfiguration().setInt("hbase.rpc.timeout", 10 * 1000);
497
498    // For less frequently updated regions flush after every 2 flushes
499    TEST_UTIL.getConfiguration().setInt(
500        "hbase.hregion.memstore.optionalflushcount", 2);
501
502    // We flush the cache after every 8192 bytes
503    TEST_UTIL.getConfiguration().setInt(HConstants.HREGION_MEMSTORE_FLUSH_SIZE,
504        8192);
505
506    // Increase the amount of time between client retries
507    TEST_UTIL.getConfiguration().setLong("hbase.client.pause", 10 * 1000);
508
509    // Reduce thread wake frequency so that other threads can get
510    // a chance to run.
511    TEST_UTIL.getConfiguration().setInt(HConstants.THREAD_WAKE_FREQUENCY,
512        2 * 1000);
513
514    /**** configuration for testLogRollOnDatanodeDeath ****/
515    // lower the namenode & datanode heartbeat so the namenode
516    // quickly detects datanode failures
517    TEST_UTIL.getConfiguration().setInt("dfs.namenode.heartbeat.recheck-interval", 5000);
518    TEST_UTIL.getConfiguration().setInt("dfs.heartbeat.interval", 1);
519    // the namenode might still try to choose the recently-dead datanode
520    // for a pipeline, so try to a new pipeline multiple times
521    TEST_UTIL.getConfiguration().setInt("dfs.client.block.write.retries", 30);
522    TEST_UTIL.getConfiguration().setInt(
523        "hbase.regionserver.hlog.tolerable.lowreplication", 2);
524    TEST_UTIL.getConfiguration().setInt(
525        "hbase.regionserver.hlog.lowreplication.rolllimit", 3);
526  }
527
528  private HRegionServer startAndWriteData(TableName tableName, byte[] value)
529  throws IOException, InterruptedException {
530    // When the hbase:meta table can be opened, the region servers are running
531    TEST_UTIL.getConnection().getTable(TableName.META_TABLE_NAME).close();
532
533    // Create the test table and open it
534    HTableDescriptor desc = new HTableDescriptor(tableName);
535    desc.addFamily(new HColumnDescriptor(HConstants.CATALOG_FAMILY));
536    admin.createTable(desc);
537    Table table = TEST_UTIL.getConnection().getTable(tableName);
538
539    HRegionServer regionServer = TEST_UTIL.getRSForFirstRegionInTable(tableName);
540    for (int i = 1; i <= 256; i++) { // 256 writes should cause 8 log rolls
541      Put put = new Put(Bytes.toBytes("row" + String.format("%1$04d", i)));
542      put.addColumn(HConstants.CATALOG_FAMILY, null, value);
543      table.put(put);
544      if (i % 32 == 0) {
545        // After every 32 writes sleep to let the log roller run
546        try {
547          Thread.sleep(2000);
548        } catch (InterruptedException e) {
549          // continue
550        }
551      }
552    }
553
554    table.close();
555    return regionServer;
556  }
557
558  /**
559   * Check that we have an exception if the cluster is not there.
560   */
561  @Test
562  public void testCheckHBaseAvailableWithoutCluster() {
563    Configuration conf = new Configuration(TEST_UTIL.getConfiguration());
564
565    // Change the ZK address to go to something not used.
566    conf.setInt(HConstants.ZOOKEEPER_CLIENT_PORT,
567      conf.getInt(HConstants.ZOOKEEPER_CLIENT_PORT, 9999)+10);
568
569    long start = System.currentTimeMillis();
570    try {
571      HBaseAdmin.available(conf);
572      assertTrue(false);
573    } catch (ZooKeeperConnectionException ignored) {
574    } catch (IOException ignored) {
575    }
576    long end = System.currentTimeMillis();
577
578    LOG.info("It took "+(end-start)+" ms to find out that" +
579      " HBase was not available");
580  }
581
582  @Test
583  public void testDisableCatalogTable() throws Exception {
584    try {
585      this.admin.disableTable(TableName.META_TABLE_NAME);
586      fail("Expected to throw ConstraintException");
587    } catch (ConstraintException e) {
588    }
589    // Before the fix for HBASE-6146, the below table creation was failing as the hbase:meta table
590    // actually getting disabled by the disableTable() call.
591    HTableDescriptor htd =
592        new HTableDescriptor(TableName.valueOf(Bytes.toBytes(name.getMethodName())));
593    HColumnDescriptor hcd = new HColumnDescriptor(Bytes.toBytes("cf1"));
594    htd.addFamily(hcd);
595    TEST_UTIL.getHBaseAdmin().createTable(htd);
596  }
597
598  @Test
599  public void testIsEnabledOrDisabledOnUnknownTable() throws Exception {
600    try {
601      admin.isTableEnabled(TableName.valueOf(name.getMethodName()));
602      fail("Test should fail if isTableEnabled called on unknown table.");
603    } catch (IOException e) {
604    }
605
606    try {
607      admin.isTableDisabled(TableName.valueOf(name.getMethodName()));
608      fail("Test should fail if isTableDisabled called on unknown table.");
609    } catch (IOException e) {
610    }
611  }
612
613  @Test
614  public void testGetRegion() throws Exception {
615    // We use actual HBaseAdmin instance instead of going via Admin interface in
616    // here because makes use of an internal HBA method (TODO: Fix.).
617    HBaseAdmin rawAdmin = TEST_UTIL.getHBaseAdmin();
618
619    final TableName tableName = TableName.valueOf(name.getMethodName());
620    LOG.info("Started " + tableName);
621    Table t = TEST_UTIL.createMultiRegionTable(tableName, HConstants.CATALOG_FAMILY);
622
623    try (RegionLocator locator = TEST_UTIL.getConnection().getRegionLocator(tableName)) {
624      HRegionLocation regionLocation = locator.getRegionLocation(Bytes.toBytes("mmm"));
625      RegionInfo region = regionLocation.getRegionInfo();
626      byte[] regionName = region.getRegionName();
627      Pair<RegionInfo, ServerName> pair = rawAdmin.getRegion(regionName);
628      assertTrue(Bytes.equals(regionName, pair.getFirst().getRegionName()));
629      pair = rawAdmin.getRegion(region.getEncodedNameAsBytes());
630      assertTrue(Bytes.equals(regionName, pair.getFirst().getRegionName()));
631    }
632  }
633
634  @Test
635  public void testBalancer() throws Exception {
636    boolean initialState = admin.isBalancerEnabled();
637
638    // Start the balancer, wait for it.
639    boolean prevState = admin.setBalancerRunning(!initialState, true);
640
641    // The previous state should be the original state we observed
642    assertEquals(initialState, prevState);
643
644    // Current state should be opposite of the original
645    assertEquals(!initialState, admin.isBalancerEnabled());
646
647    // Reset it back to what it was
648    prevState = admin.setBalancerRunning(initialState, true);
649
650    // The previous state should be the opposite of the initial state
651    assertEquals(!initialState, prevState);
652    // Current state should be the original state again
653    assertEquals(initialState, admin.isBalancerEnabled());
654  }
655
656  @Test
657  public void testRegionNormalizer() throws Exception {
658    boolean initialState = admin.isNormalizerEnabled();
659
660    // flip state
661    boolean prevState = admin.setNormalizerRunning(!initialState);
662
663    // The previous state should be the original state we observed
664    assertEquals(initialState, prevState);
665
666    // Current state should be opposite of the original
667    assertEquals(!initialState, admin.isNormalizerEnabled());
668
669    // Reset it back to what it was
670    prevState = admin.setNormalizerRunning(initialState);
671
672    // The previous state should be the opposite of the initial state
673    assertEquals(!initialState, prevState);
674    // Current state should be the original state again
675    assertEquals(initialState, admin.isNormalizerEnabled());
676  }
677
678  @Test
679  public void testAbortProcedureFail() throws Exception {
680    Random randomGenerator = new Random();
681    long procId = randomGenerator.nextLong();
682
683    boolean abortResult = admin.abortProcedure(procId, true);
684    assertFalse(abortResult);
685  }
686
687  @Test
688  public void testGetProcedures() throws Exception {
689    String procList = admin.getProcedures();
690    assertTrue(procList.startsWith("["));
691  }
692
693  @Test
694  public void testGetLocks() throws Exception {
695    String lockList = admin.getLocks();
696    assertTrue(lockList.startsWith("["));
697  }
698
699  @Test
700  public void testDecommissionRegionServers() throws Exception {
701    List<ServerName> decommissionedRegionServers = admin.listDecommissionedRegionServers();
702    assertTrue(decommissionedRegionServers.isEmpty());
703
704    final TableName tableName = TableName.valueOf(name.getMethodName());
705    TEST_UTIL.createMultiRegionTable(tableName, Bytes.toBytes("f"), 6);
706
707    ArrayList<ServerName> clusterRegionServers =
708        new ArrayList<>(admin.getClusterMetrics(EnumSet.of(Option.LIVE_SERVERS))
709          .getLiveServerMetrics().keySet());
710
711    assertEquals(3, clusterRegionServers.size());
712
713    HashMap<ServerName, List<RegionInfo>> serversToDecommssion = new HashMap<>();
714    // Get a server that has regions. We will decommission two of the servers,
715    // leaving one online.
716    int i;
717    for (i = 0; i < clusterRegionServers.size(); i++) {
718      List<RegionInfo> regionsOnServer = admin.getRegions(clusterRegionServers.get(i));
719      if (regionsOnServer.size() > 0) {
720        serversToDecommssion.put(clusterRegionServers.get(i), regionsOnServer);
721        break;
722      }
723    }
724
725    clusterRegionServers.remove(i);
726    // Get another server to decommission.
727    serversToDecommssion.put(clusterRegionServers.get(0),
728      admin.getRegions(clusterRegionServers.get(0)));
729
730    ServerName remainingServer = clusterRegionServers.get(1);
731
732    // Decommission
733    admin.decommissionRegionServers(new ArrayList<ServerName>(serversToDecommssion.keySet()), true);
734    assertEquals(2, admin.listDecommissionedRegionServers().size());
735
736    // Verify the regions have been off the decommissioned servers, all on the one
737    // remaining server.
738    for (ServerName server : serversToDecommssion.keySet()) {
739      for (RegionInfo region : serversToDecommssion.get(server)) {
740        TEST_UTIL.assertRegionOnServer(region, remainingServer, 10000);
741      }
742    }
743
744    // Recommission and load the regions.
745    for (ServerName server : serversToDecommssion.keySet()) {
746      List<byte[]> encodedRegionNames = serversToDecommssion.get(server).stream()
747          .map(region -> region.getEncodedNameAsBytes()).collect(Collectors.toList());
748      admin.recommissionRegionServer(server, encodedRegionNames);
749    }
750    assertTrue(admin.listDecommissionedRegionServers().isEmpty());
751    // Verify the regions have been moved to the recommissioned servers
752    for (ServerName server : serversToDecommssion.keySet()) {
753      for (RegionInfo region : serversToDecommssion.get(server)) {
754        TEST_UTIL.assertRegionOnServer(region, server, 10000);
755      }
756    }
757  }
758}