1   /**
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  
20  package org.apache.hadoop.hbase.coprocessor;
21  
22  import java.io.IOException;
23  import java.util.ArrayList;
24  import java.util.Arrays;
25  
26  import org.apache.hadoop.conf.Configuration;
27  import org.apache.hadoop.hbase.Coprocessor;
28  import org.apache.hadoop.hbase.CoprocessorEnvironment;
29  import org.apache.hadoop.hbase.HBaseTestingUtility;
30  import org.apache.hadoop.hbase.MediumTests;
31  import org.apache.hadoop.hbase.client.Append;
32  import org.apache.hadoop.hbase.client.Delete;
33  import org.apache.hadoop.hbase.client.Get;
34  import org.apache.hadoop.hbase.client.HTable;
35  import org.apache.hadoop.hbase.client.HTableInterface;
36  import org.apache.hadoop.hbase.client.Increment;
37  import org.apache.hadoop.hbase.client.Put;
38  import org.apache.hadoop.hbase.client.Result;
39  import org.apache.hadoop.hbase.client.ResultScanner;
40  import org.apache.hadoop.hbase.client.Row;
41  import org.apache.hadoop.hbase.client.RowMutations;
42  import org.apache.hadoop.hbase.client.Scan;
43  import org.apache.hadoop.hbase.master.MasterCoprocessorHost;
44  import org.apache.hadoop.hbase.util.Bytes;
45  import org.apache.hadoop.hbase.util.VersionInfo;
46  import org.junit.After;
47  import org.junit.AfterClass;
48  import org.junit.Before;
49  import org.junit.BeforeClass;
50  import org.junit.Test;
51  import org.junit.experimental.categories.Category;
52  
53  import static org.junit.Assert.*;
54  
55  /**
56   * Tests class {@link org.apache.hadoop.hbase.coprocessor.CoprocessorHost.Environment.HTableWrapper}
57   * by invoking its methods and briefly asserting the result is reasonable.
58   */
59  @Category(MediumTests.class)
60  public class TestHTableWrapper {
61  
62    private static final HBaseTestingUtility util = new HBaseTestingUtility();
63  
64    private static final byte[] TEST_TABLE = Bytes.toBytes("test");
65    private static final byte[] TEST_FAMILY = Bytes.toBytes("f1");
66  
67    private static final byte[] ROW_A = Bytes.toBytes("aaa");
68    private static final byte[] ROW_B = Bytes.toBytes("bbb");
69    private static final byte[] ROW_C = Bytes.toBytes("ccc");
70    private static final byte[] ROW_D = Bytes.toBytes("ddd");
71    private static final byte[] ROW_E = Bytes.toBytes("eee");
72  
73    private static final byte[] qualifierCol1 = Bytes.toBytes("col1");
74  
75    private static final byte[] bytes1 = Bytes.toBytes(1);
76    private static final byte[] bytes2 = Bytes.toBytes(2);
77    private static final byte[] bytes3 = Bytes.toBytes(3);
78    private static final byte[] bytes4 = Bytes.toBytes(4);
79    private static final byte[] bytes5 = Bytes.toBytes(5);
80  
81    static class DummyRegionObserver extends BaseRegionObserver {
82    }
83  
84    private HTableInterface hTableInterface;
85    private HTable table;
86  
87    @BeforeClass
88    public static void setupBeforeClass() throws Exception {
89      util.startMiniCluster();
90    }
91  
92    @AfterClass
93    public static void tearDownAfterClass() throws Exception {
94      util.shutdownMiniCluster();
95    }
96  
97    @Before
98    public void before() throws Exception {
99      table = util.createTable(TEST_TABLE, TEST_FAMILY);
100 
101     Put puta = new Put(ROW_A);
102     puta.add(TEST_FAMILY, qualifierCol1, bytes1);
103     table.put(puta);
104 
105     Put putb = new Put(ROW_B);
106     putb.add(TEST_FAMILY, qualifierCol1, bytes2);
107     table.put(putb);
108 
109     Put putc = new Put(ROW_C);
110     putc.add(TEST_FAMILY, qualifierCol1, bytes3);
111     table.put(putc);
112   }
113 
114   @After
115   public void after() throws Exception {
116     try {
117       if (table != null) {
118         table.close();
119       }
120     } finally {
121       util.deleteTable(TEST_TABLE);
122     }
123   }
124 
125   @Test
126   public void testHTableInterfaceMethods() throws Exception {
127     Configuration conf = util.getConfiguration();
128     MasterCoprocessorHost cpHost = util.getMiniHBaseCluster().getMaster().getCoprocessorHost();
129     Class<?> implClazz = DummyRegionObserver.class;
130     cpHost.load(implClazz, Coprocessor.PRIORITY_HIGHEST, conf);
131     CoprocessorEnvironment env = cpHost.findCoprocessorEnvironment(implClazz.getName());
132     assertEquals(Coprocessor.VERSION, env.getVersion());
133     assertEquals(VersionInfo.getVersion(), env.getHBaseVersion());
134     hTableInterface = env.getTable(TEST_TABLE);
135     checkHTableInterfaceMethods();
136     cpHost.shutdown(env);
137   }
138 
139   private void checkHTableInterfaceMethods() throws Exception {
140     checkConf();
141     checkNameAndDescriptor();
142     checkAutoFlush();
143     checkBufferSize();
144     checkExists();
145     checkGetRowOrBefore();
146     checkAppend();
147     checkPutsAndDeletes();
148     checkCheckAndPut();
149     checkCheckAndDelete();
150     checkIncrementColumnValue();
151     checkIncrement();
152     checkBatch();
153     checkMutateRow();
154     checkResultScanner();
155 
156     hTableInterface.flushCommits();
157     hTableInterface.close();
158   }
159 
160   private void checkConf() {
161     Configuration confExpected = util.getConfiguration();
162     Configuration confActual = hTableInterface.getConfiguration();
163     assertTrue(confExpected == confActual);
164   }
165 
166   private void checkNameAndDescriptor() throws IOException {
167     assertArrayEquals(TEST_TABLE, hTableInterface.getTableName());
168     assertEquals(table.getTableDescriptor(), hTableInterface.getTableDescriptor());
169   }
170 
171   private void checkAutoFlush() {
172     boolean initialAutoFlush = hTableInterface.isAutoFlush();
173     hTableInterface.setAutoFlush(false);
174     assertFalse(hTableInterface.isAutoFlush());
175     hTableInterface.setAutoFlush(true, true);
176     assertTrue(hTableInterface.isAutoFlush());
177     hTableInterface.setAutoFlush(initialAutoFlush);
178   }
179 
180   private void checkBufferSize() throws IOException {
181     long initialWriteBufferSize = hTableInterface.getWriteBufferSize();
182     hTableInterface.setWriteBufferSize(12345L);
183     assertEquals(12345L, hTableInterface.getWriteBufferSize());
184     hTableInterface.setWriteBufferSize(initialWriteBufferSize);
185   }
186 
187   private void checkExists() throws IOException {
188     boolean ex = hTableInterface.exists(new Get(ROW_A).addColumn(TEST_FAMILY, qualifierCol1));
189     assertTrue(ex);
190   }
191 
192   @SuppressWarnings("deprecation")
193   private void checkGetRowOrBefore() throws IOException {
194     Result rowOrBeforeResult = hTableInterface.getRowOrBefore(ROW_A, TEST_FAMILY);
195     assertArrayEquals(ROW_A, rowOrBeforeResult.getRow());
196   }
197 
198   private void checkAppend() throws IOException {
199     final byte[] appendValue = Bytes.toBytes("append");
200     Append append = new Append(qualifierCol1).add(TEST_FAMILY, qualifierCol1, appendValue);
201     Result appendResult = hTableInterface.append(append);
202     byte[] appendedRow = appendResult.getRow();
203     checkRowValue(appendedRow, appendValue);
204   }
205 
206   private void checkPutsAndDeletes() throws IOException {
207     // put:
208     Put putD = new Put(ROW_D).add(TEST_FAMILY, qualifierCol1, bytes2);
209     hTableInterface.put(putD);
210     checkRowValue(ROW_D, bytes2);
211 
212     // delete:
213     Delete delete = new Delete(ROW_D);
214     hTableInterface.delete(delete);
215     checkRowValue(ROW_D, null);
216 
217     // multiple puts:
218     Put[] puts = new Put[] { new Put(ROW_D).add(TEST_FAMILY, qualifierCol1, bytes2),
219         new Put(ROW_E).add(TEST_FAMILY, qualifierCol1, bytes3) };
220     hTableInterface.put(Arrays.asList(puts));
221     checkRowsValues(new byte[][] { ROW_D, ROW_E }, new byte[][] { bytes2, bytes3 });
222 
223     // multiple deletes:
224     Delete[] deletes = new Delete[] { new Delete(ROW_D), new Delete(ROW_E) };
225     hTableInterface.delete(new ArrayList<Delete>(Arrays.asList(deletes)));
226     checkRowsValues(new byte[][] { ROW_D, ROW_E }, new byte[][] { null, null });
227   }
228 
229   private void checkCheckAndPut() throws IOException {
230     Put putC = new Put(ROW_C).add(TEST_FAMILY, qualifierCol1, bytes5);
231     assertFalse(hTableInterface.checkAndPut(ROW_C, TEST_FAMILY, qualifierCol1, /* expect */
232         bytes4, putC/* newValue */));
233     assertTrue(hTableInterface.checkAndPut(ROW_C, TEST_FAMILY, qualifierCol1, /* expect */
234         bytes3, putC/* newValue */));
235     checkRowValue(ROW_C, bytes5);
236   }
237 
238   private void checkCheckAndDelete() throws IOException {
239     Delete delete = new Delete(ROW_C);
240     assertFalse(hTableInterface.checkAndDelete(ROW_C, TEST_FAMILY, qualifierCol1, bytes4, delete));
241     assertTrue(hTableInterface.checkAndDelete(ROW_C, TEST_FAMILY, qualifierCol1, bytes5, delete));
242     checkRowValue(ROW_C, null);
243   }
244 
245   private void checkIncrementColumnValue() throws IOException {
246     hTableInterface.put(new Put(ROW_A).add(TEST_FAMILY, qualifierCol1, Bytes.toBytes(1L)));
247     checkRowValue(ROW_A, Bytes.toBytes(1L));
248 
249     final long newVal = hTableInterface
250         .incrementColumnValue(ROW_A, TEST_FAMILY, qualifierCol1, 10L);
251     assertEquals(11L, newVal);
252     checkRowValue(ROW_A, Bytes.toBytes(11L));
253   }
254 
255   private void checkIncrement() throws IOException {
256     hTableInterface.increment(new Increment(ROW_A).addColumn(TEST_FAMILY, qualifierCol1, -15L));
257     checkRowValue(ROW_A, Bytes.toBytes(-4L));
258   }
259 
260   private void checkBatch() throws IOException, InterruptedException {
261     Object[] results1 = hTableInterface.batch(Arrays.asList(new Row[] {
262         new Increment(ROW_A).addColumn(TEST_FAMILY, qualifierCol1, 2L),
263         new Increment(ROW_A).addColumn(TEST_FAMILY, qualifierCol1, 2L) }));
264     assertEquals(2, results1.length);
265     for (Object r2 : results1) {
266       assertTrue(r2 instanceof Result);
267     }
268     checkRowValue(ROW_A, Bytes.toBytes(0L));
269     Object[] results2 = new Result[2];
270     hTableInterface.batch(
271         Arrays.asList(new Row[] { new Increment(ROW_A).addColumn(TEST_FAMILY, qualifierCol1, 2L),
272             new Increment(ROW_A).addColumn(TEST_FAMILY, qualifierCol1, 2L) }), results2);
273     for (Object r2 : results2) {
274       assertTrue(r2 instanceof Result);
275     }
276     checkRowValue(ROW_A, Bytes.toBytes(4L));
277   }
278 
279   private void checkMutateRow() throws IOException {
280     Put put = new Put(ROW_A).add(TEST_FAMILY, qualifierCol1, bytes1);
281     RowMutations rowMutations = new RowMutations(ROW_A);
282     rowMutations.add(put);
283     hTableInterface.mutateRow(rowMutations);
284     checkRowValue(ROW_A, bytes1);
285   }
286 
287   private void checkResultScanner() throws IOException {
288     ResultScanner resultScanner = hTableInterface.getScanner(TEST_FAMILY);
289     Result[] results = resultScanner.next(10);
290     assertEquals(3, results.length);
291 
292     resultScanner = hTableInterface.getScanner(TEST_FAMILY, qualifierCol1);
293     results = resultScanner.next(10);
294     assertEquals(3, results.length);
295 
296     resultScanner = hTableInterface.getScanner(new Scan(ROW_A, ROW_C));
297     results = resultScanner.next(10);
298     assertEquals(2, results.length);
299   }
300 
301   private void checkRowValue(byte[] row, byte[] expectedValue) throws IOException {
302     Get get = new Get(row).addColumn(TEST_FAMILY, qualifierCol1);
303     Result result = hTableInterface.get(get);
304     byte[] actualValue = result.getValue(TEST_FAMILY, qualifierCol1);
305     assertArrayEquals(expectedValue, actualValue);
306   }
307 
308   private void checkRowsValues(byte[][] rows, byte[][] expectedValues) throws IOException {
309     if (rows.length != expectedValues.length) {
310       throw new IllegalArgumentException();
311     }
312     Get[] gets = new Get[rows.length];
313     for (int i = 0; i < gets.length; i++) {
314       gets[i] = new Get(rows[i]).addColumn(TEST_FAMILY, qualifierCol1);
315     }
316     Result[] results = hTableInterface.get(Arrays.asList(gets));
317     for (int i = 0; i < expectedValues.length; i++) {
318       byte[] actualValue = results[i].getValue(TEST_FAMILY, qualifierCol1);
319       assertArrayEquals(expectedValues[i], actualValue);
320     }
321   }
322 
323 }