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 com.google.common.collect.Lists;
22  import org.apache.commons.logging.Log;
23  import org.apache.commons.logging.LogFactory;
24  import org.apache.hadoop.conf.Configuration;
25  import org.apache.hadoop.hbase.Cell;
26  import org.apache.hadoop.hbase.CompatibilityFactory;
27  import org.apache.hadoop.hbase.CoprocessorEnvironment;
28  import org.apache.hadoop.hbase.HBaseTestingUtility;
29  import org.apache.hadoop.hbase.HColumnDescriptor;
30  import org.apache.hadoop.hbase.HTableDescriptor;
31  import org.apache.hadoop.hbase.TableName;
32  import org.apache.hadoop.hbase.client.Admin;
33  import org.apache.hadoop.hbase.client.Get;
34  import org.apache.hadoop.hbase.client.HBaseAdmin;
35  import org.apache.hadoop.hbase.client.Put;
36  import org.apache.hadoop.hbase.client.Scan;
37  import org.apache.hadoop.hbase.client.Increment;
38  import org.apache.hadoop.hbase.client.Delete;
39  import org.apache.hadoop.hbase.client.Durability;
40  import org.apache.hadoop.hbase.client.Table;
41  import org.apache.hadoop.hbase.coprocessor.BaseRegionObserver;
42  import org.apache.hadoop.hbase.coprocessor.ObserverContext;
43  import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
44  import org.apache.hadoop.hbase.filter.ParseFilter;
45  import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos;
46  import org.apache.hadoop.hbase.security.UserProvider;
47  import org.apache.hadoop.hbase.test.MetricsAssertHelper;
48  import org.apache.hadoop.hbase.testclassification.MediumTests;
49  import org.apache.hadoop.hbase.thrift.ErrorThrowingGetObserver;
50  import org.apache.hadoop.hbase.thrift.ThriftMetrics;
51  import org.apache.hadoop.hbase.thrift2.generated.TAppend;
52  import org.apache.hadoop.hbase.thrift2.generated.TColumn;
53  import org.apache.hadoop.hbase.thrift2.generated.TColumnIncrement;
54  import org.apache.hadoop.hbase.thrift2.generated.TColumnValue;
55  import org.apache.hadoop.hbase.thrift2.generated.TCompareOp;
56  import org.apache.hadoop.hbase.thrift2.generated.TDelete;
57  import org.apache.hadoop.hbase.thrift2.generated.TDeleteType;
58  import org.apache.hadoop.hbase.thrift2.generated.TGet;
59  import org.apache.hadoop.hbase.thrift2.generated.THBaseService;
60  import org.apache.hadoop.hbase.thrift2.generated.TIOError;
61  import org.apache.hadoop.hbase.thrift2.generated.TIllegalArgument;
62  import org.apache.hadoop.hbase.thrift2.generated.TIncrement;
63  import org.apache.hadoop.hbase.thrift2.generated.TPut;
64  import org.apache.hadoop.hbase.thrift2.generated.TResult;
65  import org.apache.hadoop.hbase.thrift2.generated.TScan;
66  import org.apache.hadoop.hbase.thrift2.generated.TMutation;
67  import org.apache.hadoop.hbase.thrift2.generated.TRowMutations;
68  import org.apache.hadoop.hbase.thrift2.generated.TDurability;
69  import org.apache.hadoop.hbase.util.Bytes;
70  import org.apache.thrift.TException;
71  import org.junit.AfterClass;
72  import org.junit.Before;
73  import org.junit.BeforeClass;
74  import org.junit.Test;
75  import org.junit.experimental.categories.Category;
76  
77  import java.io.IOException;
78  import java.io.InterruptedIOException;
79  import java.nio.ByteBuffer;
80  import java.util.ArrayList;
81  import java.util.Arrays;
82  import java.util.Collections;
83  import java.util.Comparator;
84  import java.util.List;
85  import java.util.Map;
86  import java.util.HashMap;
87  import java.util.concurrent.TimeUnit;
88  
89  import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.getFromThrift;
90  import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.putFromThrift;
91  import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.scanFromThrift;
92  import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.incrementFromThrift;
93  import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.deleteFromThrift;
94  import static org.junit.Assert.*;
95  import static java.nio.ByteBuffer.wrap;
96  
97  /**
98   * Unit testing for ThriftServer.HBaseHandler, a part of the org.apache.hadoop.hbase.thrift2
99   * package.
100  */
101 @Category(MediumTests.class)
102 public class TestThriftHBaseServiceHandler {
103 
104   private static final Log LOG = LogFactory.getLog(TestThriftHBaseServiceHandler.class);
105   private static final HBaseTestingUtility UTIL = new HBaseTestingUtility();
106 
107   // Static names for tables, columns, rows, and values
108   private static byte[] tableAname = Bytes.toBytes("tableA");
109   private static byte[] familyAname = Bytes.toBytes("familyA");
110   private static byte[] familyBname = Bytes.toBytes("familyB");
111   private static byte[] qualifierAname = Bytes.toBytes("qualifierA");
112   private static byte[] qualifierBname = Bytes.toBytes("qualifierB");
113   private static byte[] valueAname = Bytes.toBytes("valueA");
114   private static byte[] valueBname = Bytes.toBytes("valueB");
115   private static HColumnDescriptor[] families = new HColumnDescriptor[] {
116       new HColumnDescriptor(familyAname).setMaxVersions(3),
117       new HColumnDescriptor(familyBname).setMaxVersions(2)
118   };
119 
120 
121   private static final MetricsAssertHelper metricsHelper =
122       CompatibilityFactory.getInstance(MetricsAssertHelper.class);
123 
124 
125   public void assertTColumnValuesEqual(List<TColumnValue> columnValuesA,
126       List<TColumnValue> columnValuesB) {
127     assertEquals(columnValuesA.size(), columnValuesB.size());
128     Comparator<TColumnValue> comparator = new Comparator<TColumnValue>() {
129       @Override
130       public int compare(TColumnValue o1, TColumnValue o2) {
131         return Bytes.compareTo(Bytes.add(o1.getFamily(), o1.getQualifier()),
132             Bytes.add(o2.getFamily(), o2.getQualifier()));
133       }
134     };
135     Collections.sort(columnValuesA, comparator);
136     Collections.sort(columnValuesB, comparator);
137 
138     for (int i = 0; i < columnValuesA.size(); i++) {
139       TColumnValue a = columnValuesA.get(i);
140       TColumnValue b = columnValuesB.get(i);
141       assertTColumnValueEqual(a, b);
142     }
143   }
144 
145   public void assertTColumnValueEqual(TColumnValue a, TColumnValue b) {
146     assertArrayEquals(a.getFamily(), b.getFamily());
147     assertArrayEquals(a.getQualifier(), b.getQualifier());
148     assertArrayEquals(a.getValue(), b.getValue());
149   }
150 
151   @BeforeClass
152   public static void beforeClass() throws Exception {
153     UTIL.getConfiguration().set("hbase.client.retries.number", "3");
154     UTIL.startMiniCluster();
155     Admin admin = new HBaseAdmin(UTIL.getConfiguration());
156     HTableDescriptor tableDescriptor = new HTableDescriptor(TableName.valueOf(tableAname));
157     for (HColumnDescriptor family : families) {
158       tableDescriptor.addFamily(family);
159     }
160     admin.createTable(tableDescriptor);
161     admin.close();
162   }
163 
164   @AfterClass
165   public static void afterClass() throws Exception {
166     UTIL.shutdownMiniCluster();
167   }
168 
169   @Before
170   public void setup() throws Exception {
171 
172   }
173 
174   private ThriftHBaseServiceHandler createHandler() throws TException {
175     try {
176       Configuration conf = UTIL.getConfiguration();
177       return new ThriftHBaseServiceHandler(conf, UserProvider.instantiate(conf));
178     } catch (IOException ie) {
179       throw new TException(ie);
180     }
181   }
182 
183   @Test
184   public void testExists() throws TIOError, TException {
185     ThriftHBaseServiceHandler handler = createHandler();
186     byte[] rowName = "testExists".getBytes();
187     ByteBuffer table = wrap(tableAname);
188 
189     TGet get = new TGet(wrap(rowName));
190     assertFalse(handler.exists(table, get));
191 
192     List<TColumnValue> columnValues = new ArrayList<TColumnValue>();
193     columnValues.add(new TColumnValue(wrap(familyAname), wrap(qualifierAname), wrap(valueAname)));
194     columnValues.add(new TColumnValue(wrap(familyBname), wrap(qualifierBname), wrap(valueBname)));
195     TPut put = new TPut(wrap(rowName), columnValues);
196     put.setColumnValues(columnValues);
197 
198     handler.put(table, put);
199 
200     assertTrue(handler.exists(table, get));
201   }
202 
203   @Test
204   public void testPutGet() throws Exception {
205     ThriftHBaseServiceHandler handler = createHandler();
206     byte[] rowName = "testPutGet".getBytes();
207     ByteBuffer table = wrap(tableAname);
208 
209     List<TColumnValue> columnValues = new ArrayList<TColumnValue>();
210     columnValues.add(new TColumnValue(wrap(familyAname), wrap(qualifierAname), wrap(valueAname)));
211     columnValues.add(new TColumnValue(wrap(familyBname), wrap(qualifierBname), wrap(valueBname)));
212     TPut put = new TPut(wrap(rowName), columnValues);
213 
214     put.setColumnValues(columnValues);
215 
216     handler.put(table, put);
217 
218     TGet get = new TGet(wrap(rowName));
219 
220     TResult result = handler.get(table, get);
221     assertArrayEquals(rowName, result.getRow());
222     List<TColumnValue> returnedColumnValues = result.getColumnValues();
223     assertTColumnValuesEqual(columnValues, returnedColumnValues);
224   }
225 
226   @Test
227   public void testPutGetMultiple() throws Exception {
228     ThriftHBaseServiceHandler handler = createHandler();
229     ByteBuffer table = wrap(tableAname);
230     byte[] rowName1 = "testPutGetMultiple1".getBytes();
231     byte[] rowName2 = "testPutGetMultiple2".getBytes();
232 
233     List<TColumnValue> columnValues = new ArrayList<TColumnValue>();
234     columnValues.add(new TColumnValue(wrap(familyAname), wrap(qualifierAname), wrap(valueAname)));
235     columnValues.add(new TColumnValue(wrap(familyBname), wrap(qualifierBname), wrap(valueBname)));
236     List<TPut> puts = new ArrayList<TPut>();
237     puts.add(new TPut(wrap(rowName1), columnValues));
238     puts.add(new TPut(wrap(rowName2), columnValues));
239 
240     handler.putMultiple(table, puts);
241 
242     List<TGet> gets = new ArrayList<TGet>();
243     gets.add(new TGet(wrap(rowName1)));
244     gets.add(new TGet(wrap(rowName2)));
245 
246     List<TResult> results = handler.getMultiple(table, gets);
247     assertEquals(2, results.size());
248 
249     assertArrayEquals(rowName1, results.get(0).getRow());
250     assertTColumnValuesEqual(columnValues, results.get(0).getColumnValues());
251 
252     assertArrayEquals(rowName2, results.get(1).getRow());
253     assertTColumnValuesEqual(columnValues, results.get(1).getColumnValues());
254   }
255 
256   @Test
257   public void testDeleteMultiple() throws Exception {
258     ThriftHBaseServiceHandler handler = createHandler();
259     ByteBuffer table = wrap(tableAname);
260     byte[] rowName1 = "testDeleteMultiple1".getBytes();
261     byte[] rowName2 = "testDeleteMultiple2".getBytes();
262 
263     List<TColumnValue> columnValues = new ArrayList<TColumnValue>();
264     columnValues.add(new TColumnValue(wrap(familyAname), wrap(qualifierAname), wrap(valueAname)));
265     columnValues.add(new TColumnValue(wrap(familyBname), wrap(qualifierBname), wrap(valueBname)));
266     List<TPut> puts = new ArrayList<TPut>();
267     puts.add(new TPut(wrap(rowName1), columnValues));
268     puts.add(new TPut(wrap(rowName2), columnValues));
269 
270     handler.putMultiple(table, puts);
271 
272     List<TDelete> deletes = new ArrayList<TDelete>();
273     deletes.add(new TDelete(wrap(rowName1)));
274     deletes.add(new TDelete(wrap(rowName2)));
275 
276     List<TDelete> deleteResults = handler.deleteMultiple(table, deletes);
277     // 0 means they were all successfully applies
278     assertEquals(0, deleteResults.size());
279 
280     assertFalse(handler.exists(table, new TGet(wrap(rowName1))));
281     assertFalse(handler.exists(table, new TGet(wrap(rowName2))));
282   }
283 
284   @Test
285   public void testDelete() throws Exception {
286     ThriftHBaseServiceHandler handler = createHandler();
287     byte[] rowName = "testDelete".getBytes();
288     ByteBuffer table = wrap(tableAname);
289 
290     List<TColumnValue> columnValues = new ArrayList<TColumnValue>();
291     TColumnValue columnValueA = new TColumnValue(wrap(familyAname), wrap(qualifierAname),
292       wrap(valueAname));
293     TColumnValue columnValueB = new TColumnValue(wrap(familyBname), wrap(qualifierBname),
294       wrap(valueBname));
295     columnValues.add(columnValueA);
296     columnValues.add(columnValueB);
297     TPut put = new TPut(wrap(rowName), columnValues);
298 
299     put.setColumnValues(columnValues);
300 
301     handler.put(table, put);
302 
303     TDelete delete = new TDelete(wrap(rowName));
304     List<TColumn> deleteColumns = new ArrayList<TColumn>();
305     TColumn deleteColumn = new TColumn(wrap(familyAname));
306     deleteColumn.setQualifier(qualifierAname);
307     deleteColumns.add(deleteColumn);
308     delete.setColumns(deleteColumns);
309 
310     handler.deleteSingle(table, delete);
311 
312     TGet get = new TGet(wrap(rowName));
313     TResult result = handler.get(table, get);
314     assertArrayEquals(rowName, result.getRow());
315     List<TColumnValue> returnedColumnValues = result.getColumnValues();
316     List<TColumnValue> expectedColumnValues = new ArrayList<TColumnValue>();
317     expectedColumnValues.add(columnValueB);
318     assertTColumnValuesEqual(expectedColumnValues, returnedColumnValues);
319   }
320 
321   @Test
322   public void testDeleteAllTimestamps() throws Exception {
323     ThriftHBaseServiceHandler handler = createHandler();
324     byte[] rowName = "testDeleteAllTimestamps".getBytes();
325     ByteBuffer table = wrap(tableAname);
326 
327     List<TColumnValue> columnValues = new ArrayList<TColumnValue>();
328     TColumnValue columnValueA = new TColumnValue(wrap(familyAname), wrap(qualifierAname),
329       wrap(valueAname));
330     columnValueA.setTimestamp(System.currentTimeMillis() - 10);
331     columnValues.add(columnValueA);
332     TPut put = new TPut(wrap(rowName), columnValues);
333 
334     put.setColumnValues(columnValues);
335 
336     handler.put(table, put);
337     columnValueA.setTimestamp(System.currentTimeMillis());
338     handler.put(table, put);
339 
340     TGet get = new TGet(wrap(rowName));
341     get.setMaxVersions(2);
342     TResult result = handler.get(table, get);
343     assertEquals(2, result.getColumnValuesSize());
344 
345     TDelete delete = new TDelete(wrap(rowName));
346     List<TColumn> deleteColumns = new ArrayList<TColumn>();
347     TColumn deleteColumn = new TColumn(wrap(familyAname));
348     deleteColumn.setQualifier(qualifierAname);
349     deleteColumns.add(deleteColumn);
350     delete.setColumns(deleteColumns);
351     delete.setDeleteType(TDeleteType.DELETE_COLUMNS); // This is the default anyway.
352 
353     handler.deleteSingle(table, delete);
354 
355     get = new TGet(wrap(rowName));
356     result = handler.get(table, get);
357     assertNull(result.getRow());
358     assertEquals(0, result.getColumnValuesSize());
359   }
360 
361   @Test
362   public void testDeleteSingleTimestamp() throws Exception {
363     ThriftHBaseServiceHandler handler = createHandler();
364     byte[] rowName = "testDeleteSingleTimestamp".getBytes();
365     ByteBuffer table = wrap(tableAname);
366 
367     long timestamp1 = System.currentTimeMillis() - 10;
368     long timestamp2 = System.currentTimeMillis();
369 
370     List<TColumnValue> columnValues = new ArrayList<TColumnValue>();
371     TColumnValue columnValueA = new TColumnValue(wrap(familyAname), wrap(qualifierAname),
372       wrap(valueAname));
373     columnValueA.setTimestamp(timestamp1);
374     columnValues.add(columnValueA);
375     TPut put = new TPut(wrap(rowName), columnValues);
376 
377     put.setColumnValues(columnValues);
378 
379     handler.put(table, put);
380     columnValueA.setTimestamp(timestamp2);
381     handler.put(table, put);
382 
383     TGet get = new TGet(wrap(rowName));
384     get.setMaxVersions(2);
385     TResult result = handler.get(table, get);
386     assertEquals(2, result.getColumnValuesSize());
387 
388     TDelete delete = new TDelete(wrap(rowName));
389     List<TColumn> deleteColumns = new ArrayList<TColumn>();
390     TColumn deleteColumn = new TColumn(wrap(familyAname));
391     deleteColumn.setQualifier(qualifierAname);
392     deleteColumns.add(deleteColumn);
393     delete.setColumns(deleteColumns);
394     delete.setDeleteType(TDeleteType.DELETE_COLUMN);
395 
396     handler.deleteSingle(table, delete);
397 
398     get = new TGet(wrap(rowName));
399     result = handler.get(table, get);
400     assertArrayEquals(rowName, result.getRow());
401     assertEquals(1, result.getColumnValuesSize());
402     // the older timestamp should remain.
403     assertEquals(timestamp1, result.getColumnValues().get(0).getTimestamp());
404   }
405 
406   @Test
407   public void testIncrement() throws Exception {
408     ThriftHBaseServiceHandler handler = createHandler();
409     byte[] rowName = "testIncrement".getBytes();
410     ByteBuffer table = wrap(tableAname);
411 
412     List<TColumnValue> columnValues = new ArrayList<TColumnValue>();
413     columnValues.add(new TColumnValue(wrap(familyAname), wrap(qualifierAname),
414       wrap(Bytes.toBytes(1L))));
415     TPut put = new TPut(wrap(rowName), columnValues);
416     put.setColumnValues(columnValues);
417     handler.put(table, put);
418 
419     List<TColumnIncrement> incrementColumns = new ArrayList<TColumnIncrement>();
420     incrementColumns.add(new TColumnIncrement(wrap(familyAname), wrap(qualifierAname)));
421     TIncrement increment = new TIncrement(wrap(rowName), incrementColumns);
422     handler.increment(table, increment);
423 
424     TGet get = new TGet(wrap(rowName));
425     TResult result = handler.get(table, get);
426 
427     assertArrayEquals(rowName, result.getRow());
428     assertEquals(1, result.getColumnValuesSize());
429     TColumnValue columnValue = result.getColumnValues().get(0);
430     assertArrayEquals(Bytes.toBytes(2L), columnValue.getValue());
431   }
432 
433   @Test
434   public void testAppend() throws Exception {
435     ThriftHBaseServiceHandler handler = createHandler();
436     byte[] rowName = "testAppend".getBytes();
437     ByteBuffer table = wrap(tableAname);
438     byte[] v1 = Bytes.toBytes("42");
439     byte[] v2 = Bytes.toBytes("23");
440     List<TColumnValue> columnValues = new ArrayList<TColumnValue>();
441     columnValues.add(new TColumnValue(wrap(familyAname), wrap(qualifierAname), wrap(v1)));
442     TPut put = new TPut(wrap(rowName), columnValues);
443     put.setColumnValues(columnValues);
444     handler.put(table, put);
445 
446     List<TColumnValue> appendColumns = new ArrayList<TColumnValue>();
447     appendColumns.add(new TColumnValue(wrap(familyAname), wrap(qualifierAname), wrap(v2)));
448     TAppend append = new TAppend(wrap(rowName), appendColumns);
449     handler.append(table, append);
450 
451     TGet get = new TGet(wrap(rowName));
452     TResult result = handler.get(table, get);
453 
454     assertArrayEquals(rowName, result.getRow());
455     assertEquals(1, result.getColumnValuesSize());
456     TColumnValue columnValue = result.getColumnValues().get(0);
457     assertArrayEquals(Bytes.add(v1, v2), columnValue.getValue());
458   }
459 
460   /**
461    * check that checkAndPut fails if the cell does not exist, then put in the cell, then check
462    * that the checkAndPut succeeds.
463    *
464    * @throws Exception
465    */
466   @Test
467   public void testCheckAndPut() throws Exception {
468     ThriftHBaseServiceHandler handler = createHandler();
469     byte[] rowName = "testCheckAndPut".getBytes();
470     ByteBuffer table = wrap(tableAname);
471 
472     List<TColumnValue> columnValuesA = new ArrayList<TColumnValue>();
473     TColumnValue columnValueA = new TColumnValue(wrap(familyAname), wrap(qualifierAname),
474       wrap(valueAname));
475     columnValuesA.add(columnValueA);
476     TPut putA = new TPut(wrap(rowName), columnValuesA);
477     putA.setColumnValues(columnValuesA);
478 
479     List<TColumnValue> columnValuesB = new ArrayList<TColumnValue>();
480     TColumnValue columnValueB = new TColumnValue(wrap(familyBname), wrap(qualifierBname),
481       wrap(valueBname));
482     columnValuesB.add(columnValueB);
483     TPut putB = new TPut(wrap(rowName), columnValuesB);
484     putB.setColumnValues(columnValuesB);
485 
486     assertFalse(handler.checkAndPut(table, wrap(rowName), wrap(familyAname),
487       wrap(qualifierAname), wrap(valueAname), putB));
488 
489     TGet get = new TGet(wrap(rowName));
490     TResult result = handler.get(table, get);
491     assertEquals(0, result.getColumnValuesSize());
492 
493     handler.put(table, putA);
494 
495     assertTrue(handler.checkAndPut(table, wrap(rowName), wrap(familyAname),
496       wrap(qualifierAname), wrap(valueAname), putB));
497 
498     result = handler.get(table, get);
499     assertArrayEquals(rowName, result.getRow());
500     List<TColumnValue> returnedColumnValues = result.getColumnValues();
501     List<TColumnValue> expectedColumnValues = new ArrayList<TColumnValue>();
502     expectedColumnValues.add(columnValueA);
503     expectedColumnValues.add(columnValueB);
504     assertTColumnValuesEqual(expectedColumnValues, returnedColumnValues);
505   }
506 
507   /**
508    * check that checkAndDelete fails if the cell does not exist, then put in the cell, then
509    * check that the checkAndDelete succeeds.
510    *
511    * @throws Exception
512    */
513   @Test
514   public void testCheckAndDelete() throws Exception {
515     ThriftHBaseServiceHandler handler = createHandler();
516     byte[] rowName = "testCheckAndDelete".getBytes();
517     ByteBuffer table = wrap(tableAname);
518 
519     List<TColumnValue> columnValuesA = new ArrayList<TColumnValue>();
520     TColumnValue columnValueA = new TColumnValue(wrap(familyAname), wrap(qualifierAname),
521       wrap(valueAname));
522     columnValuesA.add(columnValueA);
523     TPut putA = new TPut(wrap(rowName), columnValuesA);
524     putA.setColumnValues(columnValuesA);
525 
526     List<TColumnValue> columnValuesB = new ArrayList<TColumnValue>();
527     TColumnValue columnValueB = new TColumnValue(wrap(familyBname), wrap(qualifierBname),
528       wrap(valueBname));
529     columnValuesB.add(columnValueB);
530     TPut putB = new TPut(wrap(rowName), columnValuesB);
531     putB.setColumnValues(columnValuesB);
532 
533     // put putB so that we know whether the row has been deleted or not
534     handler.put(table, putB);
535 
536     TDelete delete = new TDelete(wrap(rowName));
537 
538     assertFalse(handler.checkAndDelete(table, wrap(rowName), wrap(familyAname),
539         wrap(qualifierAname), wrap(valueAname), delete));
540 
541     TGet get = new TGet(wrap(rowName));
542     TResult result = handler.get(table, get);
543     assertArrayEquals(rowName, result.getRow());
544     assertTColumnValuesEqual(columnValuesB, result.getColumnValues());
545 
546     handler.put(table, putA);
547 
548     assertTrue(handler.checkAndDelete(table, wrap(rowName), wrap(familyAname),
549       wrap(qualifierAname), wrap(valueAname), delete));
550 
551     result = handler.get(table, get);
552     assertFalse(result.isSetRow());
553     assertEquals(0, result.getColumnValuesSize());
554   }
555 
556   @Test
557   public void testScan() throws Exception {
558     ThriftHBaseServiceHandler handler = createHandler();
559     ByteBuffer table = wrap(tableAname);
560 
561     // insert data
562     TColumnValue columnValue = new TColumnValue(wrap(familyAname), wrap(qualifierAname),
563       wrap(valueAname));
564     List<TColumnValue> columnValues = new ArrayList<TColumnValue>();
565     columnValues.add(columnValue);
566     for (int i = 0; i < 10; i++) {
567       TPut put = new TPut(wrap(("testScan" + i).getBytes()), columnValues);
568       handler.put(table, put);
569     }
570 
571     // create scan instance
572     TScan scan = new TScan();
573     List<TColumn> columns = new ArrayList<TColumn>();
574     TColumn column = new TColumn();
575     column.setFamily(familyAname);
576     column.setQualifier(qualifierAname);
577     columns.add(column);
578     scan.setColumns(columns);
579     scan.setStartRow("testScan".getBytes());
580     scan.setStopRow("testScan\uffff".getBytes());
581 
582     // get scanner and rows
583     int scanId = handler.openScanner(table, scan);
584     List<TResult> results = handler.getScannerRows(scanId, 10);
585     assertEquals(10, results.size());
586     for (int i = 0; i < 10; i++) {
587       // check if the rows are returned and in order
588       assertArrayEquals(("testScan" + i).getBytes(), results.get(i).getRow());
589     }
590 
591     // check that we are at the end of the scan
592     results = handler.getScannerRows(scanId, 10);
593     assertEquals(0, results.size());
594 
595     // close scanner and check that it was indeed closed
596     handler.closeScanner(scanId);
597     try {
598       handler.getScannerRows(scanId, 10);
599       fail("Scanner id should be invalid");
600     } catch (TIllegalArgument e) {
601     }
602   }
603 
604   /**
605    * Tests keeping a HBase scanner alive for long periods of time. Each call to getScannerRow()
606    * should reset the ConnectionCache timeout for the scanner's connection
607    * @throws Exception
608    */
609   @Test
610   public void testLongLivedScan() throws Exception {
611     int numTrials = 6;
612     int trialPause = 1000;
613     int cleanUpInterval = 100;
614     Configuration conf = new Configuration(UTIL.getConfiguration());
615     // Set the ConnectionCache timeout to trigger halfway through the trials
616     conf.setInt(ThriftHBaseServiceHandler.MAX_IDLETIME, (numTrials / 2) * trialPause);
617     conf.setInt(ThriftHBaseServiceHandler.CLEANUP_INTERVAL, cleanUpInterval);
618     ThriftHBaseServiceHandler handler = new ThriftHBaseServiceHandler(conf,
619         UserProvider.instantiate(conf));
620 
621     ByteBuffer table = wrap(tableAname);
622     // insert data
623     TColumnValue columnValue = new TColumnValue(wrap(familyAname), wrap(qualifierAname),
624         wrap(valueAname));
625     List<TColumnValue> columnValues = new ArrayList<TColumnValue>();
626     columnValues.add(columnValue);
627     for (int i = 0; i < numTrials; i++) {
628       TPut put = new TPut(wrap(("testScan" + i).getBytes()), columnValues);
629       handler.put(table, put);
630     }
631 
632     // create scan instance
633     TScan scan = new TScan();
634     List<TColumn> columns = new ArrayList<TColumn>();
635     TColumn column = new TColumn();
636     column.setFamily(familyAname);
637     column.setQualifier(qualifierAname);
638     columns.add(column);
639     scan.setColumns(columns);
640     scan.setStartRow("testScan".getBytes());
641     scan.setStopRow("testScan\uffff".getBytes());
642     // Prevent the scanner from caching results
643     scan.setCaching(1);
644 
645     // get scanner and rows
646     int scanId = handler.openScanner(table, scan);
647     for (int i = 0; i < numTrials; i++) {
648       // Make sure that the Scanner doesn't throw an exception after the ConnectionCache timeout
649       List<TResult> results = handler.getScannerRows(scanId, 1);
650       assertArrayEquals(("testScan" + i).getBytes(), results.get(0).getRow());
651       Thread.sleep(trialPause);
652     }
653   }
654 
655   @Test
656   public void testReverseScan() throws Exception {
657     ThriftHBaseServiceHandler handler = createHandler();
658     ByteBuffer table = wrap(tableAname);
659 
660     // insert data
661     TColumnValue columnValue = new TColumnValue(wrap(familyAname), wrap(qualifierAname),
662       wrap(valueAname));
663     List<TColumnValue> columnValues = new ArrayList<TColumnValue>();
664     columnValues.add(columnValue);
665     for (int i = 0; i < 10; i++) {
666       TPut put = new TPut(wrap(("testReverseScan" + i).getBytes()), columnValues);
667       handler.put(table, put);
668     }
669 
670     // create reverse scan instance
671     TScan scan = new TScan();
672     scan.setReversed(true);
673     List<TColumn> columns = new ArrayList<TColumn>();
674     TColumn column = new TColumn();
675     column.setFamily(familyAname);
676     column.setQualifier(qualifierAname);
677     columns.add(column);
678     scan.setColumns(columns);
679     scan.setStartRow("testReverseScan\uffff".getBytes());
680     scan.setStopRow("testReverseScan".getBytes());
681 
682     // get scanner and rows
683     int scanId = handler.openScanner(table, scan);
684     List<TResult> results = handler.getScannerRows(scanId, 10);
685     assertEquals(10, results.size());
686     for (int i = 0; i < 10; i++) {
687       // check if the rows are returned and in order
688       assertArrayEquals(("testReverseScan" + (9 - i)).getBytes(), results.get(i).getRow());
689     }
690 
691     // check that we are at the end of the scan
692     results = handler.getScannerRows(scanId, 10);
693     assertEquals(0, results.size());
694 
695     // close scanner and check that it was indeed closed
696     handler.closeScanner(scanId);
697     try {
698       handler.getScannerRows(scanId, 10);
699       fail("Scanner id should be invalid");
700     } catch (TIllegalArgument e) {
701     }
702   }
703 
704   @Test
705   public void testScanWithFilter() throws Exception {
706     ThriftHBaseServiceHandler handler = createHandler();
707     ByteBuffer table = wrap(tableAname);
708 
709     // insert data
710     TColumnValue columnValue = new TColumnValue(wrap(familyAname), wrap(qualifierAname),
711       wrap(valueAname));
712     List<TColumnValue> columnValues = new ArrayList<TColumnValue>();
713     columnValues.add(columnValue);
714     for (int i = 0; i < 10; i++) {
715       TPut put = new TPut(wrap(("testScanWithFilter" + i).getBytes()), columnValues);
716       handler.put(table, put);
717     }
718 
719     // create scan instance with filter
720     TScan scan = new TScan();
721     List<TColumn> columns = new ArrayList<TColumn>();
722     TColumn column = new TColumn();
723     column.setFamily(familyAname);
724     column.setQualifier(qualifierAname);
725     columns.add(column);
726     scan.setColumns(columns);
727     scan.setStartRow("testScanWithFilter".getBytes());
728     scan.setStopRow("testScanWithFilter\uffff".getBytes());
729     // only get the key part
730     scan.setFilterString(wrap(("KeyOnlyFilter()").getBytes()));
731 
732     // get scanner and rows
733     int scanId = handler.openScanner(table, scan);
734     List<TResult> results = handler.getScannerRows(scanId, 10);
735     assertEquals(10, results.size());
736     for (int i = 0; i < 10; i++) {
737       // check if the rows are returned and in order
738       assertArrayEquals(("testScanWithFilter" + i).getBytes(), results.get(i).getRow());
739       // check that the value is indeed stripped by the filter
740       assertEquals(0, results.get(i).getColumnValues().get(0).getValue().length);
741     }
742 
743     // check that we are at the end of the scan
744     results = handler.getScannerRows(scanId, 10);
745     assertEquals(0, results.size());
746 
747     // close scanner and check that it was indeed closed
748     handler.closeScanner(scanId);
749     try {
750       handler.getScannerRows(scanId, 10);
751       fail("Scanner id should be invalid");
752     } catch (TIllegalArgument e) {
753     }
754   }
755 
756   @Test
757   public void testPutTTL() throws Exception {
758     ThriftHBaseServiceHandler handler = createHandler();
759     byte[] rowName = "testPutTTL".getBytes();
760     ByteBuffer table = wrap(tableAname);
761     List<TColumnValue> columnValues = new ArrayList<TColumnValue>();
762 
763     // Add some dummy data
764     columnValues.add(
765         new TColumnValue(
766             wrap(familyAname),
767             wrap(qualifierAname),
768             wrap(Bytes.toBytes(1L))));
769 
770 
771     TPut put = new TPut(wrap(rowName), columnValues);
772     put.setColumnValues(columnValues);
773 
774     Map<ByteBuffer, ByteBuffer> attributes = new HashMap<>();
775 
776     // Time in ms for the kv's to live.
777     long ttlTimeMs = 2000L;
778 
779     // the _ttl attribute is a number of ms ttl for key values in this put.
780     attributes.put(wrap(Bytes.toBytes("_ttl")), wrap(Bytes.toBytes(ttlTimeMs)));
781     // Attach the attributes
782     put.setAttributes(attributes);
783     // Send it.
784     handler.put(table, put);
785 
786     // Now get the data back
787     TGet getOne = new TGet(wrap(rowName));
788     TResult resultOne = handler.get(table, getOne);
789 
790     // It's there.
791     assertArrayEquals(rowName, resultOne.getRow());
792     assertEquals(1, resultOne.getColumnValuesSize());
793 
794     // Sleep 30 seconds just to make 100% sure that the key value should be expired.
795     Thread.sleep(ttlTimeMs * 15);
796 
797     TGet getTwo = new TGet(wrap(rowName));
798     TResult resultTwo = handler.get(table, getTwo);
799 
800 
801     // Nothing should be there since it's ttl'd out.
802     assertNull(resultTwo.getRow());
803     assertEquals(0, resultTwo.getColumnValuesSize());
804   }
805 
806   /**
807    * Padding numbers to make comparison of sort order easier in a for loop
808    *
809    * @param n  The number to pad.
810    * @param pad  The length to pad up to.
811    * @return The padded number as a string.
812    */
813   private String pad(int n, byte pad) {
814     String res = Integer.toString(n);
815     while (res.length() < pad) res = "0" + res;
816     return res;
817   }
818 
819   @Test
820   public void testScanWithBatchSize() throws Exception {
821     ThriftHBaseServiceHandler handler = createHandler();
822     ByteBuffer table = wrap(tableAname);
823 
824     // insert data
825     List<TColumnValue> columnValues = new ArrayList<TColumnValue>();
826     for (int i = 0; i < 100; i++) {
827       String colNum = pad(i, (byte) 3);
828       TColumnValue columnValue = new TColumnValue(wrap(familyAname),
829         wrap(("col" + colNum).getBytes()), wrap(("val" + colNum).getBytes()));
830       columnValues.add(columnValue);
831     }
832     TPut put = new TPut(wrap(("testScanWithBatchSize").getBytes()), columnValues);
833     handler.put(table, put);
834 
835     // create scan instance
836     TScan scan = new TScan();
837     List<TColumn> columns = new ArrayList<TColumn>();
838     TColumn column = new TColumn();
839     column.setFamily(familyAname);
840     columns.add(column);
841     scan.setColumns(columns);
842     scan.setStartRow("testScanWithBatchSize".getBytes());
843     scan.setStopRow("testScanWithBatchSize\uffff".getBytes());
844     // set batch size to 10 columns per call
845     scan.setBatchSize(10);
846 
847     // get scanner
848     int scanId = handler.openScanner(table, scan);
849     List<TResult> results = null;
850     for (int i = 0; i < 10; i++) {
851       // get batch for single row (10x10 is what we expect)
852       results = handler.getScannerRows(scanId, 1);
853       assertEquals(1, results.size());
854       // check length of batch
855       List<TColumnValue> cols = results.get(0).getColumnValues();
856       assertEquals(10, cols.size());
857       // check if the columns are returned and in order
858       for (int y = 0; y < 10; y++) {
859         int colNum = y + (10 * i);
860         String colNumPad = pad(colNum, (byte) 3);
861         assertArrayEquals(("col" + colNumPad).getBytes(), cols.get(y).getQualifier());
862       }
863     }
864 
865     // check that we are at the end of the scan
866     results = handler.getScannerRows(scanId, 1);
867     assertEquals(0, results.size());
868 
869     // close scanner and check that it was indeed closed
870     handler.closeScanner(scanId);
871     try {
872       handler.getScannerRows(scanId, 1);
873       fail("Scanner id should be invalid");
874     } catch (TIllegalArgument e) {
875     }
876   }
877 
878   @Test
879   public void testGetScannerResults() throws Exception {
880     ThriftHBaseServiceHandler handler = createHandler();
881     ByteBuffer table = wrap(tableAname);
882 
883     // insert data
884     TColumnValue columnValue =
885         new TColumnValue(wrap(familyAname), wrap(qualifierAname), wrap(valueAname));
886     List<TColumnValue> columnValues = new ArrayList<TColumnValue>();
887     columnValues.add(columnValue);
888     for (int i = 0; i < 20; i++) {
889       TPut put =
890           new TPut(wrap(("testGetScannerResults" + pad(i, (byte) 2)).getBytes()), columnValues);
891       handler.put(table, put);
892     }
893 
894     // create scan instance
895     TScan scan = new TScan();
896     List<TColumn> columns = new ArrayList<TColumn>();
897     TColumn column = new TColumn();
898     column.setFamily(familyAname);
899     column.setQualifier(qualifierAname);
900     columns.add(column);
901     scan.setColumns(columns);
902     scan.setStartRow("testGetScannerResults".getBytes());
903 
904     // get 5 rows and check the returned results
905     scan.setStopRow("testGetScannerResults05".getBytes());
906     List<TResult> results = handler.getScannerResults(table, scan, 5);
907     assertEquals(5, results.size());
908     for (int i = 0; i < 5; i++) {
909       // check if the rows are returned and in order
910       assertArrayEquals(("testGetScannerResults" + pad(i, (byte) 2)).getBytes(), results.get(i)
911           .getRow());
912     }
913 
914     // get 10 rows and check the returned results
915     scan.setStopRow("testGetScannerResults10".getBytes());
916     results = handler.getScannerResults(table, scan, 10);
917     assertEquals(10, results.size());
918     for (int i = 0; i < 10; i++) {
919       // check if the rows are returned and in order
920       assertArrayEquals(("testGetScannerResults" + pad(i, (byte) 2)).getBytes(), results.get(i)
921           .getRow());
922     }
923 
924     // get 20 rows and check the returned results
925     scan.setStopRow("testGetScannerResults20".getBytes());
926     results = handler.getScannerResults(table, scan, 20);
927     assertEquals(20, results.size());
928     for (int i = 0; i < 20; i++) {
929       // check if the rows are returned and in order
930       assertArrayEquals(("testGetScannerResults" + pad(i, (byte) 2)).getBytes(), results.get(i)
931           .getRow());
932     }
933 
934     // reverse scan
935     scan = new TScan();
936     scan.setColumns(columns);
937     scan.setReversed(true);
938     scan.setStartRow("testGetScannerResults20".getBytes());
939     scan.setStopRow("testGetScannerResults".getBytes());
940     results = handler.getScannerResults(table, scan, 20);
941     assertEquals(20, results.size());
942     for (int i = 0; i < 20; i++) {
943       // check if the rows are returned and in order
944       assertArrayEquals(("testGetScannerResults" + pad(19 - i, (byte) 2)).getBytes(), results.get(i)
945           .getRow());
946     }
947  }
948 
949   @Test
950   public void testFilterRegistration() throws Exception {
951     Configuration conf = UTIL.getConfiguration();
952     conf.set("hbase.thrift.filters", "MyFilter:filterclass");
953     ThriftServer.registerFilters(conf);
954     Map<String, String> registeredFilters = ParseFilter.getAllFilters();
955     assertEquals("filterclass", registeredFilters.get("MyFilter"));
956   }
957 
958   @Test
959   public void testMetrics() throws Exception {
960     Configuration conf = UTIL.getConfiguration();
961     ThriftMetrics metrics = getMetrics(conf);
962     ThriftHBaseServiceHandler hbaseHandler = createHandler();
963     THBaseService.Iface handler =
964         ThriftHBaseServiceHandler.newInstance(hbaseHandler, metrics);
965     byte[] rowName = "testMetrics".getBytes();
966     ByteBuffer table = wrap(tableAname);
967 
968     TGet get = new TGet(wrap(rowName));
969     assertFalse(handler.exists(table, get));
970 
971     List<TColumnValue> columnValues = new ArrayList<TColumnValue>();
972     columnValues.add(new TColumnValue(wrap(familyAname), wrap(qualifierAname), wrap(valueAname)));
973     columnValues.add(new TColumnValue(wrap(familyBname), wrap(qualifierBname),  wrap(valueBname)));
974     TPut put = new TPut(wrap(rowName), columnValues);
975     put.setColumnValues(columnValues);
976 
977     handler.put(table, put);
978 
979     assertTrue(handler.exists(table, get));
980     metricsHelper.assertCounter("put_num_ops", 1, metrics.getSource());
981     metricsHelper.assertCounter( "exists_num_ops", 2, metrics.getSource());
982   }
983 
984   private static ThriftMetrics getMetrics(Configuration conf) throws Exception {
985     ThriftMetrics m = new ThriftMetrics(conf, ThriftMetrics.ThriftServerType.TWO);
986     m.getSource().init(); //Clear all the metrics
987     return m;
988   }
989 
990   @Test
991   public void testMetricsWithException() throws Exception {
992     byte[] rowkey = Bytes.toBytes("row1");
993     byte[] family = Bytes.toBytes("f");
994     byte[] col = Bytes.toBytes("c");
995     // create a table which will throw exceptions for requests
996     TableName tableName = TableName.valueOf("testMetricsWithException");
997     HTableDescriptor tableDesc = new HTableDescriptor(tableName);
998     tableDesc.addCoprocessor(ErrorThrowingGetObserver.class.getName());
999     tableDesc.addFamily(new HColumnDescriptor(family));
1000 
1001     Table table = UTIL.createTable(tableDesc, null);
1002     table.put(new Put(rowkey).addColumn(family, col, Bytes.toBytes("val1")));
1003 
1004     ThriftHBaseServiceHandler hbaseHandler = createHandler();
1005     ThriftMetrics metrics = getMetrics(UTIL.getConfiguration());
1006     THBaseService.Iface handler =
1007         ThriftHBaseServiceHandler.newInstance(hbaseHandler, metrics);
1008     ByteBuffer tTableName = wrap(tableName.getName());
1009 
1010     // check metrics increment with a successful get
1011     long preGetCounter = metricsHelper.checkCounterExists("get_num_ops", metrics.getSource()) ?
1012         metricsHelper.getCounter("get_num_ops", metrics.getSource()) :
1013         0;
1014     TGet tGet = new TGet(wrap(rowkey));
1015     TResult tResult = handler.get(tTableName, tGet);
1016 
1017     List<TColumnValue> expectedColumnValues = Lists.newArrayList(
1018         new TColumnValue(wrap(family), wrap(col), wrap(Bytes.toBytes("val1")))
1019     );
1020     assertArrayEquals(rowkey, tResult.getRow());
1021     List<TColumnValue> returnedColumnValues = tResult.getColumnValues();
1022     assertTColumnValuesEqual(expectedColumnValues, returnedColumnValues);
1023 
1024     metricsHelper.assertCounter("get_num_ops", preGetCounter + 1, metrics.getSource());
1025 
1026     // check metrics increment when the get throws each exception type
1027     for (ErrorThrowingGetObserver.ErrorType type : ErrorThrowingGetObserver.ErrorType.values()) {
1028       testExceptionType(handler, metrics, tTableName, rowkey, type);
1029     }
1030   }
1031 
1032   private void testExceptionType(THBaseService.Iface handler, ThriftMetrics metrics,
1033                                  ByteBuffer tTableName, byte[] rowkey, ErrorThrowingGetObserver.ErrorType errorType) {
1034     long preGetCounter = metricsHelper.getCounter("get_num_ops", metrics.getSource());
1035     String exceptionKey = errorType.getMetricName();
1036     long preExceptionCounter = metricsHelper.checkCounterExists(exceptionKey, metrics.getSource()) ?
1037         metricsHelper.getCounter(exceptionKey, metrics.getSource()) :
1038         0;
1039     TGet tGet = new TGet(wrap(rowkey));
1040     Map<ByteBuffer, ByteBuffer> attributes = new HashMap<>();
1041     attributes.put(wrap(Bytes.toBytes(ErrorThrowingGetObserver.SHOULD_ERROR_ATTRIBUTE)),
1042         wrap(Bytes.toBytes(errorType.name())));
1043     tGet.setAttributes(attributes);
1044     try {
1045       TResult tResult = handler.get(tTableName, tGet);
1046       fail("Get with error attribute should have thrown an exception");
1047     } catch (TException e) {
1048       LOG.info("Received exception: ", e);
1049       metricsHelper.assertCounter("get_num_ops", preGetCounter + 1, metrics.getSource());
1050       metricsHelper.assertCounter(exceptionKey, preExceptionCounter + 1, metrics.getSource());
1051     }
1052 
1053   }
1054 
1055   /**
1056    * See HBASE-17611
1057    *
1058    * Latency metrics were capped at ~ 2 seconds due to the use of an int variable to capture the
1059    * duration.
1060    */
1061   @Test
1062   public void testMetricsPrecision() throws Exception {
1063     byte[] rowkey = Bytes.toBytes("row1");
1064     byte[] family = Bytes.toBytes("f");
1065     byte[] col = Bytes.toBytes("c");
1066     // create a table which will throw exceptions for requests
1067     TableName tableName = TableName.valueOf("testMetricsPrecision");
1068     HTableDescriptor tableDesc = new HTableDescriptor(tableName);
1069     tableDesc.addCoprocessor(DelayingRegionObserver.class.getName());
1070     tableDesc.addFamily(new HColumnDescriptor(family));
1071 
1072     Table table = null;
1073     try {
1074       table = UTIL.createTable(tableDesc, null);
1075 
1076       table.put(new Put(rowkey).addColumn(family, col, Bytes.toBytes("val1")));
1077 
1078       ThriftHBaseServiceHandler hbaseHandler = createHandler();
1079       ThriftMetrics metrics = getMetrics(UTIL.getConfiguration());
1080       THBaseService.Iface handler =
1081           ThriftHBaseServiceHandler.newInstance(hbaseHandler, metrics);
1082       ByteBuffer tTableName = wrap(tableName.getName());
1083 
1084       // check metrics latency with a successful get
1085       TGet tGet = new TGet(wrap(rowkey));
1086       TResult tResult = handler.get(tTableName, tGet);
1087 
1088       List<TColumnValue> expectedColumnValues = Lists.newArrayList(
1089           new TColumnValue(wrap(family), wrap(col), wrap(Bytes.toBytes("val1")))
1090       );
1091       assertArrayEquals(rowkey, tResult.getRow());
1092       List<TColumnValue> returnedColumnValues = tResult.getColumnValues();
1093       assertTColumnValuesEqual(expectedColumnValues, returnedColumnValues);
1094 
1095       metricsHelper.assertGaugeGt("get_max", 3000L, metrics.getSource());
1096     } finally {
1097       if (table != null) {
1098         try {
1099           table.close();
1100         } catch (IOException ignored) {
1101         }
1102         UTIL.deleteTable(tableName);
1103       }
1104     }
1105   }
1106 
1107 
1108   @Test
1109   public void testAttribute() throws Exception {
1110     byte[] rowName = "testAttribute".getBytes();
1111     byte[] attributeKey = "attribute1".getBytes();
1112     byte[] attributeValue = "value1".getBytes();
1113     Map<ByteBuffer, ByteBuffer> attributes = new HashMap<ByteBuffer, ByteBuffer>();
1114     attributes.put(wrap(attributeKey), wrap(attributeValue));
1115 
1116     TGet tGet = new TGet(wrap(rowName));
1117     tGet.setAttributes(attributes);
1118     Get get = getFromThrift(tGet);
1119     assertArrayEquals(get.getAttribute("attribute1"), attributeValue);
1120 
1121     List<TColumnValue> columnValues = new ArrayList<TColumnValue>();
1122     columnValues.add(new TColumnValue(wrap(familyAname), wrap(qualifierAname), wrap(valueAname)));
1123     TPut tPut = new TPut(wrap(rowName) , columnValues);
1124     tPut.setAttributes(attributes);
1125     Put put = putFromThrift(tPut);
1126     assertArrayEquals(put.getAttribute("attribute1"), attributeValue);
1127 
1128     TScan tScan = new TScan();
1129     tScan.setAttributes(attributes);
1130     Scan scan = scanFromThrift(tScan);
1131     assertArrayEquals(scan.getAttribute("attribute1"), attributeValue);
1132 
1133     List<TColumnIncrement> incrementColumns = new ArrayList<TColumnIncrement>();
1134     incrementColumns.add(new TColumnIncrement(wrap(familyAname), wrap(qualifierAname)));
1135     TIncrement tIncrement = new TIncrement(wrap(rowName), incrementColumns);
1136     tIncrement.setAttributes(attributes);
1137     Increment increment = incrementFromThrift(tIncrement);
1138     assertArrayEquals(increment.getAttribute("attribute1"), attributeValue);
1139 
1140     TDelete tDelete = new TDelete(wrap(rowName));
1141     tDelete.setAttributes(attributes);
1142     Delete delete = deleteFromThrift(tDelete);
1143     assertArrayEquals(delete.getAttribute("attribute1"), attributeValue);
1144   }
1145 
1146   /**
1147    * Put valueA to a row, make sure put has happened, then create a mutation object to put valueB
1148    * and delete ValueA, then check that the row value is only valueB.
1149    *
1150    * @throws Exception
1151    */
1152   @Test
1153   public void testMutateRow() throws Exception {
1154     ThriftHBaseServiceHandler handler = createHandler();
1155     byte[] rowName = "testMutateRow".getBytes();
1156     ByteBuffer table = wrap(tableAname);
1157 
1158     List<TColumnValue> columnValuesA = new ArrayList<TColumnValue>();
1159     TColumnValue columnValueA = new TColumnValue(wrap(familyAname), wrap(qualifierAname),
1160         wrap(valueAname));
1161     columnValuesA.add(columnValueA);
1162     TPut putA = new TPut(wrap(rowName), columnValuesA);
1163     putA.setColumnValues(columnValuesA);
1164 
1165     handler.put(table,putA);
1166 
1167     TGet get = new TGet(wrap(rowName));
1168     TResult result = handler.get(table, get);
1169     assertArrayEquals(rowName, result.getRow());
1170     List<TColumnValue> returnedColumnValues = result.getColumnValues();
1171 
1172     List<TColumnValue> expectedColumnValues = new ArrayList<TColumnValue>();
1173     expectedColumnValues.add(columnValueA);
1174     assertTColumnValuesEqual(expectedColumnValues, returnedColumnValues);
1175 
1176     List<TColumnValue> columnValuesB = new ArrayList<TColumnValue>();
1177     TColumnValue columnValueB = new TColumnValue(wrap(familyAname), wrap(qualifierBname),
1178         wrap(valueBname));
1179     columnValuesB.add(columnValueB);
1180     TPut putB = new TPut(wrap(rowName), columnValuesB);
1181     putB.setColumnValues(columnValuesB);
1182 
1183     TDelete delete = new TDelete(wrap(rowName));
1184     List<TColumn> deleteColumns = new ArrayList<TColumn>();
1185     TColumn deleteColumn = new TColumn(wrap(familyAname));
1186     deleteColumn.setQualifier(qualifierAname);
1187     deleteColumns.add(deleteColumn);
1188     delete.setColumns(deleteColumns);
1189 
1190     List<TMutation> mutations = new ArrayList<TMutation>();
1191     TMutation mutationA = TMutation.put(putB);
1192     mutations.add(mutationA);
1193 
1194     TMutation mutationB = TMutation.deleteSingle(delete);
1195     mutations.add(mutationB);
1196 
1197     TRowMutations tRowMutations = new TRowMutations(wrap(rowName),mutations);
1198     handler.mutateRow(table,tRowMutations);
1199 
1200     result = handler.get(table, get);
1201     assertArrayEquals(rowName, result.getRow());
1202     returnedColumnValues = result.getColumnValues();
1203 
1204     expectedColumnValues = new ArrayList<TColumnValue>();
1205     expectedColumnValues.add(columnValueB);
1206     assertTColumnValuesEqual(expectedColumnValues, returnedColumnValues);
1207   }
1208 
1209   /**
1210    * Create TPut, TDelete , TIncrement objects, set durability then call ThriftUtility
1211    * functions to get Put , Delete and Increment respectively. Use getDurability to make sure
1212    * the returned objects have the appropriate durability setting.
1213    *
1214    * @throws Exception
1215    */
1216   @Test
1217   public void testDurability() throws Exception {
1218     byte[] rowName = "testDurability".getBytes();
1219     List<TColumnValue> columnValues = new ArrayList<TColumnValue>();
1220     columnValues.add(new TColumnValue(wrap(familyAname), wrap(qualifierAname), wrap(valueAname)));
1221 
1222     List<TColumnIncrement> incrementColumns = new ArrayList<TColumnIncrement>();
1223     incrementColumns.add(new TColumnIncrement(wrap(familyAname), wrap(qualifierAname)));
1224 
1225     TDelete tDelete = new TDelete(wrap(rowName));
1226     tDelete.setDurability(TDurability.SKIP_WAL);
1227     Delete delete = deleteFromThrift(tDelete);
1228     assertEquals(delete.getDurability(), Durability.SKIP_WAL);
1229 
1230     tDelete.setDurability(TDurability.ASYNC_WAL);
1231     delete = deleteFromThrift(tDelete);
1232     assertEquals(delete.getDurability(), Durability.ASYNC_WAL);
1233 
1234     tDelete.setDurability(TDurability.SYNC_WAL);
1235     delete = deleteFromThrift(tDelete);
1236     assertEquals(delete.getDurability(), Durability.SYNC_WAL);
1237 
1238     tDelete.setDurability(TDurability.FSYNC_WAL);
1239     delete = deleteFromThrift(tDelete);
1240     assertEquals(delete.getDurability(), Durability.FSYNC_WAL);
1241 
1242     TPut tPut = new TPut(wrap(rowName), columnValues);
1243     tPut.setDurability(TDurability.SKIP_WAL);
1244     Put put = putFromThrift(tPut);
1245     assertEquals(put.getDurability(), Durability.SKIP_WAL);
1246 
1247     tPut.setDurability(TDurability.ASYNC_WAL);
1248     put = putFromThrift(tPut);
1249     assertEquals(put.getDurability(), Durability.ASYNC_WAL);
1250 
1251     tPut.setDurability(TDurability.SYNC_WAL);
1252     put = putFromThrift(tPut);
1253     assertEquals(put.getDurability(), Durability.SYNC_WAL);
1254 
1255     tPut.setDurability(TDurability.FSYNC_WAL);
1256     put = putFromThrift(tPut);
1257     assertEquals(put.getDurability(), Durability.FSYNC_WAL);
1258 
1259     TIncrement tIncrement = new TIncrement(wrap(rowName), incrementColumns);
1260 
1261     tIncrement.setDurability(TDurability.SKIP_WAL);
1262     Increment increment = incrementFromThrift(tIncrement);
1263     assertEquals(increment.getDurability(), Durability.SKIP_WAL);
1264 
1265     tIncrement.setDurability(TDurability.ASYNC_WAL);
1266     increment = incrementFromThrift(tIncrement);
1267     assertEquals(increment.getDurability(), Durability.ASYNC_WAL);
1268 
1269     tIncrement.setDurability(TDurability.SYNC_WAL);
1270     increment = incrementFromThrift(tIncrement);
1271     assertEquals(increment.getDurability(), Durability.SYNC_WAL);
1272 
1273     tIncrement.setDurability(TDurability.FSYNC_WAL);
1274     increment = incrementFromThrift(tIncrement);
1275     assertEquals(increment.getDurability(), Durability.FSYNC_WAL);
1276   }
1277 
1278   @Test
1279   public void testCheckAndMutate() throws Exception {
1280     ThriftHBaseServiceHandler handler = createHandler();
1281     ByteBuffer table = wrap(tableAname);
1282     ByteBuffer row = wrap("row".getBytes());
1283     ByteBuffer family = wrap(familyAname);
1284     ByteBuffer qualifier = wrap(qualifierAname);
1285     ByteBuffer value = wrap(valueAname);
1286 
1287     // Create a mutation to write to 'B', our "mutate" of "checkAndMutate"
1288     List<TColumnValue> columnValuesB = new ArrayList<TColumnValue>();
1289     TColumnValue columnValueB = new TColumnValue(family, wrap(qualifierBname), wrap(valueBname));
1290     columnValuesB.add(columnValueB);
1291     TPut putB = new TPut(row, columnValuesB);
1292     putB.setColumnValues(columnValuesB);
1293 
1294     TRowMutations tRowMutations = new TRowMutations(row,
1295         Arrays.<TMutation> asList(TMutation.put(putB)));
1296 
1297     // Empty table when we begin
1298     TResult result = handler.get(table, new TGet(row));
1299     assertEquals(0, result.getColumnValuesSize());
1300 
1301     // checkAndMutate -- condition should fail because the value doesn't exist.
1302     assertFalse("Expected condition to not pass",
1303         handler.checkAndMutate(table, row, family, qualifier, TCompareOp.EQUAL, value,
1304             tRowMutations));
1305 
1306     List<TColumnValue> columnValuesA = new ArrayList<TColumnValue>();
1307     TColumnValue columnValueA = new TColumnValue(family, qualifier, value);
1308     columnValuesA.add(columnValueA);
1309 
1310     // Put an update 'A'
1311     handler.put(table, new TPut(row, columnValuesA));
1312 
1313     // Verify that the update is there
1314     result = handler.get(table, new TGet(row));
1315     assertEquals(1, result.getColumnValuesSize());
1316     assertTColumnValueEqual(columnValueA, result.getColumnValues().get(0));
1317 
1318     // checkAndMutate -- condition should pass since we added the value
1319     assertTrue("Expected condition to pass",
1320         handler.checkAndMutate(table, row, family, qualifier, TCompareOp.EQUAL, value,
1321             tRowMutations));
1322 
1323     result = handler.get(table, new TGet(row));
1324     assertEquals(2, result.getColumnValuesSize());
1325     assertTColumnValueEqual(columnValueA, result.getColumnValues().get(0));
1326     assertTColumnValueEqual(columnValueB, result.getColumnValues().get(1));
1327   }
1328 
1329   public static class DelayingRegionObserver extends BaseRegionObserver {
1330     private static final Log LOG = LogFactory.getLog(DelayingRegionObserver.class);
1331     // sleep time in msec
1332     private long delayMillis;
1333 
1334     @Override
1335     public void start(CoprocessorEnvironment e) throws IOException {
1336       this.delayMillis = e.getConfiguration()
1337           .getLong("delayingregionobserver.delay", 3000);
1338     }
1339 
1340     @Override
1341     public void preGetOp(ObserverContext<RegionCoprocessorEnvironment> e, Get get,
1342                          List<Cell> results) throws IOException {
1343       try {
1344         long start = System.currentTimeMillis();
1345         TimeUnit.MILLISECONDS.sleep(delayMillis);
1346         if (LOG.isTraceEnabled()) {
1347           LOG.trace("Slept for " + (System.currentTimeMillis() - start) + " msec");
1348         }
1349       } catch (InterruptedException ie) {
1350         throw new InterruptedIOException("Interrupted while sleeping");
1351       }
1352     }
1353   }
1354 }
1355