View Javadoc

1   /*
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  package org.apache.hadoop.hbase.thrift;
20  
21  import static org.junit.Assert.assertEquals;
22  import static org.junit.Assert.assertFalse;
23  import static org.junit.Assert.assertTrue;
24  
25  import java.io.IOException;
26  import java.nio.ByteBuffer;
27  import java.util.ArrayList;
28  import java.util.List;
29  import java.util.Map;
30  
31  import org.apache.commons.logging.Log;
32  import org.apache.commons.logging.LogFactory;
33  import org.apache.hadoop.conf.Configuration;
34  import org.apache.hadoop.hbase.CompatibilityFactory;
35  import org.apache.hadoop.hbase.TableName;
36  import org.apache.hadoop.hbase.HBaseTestingUtility;
37  import org.apache.hadoop.hbase.HConstants;
38  import org.apache.hadoop.hbase.HRegionInfo;
39  import org.apache.hadoop.hbase.MediumTests;
40  import org.apache.hadoop.hbase.filter.ParseFilter;
41  import org.apache.hadoop.hbase.test.MetricsAssertHelper;
42  import org.apache.hadoop.hbase.thrift.ThriftServerRunner.HBaseHandler;
43  import org.apache.hadoop.hbase.thrift.generated.BatchMutation;
44  import org.apache.hadoop.hbase.thrift.generated.ColumnDescriptor;
45  import org.apache.hadoop.hbase.thrift.generated.Hbase;
46  import org.apache.hadoop.hbase.thrift.generated.IOError;
47  import org.apache.hadoop.hbase.thrift.generated.Mutation;
48  import org.apache.hadoop.hbase.thrift.generated.TCell;
49  import org.apache.hadoop.hbase.thrift.generated.TScan;
50  import org.apache.hadoop.hbase.thrift.generated.TIncrement;
51  import org.apache.hadoop.hbase.thrift.generated.TRegionInfo;
52  import org.apache.hadoop.hbase.thrift.generated.TRowResult;
53  import org.apache.hadoop.hbase.util.Bytes;
54  import org.apache.hadoop.hbase.util.Threads;
55  import org.junit.AfterClass;
56  import org.junit.BeforeClass;
57  import org.junit.Test;
58  import org.junit.experimental.categories.Category;
59  
60  /**
61   * Unit testing for ThriftServerRunner.HBaseHandler, a part of the
62   * org.apache.hadoop.hbase.thrift package.
63   */
64  @Category(MediumTests.class)
65  public class TestThriftServer {
66    private static final HBaseTestingUtility UTIL = new HBaseTestingUtility();
67    private static final Log LOG = LogFactory.getLog(TestThriftServer.class);
68    private static final MetricsAssertHelper metricsHelper = CompatibilityFactory
69        .getInstance(MetricsAssertHelper.class);
70    protected static final int MAXVERSIONS = 3;
71  
72    private static ByteBuffer asByteBuffer(String i) {
73      return ByteBuffer.wrap(Bytes.toBytes(i));
74    }
75    private static ByteBuffer asByteBuffer(long l) {
76      return ByteBuffer.wrap(Bytes.toBytes(l));
77    }
78  
79    // Static names for tables, columns, rows, and values
80    private static ByteBuffer tableAname = asByteBuffer("tableA");
81    private static ByteBuffer tableBname = asByteBuffer("tableB");
82    private static ByteBuffer columnAname = asByteBuffer("columnA:");
83    private static ByteBuffer columnAAname = asByteBuffer("columnA:A");
84    private static ByteBuffer columnBname = asByteBuffer("columnB:");
85    private static ByteBuffer rowAname = asByteBuffer("rowA");
86    private static ByteBuffer rowBname = asByteBuffer("rowB");
87    private static ByteBuffer valueAname = asByteBuffer("valueA");
88    private static ByteBuffer valueBname = asByteBuffer("valueB");
89    private static ByteBuffer valueCname = asByteBuffer("valueC");
90    private static ByteBuffer valueDname = asByteBuffer("valueD");
91    private static ByteBuffer valueEname = asByteBuffer(100l);
92  
93    @BeforeClass
94    public static void beforeClass() throws Exception {
95      UTIL.getConfiguration().setBoolean(ThriftServerRunner.COALESCE_INC_KEY, true);
96      UTIL.startMiniCluster();
97    }
98  
99    @AfterClass
100   public static void afterClass() throws Exception {
101     UTIL.shutdownMiniCluster();
102   }
103 
104   /**
105    * Runs all of the tests under a single JUnit test method.  We
106    * consolidate all testing to one method because HBaseClusterTestCase
107    * is prone to OutOfMemoryExceptions when there are three or more
108    * JUnit test methods.
109    *
110    * @throws Exception
111    */
112   @Test
113   public void testAll() throws Exception {
114     // Run all tests
115     doTestTableCreateDrop();
116     doTestThriftMetrics();
117     doTestTableMutations();
118     doTestTableTimestampsAndColumns();
119     doTestTableScanners();
120     doTestGetTableRegions();
121     doTestFilterRegistration();
122     doTestGetRegionInfo();
123     doTestIncrements();
124   }
125 
126   /**
127    * Tests for creating, enabling, disabling, and deleting tables.  Also
128    * tests that creating a table with an invalid column name yields an
129    * IllegalArgument exception.
130    *
131    * @throws Exception
132    */
133   public void doTestTableCreateDrop() throws Exception {
134     ThriftServerRunner.HBaseHandler handler =
135       new ThriftServerRunner.HBaseHandler(UTIL.getConfiguration());
136     doTestTableCreateDrop(handler);
137   }
138 
139   public static void doTestTableCreateDrop(Hbase.Iface handler) throws Exception {
140     createTestTables(handler);
141     dropTestTables(handler);
142   }
143 
144   public static final class MySlowHBaseHandler extends ThriftServerRunner.HBaseHandler
145       implements Hbase.Iface {
146 
147     protected MySlowHBaseHandler(Configuration c)
148         throws IOException {
149       super(c);
150     }
151 
152     @Override
153     public List<ByteBuffer> getTableNames() throws IOError {
154       Threads.sleepWithoutInterrupt(3000);
155       return super.getTableNames();
156     }
157   }
158 
159   /**
160    * Tests if the metrics for thrift handler work correctly
161    */
162   public void doTestThriftMetrics() throws Exception {
163     Configuration conf = UTIL.getConfiguration();
164     ThriftMetrics metrics = getMetrics(conf);
165     Hbase.Iface handler = getHandlerForMetricsTest(metrics, conf);
166     createTestTables(handler);
167     dropTestTables(handler);
168     metricsHelper.assertCounter("createTable_num_ops", 2, metrics.getSource());
169     metricsHelper.assertCounter("deleteTable_num_ops", 2, metrics.getSource());
170     metricsHelper.assertCounter("disableTable_num_ops", 2, metrics.getSource());
171     handler.getTableNames(); // This will have an artificial delay.
172 
173     // 3 to 6 seconds (to account for potential slowness), measured in nanoseconds
174    metricsHelper.assertGaugeGt("getTableNames_avg_time", 3L * 1000 * 1000 * 1000, metrics.getSource());
175    metricsHelper.assertGaugeLt("getTableNames_avg_time",6L * 1000 * 1000 * 1000, metrics.getSource());
176   }
177 
178   private static Hbase.Iface getHandlerForMetricsTest(ThriftMetrics metrics, Configuration conf)
179       throws Exception {
180     Hbase.Iface handler = new MySlowHBaseHandler(conf);
181     return HbaseHandlerMetricsProxy.newInstance(handler, metrics, conf);
182   }
183 
184   private static ThriftMetrics getMetrics(Configuration conf) throws Exception {
185     return new ThriftMetrics( conf, ThriftMetrics.ThriftServerType.ONE);
186   }
187 
188 
189   public static void createTestTables(Hbase.Iface handler) throws Exception {
190     // Create/enable/disable/delete tables, ensure methods act correctly
191     assertEquals(handler.getTableNames().size(), 0);
192     handler.createTable(tableAname, getColumnDescriptors());
193     assertEquals(handler.getTableNames().size(), 1);
194     assertEquals(handler.getColumnDescriptors(tableAname).size(), 2);
195     assertTrue(handler.isTableEnabled(tableAname));
196     handler.createTable(tableBname, new ArrayList<ColumnDescriptor>());
197     assertEquals(handler.getTableNames().size(), 2);
198   }
199 
200   public static void checkTableList(Hbase.Iface handler) throws Exception {
201     assertTrue(handler.getTableNames().contains(tableAname));
202   }
203 
204   public static void dropTestTables(Hbase.Iface handler) throws Exception {
205     handler.disableTable(tableBname);
206     assertFalse(handler.isTableEnabled(tableBname));
207     handler.deleteTable(tableBname);
208     assertEquals(handler.getTableNames().size(), 1);
209     handler.disableTable(tableAname);
210     assertFalse(handler.isTableEnabled(tableAname));
211     /* TODO Reenable.
212     assertFalse(handler.isTableEnabled(tableAname));
213     handler.enableTable(tableAname);
214     assertTrue(handler.isTableEnabled(tableAname));
215     handler.disableTable(tableAname);*/
216     handler.deleteTable(tableAname);
217     assertEquals(handler.getTableNames().size(), 0);
218   }
219 
220   public void doTestIncrements() throws Exception {
221     ThriftServerRunner.HBaseHandler handler =
222         new ThriftServerRunner.HBaseHandler(UTIL.getConfiguration());
223     createTestTables(handler);
224     doTestIncrements(handler);
225     dropTestTables(handler);
226   }
227 
228   public static void doTestIncrements(HBaseHandler handler) throws Exception {
229     List<Mutation> mutations = new ArrayList<Mutation>(1);
230     mutations.add(new Mutation(false, columnAAname, valueEname, true));
231     mutations.add(new Mutation(false, columnAname, valueEname, true));
232     handler.mutateRow(tableAname, rowAname, mutations, null);
233     handler.mutateRow(tableAname, rowBname, mutations, null);
234 
235     List<TIncrement> increments = new ArrayList<TIncrement>();
236     increments.add(new TIncrement(tableAname, rowBname, columnAAname, 7));
237     increments.add(new TIncrement(tableAname, rowBname, columnAAname, 7));
238     increments.add(new TIncrement(tableAname, rowBname, columnAAname, 7));
239 
240     int numIncrements = 60000;
241     for (int i = 0; i < numIncrements; i++) {
242       handler.increment(new TIncrement(tableAname, rowAname, columnAname, 2));
243       handler.incrementRows(increments);
244     }
245 
246     Thread.sleep(1000);
247     long lv = handler.get(tableAname, rowAname, columnAname, null).get(0).value.getLong();
248     // Wait on all increments being flushed
249     while (handler.coalescer.getQueueSize() != 0) Threads.sleep(10);
250     assertEquals((100 + (2 * numIncrements)), lv );
251 
252 
253     lv = handler.get(tableAname, rowBname, columnAAname, null).get(0).value.getLong();
254     assertEquals((100 + (3 * 7 * numIncrements)), lv);
255 
256     assertTrue(handler.coalescer.getSuccessfulCoalescings() > 0);
257 
258   }
259 
260   /**
261    * Tests adding a series of Mutations and BatchMutations, including a
262    * delete mutation.  Also tests data retrieval, and getting back multiple
263    * versions.
264    *
265    * @throws Exception
266    */
267   public void doTestTableMutations() throws Exception {
268     ThriftServerRunner.HBaseHandler handler =
269       new ThriftServerRunner.HBaseHandler(UTIL.getConfiguration());
270     doTestTableMutations(handler);
271   }
272 
273   public static void doTestTableMutations(Hbase.Iface handler) throws Exception {
274     // Setup
275     handler.createTable(tableAname, getColumnDescriptors());
276 
277     // Apply a few Mutations to rowA
278     //     mutations.add(new Mutation(false, columnAname, valueAname));
279     //     mutations.add(new Mutation(false, columnBname, valueBname));
280     handler.mutateRow(tableAname, rowAname, getMutations(), null);
281 
282     // Assert that the changes were made
283     assertEquals(valueAname,
284       handler.get(tableAname, rowAname, columnAname, null).get(0).value);
285     TRowResult rowResult1 = handler.getRow(tableAname, rowAname, null).get(0);
286     assertEquals(rowAname, rowResult1.row);
287     assertEquals(valueBname,
288       rowResult1.columns.get(columnBname).value);
289 
290     // Apply a few BatchMutations for rowA and rowB
291     // rowAmutations.add(new Mutation(true, columnAname, null));
292     // rowAmutations.add(new Mutation(false, columnBname, valueCname));
293     // batchMutations.add(new BatchMutation(rowAname, rowAmutations));
294     // Mutations to rowB
295     // rowBmutations.add(new Mutation(false, columnAname, valueCname));
296     // rowBmutations.add(new Mutation(false, columnBname, valueDname));
297     // batchMutations.add(new BatchMutation(rowBname, rowBmutations));
298     handler.mutateRows(tableAname, getBatchMutations(), null);
299 
300     // Assert that changes were made to rowA
301     List<TCell> cells = handler.get(tableAname, rowAname, columnAname, null);
302     assertFalse(cells.size() > 0);
303     assertEquals(valueCname, handler.get(tableAname, rowAname, columnBname, null).get(0).value);
304     List<TCell> versions = handler.getVer(tableAname, rowAname, columnBname, MAXVERSIONS, null);
305     assertEquals(valueCname, versions.get(0).value);
306     assertEquals(valueBname, versions.get(1).value);
307 
308     // Assert that changes were made to rowB
309     TRowResult rowResult2 = handler.getRow(tableAname, rowBname, null).get(0);
310     assertEquals(rowBname, rowResult2.row);
311     assertEquals(valueCname, rowResult2.columns.get(columnAname).value);
312     assertEquals(valueDname, rowResult2.columns.get(columnBname).value);
313 
314     // Apply some deletes
315     handler.deleteAll(tableAname, rowAname, columnBname, null);
316     handler.deleteAllRow(tableAname, rowBname, null);
317 
318     // Assert that the deletes were applied
319     int size = handler.get(tableAname, rowAname, columnBname, null).size();
320     assertEquals(0, size);
321     size = handler.getRow(tableAname, rowBname, null).size();
322     assertEquals(0, size);
323 
324     // Try null mutation
325     List<Mutation> mutations = new ArrayList<Mutation>();
326     mutations.add(new Mutation(false, columnAname, null, true));
327     handler.mutateRow(tableAname, rowAname, mutations, null);
328     TRowResult rowResult3 = handler.getRow(tableAname, rowAname, null).get(0);
329     assertEquals(rowAname, rowResult3.row);
330     assertEquals(0, rowResult3.columns.get(columnAname).value.remaining());
331 
332     // Teardown
333     handler.disableTable(tableAname);
334     handler.deleteTable(tableAname);
335   }
336 
337   /**
338    * Similar to testTableMutations(), except Mutations are applied with
339    * specific timestamps and data retrieval uses these timestamps to
340    * extract specific versions of data.
341    *
342    * @throws Exception
343    */
344   public void doTestTableTimestampsAndColumns() throws Exception {
345     // Setup
346     ThriftServerRunner.HBaseHandler handler =
347       new ThriftServerRunner.HBaseHandler(UTIL.getConfiguration());
348     handler.createTable(tableAname, getColumnDescriptors());
349 
350     // Apply timestamped Mutations to rowA
351     long time1 = System.currentTimeMillis();
352     handler.mutateRowTs(tableAname, rowAname, getMutations(), time1, null);
353 
354     Thread.sleep(1000);
355 
356     // Apply timestamped BatchMutations for rowA and rowB
357     long time2 = System.currentTimeMillis();
358     handler.mutateRowsTs(tableAname, getBatchMutations(), time2, null);
359 
360     // Apply an overlapping timestamped mutation to rowB
361     handler.mutateRowTs(tableAname, rowBname, getMutations(), time2, null);
362 
363     // the getVerTs is [inf, ts) so you need to increment one.
364     time1 += 1;
365     time2 += 2;
366 
367     // Assert that the timestamp-related methods retrieve the correct data
368     assertEquals(2, handler.getVerTs(tableAname, rowAname, columnBname, time2,
369       MAXVERSIONS, null).size());
370     assertEquals(1, handler.getVerTs(tableAname, rowAname, columnBname, time1,
371       MAXVERSIONS, null).size());
372 
373     TRowResult rowResult1 = handler.getRowTs(tableAname, rowAname, time1, null).get(0);
374     TRowResult rowResult2 = handler.getRowTs(tableAname, rowAname, time2, null).get(0);
375     // columnA was completely deleted
376     //assertTrue(Bytes.equals(rowResult1.columns.get(columnAname).value, valueAname));
377     assertEquals(rowResult1.columns.get(columnBname).value, valueBname);
378     assertEquals(rowResult2.columns.get(columnBname).value, valueCname);
379 
380     // ColumnAname has been deleted, and will never be visible even with a getRowTs()
381     assertFalse(rowResult2.columns.containsKey(columnAname));
382 
383     List<ByteBuffer> columns = new ArrayList<ByteBuffer>();
384     columns.add(columnBname);
385 
386     rowResult1 = handler.getRowWithColumns(tableAname, rowAname, columns, null).get(0);
387     assertEquals(rowResult1.columns.get(columnBname).value, valueCname);
388     assertFalse(rowResult1.columns.containsKey(columnAname));
389 
390     rowResult1 = handler.getRowWithColumnsTs(tableAname, rowAname, columns, time1, null).get(0);
391     assertEquals(rowResult1.columns.get(columnBname).value, valueBname);
392     assertFalse(rowResult1.columns.containsKey(columnAname));
393 
394     // Apply some timestamped deletes
395     // this actually deletes _everything_.
396     // nukes everything in columnB: forever.
397     handler.deleteAllTs(tableAname, rowAname, columnBname, time1, null);
398     handler.deleteAllRowTs(tableAname, rowBname, time2, null);
399 
400     // Assert that the timestamp-related methods retrieve the correct data
401     int size = handler.getVerTs(tableAname, rowAname, columnBname, time1, MAXVERSIONS, null).size();
402     assertEquals(0, size);
403 
404     size = handler.getVerTs(tableAname, rowAname, columnBname, time2, MAXVERSIONS, null).size();
405     assertEquals(1, size);
406 
407     // should be available....
408     assertEquals(handler.get(tableAname, rowAname, columnBname, null).get(0).value, valueCname);
409 
410     assertEquals(0, handler.getRow(tableAname, rowBname, null).size());
411 
412     // Teardown
413     handler.disableTable(tableAname);
414     handler.deleteTable(tableAname);
415   }
416 
417   /**
418    * Tests the four different scanner-opening methods (with and without
419    * a stoprow, with and without a timestamp).
420    *
421    * @throws Exception
422    */
423   public void doTestTableScanners() throws Exception {
424     // Setup
425     ThriftServerRunner.HBaseHandler handler =
426       new ThriftServerRunner.HBaseHandler(UTIL.getConfiguration());
427     handler.createTable(tableAname, getColumnDescriptors());
428 
429     // Apply timestamped Mutations to rowA
430     long time1 = System.currentTimeMillis();
431     handler.mutateRowTs(tableAname, rowAname, getMutations(), time1, null);
432 
433     // Sleep to assure that 'time1' and 'time2' will be different even with a
434     // coarse grained system timer.
435     Thread.sleep(1000);
436 
437     // Apply timestamped BatchMutations for rowA and rowB
438     long time2 = System.currentTimeMillis();
439     handler.mutateRowsTs(tableAname, getBatchMutations(), time2, null);
440 
441     time1 += 1;
442 
443     // Test a scanner on all rows and all columns, no timestamp
444     int scanner1 = handler.scannerOpen(tableAname, rowAname, getColumnList(true, true), null);
445     TRowResult rowResult1a = handler.scannerGet(scanner1).get(0);
446     assertEquals(rowResult1a.row, rowAname);
447     // This used to be '1'.  I don't know why when we are asking for two columns
448     // and when the mutations above would seem to add two columns to the row.
449     // -- St.Ack 05/12/2009
450     assertEquals(rowResult1a.columns.size(), 1);
451     assertEquals(rowResult1a.columns.get(columnBname).value, valueCname);
452 
453     TRowResult rowResult1b = handler.scannerGet(scanner1).get(0);
454     assertEquals(rowResult1b.row, rowBname);
455     assertEquals(rowResult1b.columns.size(), 2);
456     assertEquals(rowResult1b.columns.get(columnAname).value, valueCname);
457     assertEquals(rowResult1b.columns.get(columnBname).value, valueDname);
458     closeScanner(scanner1, handler);
459 
460     // Test a scanner on all rows and all columns, with timestamp
461     int scanner2 = handler.scannerOpenTs(tableAname, rowAname, getColumnList(true, true), time1, null);
462     TRowResult rowResult2a = handler.scannerGet(scanner2).get(0);
463     assertEquals(rowResult2a.columns.size(), 1);
464     // column A deleted, does not exist.
465     //assertTrue(Bytes.equals(rowResult2a.columns.get(columnAname).value, valueAname));
466     assertEquals(rowResult2a.columns.get(columnBname).value, valueBname);
467     closeScanner(scanner2, handler);
468 
469     // Test a scanner on the first row and first column only, no timestamp
470     int scanner3 = handler.scannerOpenWithStop(tableAname, rowAname, rowBname,
471         getColumnList(true, false), null);
472     closeScanner(scanner3, handler);
473 
474     // Test a scanner on the first row and second column only, with timestamp
475     int scanner4 = handler.scannerOpenWithStopTs(tableAname, rowAname, rowBname,
476         getColumnList(false, true), time1, null);
477     TRowResult rowResult4a = handler.scannerGet(scanner4).get(0);
478     assertEquals(rowResult4a.columns.size(), 1);
479     assertEquals(rowResult4a.columns.get(columnBname).value, valueBname);
480 
481     // Test scanner using a TScan object once with sortColumns False and once with sortColumns true
482     TScan scanNoSortColumns = new TScan();
483     scanNoSortColumns.setStartRow(rowAname);
484     scanNoSortColumns.setStopRow(rowBname);
485 
486     int scanner5 = handler.scannerOpenWithScan(tableAname , scanNoSortColumns, null);
487     TRowResult rowResult5 = handler.scannerGet(scanner5).get(0);
488     assertEquals(rowResult5.columns.size(), 1);
489     assertEquals(rowResult5.columns.get(columnBname).value, valueCname);
490 
491     TScan scanSortColumns = new TScan();
492     scanSortColumns.setStartRow(rowAname);
493     scanSortColumns.setStopRow(rowBname);
494     scanSortColumns = scanSortColumns.setSortColumns(true);
495 
496     int scanner6 = handler.scannerOpenWithScan(tableAname ,scanSortColumns, null);
497     TRowResult rowResult6 = handler.scannerGet(scanner6).get(0);
498     assertEquals(rowResult6.sortedColumns.size(), 1);
499     assertEquals(rowResult6.sortedColumns.get(0).getCell().value, valueCname);
500 
501     List<Mutation> rowBmutations = new ArrayList<Mutation>();
502     for (int i = 0; i < 20; i++) {
503       rowBmutations.add(new Mutation(false, asByteBuffer("columnA:" + i), valueCname, true));
504     }
505     ByteBuffer rowC = asByteBuffer("rowC");
506     handler.mutateRow(tableAname, rowC, rowBmutations, null);
507 
508     TScan scanSortMultiColumns = new TScan();
509     scanSortMultiColumns.setStartRow(rowC);
510     scanSortMultiColumns = scanSortMultiColumns.setSortColumns(true);
511     int scanner7 = handler.scannerOpenWithScan(tableAname, scanSortMultiColumns, null);
512     TRowResult rowResult7 = handler.scannerGet(scanner7).get(0);
513 
514     ByteBuffer smallerColumn = asByteBuffer("columnA:");
515     for (int i = 0; i < 20; i++) {
516       ByteBuffer currentColumn = rowResult7.sortedColumns.get(i).columnName;
517       assertTrue(Bytes.compareTo(smallerColumn.array(), currentColumn.array()) < 0);
518       smallerColumn = currentColumn;
519     }
520 
521     // Teardown
522     handler.disableTable(tableAname);
523     handler.deleteTable(tableAname);
524   }
525 
526   /**
527    * For HBASE-2556
528    * Tests for GetTableRegions
529    *
530    * @throws Exception
531    */
532   public void doTestGetTableRegions() throws Exception {
533     ThriftServerRunner.HBaseHandler handler =
534       new ThriftServerRunner.HBaseHandler(UTIL.getConfiguration());
535     doTestGetTableRegions(handler);
536   }
537 
538   public static void doTestGetTableRegions(Hbase.Iface handler)
539       throws Exception {
540     assertEquals(handler.getTableNames().size(), 0);
541     handler.createTable(tableAname, getColumnDescriptors());
542     assertEquals(handler.getTableNames().size(), 1);
543     List<TRegionInfo> regions = handler.getTableRegions(tableAname);
544     int regionCount = regions.size();
545     assertEquals("empty table should have only 1 region, " +
546             "but found " + regionCount, regionCount, 1);
547     LOG.info("Region found:" + regions.get(0));
548     handler.disableTable(tableAname);
549     handler.deleteTable(tableAname);
550     regionCount = handler.getTableRegions(tableAname).size();
551     assertEquals("non-existing table should have 0 region, " +
552             "but found " + regionCount, regionCount, 0);
553   }
554 
555   public void doTestFilterRegistration() throws Exception {
556     Configuration conf = UTIL.getConfiguration();
557 
558     conf.set("hbase.thrift.filters", "MyFilter:filterclass");
559 
560     ThriftServerRunner.registerFilters(conf);
561 
562     Map<String, String> registeredFilters = ParseFilter.getAllFilters();
563 
564     assertEquals("filterclass", registeredFilters.get("MyFilter"));
565   }
566 
567   public void doTestGetRegionInfo() throws Exception {
568     ThriftServerRunner.HBaseHandler handler =
569       new ThriftServerRunner.HBaseHandler(UTIL.getConfiguration());
570     doTestGetRegionInfo(handler);
571   }
572 
573   public static void doTestGetRegionInfo(Hbase.Iface handler) throws Exception {
574     // Create tableA and add two columns to rowA
575     handler.createTable(tableAname, getColumnDescriptors());
576     try {
577       handler.mutateRow(tableAname, rowAname, getMutations(), null);
578       byte[] searchRow = HRegionInfo.createRegionName(
579           TableName.valueOf(tableAname.array()), rowAname.array(),
580           HConstants.NINES, false);
581       TRegionInfo regionInfo = handler.getRegionInfo(ByteBuffer.wrap(searchRow));
582       assertTrue(Bytes.toStringBinary(regionInfo.getName()).startsWith(
583             Bytes.toStringBinary(tableAname)));
584     } finally {
585       handler.disableTable(tableAname);
586       handler.deleteTable(tableAname);
587     }
588   }
589 
590   /**
591    *
592    * @return a List of ColumnDescriptors for use in creating a table.  Has one
593    * default ColumnDescriptor and one ColumnDescriptor with fewer versions
594    */
595   private static List<ColumnDescriptor> getColumnDescriptors() {
596     ArrayList<ColumnDescriptor> cDescriptors = new ArrayList<ColumnDescriptor>();
597 
598     // A default ColumnDescriptor
599     ColumnDescriptor cDescA = new ColumnDescriptor();
600     cDescA.name = columnAname;
601     cDescriptors.add(cDescA);
602 
603     // A slightly customized ColumnDescriptor (only 2 versions)
604     ColumnDescriptor cDescB = new ColumnDescriptor(columnBname, 2, "NONE",
605         false, "NONE", 0, 0, false, -1);
606     cDescriptors.add(cDescB);
607 
608     return cDescriptors;
609   }
610 
611   /**
612    *
613    * @param includeA whether or not to include columnA
614    * @param includeB whether or not to include columnB
615    * @return a List of column names for use in retrieving a scanner
616    */
617   private List<ByteBuffer> getColumnList(boolean includeA, boolean includeB) {
618     List<ByteBuffer> columnList = new ArrayList<ByteBuffer>();
619     if (includeA) columnList.add(columnAname);
620     if (includeB) columnList.add(columnBname);
621     return columnList;
622   }
623 
624   /**
625    *
626    * @return a List of Mutations for a row, with columnA having valueA
627    * and columnB having valueB
628    */
629   private static List<Mutation> getMutations() {
630     List<Mutation> mutations = new ArrayList<Mutation>();
631     mutations.add(new Mutation(false, columnAname, valueAname, true));
632     mutations.add(new Mutation(false, columnBname, valueBname, true));
633     return mutations;
634   }
635 
636   /**
637    *
638    * @return a List of BatchMutations with the following effects:
639    * (rowA, columnA): delete
640    * (rowA, columnB): place valueC
641    * (rowB, columnA): place valueC
642    * (rowB, columnB): place valueD
643    */
644   private static List<BatchMutation> getBatchMutations() {
645     List<BatchMutation> batchMutations = new ArrayList<BatchMutation>();
646 
647     // Mutations to rowA.  You can't mix delete and put anymore.
648     List<Mutation> rowAmutations = new ArrayList<Mutation>();
649     rowAmutations.add(new Mutation(true, columnAname, null, true));
650     batchMutations.add(new BatchMutation(rowAname, rowAmutations));
651 
652     rowAmutations = new ArrayList<Mutation>();
653     rowAmutations.add(new Mutation(false, columnBname, valueCname, true));
654     batchMutations.add(new BatchMutation(rowAname, rowAmutations));
655 
656     // Mutations to rowB
657     List<Mutation> rowBmutations = new ArrayList<Mutation>();
658     rowBmutations.add(new Mutation(false, columnAname, valueCname, true));
659     rowBmutations.add(new Mutation(false, columnBname, valueDname, true));
660     batchMutations.add(new BatchMutation(rowBname, rowBmutations));
661 
662     return batchMutations;
663   }
664 
665   /**
666    * Asserts that the passed scanner is exhausted, and then closes
667    * the scanner.
668    *
669    * @param scannerId the scanner to close
670    * @param handler the HBaseHandler interfacing to HBase
671    * @throws Exception
672    */
673   private void closeScanner(
674       int scannerId, ThriftServerRunner.HBaseHandler handler) throws Exception {
675     handler.scannerGet(scannerId);
676     handler.scannerClose(scannerId);
677   }
678 
679 }
680