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