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