You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by st...@apache.org on 2013/09/17 07:45:04 UTC

svn commit: r1523907 - in /hbase/branches/0.96: hbase-client/src/main/java/org/apache/hadoop/hbase/ hbase-server/src/main/java/org/apache/hadoop/hbase/master/ hbase-server/src/test/java/org/apache/hadoop/hbase/

Author: stack
Date: Tue Sep 17 05:45:03 2013
New Revision: 1523907

URL: http://svn.apache.org/r1523907
Log:
HBASE-9510 Namespace operations should throw clean exceptions

Added:
    hbase/branches/0.96/hbase-client/src/main/java/org/apache/hadoop/hbase/NamespaceExistException.java
    hbase/branches/0.96/hbase-client/src/main/java/org/apache/hadoop/hbase/NamespaceNotFoundException.java
Modified:
    hbase/branches/0.96/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java
    hbase/branches/0.96/hbase-server/src/main/java/org/apache/hadoop/hbase/master/TableNamespaceManager.java
    hbase/branches/0.96/hbase-server/src/test/java/org/apache/hadoop/hbase/TestNamespace.java

Added: hbase/branches/0.96/hbase-client/src/main/java/org/apache/hadoop/hbase/NamespaceExistException.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.96/hbase-client/src/main/java/org/apache/hadoop/hbase/NamespaceExistException.java?rev=1523907&view=auto
==============================================================================
--- hbase/branches/0.96/hbase-client/src/main/java/org/apache/hadoop/hbase/NamespaceExistException.java (added)
+++ hbase/branches/0.96/hbase-client/src/main/java/org/apache/hadoop/hbase/NamespaceExistException.java Tue Sep 17 05:45:03 2013
@@ -0,0 +1,39 @@
+/**
+ * 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;
+
+import org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.classification.InterfaceStability;
+
+/**
+ * Thrown when a namespace exists but should not
+ */
+@InterfaceAudience.Public
+@InterfaceStability.Stable
+public class NamespaceExistException extends DoNotRetryIOException {
+
+  private static final long serialVersionUID = -1582357514338825412L;
+
+  public NamespaceExistException() {
+  }
+
+  public NamespaceExistException(String namespace) {
+    super(namespace);
+  }
+}

Added: hbase/branches/0.96/hbase-client/src/main/java/org/apache/hadoop/hbase/NamespaceNotFoundException.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.96/hbase-client/src/main/java/org/apache/hadoop/hbase/NamespaceNotFoundException.java?rev=1523907&view=auto
==============================================================================
--- hbase/branches/0.96/hbase-client/src/main/java/org/apache/hadoop/hbase/NamespaceNotFoundException.java (added)
+++ hbase/branches/0.96/hbase-client/src/main/java/org/apache/hadoop/hbase/NamespaceNotFoundException.java Tue Sep 17 05:45:03 2013
@@ -0,0 +1,39 @@
+/**
+ * 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;
+
+import org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.classification.InterfaceStability;
+
+/**
+ * Thrown when a namespace can not be located
+ */
+@InterfaceAudience.Public
+@InterfaceStability.Stable
+public class NamespaceNotFoundException extends DoNotRetryIOException {
+
+  private static final long serialVersionUID = -6673607347330260324L;
+
+  public NamespaceNotFoundException() {
+  }
+
+  public NamespaceNotFoundException(String namespace) {
+    super(namespace);
+  }
+}

Modified: hbase/branches/0.96/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.96/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java?rev=1523907&r1=1523906&r2=1523907&view=diff
==============================================================================
--- hbase/branches/0.96/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java (original)
+++ hbase/branches/0.96/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java Tue Sep 17 05:45:03 2013
@@ -51,22 +51,21 @@ import org.apache.hadoop.hbase.Abortable
 import org.apache.hadoop.hbase.Chore;
 import org.apache.hadoop.hbase.ClusterId;
 import org.apache.hadoop.hbase.ClusterStatus;
-import org.apache.hadoop.hbase.TableName;
 import org.apache.hadoop.hbase.HBaseIOException;
-import org.apache.hadoop.hbase.NamespaceDescriptor;
-import org.apache.hadoop.hbase.constraint.ConstraintException;
-import org.apache.hadoop.hbase.exceptions.DeserializationException;
 import org.apache.hadoop.hbase.HColumnDescriptor;
 import org.apache.hadoop.hbase.HConstants;
 import org.apache.hadoop.hbase.HRegionInfo;
 import org.apache.hadoop.hbase.HTableDescriptor;
 import org.apache.hadoop.hbase.HealthCheckChore;
 import org.apache.hadoop.hbase.MasterNotRunningException;
+import org.apache.hadoop.hbase.NamespaceDescriptor;
+import org.apache.hadoop.hbase.NamespaceNotFoundException;
 import org.apache.hadoop.hbase.PleaseHoldException;
 import org.apache.hadoop.hbase.Server;
 import org.apache.hadoop.hbase.ServerLoad;
 import org.apache.hadoop.hbase.ServerName;
 import org.apache.hadoop.hbase.TableDescriptors;
+import org.apache.hadoop.hbase.TableName;
 import org.apache.hadoop.hbase.TableNotDisabledException;
 import org.apache.hadoop.hbase.TableNotFoundException;
 import org.apache.hadoop.hbase.UnknownRegionException;
@@ -217,8 +216,11 @@ import org.apache.hadoop.metrics.util.MB
 import org.apache.hadoop.net.DNS;
 import org.apache.zookeeper.KeeperException;
 import org.apache.zookeeper.Watcher;
+import org.apache.hadoop.hbase.exceptions.DeserializationException;
 
+import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
 import com.google.protobuf.Descriptors;
 import com.google.protobuf.Message;
 import com.google.protobuf.RpcCallback;
@@ -365,7 +367,7 @@ MasterServices, Server {
 
   /** The health check chore. */
   private HealthCheckChore healthCheckChore;
-  
+
   /**
    * is in distributedLogReplay mode. When true, SplitLogWorker directly replays WAL edits to newly
    * assigned region servers instead of creating recovered.edits files.
@@ -490,7 +492,7 @@ MasterServices, Server {
       }
     }
 
-    distributedLogReplay = this.conf.getBoolean(HConstants.DISTRIBUTED_LOG_REPLAY_KEY, 
+    distributedLogReplay = this.conf.getBoolean(HConstants.DISTRIBUTED_LOG_REPLAY_KEY,
       HConstants.DEFAULT_DISTRIBUTED_LOG_REPLAY_CONFIG);
   }
 
@@ -903,7 +905,7 @@ MasterServices, Server {
       status.setStatus("Starting namespace manager");
       initNamespace();
     }
-    
+
     if (this.cpHost != null) {
       try {
         this.cpHost.preMasterInitialization();
@@ -1362,6 +1364,7 @@ MasterServices, Server {
     return !isStopped();
   }
 
+  @Override
   public IsMasterRunningResponse isMasterRunning(RpcController c, IsMasterRunningRequest req)
   throws ServiceException {
     return IsMasterRunningResponse.newBuilder().setIsMasterRunning(isMasterRunning()).build();
@@ -1719,9 +1722,7 @@ MasterServices, Server {
     }
 
     String namespace = hTableDescriptor.getTableName().getNamespaceAsString();
-    if (getNamespaceDescriptor(namespace) == null) {
-      throw new ConstraintException("Namespace " + namespace + " does not exist");
-    }
+    getNamespaceDescriptor(namespace); // ensure namespace exists
 
     HRegionInfo[] newRegions = getHRegionInfos(hTableDescriptor, splitKeys);
     checkInitialized();
@@ -2102,6 +2103,7 @@ MasterServices, Server {
       }
     }
     Collections.sort(backupMasters, new Comparator<ServerName>() {
+      @Override
       public int compare(ServerName s1, ServerName s2) {
         return s1.getServerName().compareTo(s2.getServerName());
       }});
@@ -2209,6 +2211,7 @@ MasterServices, Server {
     this.zooKeeper.reconnectAfterExpiration();
 
     Callable<Boolean> callable = new Callable<Boolean> () {
+      @Override
       public Boolean call() throws InterruptedException,
           IOException, KeeperException {
         MonitoredTask status =
@@ -2384,6 +2387,7 @@ MasterServices, Server {
     return this.stopped;
   }
 
+  @Override
   public boolean isAborted() {
     return this.abort;
   }
@@ -2415,6 +2419,7 @@ MasterServices, Server {
    *
    * @return true if master is ready to go, false if not.
    */
+  @Override
   public boolean isInitialized() {
     return initialized;
   }
@@ -2424,6 +2429,7 @@ MasterServices, Server {
    * assignMeta to prevent processing of ServerShutdownHandler.
    * @return true if assignMeta has completed;
    */
+  @Override
   public boolean isServerShutdownHandlerEnabled() {
     return this.serverShutdownHandlerEnabled;
   }
@@ -2522,6 +2528,7 @@ MasterServices, Server {
    * @return GetTableDescriptorsResponse
    * @throws ServiceException
    */
+  @Override
   public GetTableDescriptorsResponse getTableDescriptors(
 	      RpcController controller, GetTableDescriptorsRequest req) throws ServiceException {
     List<HTableDescriptor> descriptors = new ArrayList<HTableDescriptor>();
@@ -2590,6 +2597,7 @@ MasterServices, Server {
    * @return GetTableNamesResponse
    * @throws ServiceException
    */
+  @Override
   public GetTableNamesResponse getTableNames(
         RpcController controller, GetTableNamesRequest req) throws ServiceException {
     try {
@@ -3031,6 +3039,7 @@ MasterServices, Server {
     return org.apache.commons.lang.StringUtils.isNotBlank(healthScriptLocation);
   }
 
+  @Override
   public void createNamespace(NamespaceDescriptor descriptor) throws IOException {
     TableName.isLegalNamespaceName(Bytes.toBytes(descriptor.getName()));
     if (cpHost != null) {
@@ -3045,6 +3054,7 @@ MasterServices, Server {
     }
   }
 
+  @Override
   public void modifyNamespace(NamespaceDescriptor descriptor) throws IOException {
     TableName.isLegalNamespaceName(Bytes.toBytes(descriptor.getName()));
     if (cpHost != null) {
@@ -3059,6 +3069,7 @@ MasterServices, Server {
     }
   }
 
+  @Override
   public void deleteNamespace(String name) throws IOException {
     if (cpHost != null) {
       if (cpHost.preDeleteNamespace(name)) {
@@ -3072,19 +3083,29 @@ MasterServices, Server {
     }
   }
 
+  @Override
   public NamespaceDescriptor getNamespaceDescriptor(String name) throws IOException {
-      return tableNamespaceManager.get(name);
+    NamespaceDescriptor nsd = tableNamespaceManager.get(name);
+    if (nsd == null) {
+      throw new NamespaceNotFoundException(name);
+    }
+    return nsd;
   }
 
+  @Override
   public List<NamespaceDescriptor> listNamespaceDescriptors() throws IOException {
     return Lists.newArrayList(tableNamespaceManager.list());
   }
 
+  @Override
   public List<HTableDescriptor> listTableDescriptorsByNamespace(String name) throws IOException {
+    getNamespaceDescriptor(name); // check that namespace exists
     return Lists.newArrayList(tableDescriptors.getByNamespace(name).values());
   }
 
+  @Override
   public List<TableName> listTableNamesByNamespace(String name) throws IOException {
+    getNamespaceDescriptor(name); // check that namespace exists
     List<TableName> tableNames = Lists.newArrayList();
     for (HTableDescriptor descriptor: tableDescriptors.getByNamespace(name).values()) {
       tableNames.add(descriptor.getTableName());

Modified: hbase/branches/0.96/hbase-server/src/main/java/org/apache/hadoop/hbase/master/TableNamespaceManager.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.96/hbase-server/src/main/java/org/apache/hadoop/hbase/master/TableNamespaceManager.java?rev=1523907&r1=1523906&r2=1523907&view=diff
==============================================================================
--- hbase/branches/0.96/hbase-server/src/main/java/org/apache/hadoop/hbase/master/TableNamespaceManager.java (original)
+++ hbase/branches/0.96/hbase-server/src/main/java/org/apache/hadoop/hbase/master/TableNamespaceManager.java Tue Sep 17 05:45:03 2013
@@ -33,6 +33,8 @@ import org.apache.hadoop.hbase.HConstant
 import org.apache.hadoop.hbase.HRegionInfo;
 import org.apache.hadoop.hbase.HTableDescriptor;
 import org.apache.hadoop.hbase.NamespaceDescriptor;
+import org.apache.hadoop.hbase.NamespaceExistException;
+import org.apache.hadoop.hbase.NamespaceNotFoundException;
 import org.apache.hadoop.hbase.TableName;
 import org.apache.hadoop.hbase.ZKNamespaceManager;
 import org.apache.hadoop.hbase.catalog.MetaReader;
@@ -113,14 +115,14 @@ public class TableNamespaceManager {
         nsTable = new HTable(conf, TableName.NAMESPACE_TABLE_NAME);
         zkNamespaceManager = new ZKNamespaceManager(masterServices.getZooKeeper());
         zkNamespaceManager.start();
-    
+
         if (get(nsTable, NamespaceDescriptor.DEFAULT_NAMESPACE.getName()) == null) {
           create(nsTable, NamespaceDescriptor.DEFAULT_NAMESPACE);
         }
         if (get(nsTable, NamespaceDescriptor.SYSTEM_NAMESPACE.getName()) == null) {
           create(nsTable, NamespaceDescriptor.SYSTEM_NAMESPACE);
         }
-    
+
         ResultScanner scanner = nsTable.getScanner(HTableDescriptor.NAMESPACE_FAMILY_INFO_BYTES);
         try {
           for(Result result : scanner) {
@@ -160,7 +162,7 @@ public class TableNamespaceManager {
   public synchronized void update(NamespaceDescriptor ns) throws IOException {
     HTable table = getNamespaceTable();
     if (get(table, ns.getName()) == null) {
-      throw new ConstraintException("Namespace "+ns.getName()+" does not exist");
+      throw new NamespaceNotFoundException(ns.getName());
     }
     upsert(table, ns);
   }
@@ -179,7 +181,7 @@ public class TableNamespaceManager {
 
   private void create(HTable table, NamespaceDescriptor ns) throws IOException {
     if (get(table, ns.getName()) != null) {
-      throw new ConstraintException("Namespace "+ns.getName()+" already exists");
+      throw new NamespaceExistException(ns.getName());
     }
     FileSystem fs = masterServices.getMasterFileSystem().getFileSystem();
     fs.mkdirs(FSUtils.getNamespaceDir(
@@ -203,6 +205,9 @@ public class TableNamespaceManager {
   }
 
   public synchronized void remove(String name) throws IOException {
+    if (get(name) == null) {
+      throw new NamespaceNotFoundException(name);
+    }
     if (NamespaceDescriptor.RESERVED_NAMESPACES.contains(name)) {
       throw new ConstraintException("Reserved namespace "+name+" cannot be removed.");
     }
@@ -210,7 +215,7 @@ public class TableNamespaceManager {
     try {
       tableCount = masterServices.listTableDescriptorsByNamespace(name).size();
     } catch (FileNotFoundException fnfe) {
-      throw new ConstraintException("namespace " + name + " does not exist");
+      throw new NamespaceNotFoundException(name);
     }
     if (tableCount > 0) {
       throw new ConstraintException("Only empty namespaces can be removed. " +

Modified: hbase/branches/0.96/hbase-server/src/test/java/org/apache/hadoop/hbase/TestNamespace.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.96/hbase-server/src/test/java/org/apache/hadoop/hbase/TestNamespace.java?rev=1523907&r1=1523906&r2=1523907&view=diff
==============================================================================
--- hbase/branches/0.96/hbase-server/src/test/java/org/apache/hadoop/hbase/TestNamespace.java (original)
+++ hbase/branches/0.96/hbase-server/src/test/java/org/apache/hadoop/hbase/TestNamespace.java Tue Sep 17 05:45:03 2013
@@ -18,7 +18,17 @@
  */
 package org.apache.hadoop.hbase;
 
-import com.google.common.collect.Sets;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
+import java.util.Set;
+import java.util.concurrent.Callable;
+
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.hadoop.fs.FileSystem;
@@ -33,7 +43,9 @@ import org.apache.hadoop.hbase.util.Byte
 import org.apache.hadoop.hbase.util.FSUtils;
 import org.apache.hadoop.hbase.zookeeper.ZKUtil;
 import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
+import com.google.common.collect.Sets;
 import org.junit.AfterClass;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Ignore;
@@ -117,8 +129,8 @@ public class TestNamespace {
     }
     //verify system tables aren't listed
     assertEquals(0, admin.listTables().length);
-    
-    //Try creating default and system namespaces. 
+
+    //Try creating default and system namespaces.
     boolean exceptionCaught = false;
     try {
       admin.createNamespace(NamespaceDescriptor.DEFAULT_NAMESPACE);
@@ -139,7 +151,7 @@ public class TestNamespace {
       assertTrue(exceptionCaught);
     }
   }
-  
+
   @Test
   public void testDeleteReservedNS() throws Exception {
     boolean exceptionCaught = false;
@@ -192,7 +204,7 @@ public class TestNamespace {
     LOG.info(testName);
 
     byte[] tableName = Bytes.toBytes("my_table");
-    byte[] tableNameFoo = Bytes.toBytes(nsName+".my_table");
+    byte[] tableNameFoo = Bytes.toBytes(nsName+":my_table");
     //create namespace and verify
     admin.createNamespace(NamespaceDescriptor.create(nsName).build());
     TEST_UTIL.createTable(tableName, Bytes.toBytes(nsName));
@@ -219,8 +231,8 @@ public class TestNamespace {
     desc.addFamily(colDesc);
     try {
       admin.createTable(desc);
-      fail("Expected no namespace constraint exception");
-    } catch (ConstraintException ex) {
+      fail("Expected no namespace exists exception");
+    } catch (NamespaceNotFoundException ex) {
     }
     //create table and in new namespace
     admin.createNamespace(NamespaceDescriptor.create(nsName).build());
@@ -262,7 +274,7 @@ public class TestNamespace {
     HColumnDescriptor colDesc = new HColumnDescriptor("cf1");
     desc.addFamily(colDesc);
     admin.createTable(desc);
-    assertTrue(admin.listTables().length == 1);  
+    assertTrue(admin.listTables().length == 1);
     admin.disableTable(desc.getTableName());
     admin.deleteTable(desc.getTableName());
   }
@@ -307,4 +319,109 @@ public class TestNamespace {
             ZooKeeperWatcher.namespaceZNode).size());
   }
 
+  @Test(timeout = 60000)
+  public void testNamespaceOperations() throws IOException {
+    admin.createNamespace(NamespaceDescriptor.create(prefix + "ns1").build());
+    admin.createNamespace(NamespaceDescriptor.create(prefix + "ns2").build());
+
+    // create namespace that already exists
+    runWithExpectedException(new Callable<Void>() {
+      @Override
+      public Void call() throws Exception {
+        admin.createNamespace(NamespaceDescriptor.create(prefix + "ns1").build());
+        return null;
+      }
+    }, NamespaceExistException.class);
+
+    // create a table in non-existing namespace
+    runWithExpectedException(new Callable<Void>() {
+      @Override
+      public Void call() throws Exception {
+        HTableDescriptor htd = new HTableDescriptor(TableName.valueOf("non_existing_namespace", "table1"));
+        htd.addFamily(new HColumnDescriptor("family1"));
+        admin.createTable(htd);
+        return null;
+      }
+    }, NamespaceNotFoundException.class);
+
+    // get descriptor for existing namespace
+    admin.getNamespaceDescriptor(prefix + "ns1");
+
+    // get descriptor for non-existing namespace
+    runWithExpectedException(new Callable<NamespaceDescriptor>() {
+      @Override
+      public NamespaceDescriptor call() throws Exception {
+        return admin.getNamespaceDescriptor("non_existing_namespace");
+      }
+    }, NamespaceNotFoundException.class);
+
+    // delete descriptor for existing namespace
+    admin.deleteNamespace(prefix + "ns2");
+
+    // delete descriptor for non-existing namespace
+    runWithExpectedException(new Callable<Void>() {
+      @Override
+      public Void call() throws Exception {
+        admin.deleteNamespace("non_existing_namespace");
+        return null;
+      }
+    }, NamespaceNotFoundException.class);
+
+    // modify namespace descriptor for existing namespace
+    NamespaceDescriptor ns1 = admin.getNamespaceDescriptor(prefix + "ns1");
+    ns1.setConfiguration("foo", "bar");
+    admin.modifyNamespace(ns1);
+
+    // modify namespace descriptor for non-existing namespace
+    runWithExpectedException(new Callable<Void>() {
+      @Override
+      public Void call() throws Exception {
+        admin.modifyNamespace(NamespaceDescriptor.create("non_existing_namespace").build());
+        return null;
+      }
+    }, NamespaceNotFoundException.class);
+
+    // get table descriptors for existing namespace
+    HTableDescriptor htd = new HTableDescriptor(TableName.valueOf(prefix + "ns1", "table1"));
+    htd.addFamily(new HColumnDescriptor("family1"));
+    admin.createTable(htd);
+    HTableDescriptor[] htds = admin.listTableDescriptorsByNamespace(prefix + "ns1");
+    assertNotNull("Should have not returned null", htds);
+    assertEquals("Should have returned non-empty array", 1, htds.length);
+
+    // get table descriptors for non-existing namespace
+    runWithExpectedException(new Callable<Void>() {
+      @Override
+      public Void call() throws Exception {
+        admin.listTableDescriptorsByNamespace("non_existing_namespace");
+        return null;
+      }
+    }, NamespaceNotFoundException.class);
+
+    // get table names for existing namespace
+    TableName[] tableNames = admin.listTableNamesByNamespace(prefix + "ns1");
+    assertNotNull("Should have not returned null", tableNames);
+    assertEquals("Should have returned non-empty array", 1, tableNames.length);
+
+    // get table names for non-existing namespace
+    runWithExpectedException(new Callable<Void>() {
+      @Override
+      public Void call() throws Exception {
+        admin.listTableNamesByNamespace("non_existing_namespace");
+        return null;
+      }
+    }, NamespaceNotFoundException.class);
+
+  }
+
+  private static <V, E> void runWithExpectedException(Callable<V> callable, Class<E> exceptionClass) {
+    try {
+      callable.call();
+    } catch(Exception ex) {
+      Assert.assertEquals(exceptionClass, ex.getClass());
+      return;
+    }
+    fail("Should have thrown exception " + exceptionClass);
+  }
+
 }