You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by ap...@apache.org on 2018/10/05 00:20:09 UTC

[3/9] hbase git commit: HBASE-21265 Split up TestRSGroups

http://git-wip-us.apache.org/repos/asf/hbase/blob/e42741e0/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsBase.java
----------------------------------------------------------------------
diff --git a/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsBase.java b/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsBase.java
index 43099db..6a70b30 100644
--- a/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsBase.java
+++ b/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsBase.java
@@ -17,67 +17,61 @@
  */
 package org.apache.hadoop.hbase.rsgroup;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
 
 import java.io.IOException;
-import java.security.SecureRandom;
-import java.util.ArrayList;
 import java.util.EnumSet;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
+import java.util.Random;
 import java.util.Set;
 import java.util.TreeMap;
+
 import org.apache.hadoop.hbase.ClusterMetrics;
 import org.apache.hadoop.hbase.ClusterMetrics.Option;
 import org.apache.hadoop.hbase.HBaseCluster;
 import org.apache.hadoop.hbase.HBaseTestingUtility;
-import org.apache.hadoop.hbase.HColumnDescriptor;
-import org.apache.hadoop.hbase.HTableDescriptor;
+import org.apache.hadoop.hbase.HConstants;
+import org.apache.hadoop.hbase.MiniHBaseCluster;
 import org.apache.hadoop.hbase.NamespaceDescriptor;
 import org.apache.hadoop.hbase.RegionMetrics;
 import org.apache.hadoop.hbase.ServerMetrics;
 import org.apache.hadoop.hbase.ServerName;
 import org.apache.hadoop.hbase.TableName;
-import org.apache.hadoop.hbase.TableNotFoundException;
 import org.apache.hadoop.hbase.Waiter;
 import org.apache.hadoop.hbase.client.Admin;
-import org.apache.hadoop.hbase.client.ClusterConnection;
 import org.apache.hadoop.hbase.client.RegionInfo;
-import org.apache.hadoop.hbase.constraint.ConstraintException;
+import org.apache.hadoop.hbase.client.TableDescriptor;
+import org.apache.hadoop.hbase.coprocessor.CoprocessorHost;
+import org.apache.hadoop.hbase.coprocessor.MasterCoprocessor;
+import org.apache.hadoop.hbase.coprocessor.MasterCoprocessorEnvironment;
+import org.apache.hadoop.hbase.coprocessor.MasterObserver;
+import org.apache.hadoop.hbase.coprocessor.ObserverContext;
 import org.apache.hadoop.hbase.master.HMaster;
+import org.apache.hadoop.hbase.master.MasterCoprocessorHost;
+import org.apache.hadoop.hbase.master.ServerManager;
+import org.apache.hadoop.hbase.master.snapshot.SnapshotManager;
 import org.apache.hadoop.hbase.net.Address;
 import org.apache.hadoop.hbase.util.Bytes;
-import org.junit.Assert;
-import org.junit.Before;
+
 import org.junit.Rule;
-import org.junit.Test;
 import org.junit.rules.TestName;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import org.apache.hbase.thirdparty.com.google.common.collect.Lists;
 import org.apache.hbase.thirdparty.com.google.common.collect.Maps;
 import org.apache.hbase.thirdparty.com.google.common.collect.Sets;
-import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
-import org.apache.hadoop.hbase.shaded.protobuf.generated.AdminProtos;
-import org.apache.hadoop.hbase.shaded.protobuf.generated.AdminProtos.GetServerInfoRequest;
 
 public abstract class TestRSGroupsBase {
   protected static final Logger LOG = LoggerFactory.getLogger(TestRSGroupsBase.class);
-  @Rule
-  public TestName name = new TestName();
 
   //shared
   protected final static String groupPrefix = "Group";
   protected final static String tablePrefix = "Group";
-  protected final static SecureRandom rand = new SecureRandom();
+  protected final static Random rand = new Random();
 
   //shared, cluster type specific
   protected static HBaseTestingUtility TEST_UTIL;
@@ -85,26 +79,115 @@ public abstract class TestRSGroupsBase {
   protected static HBaseCluster cluster;
   protected static RSGroupAdmin rsGroupAdmin;
   protected static HMaster master;
+  protected static boolean INIT = false;
+  protected static RSGroupAdminEndpoint rsGroupAdminEndpoint;
+  protected static CPMasterObserver observer;
 
   public final static long WAIT_TIMEOUT = 60000*5;
   public final static int NUM_SLAVES_BASE = 4; //number of slaves for the smallest cluster
   public static int NUM_DEAD_SERVERS = 0;
 
   // Per test variables
-  TableName tableName;
-  @Before
-  public void setup() {
+  @Rule
+  public TestName name = new TestName();
+  protected TableName tableName;
+
+  public static void setUpTestBeforeClass() throws Exception {
+    TEST_UTIL = new HBaseTestingUtility();
+    TEST_UTIL.getConfiguration().setFloat(
+            "hbase.master.balancer.stochastic.tableSkewCost", 6000);
+    TEST_UTIL.getConfiguration().set(
+        HConstants.HBASE_MASTER_LOADBALANCER_CLASS,
+        RSGroupBasedLoadBalancer.class.getName());
+    TEST_UTIL.getConfiguration().set(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY,
+        RSGroupAdminEndpoint.class.getName() + "," + CPMasterObserver.class.getName());
+    TEST_UTIL.startMiniCluster(NUM_SLAVES_BASE - 1);
+    TEST_UTIL.getConfiguration().setInt(
+        ServerManager.WAIT_ON_REGIONSERVERS_MINTOSTART,
+        NUM_SLAVES_BASE - 1);
+    TEST_UTIL.getConfiguration().setBoolean(SnapshotManager.HBASE_SNAPSHOT_ENABLED, true);
+    initialize();
+  }
+
+  protected static void initialize() throws Exception {
+    admin = TEST_UTIL.getAdmin();
+    cluster = TEST_UTIL.getHBaseCluster();
+    master = ((MiniHBaseCluster)cluster).getMaster();
+
+    //wait for balancer to come online
+    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
+      @Override
+      public boolean evaluate() throws Exception {
+        return master.isInitialized() &&
+            ((RSGroupBasedLoadBalancer) master.getLoadBalancer()).isOnline();
+      }
+    });
+    admin.setBalancerRunning(false,true);
+    rsGroupAdmin = new VerifyingRSGroupAdminClient(
+        new RSGroupAdminClient(TEST_UTIL.getConnection()), TEST_UTIL.getConfiguration());
+    MasterCoprocessorHost host = master.getMasterCoprocessorHost();
+    observer = (CPMasterObserver) host.findCoprocessor(CPMasterObserver.class.getName());
+    rsGroupAdminEndpoint = (RSGroupAdminEndpoint)
+        host.findCoprocessor(RSGroupAdminEndpoint.class.getName());
+  }
+
+  public static void tearDownAfterClass() throws Exception {
+    TEST_UTIL.shutdownMiniCluster();
+  }
+
+  public void setUpBeforeMethod() throws Exception {
     LOG.info(name.getMethodName());
     tableName = TableName.valueOf(tablePrefix + "_" + name.getMethodName());
+    if (!INIT) {
+      INIT = true;
+      tearDownAfterMethod();
+    }
+    observer.resetFlags();
   }
 
-  protected RSGroupInfo addGroup(String groupName, int serverCount)
+  public void tearDownAfterMethod() throws Exception {
+    deleteTableIfNecessary();
+    deleteNamespaceIfNecessary();
+    deleteGroups();
+
+    for(ServerName sn : admin.listDecommissionedRegionServers()){
+      admin.recommissionRegionServer(sn, null);
+    }
+    assertTrue(admin.listDecommissionedRegionServers().isEmpty());
+
+    int missing = NUM_SLAVES_BASE - getNumServers();
+    LOG.info("Restoring servers: "+missing);
+    for(int i=0; i<missing; i++) {
+      ((MiniHBaseCluster)cluster).startRegionServer();
+    }
+
+    rsGroupAdmin.addRSGroup("master");
+    ServerName masterServerName =
+        ((MiniHBaseCluster)cluster).getMaster().getServerName();
+
+    try {
+      rsGroupAdmin.moveServers(Sets.newHashSet(masterServerName.getAddress()), "master");
+    } catch (Exception ex) {
+      LOG.warn("Got this on setup, FYI", ex);
+    }
+    assertTrue(observer.preMoveServersCalled);
+    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
+      @Override
+      public boolean evaluate() throws Exception {
+        LOG.info("Waiting for cleanup to finish " + rsGroupAdmin.listRSGroups());
+        //Might be greater since moving servers back to default
+        //is after starting a server
+
+        return rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP).getServers().size()
+            == NUM_SLAVES_BASE;
+      }
+    });
+  }
+
+  public RSGroupInfo addGroup(String groupName, int serverCount)
       throws IOException, InterruptedException {
     RSGroupInfo defaultInfo = rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP);
-    assertTrue(defaultInfo != null);
-    assertTrue(defaultInfo.getServers().size() >= serverCount);
     rsGroupAdmin.addRSGroup(groupName);
-
     Set<Address> set = new HashSet<>();
     for(Address server: defaultInfo.getServers()) {
       if(set.size() == serverCount) {
@@ -114,24 +197,23 @@ public abstract class TestRSGroupsBase {
     }
     rsGroupAdmin.moveServers(set, groupName);
     RSGroupInfo result = rsGroupAdmin.getRSGroupInfo(groupName);
-    assertTrue(result.getServers().size() >= serverCount);
     return result;
   }
 
-  void removeGroup(String groupName) throws IOException {
-    RSGroupInfo RSGroupInfo = rsGroupAdmin.getRSGroupInfo(groupName);
-    rsGroupAdmin.moveTables(RSGroupInfo.getTables(), RSGroupInfo.DEFAULT_GROUP);
-    rsGroupAdmin.moveServers(RSGroupInfo.getServers(), RSGroupInfo.DEFAULT_GROUP);
+  public void removeGroup(String groupName) throws IOException {
+    RSGroupInfo groupInfo = rsGroupAdmin.getRSGroupInfo(groupName);
+    rsGroupAdmin.moveTables(groupInfo.getTables(), RSGroupInfo.DEFAULT_GROUP);
+    rsGroupAdmin.moveServers(groupInfo.getServers(), RSGroupInfo.DEFAULT_GROUP);
     rsGroupAdmin.removeRSGroup(groupName);
   }
 
-  protected void deleteTableIfNecessary() throws IOException {
-    for (HTableDescriptor desc : TEST_UTIL.getAdmin().listTables(tablePrefix+".*")) {
+  public void deleteTableIfNecessary() throws IOException {
+    for (TableDescriptor desc : TEST_UTIL.getAdmin().listTables(tablePrefix+".*")) {
       TEST_UTIL.deleteTable(desc.getTableName());
     }
   }
 
-  protected void deleteNamespaceIfNecessary() throws IOException {
+  public void deleteNamespaceIfNecessary() throws IOException {
     for (NamespaceDescriptor desc : TEST_UTIL.getAdmin().listNamespaceDescriptors()) {
       if(desc.getName().startsWith(tablePrefix)) {
         admin.deleteNamespace(desc.getName());
@@ -139,9 +221,8 @@ public abstract class TestRSGroupsBase {
     }
   }
 
-  protected void deleteGroups() throws IOException {
-    RSGroupAdmin groupAdmin =
-        new RSGroupAdminClient(TEST_UTIL.getConnection());
+  public void deleteGroups() throws IOException {
+    RSGroupAdmin groupAdmin = new RSGroupAdminClient(TEST_UTIL.getConnection());
     for(RSGroupInfo group: groupAdmin.listRSGroups()) {
       if(!group.getName().equals(RSGroupInfo.DEFAULT_GROUP)) {
         groupAdmin.moveTables(group.getTables(), RSGroupInfo.DEFAULT_GROUP);
@@ -193,85 +274,6 @@ public abstract class TestRSGroupsBase {
     return map;
   }
 
-  @Test
-  public void testBogusArgs() throws Exception {
-    assertNull(rsGroupAdmin.getRSGroupInfoOfTable(TableName.valueOf("nonexistent")));
-    assertNull(rsGroupAdmin.getRSGroupOfServer(Address.fromParts("bogus",123)));
-    assertNull(rsGroupAdmin.getRSGroupInfo("bogus"));
-
-    try {
-      rsGroupAdmin.removeRSGroup("bogus");
-      fail("Expected removing bogus group to fail");
-    } catch(ConstraintException ex) {
-      //expected
-    }
-
-    try {
-      rsGroupAdmin.moveTables(Sets.newHashSet(TableName.valueOf("bogustable")), "bogus");
-      fail("Expected move with bogus group to fail");
-    } catch(ConstraintException|TableNotFoundException ex) {
-      //expected
-    }
-
-    try {
-      rsGroupAdmin.moveServers(Sets.newHashSet(Address.fromParts("bogus",123)), "bogus");
-      fail("Expected move with bogus group to fail");
-    } catch(ConstraintException ex) {
-      //expected
-    }
-
-    try {
-      admin.setBalancerRunning(true,true);
-      rsGroupAdmin.balanceRSGroup("bogus");
-      admin.setBalancerRunning(false,true);
-      fail("Expected move with bogus group to fail");
-    } catch(ConstraintException ex) {
-      //expected
-    }
-  }
-
-  @Test
-  public void testCreateMultiRegion() throws IOException {
-    byte[] end = {1,3,5,7,9};
-    byte[] start = {0,2,4,6,8};
-    byte[][] f = {Bytes.toBytes("f")};
-    TEST_UTIL.createTable(tableName, f,1,start,end,10);
-  }
-
-  @Test
-  public void testCreateAndDrop() throws Exception {
-    TEST_UTIL.createTable(tableName, Bytes.toBytes("cf"));
-    //wait for created table to be assigned
-    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
-      @Override
-      public boolean evaluate() throws Exception {
-        return getTableRegionMap().get(tableName) != null;
-      }
-    });
-    TEST_UTIL.deleteTable(tableName);
-  }
-
-
-  @Test
-  public void testSimpleRegionServerMove() throws IOException,
-      InterruptedException {
-    int initNumGroups = rsGroupAdmin.listRSGroups().size();
-    RSGroupInfo appInfo = addGroup(getGroupName(name.getMethodName()), 1);
-    RSGroupInfo adminInfo = addGroup(getGroupName(name.getMethodName()), 1);
-    RSGroupInfo dInfo = rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP);
-    Assert.assertEquals(initNumGroups + 2, rsGroupAdmin.listRSGroups().size());
-    assertEquals(1, adminInfo.getServers().size());
-    assertEquals(1, appInfo.getServers().size());
-    assertEquals(getNumServers() - 2, dInfo.getServers().size());
-    rsGroupAdmin.moveServers(appInfo.getServers(),
-        RSGroupInfo.DEFAULT_GROUP);
-    rsGroupAdmin.removeRSGroup(appInfo.getName());
-    rsGroupAdmin.moveServers(adminInfo.getServers(),
-        RSGroupInfo.DEFAULT_GROUP);
-    rsGroupAdmin.removeRSGroup(adminInfo.getName());
-    Assert.assertEquals(rsGroupAdmin.listRSGroups().size(), initNumGroups);
-  }
-
   // return the real number of region servers, excluding the master embedded region server in 2.0+
   public int getNumServers() throws IOException {
     ClusterMetrics status =
@@ -286,867 +288,197 @@ public abstract class TestRSGroupsBase {
     return count;
   }
 
-  @Test
-  public void testMoveServers() throws Exception {
-    //create groups and assign servers
-    addGroup("bar", 3);
-    rsGroupAdmin.addRSGroup("foo");
-
-    RSGroupInfo barGroup = rsGroupAdmin.getRSGroupInfo("bar");
-    RSGroupInfo fooGroup = rsGroupAdmin.getRSGroupInfo("foo");
-    assertEquals(3, barGroup.getServers().size());
-    assertEquals(0, fooGroup.getServers().size());
-
-    //test fail bogus server move
-    try {
-      rsGroupAdmin.moveServers(Sets.newHashSet(Address.fromString("foo:9999")),"foo");
-      fail("Bogus servers shouldn't have been successfully moved.");
-    } catch(IOException ex) {
-      String exp = "Source RSGroup for server foo:9999 does not exist.";
-      String msg = "Expected '"+exp+"' in exception message: ";
-      assertTrue(msg+" "+ex.getMessage(), ex.getMessage().contains(exp));
-    }
-
-    //test success case
-    LOG.info("moving servers "+barGroup.getServers()+" to group foo");
-    rsGroupAdmin.moveServers(barGroup.getServers(), fooGroup.getName());
-
-    barGroup = rsGroupAdmin.getRSGroupInfo("bar");
-    fooGroup = rsGroupAdmin.getRSGroupInfo("foo");
-    assertEquals(0,barGroup.getServers().size());
-    assertEquals(3,fooGroup.getServers().size());
-
-    LOG.info("moving servers "+fooGroup.getServers()+" to group default");
-    rsGroupAdmin.moveServers(fooGroup.getServers(), RSGroupInfo.DEFAULT_GROUP);
-
-    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
-      @Override
-      public boolean evaluate() throws Exception {
-        return getNumServers() ==
-        rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP).getServers().size();
-      }
-    });
-
-    fooGroup = rsGroupAdmin.getRSGroupInfo("foo");
-    assertEquals(0,fooGroup.getServers().size());
-
-    //test group removal
-    LOG.info("Remove group "+barGroup.getName());
-    rsGroupAdmin.removeRSGroup(barGroup.getName());
-    Assert.assertEquals(null, rsGroupAdmin.getRSGroupInfo(barGroup.getName()));
-    LOG.info("Remove group "+fooGroup.getName());
-    rsGroupAdmin.removeRSGroup(fooGroup.getName());
-    Assert.assertEquals(null, rsGroupAdmin.getRSGroupInfo(fooGroup.getName()));
+  public String getGroupName(String baseName) {
+    return groupPrefix+"_"+baseName+"_"+rand.nextInt(Integer.MAX_VALUE);
   }
 
-  @Test
-  public void testMoveServersFromDefaultGroup() throws Exception {
-    //create groups and assign servers
-    rsGroupAdmin.addRSGroup("foo");
-
-    RSGroupInfo fooGroup = rsGroupAdmin.getRSGroupInfo("foo");
-    assertEquals(0, fooGroup.getServers().size());
-    RSGroupInfo defaultGroup = rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP);
-
-    //test remove all servers from default
-    try {
-      rsGroupAdmin.moveServers(defaultGroup.getServers(), fooGroup.getName());
-      fail(RSGroupAdminServer.KEEP_ONE_SERVER_IN_DEFAULT_ERROR_MESSAGE);
-    } catch (ConstraintException ex) {
-      assertTrue(ex.getMessage().contains(RSGroupAdminServer
-              .KEEP_ONE_SERVER_IN_DEFAULT_ERROR_MESSAGE));
+  public static class CPMasterObserver implements MasterCoprocessor, MasterObserver {
+    boolean preBalanceRSGroupCalled = false;
+    boolean postBalanceRSGroupCalled = false;
+    boolean preMoveServersCalled = false;
+    boolean postMoveServersCalled = false;
+    boolean preMoveTablesCalled = false;
+    boolean postMoveTablesCalled = false;
+    boolean preAddRSGroupCalled = false;
+    boolean postAddRSGroupCalled = false;
+    boolean preRemoveRSGroupCalled = false;
+    boolean postRemoveRSGroupCalled = false;
+    boolean preRemoveServersCalled = false;
+    boolean postRemoveServersCalled = false;
+    boolean preMoveServersAndTables = false;
+    boolean postMoveServersAndTables = false;
+    boolean preGetRSGroupInfoCalled = false;
+    boolean postGetRSGroupInfoCalled = false;
+    boolean preGetRSGroupInfoOfTableCalled = false;
+    boolean postGetRSGroupInfoOfTableCalled = false;
+    boolean preListRSGroupsCalled = false;
+    boolean postListRSGroupsCalled = false;
+    boolean preGetRSGroupInfoOfServerCalled = false;
+    boolean postGetRSGroupInfoOfServerCalled = false;
+
+    public void resetFlags() {
+      preBalanceRSGroupCalled = false;
+      postBalanceRSGroupCalled = false;
+      preMoveServersCalled = false;
+      postMoveServersCalled = false;
+      preMoveTablesCalled = false;
+      postMoveTablesCalled = false;
+      preAddRSGroupCalled = false;
+      postAddRSGroupCalled = false;
+      preRemoveRSGroupCalled = false;
+      postRemoveRSGroupCalled = false;
+      preRemoveServersCalled = false;
+      postRemoveServersCalled = false;
+      preMoveServersAndTables = false;
+      postMoveServersAndTables = false;
+      preGetRSGroupInfoCalled = false;
+      postGetRSGroupInfoCalled = false;
+      preGetRSGroupInfoOfTableCalled = false;
+      postGetRSGroupInfoOfTableCalled = false;
+      preListRSGroupsCalled = false;
+      postListRSGroupsCalled = false;
+      preGetRSGroupInfoOfServerCalled = false;
+      postGetRSGroupInfoOfServerCalled = false;
+    }
+
+    @Override
+    public Optional<MasterObserver> getMasterObserver() {
+      return Optional.of(this);
     }
 
-    //test success case, remove one server from default ,keep at least one server
-    if (defaultGroup.getServers().size() > 1) {
-      Address serverInDefaultGroup = defaultGroup.getServers().iterator().next();
-      LOG.info("moving server " + serverInDefaultGroup + " from group default to group " +
-              fooGroup.getName());
-      rsGroupAdmin.moveServers(Sets.newHashSet(serverInDefaultGroup), fooGroup.getName());
+    @Override
+    public void preMoveServersAndTables(final ObserverContext<MasterCoprocessorEnvironment> ctx,
+        Set<Address> servers, Set<TableName> tables, String targetGroup) throws IOException {
+      preMoveServersAndTables = true;
     }
 
-    fooGroup = rsGroupAdmin.getRSGroupInfo("foo");
-    LOG.info("moving servers " + fooGroup.getServers() + " to group default");
-    rsGroupAdmin.moveServers(fooGroup.getServers(), RSGroupInfo.DEFAULT_GROUP);
-
-    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
-      @Override
-      public boolean evaluate() throws Exception {
-        return getNumServers() ==
-                rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP).getServers().size();
-      }
-    });
-
-    fooGroup = rsGroupAdmin.getRSGroupInfo("foo");
-    assertEquals(0, fooGroup.getServers().size());
-
-    //test group removal
-    LOG.info("Remove group " + fooGroup.getName());
-    rsGroupAdmin.removeRSGroup(fooGroup.getName());
-    Assert.assertEquals(null, rsGroupAdmin.getRSGroupInfo(fooGroup.getName()));
-  }
-
-  @Test
-  public void testTableMoveTruncateAndDrop() throws Exception {
-    final byte[] familyNameBytes = Bytes.toBytes("f");
-    String newGroupName = getGroupName(name.getMethodName());
-    final RSGroupInfo newGroup = addGroup(newGroupName, 2);
-
-    TEST_UTIL.createMultiRegionTable(tableName, familyNameBytes, 5);
-    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
-      @Override
-      public boolean evaluate() throws Exception {
-        List<String> regions = getTableRegionMap().get(tableName);
-        if (regions == null) {
-          return false;
-        }
-
-        return getTableRegionMap().get(tableName).size() >= 5;
-      }
-    });
-
-    RSGroupInfo tableGrp = rsGroupAdmin.getRSGroupInfoOfTable(tableName);
-    assertTrue(tableGrp.getName().equals(RSGroupInfo.DEFAULT_GROUP));
-
-    //change table's group
-    LOG.info("Moving table "+tableName+" to "+newGroup.getName());
-    rsGroupAdmin.moveTables(Sets.newHashSet(tableName), newGroup.getName());
-
-    //verify group change
-    Assert.assertEquals(newGroup.getName(),
-        rsGroupAdmin.getRSGroupInfoOfTable(tableName).getName());
-
-    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
-      @Override
-      public boolean evaluate() throws Exception {
-        Map<ServerName, List<String>> serverMap = getTableServerRegionMap().get(tableName);
-        int count = 0;
-        if (serverMap != null) {
-          for (ServerName rs : serverMap.keySet()) {
-            if (newGroup.containsServer(rs.getAddress())) {
-              count += serverMap.get(rs).size();
-            }
-          }
-        }
-        return count == 5;
-      }
-    });
-
-    //test truncate
-    admin.disableTable(tableName);
-    admin.truncateTable(tableName, true);
-    Assert.assertEquals(1, rsGroupAdmin.getRSGroupInfo(newGroup.getName()).getTables().size());
-    Assert.assertEquals(tableName, rsGroupAdmin.getRSGroupInfo(
-        newGroup.getName()).getTables().first());
-
-    //verify removed table is removed from group
-    TEST_UTIL.deleteTable(tableName);
-    Assert.assertEquals(0, rsGroupAdmin.getRSGroupInfo(newGroup.getName()).getTables().size());
-  }
-
-  @Test
-  public void testGroupBalance() throws Exception {
-    LOG.info(name.getMethodName());
-    String newGroupName = getGroupName(name.getMethodName());
-    final RSGroupInfo newGroup = addGroup(newGroupName, 3);
-
-    final TableName tableName = TableName.valueOf(tablePrefix+"_ns", name.getMethodName());
-    admin.createNamespace(
-        NamespaceDescriptor.create(tableName.getNamespaceAsString())
-            .addConfiguration(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP, newGroupName).build());
-    final byte[] familyNameBytes = Bytes.toBytes("f");
-    final HTableDescriptor desc = new HTableDescriptor(tableName);
-    desc.addFamily(new HColumnDescriptor("f"));
-    byte [] startKey = Bytes.toBytes("aaaaa");
-    byte [] endKey = Bytes.toBytes("zzzzz");
-    admin.createTable(desc, startKey, endKey, 6);
-    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
-      @Override
-      public boolean evaluate() throws Exception {
-        List<String> regions = getTableRegionMap().get(tableName);
-        if (regions == null) {
-          return false;
-        }
-        return regions.size() >= 6;
-      }
-    });
-
-    //make assignment uneven, move all regions to one server
-    Map<ServerName,List<String>> assignMap =
-        getTableServerRegionMap().get(tableName);
-    final ServerName first = assignMap.entrySet().iterator().next().getKey();
-    for(RegionInfo region: admin.getTableRegions(tableName)) {
-      if(!assignMap.get(first).contains(region.getRegionNameAsString())) {
-        admin.move(region.getEncodedNameAsBytes(), Bytes.toBytes(first.getServerName()));
-      }
+    @Override
+    public void postMoveServersAndTables(final ObserverContext<MasterCoprocessorEnvironment> ctx,
+        Set<Address> servers, Set<TableName> tables, String targetGroup) throws IOException {
+      postMoveServersAndTables = true;
     }
-    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
-      @Override
-      public boolean evaluate() throws Exception {
-        Map<ServerName, List<String>> map = getTableServerRegionMap().get(tableName);
-        if (map == null) {
-          return true;
-        }
-        List<String> regions = map.get(first);
-        if (regions == null) {
-          return true;
-        }
-        return regions.size() >= 6;
-      }
-    });
-
-    //balance the other group and make sure it doesn't affect the new group
-    admin.setBalancerRunning(true,true);
-    rsGroupAdmin.balanceRSGroup(RSGroupInfo.DEFAULT_GROUP);
-    assertEquals(6, getTableServerRegionMap().get(tableName).get(first).size());
-
-    //disable balance, balancer will not be run and return false
-    admin.setBalancerRunning(false,true);
-    assertFalse(rsGroupAdmin.balanceRSGroup(newGroupName));
-    assertEquals(6, getTableServerRegionMap().get(tableName).get(first).size());
 
-    //enable balance
-    admin.setBalancerRunning(true,true);
-    rsGroupAdmin.balanceRSGroup(newGroupName);
-    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
-      @Override
-      public boolean evaluate() throws Exception {
-        for (List<String> regions : getTableServerRegionMap().get(tableName).values()) {
-          if (2 != regions.size()) {
-            return false;
-          }
-        }
-        return true;
-      }
-    });
-    admin.setBalancerRunning(false,true);
-  }
-
-  @Test
-  public void testRegionMove() throws Exception {
-    final RSGroupInfo newGroup = addGroup(getGroupName(name.getMethodName()), 1);
-    final byte[] familyNameBytes = Bytes.toBytes("f");
-    // All the regions created below will be assigned to the default group.
-    TEST_UTIL.createMultiRegionTable(tableName, familyNameBytes, 6);
-    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
-      @Override
-      public boolean evaluate() throws Exception {
-        List<String> regions = getTableRegionMap().get(tableName);
-        if (regions == null) {
-          return false;
-        }
-
-        return getTableRegionMap().get(tableName).size() >= 6;
-      }
-    });
-
-    //get target region to move
-    Map<ServerName,List<String>> assignMap =
-        getTableServerRegionMap().get(tableName);
-    String targetRegion = null;
-    for(ServerName server : assignMap.keySet()) {
-      targetRegion = assignMap.get(server).size() > 0 ? assignMap.get(server).get(0) : null;
-      if(targetRegion != null) {
-        break;
-      }
+    @Override
+    public void preRemoveServers(
+        final ObserverContext<MasterCoprocessorEnvironment> ctx,
+        Set<Address> servers) throws IOException {
+      preRemoveServersCalled = true;
     }
-    //get server which is not a member of new group
-    ServerName targetServer = null;
-    for (ServerName server : admin.getClusterMetrics(EnumSet.of(Option.LIVE_SERVERS))
-                                  .getLiveServerMetrics().keySet()) {
-      if (!newGroup.containsServer(server.getAddress())) {
-        targetServer = server;
-        break;
-      }
-    }
-
-    final AdminProtos.AdminService.BlockingInterface targetRS =
-      ((ClusterConnection) admin.getConnection()).getAdmin(targetServer);
 
-    //move target server to group
-    rsGroupAdmin.moveServers(Sets.newHashSet(targetServer.getAddress()),
-        newGroup.getName());
-    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
-      @Override
-      public boolean evaluate() throws Exception {
-        return ProtobufUtil.getOnlineRegions(targetRS).size() <= 0;
-      }
-    });
-
-    // Lets move this region to the new group.
-    TEST_UTIL.getAdmin().move(Bytes.toBytes(RegionInfo.encodeRegionName(
-            Bytes.toBytes(targetRegion))), Bytes.toBytes(targetServer.getServerName()));
-    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
-      @Override
-      public boolean evaluate() throws Exception {
-        return
-            getTableRegionMap().get(tableName) != null &&
-                getTableRegionMap().get(tableName).size() == 6 &&
-                admin.getClusterMetrics(EnumSet.of(Option.REGIONS_IN_TRANSITION))
-                     .getRegionStatesInTransition().size() < 1;
-      }
-    });
-
-    //verify that targetServer didn't open it
-    for (RegionInfo region: ProtobufUtil.getOnlineRegions(targetRS)) {
-      if (targetRegion.equals(region.getRegionNameAsString())) {
-        fail("Target server opened region");
-      }
+    @Override
+    public void postRemoveServers(
+        final ObserverContext<MasterCoprocessorEnvironment> ctx,
+        Set<Address> servers) throws IOException {
+      postRemoveServersCalled = true;
     }
-  }
 
-  @Test
-  public void testFailRemoveGroup() throws IOException, InterruptedException {
-    int initNumGroups = rsGroupAdmin.listRSGroups().size();
-    addGroup("bar", 3);
-    TEST_UTIL.createTable(tableName, Bytes.toBytes("f"));
-    rsGroupAdmin.moveTables(Sets.newHashSet(tableName), "bar");
-    RSGroupInfo barGroup = rsGroupAdmin.getRSGroupInfo("bar");
-    //group is not empty therefore it should fail
-    try {
-      rsGroupAdmin.removeRSGroup(barGroup.getName());
-      fail("Expected remove group to fail");
-    } catch(IOException e) {
-    }
-    //group cannot lose all it's servers therefore it should fail
-    try {
-      rsGroupAdmin.moveServers(barGroup.getServers(), RSGroupInfo.DEFAULT_GROUP);
-      fail("Expected move servers to fail");
-    } catch(IOException e) {
+    @Override
+    public void preRemoveRSGroup(final ObserverContext<MasterCoprocessorEnvironment> ctx,
+        String name) throws IOException {
+      preRemoveRSGroupCalled = true;
     }
 
-    rsGroupAdmin.moveTables(barGroup.getTables(), RSGroupInfo.DEFAULT_GROUP);
-    try {
-      rsGroupAdmin.removeRSGroup(barGroup.getName());
-      fail("Expected move servers to fail");
-    } catch(IOException e) {
+    @Override
+    public void postRemoveRSGroup(final ObserverContext<MasterCoprocessorEnvironment> ctx,
+        String name) throws IOException {
+      postRemoveRSGroupCalled = true;
     }
 
-    rsGroupAdmin.moveServers(barGroup.getServers(), RSGroupInfo.DEFAULT_GROUP);
-    rsGroupAdmin.removeRSGroup(barGroup.getName());
-
-    Assert.assertEquals(initNumGroups, rsGroupAdmin.listRSGroups().size());
-  }
-
-  @Test
-  public void testKillRS() throws Exception {
-    RSGroupInfo appInfo = addGroup("appInfo", 1);
-
-    final TableName tableName = TableName.valueOf(tablePrefix+"_ns", name.getMethodName());
-    admin.createNamespace(
-        NamespaceDescriptor.create(tableName.getNamespaceAsString())
-            .addConfiguration(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP, appInfo.getName()).build());
-    final HTableDescriptor desc = new HTableDescriptor(tableName);
-    desc.addFamily(new HColumnDescriptor("f"));
-    admin.createTable(desc);
-    //wait for created table to be assigned
-    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
-      @Override
-      public boolean evaluate() throws Exception {
-        return getTableRegionMap().get(desc.getTableName()) != null;
-      }
-    });
-
-    ServerName targetServer = ServerName.parseServerName(
-        appInfo.getServers().iterator().next().toString());
-    AdminProtos.AdminService.BlockingInterface targetRS =
-      ((ClusterConnection) admin.getConnection()).getAdmin(targetServer);
-    RegionInfo targetRegion = ProtobufUtil.getOnlineRegions(targetRS).get(0);
-    Assert.assertEquals(1, ProtobufUtil.getOnlineRegions(targetRS).size());
-
-    try {
-      //stopping may cause an exception
-      //due to the connection loss
-      targetRS.stopServer(null,
-          AdminProtos.StopServerRequest.newBuilder().setReason("Die").build());
-    } catch(Exception e) {
+    @Override
+    public void preAddRSGroup(final ObserverContext<MasterCoprocessorEnvironment> ctx,
+        String name) throws IOException {
+      preAddRSGroupCalled = true;
     }
-    assertFalse(cluster.getClusterMetrics().getLiveServerMetrics().containsKey(targetServer));
-
-    //wait for created table to be assigned
-    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
-      @Override
-      public boolean evaluate() throws Exception {
-        return cluster.getClusterMetrics().getRegionStatesInTransition().isEmpty();
-      }
-    });
-    Set<Address> newServers = Sets.newHashSet();
-    newServers.add(
-        rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP).getServers().iterator().next());
-    rsGroupAdmin.moveServers(newServers, appInfo.getName());
-
-    //Make sure all the table's regions get reassigned
-    //disabling the table guarantees no conflicting assign/unassign (ie SSH) happens
-    admin.disableTable(tableName);
-    admin.enableTable(tableName);
-
-    //wait for region to be assigned
-    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
-      @Override
-      public boolean evaluate() throws Exception {
-        return cluster.getClusterMetrics().getRegionStatesInTransition().isEmpty();
-      }
-    });
-
-    targetServer = ServerName.parseServerName(
-        newServers.iterator().next().toString());
-    targetRS =
-      ((ClusterConnection) admin.getConnection()).getAdmin(targetServer);
-    Assert.assertEquals(1, ProtobufUtil.getOnlineRegions(targetRS).size());
-    Assert.assertEquals(tableName,
-        ProtobufUtil.getOnlineRegions(targetRS).get(0).getTable());
-  }
-
-  @Test
-  public void testValidGroupNames() throws IOException {
-    String[] badNames = {"foo*","foo@","-"};
-    String[] goodNames = {"foo_123"};
 
-    for(String entry: badNames) {
-      try {
-        rsGroupAdmin.addRSGroup(entry);
-        fail("Expected a constraint exception for: "+entry);
-      } catch(ConstraintException ex) {
-        //expected
-      }
+    @Override
+    public void postAddRSGroup(final ObserverContext<MasterCoprocessorEnvironment> ctx,
+        String name) throws IOException {
+      postAddRSGroupCalled = true;
     }
 
-    for(String entry: goodNames) {
-      rsGroupAdmin.addRSGroup(entry);
+    @Override
+    public void preMoveTables(final ObserverContext<MasterCoprocessorEnvironment> ctx,
+        Set<TableName> tables, String targetGroup) throws IOException {
+      preMoveTablesCalled = true;
     }
-  }
-
-  private String getGroupName(String baseName) {
-    return groupPrefix+"_"+baseName+"_"+rand.nextInt(Integer.MAX_VALUE);
-  }
-
-  @Test
-  public void testMultiTableMove() throws Exception {
-    final TableName tableNameA = TableName.valueOf(tablePrefix + name.getMethodName() + "A");
-    final TableName tableNameB = TableName.valueOf(tablePrefix + name.getMethodName() + "B");
-    final byte[] familyNameBytes = Bytes.toBytes("f");
-    String newGroupName = getGroupName(name.getMethodName());
-    final RSGroupInfo newGroup = addGroup(newGroupName, 1);
-
-    TEST_UTIL.createTable(tableNameA, familyNameBytes);
-    TEST_UTIL.createTable(tableNameB, familyNameBytes);
-    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
-      @Override
-      public boolean evaluate() throws Exception {
-        List<String> regionsA = getTableRegionMap().get(tableNameA);
-        if (regionsA == null) {
-          return false;
-        }
-
-        List<String> regionsB = getTableRegionMap().get(tableNameB);
-        if (regionsB == null) {
-          return false;
-        }
-
-        return getTableRegionMap().get(tableNameA).size() >= 1
-                && getTableRegionMap().get(tableNameB).size() >= 1;
-      }
-    });
-
-    RSGroupInfo tableGrpA = rsGroupAdmin.getRSGroupInfoOfTable(tableNameA);
-    assertTrue(tableGrpA.getName().equals(RSGroupInfo.DEFAULT_GROUP));
-
-    RSGroupInfo tableGrpB = rsGroupAdmin.getRSGroupInfoOfTable(tableNameB);
-    assertTrue(tableGrpB.getName().equals(RSGroupInfo.DEFAULT_GROUP));
-    //change table's group
-    LOG.info("Moving table [" + tableNameA + "," + tableNameB + "] to " + newGroup.getName());
-    rsGroupAdmin.moveTables(Sets.newHashSet(tableNameA, tableNameB), newGroup.getName());
-
-    //verify group change
-    Assert.assertEquals(newGroup.getName(),
-            rsGroupAdmin.getRSGroupInfoOfTable(tableNameA).getName());
-
-    Assert.assertEquals(newGroup.getName(),
-            rsGroupAdmin.getRSGroupInfoOfTable(tableNameB).getName());
-
-    //verify tables' not exist in old group
-    Set<TableName> DefaultTables = rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP)
-            .getTables();
-    assertFalse(DefaultTables.contains(tableNameA));
-    assertFalse(DefaultTables.contains(tableNameB));
-
-    //verify tables' exist in new group
-    Set<TableName> newGroupTables = rsGroupAdmin.getRSGroupInfo(newGroupName).getTables();
-    assertTrue(newGroupTables.contains(tableNameA));
-    assertTrue(newGroupTables.contains(tableNameB));
-  }
-
-  @Test
-  public void testDisabledTableMove() throws Exception {
-    final byte[] familyNameBytes = Bytes.toBytes("f");
-    String newGroupName = getGroupName(name.getMethodName());
-    final RSGroupInfo newGroup = addGroup(newGroupName, 2);
-
-    TEST_UTIL.createMultiRegionTable(tableName, familyNameBytes, 5);
-    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
-      @Override
-      public boolean evaluate() throws Exception {
-        List<String> regions = getTableRegionMap().get(tableName);
-        if (regions == null) {
-          return false;
-        }
-        return getTableRegionMap().get(tableName).size() >= 5;
-      }
-    });
-
-    RSGroupInfo tableGrp = rsGroupAdmin.getRSGroupInfoOfTable(tableName);
-    assertTrue(tableGrp.getName().equals(RSGroupInfo.DEFAULT_GROUP));
 
-    //test disable table
-    admin.disableTable(tableName);
-
-    //change table's group
-    LOG.info("Moving table "+ tableName + " to " + newGroup.getName());
-    rsGroupAdmin.moveTables(Sets.newHashSet(tableName), newGroup.getName());
-
-    //verify group change
-    Assert.assertEquals(newGroup.getName(),
-        rsGroupAdmin.getRSGroupInfoOfTable(tableName).getName());
-  }
-
-  @Test
-  public void testNonExistentTableMove() throws Exception {
-    TableName tableName = TableName.valueOf(tablePrefix + name.getMethodName());
-
-    RSGroupInfo tableGrp = rsGroupAdmin.getRSGroupInfoOfTable(tableName);
-    assertNull(tableGrp);
-
-    //test if table exists already.
-    boolean exist = admin.tableExists(tableName);
-    assertFalse(exist);
-
-    LOG.info("Moving table "+ tableName + " to " + RSGroupInfo.DEFAULT_GROUP);
-    try {
-      rsGroupAdmin.moveTables(Sets.newHashSet(tableName), RSGroupInfo.DEFAULT_GROUP);
-      fail("Table " + tableName + " shouldn't have been successfully moved.");
-    } catch(IOException ex) {
-      assertTrue(ex instanceof TableNotFoundException);
+    @Override
+    public void postMoveTables(final ObserverContext<MasterCoprocessorEnvironment> ctx,
+        Set<TableName> tables, String targetGroup) throws IOException {
+      postMoveTablesCalled = true;
     }
 
-    try {
-      rsGroupAdmin.moveServersAndTables(
-          Sets.newHashSet(Address.fromParts("bogus",123)),
-          Sets.newHashSet(tableName), RSGroupInfo.DEFAULT_GROUP);
-      fail("Table " + tableName + " shouldn't have been successfully moved.");
-    } catch(IOException ex) {
-      assertTrue(ex instanceof TableNotFoundException);
+    @Override
+    public void preMoveServers(final ObserverContext<MasterCoprocessorEnvironment> ctx,
+        Set<Address> servers, String targetGroup) throws IOException {
+      preMoveServersCalled = true;
     }
-    //verify group change
-    assertNull(rsGroupAdmin.getRSGroupInfoOfTable(tableName));
-  }
 
-  @Test
-  public void testMoveServersAndTables() throws Exception {
-    LOG.info("testMoveServersAndTables");
-    final RSGroupInfo newGroup = addGroup(getGroupName(name.getMethodName()), 1);
-    //create table
-    final byte[] familyNameBytes = Bytes.toBytes("f");
-    TEST_UTIL.createMultiRegionTable(tableName, familyNameBytes, 5);
-    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
-      @Override
-      public boolean evaluate() throws Exception {
-        List<String> regions = getTableRegionMap().get(tableName);
-        if (regions == null) {
-          return false;
-        }
-
-        return getTableRegionMap().get(tableName).size() >= 5;
-      }
-    });
-
-    //get server which is not a member of new group
-    ServerName targetServer = null;
-    for(ServerName server : admin.getClusterMetrics(EnumSet.of(Option.LIVE_SERVERS))
-      .getLiveServerMetrics().keySet()) {
-      if(!newGroup.containsServer(server.getAddress()) &&
-           !rsGroupAdmin.getRSGroupInfo("master").containsServer(server.getAddress())) {
-        targetServer = server;
-        break;
-      }
+    @Override
+    public void postMoveServers(final ObserverContext<MasterCoprocessorEnvironment> ctx,
+        Set<Address> servers, String targetGroup) throws IOException {
+      postMoveServersCalled = true;
     }
 
-    LOG.debug("Print group info : " + rsGroupAdmin.listRSGroups());
-    int oldDefaultGroupServerSize =
-            rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP).getServers().size();
-    int oldDefaultGroupTableSize =
-            rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP).getTables().size();
-
-    //test fail bogus server move
-    try {
-      rsGroupAdmin.moveServersAndTables(Sets.newHashSet(Address.fromString("foo:9999")),
-              Sets.newHashSet(tableName), newGroup.getName());
-      fail("Bogus servers shouldn't have been successfully moved.");
-    } catch(IOException ex) {
-      String exp = "Source RSGroup for server foo:9999 does not exist.";
-      String msg = "Expected '" + exp + "' in exception message: ";
-      assertTrue(msg + " " + ex.getMessage(), ex.getMessage().contains(exp));
+    @Override
+    public void preBalanceRSGroup(final ObserverContext<MasterCoprocessorEnvironment> ctx,
+        String groupName) throws IOException {
+      preBalanceRSGroupCalled = true;
     }
 
-    //test fail server move
-    try {
-      rsGroupAdmin.moveServersAndTables(Sets.newHashSet(targetServer.getAddress()),
-              Sets.newHashSet(tableName), RSGroupInfo.DEFAULT_GROUP);
-      fail("servers shouldn't have been successfully moved.");
-    } catch(IOException ex) {
-      String exp = "Target RSGroup " + RSGroupInfo.DEFAULT_GROUP +
-              " is same as source " + RSGroupInfo.DEFAULT_GROUP + " RSGroup.";
-      String msg = "Expected '" + exp + "' in exception message: ";
-      assertTrue(msg + " " + ex.getMessage(), ex.getMessage().contains(exp));
+    @Override
+    public void postBalanceRSGroup(final ObserverContext<MasterCoprocessorEnvironment> ctx,
+        String groupName, boolean balancerRan) throws IOException {
+      postBalanceRSGroupCalled = true;
     }
 
-    //verify default group info
-    Assert.assertEquals(oldDefaultGroupServerSize,
-            rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP).getServers().size());
-    Assert.assertEquals(oldDefaultGroupTableSize,
-            rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP).getTables().size());
-
-    //verify new group info
-    Assert.assertEquals(1,
-            rsGroupAdmin.getRSGroupInfo(newGroup.getName()).getServers().size());
-    Assert.assertEquals(0,
-            rsGroupAdmin.getRSGroupInfo(newGroup.getName()).getTables().size());
-
-    //get all region to move targetServer
-    List<String> regionList = getTableRegionMap().get(tableName);
-    for(String region : regionList) {
-      // Lets move this region to the targetServer
-      TEST_UTIL.getAdmin().move(Bytes.toBytes(RegionInfo.encodeRegionName(Bytes.toBytes(region))),
-              Bytes.toBytes(targetServer.getServerName()));
+    @Override
+    public void preGetRSGroupInfo(final ObserverContext<MasterCoprocessorEnvironment> ctx,
+        final String groupName) throws IOException {
+      preGetRSGroupInfoCalled = true;
     }
 
-    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
-      @Override
-      public boolean evaluate() throws Exception {
-        return getTableRegionMap().get(tableName) != null &&
-                getTableRegionMap().get(tableName).size() == 5 &&
-                getTableServerRegionMap().get(tableName).size() == 1 &&
-                admin.getClusterMetrics(EnumSet.of(Option.REGIONS_IN_TRANSITION))
-                     .getRegionStatesInTransition().size() < 1;
-      }
-    });
-
-    //verify that all region move to targetServer
-    Assert.assertEquals(5, getTableServerRegionMap().get(tableName).get(targetServer).size());
-
-    //move targetServer and table to newGroup
-    LOG.info("moving server and table to newGroup");
-    rsGroupAdmin.moveServersAndTables(Sets.newHashSet(targetServer.getAddress()),
-            Sets.newHashSet(tableName), newGroup.getName());
-
-    //verify group change
-    Assert.assertEquals(newGroup.getName(),
-            rsGroupAdmin.getRSGroupInfoOfTable(tableName).getName());
-
-    //verify servers' not exist in old group
-    Set<Address> defaultServers = rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP)
-            .getServers();
-    assertFalse(defaultServers.contains(targetServer.getAddress()));
-
-    //verify servers' exist in new group
-    Set<Address> newGroupServers = rsGroupAdmin.getRSGroupInfo(newGroup.getName()).getServers();
-    assertTrue(newGroupServers.contains(targetServer.getAddress()));
-
-    //verify tables' not exist in old group
-    Set<TableName> defaultTables = rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP)
-            .getTables();
-    assertFalse(defaultTables.contains(tableName));
-
-    //verify tables' exist in new group
-    Set<TableName> newGroupTables = rsGroupAdmin.getRSGroupInfo(newGroup.getName()).getTables();
-    assertTrue(newGroupTables.contains(tableName));
-
-    //verify that all region still assgin on targetServer
-    Assert.assertEquals(5, getTableServerRegionMap().get(tableName).get(targetServer).size());
-  }
-
-  @Test
-  public void testClearDeadServers() throws Exception {
-    LOG.info("testClearDeadServers");
-    final RSGroupInfo newGroup = addGroup(getGroupName(name.getMethodName()), 3);
-    NUM_DEAD_SERVERS = cluster.getClusterMetrics().getDeadServerNames().size();
-
-    ServerName targetServer = ServerName.parseServerName(
-        newGroup.getServers().iterator().next().toString());
-    AdminProtos.AdminService.BlockingInterface targetRS =
-        ((ClusterConnection) admin.getConnection()).getAdmin(targetServer);
-    try {
-      targetServer = ProtobufUtil.toServerName(targetRS.getServerInfo(null,
-          GetServerInfoRequest.newBuilder().build()).getServerInfo().getServerName());
-      //stopping may cause an exception
-      //due to the connection loss
-      targetRS.stopServer(null,
-          AdminProtos.StopServerRequest.newBuilder().setReason("Die").build());
-      NUM_DEAD_SERVERS ++;
-    } catch(Exception e) {
+    @Override
+    public void postGetRSGroupInfo(final ObserverContext<MasterCoprocessorEnvironment> ctx,
+        final String groupName) throws IOException {
+      postGetRSGroupInfoCalled = true;
     }
-    //wait for stopped regionserver to dead server list
-    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
-      @Override
-      public boolean evaluate() throws Exception {
-        return !master.getServerManager().areDeadServersInProgress()
-            && cluster.getClusterMetrics().getDeadServerNames().size() == NUM_DEAD_SERVERS;
-      }
-    });
-    assertFalse(cluster.getClusterMetrics().getLiveServerMetrics().containsKey(targetServer));
-    assertTrue(cluster.getClusterMetrics().getDeadServerNames().contains(targetServer));
-    assertTrue(newGroup.getServers().contains(targetServer.getAddress()));
-
-    //clear dead servers list
-    List<ServerName> notClearedServers = admin.clearDeadServers(Lists.newArrayList(targetServer));
-    assertEquals(0, notClearedServers.size());
-
-    Set<Address> newGroupServers = rsGroupAdmin.getRSGroupInfo(newGroup.getName()).getServers();
-    assertFalse(newGroupServers.contains(targetServer.getAddress()));
-    assertEquals(2, newGroupServers.size());
-  }
-
-  @Test
-  public void testRemoveServers() throws Exception {
-    LOG.info("testRemoveServers");
-    final RSGroupInfo newGroup = addGroup(getGroupName(name.getMethodName()), 3);
-    Iterator<Address> iterator = newGroup.getServers().iterator();
-    ServerName targetServer = ServerName.parseServerName(iterator.next().toString());
 
-    // remove online servers
-    try {
-      rsGroupAdmin.removeServers(Sets.newHashSet(targetServer.getAddress()));
-      fail("Online servers shouldn't have been successfully removed.");
-    } catch(IOException ex) {
-      String exp = "Server " + targetServer.getAddress()
-          + " is an online server, not allowed to remove.";
-      String msg = "Expected '" + exp + "' in exception message: ";
-      assertTrue(msg + " " + ex.getMessage(), ex.getMessage().contains(exp));
+    @Override
+    public void preGetRSGroupInfoOfTable(final ObserverContext<MasterCoprocessorEnvironment> ctx,
+        final TableName tableName) throws IOException {
+      preGetRSGroupInfoOfTableCalled = true;
     }
-    assertTrue(newGroup.getServers().contains(targetServer.getAddress()));
 
-    // remove dead servers
-    NUM_DEAD_SERVERS = cluster.getClusterMetrics().getDeadServerNames().size();
-    AdminProtos.AdminService.BlockingInterface targetRS =
-        ((ClusterConnection) admin.getConnection()).getAdmin(targetServer);
-    try {
-      targetServer = ProtobufUtil.toServerName(targetRS.getServerInfo(null,
-          GetServerInfoRequest.newBuilder().build()).getServerInfo().getServerName());
-      //stopping may cause an exception
-      //due to the connection loss
-      LOG.info("stopping server " + targetServer.getHostAndPort());
-      targetRS.stopServer(null,
-          AdminProtos.StopServerRequest.newBuilder().setReason("Die").build());
-      NUM_DEAD_SERVERS ++;
-    } catch(Exception e) {
+    @Override
+    public void postGetRSGroupInfoOfTable(final ObserverContext<MasterCoprocessorEnvironment> ctx,
+        final TableName tableName) throws IOException {
+      postGetRSGroupInfoOfTableCalled = true;
     }
 
-    //wait for stopped regionserver to dead server list
-    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
-      @Override
-      public boolean evaluate() throws Exception {
-        return !master.getServerManager().areDeadServersInProgress()
-            && cluster.getClusterMetrics().getDeadServerNames().size() == NUM_DEAD_SERVERS;
-      }
-    });
-
-    try {
-      rsGroupAdmin.removeServers(Sets.newHashSet(targetServer.getAddress()));
-      fail("Dead servers shouldn't have been successfully removed.");
-    } catch(IOException ex) {
-      String exp = "Server " + targetServer.getAddress() + " is on the dead servers list,"
-          + " Maybe it will come back again, not allowed to remove.";
-      String msg = "Expected '" + exp + "' in exception message: ";
-      assertTrue(msg + " " + ex.getMessage(), ex.getMessage().contains(exp));
+    @Override
+    public void preListRSGroups(final ObserverContext<MasterCoprocessorEnvironment> ctx)
+        throws IOException {
+      preListRSGroupsCalled = true;
     }
-    assertTrue(newGroup.getServers().contains(targetServer.getAddress()));
-
-    // remove decommissioned servers
-    List<ServerName> serversToDecommission = new ArrayList<>();
-    targetServer = ServerName.parseServerName(iterator.next().toString());
-    targetRS = ((ClusterConnection) admin.getConnection()).getAdmin(targetServer);
-    targetServer = ProtobufUtil.toServerName(targetRS.getServerInfo(null,
-          GetServerInfoRequest.newBuilder().build()).getServerInfo().getServerName());
-    assertTrue(master.getServerManager().getOnlineServers().containsKey(targetServer));
-    serversToDecommission.add(targetServer);
-
-    admin.decommissionRegionServers(serversToDecommission, true);
-    assertEquals(1, admin.listDecommissionedRegionServers().size());
-
-    assertTrue(newGroup.getServers().contains(targetServer.getAddress()));
-    rsGroupAdmin.removeServers(Sets.newHashSet(targetServer.getAddress()));
-    Set<Address> newGroupServers = rsGroupAdmin.getRSGroupInfo(newGroup.getName()).getServers();
-    assertFalse(newGroupServers.contains(targetServer.getAddress()));
-    assertEquals(2, newGroupServers.size());
-  }
 
-  @Test
-  public void testCreateWhenRsgroupNoOnlineServers() throws Exception {
-    LOG.info("testCreateWhenRsgroupNoOnlineServers");
-
-    // set rsgroup has no online servers and test create table
-    final RSGroupInfo appInfo = addGroup("appInfo", 1);
-    Iterator<Address> iterator = appInfo.getServers().iterator();
-    List<ServerName> serversToDecommission = new ArrayList<>();
-    ServerName targetServer = ServerName.parseServerName(iterator.next().toString());
-    AdminProtos.AdminService.BlockingInterface targetRS =
-        ((ClusterConnection) admin.getConnection()).getAdmin(targetServer);
-    targetServer = ProtobufUtil.toServerName(
-        targetRS.getServerInfo(null, GetServerInfoRequest.newBuilder().build()).getServerInfo()
-            .getServerName());
-    assertTrue(master.getServerManager().getOnlineServers().containsKey(targetServer));
-    serversToDecommission.add(targetServer);
-    admin.decommissionRegionServers(serversToDecommission, true);
-    assertEquals(1, admin.listDecommissionedRegionServers().size());
+    @Override
+    public void postListRSGroups(final ObserverContext<MasterCoprocessorEnvironment> ctx)
+        throws IOException {
+      postListRSGroupsCalled = true;
+    }
 
-    final TableName tableName = TableName.valueOf(tablePrefix + "_ns", name.getMethodName());
-    admin.createNamespace(NamespaceDescriptor.create(tableName.getNamespaceAsString())
-        .addConfiguration(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP, appInfo.getName()).build());
-    final HTableDescriptor desc = new HTableDescriptor(tableName);
-    desc.addFamily(new HColumnDescriptor("f"));
-    try {
-      admin.createTable(desc);
-      fail("Shouldn't create table successfully!");
-    } catch (Exception e) {
-      LOG.debug("create table error", e);
+    @Override
+    public void preGetRSGroupInfoOfServer(final ObserverContext<MasterCoprocessorEnvironment> ctx,
+        final Address server) throws IOException {
+      preGetRSGroupInfoOfServerCalled = true;
     }
 
-    // recommission and test create table
-    admin.recommissionRegionServer(targetServer, null);
-    assertEquals(0, admin.listDecommissionedRegionServers().size());
-    admin.createTable(desc);
-    // wait for created table to be assigned
-    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
-      @Override public boolean evaluate() throws Exception {
-        return getTableRegionMap().get(desc.getTableName()) != null;
-      }
-    });
-  }
-  @Test
-  public void testClearNotProcessedDeadServer() throws Exception {
-    LOG.info("testClearNotProcessedDeadServer");
-    NUM_DEAD_SERVERS = cluster.getClusterMetrics().getDeadServerNames().size();
-    RSGroupInfo appInfo = addGroup("deadServerGroup", 1);
-    ServerName targetServer =
-        ServerName.parseServerName(appInfo.getServers().iterator().next().toString());
-    AdminProtos.AdminService.BlockingInterface targetRS =
-        ((ClusterConnection) admin.getConnection()).getAdmin(targetServer);
-    try {
-      targetServer = ProtobufUtil.toServerName(targetRS.getServerInfo(null,
-          AdminProtos.GetServerInfoRequest.newBuilder().build()).getServerInfo().getServerName());
-      //stopping may cause an exception
-      //due to the connection loss
-      targetRS.stopServer(null,
-          AdminProtos.StopServerRequest.newBuilder().setReason("Die").build());
-      NUM_DEAD_SERVERS ++;
-    } catch(Exception e) {
+    @Override
+    public void postGetRSGroupInfoOfServer(final ObserverContext<MasterCoprocessorEnvironment> ctx,
+        final Address server) throws IOException {
+      postGetRSGroupInfoOfServerCalled = true;
     }
-    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
-      @Override
-      public boolean evaluate() throws Exception {
-        return cluster.getClusterMetrics().getDeadServerNames().size() == NUM_DEAD_SERVERS;
-      }
-    });
-    List<ServerName> notClearedServers = admin.clearDeadServers(Lists.newArrayList(targetServer));
-    assertEquals(1, notClearedServers.size());
   }
+
 }

http://git-wip-us.apache.org/repos/asf/hbase/blob/e42741e0/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsBasics.java
----------------------------------------------------------------------
diff --git a/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsBasics.java b/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsBasics.java
new file mode 100644
index 0000000..7415ab5
--- /dev/null
+++ b/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsBasics.java
@@ -0,0 +1,320 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.hbase.rsgroup;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.hadoop.hbase.HBaseClassTestRule;
+import org.apache.hadoop.hbase.HColumnDescriptor;
+import org.apache.hadoop.hbase.HTableDescriptor;
+import org.apache.hadoop.hbase.NamespaceDescriptor;
+import org.apache.hadoop.hbase.ServerName;
+import org.apache.hadoop.hbase.TableName;
+import org.apache.hadoop.hbase.Waiter;
+import org.apache.hadoop.hbase.client.ClusterConnection;
+import org.apache.hadoop.hbase.net.Address;
+import org.apache.hadoop.hbase.quotas.QuotaTableUtil;
+import org.apache.hadoop.hbase.quotas.QuotaUtil;
+import org.apache.hadoop.hbase.util.Bytes;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
+import org.apache.hadoop.hbase.shaded.protobuf.generated.AdminProtos;
+import org.apache.hadoop.hbase.shaded.protobuf.generated.AdminProtos.GetServerInfoRequest;
+import org.apache.hadoop.hbase.testclassification.MediumTests;
+import org.apache.hbase.thirdparty.com.google.common.collect.Lists;
+
+@Category({MediumTests.class})
+public class TestRSGroupsBasics extends TestRSGroupsBase {
+
+  @ClassRule
+  public static final HBaseClassTestRule CLASS_RULE =
+      HBaseClassTestRule.forClass(TestRSGroupsBasics.class);
+
+  protected static final Logger LOG = LoggerFactory.getLogger(TestRSGroupsBasics.class);
+
+  @BeforeClass
+  public static void setUp() throws Exception {
+    setUpTestBeforeClass();
+  }
+
+  @AfterClass
+  public static void tearDown() throws Exception {
+    tearDownAfterClass();
+  }
+
+  @Before
+  public void beforeMethod() throws Exception {
+    setUpBeforeMethod();
+  }
+
+  @After
+  public void afterMethod() throws Exception {
+    tearDownAfterMethod();
+  }
+
+  @Test
+  public void testBasicStartUp() throws IOException {
+    RSGroupInfo defaultInfo = rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP);
+    assertEquals(4, defaultInfo.getServers().size());
+    // Assignment of root and meta regions.
+    int count = master.getAssignmentManager().getRegionStates().getRegionAssignments().size();
+    //3 meta,namespace, group
+    assertEquals(3, count);
+  }
+
+  @Test
+  public void testCreateAndDrop() throws Exception {
+    TEST_UTIL.createTable(tableName, Bytes.toBytes("cf"));
+    //wait for created table to be assigned
+    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
+      @Override
+      public boolean evaluate() throws Exception {
+        return getTableRegionMap().get(tableName) != null;
+      }
+    });
+    TEST_UTIL.deleteTable(tableName);
+  }
+
+  @Test
+  public void testCreateMultiRegion() throws IOException {
+    byte[] end = {1,3,5,7,9};
+    byte[] start = {0,2,4,6,8};
+    byte[][] f = {Bytes.toBytes("f")};
+    TEST_UTIL.createTable(tableName, f,1,start,end,10);
+  }
+
+  @Test
+  public void testNamespaceCreateAndAssign() throws Exception {
+    LOG.info("testNamespaceCreateAndAssign");
+    String nsName = tablePrefix+"_foo";
+    final TableName tableName = TableName.valueOf(nsName, tablePrefix + "_testCreateAndAssign");
+    RSGroupInfo appInfo = addGroup("appInfo", 1);
+    admin.createNamespace(NamespaceDescriptor.create(nsName)
+        .addConfiguration(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP, "appInfo").build());
+    final HTableDescriptor desc = new HTableDescriptor(tableName);
+    desc.addFamily(new HColumnDescriptor("f"));
+    admin.createTable(desc);
+    //wait for created table to be assigned
+    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
+      @Override
+      public boolean evaluate() throws Exception {
+        return getTableRegionMap().get(desc.getTableName()) != null;
+      }
+    });
+    ServerName targetServer =
+        ServerName.parseServerName(appInfo.getServers().iterator().next().toString());
+    AdminProtos.AdminService.BlockingInterface rs =
+      ((ClusterConnection) admin.getConnection()).getAdmin(targetServer);
+    //verify it was assigned to the right group
+    Assert.assertEquals(1, ProtobufUtil.getOnlineRegions(rs).size());
+  }
+
+  @Test
+  public void testCreateWhenRsgroupNoOnlineServers() throws Exception {
+    LOG.info("testCreateWhenRsgroupNoOnlineServers");
+
+    // set rsgroup has no online servers and test create table
+    final RSGroupInfo appInfo = addGroup("appInfo", 1);
+    Iterator<Address> iterator = appInfo.getServers().iterator();
+    List<ServerName> serversToDecommission = new ArrayList<>();
+    ServerName targetServer = ServerName.parseServerName(iterator.next().toString());
+    AdminProtos.AdminService.BlockingInterface targetRS =
+        ((ClusterConnection) admin.getConnection()).getAdmin(targetServer);
+    targetServer = ProtobufUtil.toServerName(
+        targetRS.getServerInfo(null, GetServerInfoRequest.newBuilder().build()).getServerInfo()
+            .getServerName());
+    assertTrue(master.getServerManager().getOnlineServers().containsKey(targetServer));
+    serversToDecommission.add(targetServer);
+    admin.decommissionRegionServers(serversToDecommission, true);
+    assertEquals(1, admin.listDecommissionedRegionServers().size());
+
+    final TableName tableName = TableName.valueOf(tablePrefix + "_ns", name.getMethodName());
+    admin.createNamespace(NamespaceDescriptor.create(tableName.getNamespaceAsString())
+        .addConfiguration(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP, appInfo.getName()).build());
+    final HTableDescriptor desc = new HTableDescriptor(tableName);
+    desc.addFamily(new HColumnDescriptor("f"));
+    try {
+      admin.createTable(desc);
+      fail("Shouldn't create table successfully!");
+    } catch (Exception e) {
+      LOG.debug("create table error", e);
+    }
+
+    // recommission and test create table
+    admin.recommissionRegionServer(targetServer, null);
+    assertEquals(0, admin.listDecommissionedRegionServers().size());
+    admin.createTable(desc);
+    // wait for created table to be assigned
+    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
+      @Override public boolean evaluate() throws Exception {
+        return getTableRegionMap().get(desc.getTableName()) != null;
+      }
+    });
+  }
+
+  @Test
+  public void testDefaultNamespaceCreateAndAssign() throws Exception {
+    LOG.info("testDefaultNamespaceCreateAndAssign");
+    String tableName = tablePrefix + "_testCreateAndAssign";
+    admin.modifyNamespace(NamespaceDescriptor.create("default")
+        .addConfiguration(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP, "default").build());
+    final HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(tableName));
+    desc.addFamily(new HColumnDescriptor("f"));
+    admin.createTable(desc);
+    //wait for created table to be assigned
+    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
+      @Override
+      public boolean evaluate() throws Exception {
+        return getTableRegionMap().get(desc.getTableName()) != null;
+      }
+    });
+  }
+
+  @Test
+  public void testCloneSnapshot() throws Exception {
+    byte[] FAMILY = Bytes.toBytes("test");
+    String snapshotName = tableName.getNameAsString() + "_snap";
+    TableName clonedTableName = TableName.valueOf(tableName.getNameAsString() + "_clone");
+
+    // create base table
+    TEST_UTIL.createTable(tableName, FAMILY);
+
+    // create snapshot
+    admin.snapshot(snapshotName, tableName);
+
+    // clone
+    admin.cloneSnapshot(snapshotName, clonedTableName);
+  }
+
+  @Test
+  public void testClearDeadServers() throws Exception {
+    LOG.info("testClearDeadServers");
+    final RSGroupInfo newGroup = addGroup(getGroupName(name.getMethodName()), 3);
+    NUM_DEAD_SERVERS = cluster.getClusterMetrics().getDeadServerNames().size();
+
+    ServerName targetServer = ServerName.parseServerName(
+        newGroup.getServers().iterator().next().toString());
+    AdminProtos.AdminService.BlockingInterface targetRS =
+        ((ClusterConnection) admin.getConnection()).getAdmin(targetServer);
+    try {
+      targetServer = ProtobufUtil.toServerName(targetRS.getServerInfo(null,
+          GetServerInfoRequest.newBuilder().build()).getServerInfo().getServerName());
+      //stopping may cause an exception
+      //due to the connection loss
+      targetRS.stopServer(null,
+          AdminProtos.StopServerRequest.newBuilder().setReason("Die").build());
+      NUM_DEAD_SERVERS ++;
+    } catch(Exception e) {
+    }
+    //wait for stopped regionserver to dead server list
+    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
+      @Override
+      public boolean evaluate() throws Exception {
+        return !master.getServerManager().areDeadServersInProgress()
+            && cluster.getClusterMetrics().getDeadServerNames().size() == NUM_DEAD_SERVERS;
+      }
+    });
+    assertFalse(cluster.getClusterMetrics().getLiveServerMetrics().containsKey(targetServer));
+    assertTrue(cluster.getClusterMetrics().getDeadServerNames().contains(targetServer));
+    assertTrue(newGroup.getServers().contains(targetServer.getAddress()));
+
+    //clear dead servers list
+    List<ServerName> notClearedServers = admin.clearDeadServers(Lists.newArrayList(targetServer));
+    assertEquals(0, notClearedServers.size());
+
+    Set<Address> newGroupServers = rsGroupAdmin.getRSGroupInfo(newGroup.getName()).getServers();
+    assertFalse(newGroupServers.contains(targetServer.getAddress()));
+    assertEquals(2, newGroupServers.size());
+  }
+
+  @Test
+  public void testClearNotProcessedDeadServer() throws Exception {
+    LOG.info("testClearNotProcessedDeadServer");
+    NUM_DEAD_SERVERS = cluster.getClusterMetrics().getDeadServerNames().size();
+    RSGroupInfo appInfo = addGroup("deadServerGroup", 1);
+    ServerName targetServer =
+        ServerName.parseServerName(appInfo.getServers().iterator().next().toString());
+    AdminProtos.AdminService.BlockingInterface targetRS =
+        ((ClusterConnection) admin.getConnection()).getAdmin(targetServer);
+    try {
+      targetServer = ProtobufUtil.toServerName(targetRS.getServerInfo(null,
+          AdminProtos.GetServerInfoRequest.newBuilder().build()).getServerInfo().getServerName());
+      //stopping may cause an exception
+      //due to the connection loss
+      targetRS.stopServer(null,
+          AdminProtos.StopServerRequest.newBuilder().setReason("Die").build());
+      NUM_DEAD_SERVERS ++;
+    } catch(Exception e) {
+    }
+    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
+      @Override
+      public boolean evaluate() throws Exception {
+        return cluster.getClusterMetrics().getDeadServerNames().size() == NUM_DEAD_SERVERS;
+      }
+    });
+    List<ServerName> notClearedServers =
+        admin.clearDeadServers(Lists.newArrayList(targetServer));
+    assertEquals(1, notClearedServers.size());
+  }
+
+  @Test
+  public void testRSGroupsWithHBaseQuota() throws Exception {
+    TEST_UTIL.getConfiguration().setBoolean(QuotaUtil.QUOTA_CONF_KEY, true);
+    restartHBaseCluster();
+    try {
+      TEST_UTIL.waitFor(90000, new Waiter.Predicate<Exception>() {
+        @Override
+        public boolean evaluate() throws Exception {
+          return admin.isTableAvailable(QuotaTableUtil.QUOTA_TABLE_NAME);
+        }
+      });
+    } finally {
+      TEST_UTIL.getConfiguration().setBoolean(QuotaUtil.QUOTA_CONF_KEY, false);
+      restartHBaseCluster();
+    }
+  }
+
+  private void restartHBaseCluster() throws Exception {
+    LOG.info("\n\nShutting down cluster");
+    TEST_UTIL.shutdownMiniHBaseCluster();
+    LOG.info("\n\nSleeping a bit");
+    Thread.sleep(2000);
+    TEST_UTIL.restartHBaseCluster(NUM_SLAVES_BASE - 1);
+    initialize();
+  }
+}

http://git-wip-us.apache.org/repos/asf/hbase/blob/e42741e0/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsKillRS.java
----------------------------------------------------------------------
diff --git a/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsKillRS.java b/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsKillRS.java
new file mode 100644
index 0000000..bce4cc9
--- /dev/null
+++ b/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsKillRS.java
@@ -0,0 +1,149 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.hbase.rsgroup;
+
+import static org.junit.Assert.assertFalse;
+
+import java.util.Set;
+
+import org.apache.hadoop.hbase.HBaseClassTestRule;
+import org.apache.hadoop.hbase.HColumnDescriptor;
+import org.apache.hadoop.hbase.HTableDescriptor;
+import org.apache.hadoop.hbase.NamespaceDescriptor;
+import org.apache.hadoop.hbase.ServerName;
+import org.apache.hadoop.hbase.TableName;
+import org.apache.hadoop.hbase.Waiter;
+import org.apache.hadoop.hbase.client.ClusterConnection;
+import org.apache.hadoop.hbase.client.RegionInfo;
+import org.apache.hadoop.hbase.net.Address;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
+import org.apache.hadoop.hbase.shaded.protobuf.generated.AdminProtos;
+import org.apache.hadoop.hbase.testclassification.MediumTests;
+import org.apache.hbase.thirdparty.com.google.common.collect.Sets;
+
+@Category({MediumTests.class})
+public class TestRSGroupsKillRS extends TestRSGroupsBase {
+
+  @ClassRule
+  public static final HBaseClassTestRule CLASS_RULE =
+      HBaseClassTestRule.forClass(TestRSGroupsKillRS.class);
+
+  protected static final Logger LOG = LoggerFactory.getLogger(TestRSGroupsKillRS.class);
+
+  @BeforeClass
+  public static void setUp() throws Exception {
+    setUpTestBeforeClass();
+  }
+
+  @AfterClass
+  public static void tearDown() throws Exception {
+    tearDownAfterClass();
+  }
+
+  @Before
+  public void beforeMethod() throws Exception {
+    setUpBeforeMethod();
+  }
+
+  @After
+  public void afterMethod() throws Exception {
+    tearDownAfterMethod();
+  }
+
+  @Test
+  public void testKillRS() throws Exception {
+    RSGroupInfo appInfo = addGroup("appInfo", 1);
+
+    final TableName tableName = TableName.valueOf(tablePrefix+"_ns", name.getMethodName());
+    admin.createNamespace(
+        NamespaceDescriptor.create(tableName.getNamespaceAsString())
+            .addConfiguration(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP, appInfo.getName()).build());
+    final HTableDescriptor desc = new HTableDescriptor(tableName);
+    desc.addFamily(new HColumnDescriptor("f"));
+    admin.createTable(desc);
+    //wait for created table to be assigned
+    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
+      @Override
+      public boolean evaluate() throws Exception {
+        return getTableRegionMap().get(desc.getTableName()) != null;
+      }
+    });
+
+    ServerName targetServer = ServerName.parseServerName(
+        appInfo.getServers().iterator().next().toString());
+    AdminProtos.AdminService.BlockingInterface targetRS =
+      ((ClusterConnection) admin.getConnection()).getAdmin(targetServer);
+    RegionInfo targetRegion = ProtobufUtil.getOnlineRegions(targetRS).get(0);
+    Assert.assertEquals(1, ProtobufUtil.getOnlineRegions(targetRS).size());
+
+    try {
+      //stopping may cause an exception
+      //due to the connection loss
+      targetRS.stopServer(null,
+          AdminProtos.StopServerRequest.newBuilder().setReason("Die").build());
+    } catch(Exception e) {
+    }
+    assertFalse(cluster.getClusterMetrics().getLiveServerMetrics().containsKey(targetServer));
+
+    //wait for created table to be assigned
+    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
+      @Override
+      public boolean evaluate() throws Exception {
+        return cluster.getClusterMetrics().getRegionStatesInTransition().isEmpty();
+      }
+    });
+    Set<Address> newServers = Sets.newHashSet();
+    newServers.add(
+        rsGroupAdmin.getRSGroupInfo(RSGroupInfo.DEFAULT_GROUP).getServers().iterator().next());
+    rsGroupAdmin.moveServers(newServers, appInfo.getName());
+
+    //Make sure all the table's regions get reassigned
+    //disabling the table guarantees no conflicting assign/unassign (ie SSH) happens
+    admin.disableTable(tableName);
+    admin.enableTable(tableName);
+
+    //wait for region to be assigned
+    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
+      @Override
+      public boolean evaluate() throws Exception {
+        return cluster.getClusterMetrics().getRegionStatesInTransition().isEmpty();
+      }
+    });
+
+    targetServer = ServerName.parseServerName(
+        newServers.iterator().next().toString());
+    targetRS =
+      ((ClusterConnection) admin.getConnection()).getAdmin(targetServer);
+    Assert.assertEquals(1, ProtobufUtil.getOnlineRegions(targetRS).size());
+    Assert.assertEquals(tableName,
+        ProtobufUtil.getOnlineRegions(targetRS).get(0).getTable());
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/hbase/blob/e42741e0/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsOfflineMode.java
----------------------------------------------------------------------
diff --git a/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsOfflineMode.java b/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsOfflineMode.java
index 1d5881e..b93de57 100644
--- a/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsOfflineMode.java
+++ b/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsOfflineMode.java
@@ -36,6 +36,7 @@ import org.apache.hadoop.hbase.master.ServerManager;
 import org.apache.hadoop.hbase.regionserver.HRegionServer;
 import org.apache.hadoop.hbase.testclassification.MediumTests;
 import org.apache.hadoop.hbase.util.Bytes;
+
 import org.junit.AfterClass;
 import org.junit.Assert;
 import org.junit.BeforeClass;

http://git-wip-us.apache.org/repos/asf/hbase/blob/e42741e0/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsWithACL.java
----------------------------------------------------------------------
diff --git a/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsWithACL.java b/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsWithACL.java
index a63626d..b6f6463 100644
--- a/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsWithACL.java
+++ b/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsWithACL.java
@@ -41,6 +41,7 @@ import org.apache.hadoop.hbase.security.access.TableAuthManager;
 import org.apache.hadoop.hbase.testclassification.MediumTests;
 import org.apache.hadoop.hbase.testclassification.SecurityTests;
 import org.apache.hadoop.hbase.util.Bytes;
+
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.ClassRule;
@@ -177,9 +178,10 @@ public class TestRSGroupsWithACL extends SecureTestUtil{
     try {
       assertEquals(4, AccessControlClient.getUserPermissions(systemUserConnection,
           TEST_TABLE.toString()).size());
+    } catch (AssertionError e) {
+      fail(e.getMessage());
     } catch (Throwable e) {
       LOG.error("error during call of AccessControlClient.getUserPermissions. ", e);
-      fail("error during call of AccessControlClient.getUserPermissions.");
     }
   }