HBASE-14212 Add IT test for procedure-v2-based namespace DDL (Stephen Yuan Jiang)

This commit is contained in:
Stephen Yuan Jiang 2015-09-25 16:23:48 -07:00
parent eeefc3d589
commit daccb1c0c2

View File

@ -58,13 +58,19 @@ import org.junit.experimental.categories.Category;
* <li>DeleteTableAction</li>
* <li>AddRowAction</li>
* </ul>
* Actions performing DDL operations:
* Actions performing column family DDL operations:
* <ul>
* <li>AddColumnFamilyAction</li>
* <li>AlterColumnFamilyVersionsAction</li>
* <li>AlterColumnFamilyEncodingAction</li>
* <li>DeleteColumnFamilyAction</li>
* </ul>
* Actions performing namespace DDL operations:
* <ul>
* <li>AddNamespaceAction</li>
* <li>AlterNamespaceAction</li>
* <li>DeleteNamespaceAction</li>
* </ul>
* <br/>
*
* The threads run for a period of time (default 20 minutes) then are stopped at the end of
@ -115,6 +121,9 @@ public class IntegrationTestDDLMasterFailover extends IntegrationTestBase {
protected int numThreads, numRegions;
ConcurrentHashMap<String, NamespaceDescriptor> namespaceMap =
new ConcurrentHashMap<String, NamespaceDescriptor>();
ConcurrentHashMap<TableName, HTableDescriptor> enabledTables =
new ConcurrentHashMap<TableName, HTableDescriptor>();
@ -140,6 +149,11 @@ public class IntegrationTestDDLMasterFailover extends IntegrationTestBase {
admin.disableTables("ittable-\\d+");
admin.deleteTables("ittable-\\d+");
}
enabledTables.clear();
disabledTables.clear();
deletedTables.clear();
namespaceMap.clear();
Connection connection = getConnection();
connection.close();
super.cleanUpCluster();
@ -165,6 +179,23 @@ public class IntegrationTestDDLMasterFailover extends IntegrationTestBase {
return connection;
}
protected void verifyNamespaces() throws IOException{
Connection connection = getConnection();
Admin admin = connection.getAdmin();
// iterating concurrent map
for (String nsName : namespaceMap.keySet()){
try {
Assert.assertTrue(
"Namespace: " + nsName + " in namespaceMap does not exist",
admin.getNamespaceDescriptor(nsName) != null);
} catch (NamespaceNotFoundException nsnfe) {
Assert.fail(
"Namespace: " + nsName + " in namespaceMap does not exist: " + nsnfe.getMessage());
}
}
admin.close();
}
protected void verifyTables() throws IOException{
Connection connection = getConnection();
Admin admin = connection.getAdmin();
@ -201,6 +232,148 @@ public class IntegrationTestDDLMasterFailover extends IntegrationTestBase {
abstract void perform() throws IOException;
}
private abstract class NamespaceAction extends MasterAction {
final String nsTestConfigKey = "hbase.namespace.testKey";
// NamespaceAction has implemented selectNamespace() shared by multiple namespace Actions
protected NamespaceDescriptor selectNamespace(
ConcurrentHashMap<String, NamespaceDescriptor> namespaceMap) {
// randomly select namespace from namespaceMap
if (namespaceMap.isEmpty()) {
return null;
}
// synchronization to prevent removal from multiple threads
synchronized (namespaceMap) {
ArrayList<String> namespaceList = new ArrayList<String>(namespaceMap.keySet());
String randomKey = namespaceList.get(RandomUtils.nextInt(namespaceList.size()));
NamespaceDescriptor randomNsd = namespaceMap.get(randomKey);
// remove from namespaceMap
namespaceMap.remove(randomKey);
return randomNsd;
}
}
}
private class CreateNamespaceAction extends NamespaceAction {
@Override
void perform() throws IOException {
Admin admin = connection.getAdmin();
try {
NamespaceDescriptor nsd;
while (true) {
nsd = createNamespaceDesc();
try {
if (admin.getNamespaceDescriptor(nsd.getName()) != null) {
// the namespace has already existed.
continue;
} else {
// currently, the code never return null - always throws exception if
// namespace is not found - this just a defensive programming to make
// sure null situation is handled in case the method changes in the
// future.
break;
}
} catch (NamespaceNotFoundException nsnfe) {
// This is expected for a random generated NamespaceDescriptor
break;
}
}
LOG.info("Creating namespace:" + nsd);
admin.createNamespace(nsd);
NamespaceDescriptor freshNamespaceDesc = admin.getNamespaceDescriptor(nsd.getName());
Assert.assertTrue("Namespace: " + nsd + " was not created", freshNamespaceDesc != null);
LOG.info("Created namespace:" + freshNamespaceDesc);
namespaceMap.put(nsd.getName(), freshNamespaceDesc);
} catch (Exception e){
LOG.warn("Caught exception in action: " + this.getClass());
throw e;
} finally {
admin.close();
}
verifyNamespaces();
}
private NamespaceDescriptor createNamespaceDesc() {
String namespaceName = "itnamespace" + String.format("%010d",
RandomUtils.nextInt(Integer.MAX_VALUE));
NamespaceDescriptor nsd = NamespaceDescriptor.create(namespaceName).build();
nsd.setConfiguration(
nsTestConfigKey,
String.format("%010d", RandomUtils.nextInt(Integer.MAX_VALUE)));
return nsd;
}
}
private class ModifyNamespaceAction extends NamespaceAction {
@Override
void perform() throws IOException {
NamespaceDescriptor selected = selectNamespace(namespaceMap);
if (selected == null) {
return;
}
Admin admin = connection.getAdmin();
try {
String namespaceName = selected.getName();
LOG.info("Modifying namespace :" + selected);
NamespaceDescriptor modifiedNsd = NamespaceDescriptor.create(namespaceName).build();
String nsValueNew;
do {
nsValueNew = String.format("%010d", RandomUtils.nextInt(Integer.MAX_VALUE));
} while (selected.getConfigurationValue(nsTestConfigKey).equals(nsValueNew));
modifiedNsd.setConfiguration(nsTestConfigKey, nsValueNew);
admin.modifyNamespace(modifiedNsd);
NamespaceDescriptor freshNamespaceDesc = admin.getNamespaceDescriptor(namespaceName);
Assert.assertTrue(
"Namespace: " + selected + " was not modified",
freshNamespaceDesc.getConfigurationValue(nsTestConfigKey).equals(nsValueNew));
LOG.info("Modified namespace :" + freshNamespaceDesc);
namespaceMap.put(namespaceName, freshNamespaceDesc);
} catch (Exception e){
LOG.warn("Caught exception in action: " + this.getClass());
throw e;
} finally {
admin.close();
}
verifyNamespaces();
}
}
private class DeleteNamespaceAction extends NamespaceAction {
@Override
void perform() throws IOException {
NamespaceDescriptor selected = selectNamespace(namespaceMap);
if (selected == null) {
return;
}
Admin admin = connection.getAdmin();
try {
String namespaceName = selected.getName();
LOG.info("Deleting namespace :" + selected);
admin.deleteNamespace(namespaceName);
try {
if (admin.getNamespaceDescriptor(namespaceName) != null) {
// the namespace still exists.
Assert.assertTrue("Namespace: " + selected + " was not deleted", false);
} else {
LOG.info("Deleted namespace :" + selected);
}
} catch (NamespaceNotFoundException nsnfe) {
// This is expected result
LOG.info("Deleted namespace :" + selected);
}
} catch (Exception e){
LOG.warn("Caught exception in action: " + this.getClass());
throw e;
} finally {
admin.close();
}
verifyNamespaces();
}
}
private abstract class TableAction extends MasterAction{
// TableAction has implemented selectTable() shared by multiple table Actions
protected HTableDescriptor selectTable(ConcurrentHashMap<TableName, HTableDescriptor> tableMap)
@ -610,6 +783,9 @@ public class IntegrationTestDDLMasterFailover extends IntegrationTestBase {
}
private enum ACTION {
CREATE_NAMESPACE,
MODIFY_NAMESPACE,
DELETE_NAMESPACE,
CREATE_TABLE,
DISABLE_TABLE,
ENABLE_TABLE,
@ -637,6 +813,15 @@ public class IntegrationTestDDLMasterFailover extends IntegrationTestBase {
try {
switch (selectedAction) {
case CREATE_NAMESPACE:
new CreateNamespaceAction().perform();
break;
case MODIFY_NAMESPACE:
new ModifyNamespaceAction().perform();
break;
case DELETE_NAMESPACE:
new DeleteNamespaceAction().perform();
break;
case CREATE_TABLE:
// stop creating new tables in the later stage of the test to avoid too many empty
// tables
@ -741,6 +926,8 @@ public class IntegrationTestDDLMasterFailover extends IntegrationTestBase {
// verify
LOG.info("Verify actions of all threads succeeded");
checkException(workers);
LOG.info("Verify namespaces");
verifyNamespaces();
LOG.info("Verify states of all tables");
verifyTables();