1   /*
2    * Copyright 2010 The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  package org.apache.hadoop.hbase.coprocessor;
21  
22  import static org.junit.Assert.assertArrayEquals;
23  import static org.junit.Assert.assertEquals;
24  
25  import java.io.IOException;
26  import java.util.Map;
27  
28  import org.apache.hadoop.conf.Configuration;
29  import org.apache.hadoop.hbase.HBaseConfiguration;
30  import org.apache.hadoop.hbase.HBaseTestingUtility;
31  import org.apache.hadoop.hbase.HConstants;
32  import org.apache.hadoop.hbase.MediumTests;
33  import org.apache.hadoop.hbase.MiniHBaseCluster;
34  import org.apache.hadoop.hbase.client.HBaseAdmin;
35  import org.apache.hadoop.hbase.client.HTable;
36  import org.apache.hadoop.hbase.client.Put;
37  import org.apache.hadoop.hbase.client.Scan;
38  import org.apache.hadoop.hbase.client.coprocessor.Batch;
39  import org.apache.hadoop.hbase.client.coprocessor.Exec;
40  import org.apache.hadoop.hbase.io.HbaseObjectWritable;
41  import org.apache.hadoop.hbase.util.Bytes;
42  import org.apache.hadoop.io.DataInputBuffer;
43  import org.apache.hadoop.io.DataOutputBuffer;
44  import org.apache.hadoop.io.Text;
45  import org.junit.AfterClass;
46  import org.junit.BeforeClass;
47  import org.junit.Ignore;
48  import org.junit.Test;
49  import org.junit.experimental.categories.Category;
50  
51  /**
52   * TestEndpoint: test cases to verify coprocessor Endpoint
53   */
54  @Category(MediumTests.class)
55  public class TestCoprocessorEndpoint {
56  
57    private static final byte[] TEST_TABLE = Bytes.toBytes("TestTable");
58    private static final byte[] TEST_FAMILY = Bytes.toBytes("TestFamily");
59    private static final byte[] TEST_QUALIFIER = Bytes.toBytes("TestQualifier");
60    private static byte[] ROW = Bytes.toBytes("testRow");
61    
62    private static final String protocolName =  "org.apache.hadoop.hbase.CustomProtocol";
63    private static final String methodName = "myFunc";
64  
65    private static final int ROWSIZE = 20;
66    private static final int rowSeperator1 = 5;
67    private static final int rowSeperator2 = 12;
68    private static byte[][] ROWS = makeN(ROW, ROWSIZE);
69  
70    private static HBaseTestingUtility util = new HBaseTestingUtility();
71    private static MiniHBaseCluster cluster = null;
72  
73    @BeforeClass
74    public static void setupBeforeClass() throws Exception {
75      // set configure to indicate which cp should be loaded
76      Configuration conf = util.getConfiguration();
77      conf.setStrings(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,
78          "org.apache.hadoop.hbase.coprocessor.ColumnAggregationEndpoint",
79          "org.apache.hadoop.hbase.coprocessor.GenericEndpoint");
80      conf.setStrings(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY,
81          "org.apache.hadoop.hbase.coprocessor.GenericEndpoint");
82  
83      util.startMiniCluster(2);
84      cluster = util.getMiniHBaseCluster();
85  
86      HTable table = util.createTable(TEST_TABLE, TEST_FAMILY);
87      util.createMultiRegions(util.getConfiguration(), table, TEST_FAMILY,
88                              new byte[][] { HConstants.EMPTY_BYTE_ARRAY,
89                                  ROWS[rowSeperator1], ROWS[rowSeperator2] });
90  
91      for (int i = 0; i < ROWSIZE; i++) {
92        Put put = new Put(ROWS[i]);
93        put.setWriteToWAL(false);
94        put.add(TEST_FAMILY, TEST_QUALIFIER, Bytes.toBytes(i));
95        table.put(put);
96      }
97  
98      // sleep here is an ugly hack to allow region transitions to finish
99      long timeout = System.currentTimeMillis() + (15 * 1000);
100     while ((System.currentTimeMillis() < timeout) &&
101       (table.getRegionsInfo().size() != 2)) {
102       Thread.sleep(250);
103     }
104     table.close();
105   }
106 
107   @AfterClass
108   public static void tearDownAfterClass() throws Exception {
109     util.shutdownMiniCluster();
110   }
111 
112   @Test
113   public void testGeneric() throws Throwable {
114     HTable table = new HTable(util.getConfiguration(), TEST_TABLE);
115     GenericProtocol protocol = table.coprocessorProxy(GenericProtocol.class,
116                                                       Bytes.toBytes("testRow"));
117     String workResult1 = protocol.doWork("foo");
118     assertEquals("foo", workResult1);
119     byte[] workResult2 = protocol.doWork(new byte[]{1});
120     assertArrayEquals(new byte[]{1}, workResult2);
121     byte workResult3 = protocol.doWork((byte)1);
122     assertEquals((byte)1, workResult3);
123     char workResult4 = protocol.doWork('c');
124     assertEquals('c', workResult4);
125     boolean workResult5 = protocol.doWork(true);
126     assertEquals(true, workResult5);
127     short workResult6 = protocol.doWork((short)1);
128     assertEquals((short)1, workResult6);
129     int workResult7 = protocol.doWork(5);
130     assertEquals(5, workResult7);
131     long workResult8 = protocol.doWork(5l);
132     assertEquals(5l, workResult8);
133     double workResult9 = protocol.doWork(6d);
134     assertEquals(6d, workResult9, 0.01);
135     float workResult10 = protocol.doWork(6f);
136     assertEquals(6f, workResult10, 0.01);
137     Text workResult11 = protocol.doWork(new Text("foo"));
138     assertEquals(new Text("foo"), workResult11);
139     table.close();
140   }
141 
142   @Test
143   public void testMasterGeneric() throws Throwable {
144     HBaseAdmin admin = new HBaseAdmin(util.getConfiguration());
145     GenericProtocol protocol = admin.coprocessorProxy(GenericProtocol.class);
146     String workResult1 = protocol.doWork("foo");
147     assertEquals("foo", workResult1);
148     byte[] workResult2 = protocol.doWork(new byte[]{1});
149     assertArrayEquals(new byte[]{1}, workResult2);
150     byte workResult3 = protocol.doWork((byte)1);
151     assertEquals((byte)1, workResult3);
152     char workResult4 = protocol.doWork('c');
153     assertEquals('c', workResult4);
154     boolean workResult5 = protocol.doWork(true);
155     assertEquals(true, workResult5);
156     short workResult6 = protocol.doWork((short)1);
157     assertEquals((short)1, workResult6);
158     int workResult7 = protocol.doWork(5);
159     assertEquals(5, workResult7);
160     long workResult8 = protocol.doWork(5l);
161     assertEquals(5l, workResult8);
162     double workResult9 = protocol.doWork(6d);
163     assertEquals(6d, workResult9, 0.01);
164     float workResult10 = protocol.doWork(6f);
165     assertEquals(6f, workResult10, 0.01);
166     Text workResult11 = protocol.doWork(new Text("foo"));
167     assertEquals(new Text("foo"), workResult11);
168   }
169 
170   @Ignore @Test
171   public void testAggregation() throws Throwable {
172     HTable table = new HTable(util.getConfiguration(), TEST_TABLE);
173     Map<byte[], Long> results;
174 
175     // scan: for all regions
176     results = table
177         .coprocessorExec(ColumnAggregationProtocol.class,
178                          ROWS[rowSeperator1 - 1], ROWS[rowSeperator2 + 1],
179                          new Batch.Call<ColumnAggregationProtocol, Long>() {
180                            public Long call(ColumnAggregationProtocol instance)
181                                throws IOException {
182                              return instance.sum(TEST_FAMILY, TEST_QUALIFIER);
183                            }
184                          });
185     int sumResult = 0;
186     int expectedResult = 0;
187     for (Map.Entry<byte[], Long> e : results.entrySet()) {
188       sumResult += e.getValue();
189     }
190     for (int i = 0; i < ROWSIZE; i++) {
191       expectedResult += i;
192     }
193     assertEquals("Invalid result", sumResult, expectedResult);
194 
195     results.clear();
196 
197     // scan: for region 2 and region 3
198     results = table
199         .coprocessorExec(ColumnAggregationProtocol.class,
200                          ROWS[rowSeperator1 + 1], ROWS[rowSeperator2 + 1],
201                          new Batch.Call<ColumnAggregationProtocol, Long>() {
202                            public Long call(ColumnAggregationProtocol instance)
203                                throws IOException {
204                              return instance.sum(TEST_FAMILY, TEST_QUALIFIER);
205                            }
206                          });
207     sumResult = 0;
208     expectedResult = 0;
209     for (Map.Entry<byte[], Long> e : results.entrySet()) {
210       sumResult += e.getValue();
211     }
212     for (int i = rowSeperator1; i < ROWSIZE; i++) {
213       expectedResult += i;
214     }
215     assertEquals("Invalid result", sumResult, expectedResult);
216     table.close();
217   }
218 
219   @Test
220   public void testExecDeserialization() throws IOException {
221     DataOutputBuffer dob = new DataOutputBuffer();
222     dob.writeUTF(methodName);
223     dob.writeInt(1);
224     Scan scan = new Scan();
225     HbaseObjectWritable.writeObject(dob, scan, Scan.class, new Configuration());
226     dob.writeUTF("org.apache.hadoop.hbase.client.Scan");
227     Bytes.writeByteArray(dob, new byte[]{'a'});
228     // this is the dynamic protocol name
229     dob.writeUTF(protocolName);
230 
231     DataInputBuffer dib = new DataInputBuffer();
232     dib.reset(dob.getData(), dob.getLength());
233 
234     Exec after = new Exec();
235     after.setConf(HBaseConfiguration.create());
236     after.readFields(dib);
237     // no error thrown
238     assertEquals(after.getProtocolName(), protocolName);
239     assertEquals(after.getMethodName(), methodName);
240   }
241 
242   private static byte[][] makeN(byte[] base, int n) {
243     byte[][] ret = new byte[n][];
244     for (int i = 0; i < n; i++) {
245       ret[i] = Bytes.add(base, Bytes.toBytes(String.format("%02d", i)));
246     }
247     return ret;
248   }
249 
250   @org.junit.Rule
251   public org.apache.hadoop.hbase.ResourceCheckerJUnitRule cu =
252     new org.apache.hadoop.hbase.ResourceCheckerJUnitRule();
253 }
254