001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.thrift2;
019
020import static java.nio.ByteBuffer.wrap;
021import static org.apache.hadoop.hbase.thrift.HBaseServiceHandler.CLEANUP_INTERVAL;
022import static org.apache.hadoop.hbase.thrift.HBaseServiceHandler.MAX_IDLETIME;
023import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.deleteFromThrift;
024import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.getFromThrift;
025import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.incrementFromThrift;
026import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.putFromThrift;
027import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.scanFromThrift;
028import static org.junit.Assert.assertArrayEquals;
029import static org.junit.Assert.assertEquals;
030import static org.junit.Assert.assertFalse;
031import static org.junit.Assert.assertNull;
032import static org.junit.Assert.assertTrue;
033import static org.junit.Assert.fail;
034
035import java.io.IOException;
036import java.io.InterruptedIOException;
037import java.nio.ByteBuffer;
038import java.util.ArrayList;
039import java.util.Arrays;
040import java.util.Collections;
041import java.util.Comparator;
042import java.util.HashMap;
043import java.util.List;
044import java.util.Map;
045import java.util.Optional;
046import java.util.concurrent.TimeUnit;
047import org.apache.hadoop.conf.Configuration;
048import org.apache.hadoop.hbase.Cell;
049import org.apache.hadoop.hbase.CompatibilityFactory;
050import org.apache.hadoop.hbase.CoprocessorEnvironment;
051import org.apache.hadoop.hbase.HBaseClassTestRule;
052import org.apache.hadoop.hbase.HBaseTestingUtility;
053import org.apache.hadoop.hbase.HColumnDescriptor;
054import org.apache.hadoop.hbase.HTableDescriptor;
055import org.apache.hadoop.hbase.TableName;
056import org.apache.hadoop.hbase.client.Admin;
057import org.apache.hadoop.hbase.client.Consistency;
058import org.apache.hadoop.hbase.client.Delete;
059import org.apache.hadoop.hbase.client.Durability;
060import org.apache.hadoop.hbase.client.Get;
061import org.apache.hadoop.hbase.client.Increment;
062import org.apache.hadoop.hbase.client.Put;
063import org.apache.hadoop.hbase.client.Scan;
064import org.apache.hadoop.hbase.client.Table;
065import org.apache.hadoop.hbase.client.TableDescriptor;
066import org.apache.hadoop.hbase.coprocessor.ObserverContext;
067import org.apache.hadoop.hbase.coprocessor.RegionCoprocessor;
068import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
069import org.apache.hadoop.hbase.coprocessor.RegionObserver;
070import org.apache.hadoop.hbase.filter.ParseFilter;
071import org.apache.hadoop.hbase.security.UserProvider;
072import org.apache.hadoop.hbase.test.MetricsAssertHelper;
073import org.apache.hadoop.hbase.testclassification.ClientTests;
074import org.apache.hadoop.hbase.testclassification.MediumTests;
075import org.apache.hadoop.hbase.thrift.ErrorThrowingGetObserver;
076import org.apache.hadoop.hbase.thrift.HbaseHandlerMetricsProxy;
077import org.apache.hadoop.hbase.thrift.ThriftMetrics;
078import org.apache.hadoop.hbase.thrift2.generated.TAppend;
079import org.apache.hadoop.hbase.thrift2.generated.TColumn;
080import org.apache.hadoop.hbase.thrift2.generated.TColumnFamilyDescriptor;
081import org.apache.hadoop.hbase.thrift2.generated.TColumnIncrement;
082import org.apache.hadoop.hbase.thrift2.generated.TColumnValue;
083import org.apache.hadoop.hbase.thrift2.generated.TCompareOp;
084import org.apache.hadoop.hbase.thrift2.generated.TConsistency;
085import org.apache.hadoop.hbase.thrift2.generated.TDataBlockEncoding;
086import org.apache.hadoop.hbase.thrift2.generated.TDelete;
087import org.apache.hadoop.hbase.thrift2.generated.TDeleteType;
088import org.apache.hadoop.hbase.thrift2.generated.TDurability;
089import org.apache.hadoop.hbase.thrift2.generated.TGet;
090import org.apache.hadoop.hbase.thrift2.generated.THBaseService;
091import org.apache.hadoop.hbase.thrift2.generated.TIOError;
092import org.apache.hadoop.hbase.thrift2.generated.TIllegalArgument;
093import org.apache.hadoop.hbase.thrift2.generated.TIncrement;
094import org.apache.hadoop.hbase.thrift2.generated.TMutation;
095import org.apache.hadoop.hbase.thrift2.generated.TNamespaceDescriptor;
096import org.apache.hadoop.hbase.thrift2.generated.TPut;
097import org.apache.hadoop.hbase.thrift2.generated.TReadType;
098import org.apache.hadoop.hbase.thrift2.generated.TResult;
099import org.apache.hadoop.hbase.thrift2.generated.TRowMutations;
100import org.apache.hadoop.hbase.thrift2.generated.TScan;
101import org.apache.hadoop.hbase.thrift2.generated.TTableDescriptor;
102import org.apache.hadoop.hbase.thrift2.generated.TTableName;
103import org.apache.hadoop.hbase.thrift2.generated.TTimeRange;
104import org.apache.hadoop.hbase.util.Bytes;
105import org.apache.thrift.TException;
106import org.junit.AfterClass;
107import org.junit.Before;
108import org.junit.BeforeClass;
109import org.junit.ClassRule;
110import org.junit.Rule;
111import org.junit.Test;
112import org.junit.experimental.categories.Category;
113import org.junit.rules.TestName;
114import org.slf4j.Logger;
115import org.slf4j.LoggerFactory;
116
117import org.apache.hbase.thirdparty.com.google.common.collect.Lists;
118import org.apache.hbase.thirdparty.org.apache.commons.collections4.CollectionUtils;
119
120/**
121 * Unit testing for ThriftServer.HBaseServiceHandler, a part of the org.apache.hadoop.hbase.thrift2
122 * package.
123 */
124@Category({ClientTests.class, MediumTests.class})
125public class TestThriftHBaseServiceHandler {
126
127  @ClassRule
128  public static final HBaseClassTestRule CLASS_RULE =
129      HBaseClassTestRule.forClass(TestThriftHBaseServiceHandler.class);
130
131  private static final Logger LOG = LoggerFactory.getLogger(TestThriftHBaseServiceHandler.class);
132  private static final HBaseTestingUtility UTIL = new HBaseTestingUtility();
133
134  // Static names for tables, columns, rows, and values
135  private static byte[] tableAname = Bytes.toBytes("tableA");
136  private static byte[] familyAname = Bytes.toBytes("familyA");
137  private static byte[] familyBname = Bytes.toBytes("familyB");
138  private static byte[] qualifierAname = Bytes.toBytes("qualifierA");
139  private static byte[] qualifierBname = Bytes.toBytes("qualifierB");
140  private static byte[] valueAname = Bytes.toBytes("valueA");
141  private static byte[] valueBname = Bytes.toBytes("valueB");
142  private static HColumnDescriptor[] families = new HColumnDescriptor[] {
143      new HColumnDescriptor(familyAname).setMaxVersions(3),
144      new HColumnDescriptor(familyBname).setMaxVersions(2)
145  };
146
147
148  private static final MetricsAssertHelper metricsHelper =
149      CompatibilityFactory.getInstance(MetricsAssertHelper.class);
150
151  @Rule
152  public TestName name = new TestName();
153
154
155  public void assertTColumnValuesEqual(List<TColumnValue> columnValuesA,
156      List<TColumnValue> columnValuesB) {
157    assertEquals(columnValuesA.size(), columnValuesB.size());
158    Comparator<TColumnValue> comparator = new Comparator<TColumnValue>() {
159      @Override
160      public int compare(TColumnValue o1, TColumnValue o2) {
161        return Bytes.compareTo(Bytes.add(o1.getFamily(), o1.getQualifier()),
162            Bytes.add(o2.getFamily(), o2.getQualifier()));
163      }
164    };
165    Collections.sort(columnValuesA, comparator);
166    Collections.sort(columnValuesB, comparator);
167
168    for (int i = 0; i < columnValuesA.size(); i++) {
169      TColumnValue a = columnValuesA.get(i);
170      TColumnValue b = columnValuesB.get(i);
171      assertTColumnValueEqual(a, b);
172    }
173  }
174
175  public void assertTColumnValueEqual(TColumnValue a, TColumnValue b) {
176    assertArrayEquals(a.getFamily(), b.getFamily());
177    assertArrayEquals(a.getQualifier(), b.getQualifier());
178    assertArrayEquals(a.getValue(), b.getValue());
179  }
180
181  @BeforeClass
182  public static void beforeClass() throws Exception {
183    UTIL.getConfiguration().set("hbase.client.retries.number", "3");
184    UTIL.startMiniCluster();
185    Admin admin = UTIL.getAdmin();
186    HTableDescriptor tableDescriptor = new HTableDescriptor(TableName.valueOf(tableAname));
187    for (HColumnDescriptor family : families) {
188      tableDescriptor.addFamily(family);
189    }
190    admin.createTable(tableDescriptor);
191    admin.close();
192  }
193
194  @AfterClass
195  public static void afterClass() throws Exception {
196    UTIL.shutdownMiniCluster();
197  }
198
199  @Before
200  public void setup() throws Exception {
201
202  }
203
204  private ThriftHBaseServiceHandler createHandler() throws TException {
205    try {
206      Configuration conf = UTIL.getConfiguration();
207      return new ThriftHBaseServiceHandler(conf, UserProvider.instantiate(conf));
208    } catch (IOException ie) {
209      throw new TException(ie);
210    }
211  }
212
213  @Test
214  public void testExists() throws TIOError, TException {
215    ThriftHBaseServiceHandler handler = createHandler();
216    byte[] rowName = Bytes.toBytes("testExists");
217    ByteBuffer table = wrap(tableAname);
218
219    TGet get = new TGet(wrap(rowName));
220    assertFalse(handler.exists(table, get));
221
222    List<TColumnValue> columnValues = new ArrayList<>(2);
223    columnValues.add(new TColumnValue(wrap(familyAname), wrap(qualifierAname), wrap(valueAname)));
224    columnValues.add(new TColumnValue(wrap(familyBname), wrap(qualifierBname), wrap(valueBname)));
225    TPut put = new TPut(wrap(rowName), columnValues);
226    put.setColumnValues(columnValues);
227
228    handler.put(table, put);
229
230    assertTrue(handler.exists(table, get));
231  }
232
233  @Test
234  public void testExistsAll() throws TIOError, TException {
235    ThriftHBaseServiceHandler handler = createHandler();
236    byte[] rowName1 = Bytes.toBytes("testExistsAll1");
237    byte[] rowName2 = Bytes.toBytes("testExistsAll2");
238    ByteBuffer table = wrap(tableAname);
239
240    List<TGet> gets = new ArrayList<>();
241    gets.add(new TGet(wrap(rowName2)));
242    gets.add(new TGet(wrap(rowName2)));
243    List<Boolean> existsResult1 = handler.existsAll(table, gets);
244    assertFalse(existsResult1.get(0));
245    assertFalse(existsResult1.get(1));
246
247    List<TColumnValue> columnValues = new ArrayList<TColumnValue>();
248    columnValues.add(new TColumnValue(wrap(familyAname), wrap(qualifierAname), wrap(valueAname)));
249    columnValues.add(new TColumnValue(wrap(familyBname), wrap(qualifierBname), wrap(valueBname)));
250    List<TPut> puts = new ArrayList<TPut>();
251    puts.add(new TPut(wrap(rowName1), columnValues));
252    puts.add(new TPut(wrap(rowName2), columnValues));
253
254    handler.putMultiple(table, puts);
255    List<Boolean> existsResult2 = handler.existsAll(table,gets );
256
257    assertTrue(existsResult2.get(0));
258    assertTrue(existsResult2.get(1));
259  }
260
261  @Test
262  public void testPutGet() throws Exception {
263    ThriftHBaseServiceHandler handler = createHandler();
264    byte[] rowName = Bytes.toBytes("testPutGet");
265    ByteBuffer table = wrap(tableAname);
266
267    List<TColumnValue> columnValues = new ArrayList<>(2);
268    columnValues.add(new TColumnValue(wrap(familyAname), wrap(qualifierAname), wrap(valueAname)));
269    columnValues.add(new TColumnValue(wrap(familyBname), wrap(qualifierBname), wrap(valueBname)));
270    TPut put = new TPut(wrap(rowName), columnValues);
271
272    put.setColumnValues(columnValues);
273
274    handler.put(table, put);
275
276    TGet get = new TGet(wrap(rowName));
277
278    TResult result = handler.get(table, get);
279    assertArrayEquals(rowName, result.getRow());
280    List<TColumnValue> returnedColumnValues = result.getColumnValues();
281    assertTColumnValuesEqual(columnValues, returnedColumnValues);
282  }
283
284  @Test
285  public void testPutGetMultiple() throws Exception {
286    ThriftHBaseServiceHandler handler = createHandler();
287    ByteBuffer table = wrap(tableAname);
288    byte[] rowName1 = Bytes.toBytes("testPutGetMultiple1");
289    byte[] rowName2 = Bytes.toBytes("testPutGetMultiple2");
290
291    List<TColumnValue> columnValues = new ArrayList<>(2);
292    columnValues.add(new TColumnValue(wrap(familyAname), wrap(qualifierAname), wrap(valueAname)));
293    columnValues.add(new TColumnValue(wrap(familyBname), wrap(qualifierBname), wrap(valueBname)));
294    List<TPut> puts = new ArrayList<>(2);
295    puts.add(new TPut(wrap(rowName1), columnValues));
296    puts.add(new TPut(wrap(rowName2), columnValues));
297
298    handler.putMultiple(table, puts);
299
300    List<TGet> gets = new ArrayList<>(2);
301    gets.add(new TGet(wrap(rowName1)));
302    gets.add(new TGet(wrap(rowName2)));
303
304    List<TResult> results = handler.getMultiple(table, gets);
305    assertEquals(2, results.size());
306
307    assertArrayEquals(rowName1, results.get(0).getRow());
308    assertTColumnValuesEqual(columnValues, results.get(0).getColumnValues());
309
310    assertArrayEquals(rowName2, results.get(1).getRow());
311    assertTColumnValuesEqual(columnValues, results.get(1).getColumnValues());
312  }
313
314  @Test
315  public void testDeleteMultiple() throws Exception {
316    ThriftHBaseServiceHandler handler = createHandler();
317    ByteBuffer table = wrap(tableAname);
318    byte[] rowName1 = Bytes.toBytes("testDeleteMultiple1");
319    byte[] rowName2 = Bytes.toBytes("testDeleteMultiple2");
320
321    List<TColumnValue> columnValues = new ArrayList<>(2);
322    columnValues.add(new TColumnValue(wrap(familyAname), wrap(qualifierAname), wrap(valueAname)));
323    columnValues.add(new TColumnValue(wrap(familyBname), wrap(qualifierBname), wrap(valueBname)));
324    List<TPut> puts = new ArrayList<>(2);
325    puts.add(new TPut(wrap(rowName1), columnValues));
326    puts.add(new TPut(wrap(rowName2), columnValues));
327
328    handler.putMultiple(table, puts);
329
330    List<TDelete> deletes = new ArrayList<>(2);
331    deletes.add(new TDelete(wrap(rowName1)));
332    deletes.add(new TDelete(wrap(rowName2)));
333
334    List<TDelete> deleteResults = handler.deleteMultiple(table, deletes);
335    // 0 means they were all successfully applies
336    assertEquals(0, deleteResults.size());
337
338    assertFalse(handler.exists(table, new TGet(wrap(rowName1))));
339    assertFalse(handler.exists(table, new TGet(wrap(rowName2))));
340  }
341
342  @Test
343  public void testDelete() throws Exception {
344    ThriftHBaseServiceHandler handler = createHandler();
345    byte[] rowName = Bytes.toBytes("testDelete");
346    ByteBuffer table = wrap(tableAname);
347
348    List<TColumnValue> columnValues = new ArrayList<>(2);
349    TColumnValue columnValueA = new TColumnValue(wrap(familyAname), wrap(qualifierAname),
350      wrap(valueAname));
351    TColumnValue columnValueB = new TColumnValue(wrap(familyBname), wrap(qualifierBname),
352      wrap(valueBname));
353    columnValues.add(columnValueA);
354    columnValues.add(columnValueB);
355    TPut put = new TPut(wrap(rowName), columnValues);
356
357    put.setColumnValues(columnValues);
358
359    handler.put(table, put);
360
361    TDelete delete = new TDelete(wrap(rowName));
362    List<TColumn> deleteColumns = new ArrayList<>(1);
363    TColumn deleteColumn = new TColumn(wrap(familyAname));
364    deleteColumn.setQualifier(qualifierAname);
365    deleteColumns.add(deleteColumn);
366    delete.setColumns(deleteColumns);
367
368    handler.deleteSingle(table, delete);
369
370    TGet get = new TGet(wrap(rowName));
371    TResult result = handler.get(table, get);
372    assertArrayEquals(rowName, result.getRow());
373    List<TColumnValue> returnedColumnValues = result.getColumnValues();
374    List<TColumnValue> expectedColumnValues = new ArrayList<>(1);
375    expectedColumnValues.add(columnValueB);
376    assertTColumnValuesEqual(expectedColumnValues, returnedColumnValues);
377  }
378
379  @Test
380  public void testDeleteAllTimestamps() throws Exception {
381    ThriftHBaseServiceHandler handler = createHandler();
382    byte[] rowName = Bytes.toBytes("testDeleteAllTimestamps");
383    ByteBuffer table = wrap(tableAname);
384
385    List<TColumnValue> columnValues = new ArrayList<>(1);
386    TColumnValue columnValueA = new TColumnValue(wrap(familyAname), wrap(qualifierAname),
387      wrap(valueAname));
388    columnValueA.setTimestamp(System.currentTimeMillis() - 10);
389    columnValues.add(columnValueA);
390    TPut put = new TPut(wrap(rowName), columnValues);
391
392    put.setColumnValues(columnValues);
393
394    handler.put(table, put);
395    columnValueA.setTimestamp(System.currentTimeMillis());
396    handler.put(table, put);
397
398    TGet get = new TGet(wrap(rowName));
399    get.setMaxVersions(2);
400    TResult result = handler.get(table, get);
401    assertEquals(2, result.getColumnValuesSize());
402
403    TDelete delete = new TDelete(wrap(rowName));
404    List<TColumn> deleteColumns = new ArrayList<>(1);
405    TColumn deleteColumn = new TColumn(wrap(familyAname));
406    deleteColumn.setQualifier(qualifierAname);
407    deleteColumns.add(deleteColumn);
408    delete.setColumns(deleteColumns);
409    delete.setDeleteType(TDeleteType.DELETE_COLUMNS); // This is the default anyway.
410
411    handler.deleteSingle(table, delete);
412
413    get = new TGet(wrap(rowName));
414    result = handler.get(table, get);
415    assertNull(result.getRow());
416    assertEquals(0, result.getColumnValuesSize());
417  }
418
419  @Test
420  public void testDeleteSingleTimestamp() throws Exception {
421    ThriftHBaseServiceHandler handler = createHandler();
422    byte[] rowName = Bytes.toBytes("testDeleteSingleTimestamp");
423    ByteBuffer table = wrap(tableAname);
424
425    long timestamp1 = System.currentTimeMillis() - 10;
426    long timestamp2 = System.currentTimeMillis();
427
428    List<TColumnValue> columnValues = new ArrayList<>(1);
429    TColumnValue columnValueA = new TColumnValue(wrap(familyAname), wrap(qualifierAname),
430      wrap(valueAname));
431    columnValueA.setTimestamp(timestamp1);
432    columnValues.add(columnValueA);
433    TPut put = new TPut(wrap(rowName), columnValues);
434
435    put.setColumnValues(columnValues);
436
437    handler.put(table, put);
438    columnValueA.setTimestamp(timestamp2);
439    handler.put(table, put);
440
441    TGet get = new TGet(wrap(rowName));
442    get.setMaxVersions(2);
443    TResult result = handler.get(table, get);
444    assertEquals(2, result.getColumnValuesSize());
445
446    TDelete delete = new TDelete(wrap(rowName));
447    List<TColumn> deleteColumns = new ArrayList<>(1);
448    TColumn deleteColumn = new TColumn(wrap(familyAname));
449    deleteColumn.setQualifier(qualifierAname);
450    deleteColumns.add(deleteColumn);
451    delete.setColumns(deleteColumns);
452    delete.setDeleteType(TDeleteType.DELETE_COLUMN);
453
454    handler.deleteSingle(table, delete);
455
456    get = new TGet(wrap(rowName));
457    result = handler.get(table, get);
458    assertArrayEquals(rowName, result.getRow());
459    assertEquals(1, result.getColumnValuesSize());
460    // the older timestamp should remain.
461    assertEquals(timestamp1, result.getColumnValues().get(0).getTimestamp());
462  }
463
464  @Test
465  public void testDeleteFamily() throws Exception {
466    ThriftHBaseServiceHandler handler = createHandler();
467    byte[] rowName = Bytes.toBytes("testDeleteFamily");
468    ByteBuffer table = wrap(tableAname);
469
470    long timestamp1 = System.currentTimeMillis() - 10;
471    long timestamp2 = System.currentTimeMillis();
472
473    List<TColumnValue> columnValues = new ArrayList<>();
474    TColumnValue columnValueA =
475        new TColumnValue(wrap(familyAname), wrap(qualifierAname), wrap(valueAname));
476    columnValueA.setTimestamp(timestamp1);
477    columnValues.add(columnValueA);
478    TPut put = new TPut(wrap(rowName), columnValues);
479
480    put.setColumnValues(columnValues);
481
482    handler.put(table, put);
483    columnValueA.setTimestamp(timestamp2);
484    handler.put(table, put);
485
486    TGet get = new TGet(wrap(rowName));
487    get.setMaxVersions(2);
488    TResult result = handler.get(table, get);
489    assertEquals(2, result.getColumnValuesSize());
490
491    TDelete delete = new TDelete(wrap(rowName));
492    List<TColumn> deleteColumns = new ArrayList<>();
493    TColumn deleteColumn = new TColumn(wrap(familyAname));
494    deleteColumns.add(deleteColumn);
495    delete.setColumns(deleteColumns);
496    delete.setDeleteType(TDeleteType.DELETE_FAMILY);
497
498    handler.deleteSingle(table, delete);
499
500    get = new TGet(wrap(rowName));
501    result = handler.get(table, get);
502    assertArrayEquals(null, result.getRow());
503    assertEquals(0, result.getColumnValuesSize());
504  }
505
506  @Test
507  public void testDeleteFamilyVersion() throws Exception {
508    ThriftHBaseServiceHandler handler = createHandler();
509    byte[] rowName = Bytes.toBytes("testDeleteFamilyVersion");
510    ByteBuffer table = wrap(tableAname);
511
512    long timestamp1 = System.currentTimeMillis() - 10;
513    long timestamp2 = System.currentTimeMillis();
514
515    List<TColumnValue> columnValues = new ArrayList<>();
516    TColumnValue columnValueA =
517        new TColumnValue(wrap(familyAname), wrap(qualifierAname), wrap(valueAname));
518    columnValueA.setTimestamp(timestamp1);
519    columnValues.add(columnValueA);
520    TPut put = new TPut(wrap(rowName), columnValues);
521
522    put.setColumnValues(columnValues);
523
524    handler.put(table, put);
525    columnValueA.setTimestamp(timestamp2);
526    handler.put(table, put);
527
528    TGet get = new TGet(wrap(rowName));
529    get.setMaxVersions(2);
530    TResult result = handler.get(table, get);
531    assertEquals(2, result.getColumnValuesSize());
532
533    TDelete delete = new TDelete(wrap(rowName));
534    List<TColumn> deleteColumns = new ArrayList<>();
535    TColumn deleteColumn = new TColumn(wrap(familyAname));
536    deleteColumn.setTimestamp(timestamp1);
537    deleteColumns.add(deleteColumn);
538    delete.setColumns(deleteColumns);
539    delete.setDeleteType(TDeleteType.DELETE_FAMILY_VERSION);
540
541    handler.deleteSingle(table, delete);
542
543    get = new TGet(wrap(rowName));
544    result = handler.get(table, get);
545    assertArrayEquals(rowName, result.getRow());
546    assertEquals(1, result.getColumnValuesSize());
547    assertEquals(timestamp2, result.getColumnValues().get(0).getTimestamp());
548  }
549
550  @Test
551  public void testIncrement() throws Exception {
552    ThriftHBaseServiceHandler handler = createHandler();
553    byte[] rowName = Bytes.toBytes("testIncrement");
554    ByteBuffer table = wrap(tableAname);
555
556    List<TColumnValue> columnValues = new ArrayList<>(1);
557    columnValues.add(new TColumnValue(wrap(familyAname), wrap(qualifierAname),
558      wrap(Bytes.toBytes(1L))));
559    TPut put = new TPut(wrap(rowName), columnValues);
560    put.setColumnValues(columnValues);
561    handler.put(table, put);
562
563    List<TColumnIncrement> incrementColumns = new ArrayList<>(1);
564    incrementColumns.add(new TColumnIncrement(wrap(familyAname), wrap(qualifierAname)));
565    TIncrement increment = new TIncrement(wrap(rowName), incrementColumns);
566    handler.increment(table, increment);
567
568    TGet get = new TGet(wrap(rowName));
569    TResult result = handler.get(table, get);
570
571    assertArrayEquals(rowName, result.getRow());
572    assertEquals(1, result.getColumnValuesSize());
573    TColumnValue columnValue = result.getColumnValues().get(0);
574    assertArrayEquals(Bytes.toBytes(2L), columnValue.getValue());
575  }
576
577  @Test
578  public void testAppend() throws Exception {
579    ThriftHBaseServiceHandler handler = createHandler();
580    byte[] rowName = Bytes.toBytes("testAppend");
581    ByteBuffer table = wrap(tableAname);
582    byte[] v1 = Bytes.toBytes("42");
583    byte[] v2 = Bytes.toBytes("23");
584    List<TColumnValue> columnValues = new ArrayList<>(1);
585    columnValues.add(new TColumnValue(wrap(familyAname), wrap(qualifierAname), wrap(v1)));
586    TPut put = new TPut(wrap(rowName), columnValues);
587    put.setColumnValues(columnValues);
588    handler.put(table, put);
589
590    List<TColumnValue> appendColumns = new ArrayList<>(1);
591    appendColumns.add(new TColumnValue(wrap(familyAname), wrap(qualifierAname), wrap(v2)));
592    TAppend append = new TAppend(wrap(rowName), appendColumns);
593    handler.append(table, append);
594
595    TGet get = new TGet(wrap(rowName));
596    TResult result = handler.get(table, get);
597
598    assertArrayEquals(rowName, result.getRow());
599    assertEquals(1, result.getColumnValuesSize());
600    TColumnValue columnValue = result.getColumnValues().get(0);
601    assertArrayEquals(Bytes.add(v1, v2), columnValue.getValue());
602  }
603
604  /**
605   * check that checkAndPut fails if the cell does not exist, then put in the cell, then check
606   * that the checkAndPut succeeds.
607   */
608  @Test
609  public void testCheckAndPut() throws Exception {
610    ThriftHBaseServiceHandler handler = createHandler();
611    byte[] rowName = Bytes.toBytes("testCheckAndPut");
612    ByteBuffer table = wrap(tableAname);
613
614    List<TColumnValue> columnValuesA = new ArrayList<>(1);
615    TColumnValue columnValueA = new TColumnValue(wrap(familyAname), wrap(qualifierAname),
616      wrap(valueAname));
617    columnValuesA.add(columnValueA);
618    TPut putA = new TPut(wrap(rowName), columnValuesA);
619    putA.setColumnValues(columnValuesA);
620
621    List<TColumnValue> columnValuesB = new ArrayList<>(1);
622    TColumnValue columnValueB = new TColumnValue(wrap(familyBname), wrap(qualifierBname),
623      wrap(valueBname));
624    columnValuesB.add(columnValueB);
625    TPut putB = new TPut(wrap(rowName), columnValuesB);
626    putB.setColumnValues(columnValuesB);
627
628    assertFalse(handler.checkAndPut(table, wrap(rowName), wrap(familyAname),
629      wrap(qualifierAname), wrap(valueAname), putB));
630
631    TGet get = new TGet(wrap(rowName));
632    TResult result = handler.get(table, get);
633    assertEquals(0, result.getColumnValuesSize());
634
635    handler.put(table, putA);
636
637    assertTrue(handler.checkAndPut(table, wrap(rowName), wrap(familyAname),
638      wrap(qualifierAname), wrap(valueAname), putB));
639
640    result = handler.get(table, get);
641    assertArrayEquals(rowName, result.getRow());
642    List<TColumnValue> returnedColumnValues = result.getColumnValues();
643    List<TColumnValue> expectedColumnValues = new ArrayList<>(2);
644    expectedColumnValues.add(columnValueA);
645    expectedColumnValues.add(columnValueB);
646    assertTColumnValuesEqual(expectedColumnValues, returnedColumnValues);
647  }
648
649  /**
650   * check that checkAndDelete fails if the cell does not exist, then put in the cell, then
651   * check that the checkAndDelete succeeds.
652   */
653  @Test
654  public void testCheckAndDelete() throws Exception {
655    ThriftHBaseServiceHandler handler = createHandler();
656    byte[] rowName = Bytes.toBytes("testCheckAndDelete");
657    ByteBuffer table = wrap(tableAname);
658
659    List<TColumnValue> columnValuesA = new ArrayList<>(1);
660    TColumnValue columnValueA = new TColumnValue(wrap(familyAname), wrap(qualifierAname),
661      wrap(valueAname));
662    columnValuesA.add(columnValueA);
663    TPut putA = new TPut(wrap(rowName), columnValuesA);
664    putA.setColumnValues(columnValuesA);
665
666    List<TColumnValue> columnValuesB = new ArrayList<>(1);
667    TColumnValue columnValueB = new TColumnValue(wrap(familyBname), wrap(qualifierBname),
668      wrap(valueBname));
669    columnValuesB.add(columnValueB);
670    TPut putB = new TPut(wrap(rowName), columnValuesB);
671    putB.setColumnValues(columnValuesB);
672
673    // put putB so that we know whether the row has been deleted or not
674    handler.put(table, putB);
675
676    TDelete delete = new TDelete(wrap(rowName));
677
678    assertFalse(handler.checkAndDelete(table, wrap(rowName), wrap(familyAname),
679        wrap(qualifierAname), wrap(valueAname), delete));
680
681    TGet get = new TGet(wrap(rowName));
682    TResult result = handler.get(table, get);
683    assertArrayEquals(rowName, result.getRow());
684    assertTColumnValuesEqual(columnValuesB, result.getColumnValues());
685
686    handler.put(table, putA);
687
688    assertTrue(handler.checkAndDelete(table, wrap(rowName), wrap(familyAname),
689      wrap(qualifierAname), wrap(valueAname), delete));
690
691    result = handler.get(table, get);
692    assertFalse(result.isSetRow());
693    assertEquals(0, result.getColumnValuesSize());
694  }
695
696  @Test
697  public void testScan() throws Exception {
698    ThriftHBaseServiceHandler handler = createHandler();
699    ByteBuffer table = wrap(tableAname);
700
701    // insert data
702    TColumnValue columnValue = new TColumnValue(wrap(familyAname), wrap(qualifierAname),
703      wrap(valueAname));
704    List<TColumnValue> columnValues = new ArrayList<>(1);
705    columnValues.add(columnValue);
706    for (int i = 0; i < 10; i++) {
707      TPut put = new TPut(wrap(Bytes.toBytes("testScan" + i)), columnValues);
708      handler.put(table, put);
709    }
710
711    // create scan instance
712    TScan scan = new TScan();
713    List<TColumn> columns = new ArrayList<>(1);
714    TColumn column = new TColumn();
715    column.setFamily(familyAname);
716    column.setQualifier(qualifierAname);
717    columns.add(column);
718    scan.setColumns(columns);
719    scan.setStartRow(Bytes.toBytes("testScan"));
720    scan.setStopRow(Bytes.toBytes("testScan\uffff"));
721
722    // get scanner and rows
723    int scanId = handler.openScanner(table, scan);
724    List<TResult> results = handler.getScannerRows(scanId, 10);
725    assertEquals(10, results.size());
726    for (int i = 0; i < 10; i++) {
727      // check if the rows are returned and in order
728      assertArrayEquals(Bytes.toBytes("testScan" + i), results.get(i).getRow());
729    }
730
731    // check that we are at the end of the scan
732    results = handler.getScannerRows(scanId, 10);
733    assertEquals(0, results.size());
734
735    // close scanner and check that it was indeed closed
736    handler.closeScanner(scanId);
737    try {
738      handler.getScannerRows(scanId, 10);
739      fail("Scanner id should be invalid");
740    } catch (TIllegalArgument e) {
741    }
742  }
743
744  /**
745   * Tests keeping a HBase scanner alive for long periods of time. Each call to getScannerRow()
746   * should reset the ConnectionCache timeout for the scanner's connection
747   */
748  @Test
749  public void testLongLivedScan() throws Exception {
750    int numTrials = 6;
751    int trialPause = 1000;
752    int cleanUpInterval = 100;
753    Configuration conf = new Configuration(UTIL.getConfiguration());
754    // Set the ConnectionCache timeout to trigger halfway through the trials
755    conf.setInt(MAX_IDLETIME, (numTrials / 2) * trialPause);
756    conf.setInt(CLEANUP_INTERVAL, cleanUpInterval);
757    ThriftHBaseServiceHandler handler = new ThriftHBaseServiceHandler(conf,
758        UserProvider.instantiate(conf));
759
760    ByteBuffer table = wrap(tableAname);
761    // insert data
762    TColumnValue columnValue = new TColumnValue(wrap(familyAname), wrap(qualifierAname),
763        wrap(valueAname));
764    List<TColumnValue> columnValues = new ArrayList<>(1);
765    columnValues.add(columnValue);
766    for (int i = 0; i < numTrials; i++) {
767      TPut put = new TPut(wrap(Bytes.toBytes("testScan" + i)), columnValues);
768      handler.put(table, put);
769    }
770
771    // create scan instance
772    TScan scan = new TScan();
773    List<TColumn> columns = new ArrayList<>(1);
774    TColumn column = new TColumn();
775    column.setFamily(familyAname);
776    column.setQualifier(qualifierAname);
777    columns.add(column);
778    scan.setColumns(columns);
779    scan.setStartRow(Bytes.toBytes("testScan"));
780    scan.setStopRow(Bytes.toBytes("testScan\uffff"));
781    // Prevent the scanner from caching results
782    scan.setCaching(1);
783
784    // get scanner and rows
785    int scanId = handler.openScanner(table, scan);
786    for (int i = 0; i < numTrials; i++) {
787      // Make sure that the Scanner doesn't throw an exception after the ConnectionCache timeout
788      List<TResult> results = handler.getScannerRows(scanId, 1);
789      assertArrayEquals(Bytes.toBytes("testScan" + i), results.get(0).getRow());
790      Thread.sleep(trialPause);
791    }
792  }
793
794  @Test
795  public void testReverseScan() throws Exception {
796    ThriftHBaseServiceHandler handler = createHandler();
797    ByteBuffer table = wrap(tableAname);
798
799    // insert data
800    TColumnValue columnValue = new TColumnValue(wrap(familyAname), wrap(qualifierAname),
801      wrap(valueAname));
802    List<TColumnValue> columnValues = new ArrayList<>(1);
803    columnValues.add(columnValue);
804    for (int i = 0; i < 10; i++) {
805      TPut put = new TPut(wrap(Bytes.toBytes("testReverseScan" + i)), columnValues);
806      handler.put(table, put);
807    }
808
809    // create reverse scan instance
810    TScan scan = new TScan();
811    scan.setReversed(true);
812    List<TColumn> columns = new ArrayList<>(1);
813    TColumn column = new TColumn();
814    column.setFamily(familyAname);
815    column.setQualifier(qualifierAname);
816    columns.add(column);
817    scan.setColumns(columns);
818    scan.setStartRow(Bytes.toBytes("testReverseScan\uffff"));
819    scan.setStopRow(Bytes.toBytes("testReverseScan"));
820
821    // get scanner and rows
822    int scanId = handler.openScanner(table, scan);
823    List<TResult> results = handler.getScannerRows(scanId, 10);
824    assertEquals(10, results.size());
825    for (int i = 0; i < 10; i++) {
826      // check if the rows are returned and in order
827      assertArrayEquals(Bytes.toBytes("testReverseScan" + (9 - i)), results.get(i).getRow());
828    }
829
830    // check that we are at the end of the scan
831    results = handler.getScannerRows(scanId, 10);
832    assertEquals(0, results.size());
833
834    // close scanner and check that it was indeed closed
835    handler.closeScanner(scanId);
836    try {
837      handler.getScannerRows(scanId, 10);
838      fail("Scanner id should be invalid");
839    } catch (TIllegalArgument e) {
840    }
841  }
842
843  @Test
844  public void testScanWithFilter() throws Exception {
845    ThriftHBaseServiceHandler handler = createHandler();
846    ByteBuffer table = wrap(tableAname);
847
848    // insert data
849    TColumnValue columnValue = new TColumnValue(wrap(familyAname), wrap(qualifierAname),
850      wrap(valueAname));
851    List<TColumnValue> columnValues = new ArrayList<>(1);
852    columnValues.add(columnValue);
853    for (int i = 0; i < 10; i++) {
854      TPut put = new TPut(wrap(Bytes.toBytes("testScanWithFilter" + i)), columnValues);
855      handler.put(table, put);
856    }
857
858    // create scan instance with filter
859    TScan scan = new TScan();
860    List<TColumn> columns = new ArrayList<>(1);
861    TColumn column = new TColumn();
862    column.setFamily(familyAname);
863    column.setQualifier(qualifierAname);
864    columns.add(column);
865    scan.setColumns(columns);
866    scan.setStartRow(Bytes.toBytes("testScanWithFilter"));
867    scan.setStopRow(Bytes.toBytes("testScanWithFilter\uffff"));
868    // only get the key part
869    scan.setFilterString(wrap(Bytes.toBytes("KeyOnlyFilter()")));
870
871    // get scanner and rows
872    int scanId = handler.openScanner(table, scan);
873    List<TResult> results = handler.getScannerRows(scanId, 10);
874    assertEquals(10, results.size());
875    for (int i = 0; i < 10; i++) {
876      // check if the rows are returned and in order
877      assertArrayEquals(Bytes.toBytes("testScanWithFilter" + i), results.get(i).getRow());
878      // check that the value is indeed stripped by the filter
879      assertEquals(0, results.get(i).getColumnValues().get(0).getValue().length);
880    }
881
882    // check that we are at the end of the scan
883    results = handler.getScannerRows(scanId, 10);
884    assertEquals(0, results.size());
885
886    // close scanner and check that it was indeed closed
887    handler.closeScanner(scanId);
888    try {
889      handler.getScannerRows(scanId, 10);
890      fail("Scanner id should be invalid");
891    } catch (TIllegalArgument e) {
892    }
893  }
894
895  @Test
896  public void testScanWithColumnFamilyTimeRange() throws Exception {
897    ThriftHBaseServiceHandler handler = createHandler();
898    ByteBuffer table = wrap(tableAname);
899
900    // insert data
901    TColumnValue familyAColumnValue = new TColumnValue(wrap(familyAname), wrap(qualifierAname),
902        wrap(valueAname));
903    TColumnValue familyBColumnValue = new TColumnValue(wrap(familyBname), wrap(qualifierBname),
904        wrap(valueBname));
905    long minTimestamp = System.currentTimeMillis();
906    for (int i = 0; i < 10; i++) {
907      familyAColumnValue.setTimestamp(minTimestamp + i);
908      familyBColumnValue.setTimestamp(minTimestamp + i);
909      List<TColumnValue> columnValues = new ArrayList<>(2);
910      columnValues.add(familyAColumnValue);
911      columnValues.add(familyBColumnValue);
912      TPut put = new TPut(wrap(Bytes.toBytes("testScanWithColumnFamilyTimeRange" + i)),
913          columnValues);
914      handler.put(table, put);
915    }
916
917    // create scan instance with column family time range
918    TScan scan = new TScan();
919    Map<ByteBuffer,TTimeRange> colFamTimeRangeMap = new HashMap<>(2);
920    colFamTimeRangeMap.put(wrap(familyAname), new TTimeRange(minTimestamp + 3, minTimestamp + 5));
921    colFamTimeRangeMap.put(wrap(familyBname), new TTimeRange(minTimestamp + 6, minTimestamp + 9));
922    scan.setColFamTimeRangeMap(colFamTimeRangeMap);
923
924    // get scanner and rows
925    int scanId = handler.openScanner(table, scan);
926    List<TResult> results = handler.getScannerRows(scanId, 5);
927    assertEquals(5, results.size());
928    int familyACount = 0;
929    int familyBCount = 0;
930    for (TResult result : results) {
931      List<TColumnValue> columnValues = result.getColumnValues();
932      if (CollectionUtils.isNotEmpty(columnValues)) {
933        if (Bytes.equals(familyAname, columnValues.get(0).getFamily())) {
934          familyACount++;
935        } else if (Bytes.equals(familyBname, columnValues.get(0).getFamily())) {
936          familyBCount++;
937        }
938      }
939    }
940    assertEquals(2, familyACount);
941    assertEquals(3, familyBCount);
942
943    // check that we are at the end of the scan
944    results = handler.getScannerRows(scanId, 1);
945    assertEquals(0, results.size());
946
947    // close scanner and check that it was indeed closed
948    handler.closeScanner(scanId);
949    try {
950      handler.getScannerRows(scanId, 1);
951      fail("Scanner id should be invalid");
952    } catch (TIllegalArgument e) {
953    }
954  }
955
956  @Test
957  public void testSmallScan() throws Exception {
958    ThriftHBaseServiceHandler handler = createHandler();
959    ByteBuffer table = wrap(tableAname);
960
961    // insert data
962    TColumnValue columnValue = new TColumnValue(wrap(familyAname), wrap(qualifierAname),
963            wrap(valueAname));
964    List<TColumnValue> columnValues = new ArrayList<>();
965    columnValues.add(columnValue);
966    for (int i = 0; i < 10; i++) {
967      TPut put = new TPut(wrap(Bytes.toBytes("testSmallScan" + i)), columnValues);
968      handler.put(table, put);
969    }
970
971    // small scan instance
972    TScan scan = new TScan();
973    scan.setStartRow(Bytes.toBytes("testSmallScan"));
974    scan.setStopRow(Bytes.toBytes("testSmallScan\uffff"));
975    scan.setReadType(TReadType.PREAD);
976    scan.setCaching(2);
977
978    // get scanner and rows
979    int scanId = handler.openScanner(table, scan);
980    List<TResult> results = handler.getScannerRows(scanId, 10);
981    assertEquals(10, results.size());
982    for (int i = 0; i < 10; i++) {
983      // check if the rows are returned and in order
984      assertArrayEquals(Bytes.toBytes("testSmallScan" + i), results.get(i).getRow());
985    }
986
987    // check that we are at the end of the scan
988    results = handler.getScannerRows(scanId, 10);
989    assertEquals(0, results.size());
990
991    // close scanner and check that it was indeed closed
992    handler.closeScanner(scanId);
993    try {
994      handler.getScannerRows(scanId, 10);
995      fail("Scanner id should be invalid");
996    } catch (TIllegalArgument e) {
997    }
998  }
999
1000  @Test
1001  public void testPutTTL() throws Exception {
1002    ThriftHBaseServiceHandler handler = createHandler();
1003    byte[] rowName = Bytes.toBytes("testPutTTL");
1004    ByteBuffer table = wrap(tableAname);
1005    List<TColumnValue> columnValues = new ArrayList<>(1);
1006
1007    // Add some dummy data
1008    columnValues.add(
1009        new TColumnValue(
1010            wrap(familyAname),
1011            wrap(qualifierAname),
1012            wrap(Bytes.toBytes(1L))));
1013
1014
1015    TPut put = new TPut(wrap(rowName), columnValues);
1016    put.setColumnValues(columnValues);
1017
1018    Map<ByteBuffer, ByteBuffer> attributes = new HashMap<>();
1019
1020    // Time in ms for the kv's to live.
1021    long ttlTimeMs = 2000L;
1022
1023    // the _ttl attribute is a number of ms ttl for key values in this put.
1024    attributes.put(wrap(Bytes.toBytes("_ttl")), wrap(Bytes.toBytes(ttlTimeMs)));
1025    // Attach the attributes
1026    put.setAttributes(attributes);
1027    // Send it.
1028    handler.put(table, put);
1029
1030    // Now get the data back
1031    TGet getOne = new TGet(wrap(rowName));
1032    TResult resultOne = handler.get(table, getOne);
1033
1034    // It's there.
1035    assertArrayEquals(rowName, resultOne.getRow());
1036    assertEquals(1, resultOne.getColumnValuesSize());
1037
1038    // Sleep 30 seconds just to make 100% sure that the key value should be expired.
1039    Thread.sleep(ttlTimeMs * 15);
1040
1041    TGet getTwo = new TGet(wrap(rowName));
1042    TResult resultTwo = handler.get(table, getTwo);
1043
1044
1045    // Nothing should be there since it's ttl'd out.
1046    assertNull(resultTwo.getRow());
1047    assertEquals(0, resultTwo.getColumnValuesSize());
1048  }
1049
1050  /**
1051   * Padding numbers to make comparison of sort order easier in a for loop
1052   *
1053   * @param n  The number to pad.
1054   * @param pad  The length to pad up to.
1055   * @return The padded number as a string.
1056   */
1057  private String pad(int n, byte pad) {
1058    String res = Integer.toString(n);
1059    while (res.length() < pad) res = "0" + res;
1060    return res;
1061  }
1062
1063  @Test
1064  public void testScanWithBatchSize() throws Exception {
1065    ThriftHBaseServiceHandler handler = createHandler();
1066    ByteBuffer table = wrap(tableAname);
1067
1068    // insert data
1069    List<TColumnValue> columnValues = new ArrayList<>(100);
1070    for (int i = 0; i < 100; i++) {
1071      String colNum = pad(i, (byte) 3);
1072      TColumnValue columnValue = new TColumnValue(wrap(familyAname),
1073        wrap(Bytes.toBytes("col" + colNum)), wrap(Bytes.toBytes("val" + colNum)));
1074      columnValues.add(columnValue);
1075    }
1076    TPut put = new TPut(wrap(Bytes.toBytes("testScanWithBatchSize")), columnValues);
1077    handler.put(table, put);
1078
1079    // create scan instance
1080    TScan scan = new TScan();
1081    List<TColumn> columns = new ArrayList<>(1);
1082    TColumn column = new TColumn();
1083    column.setFamily(familyAname);
1084    columns.add(column);
1085    scan.setColumns(columns);
1086    scan.setStartRow(Bytes.toBytes("testScanWithBatchSize"));
1087    scan.setStopRow(Bytes.toBytes("testScanWithBatchSize\uffff"));
1088    // set batch size to 10 columns per call
1089    scan.setBatchSize(10);
1090
1091    // get scanner
1092    int scanId = handler.openScanner(table, scan);
1093    List<TResult> results = null;
1094    for (int i = 0; i < 10; i++) {
1095      // get batch for single row (10x10 is what we expect)
1096      results = handler.getScannerRows(scanId, 1);
1097      assertEquals(1, results.size());
1098      // check length of batch
1099      List<TColumnValue> cols = results.get(0).getColumnValues();
1100      assertEquals(10, cols.size());
1101      // check if the columns are returned and in order
1102      for (int y = 0; y < 10; y++) {
1103        int colNum = y + (10 * i);
1104        String colNumPad = pad(colNum, (byte) 3);
1105        assertArrayEquals(Bytes.toBytes("col" + colNumPad), cols.get(y).getQualifier());
1106      }
1107    }
1108
1109    // check that we are at the end of the scan
1110    results = handler.getScannerRows(scanId, 1);
1111    assertEquals(0, results.size());
1112
1113    // close scanner and check that it was indeed closed
1114    handler.closeScanner(scanId);
1115    try {
1116      handler.getScannerRows(scanId, 1);
1117      fail("Scanner id should be invalid");
1118    } catch (TIllegalArgument e) {
1119    }
1120  }
1121
1122  @Test
1123  public void testGetScannerResults() throws Exception {
1124    ThriftHBaseServiceHandler handler = createHandler();
1125    ByteBuffer table = wrap(tableAname);
1126
1127    // insert data
1128    TColumnValue columnValue =
1129        new TColumnValue(wrap(familyAname), wrap(qualifierAname), wrap(valueAname));
1130    List<TColumnValue> columnValues = new ArrayList<>(1);
1131    columnValues.add(columnValue);
1132    for (int i = 0; i < 20; i++) {
1133      TPut put =
1134          new TPut(wrap(Bytes.toBytes("testGetScannerResults" + pad(i, (byte) 2))), columnValues);
1135      handler.put(table, put);
1136    }
1137
1138    // create scan instance
1139    TScan scan = new TScan();
1140    List<TColumn> columns = new ArrayList<>(1);
1141    TColumn column = new TColumn();
1142    column.setFamily(familyAname);
1143    column.setQualifier(qualifierAname);
1144    columns.add(column);
1145    scan.setColumns(columns);
1146    scan.setStartRow(Bytes.toBytes("testGetScannerResults"));
1147
1148    // get 5 rows and check the returned results
1149    scan.setStopRow(Bytes.toBytes("testGetScannerResults05"));
1150    List<TResult> results = handler.getScannerResults(table, scan, 5);
1151    assertEquals(5, results.size());
1152    for (int i = 0; i < 5; i++) {
1153      // check if the rows are returned and in order
1154      assertArrayEquals(Bytes.toBytes("testGetScannerResults" + pad(i, (byte) 2)), results.get(i)
1155          .getRow());
1156    }
1157
1158    // get 10 rows and check the returned results
1159    scan.setStopRow(Bytes.toBytes("testGetScannerResults10"));
1160    results = handler.getScannerResults(table, scan, 10);
1161    assertEquals(10, results.size());
1162    for (int i = 0; i < 10; i++) {
1163      // check if the rows are returned and in order
1164      assertArrayEquals(Bytes.toBytes("testGetScannerResults" + pad(i, (byte) 2)), results.get(i)
1165          .getRow());
1166    }
1167
1168    // get 20 rows and check the returned results
1169    scan.setStopRow(Bytes.toBytes("testGetScannerResults20"));
1170    results = handler.getScannerResults(table, scan, 20);
1171    assertEquals(20, results.size());
1172    for (int i = 0; i < 20; i++) {
1173      // check if the rows are returned and in order
1174      assertArrayEquals(Bytes.toBytes("testGetScannerResults" + pad(i, (byte) 2)), results.get(i)
1175          .getRow());
1176    }
1177
1178    // reverse scan
1179    scan = new TScan();
1180    scan.setColumns(columns);
1181    scan.setReversed(true);
1182    scan.setStartRow(Bytes.toBytes("testGetScannerResults20"));
1183    scan.setStopRow(Bytes.toBytes("testGetScannerResults"));
1184    results = handler.getScannerResults(table, scan, 20);
1185    assertEquals(20, results.size());
1186    for (int i = 0; i < 20; i++) {
1187      // check if the rows are returned and in order
1188      assertArrayEquals(Bytes.toBytes("testGetScannerResults" + pad(19 - i, (byte) 2)),
1189          results.get(i).getRow());
1190    }
1191 }
1192
1193  @Test
1194  public void testFilterRegistration() throws Exception {
1195    Configuration conf = UTIL.getConfiguration();
1196    conf.set("hbase.thrift.filters", "MyFilter:filterclass");
1197    ThriftServer.registerFilters(conf);
1198    Map<String, String> registeredFilters = ParseFilter.getAllFilters();
1199    assertEquals("filterclass", registeredFilters.get("MyFilter"));
1200  }
1201
1202  @Test
1203  public void testMetrics() throws Exception {
1204    Configuration conf = UTIL.getConfiguration();
1205    ThriftMetrics metrics = getMetrics(conf);
1206    ThriftHBaseServiceHandler hbaseHandler = createHandler();
1207    THBaseService.Iface handler =
1208        HbaseHandlerMetricsProxy.newInstance(hbaseHandler, metrics,  conf);
1209    byte[] rowName = Bytes.toBytes("testMetrics");
1210    ByteBuffer table = wrap(tableAname);
1211
1212    TGet get = new TGet(wrap(rowName));
1213    assertFalse(handler.exists(table, get));
1214
1215    List<TColumnValue> columnValues = new ArrayList<>(2);
1216    columnValues.add(new TColumnValue(wrap(familyAname), wrap(qualifierAname), wrap(valueAname)));
1217    columnValues.add(new TColumnValue(wrap(familyBname), wrap(qualifierBname),  wrap(valueBname)));
1218    TPut put = new TPut(wrap(rowName), columnValues);
1219    put.setColumnValues(columnValues);
1220
1221    handler.put(table, put);
1222
1223    assertTrue(handler.exists(table, get));
1224    metricsHelper.assertCounter("put_num_ops", 1, metrics.getSource());
1225    metricsHelper.assertCounter( "exists_num_ops", 2, metrics.getSource());
1226  }
1227
1228  private static ThriftMetrics getMetrics(Configuration conf) throws Exception {
1229    ThriftMetrics m = new ThriftMetrics(conf, ThriftMetrics.ThriftServerType.TWO);
1230    m.getSource().init(); //Clear all the metrics
1231    return m;
1232  }
1233
1234  @Test
1235  public void testMetricsWithException() throws Exception {
1236    byte[] rowkey = Bytes.toBytes("row1");
1237    byte[] family = Bytes.toBytes("f");
1238    byte[] col = Bytes.toBytes("c");
1239    // create a table which will throw exceptions for requests
1240    TableName tableName = TableName.valueOf(name.getMethodName());
1241    HTableDescriptor tableDesc = new HTableDescriptor(tableName);
1242    tableDesc.addCoprocessor(ErrorThrowingGetObserver.class.getName());
1243    tableDesc.addFamily(new HColumnDescriptor(family));
1244
1245    Table table = UTIL.createTable(tableDesc, null);
1246    table.put(new Put(rowkey).addColumn(family, col, Bytes.toBytes("val1")));
1247
1248    ThriftHBaseServiceHandler hbaseHandler = createHandler();
1249    ThriftMetrics metrics = getMetrics(UTIL.getConfiguration());
1250    THBaseService.Iface handler =
1251        HbaseHandlerMetricsProxy.newInstance(hbaseHandler, metrics, null);
1252    ByteBuffer tTableName = wrap(tableName.getName());
1253
1254    // check metrics increment with a successful get
1255    long preGetCounter = metricsHelper.checkCounterExists("get_num_ops", metrics.getSource()) ?
1256        metricsHelper.getCounter("get_num_ops", metrics.getSource()) :
1257        0;
1258    TGet tGet = new TGet(wrap(rowkey));
1259    TResult tResult = handler.get(tTableName, tGet);
1260
1261    List<TColumnValue> expectedColumnValues = Lists.newArrayList(
1262        new TColumnValue(wrap(family), wrap(col), wrap(Bytes.toBytes("val1")))
1263    );
1264    assertArrayEquals(rowkey, tResult.getRow());
1265    List<TColumnValue> returnedColumnValues = tResult.getColumnValues();
1266    assertTColumnValuesEqual(expectedColumnValues, returnedColumnValues);
1267
1268    metricsHelper.assertCounter("get_num_ops", preGetCounter + 1, metrics.getSource());
1269
1270    // check metrics increment when the get throws each exception type
1271    for (ErrorThrowingGetObserver.ErrorType type : ErrorThrowingGetObserver.ErrorType.values()) {
1272      testExceptionType(handler, metrics, tTableName, rowkey, type);
1273    }
1274  }
1275
1276  private void testExceptionType(THBaseService.Iface handler, ThriftMetrics metrics,
1277                                 ByteBuffer tTableName, byte[] rowkey, ErrorThrowingGetObserver.ErrorType errorType) {
1278    long preGetCounter = metricsHelper.getCounter("get_num_ops", metrics.getSource());
1279    String exceptionKey = errorType.getMetricName();
1280    long preExceptionCounter = metricsHelper.checkCounterExists(exceptionKey, metrics.getSource()) ?
1281        metricsHelper.getCounter(exceptionKey, metrics.getSource()) :
1282        0;
1283    TGet tGet = new TGet(wrap(rowkey));
1284    Map<ByteBuffer, ByteBuffer> attributes = new HashMap<>();
1285    attributes.put(wrap(Bytes.toBytes(ErrorThrowingGetObserver.SHOULD_ERROR_ATTRIBUTE)),
1286        wrap(Bytes.toBytes(errorType.name())));
1287    tGet.setAttributes(attributes);
1288    try {
1289      TResult tResult = handler.get(tTableName, tGet);
1290      fail("Get with error attribute should have thrown an exception");
1291    } catch (TException e) {
1292      LOG.info("Received exception: ", e);
1293      metricsHelper.assertCounter("get_num_ops", preGetCounter + 1, metrics.getSource());
1294      metricsHelper.assertCounter(exceptionKey, preExceptionCounter + 1, metrics.getSource());
1295    }
1296
1297  }
1298
1299  /**
1300   * See HBASE-17611
1301   *
1302   * Latency metrics were capped at ~ 2 seconds due to the use of an int variable to capture the
1303   * duration.
1304   */
1305  @Test
1306  public void testMetricsPrecision() throws Exception {
1307    byte[] rowkey = Bytes.toBytes("row1");
1308    byte[] family = Bytes.toBytes("f");
1309    byte[] col = Bytes.toBytes("c");
1310    // create a table which will throw exceptions for requests
1311    TableName tableName = TableName.valueOf("testMetricsPrecision");
1312    HTableDescriptor tableDesc = new HTableDescriptor(tableName);
1313    tableDesc.addCoprocessor(DelayingRegionObserver.class.getName());
1314    tableDesc.addFamily(new HColumnDescriptor(family));
1315
1316    Table table = null;
1317    try {
1318      table = UTIL.createTable(tableDesc, null);
1319
1320      table.put(new Put(rowkey).addColumn(family, col, Bytes.toBytes("val1")));
1321
1322      ThriftHBaseServiceHandler hbaseHandler = createHandler();
1323      ThriftMetrics metrics = getMetrics(UTIL.getConfiguration());
1324      THBaseService.Iface handler =
1325          HbaseHandlerMetricsProxy.newInstance(hbaseHandler, metrics, null);
1326      ByteBuffer tTableName = wrap(tableName.getName());
1327
1328      // check metrics latency with a successful get
1329      TGet tGet = new TGet(wrap(rowkey));
1330      TResult tResult = handler.get(tTableName, tGet);
1331
1332      List<TColumnValue> expectedColumnValues = Lists.newArrayList(
1333          new TColumnValue(wrap(family), wrap(col), wrap(Bytes.toBytes("val1")))
1334      );
1335      assertArrayEquals(rowkey, tResult.getRow());
1336      List<TColumnValue> returnedColumnValues = tResult.getColumnValues();
1337      assertTColumnValuesEqual(expectedColumnValues, returnedColumnValues);
1338
1339      metricsHelper.assertGaugeGt("get_max", 3000L, metrics.getSource());
1340    } finally {
1341      if (table != null) {
1342        try {
1343          table.close();
1344        } catch (IOException ignored) {
1345        }
1346        UTIL.deleteTable(tableName);
1347      }
1348    }
1349  }
1350
1351
1352  @Test
1353  public void testAttribute() throws Exception {
1354    byte[] rowName = Bytes.toBytes("testAttribute");
1355    byte[] attributeKey = Bytes.toBytes("attribute1");
1356    byte[] attributeValue = Bytes.toBytes("value1");
1357    Map<ByteBuffer, ByteBuffer> attributes = new HashMap<>();
1358    attributes.put(wrap(attributeKey), wrap(attributeValue));
1359
1360    TGet tGet = new TGet(wrap(rowName));
1361    tGet.setAttributes(attributes);
1362    Get get = getFromThrift(tGet);
1363    assertArrayEquals(get.getAttribute("attribute1"), attributeValue);
1364
1365    List<TColumnValue> columnValues = new ArrayList<>(1);
1366    columnValues.add(new TColumnValue(wrap(familyAname), wrap(qualifierAname), wrap(valueAname)));
1367    TPut tPut = new TPut(wrap(rowName) , columnValues);
1368    tPut.setAttributes(attributes);
1369    Put put = putFromThrift(tPut);
1370    assertArrayEquals(put.getAttribute("attribute1"), attributeValue);
1371
1372    TScan tScan = new TScan();
1373    tScan.setAttributes(attributes);
1374    Scan scan = scanFromThrift(tScan);
1375    assertArrayEquals(scan.getAttribute("attribute1"), attributeValue);
1376
1377    List<TColumnIncrement> incrementColumns = new ArrayList<>(1);
1378    incrementColumns.add(new TColumnIncrement(wrap(familyAname), wrap(qualifierAname)));
1379    TIncrement tIncrement = new TIncrement(wrap(rowName), incrementColumns);
1380    tIncrement.setAttributes(attributes);
1381    Increment increment = incrementFromThrift(tIncrement);
1382    assertArrayEquals(increment.getAttribute("attribute1"), attributeValue);
1383
1384    TDelete tDelete = new TDelete(wrap(rowName));
1385    tDelete.setAttributes(attributes);
1386    Delete delete = deleteFromThrift(tDelete);
1387    assertArrayEquals(delete.getAttribute("attribute1"), attributeValue);
1388  }
1389
1390  /**
1391   * Put valueA to a row, make sure put has happened, then create a mutation object to put valueB
1392   * and delete ValueA, then check that the row value is only valueB.
1393   */
1394  @Test
1395  public void testMutateRow() throws Exception {
1396    ThriftHBaseServiceHandler handler = createHandler();
1397    byte[] rowName = Bytes.toBytes("testMutateRow");
1398    ByteBuffer table = wrap(tableAname);
1399
1400    List<TColumnValue> columnValuesA = new ArrayList<>(1);
1401    TColumnValue columnValueA = new TColumnValue(wrap(familyAname), wrap(qualifierAname),
1402        wrap(valueAname));
1403    columnValuesA.add(columnValueA);
1404    TPut putA = new TPut(wrap(rowName), columnValuesA);
1405    putA.setColumnValues(columnValuesA);
1406
1407    handler.put(table,putA);
1408
1409    TGet get = new TGet(wrap(rowName));
1410    TResult result = handler.get(table, get);
1411    assertArrayEquals(rowName, result.getRow());
1412    List<TColumnValue> returnedColumnValues = result.getColumnValues();
1413
1414    List<TColumnValue> expectedColumnValues = new ArrayList<>(1);
1415    expectedColumnValues.add(columnValueA);
1416    assertTColumnValuesEqual(expectedColumnValues, returnedColumnValues);
1417
1418    List<TColumnValue> columnValuesB = new ArrayList<>(1);
1419    TColumnValue columnValueB = new TColumnValue(wrap(familyAname), wrap(qualifierBname),
1420        wrap(valueBname));
1421    columnValuesB.add(columnValueB);
1422    TPut putB = new TPut(wrap(rowName), columnValuesB);
1423    putB.setColumnValues(columnValuesB);
1424
1425    TDelete delete = new TDelete(wrap(rowName));
1426    List<TColumn> deleteColumns = new ArrayList<>(1);
1427    TColumn deleteColumn = new TColumn(wrap(familyAname));
1428    deleteColumn.setQualifier(qualifierAname);
1429    deleteColumns.add(deleteColumn);
1430    delete.setColumns(deleteColumns);
1431
1432    List<TMutation> mutations = new ArrayList<>(2);
1433    TMutation mutationA = TMutation.put(putB);
1434    mutations.add(mutationA);
1435
1436    TMutation mutationB = TMutation.deleteSingle(delete);
1437    mutations.add(mutationB);
1438
1439    TRowMutations tRowMutations = new TRowMutations(wrap(rowName),mutations);
1440    handler.mutateRow(table,tRowMutations);
1441
1442    result = handler.get(table, get);
1443    assertArrayEquals(rowName, result.getRow());
1444    returnedColumnValues = result.getColumnValues();
1445
1446    expectedColumnValues = new ArrayList<>(1);
1447    expectedColumnValues.add(columnValueB);
1448    assertTColumnValuesEqual(expectedColumnValues, returnedColumnValues);
1449  }
1450
1451  /**
1452   * Create TPut, TDelete , TIncrement objects, set durability then call ThriftUtility
1453   * functions to get Put , Delete and Increment respectively. Use getDurability to make sure
1454   * the returned objects have the appropriate durability setting.
1455   */
1456  @Test
1457  public void testDurability() throws Exception {
1458    byte[] rowName = Bytes.toBytes("testDurability");
1459    List<TColumnValue> columnValues = new ArrayList<>(1);
1460    columnValues.add(new TColumnValue(wrap(familyAname), wrap(qualifierAname), wrap(valueAname)));
1461
1462    List<TColumnIncrement> incrementColumns = new ArrayList<>(1);
1463    incrementColumns.add(new TColumnIncrement(wrap(familyAname), wrap(qualifierAname)));
1464
1465    TDelete tDelete = new TDelete(wrap(rowName));
1466    tDelete.setDurability(TDurability.SKIP_WAL);
1467    Delete delete = deleteFromThrift(tDelete);
1468    assertEquals(Durability.SKIP_WAL, delete.getDurability());
1469
1470    tDelete.setDurability(TDurability.ASYNC_WAL);
1471    delete = deleteFromThrift(tDelete);
1472    assertEquals(Durability.ASYNC_WAL, delete.getDurability());
1473
1474    tDelete.setDurability(TDurability.SYNC_WAL);
1475    delete = deleteFromThrift(tDelete);
1476    assertEquals(Durability.SYNC_WAL, delete.getDurability());
1477
1478    tDelete.setDurability(TDurability.FSYNC_WAL);
1479    delete = deleteFromThrift(tDelete);
1480    assertEquals(Durability.FSYNC_WAL, delete.getDurability());
1481
1482    TPut tPut = new TPut(wrap(rowName), columnValues);
1483    tPut.setDurability(TDurability.SKIP_WAL);
1484    Put put = putFromThrift(tPut);
1485    assertEquals(Durability.SKIP_WAL, put.getDurability());
1486
1487    tPut.setDurability(TDurability.ASYNC_WAL);
1488    put = putFromThrift(tPut);
1489    assertEquals(Durability.ASYNC_WAL, put.getDurability());
1490
1491    tPut.setDurability(TDurability.SYNC_WAL);
1492    put = putFromThrift(tPut);
1493    assertEquals(Durability.SYNC_WAL, put.getDurability());
1494
1495    tPut.setDurability(TDurability.FSYNC_WAL);
1496    put = putFromThrift(tPut);
1497    assertEquals(Durability.FSYNC_WAL, put.getDurability());
1498
1499    TIncrement tIncrement = new TIncrement(wrap(rowName), incrementColumns);
1500
1501    tIncrement.setDurability(TDurability.SKIP_WAL);
1502    Increment increment = incrementFromThrift(tIncrement);
1503    assertEquals(Durability.SKIP_WAL, increment.getDurability());
1504
1505    tIncrement.setDurability(TDurability.ASYNC_WAL);
1506    increment = incrementFromThrift(tIncrement);
1507    assertEquals(Durability.ASYNC_WAL, increment.getDurability());
1508
1509    tIncrement.setDurability(TDurability.SYNC_WAL);
1510    increment = incrementFromThrift(tIncrement);
1511    assertEquals(Durability.SYNC_WAL, increment.getDurability());
1512
1513    tIncrement.setDurability(TDurability.FSYNC_WAL);
1514    increment = incrementFromThrift(tIncrement);
1515    assertEquals(Durability.FSYNC_WAL, increment.getDurability());
1516  }
1517
1518  @Test
1519  public void testCheckAndMutate() throws Exception {
1520    ThriftHBaseServiceHandler handler = createHandler();
1521    ByteBuffer table = wrap(tableAname);
1522    ByteBuffer row = wrap(Bytes.toBytes("row"));
1523    ByteBuffer family = wrap(familyAname);
1524    ByteBuffer qualifier = wrap(qualifierAname);
1525    ByteBuffer value = wrap(valueAname);
1526
1527    // Create a mutation to write to 'B', our "mutate" of "checkAndMutate"
1528    List<TColumnValue> columnValuesB = new ArrayList<>(1);
1529    TColumnValue columnValueB = new TColumnValue(family, wrap(qualifierBname), wrap(valueBname));
1530    columnValuesB.add(columnValueB);
1531    TPut putB = new TPut(row, columnValuesB);
1532    putB.setColumnValues(columnValuesB);
1533
1534    TRowMutations tRowMutations = new TRowMutations(row,
1535        Arrays.<TMutation> asList(TMutation.put(putB)));
1536
1537    // Empty table when we begin
1538    TResult result = handler.get(table, new TGet(row));
1539    assertEquals(0, result.getColumnValuesSize());
1540
1541    // checkAndMutate -- condition should fail because the value doesn't exist.
1542    assertFalse("Expected condition to not pass",
1543        handler.checkAndMutate(table, row, family, qualifier, TCompareOp.EQUAL, value,
1544            tRowMutations));
1545
1546    List<TColumnValue> columnValuesA = new ArrayList<>(1);
1547    TColumnValue columnValueA = new TColumnValue(family, qualifier, value);
1548    columnValuesA.add(columnValueA);
1549
1550    // Put an update 'A'
1551    handler.put(table, new TPut(row, columnValuesA));
1552
1553    // Verify that the update is there
1554    result = handler.get(table, new TGet(row));
1555    assertEquals(1, result.getColumnValuesSize());
1556    assertTColumnValueEqual(columnValueA, result.getColumnValues().get(0));
1557
1558    // checkAndMutate -- condition should pass since we added the value
1559    assertTrue("Expected condition to pass",
1560        handler.checkAndMutate(table, row, family, qualifier, TCompareOp.EQUAL, value,
1561            tRowMutations));
1562
1563    result = handler.get(table, new TGet(row));
1564    assertEquals(2, result.getColumnValuesSize());
1565    assertTColumnValueEqual(columnValueA, result.getColumnValues().get(0));
1566    assertTColumnValueEqual(columnValueB, result.getColumnValues().get(1));
1567  }
1568
1569  @Test
1570  public void testConsistency() throws Exception {
1571    byte[] rowName = Bytes.toBytes("testConsistency");
1572    TGet tGet = new TGet(wrap(rowName));
1573    tGet.setConsistency(TConsistency.STRONG);
1574    Get get = getFromThrift(tGet);
1575    assertEquals(Consistency.STRONG, get.getConsistency());
1576
1577    tGet.setConsistency(TConsistency.TIMELINE);
1578    tGet.setTargetReplicaId(1);
1579    get = getFromThrift(tGet);
1580    assertEquals(Consistency.TIMELINE, get.getConsistency());
1581    assertEquals(1, get.getReplicaId());
1582
1583    TScan tScan = new TScan();
1584    tScan.setConsistency(TConsistency.STRONG);
1585    Scan scan = scanFromThrift(tScan);
1586    assertEquals(Consistency.STRONG, scan.getConsistency());
1587
1588    tScan.setConsistency(TConsistency.TIMELINE);
1589    tScan.setTargetReplicaId(1);
1590    scan = scanFromThrift(tScan);
1591    assertEquals(Consistency.TIMELINE, scan.getConsistency());
1592    assertEquals(1, scan.getReplicaId());
1593
1594    TResult tResult = new TResult();
1595    assertFalse(tResult.isSetStale());
1596    tResult.setStale(true);
1597    assertTrue(tResult.isSetStale());
1598  }
1599
1600  @Test
1601  public void testDDLOpertions() throws Exception {
1602    String namespace = "testDDLOpertionsNamespace";
1603    String table = "testDDLOpertionsTable";
1604    TTableName tTableName = new TTableName();
1605    tTableName.setNs(Bytes.toBytes(namespace));
1606    tTableName.setQualifier(Bytes.toBytes(table));
1607    ThriftHBaseServiceHandler handler = createHandler();
1608    //create name space
1609    TNamespaceDescriptor namespaceDescriptor = new TNamespaceDescriptor();
1610    namespaceDescriptor.setName(namespace);
1611    namespaceDescriptor.putToConfiguration("key1", "value1");
1612    namespaceDescriptor.putToConfiguration("key2", "value2");
1613    handler.createNamespace(namespaceDescriptor);
1614    //list namespace
1615    List<TNamespaceDescriptor> namespaceDescriptors = handler.listNamespaceDescriptors();
1616    // should have 3 namespace, default hbase and testDDLOpertionsNamespace
1617    assertTrue(namespaceDescriptors.size() == 3);
1618    //modify namesapce
1619    namespaceDescriptor.putToConfiguration("kye3", "value3");
1620    handler.modifyNamespace(namespaceDescriptor);
1621    //get namespace
1622    TNamespaceDescriptor namespaceDescriptorReturned = handler.getNamespaceDescriptor(namespace);
1623    assertTrue(namespaceDescriptorReturned.getConfiguration().size() == 3);
1624    //create table
1625    TTableDescriptor tableDescriptor = new TTableDescriptor();
1626    tableDescriptor.setTableName(tTableName);
1627    TColumnFamilyDescriptor columnFamilyDescriptor1 = new TColumnFamilyDescriptor();
1628    columnFamilyDescriptor1.setName(familyAname);
1629    columnFamilyDescriptor1.setDataBlockEncoding(TDataBlockEncoding.DIFF);
1630    tableDescriptor.addToColumns(columnFamilyDescriptor1);
1631    List<ByteBuffer> splitKeys = new ArrayList<>();
1632    splitKeys.add(ByteBuffer.wrap(Bytes.toBytes(5)));
1633    handler.createTable(tableDescriptor, splitKeys);
1634    //modify table
1635    tableDescriptor.setDurability(TDurability.ASYNC_WAL);
1636    handler.modifyTable(tableDescriptor);
1637    //modify column family
1638    columnFamilyDescriptor1.setInMemory(true);
1639    handler.modifyColumnFamily(tTableName, columnFamilyDescriptor1);
1640    //add column family
1641    TColumnFamilyDescriptor columnFamilyDescriptor2 = new TColumnFamilyDescriptor();
1642    columnFamilyDescriptor2.setName(familyBname);
1643    columnFamilyDescriptor2.setDataBlockEncoding(TDataBlockEncoding.PREFIX);
1644    handler.addColumnFamily(tTableName, columnFamilyDescriptor2);
1645    //get table descriptor
1646    TTableDescriptor tableDescriptorReturned = handler.getTableDescriptor(tTableName);
1647    assertTrue(tableDescriptorReturned.getColumns().size() == 2);
1648    assertTrue(tableDescriptorReturned.getDurability() ==  TDurability.ASYNC_WAL);
1649    TColumnFamilyDescriptor columnFamilyDescriptor1Returned = tableDescriptorReturned.getColumns()
1650        .stream().filter(desc -> Bytes.equals(desc.getName(), familyAname)).findFirst().get();
1651    assertTrue(columnFamilyDescriptor1Returned.isInMemory() == true);
1652    //delete column family
1653    handler.deleteColumnFamily(tTableName, ByteBuffer.wrap(familyBname));
1654    tableDescriptorReturned = handler.getTableDescriptor(tTableName);
1655    assertTrue(tableDescriptorReturned.getColumns().size() == 1);
1656    //disable table
1657    handler.disableTable(tTableName);
1658    assertTrue(handler.isTableDisabled(tTableName));
1659    //enable table
1660    handler.enableTable(tTableName);
1661    assertTrue(handler.isTableEnabled(tTableName));
1662    assertTrue(handler.isTableAvailable(tTableName));
1663    //truncate table
1664    handler.disableTable(tTableName);
1665    handler.truncateTable(tTableName, true);
1666    assertTrue(handler.isTableAvailable(tTableName));
1667    //delete table
1668    handler.disableTable(tTableName);
1669    handler.deleteTable(tTableName);
1670    assertFalse(handler.tableExists(tTableName));
1671    //delete namespace
1672    handler.deleteNamespace(namespace);
1673    namespaceDescriptors = handler.listNamespaceDescriptors();
1674    // should have 2 namespace, default and hbase
1675    assertTrue(namespaceDescriptors.size() == 2);
1676  }
1677
1678  @Test
1679  public void testGetTableDescriptor() throws Exception {
1680    ThriftHBaseServiceHandler handler = createHandler();
1681    TTableDescriptor tableDescriptor = handler
1682        .getTableDescriptor(ThriftUtilities.tableNameFromHBase(TableName.valueOf(tableAname)));
1683    TableDescriptor table = ThriftUtilities.tableDescriptorFromThrift(tableDescriptor);
1684    assertTrue(table.getTableName().equals(TableName.valueOf(tableAname)));
1685    assertTrue(table.getColumnFamilies().length == 2);
1686    assertTrue(table.getColumnFamily(familyAname).getMaxVersions() == 3);
1687    assertTrue(table.getColumnFamily(familyBname).getMaxVersions() == 2);
1688  }
1689
1690  public static class DelayingRegionObserver implements RegionCoprocessor, RegionObserver {
1691    private static final Logger LOG = LoggerFactory.getLogger(DelayingRegionObserver.class);
1692    // sleep time in msec
1693    private long delayMillis;
1694
1695    @Override
1696    public Optional<RegionObserver> getRegionObserver() {
1697      return Optional.of(this);
1698    }
1699
1700    @Override
1701    public void start(CoprocessorEnvironment e) throws IOException {
1702      this.delayMillis = e.getConfiguration()
1703          .getLong("delayingregionobserver.delay", 3000);
1704    }
1705
1706    @Override
1707    public void preGetOp(ObserverContext<RegionCoprocessorEnvironment> e, Get get,
1708                         List<Cell> results) throws IOException {
1709      try {
1710        long start = System.currentTimeMillis();
1711        TimeUnit.MILLISECONDS.sleep(delayMillis);
1712        if (LOG.isTraceEnabled()) {
1713          LOG.trace("Slept for " + (System.currentTimeMillis() - start) + " msec");
1714        }
1715      } catch (InterruptedException ie) {
1716        throw new InterruptedIOException("Interrupted while sleeping");
1717      }
1718    }
1719  }
1720}
1721