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