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.procedure2; 019 020import java.lang.Thread.UncaughtExceptionHandler; 021import java.util.Set; 022import java.util.concurrent.TimeUnit; 023import org.apache.hadoop.hbase.HBaseClassTestRule; 024import org.apache.hadoop.hbase.HBaseCommonTestingUtility; 025import org.apache.hadoop.hbase.testclassification.MasterTests; 026import org.apache.hadoop.hbase.testclassification.SmallTests; 027import org.junit.After; 028import org.junit.Before; 029import org.junit.ClassRule; 030import org.junit.Rule; 031import org.junit.Test; 032import org.junit.experimental.categories.Category; 033import org.junit.rules.ExpectedException; 034 035/** 036 * Make sure the {@link UncaughtExceptionHandler} will be called when there are unchecked exceptions 037 * thrown in the task. 038 * <p/> 039 * See HBASE-21875 and HBASE-21890 for more details. 040 */ 041@Category({ MasterTests.class, SmallTests.class }) 042public class TestRemoteProcedureDispatcherUncaughtExceptionHandler { 043 044 private static HBaseCommonTestingUtility UTIL = new HBaseCommonTestingUtility(); 045 046 @ClassRule 047 public static final HBaseClassTestRule CLASS_RULE = 048 HBaseClassTestRule.forClass(TestRemoteProcedureDispatcherUncaughtExceptionHandler.class); 049 050 private static final class ExceptionHandler implements UncaughtExceptionHandler { 051 052 private Throwable error; 053 054 @Override 055 public synchronized void uncaughtException(Thread t, Throwable e) { 056 this.error = e; 057 notifyAll(); 058 } 059 060 public synchronized void get() throws Throwable { 061 while (error == null) { 062 wait(); 063 } 064 throw error; 065 } 066 } 067 068 private static final class Dispatcher extends RemoteProcedureDispatcher<Void, Integer> { 069 070 private final UncaughtExceptionHandler handler; 071 072 public Dispatcher(UncaughtExceptionHandler handler) { 073 super(UTIL.getConfiguration()); 074 this.handler = handler; 075 } 076 077 @Override 078 protected UncaughtExceptionHandler getUncaughtExceptionHandler() { 079 return handler; 080 } 081 082 @Override 083 protected void remoteDispatch(Integer key, Set<RemoteProcedure> operations) { 084 } 085 086 @Override 087 protected void abortPendingOperations(Integer key, Set<RemoteProcedure> operations) { 088 } 089 } 090 091 @Rule 092 public ExpectedException thrown = ExpectedException.none(); 093 094 private ExceptionHandler handler; 095 096 private Dispatcher dispatcher; 097 098 @Before 099 public void setUp() { 100 handler = new ExceptionHandler(); 101 dispatcher = new Dispatcher(handler); 102 dispatcher.start(); 103 } 104 105 @After 106 public void tearDown() { 107 dispatcher.stop(); 108 dispatcher = null; 109 handler = null; 110 } 111 112 @Test 113 public void testSubmit() throws Throwable { 114 String message = "inject error"; 115 thrown.expect(RuntimeException.class); 116 thrown.expectMessage(message); 117 dispatcher.submitTask(new Runnable() { 118 119 @Override 120 public void run() { 121 throw new RuntimeException(message); 122 } 123 }); 124 handler.get(); 125 } 126 127 @Test 128 public void testDelayedSubmit() throws Throwable { 129 String message = "inject error"; 130 thrown.expect(RuntimeException.class); 131 thrown.expectMessage(message); 132 dispatcher.submitTask(new Runnable() { 133 134 @Override 135 public void run() { 136 throw new RuntimeException(message); 137 } 138 }, 100, TimeUnit.MILLISECONDS); 139 handler.get(); 140 } 141}