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