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