1   /**
2    * Copyright 2009 The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  package org.apache.hadoop.hbase.client;
21  
22  
23  import static org.junit.Assert.assertEquals;
24  import static org.junit.Assert.assertTrue;
25  import static org.junit.Assert.fail;
26  
27  import java.io.IOException;
28  import java.util.Iterator;
29  import java.util.Map;
30  import java.util.concurrent.atomic.AtomicInteger;
31  
32  import org.apache.commons.logging.Log;
33  import org.apache.commons.logging.LogFactory;
34  import org.apache.hadoop.hbase.HBaseTestingUtility;
35  import org.apache.hadoop.hbase.HColumnDescriptor;
36  import org.apache.hadoop.hbase.HConstants;
37  import org.apache.hadoop.hbase.HRegionInfo;
38  import org.apache.hadoop.hbase.HServerAddress;
39  import org.apache.hadoop.hbase.HTableDescriptor;
40  import org.apache.hadoop.hbase.TableExistsException;
41  import org.apache.hadoop.hbase.TableNotDisabledException;
42  import org.apache.hadoop.hbase.TableNotFoundException;
43  import org.apache.hadoop.hbase.util.Bytes;
44  import org.junit.AfterClass;
45  import org.junit.Before;
46  import org.junit.BeforeClass;
47  import org.junit.Test;
48  
49  
50  /**
51   * Class to test HBaseAdmin.
52   * Spins up the minicluster once at test start and then takes it down afterward.
53   * Add any testing of HBaseAdmin functionality here.
54   */
55  public class TestAdmin {
56    final Log LOG = LogFactory.getLog(getClass());
57    private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
58    private HBaseAdmin admin;
59  
60    @BeforeClass
61    public static void setUpBeforeClass() throws Exception {
62      TEST_UTIL.getConfiguration().setInt("hbase.regionserver.msginterval", 100);
63      TEST_UTIL.getConfiguration().setInt("hbase.client.pause", 250);
64      TEST_UTIL.getConfiguration().setInt("hbase.client.retries.number", 6);
65      TEST_UTIL.startMiniCluster(3);
66    }
67  
68    @AfterClass
69    public static void tearDownAfterClass() throws Exception {
70      TEST_UTIL.shutdownMiniCluster();
71    }
72  
73    @Before
74    public void setUp() throws Exception {
75      this.admin = new HBaseAdmin(TEST_UTIL.getConfiguration());
76    }
77  
78    @Test
79    public void testCreateTable() throws IOException {
80      HTableDescriptor [] tables = admin.listTables();
81      int numTables = tables.length;
82      TEST_UTIL.createTable(Bytes.toBytes("testCreateTable"),
83        HConstants.CATALOG_FAMILY);
84      tables = this.admin.listTables();
85      assertEquals(numTables + 1, tables.length);
86    }
87  
88    @Test
89    public void testCreateTableWithRegions() throws IOException {
90  
91      byte[] tableName = Bytes.toBytes("testCreateTableWithRegions");
92  
93      byte [][] splitKeys = {
94          new byte [] { 1, 1, 1 },
95          new byte [] { 2, 2, 2 },
96          new byte [] { 3, 3, 3 },
97          new byte [] { 4, 4, 4 },
98          new byte [] { 5, 5, 5 },
99          new byte [] { 6, 6, 6 },
100         new byte [] { 7, 7, 7 },
101         new byte [] { 8, 8, 8 },
102         new byte [] { 9, 9, 9 },
103     };
104     int expectedRegions = splitKeys.length + 1;
105 
106     HTableDescriptor desc = new HTableDescriptor(tableName);
107     desc.addFamily(new HColumnDescriptor(HConstants.CATALOG_FAMILY));
108     admin.createTable(desc, splitKeys);
109 
110     HTable ht = new HTable(TEST_UTIL.getConfiguration(), tableName);
111     Map<HRegionInfo,HServerAddress> regions = ht.getRegionsInfo();
112     assertEquals("Tried to create " + expectedRegions + " regions " +
113         "but only found " + regions.size(),
114         expectedRegions, regions.size());
115     System.err.println("Found " + regions.size() + " regions");
116 
117     Iterator<HRegionInfo> hris = regions.keySet().iterator();
118     HRegionInfo hri = hris.next();
119     assertTrue(hri.getStartKey() == null || hri.getStartKey().length == 0);
120     assertTrue(Bytes.equals(hri.getEndKey(), splitKeys[0]));
121     hri = hris.next();
122     assertTrue(Bytes.equals(hri.getStartKey(), splitKeys[0]));
123     assertTrue(Bytes.equals(hri.getEndKey(), splitKeys[1]));
124     hri = hris.next();
125     assertTrue(Bytes.equals(hri.getStartKey(), splitKeys[1]));
126     assertTrue(Bytes.equals(hri.getEndKey(), splitKeys[2]));
127     hri = hris.next();
128     assertTrue(Bytes.equals(hri.getStartKey(), splitKeys[2]));
129     assertTrue(Bytes.equals(hri.getEndKey(), splitKeys[3]));
130     hri = hris.next();
131     assertTrue(Bytes.equals(hri.getStartKey(), splitKeys[3]));
132     assertTrue(Bytes.equals(hri.getEndKey(), splitKeys[4]));
133     hri = hris.next();
134     assertTrue(Bytes.equals(hri.getStartKey(), splitKeys[4]));
135     assertTrue(Bytes.equals(hri.getEndKey(), splitKeys[5]));
136     hri = hris.next();
137     assertTrue(Bytes.equals(hri.getStartKey(), splitKeys[5]));
138     assertTrue(Bytes.equals(hri.getEndKey(), splitKeys[6]));
139     hri = hris.next();
140     assertTrue(Bytes.equals(hri.getStartKey(), splitKeys[6]));
141     assertTrue(Bytes.equals(hri.getEndKey(), splitKeys[7]));
142     hri = hris.next();
143     assertTrue(Bytes.equals(hri.getStartKey(), splitKeys[7]));
144     assertTrue(Bytes.equals(hri.getEndKey(), splitKeys[8]));
145     hri = hris.next();
146     assertTrue(Bytes.equals(hri.getStartKey(), splitKeys[8]));
147     assertTrue(hri.getEndKey() == null || hri.getEndKey().length == 0);
148 
149     // Now test using start/end with a number of regions
150 
151     // Use 80 bit numbers to make sure we aren't limited
152     byte [] startKey = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
153     byte [] endKey =   { 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 };
154 
155     // Splitting into 10 regions, we expect (null,1) ... (9, null)
156     // with (1,2) (2,3) (3,4) (4,5) (5,6) (6,7) (7,8) (8,9) in the middle
157 
158     expectedRegions = 10;
159 
160     byte [] TABLE_2 = Bytes.add(tableName, Bytes.toBytes("_2"));
161 
162     desc = new HTableDescriptor(TABLE_2);
163     desc.addFamily(new HColumnDescriptor(HConstants.CATALOG_FAMILY));
164     admin = new HBaseAdmin(TEST_UTIL.getConfiguration());
165     admin.createTable(desc, startKey, endKey, expectedRegions);
166 
167     ht = new HTable(TEST_UTIL.getConfiguration(), TABLE_2);
168     regions = ht.getRegionsInfo();
169     assertEquals("Tried to create " + expectedRegions + " regions " +
170         "but only found " + regions.size(),
171         expectedRegions, regions.size());
172     System.err.println("Found " + regions.size() + " regions");
173 
174     hris = regions.keySet().iterator();
175     hri = hris.next();
176     assertTrue(hri.getStartKey() == null || hri.getStartKey().length == 0);
177     assertTrue(Bytes.equals(hri.getEndKey(), new byte [] {1,1,1,1,1,1,1,1,1,1}));
178     hri = hris.next();
179     assertTrue(Bytes.equals(hri.getStartKey(), new byte [] {1,1,1,1,1,1,1,1,1,1}));
180     assertTrue(Bytes.equals(hri.getEndKey(), new byte [] {2,2,2,2,2,2,2,2,2,2}));
181     hri = hris.next();
182     assertTrue(Bytes.equals(hri.getStartKey(), new byte [] {2,2,2,2,2,2,2,2,2,2}));
183     assertTrue(Bytes.equals(hri.getEndKey(), new byte [] {3,3,3,3,3,3,3,3,3,3}));
184     hri = hris.next();
185     assertTrue(Bytes.equals(hri.getStartKey(), new byte [] {3,3,3,3,3,3,3,3,3,3}));
186     assertTrue(Bytes.equals(hri.getEndKey(), new byte [] {4,4,4,4,4,4,4,4,4,4}));
187     hri = hris.next();
188     assertTrue(Bytes.equals(hri.getStartKey(), new byte [] {4,4,4,4,4,4,4,4,4,4}));
189     assertTrue(Bytes.equals(hri.getEndKey(), new byte [] {5,5,5,5,5,5,5,5,5,5}));
190     hri = hris.next();
191     assertTrue(Bytes.equals(hri.getStartKey(), new byte [] {5,5,5,5,5,5,5,5,5,5}));
192     assertTrue(Bytes.equals(hri.getEndKey(), new byte [] {6,6,6,6,6,6,6,6,6,6}));
193     hri = hris.next();
194     assertTrue(Bytes.equals(hri.getStartKey(), new byte [] {6,6,6,6,6,6,6,6,6,6}));
195     assertTrue(Bytes.equals(hri.getEndKey(), new byte [] {7,7,7,7,7,7,7,7,7,7}));
196     hri = hris.next();
197     assertTrue(Bytes.equals(hri.getStartKey(), new byte [] {7,7,7,7,7,7,7,7,7,7}));
198     assertTrue(Bytes.equals(hri.getEndKey(), new byte [] {8,8,8,8,8,8,8,8,8,8}));
199     hri = hris.next();
200     assertTrue(Bytes.equals(hri.getStartKey(), new byte [] {8,8,8,8,8,8,8,8,8,8}));
201     assertTrue(Bytes.equals(hri.getEndKey(), new byte [] {9,9,9,9,9,9,9,9,9,9}));
202     hri = hris.next();
203     assertTrue(Bytes.equals(hri.getStartKey(), new byte [] {9,9,9,9,9,9,9,9,9,9}));
204     assertTrue(hri.getEndKey() == null || hri.getEndKey().length == 0);
205 
206     // Try once more with something that divides into something infinite
207 
208     startKey = new byte [] { 0, 0, 0, 0, 0, 0 };
209     endKey = new byte [] { 1, 0, 0, 0, 0, 0 };
210 
211     expectedRegions = 5;
212 
213     byte [] TABLE_3 = Bytes.add(tableName, Bytes.toBytes("_3"));
214 
215     desc = new HTableDescriptor(TABLE_3);
216     desc.addFamily(new HColumnDescriptor(HConstants.CATALOG_FAMILY));
217     admin = new HBaseAdmin(TEST_UTIL.getConfiguration());
218     admin.createTable(desc, startKey, endKey, expectedRegions);
219 
220     ht = new HTable(TEST_UTIL.getConfiguration(), TABLE_3);
221     regions = ht.getRegionsInfo();
222     assertEquals("Tried to create " + expectedRegions + " regions " +
223         "but only found " + regions.size(),
224         expectedRegions, regions.size());
225     System.err.println("Found " + regions.size() + " regions");
226 
227     // Try an invalid case where there are duplicate split keys
228     splitKeys = new byte [][] {
229         new byte [] { 1, 1, 1 },
230         new byte [] { 2, 2, 2 },
231         new byte [] { 3, 3, 3 },
232         new byte [] { 2, 2, 2 }
233     };
234 
235     byte [] TABLE_4 = Bytes.add(tableName, Bytes.toBytes("_4"));
236     desc = new HTableDescriptor(TABLE_4);
237     desc.addFamily(new HColumnDescriptor(HConstants.CATALOG_FAMILY));
238     admin = new HBaseAdmin(TEST_UTIL.getConfiguration());
239     try {
240       admin.createTable(desc, splitKeys);
241       assertTrue("Should not be able to create this table because of " +
242           "duplicate split keys", false);
243     } catch(IllegalArgumentException iae) {
244       // Expected
245     }
246   }
247 
248   @Test
249   public void testDisableAndEnableTable() throws IOException {
250     final byte [] row = Bytes.toBytes("row");
251     final byte [] qualifier = Bytes.toBytes("qualifier");
252     final byte [] value = Bytes.toBytes("value");
253     final byte [] table = Bytes.toBytes("testDisableAndEnableTable");
254     HTable ht = TEST_UTIL.createTable(table, HConstants.CATALOG_FAMILY);
255     Put put = new Put(row);
256     put.add(HConstants.CATALOG_FAMILY, qualifier, value);
257     ht.put(put);
258 
259     this.admin.disableTable(table);
260 
261     // Test that table is disabled
262     Get get = new Get(row);
263     get.addColumn(HConstants.CATALOG_FAMILY, qualifier);
264     boolean ok = false;
265     try {
266       ht.get(get);
267     } catch (RetriesExhaustedException e) {
268       ok = true;
269     }
270     assertEquals(true, ok);
271     this.admin.enableTable(table);
272 
273     //Test that table is enabled
274     try {
275       ht.get(get);
276     } catch (RetriesExhaustedException e) {
277       ok = false;
278     }
279     assertEquals(true, ok);
280   }
281 
282   @Test
283   public void testTableExist() throws IOException {
284     final byte [] table = Bytes.toBytes("testTableExist");
285     boolean exist = false;
286     exist = this.admin.tableExists(table);
287     assertEquals(false, exist);
288     TEST_UTIL.createTable(table, HConstants.CATALOG_FAMILY);
289     exist = this.admin.tableExists(table);
290     assertEquals(true, exist);
291   }
292 
293   /**
294    * Tests forcing split from client and having scanners successfully ride over split.
295    * @throws Exception
296    * @throws IOException
297    */
298   @Test
299   public void testForceSplit() throws Exception {
300     byte [] familyName = HConstants.CATALOG_FAMILY;
301     byte [] tableName = Bytes.toBytes("testForceSplit");
302     final HTable table = TEST_UTIL.createTable(tableName, familyName);
303     byte[] k = new byte[3];
304     int rowCount = 0;
305     for (byte b1 = 'a'; b1 < 'z'; b1++) {
306       for (byte b2 = 'a'; b2 < 'z'; b2++) {
307         for (byte b3 = 'a'; b3 < 'z'; b3++) {
308           k[0] = b1;
309           k[1] = b2;
310           k[2] = b3;
311           Put put = new Put(k);
312           put.add(familyName, new byte[0], k);
313           table.put(put);
314           rowCount++;
315         }
316       }
317     }
318 
319     // get the initial layout (should just be one region)
320     Map<HRegionInfo,HServerAddress> m = table.getRegionsInfo();
321     System.out.println("Initial regions (" + m.size() + "): " + m);
322     assertTrue(m.size() == 1);
323 
324     // Verify row count
325     Scan scan = new Scan();
326     ResultScanner scanner = table.getScanner(scan);
327     int rows = 0;
328     for(@SuppressWarnings("unused") Result result : scanner) {
329       rows++;
330     }
331     scanner.close();
332     assertEquals(rowCount, rows);
333 
334     // Have an outstanding scan going on to make sure we can scan over splits.
335     scan = new Scan();
336     scanner = table.getScanner(scan);
337     // Scan first row so we are into first region before split happens.
338     scanner.next();
339 
340     final AtomicInteger count = new AtomicInteger(0);
341     Thread t = new Thread("CheckForSplit") {
342       public void run() {
343         for (int i = 0; i < 20; i++) {
344           try {
345             sleep(1000);
346           } catch (InterruptedException e) {
347             continue;
348           }
349           // check again    table = new HTable(conf, tableName);
350           Map<HRegionInfo, HServerAddress> regions = null;
351           try {
352             regions = table.getRegionsInfo();
353           } catch (IOException e) {
354             e.printStackTrace();
355           }
356           if (regions == null) continue;
357           count.set(regions.size());
358           if (count.get() >= 2) break;
359           LOG.debug("Cycle waiting on split");
360         }
361       }
362     };
363     t.start();
364     // tell the master to split the table
365     admin.split(Bytes.toString(tableName));
366     t.join();
367 
368     // Verify row count
369     rows = 1; // We counted one row above.
370     for (@SuppressWarnings("unused") Result result : scanner) {
371       rows++;
372       if (rows > rowCount) {
373         scanner.close();
374         assertTrue("Scanned more than expected (" + rowCount + ")", false);
375       }
376     }
377     scanner.close();
378     assertEquals(rowCount, rows);
379   }
380 
381   /**
382    * HADOOP-2156
383    * @throws IOException
384    */
385   @Test (expected=IllegalArgumentException.class)
386   public void testEmptyHHTableDescriptor() throws IOException {
387     this.admin.createTable(new HTableDescriptor());
388   }
389 
390   @Test
391   public void testEnableDisableAddColumnDeleteColumn() throws Exception {
392     byte [] tableName = Bytes.toBytes("testMasterAdmin");
393     TEST_UTIL.createTable(tableName, HConstants.CATALOG_FAMILY);
394     this.admin.disableTable(tableName);
395     try {
396       new HTable(TEST_UTIL.getConfiguration(), tableName);
397     } catch (org.apache.hadoop.hbase.client.RegionOfflineException e) {
398       // Expected
399     }
400     this.admin.addColumn(tableName, new HColumnDescriptor("col2"));
401     this.admin.enableTable(tableName);
402     try {
403       this.admin.deleteColumn(tableName, Bytes.toBytes("col2"));
404     } catch(TableNotDisabledException e) {
405       // Expected
406     }
407     this.admin.disableTable(tableName);
408     this.admin.deleteColumn(tableName, Bytes.toBytes("col2"));
409     this.admin.deleteTable(tableName);
410   }
411 
412   @Test
413   public void testCreateBadTables() throws IOException {
414     String msg = null;
415     try {
416       this.admin.createTable(HTableDescriptor.ROOT_TABLEDESC);
417     } catch (IllegalArgumentException e) {
418       msg = e.toString();
419     }
420     assertTrue("Unexcepted exception message " + msg, msg != null &&
421       msg.startsWith(IllegalArgumentException.class.getName()) &&
422       msg.contains(HTableDescriptor.ROOT_TABLEDESC.getNameAsString()));
423     msg = null;
424     try {
425       this.admin.createTable(HTableDescriptor.META_TABLEDESC);
426     } catch(IllegalArgumentException e) {
427       msg = e.toString();
428     }
429     assertTrue("Unexcepted exception message " + msg, msg != null &&
430       msg.startsWith(IllegalArgumentException.class.getName()) &&
431       msg.contains(HTableDescriptor.META_TABLEDESC.getNameAsString()));
432 
433     // Now try and do concurrent creation with a bunch of threads.
434     final HTableDescriptor threadDesc =
435       new HTableDescriptor("threaded_testCreateBadTables");
436     threadDesc.addFamily(new HColumnDescriptor(HConstants.CATALOG_FAMILY));
437     int count = 10;
438     Thread [] threads = new Thread [count];
439     final AtomicInteger successes = new AtomicInteger(0);
440     final AtomicInteger failures = new AtomicInteger(0);
441     final HBaseAdmin localAdmin = this.admin;
442     for (int i = 0; i < count; i++) {
443       threads[i] = new Thread(Integer.toString(i)) {
444         @Override
445         public void run() {
446           try {
447             localAdmin.createTable(threadDesc);
448             successes.incrementAndGet();
449           } catch (TableExistsException e) {
450             failures.incrementAndGet();
451           } catch (IOException e) {
452             throw new RuntimeException("Failed threaded create" + getName(), e);
453           }
454         }
455       };
456     }
457     for (int i = 0; i < count; i++) {
458       threads[i].start();
459     }
460     for (int i = 0; i < count; i++) {
461       while(threads[i].isAlive()) {
462         try {
463           Thread.sleep(1000);
464         } catch (InterruptedException e) {
465           // continue
466         }
467       }
468     }
469     // All threads are now dead.  Count up how many tables were created and
470     // how many failed w/ appropriate exception.
471     assertEquals(1, successes.get());
472     assertEquals(count - 1, failures.get());
473   }
474 
475   /**
476    * Test for hadoop-1581 'HBASE: Unopenable tablename bug'.
477    * @throws Exception
478    */
479   @Test
480   public void testTableNameClash() throws Exception {
481     String name = "testTableNameClash";
482     admin.createTable(new HTableDescriptor(name + "SOMEUPPERCASE"));
483     admin.createTable(new HTableDescriptor(name));
484     // Before fix, below would fail throwing a NoServerForRegionException.
485     new HTable(TEST_UTIL.getConfiguration(), name);
486   }
487 
488   /**
489    * Test read only tables
490    * @throws Exception
491    */
492   @Test
493   public void testReadOnlyTable() throws Exception {
494     byte [] name = Bytes.toBytes("testReadOnlyTable");
495     HTable table = TEST_UTIL.createTable(name, HConstants.CATALOG_FAMILY);
496     byte[] value = Bytes.toBytes("somedata");
497     // This used to use an empty row... That must have been a bug
498     Put put = new Put(value);
499     put.add(HConstants.CATALOG_FAMILY, HConstants.CATALOG_FAMILY, value);
500     table.put(put);
501   }
502 
503   /**
504    * Test that user table names can contain '-' and '.' so long as they do not
505    * start with same. HBASE-771
506    * @throws IOException
507    */
508   @Test
509   public void testTableNames() throws IOException {
510     byte[][] illegalNames = new byte[][] {
511         Bytes.toBytes("-bad"),
512         Bytes.toBytes(".bad"),
513         HConstants.ROOT_TABLE_NAME,
514         HConstants.META_TABLE_NAME
515     };
516     for (int i = 0; i < illegalNames.length; i++) {
517       try {
518         new HTableDescriptor(illegalNames[i]);
519         throw new IOException("Did not detect '" +
520           Bytes.toString(illegalNames[i]) + "' as an illegal user table name");
521       } catch (IllegalArgumentException e) {
522         // expected
523       }
524     }
525     byte[] legalName = Bytes.toBytes("g-oo.d");
526     try {
527       new HTableDescriptor(legalName);
528     } catch (IllegalArgumentException e) {
529       throw new IOException("Legal user table name: '" +
530         Bytes.toString(legalName) + "' caused IllegalArgumentException: " +
531         e.getMessage());
532     }
533   }
534 
535   /**
536    * For HADOOP-2579
537    * @throws IOException
538    */
539   @Test (expected=TableExistsException.class)
540   public void testTableNotFoundExceptionWithATable() throws IOException {
541     final byte [] name = Bytes.toBytes("testTableNotFoundExceptionWithATable");
542     TEST_UTIL.createTable(name, HConstants.CATALOG_FAMILY);
543     TEST_UTIL.createTable(name, HConstants.CATALOG_FAMILY);
544   }
545 
546   /**
547    * For HADOOP-2579
548    * @throws IOException
549    */
550   @Test (expected=TableNotFoundException.class)
551   public void testTableNotFoundExceptionWithoutAnyTables() throws IOException {
552     new HTable(TEST_UTIL.getConfiguration(),
553         "testTableNotFoundExceptionWithoutAnyTables");
554   }
555 
556   @Test
557   public void testHundredsOfTable() throws IOException{
558     final int times = 100;
559     HColumnDescriptor fam1 = new HColumnDescriptor("fam1");
560     HColumnDescriptor fam2 = new HColumnDescriptor("fam2");
561     HColumnDescriptor fam3 = new HColumnDescriptor("fam3");
562 
563     for(int i = 0; i < times; i++) {
564       HTableDescriptor htd = new HTableDescriptor("table"+i);
565       htd.addFamily(fam1);
566       htd.addFamily(fam2);
567       htd.addFamily(fam3);
568       this.admin.createTable(htd);
569     }
570 
571     for(int i = 0; i < times; i++) {
572       String tableName = "table"+i;
573       this.admin.disableTable(tableName);
574       this.admin.enableTable(tableName);
575       this.admin.disableTable(tableName);
576       this.admin.deleteTable(tableName);
577     }
578   }
579 
580   @Test
581   public void testGetTableDescriptor() throws IOException {
582     HColumnDescriptor fam1 = new HColumnDescriptor("fam1");
583     HColumnDescriptor fam2 = new HColumnDescriptor("fam2");
584     HColumnDescriptor fam3 = new HColumnDescriptor("fam3");
585     HTableDescriptor htd = new HTableDescriptor("myTestTable");
586     htd.addFamily(fam1);
587     htd.addFamily(fam2);
588     htd.addFamily(fam3);
589     this.admin.createTable(htd);
590     HTable table = new HTable("myTestTable");
591     HTableDescriptor confirmedHtd = table.getTableDescriptor();
592 
593     assertEquals(htd.compareTo(confirmedHtd), 0);
594   }
595 }
596