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