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