1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.hadoop.hbase.regionserver;
21
22 import static org.junit.Assert.*;
23
24 import java.io.IOException;
25 import java.util.List;
26 import java.util.Map;
27
28 import org.apache.hadoop.hbase.*;
29 import org.apache.hadoop.hbase.client.Get;
30 import org.apache.hadoop.hbase.client.HTable;
31 import org.apache.hadoop.hbase.client.Put;
32 import org.apache.hadoop.hbase.client.Row;
33 import org.apache.hadoop.hbase.client.coprocessor.Batch;
34 import org.apache.hadoop.hbase.coprocessor.CoprocessorHost;
35 import org.apache.hadoop.hbase.ipc.CoprocessorProtocol;
36 import org.apache.hadoop.hbase.ipc.HMasterInterface;
37 import org.apache.hadoop.hbase.ipc.HMasterRegionInterface;
38 import org.apache.hadoop.hbase.ipc.ProtocolSignature;
39 import org.apache.hadoop.hbase.util.Bytes;
40 import org.apache.hadoop.hbase.util.JVMClusterUtil;
41 import org.apache.hadoop.hbase.ipc.VersionedProtocol;
42 import org.junit.AfterClass;
43 import org.junit.BeforeClass;
44 import org.junit.Test;
45
46 import com.google.common.collect.Lists;
47 import org.junit.experimental.categories.Category;
48
49 @Category(MediumTests.class)
50 public class TestServerCustomProtocol {
51
52 public static interface PingProtocol extends CoprocessorProtocol {
53 public String ping();
54 public int getPingCount();
55 public int incrementCount(int diff);
56 public String hello(String name);
57 public void noop();
58 }
59
60
61 public static class PingHandler implements Coprocessor, PingProtocol, VersionedProtocol {
62 static long VERSION = 1;
63 private int counter = 0;
64 @Override
65 public String ping() {
66 counter++;
67 return "pong";
68 }
69
70 @Override
71 public int getPingCount() {
72 return counter;
73 }
74
75 @Override
76 public int incrementCount(int diff) {
77 counter += diff;
78 return counter;
79 }
80
81 @Override
82 public String hello(String name) {
83 if (name == null) {
84 return "Who are you?";
85 } else if ("nobody".equals(name)) {
86 return null;
87 }
88 return "Hello, "+name;
89 }
90
91 @Override
92 public void noop() {
93
94 }
95
96 @Override
97 public ProtocolSignature getProtocolSignature(
98 String protocol, long version, int clientMethodsHashCode)
99 throws IOException {
100 return new ProtocolSignature(VERSION, null);
101 }
102
103 @Override
104 public long getProtocolVersion(String s, long l) throws IOException {
105 return VERSION;
106 }
107
108 @Override
109 public void start(CoprocessorEnvironment env) throws IOException {
110 }
111
112 @Override
113 public void stop(CoprocessorEnvironment env) throws IOException {
114 }
115 }
116
117 private static final byte[] TEST_TABLE = Bytes.toBytes("test");
118 private static final byte[] TEST_FAMILY = Bytes.toBytes("f1");
119
120 private static final byte[] ROW_A = Bytes.toBytes("aaa");
121 private static final byte[] ROW_B = Bytes.toBytes("bbb");
122 private static final byte[] ROW_C = Bytes.toBytes("ccc");
123
124 private static final byte[] ROW_AB = Bytes.toBytes("abb");
125 private static final byte[] ROW_BC = Bytes.toBytes("bcc");
126
127 private static HBaseTestingUtility util = new HBaseTestingUtility();
128 private static MiniHBaseCluster cluster = null;
129
130 @BeforeClass
131 public static void setupBeforeClass() throws Exception {
132 util.getConfiguration().set(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,
133 PingHandler.class.getName());
134 util.startMiniCluster(1);
135 cluster = util.getMiniHBaseCluster();
136
137 HTable table = util.createTable(TEST_TABLE, TEST_FAMILY);
138 util.createMultiRegions(util.getConfiguration(), table, TEST_FAMILY,
139 new byte[][]{ HConstants.EMPTY_BYTE_ARRAY,
140 ROW_B, ROW_C});
141
142 Put puta = new Put( ROW_A );
143 puta.add(TEST_FAMILY, Bytes.toBytes("col1"), Bytes.toBytes(1));
144 table.put(puta);
145
146 Put putb = new Put( ROW_B );
147 putb.add(TEST_FAMILY, Bytes.toBytes("col1"), Bytes.toBytes(1));
148 table.put(putb);
149
150 Put putc = new Put( ROW_C );
151 putc.add(TEST_FAMILY, Bytes.toBytes("col1"), Bytes.toBytes(1));
152 table.put(putc);
153 }
154
155 @AfterClass
156 public static void tearDownAfterClass() throws Exception {
157 util.shutdownMiniCluster();
158 }
159
160 @Test
161 public void testSingleProxy() throws Exception {
162 HTable table = new HTable(util.getConfiguration(), TEST_TABLE);
163
164 PingProtocol pinger = table.coprocessorProxy(PingProtocol.class, ROW_A);
165 String result = pinger.ping();
166 assertEquals("Invalid custom protocol response", "pong", result);
167 result = pinger.hello("George");
168 assertEquals("Invalid custom protocol response", "Hello, George", result);
169 result = pinger.hello(null);
170 assertEquals("Should handle NULL parameter", "Who are you?", result);
171 result = pinger.hello("nobody");
172 assertNull(result);
173 int cnt = pinger.getPingCount();
174 assertTrue("Count should be incremented", cnt > 0);
175 int newcnt = pinger.incrementCount(5);
176 assertEquals("Counter should have incremented by 5", cnt+5, newcnt);
177 }
178
179 @Test
180 public void testSingleMethod() throws Throwable {
181 HTable table = new HTable(util.getConfiguration(), TEST_TABLE);
182
183 List<? extends Row> rows = Lists.newArrayList(
184 new Get(ROW_A), new Get(ROW_B), new Get(ROW_C));
185
186 Batch.Call<PingProtocol,String> call = Batch.forMethod(PingProtocol.class,
187 "ping");
188 Map<byte[],String> results =
189 table.coprocessorExec(PingProtocol.class, ROW_A, ROW_C, call);
190
191
192 verifyRegionResults(table, results, ROW_A);
193 verifyRegionResults(table, results, ROW_B);
194 verifyRegionResults(table, results, ROW_C);
195
196 Batch.Call<PingProtocol,String> helloCall =
197 Batch.forMethod(PingProtocol.class, "hello", "NAME");
198 results =
199 table.coprocessorExec(PingProtocol.class, ROW_A, ROW_C, helloCall);
200
201
202 verifyRegionResults(table, results, "Hello, NAME", ROW_A);
203 verifyRegionResults(table, results, "Hello, NAME", ROW_B);
204 verifyRegionResults(table, results, "Hello, NAME", ROW_C);
205 }
206
207 @Test
208 public void testRowRange() throws Throwable {
209 HTable table = new HTable(util.getConfiguration(), TEST_TABLE);
210
211
212 Map<byte[],String> results = table.coprocessorExec(PingProtocol.class,
213 null, null, new Batch.Call<PingProtocol,String>() {
214 public String call(PingProtocol instance) {
215 return instance.ping();
216 }
217 });
218
219 verifyRegionResults(table, results, ROW_A);
220 verifyRegionResults(table, results, ROW_B);
221 verifyRegionResults(table, results, ROW_C);
222
223
224 results = table.coprocessorExec(PingProtocol.class, ROW_BC, null,
225 new Batch.Call<PingProtocol,String>() {
226 public String call(PingProtocol instance) {
227 return instance.ping();
228 }
229 });
230
231 HRegionLocation loc = table.getRegionLocation(ROW_A);
232 assertNull("Should be missing region for row aaa (prior to start row)",
233 results.get(loc.getRegionInfo().getRegionName()));
234 verifyRegionResults(table, results, ROW_B);
235 verifyRegionResults(table, results, ROW_C);
236
237
238 results = table.coprocessorExec(PingProtocol.class, null, ROW_BC,
239 new Batch.Call<PingProtocol,String>() {
240 public String call(PingProtocol instance) {
241 return instance.ping();
242 }
243 });
244
245 verifyRegionResults(table, results, ROW_A);
246 verifyRegionResults(table, results, ROW_B);
247 loc = table.getRegionLocation(ROW_C);
248 assertNull("Should be missing region for row ccc (past stop row)",
249 results.get(loc.getRegionInfo().getRegionName()));
250
251
252 results = table.coprocessorExec(PingProtocol.class, ROW_AB, ROW_BC,
253 new Batch.Call<PingProtocol,String>() {
254 public String call(PingProtocol instance) {
255 return instance.ping();
256 }
257 });
258
259 verifyRegionResults(table, results, ROW_A);
260 verifyRegionResults(table, results, ROW_B);
261 loc = table.getRegionLocation(ROW_C);
262 assertNull("Should be missing region for row ccc (past stop row)",
263 results.get(loc.getRegionInfo().getRegionName()));
264
265
266 results = table.coprocessorExec(PingProtocol.class, ROW_B, ROW_BC,
267 new Batch.Call<PingProtocol,String>() {
268 public String call(PingProtocol instance) {
269 return instance.ping();
270 }
271 });
272
273 verifyRegionResults(table, results, ROW_B);
274 loc = table.getRegionLocation(ROW_A);
275 assertNull("Should be missing region for row aaa (prior to start)",
276 results.get(loc.getRegionInfo().getRegionName()));
277 loc = table.getRegionLocation(ROW_C);
278 assertNull("Should be missing region for row ccc (past stop row)",
279 results.get(loc.getRegionInfo().getRegionName()));
280 }
281
282 @Test
283 public void testCompountCall() throws Throwable {
284 HTable table = new HTable(util.getConfiguration(), TEST_TABLE);
285
286 Map<byte[],String> results = table.coprocessorExec(PingProtocol.class,
287 ROW_A, ROW_C,
288 new Batch.Call<PingProtocol,String>() {
289 public String call(PingProtocol instance) {
290 return instance.hello(instance.ping());
291 }
292 });
293
294 verifyRegionResults(table, results, "Hello, pong", ROW_A);
295 verifyRegionResults(table, results, "Hello, pong", ROW_B);
296 verifyRegionResults(table, results, "Hello, pong", ROW_C);
297 }
298
299 @Test
300 public void testNullCall() throws Throwable {
301 HTable table = new HTable(util.getConfiguration(), TEST_TABLE);
302
303 Map<byte[],String> results = table.coprocessorExec(PingProtocol.class,
304 ROW_A, ROW_C,
305 new Batch.Call<PingProtocol,String>() {
306 public String call(PingProtocol instance) {
307 return instance.hello(null);
308 }
309 });
310
311 verifyRegionResults(table, results, "Who are you?", ROW_A);
312 verifyRegionResults(table, results, "Who are you?", ROW_B);
313 verifyRegionResults(table, results, "Who are you?", ROW_C);
314 }
315
316 @Test
317 public void testNullReturn() throws Throwable {
318 HTable table = new HTable(util.getConfiguration(), TEST_TABLE);
319
320 Map<byte[],String> results = table.coprocessorExec(PingProtocol.class,
321 ROW_A, ROW_C,
322 new Batch.Call<PingProtocol,String>(){
323 public String call(PingProtocol instance) {
324 return instance.hello("nobody");
325 }
326 });
327
328 verifyRegionResults(table, results, null, ROW_A);
329 verifyRegionResults(table, results, null, ROW_B);
330 verifyRegionResults(table, results, null, ROW_C);
331 }
332
333 @Test
334 public void testVoidReturnType() throws Throwable {
335 HTable table = new HTable(util.getConfiguration(), TEST_TABLE);
336
337 Map<byte[],Object> results = table.coprocessorExec(PingProtocol.class,
338 ROW_A, ROW_C,
339 new Batch.Call<PingProtocol,Object>(){
340 public Object call(PingProtocol instance) {
341 instance.noop();
342 return null;
343 }
344 });
345
346 assertEquals("Should have results from three regions", 3, results.size());
347
348 for (Object v : results.values()) {
349 assertNull(v);
350 }
351 }
352
353 private void verifyRegionResults(HTable table,
354 Map<byte[],String> results, byte[] row) throws Exception {
355 verifyRegionResults(table, results, "pong", row);
356 }
357
358 private void verifyRegionResults(HTable table,
359 Map<byte[],String> results, String expected, byte[] row)
360 throws Exception {
361 HRegionLocation loc = table.getRegionLocation(row);
362 byte[] region = loc.getRegionInfo().getRegionName();
363 assertTrue("Results should contain region " +
364 Bytes.toStringBinary(region)+" for row '"+Bytes.toStringBinary(row)+"'",
365 results.containsKey(region));
366 assertEquals("Invalid result for row '"+Bytes.toStringBinary(row)+"'",
367 expected, results.get(region));
368 }
369
370 @org.junit.Rule
371 public org.apache.hadoop.hbase.ResourceCheckerJUnitRule cu =
372 new org.apache.hadoop.hbase.ResourceCheckerJUnitRule();
373 }
374