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.junit.jupiter.api.Assertions.assertEquals;
022import static org.junit.jupiter.api.Assertions.assertFalse;
023import static org.junit.jupiter.api.Assertions.assertTrue;
024
025import java.io.IOException;
026import java.nio.ByteBuffer;
027import java.util.ArrayList;
028import java.util.Arrays;
029import java.util.List;
030import org.apache.hadoop.conf.Configuration;
031import org.apache.hadoop.hbase.DoNotRetryIOException;
032import org.apache.hadoop.hbase.HBaseTestingUtil;
033import org.apache.hadoop.hbase.TableName;
034import org.apache.hadoop.hbase.client.Admin;
035import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor;
036import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
037import org.apache.hadoop.hbase.client.TableDescriptor;
038import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
039import org.apache.hadoop.hbase.security.UserProvider;
040import org.apache.hadoop.hbase.testclassification.ClientTests;
041import org.apache.hadoop.hbase.testclassification.MediumTests;
042import org.apache.hadoop.hbase.thrift2.generated.TAppend;
043import org.apache.hadoop.hbase.thrift2.generated.TColumnIncrement;
044import org.apache.hadoop.hbase.thrift2.generated.TColumnValue;
045import org.apache.hadoop.hbase.thrift2.generated.TCompareOperator;
046import org.apache.hadoop.hbase.thrift2.generated.TDelete;
047import org.apache.hadoop.hbase.thrift2.generated.TGet;
048import org.apache.hadoop.hbase.thrift2.generated.TIOError;
049import org.apache.hadoop.hbase.thrift2.generated.TIncrement;
050import org.apache.hadoop.hbase.thrift2.generated.TMutation;
051import org.apache.hadoop.hbase.thrift2.generated.TPut;
052import org.apache.hadoop.hbase.thrift2.generated.TRowMutations;
053import org.apache.hadoop.hbase.thrift2.generated.TScan;
054import org.apache.hadoop.hbase.util.Bytes;
055import org.apache.thrift.TException;
056import org.junit.jupiter.api.AfterAll;
057import org.junit.jupiter.api.BeforeAll;
058import org.junit.jupiter.api.BeforeEach;
059import org.junit.jupiter.api.Tag;
060import org.junit.jupiter.api.Test;
061
062@Tag(ClientTests.TAG)
063@Tag(MediumTests.TAG)
064public class TestThriftHBaseServiceHandlerWithReadOnly {
065
066  private static final HBaseTestingUtil UTIL = new HBaseTestingUtil();
067
068  // Static names for tables, columns, rows, and values
069  private static byte[] tableAname = Bytes.toBytes("tableA");
070  private static byte[] familyAname = Bytes.toBytes("familyA");
071  private static byte[] familyBname = Bytes.toBytes("familyB");
072  private static byte[] qualifierAname = Bytes.toBytes("qualifierA");
073  private static byte[] qualifierBname = Bytes.toBytes("qualifierB");
074  private static byte[] valueAname = Bytes.toBytes("valueA");
075  private static byte[] valueBname = Bytes.toBytes("valueB");
076  private static ColumnFamilyDescriptor[] families = new ColumnFamilyDescriptor[] {
077    ColumnFamilyDescriptorBuilder.newBuilder(familyAname).setMaxVersions(3).build(),
078    ColumnFamilyDescriptorBuilder.newBuilder(familyBname).setMaxVersions(2).build() };
079
080  @BeforeAll
081  public static void beforeClass() throws Exception {
082    UTIL.getConfiguration().setBoolean("hbase.thrift.readonly", true);
083    UTIL.getConfiguration().set("hbase.client.retries.number", "3");
084    UTIL.startMiniCluster();
085    Admin admin = UTIL.getAdmin();
086    TableDescriptor tableDescriptor = TableDescriptorBuilder
087      .newBuilder(TableName.valueOf(tableAname)).setColumnFamilies(Arrays.asList(families)).build();
088    admin.createTable(tableDescriptor);
089    admin.close();
090  }
091
092  @AfterAll
093  public static void afterClass() throws Exception {
094    UTIL.shutdownMiniCluster();
095  }
096
097  @BeforeEach
098  public void setup() throws Exception {
099
100  }
101
102  private ThriftHBaseServiceHandler createHandler() throws TException {
103    try {
104      Configuration conf = UTIL.getConfiguration();
105      return new ThriftHBaseServiceHandler(conf, UserProvider.instantiate(conf));
106    } catch (IOException ie) {
107      throw new TException(ie);
108    }
109  }
110
111  @Test
112  public void testExistsWithReadOnly() throws TException {
113
114    ThriftHBaseServiceHandler handler = createHandler();
115    byte[] rowName = Bytes.toBytes("testExists");
116    ByteBuffer table = wrap(tableAname);
117    TGet get = new TGet(wrap(rowName));
118
119    boolean exceptionCaught = false;
120    try {
121      handler.exists(table, get);
122    } catch (TIOError e) {
123      exceptionCaught = true;
124    } finally {
125      assertFalse(exceptionCaught);
126    }
127  }
128
129  @Test
130  public void testExistsAllWithReadOnly() throws TException {
131    ThriftHBaseServiceHandler handler = createHandler();
132    byte[] rowName1 = Bytes.toBytes("testExistsAll1");
133    byte[] rowName2 = Bytes.toBytes("testExistsAll2");
134    ByteBuffer table = wrap(tableAname);
135
136    List<TGet> gets = new ArrayList<>();
137    gets.add(new TGet(wrap(rowName1)));
138    gets.add(new TGet(wrap(rowName2)));
139
140    boolean exceptionCaught = false;
141    try {
142      handler.existsAll(table, gets);
143    } catch (TIOError e) {
144      exceptionCaught = true;
145    } finally {
146      assertFalse(exceptionCaught);
147    }
148  }
149
150  @Test
151  public void testGetWithReadOnly() throws Exception {
152    ThriftHBaseServiceHandler handler = createHandler();
153    byte[] rowName = Bytes.toBytes("testGet");
154    ByteBuffer table = wrap(tableAname);
155
156    TGet get = new TGet(wrap(rowName));
157
158    boolean exceptionCaught = false;
159    try {
160      handler.get(table, get);
161    } catch (TIOError e) {
162      exceptionCaught = true;
163    } finally {
164      assertFalse(exceptionCaught);
165    }
166  }
167
168  @Test
169  public void testGetMultipleWithReadOnly() throws Exception {
170    ThriftHBaseServiceHandler handler = createHandler();
171    ByteBuffer table = wrap(tableAname);
172    byte[] rowName1 = Bytes.toBytes("testGetMultiple1");
173    byte[] rowName2 = Bytes.toBytes("testGetMultiple2");
174
175    List<TGet> gets = new ArrayList<>(2);
176    gets.add(new TGet(wrap(rowName1)));
177    gets.add(new TGet(wrap(rowName2)));
178
179    boolean exceptionCaught = false;
180    try {
181      handler.getMultiple(table, gets);
182    } catch (TIOError e) {
183      exceptionCaught = true;
184    } finally {
185      assertFalse(exceptionCaught);
186    }
187  }
188
189  @Test
190  public void testPutWithReadOnly() throws Exception {
191    ThriftHBaseServiceHandler handler = createHandler();
192    ByteBuffer table = wrap(tableAname);
193    byte[] rowName = Bytes.toBytes("testPut");
194
195    List<TColumnValue> columnValues = new ArrayList<>(2);
196    columnValues.add(new TColumnValue(wrap(familyAname), wrap(qualifierAname), wrap(valueAname)));
197    columnValues.add(new TColumnValue(wrap(familyBname), wrap(qualifierBname), wrap(valueBname)));
198    TPut put = new TPut(wrap(rowName), columnValues);
199
200    boolean exceptionCaught = false;
201    try {
202      handler.put(table, put);
203    } catch (TIOError e) {
204      exceptionCaught = true;
205      assertTrue(e.getCause() instanceof DoNotRetryIOException);
206      assertEquals("Thrift Server is in Read-only mode.", e.getMessage());
207    } finally {
208      assertTrue(exceptionCaught);
209    }
210  }
211
212  @Test
213  public void testCheckAndPutWithReadOnly() throws Exception {
214    ThriftHBaseServiceHandler handler = createHandler();
215    byte[] rowName = Bytes.toBytes("testCheckAndPut");
216    ByteBuffer table = wrap(tableAname);
217
218    List<TColumnValue> columnValuesA = new ArrayList<>(1);
219    TColumnValue columnValueA =
220      new TColumnValue(wrap(familyAname), wrap(qualifierAname), wrap(valueAname));
221    columnValuesA.add(columnValueA);
222    TPut putA = new TPut(wrap(rowName), columnValuesA);
223    putA.setColumnValues(columnValuesA);
224
225    List<TColumnValue> columnValuesB = new ArrayList<>(1);
226    TColumnValue columnValueB =
227      new TColumnValue(wrap(familyBname), wrap(qualifierBname), wrap(valueBname));
228    columnValuesB.add(columnValueB);
229    TPut putB = new TPut(wrap(rowName), columnValuesB);
230    putB.setColumnValues(columnValuesB);
231
232    boolean exceptionCaught = false;
233    try {
234      handler.checkAndPut(table, wrap(rowName), wrap(familyAname), wrap(qualifierAname),
235        wrap(valueAname), putB);
236    } catch (TIOError e) {
237      exceptionCaught = true;
238      assertTrue(e.getCause() instanceof DoNotRetryIOException);
239      assertEquals("Thrift Server is in Read-only mode.", e.getMessage());
240    } finally {
241      assertTrue(exceptionCaught);
242    }
243  }
244
245  @Test
246  public void testPutMultipleWithReadOnly() throws Exception {
247    ThriftHBaseServiceHandler handler = createHandler();
248    ByteBuffer table = wrap(tableAname);
249    byte[] rowName1 = Bytes.toBytes("testPutMultiple1");
250    byte[] rowName2 = Bytes.toBytes("testPutMultiple2");
251
252    List<TColumnValue> columnValues = new ArrayList<>(2);
253    columnValues.add(new TColumnValue(wrap(familyAname), wrap(qualifierAname), wrap(valueAname)));
254    columnValues.add(new TColumnValue(wrap(familyBname), wrap(qualifierBname), wrap(valueBname)));
255    List<TPut> puts = new ArrayList<>(2);
256    puts.add(new TPut(wrap(rowName1), columnValues));
257    puts.add(new TPut(wrap(rowName2), columnValues));
258
259    boolean exceptionCaught = false;
260    try {
261      handler.putMultiple(table, puts);
262    } catch (TIOError e) {
263      exceptionCaught = true;
264      assertTrue(e.getCause() instanceof DoNotRetryIOException);
265      assertEquals("Thrift Server is in Read-only mode.", e.getMessage());
266    } finally {
267      assertTrue(exceptionCaught);
268    }
269  }
270
271  @Test
272  public void testDeleteWithReadOnly() throws Exception {
273    ThriftHBaseServiceHandler handler = createHandler();
274    byte[] rowName = Bytes.toBytes("testDelete");
275    ByteBuffer table = wrap(tableAname);
276
277    TDelete delete = new TDelete(wrap(rowName));
278
279    boolean exceptionCaught = false;
280    try {
281      handler.deleteSingle(table, delete);
282    } catch (TIOError e) {
283      exceptionCaught = true;
284      assertTrue(e.getCause() instanceof DoNotRetryIOException);
285      assertEquals("Thrift Server is in Read-only mode.", e.getMessage());
286    } finally {
287      assertTrue(exceptionCaught);
288    }
289  }
290
291  @Test
292  public void testDeleteMultipleWithReadOnly() throws Exception {
293    ThriftHBaseServiceHandler handler = createHandler();
294    ByteBuffer table = wrap(tableAname);
295    byte[] rowName1 = Bytes.toBytes("testDeleteMultiple1");
296    byte[] rowName2 = Bytes.toBytes("testDeleteMultiple2");
297
298    List<TDelete> deletes = new ArrayList<>(2);
299    deletes.add(new TDelete(wrap(rowName1)));
300    deletes.add(new TDelete(wrap(rowName2)));
301
302    boolean exceptionCaught = false;
303    try {
304      handler.deleteMultiple(table, deletes);
305    } catch (TIOError e) {
306      exceptionCaught = true;
307      assertTrue(e.getCause() instanceof DoNotRetryIOException);
308      assertEquals("Thrift Server is in Read-only mode.", e.getMessage());
309    } finally {
310      assertTrue(exceptionCaught);
311    }
312  }
313
314  @Test
315  public void testCheckAndMutateWithReadOnly() throws Exception {
316    ThriftHBaseServiceHandler handler = createHandler();
317    ByteBuffer table = wrap(tableAname);
318    ByteBuffer row = wrap(Bytes.toBytes("row"));
319    ByteBuffer family = wrap(familyAname);
320    ByteBuffer qualifier = wrap(qualifierAname);
321    ByteBuffer value = wrap(valueAname);
322
323    List<TColumnValue> columnValuesB = new ArrayList<>(1);
324    TColumnValue columnValueB = new TColumnValue(family, wrap(qualifierBname), wrap(valueBname));
325    columnValuesB.add(columnValueB);
326    TPut putB = new TPut(row, columnValuesB);
327    putB.setColumnValues(columnValuesB);
328
329    TRowMutations tRowMutations =
330      new TRowMutations(row, Arrays.<TMutation> asList(TMutation.put(putB)));
331
332    boolean exceptionCaught = false;
333    try {
334      handler.checkAndMutate(table, row, family, qualifier, TCompareOperator.EQUAL, value,
335        tRowMutations);
336    } catch (TIOError e) {
337      exceptionCaught = true;
338      assertTrue(e.getCause() instanceof DoNotRetryIOException);
339      assertEquals("Thrift Server is in Read-only mode.", e.getMessage());
340    } finally {
341      assertTrue(exceptionCaught);
342    }
343  }
344
345  @Test
346  public void testCheckAndDeleteWithReadOnly() throws Exception {
347    ThriftHBaseServiceHandler handler = createHandler();
348    byte[] rowName = Bytes.toBytes("testCheckAndDelete");
349    ByteBuffer table = wrap(tableAname);
350
351    TDelete delete = new TDelete(wrap(rowName));
352
353    boolean exceptionCaught = false;
354    try {
355      handler.checkAndDelete(table, wrap(rowName), wrap(familyAname), wrap(qualifierAname),
356        wrap(valueAname), delete);
357    } catch (TIOError e) {
358      exceptionCaught = true;
359      assertTrue(e.getCause() instanceof DoNotRetryIOException);
360      assertEquals("Thrift Server is in Read-only mode.", e.getMessage());
361    } finally {
362      assertTrue(exceptionCaught);
363    }
364  }
365
366  @Test
367  public void testIncrementWithReadOnly() throws Exception {
368    ThriftHBaseServiceHandler handler = createHandler();
369    byte[] rowName = Bytes.toBytes("testIncrement");
370    ByteBuffer table = wrap(tableAname);
371
372    List<TColumnIncrement> incrementColumns = new ArrayList<>(1);
373    incrementColumns.add(new TColumnIncrement(wrap(familyAname), wrap(qualifierAname)));
374    TIncrement increment = new TIncrement(wrap(rowName), incrementColumns);
375
376    boolean exceptionCaught = false;
377    try {
378      handler.increment(table, increment);
379    } catch (TIOError e) {
380      exceptionCaught = true;
381      assertTrue(e.getCause() instanceof DoNotRetryIOException);
382      assertEquals("Thrift Server is in Read-only mode.", e.getMessage());
383    } finally {
384      assertTrue(exceptionCaught);
385    }
386  }
387
388  @Test
389  public void testAppendWithReadOnly() throws Exception {
390    ThriftHBaseServiceHandler handler = createHandler();
391    byte[] rowName = Bytes.toBytes("testAppend");
392    ByteBuffer table = wrap(tableAname);
393    byte[] v1 = Bytes.toBytes("42");
394
395    List<TColumnValue> appendColumns = new ArrayList<>(1);
396    appendColumns.add(new TColumnValue(wrap(familyAname), wrap(qualifierAname), wrap(v1)));
397    TAppend append = new TAppend(wrap(rowName), appendColumns);
398
399    boolean exceptionCaught = false;
400    try {
401      handler.append(table, append);
402    } catch (TIOError e) {
403      exceptionCaught = true;
404      assertTrue(e.getCause() instanceof DoNotRetryIOException);
405      assertEquals("Thrift Server is in Read-only mode.", e.getMessage());
406    } finally {
407      assertTrue(exceptionCaught);
408    }
409  }
410
411  @Test
412  public void testMutateRowWithReadOnly() throws Exception {
413    ThriftHBaseServiceHandler handler = createHandler();
414    byte[] rowName = Bytes.toBytes("testMutateRow");
415    ByteBuffer table = wrap(tableAname);
416
417    List<TColumnValue> columnValuesA = new ArrayList<>(1);
418    TColumnValue columnValueA =
419      new TColumnValue(wrap(familyAname), wrap(qualifierAname), wrap(valueAname));
420    columnValuesA.add(columnValueA);
421    TPut putA = new TPut(wrap(rowName), columnValuesA);
422    putA.setColumnValues(columnValuesA);
423
424    TDelete delete = new TDelete(wrap(rowName));
425
426    List<TMutation> mutations = new ArrayList<>(2);
427    TMutation mutationA = TMutation.put(putA);
428    mutations.add(mutationA);
429    TMutation mutationB = TMutation.deleteSingle(delete);
430    mutations.add(mutationB);
431    TRowMutations tRowMutations = new TRowMutations(wrap(rowName), mutations);
432
433    boolean exceptionCaught = false;
434    try {
435      handler.mutateRow(table, tRowMutations);
436    } catch (TIOError e) {
437      exceptionCaught = true;
438      assertTrue(e.getCause() instanceof DoNotRetryIOException);
439      assertEquals("Thrift Server is in Read-only mode.", e.getMessage());
440    } finally {
441      assertTrue(exceptionCaught);
442    }
443  }
444
445  @Test
446  public void testScanWithReadOnly() throws Exception {
447    ThriftHBaseServiceHandler handler = createHandler();
448    ByteBuffer table = wrap(tableAname);
449
450    TScan scan = new TScan();
451    boolean exceptionCaught = false;
452    try {
453      int scanId = handler.openScanner(table, scan);
454      handler.getScannerRows(scanId, 10);
455      handler.closeScanner(scanId);
456    } catch (TIOError e) {
457      exceptionCaught = true;
458    } finally {
459      assertFalse(exceptionCaught);
460    }
461  }
462}