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