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.thrift2;
20  
21  import org.apache.commons.logging.Log;
22  import org.apache.commons.logging.LogFactory;
23  import org.apache.hadoop.conf.Configuration;
24  import org.apache.hadoop.hbase.CompatibilityFactory;
25  import org.apache.hadoop.hbase.HBaseTestingUtility;
26  import org.apache.hadoop.hbase.HColumnDescriptor;
27  import org.apache.hadoop.hbase.HTableDescriptor;
28  import org.apache.hadoop.hbase.MediumTests;
29  import org.apache.hadoop.hbase.TableName;
30  import org.apache.hadoop.hbase.client.Get;
31  import org.apache.hadoop.hbase.client.HBaseAdmin;
32  import org.apache.hadoop.hbase.client.Put;
33  import org.apache.hadoop.hbase.client.Scan;
34  import org.apache.hadoop.hbase.client.Increment;
35  import org.apache.hadoop.hbase.client.Delete;
36  import org.apache.hadoop.hbase.client.Durability;
37  import org.apache.hadoop.hbase.filter.ParseFilter;
38  import org.apache.hadoop.hbase.test.MetricsAssertHelper;
39  import org.apache.hadoop.hbase.thrift.ThriftMetrics;
40  import org.apache.hadoop.hbase.thrift2.generated.TAppend;
41  import org.apache.hadoop.hbase.thrift2.generated.TColumn;
42  import org.apache.hadoop.hbase.thrift2.generated.TColumnIncrement;
43  import org.apache.hadoop.hbase.thrift2.generated.TColumnValue;
44  import org.apache.hadoop.hbase.thrift2.generated.TDelete;
45  import org.apache.hadoop.hbase.thrift2.generated.TDeleteType;
46  import org.apache.hadoop.hbase.thrift2.generated.TGet;
47  import org.apache.hadoop.hbase.thrift2.generated.THBaseService;
48  import org.apache.hadoop.hbase.thrift2.generated.TIOError;
49  import org.apache.hadoop.hbase.thrift2.generated.TIllegalArgument;
50  import org.apache.hadoop.hbase.thrift2.generated.TIncrement;
51  import org.apache.hadoop.hbase.thrift2.generated.TPut;
52  import org.apache.hadoop.hbase.thrift2.generated.TResult;
53  import org.apache.hadoop.hbase.thrift2.generated.TScan;
54  import org.apache.hadoop.hbase.thrift2.generated.TMutation;
55  import org.apache.hadoop.hbase.thrift2.generated.TRowMutations;
56  import org.apache.hadoop.hbase.thrift2.generated.TDurability;
57  import org.apache.hadoop.hbase.util.Bytes;
58  import org.apache.thrift.TException;
59  import org.junit.AfterClass;
60  import org.junit.Before;
61  import org.junit.BeforeClass;
62  import org.junit.Test;
63  import org.junit.experimental.categories.Category;
64  
65  import java.nio.ByteBuffer;
66  import java.util.ArrayList;
67  import java.util.Collections;
68  import java.util.Comparator;
69  import java.util.List;
70  import java.util.Map;
71  import java.util.HashMap;
72  
73  import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.getFromThrift;
74  import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.putFromThrift;
75  import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.scanFromThrift;
76  import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.incrementFromThrift;
77  import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.deleteFromThrift;
78  import static org.junit.Assert.*;
79  import static java.nio.ByteBuffer.wrap;
80  
81  /**
82   * Unit testing for ThriftServer.HBaseHandler, a part of the org.apache.hadoop.hbase.thrift2
83   * package.
84   */
85  @Category(MediumTests.class)
86  public class TestThriftHBaseServiceHandler {
87  
88    public static final Log LOG = LogFactory.getLog(TestThriftHBaseServiceHandler.class);
89    private static final HBaseTestingUtility UTIL = new HBaseTestingUtility();
90  
91    // Static names for tables, columns, rows, and values
92    private static byte[] tableAname = Bytes.toBytes("tableA");
93    private static byte[] familyAname = Bytes.toBytes("familyA");
94    private static byte[] familyBname = Bytes.toBytes("familyB");
95    private static byte[] qualifierAname = Bytes.toBytes("qualifierA");
96    private static byte[] qualifierBname = Bytes.toBytes("qualifierB");
97    private static byte[] valueAname = Bytes.toBytes("valueA");
98    private static byte[] valueBname = Bytes.toBytes("valueB");
99    private static HColumnDescriptor[] families = new HColumnDescriptor[] {
100       new HColumnDescriptor(familyAname).setMaxVersions(3),
101       new HColumnDescriptor(familyBname).setMaxVersions(2)
102   };
103 
104 
105   private static final MetricsAssertHelper metricsHelper =
106       CompatibilityFactory.getInstance(MetricsAssertHelper.class);
107 
108 
109   public void assertTColumnValuesEqual(List<TColumnValue> columnValuesA,
110       List<TColumnValue> columnValuesB) {
111     assertEquals(columnValuesA.size(), columnValuesB.size());
112     Comparator<TColumnValue> comparator = new Comparator<TColumnValue>() {
113       @Override
114       public int compare(TColumnValue o1, TColumnValue o2) {
115         return Bytes.compareTo(Bytes.add(o1.getFamily(), o1.getQualifier()),
116             Bytes.add(o2.getFamily(), o2.getQualifier()));
117       }
118     };
119     Collections.sort(columnValuesA, comparator);
120     Collections.sort(columnValuesB, comparator);
121 
122     for (int i = 0; i < columnValuesA.size(); i++) {
123       TColumnValue a = columnValuesA.get(i);
124       TColumnValue b = columnValuesB.get(i);
125       assertArrayEquals(a.getFamily(), b.getFamily());
126       assertArrayEquals(a.getQualifier(), b.getQualifier());
127       assertArrayEquals(a.getValue(), b.getValue());
128     }
129   }
130 
131   @BeforeClass
132   public static void beforeClass() throws Exception {
133     UTIL.startMiniCluster();
134     HBaseAdmin admin = new HBaseAdmin(UTIL.getConfiguration());
135     HTableDescriptor tableDescriptor = new HTableDescriptor(TableName.valueOf(tableAname));
136     for (HColumnDescriptor family : families) {
137       tableDescriptor.addFamily(family);
138     }
139     admin.createTable(tableDescriptor);
140   }
141 
142   @AfterClass
143   public static void afterClass() throws Exception {
144     UTIL.shutdownMiniCluster();
145   }
146 
147   @Before
148   public void setup() throws Exception {
149 
150   }
151 
152   private ThriftHBaseServiceHandler createHandler() {
153     return new ThriftHBaseServiceHandler(UTIL.getConfiguration());
154   }
155 
156   @Test
157   public void testExists() throws TIOError, TException {
158     ThriftHBaseServiceHandler handler = createHandler();
159     byte[] rowName = "testExists".getBytes();
160     ByteBuffer table = wrap(tableAname);
161 
162     TGet get = new TGet(wrap(rowName));
163     assertFalse(handler.exists(table, get));
164 
165     List<TColumnValue> columnValues = new ArrayList<TColumnValue>();
166     columnValues.add(new TColumnValue(wrap(familyAname), wrap(qualifierAname), wrap(valueAname)));
167     columnValues.add(new TColumnValue(wrap(familyBname), wrap(qualifierBname), wrap(valueBname)));
168     TPut put = new TPut(wrap(rowName), columnValues);
169     put.setColumnValues(columnValues);
170 
171     handler.put(table, put);
172 
173     assertTrue(handler.exists(table, get));
174   }
175 
176   @Test
177   public void testPutGet() throws Exception {
178     ThriftHBaseServiceHandler handler = createHandler();
179     byte[] rowName = "testPutGet".getBytes();
180     ByteBuffer table = wrap(tableAname);
181 
182     List<TColumnValue> columnValues = new ArrayList<TColumnValue>();
183     columnValues.add(new TColumnValue(wrap(familyAname), wrap(qualifierAname), wrap(valueAname)));
184     columnValues.add(new TColumnValue(wrap(familyBname), wrap(qualifierBname), wrap(valueBname)));
185     TPut put = new TPut(wrap(rowName), columnValues);
186 
187     put.setColumnValues(columnValues);
188 
189     handler.put(table, put);
190 
191     TGet get = new TGet(wrap(rowName));
192 
193     TResult result = handler.get(table, get);
194     assertArrayEquals(rowName, result.getRow());
195     List<TColumnValue> returnedColumnValues = result.getColumnValues();
196     assertTColumnValuesEqual(columnValues, returnedColumnValues);
197   }
198 
199   @Test
200   public void testPutGetMultiple() throws Exception {
201     ThriftHBaseServiceHandler handler = createHandler();
202     ByteBuffer table = wrap(tableAname);
203     byte[] rowName1 = "testPutGetMultiple1".getBytes();
204     byte[] rowName2 = "testPutGetMultiple2".getBytes();
205 
206     List<TColumnValue> columnValues = new ArrayList<TColumnValue>();
207     columnValues.add(new TColumnValue(wrap(familyAname), wrap(qualifierAname), wrap(valueAname)));
208     columnValues.add(new TColumnValue(wrap(familyBname), wrap(qualifierBname), wrap(valueBname)));
209     List<TPut> puts = new ArrayList<TPut>();
210     puts.add(new TPut(wrap(rowName1), columnValues));
211     puts.add(new TPut(wrap(rowName2), columnValues));
212 
213     handler.putMultiple(table, puts);
214 
215     List<TGet> gets = new ArrayList<TGet>();
216     gets.add(new TGet(wrap(rowName1)));
217     gets.add(new TGet(wrap(rowName2)));
218 
219     List<TResult> results = handler.getMultiple(table, gets);
220     assertEquals(2, results.size());
221 
222     assertArrayEquals(rowName1, results.get(0).getRow());
223     assertTColumnValuesEqual(columnValues, results.get(0).getColumnValues());
224 
225     assertArrayEquals(rowName2, results.get(1).getRow());
226     assertTColumnValuesEqual(columnValues, results.get(1).getColumnValues());
227   }
228 
229   @Test
230   public void testDeleteMultiple() throws Exception {
231     ThriftHBaseServiceHandler handler = createHandler();
232     ByteBuffer table = wrap(tableAname);
233     byte[] rowName1 = "testDeleteMultiple1".getBytes();
234     byte[] rowName2 = "testDeleteMultiple2".getBytes();
235 
236     List<TColumnValue> columnValues = new ArrayList<TColumnValue>();
237     columnValues.add(new TColumnValue(wrap(familyAname), wrap(qualifierAname), wrap(valueAname)));
238     columnValues.add(new TColumnValue(wrap(familyBname), wrap(qualifierBname), wrap(valueBname)));
239     List<TPut> puts = new ArrayList<TPut>();
240     puts.add(new TPut(wrap(rowName1), columnValues));
241     puts.add(new TPut(wrap(rowName2), columnValues));
242 
243     handler.putMultiple(table, puts);
244 
245     List<TDelete> deletes = new ArrayList<TDelete>();
246     deletes.add(new TDelete(wrap(rowName1)));
247     deletes.add(new TDelete(wrap(rowName2)));
248 
249     List<TDelete> deleteResults = handler.deleteMultiple(table, deletes);
250     // 0 means they were all successfully applies
251     assertEquals(0, deleteResults.size());
252 
253     assertFalse(handler.exists(table, new TGet(wrap(rowName1))));
254     assertFalse(handler.exists(table, new TGet(wrap(rowName2))));
255   }
256 
257   @Test
258   public void testDelete() throws Exception {
259     ThriftHBaseServiceHandler handler = createHandler();
260     byte[] rowName = "testDelete".getBytes();
261     ByteBuffer table = wrap(tableAname);
262 
263     List<TColumnValue> columnValues = new ArrayList<TColumnValue>();
264     TColumnValue columnValueA = new TColumnValue(wrap(familyAname), wrap(qualifierAname),
265       wrap(valueAname));
266     TColumnValue columnValueB = new TColumnValue(wrap(familyBname), wrap(qualifierBname),
267       wrap(valueBname));
268     columnValues.add(columnValueA);
269     columnValues.add(columnValueB);
270     TPut put = new TPut(wrap(rowName), columnValues);
271 
272     put.setColumnValues(columnValues);
273 
274     handler.put(table, put);
275 
276     TDelete delete = new TDelete(wrap(rowName));
277     List<TColumn> deleteColumns = new ArrayList<TColumn>();
278     TColumn deleteColumn = new TColumn(wrap(familyAname));
279     deleteColumn.setQualifier(qualifierAname);
280     deleteColumns.add(deleteColumn);
281     delete.setColumns(deleteColumns);
282 
283     handler.deleteSingle(table, delete);
284 
285     TGet get = new TGet(wrap(rowName));
286     TResult result = handler.get(table, get);
287     assertArrayEquals(rowName, result.getRow());
288     List<TColumnValue> returnedColumnValues = result.getColumnValues();
289     List<TColumnValue> expectedColumnValues = new ArrayList<TColumnValue>();
290     expectedColumnValues.add(columnValueB);
291     assertTColumnValuesEqual(expectedColumnValues, returnedColumnValues);
292   }
293 
294   @Test
295   public void testDeleteAllTimestamps() throws Exception {
296     ThriftHBaseServiceHandler handler = createHandler();
297     byte[] rowName = "testDeleteAllTimestamps".getBytes();
298     ByteBuffer table = wrap(tableAname);
299 
300     List<TColumnValue> columnValues = new ArrayList<TColumnValue>();
301     TColumnValue columnValueA = new TColumnValue(wrap(familyAname), wrap(qualifierAname),
302       wrap(valueAname));
303     columnValueA.setTimestamp(System.currentTimeMillis() - 10);
304     columnValues.add(columnValueA);
305     TPut put = new TPut(wrap(rowName), columnValues);
306 
307     put.setColumnValues(columnValues);
308 
309     handler.put(table, put);
310     columnValueA.setTimestamp(System.currentTimeMillis());
311     handler.put(table, put);
312 
313     TGet get = new TGet(wrap(rowName));
314     get.setMaxVersions(2);
315     TResult result = handler.get(table, get);
316     assertEquals(2, result.getColumnValuesSize());
317 
318     TDelete delete = new TDelete(wrap(rowName));
319     List<TColumn> deleteColumns = new ArrayList<TColumn>();
320     TColumn deleteColumn = new TColumn(wrap(familyAname));
321     deleteColumn.setQualifier(qualifierAname);
322     deleteColumns.add(deleteColumn);
323     delete.setColumns(deleteColumns);
324     delete.setDeleteType(TDeleteType.DELETE_COLUMNS); // This is the default anyway.
325 
326     handler.deleteSingle(table, delete);
327 
328     get = new TGet(wrap(rowName));
329     result = handler.get(table, get);
330     assertNull(result.getRow());
331     assertEquals(0, result.getColumnValuesSize());
332   }
333 
334   @Test
335   public void testDeleteSingleTimestamp() throws Exception {
336     ThriftHBaseServiceHandler handler = createHandler();
337     byte[] rowName = "testDeleteSingleTimestamp".getBytes();
338     ByteBuffer table = wrap(tableAname);
339 
340     long timestamp1 = System.currentTimeMillis() - 10;
341     long timestamp2 = System.currentTimeMillis();
342 
343     List<TColumnValue> columnValues = new ArrayList<TColumnValue>();
344     TColumnValue columnValueA = new TColumnValue(wrap(familyAname), wrap(qualifierAname),
345       wrap(valueAname));
346     columnValueA.setTimestamp(timestamp1);
347     columnValues.add(columnValueA);
348     TPut put = new TPut(wrap(rowName), columnValues);
349 
350     put.setColumnValues(columnValues);
351 
352     handler.put(table, put);
353     columnValueA.setTimestamp(timestamp2);
354     handler.put(table, put);
355 
356     TGet get = new TGet(wrap(rowName));
357     get.setMaxVersions(2);
358     TResult result = handler.get(table, get);
359     assertEquals(2, result.getColumnValuesSize());
360 
361     TDelete delete = new TDelete(wrap(rowName));
362     List<TColumn> deleteColumns = new ArrayList<TColumn>();
363     TColumn deleteColumn = new TColumn(wrap(familyAname));
364     deleteColumn.setQualifier(qualifierAname);
365     deleteColumns.add(deleteColumn);
366     delete.setColumns(deleteColumns);
367     delete.setDeleteType(TDeleteType.DELETE_COLUMN);
368 
369     handler.deleteSingle(table, delete);
370 
371     get = new TGet(wrap(rowName));
372     result = handler.get(table, get);
373     assertArrayEquals(rowName, result.getRow());
374     assertEquals(1, result.getColumnValuesSize());
375     // the older timestamp should remain.
376     assertEquals(timestamp1, result.getColumnValues().get(0).getTimestamp());
377   }
378 
379   @Test
380   public void testIncrement() throws Exception {
381     ThriftHBaseServiceHandler handler = createHandler();
382     byte[] rowName = "testIncrement".getBytes();
383     ByteBuffer table = wrap(tableAname);
384 
385     List<TColumnValue> columnValues = new ArrayList<TColumnValue>();
386     columnValues.add(new TColumnValue(wrap(familyAname), wrap(qualifierAname),
387       wrap(Bytes.toBytes(1L))));
388     TPut put = new TPut(wrap(rowName), columnValues);
389     put.setColumnValues(columnValues);
390     handler.put(table, put);
391 
392     List<TColumnIncrement> incrementColumns = new ArrayList<TColumnIncrement>();
393     incrementColumns.add(new TColumnIncrement(wrap(familyAname), wrap(qualifierAname)));
394     TIncrement increment = new TIncrement(wrap(rowName), incrementColumns);
395     handler.increment(table, increment);
396 
397     TGet get = new TGet(wrap(rowName));
398     TResult result = handler.get(table, get);
399 
400     assertArrayEquals(rowName, result.getRow());
401     assertEquals(1, result.getColumnValuesSize());
402     TColumnValue columnValue = result.getColumnValues().get(0);
403     assertArrayEquals(Bytes.toBytes(2L), columnValue.getValue());
404   }
405 
406   @Test
407   public void testAppend() throws Exception {
408     ThriftHBaseServiceHandler handler = createHandler();
409     byte[] rowName = "testAppend".getBytes();
410     ByteBuffer table = wrap(tableAname);
411     byte[] v1 = Bytes.toBytes("42");
412     byte[] v2 = Bytes.toBytes("23");
413     List<TColumnValue> columnValues = new ArrayList<TColumnValue>();
414     columnValues.add(new TColumnValue(wrap(familyAname), wrap(qualifierAname), wrap(v1)));
415     TPut put = new TPut(wrap(rowName), columnValues);
416     put.setColumnValues(columnValues);
417     handler.put(table, put);
418 
419     List<TColumnValue> appendColumns = new ArrayList<TColumnValue>();
420     appendColumns.add(new TColumnValue(wrap(familyAname), wrap(qualifierAname), wrap(v2)));
421     TAppend append = new TAppend(wrap(rowName), appendColumns);
422     handler.append(table, append);
423 
424     TGet get = new TGet(wrap(rowName));
425     TResult result = handler.get(table, get);
426 
427     assertArrayEquals(rowName, result.getRow());
428     assertEquals(1, result.getColumnValuesSize());
429     TColumnValue columnValue = result.getColumnValues().get(0);
430     assertArrayEquals(Bytes.add(v1, v2), columnValue.getValue());
431   }
432 
433   /**
434    * check that checkAndPut fails if the cell does not exist, then put in the cell, then check
435    * that the checkAndPut succeeds.
436    *
437    * @throws Exception
438    */
439   @Test
440   public void testCheckAndPut() throws Exception {
441     ThriftHBaseServiceHandler handler = createHandler();
442     byte[] rowName = "testCheckAndPut".getBytes();
443     ByteBuffer table = wrap(tableAname);
444 
445     List<TColumnValue> columnValuesA = new ArrayList<TColumnValue>();
446     TColumnValue columnValueA = new TColumnValue(wrap(familyAname), wrap(qualifierAname),
447       wrap(valueAname));
448     columnValuesA.add(columnValueA);
449     TPut putA = new TPut(wrap(rowName), columnValuesA);
450     putA.setColumnValues(columnValuesA);
451 
452     List<TColumnValue> columnValuesB = new ArrayList<TColumnValue>();
453     TColumnValue columnValueB = new TColumnValue(wrap(familyBname), wrap(qualifierBname),
454       wrap(valueBname));
455     columnValuesB.add(columnValueB);
456     TPut putB = new TPut(wrap(rowName), columnValuesB);
457     putB.setColumnValues(columnValuesB);
458 
459     assertFalse(handler.checkAndPut(table, wrap(rowName), wrap(familyAname),
460       wrap(qualifierAname), wrap(valueAname), putB));
461 
462     TGet get = new TGet(wrap(rowName));
463     TResult result = handler.get(table, get);
464     assertEquals(0, result.getColumnValuesSize());
465 
466     handler.put(table, putA);
467 
468     assertTrue(handler.checkAndPut(table, wrap(rowName), wrap(familyAname),
469       wrap(qualifierAname), wrap(valueAname), putB));
470 
471     result = handler.get(table, get);
472     assertArrayEquals(rowName, result.getRow());
473     List<TColumnValue> returnedColumnValues = result.getColumnValues();
474     List<TColumnValue> expectedColumnValues = new ArrayList<TColumnValue>();
475     expectedColumnValues.add(columnValueA);
476     expectedColumnValues.add(columnValueB);
477     assertTColumnValuesEqual(expectedColumnValues, returnedColumnValues);
478   }
479 
480   /**
481    * check that checkAndDelete fails if the cell does not exist, then put in the cell, then
482    * check that the checkAndDelete succeeds.
483    *
484    * @throws Exception
485    */
486   @Test
487   public void testCheckAndDelete() throws Exception {
488     ThriftHBaseServiceHandler handler = createHandler();
489     byte[] rowName = "testCheckAndDelete".getBytes();
490     ByteBuffer table = wrap(tableAname);
491 
492     List<TColumnValue> columnValuesA = new ArrayList<TColumnValue>();
493     TColumnValue columnValueA = new TColumnValue(wrap(familyAname), wrap(qualifierAname),
494       wrap(valueAname));
495     columnValuesA.add(columnValueA);
496     TPut putA = new TPut(wrap(rowName), columnValuesA);
497     putA.setColumnValues(columnValuesA);
498 
499     List<TColumnValue> columnValuesB = new ArrayList<TColumnValue>();
500     TColumnValue columnValueB = new TColumnValue(wrap(familyBname), wrap(qualifierBname),
501       wrap(valueBname));
502     columnValuesB.add(columnValueB);
503     TPut putB = new TPut(wrap(rowName), columnValuesB);
504     putB.setColumnValues(columnValuesB);
505 
506     // put putB so that we know whether the row has been deleted or not
507     handler.put(table, putB);
508 
509     TDelete delete = new TDelete(wrap(rowName));
510 
511     assertFalse(handler.checkAndDelete(table, wrap(rowName), wrap(familyAname),
512         wrap(qualifierAname), wrap(valueAname), delete));
513 
514     TGet get = new TGet(wrap(rowName));
515     TResult result = handler.get(table, get);
516     assertArrayEquals(rowName, result.getRow());
517     assertTColumnValuesEqual(columnValuesB, result.getColumnValues());
518 
519     handler.put(table, putA);
520 
521     assertTrue(handler.checkAndDelete(table, wrap(rowName), wrap(familyAname),
522       wrap(qualifierAname), wrap(valueAname), delete));
523 
524     result = handler.get(table, get);
525     assertFalse(result.isSetRow());
526     assertEquals(0, result.getColumnValuesSize());
527   }
528 
529   @Test
530   public void testScan() throws Exception {
531     ThriftHBaseServiceHandler handler = createHandler();
532     ByteBuffer table = wrap(tableAname);
533 
534     // insert data
535     TColumnValue columnValue = new TColumnValue(wrap(familyAname), wrap(qualifierAname),
536       wrap(valueAname));
537     List<TColumnValue> columnValues = new ArrayList<TColumnValue>();
538     columnValues.add(columnValue);
539     for (int i = 0; i < 10; i++) {
540       TPut put = new TPut(wrap(("testScan" + i).getBytes()), columnValues);
541       handler.put(table, put);
542     }
543 
544     // create scan instance
545     TScan scan = new TScan();
546     List<TColumn> columns = new ArrayList<TColumn>();
547     TColumn column = new TColumn();
548     column.setFamily(familyAname);
549     column.setQualifier(qualifierAname);
550     columns.add(column);
551     scan.setColumns(columns);
552     scan.setStartRow("testScan".getBytes());
553     scan.setStopRow("testScan\uffff".getBytes());
554 
555     // get scanner and rows
556     int scanId = handler.openScanner(table, scan);
557     List<TResult> results = handler.getScannerRows(scanId, 10);
558     assertEquals(10, results.size());
559     for (int i = 0; i < 10; i++) {
560       // check if the rows are returned and in order
561       assertArrayEquals(("testScan" + i).getBytes(), results.get(i).getRow());
562     }
563 
564     // check that we are at the end of the scan
565     results = handler.getScannerRows(scanId, 10);
566     assertEquals(0, results.size());
567 
568     // close scanner and check that it was indeed closed
569     handler.closeScanner(scanId);
570     try {
571       handler.getScannerRows(scanId, 10);
572       fail("Scanner id should be invalid");
573     } catch (TIllegalArgument e) {
574     }
575   }
576 
577   @Test
578   public void testScanWithFilter() throws Exception {
579     ThriftHBaseServiceHandler handler = createHandler();
580     ByteBuffer table = wrap(tableAname);
581 
582     // insert data
583     TColumnValue columnValue = new TColumnValue(wrap(familyAname), wrap(qualifierAname),
584       wrap(valueAname));
585     List<TColumnValue> columnValues = new ArrayList<TColumnValue>();
586     columnValues.add(columnValue);
587     for (int i = 0; i < 10; i++) {
588       TPut put = new TPut(wrap(("testScanWithFilter" + i).getBytes()), columnValues);
589       handler.put(table, put);
590     }
591 
592     // create scan instance with filter
593     TScan scan = new TScan();
594     List<TColumn> columns = new ArrayList<TColumn>();
595     TColumn column = new TColumn();
596     column.setFamily(familyAname);
597     column.setQualifier(qualifierAname);
598     columns.add(column);
599     scan.setColumns(columns);
600     scan.setStartRow("testScanWithFilter".getBytes());
601     scan.setStopRow("testScanWithFilter\uffff".getBytes());
602     // only get the key part
603     scan.setFilterString(wrap(("KeyOnlyFilter()").getBytes()));
604 
605     // get scanner and rows
606     int scanId = handler.openScanner(table, scan);
607     List<TResult> results = handler.getScannerRows(scanId, 10);
608     assertEquals(10, results.size());
609     for (int i = 0; i < 10; i++) {
610       // check if the rows are returned and in order
611       assertArrayEquals(("testScanWithFilter" + i).getBytes(), results.get(i).getRow());
612       // check that the value is indeed stripped by the filter
613       assertEquals(0, results.get(i).getColumnValues().get(0).getValue().length);
614     }
615 
616     // check that we are at the end of the scan
617     results = handler.getScannerRows(scanId, 10);
618     assertEquals(0, results.size());
619 
620     // close scanner and check that it was indeed closed
621     handler.closeScanner(scanId);
622     try {
623       handler.getScannerRows(scanId, 10);
624       fail("Scanner id should be invalid");
625     } catch (TIllegalArgument e) {
626     }
627   }
628 
629   /**
630    * Padding numbers to make comparison of sort order easier in a for loop
631    *
632    * @param n  The number to pad.
633    * @param pad  The length to pad up to.
634    * @return The padded number as a string.
635    */
636   private String pad(int n, byte pad) {
637     String res = Integer.toString(n);
638     while (res.length() < pad) res = "0" + res;
639     return res;
640   }
641 
642   @Test
643   public void testScanWithBatchSize() throws Exception {
644     ThriftHBaseServiceHandler handler = createHandler();
645     ByteBuffer table = wrap(tableAname);
646 
647     // insert data
648     List<TColumnValue> columnValues = new ArrayList<TColumnValue>();
649     for (int i = 0; i < 100; i++) {
650       String colNum = pad(i, (byte) 3);
651       TColumnValue columnValue = new TColumnValue(wrap(familyAname),
652         wrap(("col" + colNum).getBytes()), wrap(("val" + colNum).getBytes()));
653       columnValues.add(columnValue);
654     }
655     TPut put = new TPut(wrap(("testScanWithBatchSize").getBytes()), columnValues);
656     handler.put(table, put);
657 
658     // create scan instance
659     TScan scan = new TScan();
660     List<TColumn> columns = new ArrayList<TColumn>();
661     TColumn column = new TColumn();
662     column.setFamily(familyAname);
663     columns.add(column);
664     scan.setColumns(columns);
665     scan.setStartRow("testScanWithBatchSize".getBytes());
666     scan.setStopRow("testScanWithBatchSize\uffff".getBytes());
667     // set batch size to 10 columns per call
668     scan.setBatchSize(10);
669 
670     // get scanner
671     int scanId = handler.openScanner(table, scan);
672     List<TResult> results = null;
673     for (int i = 0; i < 10; i++) {
674       // get batch for single row (10x10 is what we expect)
675       results = handler.getScannerRows(scanId, 1);
676       assertEquals(1, results.size());
677       // check length of batch
678       List<TColumnValue> cols = results.get(0).getColumnValues();
679       assertEquals(10, cols.size());
680       // check if the columns are returned and in order
681       for (int y = 0; y < 10; y++) {
682         int colNum = y + (10 * i);
683         String colNumPad = pad(colNum, (byte) 3);
684         assertArrayEquals(("col" + colNumPad).getBytes(), cols.get(y).getQualifier());
685       }
686     }
687 
688     // check that we are at the end of the scan
689     results = handler.getScannerRows(scanId, 1);
690     assertEquals(0, results.size());
691 
692     // close scanner and check that it was indeed closed
693     handler.closeScanner(scanId);
694     try {
695       handler.getScannerRows(scanId, 1);
696       fail("Scanner id should be invalid");
697     } catch (TIllegalArgument e) {
698     }
699   }
700 
701   @Test
702   public void testGetScannerResults() throws Exception {
703     ThriftHBaseServiceHandler handler = createHandler();
704     ByteBuffer table = wrap(tableAname);
705 
706     // insert data
707     TColumnValue columnValue =
708         new TColumnValue(wrap(familyAname), wrap(qualifierAname), wrap(valueAname));
709     List<TColumnValue> columnValues = new ArrayList<TColumnValue>();
710     columnValues.add(columnValue);
711     for (int i = 0; i < 20; i++) {
712       TPut put =
713           new TPut(wrap(("testGetScannerResults" + pad(i, (byte) 2)).getBytes()), columnValues);
714       handler.put(table, put);
715     }
716 
717     // create scan instance
718     TScan scan = new TScan();
719     List<TColumn> columns = new ArrayList<TColumn>();
720     TColumn column = new TColumn();
721     column.setFamily(familyAname);
722     column.setQualifier(qualifierAname);
723     columns.add(column);
724     scan.setColumns(columns);
725     scan.setStartRow("testGetScannerResults".getBytes());
726 
727     // get 5 rows and check the returned results
728     scan.setStopRow("testGetScannerResults05".getBytes());
729     List<TResult> results = handler.getScannerResults(table, scan, 5);
730     assertEquals(5, results.size());
731     for (int i = 0; i < 5; i++) {
732       // check if the rows are returned and in order
733       assertArrayEquals(("testGetScannerResults" + pad(i, (byte) 2)).getBytes(), results.get(i)
734           .getRow());
735     }
736 
737     // get 10 rows and check the returned results
738     scan.setStopRow("testGetScannerResults10".getBytes());
739     results = handler.getScannerResults(table, scan, 10);
740     assertEquals(10, results.size());
741     for (int i = 0; i < 10; i++) {
742       // check if the rows are returned and in order
743       assertArrayEquals(("testGetScannerResults" + pad(i, (byte) 2)).getBytes(), results.get(i)
744           .getRow());
745     }
746 
747     // get 20 rows and check the returned results
748     scan.setStopRow("testGetScannerResults20".getBytes());
749     results = handler.getScannerResults(table, scan, 20);
750     assertEquals(20, results.size());
751     for (int i = 0; i < 20; i++) {
752       // check if the rows are returned and in order
753       assertArrayEquals(("testGetScannerResults" + pad(i, (byte) 2)).getBytes(), results.get(i)
754           .getRow());
755     }
756  }
757 
758   @Test
759   public void testFilterRegistration() throws Exception {
760     Configuration conf = UTIL.getConfiguration();
761     conf.set("hbase.thrift.filters", "MyFilter:filterclass");
762     ThriftServer.registerFilters(conf);
763     Map<String, String> registeredFilters = ParseFilter.getAllFilters();
764     assertEquals("filterclass", registeredFilters.get("MyFilter"));
765   }
766 
767   @Test
768   public void testMetrics() throws Exception {
769     Configuration conf = UTIL.getConfiguration();
770     ThriftMetrics metrics = getMetrics(conf);
771     THBaseService.Iface handler =
772         ThriftHBaseServiceHandler.newInstance(conf, metrics);
773     byte[] rowName = "testMetrics".getBytes();
774     ByteBuffer table = wrap(tableAname);
775 
776     TGet get = new TGet(wrap(rowName));
777     assertFalse(handler.exists(table, get));
778 
779     List<TColumnValue> columnValues = new ArrayList<TColumnValue>();
780     columnValues.add(new TColumnValue(wrap(familyAname), wrap(qualifierAname), wrap(valueAname)));
781     columnValues.add(new TColumnValue(wrap(familyBname), wrap(qualifierBname),  wrap(valueBname)));
782     TPut put = new TPut(wrap(rowName), columnValues);
783     put.setColumnValues(columnValues);
784 
785     handler.put(table, put);
786 
787     assertTrue(handler.exists(table, get));
788     metricsHelper.assertCounter("put_num_ops", 1, metrics.getSource());
789     metricsHelper.assertCounter( "exists_num_ops", 2, metrics.getSource());
790   }
791 
792   private static ThriftMetrics getMetrics(Configuration conf) throws Exception {
793     ThriftMetrics m = new ThriftMetrics(conf, ThriftMetrics.ThriftServerType.TWO);
794     m.getSource().init(); //Clear all the metrics
795     return m;
796   }
797 
798   @Test
799   public void testAttribute() throws Exception {
800     byte[] rowName = "testAttribute".getBytes();
801     byte[] attributeKey = "attribute1".getBytes();
802     byte[] attributeValue = "value1".getBytes();
803     Map<ByteBuffer, ByteBuffer> attributes = new HashMap<ByteBuffer, ByteBuffer>();
804     attributes.put(wrap(attributeKey), wrap(attributeValue));
805 
806     TGet tGet = new TGet(wrap(rowName));
807     tGet.setAttributes(attributes);
808     Get get = getFromThrift(tGet);
809     assertArrayEquals(get.getAttribute("attribute1"), attributeValue);
810 
811     List<TColumnValue> columnValues = new ArrayList<TColumnValue>();
812     columnValues.add(new TColumnValue(wrap(familyAname), wrap(qualifierAname), wrap(valueAname)));
813     TPut tPut = new TPut(wrap(rowName) , columnValues);
814     tPut.setAttributes(attributes);
815     Put put = putFromThrift(tPut);
816     assertArrayEquals(put.getAttribute("attribute1"), attributeValue);
817 
818     TScan tScan = new TScan();
819     tScan.setAttributes(attributes);
820     Scan scan = scanFromThrift(tScan);
821     assertArrayEquals(scan.getAttribute("attribute1"), attributeValue);
822 
823     List<TColumnIncrement> incrementColumns = new ArrayList<TColumnIncrement>();
824     incrementColumns.add(new TColumnIncrement(wrap(familyAname), wrap(qualifierAname)));
825     TIncrement tIncrement = new TIncrement(wrap(rowName), incrementColumns);
826     tIncrement.setAttributes(attributes);
827     Increment increment = incrementFromThrift(tIncrement);
828     assertArrayEquals(increment.getAttribute("attribute1"), attributeValue);
829 
830     TDelete tDelete = new TDelete(wrap(rowName));
831     tDelete.setAttributes(attributes);
832     Delete delete = deleteFromThrift(tDelete);
833     assertArrayEquals(delete.getAttribute("attribute1"), attributeValue);
834   }
835 
836   /**
837    * Put valueA to a row, make sure put has happened, then create a mutation object to put valueB
838    * and delete ValueA, then check that the row value is only valueB.
839    *
840    * @throws Exception
841    */
842   @Test
843   public void testMutateRow() throws Exception {
844     ThriftHBaseServiceHandler handler = createHandler();
845     byte[] rowName = "testMutateRow".getBytes();
846     ByteBuffer table = wrap(tableAname);
847 
848     List<TColumnValue> columnValuesA = new ArrayList<TColumnValue>();
849     TColumnValue columnValueA = new TColumnValue(wrap(familyAname), wrap(qualifierAname),
850         wrap(valueAname));
851     columnValuesA.add(columnValueA);
852     TPut putA = new TPut(wrap(rowName), columnValuesA);
853     putA.setColumnValues(columnValuesA);
854 
855     handler.put(table,putA);
856 
857     TGet get = new TGet(wrap(rowName));
858     TResult result = handler.get(table, get);
859     assertArrayEquals(rowName, result.getRow());
860     List<TColumnValue> returnedColumnValues = result.getColumnValues();
861 
862     List<TColumnValue> expectedColumnValues = new ArrayList<TColumnValue>();
863     expectedColumnValues.add(columnValueA);
864     assertTColumnValuesEqual(expectedColumnValues, returnedColumnValues);
865 
866     List<TColumnValue> columnValuesB = new ArrayList<TColumnValue>();
867     TColumnValue columnValueB = new TColumnValue(wrap(familyAname), wrap(qualifierBname),
868         wrap(valueBname));
869     columnValuesB.add(columnValueB);
870     TPut putB = new TPut(wrap(rowName), columnValuesB);
871     putB.setColumnValues(columnValuesB);
872 
873     TDelete delete = new TDelete(wrap(rowName));
874     List<TColumn> deleteColumns = new ArrayList<TColumn>();
875     TColumn deleteColumn = new TColumn(wrap(familyAname));
876     deleteColumn.setQualifier(qualifierAname);
877     deleteColumns.add(deleteColumn);
878     delete.setColumns(deleteColumns);
879 
880     List<TMutation> mutations = new ArrayList<TMutation>();
881     TMutation mutationA = TMutation.put(putB);
882     mutations.add(mutationA);
883 
884     TMutation mutationB = TMutation.deleteSingle(delete);
885     mutations.add(mutationB);
886 
887     TRowMutations tRowMutations = new TRowMutations(wrap(rowName),mutations);
888     handler.mutateRow(table,tRowMutations);
889 
890     result = handler.get(table, get);
891     assertArrayEquals(rowName, result.getRow());
892     returnedColumnValues = result.getColumnValues();
893 
894     expectedColumnValues = new ArrayList<TColumnValue>();
895     expectedColumnValues.add(columnValueB);
896     assertTColumnValuesEqual(expectedColumnValues, returnedColumnValues);
897   }
898 
899   /**
900    * Create TPut, TDelete , TIncrement objects, set durability then call ThriftUtility
901    * functions to get Put , Delete and Increment respectively. Use getDurability to make sure
902    * the returned objects have the appropriate durability setting.
903    *
904    * @throws Exception
905    */
906   @Test
907   public void testDurability() throws Exception {
908     byte[] rowName = "testDurability".getBytes();
909     List<TColumnValue> columnValues = new ArrayList<TColumnValue>();
910     columnValues.add(new TColumnValue(wrap(familyAname), wrap(qualifierAname), wrap(valueAname)));
911 
912     List<TColumnIncrement> incrementColumns = new ArrayList<TColumnIncrement>();
913     incrementColumns.add(new TColumnIncrement(wrap(familyAname), wrap(qualifierAname)));
914 
915     TDelete tDelete = new TDelete(wrap(rowName));
916     tDelete.setDurability(TDurability.SKIP_WAL);
917     Delete delete = deleteFromThrift(tDelete);
918     assertEquals(delete.getDurability(), Durability.SKIP_WAL);
919 
920     tDelete.setDurability(TDurability.ASYNC_WAL);
921     delete = deleteFromThrift(tDelete);
922     assertEquals(delete.getDurability(), Durability.ASYNC_WAL);
923 
924     tDelete.setDurability(TDurability.SYNC_WAL);
925     delete = deleteFromThrift(tDelete);
926     assertEquals(delete.getDurability(), Durability.SYNC_WAL);
927 
928     tDelete.setDurability(TDurability.FSYNC_WAL);
929     delete = deleteFromThrift(tDelete);
930     assertEquals(delete.getDurability(), Durability.FSYNC_WAL);
931 
932     TPut tPut = new TPut(wrap(rowName), columnValues);
933     tPut.setDurability(TDurability.SKIP_WAL);
934     Put put = putFromThrift(tPut);
935     assertEquals(put.getDurability(), Durability.SKIP_WAL);
936 
937     tPut.setDurability(TDurability.ASYNC_WAL);
938     put = putFromThrift(tPut);
939     assertEquals(put.getDurability(), Durability.ASYNC_WAL);
940 
941     tPut.setDurability(TDurability.SYNC_WAL);
942     put = putFromThrift(tPut);
943     assertEquals(put.getDurability(), Durability.SYNC_WAL);
944 
945     tPut.setDurability(TDurability.FSYNC_WAL);
946     put = putFromThrift(tPut);
947     assertEquals(put.getDurability(), Durability.FSYNC_WAL);
948 
949     TIncrement tIncrement = new TIncrement(wrap(rowName), incrementColumns);
950 
951     tIncrement.setDurability(TDurability.SKIP_WAL);
952     Increment increment = incrementFromThrift(tIncrement);
953     assertEquals(increment.getDurability(), Durability.SKIP_WAL);
954 
955     tIncrement.setDurability(TDurability.ASYNC_WAL);
956     increment = incrementFromThrift(tIncrement);
957     assertEquals(increment.getDurability(), Durability.ASYNC_WAL);
958 
959     tIncrement.setDurability(TDurability.SYNC_WAL);
960     increment = incrementFromThrift(tIncrement);
961     assertEquals(increment.getDurability(), Durability.SYNC_WAL);
962 
963     tIncrement.setDurability(TDurability.FSYNC_WAL);
964     increment = incrementFromThrift(tIncrement);
965     assertEquals(increment.getDurability(), Durability.FSYNC_WAL);
966   }
967 }
968