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    private 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   @Test
688   public void testPutTTL() throws Exception {
689     ThriftHBaseServiceHandler handler = createHandler();
690     byte[] rowName = "testPutTTL".getBytes();
691     ByteBuffer table = wrap(tableAname);
692     List<TColumnValue> columnValues = new ArrayList<TColumnValue>();
693 
694     // Add some dummy data
695     columnValues.add(
696         new TColumnValue(
697             wrap(familyAname),
698             wrap(qualifierAname),
699             wrap(Bytes.toBytes(1L))));
700 
701 
702     TPut put = new TPut(wrap(rowName), columnValues);
703     put.setColumnValues(columnValues);
704 
705     Map<ByteBuffer, ByteBuffer> attributes = new HashMap<>();
706 
707     // Time in ms for the kv's to live.
708     long ttlTimeMs = 2000L;
709 
710     // the _ttl attribute is a number of ms ttl for key values in this put.
711     attributes.put(wrap(Bytes.toBytes("_ttl")), wrap(Bytes.toBytes(ttlTimeMs)));
712     // Attach the attributes
713     put.setAttributes(attributes);
714     // Send it.
715     handler.put(table, put);
716 
717     // Now get the data back
718     TGet getOne = new TGet(wrap(rowName));
719     TResult resultOne = handler.get(table, getOne);
720 
721     // It's there.
722     assertArrayEquals(rowName, resultOne.getRow());
723     assertEquals(1, resultOne.getColumnValuesSize());
724 
725     // Sleep 30 seconds just to make 100% sure that the key value should be expired.
726     Thread.sleep(ttlTimeMs * 15);
727 
728     TGet getTwo = new TGet(wrap(rowName));
729     TResult resultTwo = handler.get(table, getTwo);
730 
731 
732     // Nothing should be there since it's ttl'd out.
733     assertNull(resultTwo.getRow());
734     assertEquals(0, resultTwo.getColumnValuesSize());
735   }
736 
737   /**
738    * Padding numbers to make comparison of sort order easier in a for loop
739    *
740    * @param n  The number to pad.
741    * @param pad  The length to pad up to.
742    * @return The padded number as a string.
743    */
744   private String pad(int n, byte pad) {
745     String res = Integer.toString(n);
746     while (res.length() < pad) res = "0" + res;
747     return res;
748   }
749 
750   @Test
751   public void testScanWithBatchSize() throws Exception {
752     ThriftHBaseServiceHandler handler = createHandler();
753     ByteBuffer table = wrap(tableAname);
754 
755     // insert data
756     List<TColumnValue> columnValues = new ArrayList<TColumnValue>();
757     for (int i = 0; i < 100; i++) {
758       String colNum = pad(i, (byte) 3);
759       TColumnValue columnValue = new TColumnValue(wrap(familyAname),
760         wrap(("col" + colNum).getBytes()), wrap(("val" + colNum).getBytes()));
761       columnValues.add(columnValue);
762     }
763     TPut put = new TPut(wrap(("testScanWithBatchSize").getBytes()), columnValues);
764     handler.put(table, put);
765 
766     // create scan instance
767     TScan scan = new TScan();
768     List<TColumn> columns = new ArrayList<TColumn>();
769     TColumn column = new TColumn();
770     column.setFamily(familyAname);
771     columns.add(column);
772     scan.setColumns(columns);
773     scan.setStartRow("testScanWithBatchSize".getBytes());
774     scan.setStopRow("testScanWithBatchSize\uffff".getBytes());
775     // set batch size to 10 columns per call
776     scan.setBatchSize(10);
777 
778     // get scanner
779     int scanId = handler.openScanner(table, scan);
780     List<TResult> results = null;
781     for (int i = 0; i < 10; i++) {
782       // get batch for single row (10x10 is what we expect)
783       results = handler.getScannerRows(scanId, 1);
784       assertEquals(1, results.size());
785       // check length of batch
786       List<TColumnValue> cols = results.get(0).getColumnValues();
787       assertEquals(10, cols.size());
788       // check if the columns are returned and in order
789       for (int y = 0; y < 10; y++) {
790         int colNum = y + (10 * i);
791         String colNumPad = pad(colNum, (byte) 3);
792         assertArrayEquals(("col" + colNumPad).getBytes(), cols.get(y).getQualifier());
793       }
794     }
795 
796     // check that we are at the end of the scan
797     results = handler.getScannerRows(scanId, 1);
798     assertEquals(0, results.size());
799 
800     // close scanner and check that it was indeed closed
801     handler.closeScanner(scanId);
802     try {
803       handler.getScannerRows(scanId, 1);
804       fail("Scanner id should be invalid");
805     } catch (TIllegalArgument e) {
806     }
807   }
808 
809   @Test
810   public void testGetScannerResults() throws Exception {
811     ThriftHBaseServiceHandler handler = createHandler();
812     ByteBuffer table = wrap(tableAname);
813 
814     // insert data
815     TColumnValue columnValue =
816         new TColumnValue(wrap(familyAname), wrap(qualifierAname), wrap(valueAname));
817     List<TColumnValue> columnValues = new ArrayList<TColumnValue>();
818     columnValues.add(columnValue);
819     for (int i = 0; i < 20; i++) {
820       TPut put =
821           new TPut(wrap(("testGetScannerResults" + pad(i, (byte) 2)).getBytes()), columnValues);
822       handler.put(table, put);
823     }
824 
825     // create scan instance
826     TScan scan = new TScan();
827     List<TColumn> columns = new ArrayList<TColumn>();
828     TColumn column = new TColumn();
829     column.setFamily(familyAname);
830     column.setQualifier(qualifierAname);
831     columns.add(column);
832     scan.setColumns(columns);
833     scan.setStartRow("testGetScannerResults".getBytes());
834 
835     // get 5 rows and check the returned results
836     scan.setStopRow("testGetScannerResults05".getBytes());
837     List<TResult> results = handler.getScannerResults(table, scan, 5);
838     assertEquals(5, results.size());
839     for (int i = 0; i < 5; i++) {
840       // check if the rows are returned and in order
841       assertArrayEquals(("testGetScannerResults" + pad(i, (byte) 2)).getBytes(), results.get(i)
842           .getRow());
843     }
844 
845     // get 10 rows and check the returned results
846     scan.setStopRow("testGetScannerResults10".getBytes());
847     results = handler.getScannerResults(table, scan, 10);
848     assertEquals(10, results.size());
849     for (int i = 0; i < 10; i++) {
850       // check if the rows are returned and in order
851       assertArrayEquals(("testGetScannerResults" + pad(i, (byte) 2)).getBytes(), results.get(i)
852           .getRow());
853     }
854 
855     // get 20 rows and check the returned results
856     scan.setStopRow("testGetScannerResults20".getBytes());
857     results = handler.getScannerResults(table, scan, 20);
858     assertEquals(20, results.size());
859     for (int i = 0; i < 20; i++) {
860       // check if the rows are returned and in order
861       assertArrayEquals(("testGetScannerResults" + pad(i, (byte) 2)).getBytes(), results.get(i)
862           .getRow());
863     }
864 
865     // reverse scan
866     scan = new TScan();
867     scan.setColumns(columns);
868     scan.setReversed(true);
869     scan.setStartRow("testGetScannerResults20".getBytes());
870     scan.setStopRow("testGetScannerResults".getBytes());
871     results = handler.getScannerResults(table, scan, 20);
872     assertEquals(20, results.size());
873     for (int i = 0; i < 20; i++) {
874       // check if the rows are returned and in order
875       assertArrayEquals(("testGetScannerResults" + pad(19 - i, (byte) 2)).getBytes(), results.get(i)
876           .getRow());
877     }
878  }
879 
880   @Test
881   public void testFilterRegistration() throws Exception {
882     Configuration conf = UTIL.getConfiguration();
883     conf.set("hbase.thrift.filters", "MyFilter:filterclass");
884     ThriftServer.registerFilters(conf);
885     Map<String, String> registeredFilters = ParseFilter.getAllFilters();
886     assertEquals("filterclass", registeredFilters.get("MyFilter"));
887   }
888 
889   @Test
890   public void testMetrics() throws Exception {
891     Configuration conf = UTIL.getConfiguration();
892     ThriftMetrics metrics = getMetrics(conf);
893     ThriftHBaseServiceHandler hbaseHandler = createHandler();
894     THBaseService.Iface handler =
895         ThriftHBaseServiceHandler.newInstance(hbaseHandler, metrics);
896     byte[] rowName = "testMetrics".getBytes();
897     ByteBuffer table = wrap(tableAname);
898 
899     TGet get = new TGet(wrap(rowName));
900     assertFalse(handler.exists(table, get));
901 
902     List<TColumnValue> columnValues = new ArrayList<TColumnValue>();
903     columnValues.add(new TColumnValue(wrap(familyAname), wrap(qualifierAname), wrap(valueAname)));
904     columnValues.add(new TColumnValue(wrap(familyBname), wrap(qualifierBname),  wrap(valueBname)));
905     TPut put = new TPut(wrap(rowName), columnValues);
906     put.setColumnValues(columnValues);
907 
908     handler.put(table, put);
909 
910     assertTrue(handler.exists(table, get));
911     metricsHelper.assertCounter("put_num_ops", 1, metrics.getSource());
912     metricsHelper.assertCounter( "exists_num_ops", 2, metrics.getSource());
913   }
914 
915   private static ThriftMetrics getMetrics(Configuration conf) throws Exception {
916     ThriftMetrics m = new ThriftMetrics(conf, ThriftMetrics.ThriftServerType.TWO);
917     m.getSource().init(); //Clear all the metrics
918     return m;
919   }
920 
921   @Test
922   public void testAttribute() throws Exception {
923     byte[] rowName = "testAttribute".getBytes();
924     byte[] attributeKey = "attribute1".getBytes();
925     byte[] attributeValue = "value1".getBytes();
926     Map<ByteBuffer, ByteBuffer> attributes = new HashMap<ByteBuffer, ByteBuffer>();
927     attributes.put(wrap(attributeKey), wrap(attributeValue));
928 
929     TGet tGet = new TGet(wrap(rowName));
930     tGet.setAttributes(attributes);
931     Get get = getFromThrift(tGet);
932     assertArrayEquals(get.getAttribute("attribute1"), attributeValue);
933 
934     List<TColumnValue> columnValues = new ArrayList<TColumnValue>();
935     columnValues.add(new TColumnValue(wrap(familyAname), wrap(qualifierAname), wrap(valueAname)));
936     TPut tPut = new TPut(wrap(rowName) , columnValues);
937     tPut.setAttributes(attributes);
938     Put put = putFromThrift(tPut);
939     assertArrayEquals(put.getAttribute("attribute1"), attributeValue);
940 
941     TScan tScan = new TScan();
942     tScan.setAttributes(attributes);
943     Scan scan = scanFromThrift(tScan);
944     assertArrayEquals(scan.getAttribute("attribute1"), attributeValue);
945 
946     List<TColumnIncrement> incrementColumns = new ArrayList<TColumnIncrement>();
947     incrementColumns.add(new TColumnIncrement(wrap(familyAname), wrap(qualifierAname)));
948     TIncrement tIncrement = new TIncrement(wrap(rowName), incrementColumns);
949     tIncrement.setAttributes(attributes);
950     Increment increment = incrementFromThrift(tIncrement);
951     assertArrayEquals(increment.getAttribute("attribute1"), attributeValue);
952 
953     TDelete tDelete = new TDelete(wrap(rowName));
954     tDelete.setAttributes(attributes);
955     Delete delete = deleteFromThrift(tDelete);
956     assertArrayEquals(delete.getAttribute("attribute1"), attributeValue);
957   }
958 
959   /**
960    * Put valueA to a row, make sure put has happened, then create a mutation object to put valueB
961    * and delete ValueA, then check that the row value is only valueB.
962    *
963    * @throws Exception
964    */
965   @Test
966   public void testMutateRow() throws Exception {
967     ThriftHBaseServiceHandler handler = createHandler();
968     byte[] rowName = "testMutateRow".getBytes();
969     ByteBuffer table = wrap(tableAname);
970 
971     List<TColumnValue> columnValuesA = new ArrayList<TColumnValue>();
972     TColumnValue columnValueA = new TColumnValue(wrap(familyAname), wrap(qualifierAname),
973         wrap(valueAname));
974     columnValuesA.add(columnValueA);
975     TPut putA = new TPut(wrap(rowName), columnValuesA);
976     putA.setColumnValues(columnValuesA);
977 
978     handler.put(table,putA);
979 
980     TGet get = new TGet(wrap(rowName));
981     TResult result = handler.get(table, get);
982     assertArrayEquals(rowName, result.getRow());
983     List<TColumnValue> returnedColumnValues = result.getColumnValues();
984 
985     List<TColumnValue> expectedColumnValues = new ArrayList<TColumnValue>();
986     expectedColumnValues.add(columnValueA);
987     assertTColumnValuesEqual(expectedColumnValues, returnedColumnValues);
988 
989     List<TColumnValue> columnValuesB = new ArrayList<TColumnValue>();
990     TColumnValue columnValueB = new TColumnValue(wrap(familyAname), wrap(qualifierBname),
991         wrap(valueBname));
992     columnValuesB.add(columnValueB);
993     TPut putB = new TPut(wrap(rowName), columnValuesB);
994     putB.setColumnValues(columnValuesB);
995 
996     TDelete delete = new TDelete(wrap(rowName));
997     List<TColumn> deleteColumns = new ArrayList<TColumn>();
998     TColumn deleteColumn = new TColumn(wrap(familyAname));
999     deleteColumn.setQualifier(qualifierAname);
1000     deleteColumns.add(deleteColumn);
1001     delete.setColumns(deleteColumns);
1002 
1003     List<TMutation> mutations = new ArrayList<TMutation>();
1004     TMutation mutationA = TMutation.put(putB);
1005     mutations.add(mutationA);
1006 
1007     TMutation mutationB = TMutation.deleteSingle(delete);
1008     mutations.add(mutationB);
1009 
1010     TRowMutations tRowMutations = new TRowMutations(wrap(rowName),mutations);
1011     handler.mutateRow(table,tRowMutations);
1012 
1013     result = handler.get(table, get);
1014     assertArrayEquals(rowName, result.getRow());
1015     returnedColumnValues = result.getColumnValues();
1016 
1017     expectedColumnValues = new ArrayList<TColumnValue>();
1018     expectedColumnValues.add(columnValueB);
1019     assertTColumnValuesEqual(expectedColumnValues, returnedColumnValues);
1020   }
1021 
1022   /**
1023    * Create TPut, TDelete , TIncrement objects, set durability then call ThriftUtility
1024    * functions to get Put , Delete and Increment respectively. Use getDurability to make sure
1025    * the returned objects have the appropriate durability setting.
1026    *
1027    * @throws Exception
1028    */
1029   @Test
1030   public void testDurability() throws Exception {
1031     byte[] rowName = "testDurability".getBytes();
1032     List<TColumnValue> columnValues = new ArrayList<TColumnValue>();
1033     columnValues.add(new TColumnValue(wrap(familyAname), wrap(qualifierAname), wrap(valueAname)));
1034 
1035     List<TColumnIncrement> incrementColumns = new ArrayList<TColumnIncrement>();
1036     incrementColumns.add(new TColumnIncrement(wrap(familyAname), wrap(qualifierAname)));
1037 
1038     TDelete tDelete = new TDelete(wrap(rowName));
1039     tDelete.setDurability(TDurability.SKIP_WAL);
1040     Delete delete = deleteFromThrift(tDelete);
1041     assertEquals(delete.getDurability(), Durability.SKIP_WAL);
1042 
1043     tDelete.setDurability(TDurability.ASYNC_WAL);
1044     delete = deleteFromThrift(tDelete);
1045     assertEquals(delete.getDurability(), Durability.ASYNC_WAL);
1046 
1047     tDelete.setDurability(TDurability.SYNC_WAL);
1048     delete = deleteFromThrift(tDelete);
1049     assertEquals(delete.getDurability(), Durability.SYNC_WAL);
1050 
1051     tDelete.setDurability(TDurability.FSYNC_WAL);
1052     delete = deleteFromThrift(tDelete);
1053     assertEquals(delete.getDurability(), Durability.FSYNC_WAL);
1054 
1055     TPut tPut = new TPut(wrap(rowName), columnValues);
1056     tPut.setDurability(TDurability.SKIP_WAL);
1057     Put put = putFromThrift(tPut);
1058     assertEquals(put.getDurability(), Durability.SKIP_WAL);
1059 
1060     tPut.setDurability(TDurability.ASYNC_WAL);
1061     put = putFromThrift(tPut);
1062     assertEquals(put.getDurability(), Durability.ASYNC_WAL);
1063 
1064     tPut.setDurability(TDurability.SYNC_WAL);
1065     put = putFromThrift(tPut);
1066     assertEquals(put.getDurability(), Durability.SYNC_WAL);
1067 
1068     tPut.setDurability(TDurability.FSYNC_WAL);
1069     put = putFromThrift(tPut);
1070     assertEquals(put.getDurability(), Durability.FSYNC_WAL);
1071 
1072     TIncrement tIncrement = new TIncrement(wrap(rowName), incrementColumns);
1073 
1074     tIncrement.setDurability(TDurability.SKIP_WAL);
1075     Increment increment = incrementFromThrift(tIncrement);
1076     assertEquals(increment.getDurability(), Durability.SKIP_WAL);
1077 
1078     tIncrement.setDurability(TDurability.ASYNC_WAL);
1079     increment = incrementFromThrift(tIncrement);
1080     assertEquals(increment.getDurability(), Durability.ASYNC_WAL);
1081 
1082     tIncrement.setDurability(TDurability.SYNC_WAL);
1083     increment = incrementFromThrift(tIncrement);
1084     assertEquals(increment.getDurability(), Durability.SYNC_WAL);
1085 
1086     tIncrement.setDurability(TDurability.FSYNC_WAL);
1087     increment = incrementFromThrift(tIncrement);
1088     assertEquals(increment.getDurability(), Durability.FSYNC_WAL);
1089   }
1090 }
1091