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