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.HBaseTestingUtility;
034import org.apache.hadoop.hbase.HColumnDescriptor;
035import org.apache.hadoop.hbase.HTableDescriptor;
036import org.apache.hadoop.hbase.TableName;
037import org.apache.hadoop.hbase.client.Admin;
038import org.apache.hadoop.hbase.security.UserProvider;
039import org.apache.hadoop.hbase.testclassification.ClientTests;
040import org.apache.hadoop.hbase.testclassification.MediumTests;
041import org.apache.hadoop.hbase.thrift2.generated.TAppend;
042import org.apache.hadoop.hbase.thrift2.generated.TColumnIncrement;
043import org.apache.hadoop.hbase.thrift2.generated.TColumnValue;
044import org.apache.hadoop.hbase.thrift2.generated.TCompareOp;
045import org.apache.hadoop.hbase.thrift2.generated.TDelete;
046import org.apache.hadoop.hbase.thrift2.generated.TGet;
047import org.apache.hadoop.hbase.thrift2.generated.TIOError;
048import org.apache.hadoop.hbase.thrift2.generated.TIncrement;
049import org.apache.hadoop.hbase.thrift2.generated.TMutation;
050import org.apache.hadoop.hbase.thrift2.generated.TPut;
051import org.apache.hadoop.hbase.thrift2.generated.TRowMutations;
052import org.apache.hadoop.hbase.thrift2.generated.TScan;
053import org.apache.hadoop.hbase.util.Bytes;
054import org.apache.thrift.TException;
055import org.junit.AfterClass;
056import org.junit.Before;
057import org.junit.BeforeClass;
058import org.junit.ClassRule;
059import org.junit.Test;
060import org.junit.experimental.categories.Category;
061
062@Category({ ClientTests.class, MediumTests.class })
063public class TestThriftHBaseServiceHandlerWithReadOnly {
064
065  @ClassRule
066  public static final HBaseClassTestRule CLASS_RULE =
067    HBaseClassTestRule.forClass(TestThriftHBaseServiceHandlerWithReadOnly.class);
068
069  private static final HBaseTestingUtility UTIL = new HBaseTestingUtility();
070
071  // Static names for tables, columns, rows, and values
072  private static byte[] tableAname = Bytes.toBytes("tableA");
073  private static byte[] familyAname = Bytes.toBytes("familyA");
074  private static byte[] familyBname = Bytes.toBytes("familyB");
075  private static byte[] qualifierAname = Bytes.toBytes("qualifierA");
076  private static byte[] qualifierBname = Bytes.toBytes("qualifierB");
077  private static byte[] valueAname = Bytes.toBytes("valueA");
078  private static byte[] valueBname = Bytes.toBytes("valueB");
079  private static HColumnDescriptor[] families =
080    new HColumnDescriptor[] { new HColumnDescriptor(familyAname).setMaxVersions(3),
081      new HColumnDescriptor(familyBname).setMaxVersions(2) };
082
083  @BeforeClass
084  public static void beforeClass() throws Exception {
085    UTIL.getConfiguration().setBoolean("hbase.thrift.readonly", true);
086    UTIL.getConfiguration().set("hbase.client.retries.number", "3");
087    UTIL.startMiniCluster();
088    Admin admin = UTIL.getAdmin();
089    HTableDescriptor tableDescriptor = new HTableDescriptor(TableName.valueOf(tableAname));
090    for (HColumnDescriptor family : families) {
091      tableDescriptor.addFamily(family);
092    }
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, TCompareOp.EQUAL, value, tRowMutations);
340    } catch (TIOError e) {
341      exceptionCaught = true;
342      assertTrue(e.getCause() instanceof DoNotRetryIOException);
343      assertEquals("Thrift Server is in Read-only mode.", e.getMessage());
344    } finally {
345      assertTrue(exceptionCaught);
346    }
347  }
348
349  @Test
350  public void testCheckAndDeleteWithReadOnly() throws Exception {
351    ThriftHBaseServiceHandler handler = createHandler();
352    byte[] rowName = Bytes.toBytes("testCheckAndDelete");
353    ByteBuffer table = wrap(tableAname);
354
355    TDelete delete = new TDelete(wrap(rowName));
356
357    boolean exceptionCaught = false;
358    try {
359      handler.checkAndDelete(table, wrap(rowName), wrap(familyAname), wrap(qualifierAname),
360        wrap(valueAname), delete);
361    } catch (TIOError e) {
362      exceptionCaught = true;
363      assertTrue(e.getCause() instanceof DoNotRetryIOException);
364      assertEquals("Thrift Server is in Read-only mode.", e.getMessage());
365    } finally {
366      assertTrue(exceptionCaught);
367    }
368  }
369
370  @Test
371  public void testIncrementWithReadOnly() throws Exception {
372    ThriftHBaseServiceHandler handler = createHandler();
373    byte[] rowName = Bytes.toBytes("testIncrement");
374    ByteBuffer table = wrap(tableAname);
375
376    List<TColumnIncrement> incrementColumns = new ArrayList<>(1);
377    incrementColumns.add(new TColumnIncrement(wrap(familyAname), wrap(qualifierAname)));
378    TIncrement increment = new TIncrement(wrap(rowName), incrementColumns);
379
380    boolean exceptionCaught = false;
381    try {
382      handler.increment(table, increment);
383    } catch (TIOError e) {
384      exceptionCaught = true;
385      assertTrue(e.getCause() instanceof DoNotRetryIOException);
386      assertEquals("Thrift Server is in Read-only mode.", e.getMessage());
387    } finally {
388      assertTrue(exceptionCaught);
389    }
390  }
391
392  @Test
393  public void testAppendWithReadOnly() throws Exception {
394    ThriftHBaseServiceHandler handler = createHandler();
395    byte[] rowName = Bytes.toBytes("testAppend");
396    ByteBuffer table = wrap(tableAname);
397    byte[] v1 = Bytes.toBytes("42");
398
399    List<TColumnValue> appendColumns = new ArrayList<>(1);
400    appendColumns.add(new TColumnValue(wrap(familyAname), wrap(qualifierAname), wrap(v1)));
401    TAppend append = new TAppend(wrap(rowName), appendColumns);
402
403    boolean exceptionCaught = false;
404    try {
405      handler.append(table, append);
406    } catch (TIOError e) {
407      exceptionCaught = true;
408      assertTrue(e.getCause() instanceof DoNotRetryIOException);
409      assertEquals("Thrift Server is in Read-only mode.", e.getMessage());
410    } finally {
411      assertTrue(exceptionCaught);
412    }
413  }
414
415  @Test
416  public void testMutateRowWithReadOnly() throws Exception {
417    ThriftHBaseServiceHandler handler = createHandler();
418    byte[] rowName = Bytes.toBytes("testMutateRow");
419    ByteBuffer table = wrap(tableAname);
420
421    List<TColumnValue> columnValuesA = new ArrayList<>(1);
422    TColumnValue columnValueA =
423      new TColumnValue(wrap(familyAname), wrap(qualifierAname), wrap(valueAname));
424    columnValuesA.add(columnValueA);
425    TPut putA = new TPut(wrap(rowName), columnValuesA);
426    putA.setColumnValues(columnValuesA);
427
428    TDelete delete = new TDelete(wrap(rowName));
429
430    List<TMutation> mutations = new ArrayList<>(2);
431    TMutation mutationA = TMutation.put(putA);
432    mutations.add(mutationA);
433    TMutation mutationB = TMutation.deleteSingle(delete);
434    mutations.add(mutationB);
435    TRowMutations tRowMutations = new TRowMutations(wrap(rowName), mutations);
436
437    boolean exceptionCaught = false;
438    try {
439      handler.mutateRow(table, tRowMutations);
440    } catch (TIOError e) {
441      exceptionCaught = true;
442      assertTrue(e.getCause() instanceof DoNotRetryIOException);
443      assertEquals("Thrift Server is in Read-only mode.", e.getMessage());
444    } finally {
445      assertTrue(exceptionCaught);
446    }
447  }
448
449  @Test
450  public void testScanWithReadOnly() throws Exception {
451    ThriftHBaseServiceHandler handler = createHandler();
452    ByteBuffer table = wrap(tableAname);
453
454    TScan scan = new TScan();
455    boolean exceptionCaught = false;
456    try {
457      int scanId = handler.openScanner(table, scan);
458      handler.getScannerRows(scanId, 10);
459      handler.closeScanner(scanId);
460    } catch (TIOError e) {
461      exceptionCaught = true;
462    } finally {
463      assertFalse(exceptionCaught);
464    }
465  }
466}