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.ipc; 019 020import static org.hamcrest.CoreMatchers.instanceOf; 021import static org.hamcrest.MatcherAssert.assertThat; 022 023import java.io.IOException; 024import java.lang.reflect.Constructor; 025import java.lang.reflect.InvocationTargetException; 026import java.net.InetSocketAddress; 027import java.util.ArrayList; 028import java.util.List; 029import java.util.concurrent.CompletableFuture; 030import java.util.concurrent.TimeoutException; 031import org.apache.commons.lang3.mutable.MutableInt; 032import org.apache.hadoop.hbase.HBaseClassTestRule; 033import org.apache.hadoop.hbase.exceptions.ClientExceptionsUtil; 034import org.apache.hadoop.hbase.exceptions.TimeoutIOException; 035import org.apache.hadoop.hbase.testclassification.ClientTests; 036import org.apache.hadoop.hbase.testclassification.SmallTests; 037import org.apache.hadoop.hbase.util.FutureUtils; 038import org.junit.ClassRule; 039import org.junit.Test; 040import org.junit.experimental.categories.Category; 041 042import org.apache.hbase.thirdparty.io.netty.channel.DefaultEventLoop; 043import org.apache.hbase.thirdparty.io.netty.channel.EventLoop; 044 045@Category({ ClientTests.class, SmallTests.class }) 046public class TestIPCUtil { 047 048 @ClassRule 049 public static final HBaseClassTestRule CLASS_RULE = 050 HBaseClassTestRule.forClass(TestIPCUtil.class); 051 052 private static Throwable create(Class<? extends Throwable> clazz) throws InstantiationException, 053 IllegalAccessException, InvocationTargetException, NoSuchMethodException { 054 try { 055 Constructor<? extends Throwable> c = clazz.getDeclaredConstructor(); 056 c.setAccessible(true); 057 return c.newInstance(); 058 } catch (NoSuchMethodException e) { 059 // fall through 060 } 061 062 try { 063 Constructor<? extends Throwable> c = clazz.getDeclaredConstructor(String.class); 064 c.setAccessible(true); 065 return c.newInstance("error"); 066 } catch (NoSuchMethodException e) { 067 // fall through 068 } 069 070 try { 071 Constructor<? extends Throwable> c = clazz.getDeclaredConstructor(Throwable.class); 072 c.setAccessible(true); 073 return c.newInstance(new Exception("error")); 074 } catch (NoSuchMethodException e) { 075 // fall through 076 } 077 078 try { 079 Constructor<? extends Throwable> c = 080 clazz.getDeclaredConstructor(String.class, Throwable.class); 081 c.setAccessible(true); 082 return c.newInstance("error", new Exception("error")); 083 } catch (NoSuchMethodException e) { 084 // fall through 085 } 086 087 Constructor<? extends Throwable> c = 088 clazz.getDeclaredConstructor(Throwable.class, Throwable.class); 089 c.setAccessible(true); 090 return c.newInstance(new Exception("error"), "error"); 091 } 092 093 /** 094 * See HBASE-21862, it is very important to keep the original exception type for connection 095 * exceptions. 096 */ 097 @Test 098 public void testWrapConnectionException() throws Exception { 099 List<Throwable> exceptions = new ArrayList<>(); 100 for (Class<? extends Throwable> clazz : ClientExceptionsUtil.getConnectionExceptionTypes()) { 101 exceptions.add(create(clazz)); 102 } 103 InetSocketAddress addr = InetSocketAddress.createUnresolved("127.0.0.1", 12345); 104 for (Throwable exception : exceptions) { 105 if (exception instanceof TimeoutException) { 106 assertThat(IPCUtil.wrapException(addr, exception), instanceOf(TimeoutIOException.class)); 107 } else { 108 assertThat(IPCUtil.wrapException(addr, exception), instanceOf(exception.getClass())); 109 } 110 } 111 } 112 113 @Test 114 public void testExecute() throws IOException { 115 EventLoop eventLoop = new DefaultEventLoop(); 116 MutableInt executed = new MutableInt(0); 117 MutableInt numStackTraceElements = new MutableInt(0); 118 CompletableFuture<Void> future = new CompletableFuture<>(); 119 try { 120 IPCUtil.execute(eventLoop, new Runnable() { 121 122 @Override 123 public void run() { 124 int numElements = new Exception().getStackTrace().length; 125 int depth = executed.getAndIncrement(); 126 if (depth <= IPCUtil.MAX_DEPTH) { 127 if (numElements <= numStackTraceElements.intValue()) { 128 future.completeExceptionally( 129 new AssertionError("should call run directly but stack trace decreased from " + 130 numStackTraceElements.intValue() + " to " + numElements)); 131 return; 132 } 133 numStackTraceElements.setValue(numElements); 134 IPCUtil.execute(eventLoop, this); 135 } else { 136 if (numElements >= numStackTraceElements.intValue()) { 137 future.completeExceptionally( 138 new AssertionError("should call eventLoop.execute to prevent stack overflow but" + 139 " stack trace increased from " + numStackTraceElements.intValue() + " to " + 140 numElements)); 141 } else { 142 future.complete(null); 143 } 144 } 145 } 146 }); 147 FutureUtils.get(future); 148 } finally { 149 eventLoop.shutdownGracefully(); 150 } 151 } 152}