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.rsgroup;
019
020import static org.junit.jupiter.api.Assertions.assertEquals;
021import static org.junit.jupiter.api.Assertions.assertFalse;
022import static org.junit.jupiter.api.Assertions.assertNotNull;
023import static org.junit.jupiter.api.Assertions.assertNull;
024import static org.junit.jupiter.api.Assertions.assertTrue;
025import static org.junit.jupiter.api.Assertions.fail;
026
027import java.io.IOException;
028import java.util.List;
029import java.util.Map;
030import java.util.Set;
031import org.apache.hadoop.hbase.NamespaceDescriptor;
032import org.apache.hadoop.hbase.ServerName;
033import org.apache.hadoop.hbase.TableExistsException;
034import org.apache.hadoop.hbase.TableName;
035import org.apache.hadoop.hbase.TableNotFoundException;
036import org.apache.hadoop.hbase.Waiter;
037import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor;
038import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
039import org.apache.hadoop.hbase.client.TableDescriptor;
040import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
041import org.apache.hadoop.hbase.constraint.ConstraintException;
042import org.apache.hadoop.hbase.master.TableNamespaceManager;
043import org.apache.hadoop.hbase.net.Address;
044import org.apache.hadoop.hbase.testclassification.MediumTests;
045import org.apache.hadoop.hbase.testclassification.RSGroupTests;
046import org.apache.hadoop.hbase.util.Bytes;
047import org.junit.jupiter.api.AfterAll;
048import org.junit.jupiter.api.AfterEach;
049import org.junit.jupiter.api.BeforeAll;
050import org.junit.jupiter.api.BeforeEach;
051import org.junit.jupiter.api.Tag;
052import org.junit.jupiter.api.Test;
053import org.junit.jupiter.api.TestInfo;
054import org.slf4j.Logger;
055import org.slf4j.LoggerFactory;
056
057import org.apache.hbase.thirdparty.com.google.common.collect.Sets;
058
059@Tag(RSGroupTests.TAG)
060@Tag(MediumTests.TAG)
061public class TestRSGroupsAdmin1 extends TestRSGroupsBase {
062
063  private static final Logger LOG = LoggerFactory.getLogger(TestRSGroupsAdmin1.class);
064
065  @BeforeAll
066  public static void setUp() throws Exception {
067    setUpTestBeforeClass();
068  }
069
070  @AfterAll
071  public static void tearDown() throws Exception {
072    tearDownAfterClass();
073  }
074
075  @BeforeEach
076  public void beforeMethod(TestInfo testInfo) throws Exception {
077    setUpBeforeMethod(testInfo);
078  }
079
080  @AfterEach
081  public void afterMethod() throws Exception {
082    tearDownAfterMethod();
083  }
084
085  @Test
086  public void testValidGroupNames() throws IOException {
087    String[] badNames = { "foo*", "foo@", "-" };
088    String[] goodNames = { "foo_123" };
089
090    for (String entry : badNames) {
091      try {
092        ADMIN.addRSGroup(entry);
093        fail("Expected a constraint exception for: " + entry);
094      } catch (ConstraintException ex) {
095        // expected
096      }
097    }
098
099    for (String entry : goodNames) {
100      ADMIN.addRSGroup(entry);
101    }
102  }
103
104  @Test
105  public void testBogusArgs() throws Exception {
106    assertNull(ADMIN.getRSGroup(TableName.valueOf("nonexistent")));
107    assertNull(ADMIN.getRSGroup(Address.fromParts("bogus", 123)));
108    assertNull(ADMIN.getRSGroup("bogus"));
109
110    try {
111      ADMIN.removeRSGroup("bogus");
112      fail("Expected removing bogus group to fail");
113    } catch (ConstraintException ex) {
114      // expected
115    }
116
117    try {
118      ADMIN.setRSGroup(Sets.newHashSet(TableName.valueOf("bogustable")), "bogus");
119      fail("Expected set table to bogus group fail");
120    } catch (ConstraintException | TableNotFoundException ex) {
121      // expected
122    }
123
124    try {
125      ADMIN.moveServersToRSGroup(Sets.newHashSet(Address.fromParts("bogus", 123)), "bogus");
126      fail("Expected move with bogus group to fail");
127    } catch (ConstraintException ex) {
128      // expected
129    }
130
131    try {
132      ADMIN.balancerSwitch(true, true);
133      ADMIN.balanceRSGroup("bogus");
134      ADMIN.balancerSwitch(false, true);
135      fail("Expected move with bogus group to fail");
136    } catch (ConstraintException ex) {
137      // expected
138    }
139  }
140
141  @Test
142  public void testNamespaceConstraint() throws Exception {
143    String nsName = TABLE_PREFIX + "_foo";
144    String groupName = TABLE_PREFIX + "_foo";
145    LOG.info("testNamespaceConstraint");
146    addGroup(groupName, 1);
147    assertTrue(OBSERVER.preAddRSGroupCalled);
148    assertTrue(OBSERVER.postAddRSGroupCalled);
149
150    ADMIN.createNamespace(NamespaceDescriptor.create(nsName)
151      .addConfiguration(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP, groupName).build());
152    RSGroupInfo rsGroupInfo = ADMIN.getRSGroup(groupName);
153    ADMIN.moveServersToRSGroup(rsGroupInfo.getServers(), RSGroupInfo.DEFAULT_GROUP);
154    // test removing a referenced group
155    try {
156      ADMIN.removeRSGroup(groupName);
157      fail("Expected a constraint exception");
158    } catch (IOException ex) {
159    }
160    // test modify group
161    // changing with the same name is fine
162    ADMIN.modifyNamespace(NamespaceDescriptor.create(nsName)
163      .addConfiguration(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP, groupName).build());
164    String anotherGroup = TABLE_PREFIX + "_anotherGroup";
165    ADMIN.addRSGroup(anotherGroup);
166    // test add non-existent group
167    ADMIN.deleteNamespace(nsName);
168    ADMIN.removeRSGroup(groupName);
169    assertTrue(OBSERVER.preRemoveRSGroupCalled);
170    assertTrue(OBSERVER.postRemoveRSGroupCalled);
171    try {
172      ADMIN.createNamespace(NamespaceDescriptor.create(nsName)
173        .addConfiguration(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP, "foo").build());
174      fail("Expected a constraint exception");
175    } catch (IOException ex) {
176    }
177  }
178
179  @Test
180  public void testNamespaceConstraint2() throws Exception {
181    String nsName = TABLE_PREFIX + name.getMethodName();
182    String groupName = TABLE_PREFIX + name.getMethodName();
183    TableName tableName = TableName.valueOf(nsName, name.getMethodName());
184    addGroup(groupName, 1);
185
186    ADMIN.createNamespace(NamespaceDescriptor.create(nsName)
187      .addConfiguration(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP, groupName).build());
188
189    TEST_UTIL.createTable(tableName, "C");
190    TEST_UTIL.waitTableAvailable(tableName);
191    RSGroupInfo rsGroup = ADMIN.getRSGroup(tableName);
192    assertEquals(groupName, rsGroup.getName());
193
194    TEST_UTIL.deleteTable(tableName);
195    ADMIN.deleteNamespace(nsName);
196
197    ADMIN.moveServersToRSGroup(rsGroup.getServers(), RSGroupInfo.DEFAULT_GROUP);
198    ADMIN.removeRSGroup(groupName);
199  }
200
201  @Test
202  public void testFailRemoveGroup() throws IOException, InterruptedException {
203    int initNumGroups = ADMIN.listRSGroups().size();
204    addGroup("bar", 3);
205    TEST_UTIL.createTable(tableName, Bytes.toBytes("f"));
206    ADMIN.setRSGroup(Sets.newHashSet(tableName), "bar");
207    RSGroupInfo barGroup = ADMIN.getRSGroup("bar");
208    // group is not empty therefore it should fail
209    try {
210      ADMIN.removeRSGroup(barGroup.getName());
211      fail("Expected remove group to fail");
212    } catch (IOException e) {
213    }
214    // group cannot lose all it's servers therefore it should fail
215    try {
216      ADMIN.moveServersToRSGroup(barGroup.getServers(), RSGroupInfo.DEFAULT_GROUP);
217      fail("Expected move servers to fail");
218    } catch (IOException e) {
219    }
220
221    ADMIN.setRSGroup(Sets.newHashSet(ADMIN.listTablesInRSGroup("bar")), RSGroupInfo.DEFAULT_GROUP);
222    try {
223      ADMIN.removeRSGroup(barGroup.getName());
224      fail("Expected move servers to fail");
225    } catch (IOException e) {
226    }
227
228    ADMIN.moveServersToRSGroup(barGroup.getServers(), RSGroupInfo.DEFAULT_GROUP);
229    ADMIN.removeRSGroup(barGroup.getName());
230
231    assertEquals(initNumGroups, ADMIN.listRSGroups().size());
232  }
233
234  @Test
235  public void testMultiTableMove() throws Exception {
236    final TableName tableNameA =
237      TableName.valueOf(TABLE_PREFIX + getNameWithoutIndex(name.getMethodName()) + "A");
238    final TableName tableNameB =
239      TableName.valueOf(TABLE_PREFIX + getNameWithoutIndex(name.getMethodName()) + "B");
240    final byte[] familyNameBytes = Bytes.toBytes("f");
241    String newGroupName = getGroupName(getNameWithoutIndex(name.getMethodName()));
242    final RSGroupInfo newGroup = addGroup(newGroupName, 1);
243
244    TEST_UTIL.createTable(tableNameA, familyNameBytes);
245    TEST_UTIL.createTable(tableNameB, familyNameBytes);
246    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
247      @Override
248      public boolean evaluate() throws Exception {
249        List<String> regionsA = getTableRegionMap().get(tableNameA);
250        if (regionsA == null) {
251          return false;
252        }
253        List<String> regionsB = getTableRegionMap().get(tableNameB);
254        if (regionsB == null) {
255          return false;
256        }
257        return getTableRegionMap().get(tableNameA).size() >= 1
258          && getTableRegionMap().get(tableNameB).size() >= 1;
259      }
260    });
261
262    RSGroupInfo tableGrpA = ADMIN.getRSGroup(tableNameA);
263    assertTrue(tableGrpA.getName().equals(RSGroupInfo.DEFAULT_GROUP));
264
265    RSGroupInfo tableGrpB = ADMIN.getRSGroup(tableNameB);
266    assertTrue(tableGrpB.getName().equals(RSGroupInfo.DEFAULT_GROUP));
267    // change table's group
268    LOG.info("Moving table [" + tableNameA + "," + tableNameB + "] to " + newGroup.getName());
269    ADMIN.setRSGroup(Sets.newHashSet(tableNameA, tableNameB), newGroup.getName());
270
271    // verify group change
272    assertEquals(newGroup.getName(), ADMIN.getRSGroup(tableNameA).getName());
273
274    assertEquals(newGroup.getName(), ADMIN.getRSGroup(tableNameB).getName());
275
276    // verify tables' not exist in old group
277    Set<TableName> defaultTables =
278      Sets.newHashSet(ADMIN.listTablesInRSGroup(RSGroupInfo.DEFAULT_GROUP));
279    assertFalse(defaultTables.contains(tableNameA));
280    assertFalse(defaultTables.contains(tableNameB));
281
282    // verify tables' exist in new group
283    Set<TableName> newGroupTables = Sets.newHashSet(ADMIN.listTablesInRSGroup(newGroupName));
284    assertTrue(newGroupTables.contains(tableNameA));
285    assertTrue(newGroupTables.contains(tableNameB));
286  }
287
288  @Test
289  public void testTableMoveTruncateAndDrop() throws Exception {
290    final byte[] familyNameBytes = Bytes.toBytes("f");
291    String newGroupName = getGroupName(getNameWithoutIndex(name.getMethodName()));
292    final RSGroupInfo newGroup = addGroup(newGroupName, 2);
293
294    TEST_UTIL.createMultiRegionTable(tableName, familyNameBytes, 5);
295    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
296      @Override
297      public boolean evaluate() throws Exception {
298        List<String> regions = getTableRegionMap().get(tableName);
299        if (regions == null) {
300          return false;
301        }
302
303        return getTableRegionMap().get(tableName).size() >= 5;
304      }
305    });
306
307    RSGroupInfo tableGrp = ADMIN.getRSGroup(tableName);
308    LOG.info("got table group info is {}", tableGrp);
309    assertTrue(tableGrp.getName().equals(RSGroupInfo.DEFAULT_GROUP));
310
311    // change table's group
312    LOG.info("Moving table " + tableName + " to " + newGroup.getName());
313    ADMIN.setRSGroup(Sets.newHashSet(tableName), newGroup.getName());
314
315    // verify group change
316    assertEquals(newGroup.getName(), ADMIN.getRSGroup(tableName).getName());
317
318    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
319      @Override
320      public boolean evaluate() throws Exception {
321        Map<ServerName, List<String>> serverMap = getTableServerRegionMap().get(tableName);
322        int count = 0;
323        if (serverMap != null) {
324          for (ServerName rs : serverMap.keySet()) {
325            if (newGroup.containsServer(rs.getAddress())) {
326              count += serverMap.get(rs).size();
327            }
328          }
329        }
330        return count == 5;
331      }
332    });
333
334    // test truncate
335    ADMIN.disableTable(tableName);
336    ADMIN.truncateTable(tableName, true);
337    List<TableName> tablesInGroup = ADMIN.listTablesInRSGroup(newGroup.getName());
338    assertEquals(1, tablesInGroup.size());
339    assertEquals(tableName, tablesInGroup.get(0));
340
341    // verify removed table is removed from group
342    TEST_UTIL.deleteTable(tableName);
343    assertEquals(0, ADMIN.listTablesInRSGroup(newGroup.getName()).size());
344  }
345
346  @Test
347  public void testDisabledTableMove() throws Exception {
348    final byte[] familyNameBytes = Bytes.toBytes("f");
349    String newGroupName = getGroupName(getNameWithoutIndex(name.getMethodName()));
350    final RSGroupInfo newGroup = addGroup(newGroupName, 2);
351
352    TEST_UTIL.createMultiRegionTable(tableName, familyNameBytes, 5);
353    TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
354      @Override
355      public boolean evaluate() throws Exception {
356        List<String> regions = getTableRegionMap().get(tableName);
357        if (regions == null) {
358          return false;
359        }
360        return getTableRegionMap().get(tableName).size() >= 5;
361      }
362    });
363
364    RSGroupInfo tableGrp = ADMIN.getRSGroup(tableName);
365    assertTrue(tableGrp.getName().equals(RSGroupInfo.DEFAULT_GROUP));
366
367    // test disable table
368    ADMIN.disableTable(tableName);
369
370    // change table's group
371    LOG.info("Moving table " + tableName + " to " + newGroup.getName());
372    ADMIN.setRSGroup(Sets.newHashSet(tableName), newGroup.getName());
373
374    // verify group change
375    assertEquals(newGroup.getName(), ADMIN.getRSGroup(tableName).getName());
376  }
377
378  @Test
379  public void testNonExistentTableMove() throws Exception {
380    TableName tableName =
381      TableName.valueOf(TABLE_PREFIX + getNameWithoutIndex(name.getMethodName()));
382    RSGroupInfo tableGrp = ADMIN.getRSGroup(tableName);
383    assertNull(tableGrp);
384
385    // test if table exists already.
386    boolean exist = ADMIN.tableExists(tableName);
387    assertFalse(exist);
388
389    LOG.info("Moving table " + tableName + " to " + RSGroupInfo.DEFAULT_GROUP);
390    try {
391      ADMIN.setRSGroup(Sets.newHashSet(tableName), RSGroupInfo.DEFAULT_GROUP);
392      fail("Table " + tableName + " shouldn't have been successfully moved.");
393    } catch (IOException ex) {
394      assertTrue(ex instanceof TableNotFoundException);
395    }
396
397    try {
398      ADMIN.setRSGroup(Sets.newHashSet(tableName), RSGroupInfo.DEFAULT_GROUP);
399      ADMIN.moveServersToRSGroup(Sets.newHashSet(Address.fromParts("bogus", 123)),
400        RSGroupInfo.DEFAULT_GROUP);
401      fail("Table " + tableName + " shouldn't have been successfully moved.");
402    } catch (IOException ex) {
403      assertTrue(ex instanceof TableNotFoundException);
404    }
405    // verify group change
406    assertNull(ADMIN.getRSGroup(tableName));
407  }
408
409  @Test
410  public void testRSGroupListDoesNotContainFailedTableCreation() throws Exception {
411    toggleQuotaCheckAndRestartMiniCluster(true);
412    String nsp = "np1";
413    NamespaceDescriptor nspDesc =
414      NamespaceDescriptor.create(nsp).addConfiguration(TableNamespaceManager.KEY_MAX_REGIONS, "5")
415        .addConfiguration(TableNamespaceManager.KEY_MAX_TABLES, "2").build();
416    ADMIN.createNamespace(nspDesc);
417    assertEquals(3, ADMIN.listNamespaceDescriptors().length);
418    ColumnFamilyDescriptor fam1 = ColumnFamilyDescriptorBuilder.of("fam1");
419    TableDescriptor tableDescOne = TableDescriptorBuilder
420      .newBuilder(TableName.valueOf(nsp + TableName.NAMESPACE_DELIM + "table1"))
421      .setColumnFamily(fam1).build();
422    ADMIN.createTable(tableDescOne);
423
424    TableDescriptor tableDescTwo = TableDescriptorBuilder
425      .newBuilder(TableName.valueOf(nsp + TableName.NAMESPACE_DELIM + "table2"))
426      .setColumnFamily(fam1).build();
427    boolean constraintViolated = false;
428
429    try {
430      ADMIN.createTable(tableDescTwo, Bytes.toBytes("AAA"), Bytes.toBytes("ZZZ"), 6);
431      fail("Creation table should fail because of quota violation.");
432    } catch (Exception exp) {
433      assertTrue(exp instanceof IOException);
434      constraintViolated = true;
435    } finally {
436      assertTrue(constraintViolated,
437        "Constraint not violated for table " + tableDescTwo.getTableName());
438    }
439    List<RSGroupInfo> rsGroupInfoList = ADMIN.listRSGroups();
440    boolean foundTable2 = false;
441    boolean foundTable1 = false;
442    for (int i = 0; i < rsGroupInfoList.size(); i++) {
443      Set<TableName> tables =
444        Sets.newHashSet(ADMIN.listTablesInRSGroup(rsGroupInfoList.get(i).getName()));
445      if (tables.contains(tableDescTwo.getTableName())) {
446        foundTable2 = true;
447      }
448      if (tables.contains(tableDescOne.getTableName())) {
449        foundTable1 = true;
450      }
451    }
452    assertFalse(foundTable2, "Found table2 in rsgroup list.");
453    assertTrue(foundTable1, "Did not find table1 in rsgroup list");
454
455    TEST_UTIL.deleteTable(tableDescOne.getTableName());
456    ADMIN.deleteNamespace(nspDesc.getName());
457    toggleQuotaCheckAndRestartMiniCluster(false);
458
459  }
460
461  @Test
462  public void testNotMoveTableToNullRSGroupWhenCreatingExistingTable() throws Exception {
463    // Trigger
464    TableName tn1 = TableName.valueOf("t1");
465    TEST_UTIL.createTable(tn1, "cf1");
466    try {
467      // Create an existing table to trigger HBASE-21866
468      TEST_UTIL.createTable(tn1, "cf1");
469    } catch (TableExistsException teex) {
470      // Ignore
471    }
472
473    // Wait then verify
474    // Could not verify until the rollback of CreateTableProcedure is done
475    // (that is, the coprocessor finishes its work),
476    // or the table is still in the "default" rsgroup even though HBASE-21866
477    // is not fixed.
478    TEST_UTIL.waitFor(5000, new Waiter.Predicate<Exception>() {
479      @Override
480      public boolean evaluate() throws Exception {
481        return MASTER.getMasterProcedureExecutor().getActiveExecutorCount() == 0;
482      }
483    });
484    Set<TableName> tables = Sets.newHashSet(ADMIN.listTablesInRSGroup(RSGroupInfo.DEFAULT_GROUP));
485    assertTrue(tables.contains(tn1), "Table 't1' must be in 'default' rsgroup");
486
487    // Cleanup
488    TEST_UTIL.deleteTable(tn1);
489  }
490
491  @Test
492  public void testRenameRSGroup() throws Exception {
493    // Add rsgroup, and assign 2 servers and a table to it.
494    RSGroupInfo oldgroup = addGroup("oldgroup", 2);
495    TableName tb1 = TableName.valueOf("testRename");
496    TEST_UTIL.createTable(tb1, "tr");
497    ADMIN.setRSGroup(Sets.newHashSet(tb1), oldgroup.getName());
498    TEST_UTIL.waitFor(1000,
499      (Waiter.Predicate<Exception>) () -> ADMIN.getRSGroup(tb1).getServers().size() == 2);
500    oldgroup = ADMIN.getRSGroup(oldgroup.getName());
501    assertEquals(2, oldgroup.getServers().size());
502    assertEquals(oldgroup.getName(), ADMIN.getRSGroup(tb1).getName());
503
504    // Another rsgroup and table for verification
505    // that they are unchanged during we're renaming oldgroup.
506    RSGroupInfo normal = addGroup("normal", 1);
507    TableName tb2 = TableName.valueOf("unmovedTable");
508    TEST_UTIL.createTable(tb2, "ut");
509    ADMIN.setRSGroup(Sets.newHashSet(tb2), normal.getName());
510    TEST_UTIL.waitFor(1000,
511      (Waiter.Predicate<Exception>) () -> ADMIN.getRSGroup(tb2).getServers().size() == 1);
512    normal = ADMIN.getRSGroup(normal.getName());
513    assertEquals(1, normal.getServers().size());
514    assertEquals(normal.getName(), ADMIN.getRSGroup(tb2).getName());
515
516    // Rename rsgroup
517    ADMIN.renameRSGroup(oldgroup.getName(), "newgroup");
518    Set<Address> servers = oldgroup.getServers();
519    RSGroupInfo newgroup = ADMIN.getRSGroup("newgroup");
520    assertEquals(servers.size(), newgroup.getServers().size());
521    int match = 0;
522    for (Address addr : newgroup.getServers()) {
523      if (servers.contains(addr)) {
524        match++;
525      }
526    }
527    assertEquals(servers.size(), match);
528    assertEquals(newgroup.getName(), ADMIN.getRSGroup(tb1).getName());
529    assertEquals(normal.getName(), ADMIN.getRSGroup(tb2).getName());
530  }
531
532  @Test
533  public void testRenameRSGroupConstraints() throws Exception {
534    // Add RSGroup, and assign 2 servers and a table to it.
535    String oldGroupName = "oldGroup";
536    RSGroupInfo oldGroup = addGroup(oldGroupName, 2);
537    oldGroup = ADMIN.getRSGroup(oldGroup.getName());
538    assertNotNull(oldGroup);
539    assertEquals(2, oldGroup.getServers().size());
540
541    // Add another RSGroup
542    String anotherRSGroupName = "anotherRSGroup";
543    RSGroupInfo anotherGroup = addGroup(anotherRSGroupName, 1);
544    anotherGroup = ADMIN.getRSGroup(anotherGroup.getName());
545    assertNotNull(anotherGroup);
546    assertEquals(1, anotherGroup.getServers().size());
547
548    // Rename a non existing RSGroup
549    try {
550      ADMIN.renameRSGroup("nonExistingRSGroup", "newRSGroup1");
551      fail("ConstraintException was expected.");
552    } catch (ConstraintException e) {
553      assertTrue(e.getMessage().contains("does not exist"));
554    }
555
556    // Rename to existing group
557    try {
558      ADMIN.renameRSGroup(oldGroup.getName(), anotherRSGroupName);
559      fail("ConstraintException was expected.");
560    } catch (ConstraintException e) {
561      assertTrue(e.getMessage().contains("Group already exists"));
562    }
563
564    // Rename default RSGroup
565    try {
566      ADMIN.renameRSGroup(RSGroupInfo.DEFAULT_GROUP, "newRSGroup2");
567      fail("ConstraintException was expected.");
568    } catch (ConstraintException e) {
569      // Do nothing
570    }
571
572    // Rename to default RSGroup
573    try {
574      ADMIN.renameRSGroup(oldGroup.getName(), RSGroupInfo.DEFAULT_GROUP);
575      fail("ConstraintException was expected.");
576    } catch (ConstraintException e) {
577      assertTrue(e.getMessage().contains("Group already exists"));
578    }
579
580  }
581
582  @Test
583  public void testTableConstraint() throws Exception {
584    String prefix = name.getMethodName();
585    String ns = prefix + "_ns";
586    TableName tableName = TableName.valueOf(ns + ":" + "t");
587    String nsGroup = prefix + "_nsg";
588    String tableGroup = prefix + "_tg";
589    addGroup(nsGroup, 1);
590    addGroup(tableGroup, 1);
591    ADMIN.createNamespace(NamespaceDescriptor.create(ns).build());
592    TEST_UTIL.createTable(tableName, "C");
593    TEST_UTIL.waitTableAvailable(tableName);
594    assertEquals(ADMIN.getRSGroup(tableName).getName(), RSGroupInfo.DEFAULT_GROUP);
595    // set table's rsgroup
596    TableDescriptor td = TableDescriptorBuilder.newBuilder(ADMIN.getDescriptor(tableName))
597      .setRegionServerGroup(tableGroup).build();
598    ADMIN.modifyTable(td);
599    TEST_UTIL.waitUntilNoRegionsInTransition();
600    assertEquals(ADMIN.getRSGroup(tableName).getName(), tableGroup);
601    // set namespace's rsgroup
602    NamespaceDescriptor nd = NamespaceDescriptor.create(ADMIN.getNamespaceDescriptor(ns))
603      .addConfiguration(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP, nsGroup).build();
604    ADMIN.modifyNamespace(nd);
605    assertEquals(ADMIN.getRSGroup(tableName).getName(), tableGroup);
606    // clear table's rsgroup
607    td = TableDescriptorBuilder.newBuilder(ADMIN.getDescriptor(tableName))
608      .setRegionServerGroup(null).build();
609    ADMIN.modifyTable(td);
610    TEST_UTIL.waitUntilNoRegionsInTransition();
611    assertEquals(ADMIN.getRSGroup(tableName).getName(), nsGroup);
612
613    TEST_UTIL.deleteTable(tableName);
614    ADMIN.deleteNamespace(ns);
615  }
616}