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