1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.ipc;
19
20 import static org.junit.Assert.assertEquals;
21 import static org.junit.Assert.assertTrue;
22 import static org.junit.Assert.fail;
23 import static org.mockito.Matchers.anyObject;
24 import static org.mockito.Mockito.spy;
25 import static org.mockito.Mockito.verify;
26 import static org.mockito.internal.verification.VerificationModeFactory.times;
27
28 import java.io.IOException;
29 import java.net.ConnectException;
30 import java.net.InetAddress;
31 import java.net.InetSocketAddress;
32 import java.net.SocketTimeoutException;
33 import java.util.ArrayList;
34 import java.util.List;
35
36 import org.apache.commons.logging.Log;
37 import org.apache.commons.logging.LogFactory;
38 import org.apache.hadoop.conf.Configuration;
39 import org.apache.hadoop.hbase.Cell;
40 import org.apache.hadoop.hbase.CellScanner;
41 import org.apache.hadoop.hbase.CellUtil;
42 import org.apache.hadoop.hbase.HBaseConfiguration;
43 import org.apache.hadoop.hbase.HConstants;
44 import org.apache.hadoop.hbase.KeyValue;
45 import org.apache.hadoop.hbase.ServerName;
46 import org.apache.hadoop.hbase.client.MetricsConnection;
47 import org.apache.hadoop.hbase.exceptions.ConnectionClosingException;
48 import org.apache.hadoop.hbase.ipc.protobuf.generated.TestProtos.EchoRequestProto;
49 import org.apache.hadoop.hbase.ipc.protobuf.generated.TestProtos.EchoResponseProto;
50 import org.apache.hadoop.hbase.ipc.protobuf.generated.TestProtos.EmptyRequestProto;
51 import org.apache.hadoop.hbase.ipc.protobuf.generated.TestProtos.EmptyResponseProto;
52 import org.apache.hadoop.hbase.ipc.protobuf.generated.TestRpcServiceProtos;
53 import org.apache.hadoop.hbase.ipc.protobuf.generated.TestRpcServiceProtos.TestProtobufRpcProto.BlockingInterface;
54 import org.apache.hadoop.hbase.monitoring.MonitoredRPCHandler;
55 import org.apache.hadoop.hbase.security.User;
56 import org.apache.hadoop.hbase.util.Bytes;
57 import org.apache.hadoop.hbase.util.Pair;
58 import org.apache.hadoop.io.compress.GzipCodec;
59 import org.apache.hadoop.util.StringUtils;
60 import org.junit.Assert;
61 import org.junit.Test;
62
63 import com.google.common.collect.ImmutableList;
64 import com.google.common.collect.Lists;
65 import com.google.protobuf.BlockingRpcChannel;
66 import com.google.protobuf.BlockingService;
67 import com.google.protobuf.Descriptors.MethodDescriptor;
68 import com.google.protobuf.Message;
69 import com.google.protobuf.RpcController;
70 import com.google.protobuf.ServiceException;
71
72
73
74
75 public abstract class AbstractTestIPC {
76
77 private static final Log LOG = LogFactory.getLog(AbstractTestIPC.class);
78
79 private static byte[] CELL_BYTES = Bytes.toBytes("xyz");
80 private static KeyValue CELL = new KeyValue(CELL_BYTES, CELL_BYTES, CELL_BYTES, CELL_BYTES);
81 static byte[] BIG_CELL_BYTES = new byte[10 * 1024];
82 static KeyValue BIG_CELL = new KeyValue(CELL_BYTES, CELL_BYTES, CELL_BYTES, BIG_CELL_BYTES);
83 static final Configuration CONF = HBaseConfiguration.create();
84
85
86
87
88 static final BlockingService SERVICE =
89 TestRpcServiceProtos.TestProtobufRpcProto
90 .newReflectiveBlockingService(new TestRpcServiceProtos.TestProtobufRpcProto.BlockingInterface() {
91
92 @Override
93 public EmptyResponseProto ping(RpcController controller, EmptyRequestProto request)
94 throws ServiceException {
95 return null;
96 }
97
98 @Override
99 public EmptyResponseProto error(RpcController controller, EmptyRequestProto request)
100 throws ServiceException {
101 return null;
102 }
103
104 @Override
105 public EchoResponseProto echo(RpcController controller, EchoRequestProto request)
106 throws ServiceException {
107 if (controller instanceof PayloadCarryingRpcController) {
108 PayloadCarryingRpcController pcrc = (PayloadCarryingRpcController) controller;
109
110
111
112
113
114 CellScanner cellScanner = pcrc.cellScanner();
115 List<Cell> list = null;
116 if (cellScanner != null) {
117 list = new ArrayList<Cell>();
118 try {
119 while (cellScanner.advance()) {
120 list.add(cellScanner.current());
121 }
122 } catch (IOException e) {
123 throw new ServiceException(e);
124 }
125 }
126 cellScanner = CellUtil.createCellScanner(list);
127 ((PayloadCarryingRpcController) controller).setCellScanner(cellScanner);
128 }
129 return EchoResponseProto.newBuilder().setMessage(request.getMessage()).build();
130 }
131 });
132
133
134
135
136
137 static class TestRpcServer extends RpcServer {
138
139 TestRpcServer() throws IOException {
140 this(new FifoRpcScheduler(CONF, 1), CONF);
141 }
142
143 TestRpcServer(Configuration conf) throws IOException {
144 this(new FifoRpcScheduler(conf, 1), conf);
145 }
146
147 TestRpcServer(RpcScheduler scheduler, Configuration conf) throws IOException {
148 super(null, "testRpcServer", Lists
149 .newArrayList(new BlockingServiceAndInterface(SERVICE, null)), new InetSocketAddress(
150 "localhost", 0), conf, scheduler);
151 }
152
153 @Override
154 public Pair<Message, CellScanner> call(BlockingService service, MethodDescriptor md,
155 Message param, CellScanner cellScanner, long receiveTime, MonitoredRPCHandler status)
156 throws IOException {
157 return super.call(service, md, param, cellScanner, receiveTime, status);
158 }
159 }
160
161 protected abstract AbstractRpcClient createRpcClientNoCodec(Configuration conf);
162
163
164
165
166
167
168 @Test
169 public void testNoCodec() throws InterruptedException, IOException {
170 Configuration conf = HBaseConfiguration.create();
171 AbstractRpcClient client = createRpcClientNoCodec(conf);
172 TestRpcServer rpcServer = new TestRpcServer();
173 try {
174 rpcServer.start();
175 MethodDescriptor md = SERVICE.getDescriptorForType().findMethodByName("echo");
176 final String message = "hello";
177 EchoRequestProto param = EchoRequestProto.newBuilder().setMessage(message).build();
178 InetSocketAddress address = rpcServer.getListenerAddress();
179 if (address == null) {
180 throw new IOException("Listener channel is closed");
181 }
182 Pair<Message, CellScanner> r =
183 client.call(null, md, param, md.getOutputType().toProto(), User.getCurrent(), address,
184 new MetricsConnection.CallStats());
185 assertTrue(r.getSecond() == null);
186
187 assertTrue(r.getFirst().toString().contains(message));
188 } finally {
189 client.close();
190 rpcServer.stop();
191 }
192 }
193
194 protected abstract AbstractRpcClient createRpcClient(Configuration conf);
195
196
197
198
199
200
201
202
203
204
205 @Test
206 public void testCompressCellBlock() throws IOException, InterruptedException, SecurityException,
207 NoSuchMethodException, ServiceException {
208 Configuration conf = new Configuration(HBaseConfiguration.create());
209 conf.set("hbase.client.rpc.compressor", GzipCodec.class.getCanonicalName());
210 List<Cell> cells = new ArrayList<Cell>();
211 int count = 3;
212 for (int i = 0; i < count; i++) {
213 cells.add(CELL);
214 }
215 AbstractRpcClient client = createRpcClient(conf);
216 TestRpcServer rpcServer = new TestRpcServer();
217 try {
218 rpcServer.start();
219 MethodDescriptor md = SERVICE.getDescriptorForType().findMethodByName("echo");
220 EchoRequestProto param = EchoRequestProto.newBuilder().setMessage("hello").build();
221 PayloadCarryingRpcController pcrc =
222 new PayloadCarryingRpcController(CellUtil.createCellScanner(cells));
223 InetSocketAddress address = rpcServer.getListenerAddress();
224 if (address == null) {
225 throw new IOException("Listener channel is closed");
226 }
227 Pair<Message, CellScanner> r =
228 client.call(pcrc, md, param, md.getOutputType().toProto(), User.getCurrent(), address,
229 new MetricsConnection.CallStats());
230 int index = 0;
231 while (r.getSecond().advance()) {
232 assertTrue(CELL.equals(r.getSecond().current()));
233 index++;
234 }
235 assertEquals(count, index);
236 } finally {
237 client.close();
238 rpcServer.stop();
239 }
240 }
241
242 protected abstract AbstractRpcClient createRpcClientRTEDuringConnectionSetup(Configuration conf)
243 throws IOException;
244
245 @Test
246 public void testRTEDuringConnectionSetup() throws Exception {
247 Configuration conf = HBaseConfiguration.create();
248 TestRpcServer rpcServer = new TestRpcServer();
249 AbstractRpcClient client = createRpcClientRTEDuringConnectionSetup(conf);
250 try {
251 rpcServer.start();
252 MethodDescriptor md = SERVICE.getDescriptorForType().findMethodByName("echo");
253 EchoRequestProto param = EchoRequestProto.newBuilder().setMessage("hello").build();
254 InetSocketAddress address = rpcServer.getListenerAddress();
255 if (address == null) {
256 throw new IOException("Listener channel is closed");
257 }
258 client.call(null, md, param, null, User.getCurrent(), address,
259 new MetricsConnection.CallStats());
260 fail("Expected an exception to have been thrown!");
261 } catch (Exception e) {
262 LOG.info("Caught expected exception: " + e.toString());
263 assertTrue(StringUtils.stringifyException(e).contains("Injected fault"));
264 } finally {
265 client.close();
266 rpcServer.stop();
267 }
268 }
269
270
271 @Test
272 public void testRpcScheduler() throws IOException, InterruptedException {
273 RpcScheduler scheduler = spy(new FifoRpcScheduler(CONF, 1));
274 RpcServer rpcServer = new TestRpcServer(scheduler, CONF);
275 verify(scheduler).init((RpcScheduler.Context) anyObject());
276 AbstractRpcClient client = createRpcClient(CONF);
277 try {
278 rpcServer.start();
279 verify(scheduler).start();
280 MethodDescriptor md = SERVICE.getDescriptorForType().findMethodByName("echo");
281 EchoRequestProto param = EchoRequestProto.newBuilder().setMessage("hello").build();
282 InetSocketAddress address = rpcServer.getListenerAddress();
283 if (address == null) {
284 throw new IOException("Listener channel is closed");
285 }
286 for (int i = 0; i < 10; i++) {
287 client.call(new PayloadCarryingRpcController(
288 CellUtil.createCellScanner(ImmutableList.<Cell> of(CELL))), md, param,
289 md.getOutputType().toProto(), User.getCurrent(), address,
290 new MetricsConnection.CallStats());
291 }
292 verify(scheduler, times(10)).dispatch((CallRunner) anyObject());
293 } finally {
294 rpcServer.stop();
295 verify(scheduler).stop();
296 }
297 }
298
299
300 @Test
301 public void testRpcMaxRequestSize() throws IOException, InterruptedException {
302 Configuration conf = new Configuration(CONF);
303 conf.setInt(RpcServer.MAX_REQUEST_SIZE, 1000);
304 RpcServer rpcServer = new TestRpcServer(conf);
305 AbstractRpcClient client = createRpcClient(conf);
306 try {
307 rpcServer.start();
308 MethodDescriptor md = SERVICE.getDescriptorForType().findMethodByName("echo");
309 StringBuilder message = new StringBuilder(1200);
310 for (int i = 0; i < 200; i++) {
311 message.append("hello.");
312 }
313
314 EchoRequestProto param = EchoRequestProto.newBuilder().setMessage(message.toString()).build();
315 InetSocketAddress address = rpcServer.getListenerAddress();
316 if (address == null) {
317 throw new IOException("Listener channel is closed");
318 }
319 try {
320 client.call(new PayloadCarryingRpcController(
321 CellUtil.createCellScanner(ImmutableList.<Cell> of(CELL))), md, param,
322 md.getOutputType().toProto(), User.getCurrent(), address,
323 new MetricsConnection.CallStats());
324 fail("RPC should have failed because it exceeds max request size");
325 } catch(IOException e) {
326 LOG.info("Caught expected exception: " + e);
327 assertTrue(e.toString(),
328 StringUtils.stringifyException(e).contains("RequestTooBigException"));
329 }
330 } finally {
331 rpcServer.stop();
332 }
333 }
334
335
336
337
338 static class TestRpcServer1 extends RpcServer {
339
340 private static BlockingInterface SERVICE1 =
341 new TestRpcServiceProtos.TestProtobufRpcProto.BlockingInterface() {
342 @Override
343 public EmptyResponseProto ping(RpcController unused, EmptyRequestProto request)
344 throws ServiceException {
345 return EmptyResponseProto.newBuilder().build();
346 }
347
348 @Override
349 public EchoResponseProto echo(RpcController unused, EchoRequestProto request)
350 throws ServiceException {
351 final InetAddress remoteAddr = TestRpcServer1.getRemoteAddress();
352 final String message = remoteAddr == null ? "NULL" : remoteAddr.getHostAddress();
353 return EchoResponseProto.newBuilder().setMessage(message).build();
354 }
355
356 @Override
357 public EmptyResponseProto error(RpcController unused, EmptyRequestProto request)
358 throws ServiceException {
359 throw new ServiceException("error", new IOException("error"));
360 }
361 };
362
363 TestRpcServer1() throws IOException {
364 this(new FifoRpcScheduler(CONF, 1));
365 }
366
367 TestRpcServer1(RpcScheduler scheduler) throws IOException {
368 super(null, "testRemoteAddressInCallObject", Lists
369 .newArrayList(new BlockingServiceAndInterface(TestRpcServiceProtos.TestProtobufRpcProto
370 .newReflectiveBlockingService(SERVICE1), null)),
371 new InetSocketAddress("localhost", 0), CONF, scheduler);
372 }
373 }
374
375
376
377
378
379
380 @Test
381 public void testRpcServerForNotNullRemoteAddressInCallObject() throws IOException,
382 ServiceException {
383 final RpcScheduler scheduler = new FifoRpcScheduler(CONF, 1);
384 final TestRpcServer1 rpcServer = new TestRpcServer1(scheduler);
385 final InetSocketAddress localAddr = new InetSocketAddress("localhost", 0);
386 final AbstractRpcClient client =
387 new RpcClientImpl(CONF, HConstants.CLUSTER_ID_DEFAULT, localAddr, null);
388 try {
389 rpcServer.start();
390 final InetSocketAddress isa = rpcServer.getListenerAddress();
391 if (isa == null) {
392 throw new IOException("Listener channel is closed");
393 }
394 final BlockingRpcChannel channel =
395 client.createBlockingRpcChannel(
396 ServerName.valueOf(isa.getHostName(), isa.getPort(), System.currentTimeMillis()),
397 User.getCurrent(), 0);
398 TestRpcServiceProtos.TestProtobufRpcProto.BlockingInterface stub =
399 TestRpcServiceProtos.TestProtobufRpcProto.newBlockingStub(channel);
400 final EchoRequestProto echoRequest =
401 EchoRequestProto.newBuilder().setMessage("GetRemoteAddress").build();
402 final EchoResponseProto echoResponse = stub.echo(null, echoRequest);
403 Assert.assertEquals(localAddr.getAddress().getHostAddress(), echoResponse.getMessage());
404 } finally {
405 client.close();
406 rpcServer.stop();
407 }
408 }
409
410 @Test
411 public void testWrapException() throws Exception {
412 AbstractRpcClient client =
413 (AbstractRpcClient) RpcClientFactory.createClient(CONF, "AbstractTestIPC");
414 final InetSocketAddress address = InetSocketAddress.createUnresolved("localhost", 0);
415 assertTrue(client.wrapException(address, new ConnectException()) instanceof ConnectException);
416 assertTrue(client.wrapException(address,
417 new SocketTimeoutException()) instanceof SocketTimeoutException);
418 assertTrue(client.wrapException(address, new ConnectionClosingException(
419 "Test AbstractRpcClient#wrapException")) instanceof ConnectionClosingException);
420 assertTrue(client
421 .wrapException(address, new CallTimeoutException("Test AbstractRpcClient#wrapException"))
422 .getCause() instanceof CallTimeoutException);
423 }
424 }