View Javadoc

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