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.coprocessor;
21
22 import static org.junit.Assert.assertEquals;
23 import static org.junit.Assert.assertFalse;
24 import static org.junit.Assert.assertTrue;
25 import static org.junit.Assert.fail;
26
27 import java.io.IOException;
28
29 import org.apache.hadoop.conf.Configuration;
30 import org.apache.hadoop.hbase.Abortable;
31 import org.apache.hadoop.hbase.CoprocessorEnvironment;
32 import org.apache.hadoop.hbase.HBaseTestingUtility;
33 import org.apache.hadoop.hbase.HColumnDescriptor;
34 import org.apache.hadoop.hbase.HRegionInfo;
35 import org.apache.hadoop.hbase.HTableDescriptor;
36 import org.apache.hadoop.hbase.MediumTests;
37 import org.apache.hadoop.hbase.MiniHBaseCluster;
38 import org.apache.hadoop.hbase.TableName;
39 import org.apache.hadoop.hbase.client.HBaseAdmin;
40 import org.apache.hadoop.hbase.master.HMaster;
41 import org.apache.hadoop.hbase.master.MasterCoprocessorHost;
42 import org.apache.hadoop.hbase.util.Bytes;
43 import org.apache.hadoop.hbase.zookeeper.ZooKeeperNodeTracker;
44 import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
45 import org.junit.AfterClass;
46 import org.junit.BeforeClass;
47 import org.junit.Test;
48 import org.junit.experimental.categories.Category;
49
50
51
52
53
54
55
56 @Category(MediumTests.class)
57 public class TestMasterCoprocessorExceptionWithAbort {
58
59 public static class MasterTracker extends ZooKeeperNodeTracker {
60 public boolean masterZKNodeWasDeleted = false;
61
62 public MasterTracker(ZooKeeperWatcher zkw, String masterNode, Abortable abortable) {
63 super(zkw, masterNode, abortable);
64 }
65
66 @Override
67 public synchronized void nodeDeleted(String path) {
68 if (path.equals("/hbase/master")) {
69 masterZKNodeWasDeleted = true;
70 }
71 }
72 }
73
74 public static class CreateTableThread extends Thread {
75 HBaseTestingUtility UTIL;
76 public CreateTableThread(HBaseTestingUtility UTIL) {
77 this.UTIL = UTIL;
78 }
79
80 @Override
81 public void run() {
82
83
84 HTableDescriptor htd = new HTableDescriptor(TableName.valueOf(TEST_TABLE));
85 htd.addFamily(new HColumnDescriptor(TEST_FAMILY));
86 try {
87 HBaseAdmin admin = UTIL.getHBaseAdmin();
88 admin.createTable(htd);
89 fail("BuggyMasterObserver failed to throw an exception.");
90 } catch (IOException e) {
91 assertEquals("HBaseAdmin threw an interrupted IOException as expected.",
92 e.getClass().getName(), "java.io.InterruptedIOException");
93 }
94 }
95 }
96
97 public static class BuggyMasterObserver extends BaseMasterObserver {
98 private boolean preCreateTableCalled;
99 private boolean postCreateTableCalled;
100 private boolean startCalled;
101 private boolean postStartMasterCalled;
102
103 @Override
104 public void postCreateTable(ObserverContext<MasterCoprocessorEnvironment> env,
105 HTableDescriptor desc, HRegionInfo[] regions) throws IOException {
106
107
108 Integer i;
109 i = null;
110 i = i++;
111 }
112
113 public boolean wasCreateTableCalled() {
114 return preCreateTableCalled && postCreateTableCalled;
115 }
116
117 @Override
118 public void postStartMaster(ObserverContext<MasterCoprocessorEnvironment> ctx)
119 throws IOException {
120 postStartMasterCalled = true;
121 }
122
123 public boolean wasStartMasterCalled() {
124 return postStartMasterCalled;
125 }
126
127 @Override
128 public void start(CoprocessorEnvironment env) throws IOException {
129 startCalled = true;
130 }
131
132 public boolean wasStarted() {
133 return startCalled;
134 }
135 }
136
137 private static HBaseTestingUtility UTIL = new HBaseTestingUtility();
138 private static byte[] TEST_TABLE = Bytes.toBytes("observed_table");
139 private static byte[] TEST_FAMILY = Bytes.toBytes("fam1");
140
141 @BeforeClass
142 public static void setupBeforeClass() throws Exception {
143 Configuration conf = UTIL.getConfiguration();
144 conf.set(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY,
145 BuggyMasterObserver.class.getName());
146 conf.set("hbase.coprocessor.abortonerror", "true");
147 UTIL.startMiniCluster();
148 }
149
150 @AfterClass
151 public static void teardownAfterClass() throws Exception {
152 UTIL.shutdownMiniCluster();
153 }
154
155 @Test(timeout=30000)
156 public void testExceptionFromCoprocessorWhenCreatingTable()
157 throws IOException {
158 MiniHBaseCluster cluster = UTIL.getHBaseCluster();
159
160 HMaster master = cluster.getMaster();
161 MasterCoprocessorHost host = master.getCoprocessorHost();
162 BuggyMasterObserver cp = (BuggyMasterObserver)host.findCoprocessor(
163 BuggyMasterObserver.class.getName());
164 assertFalse("No table created yet", cp.wasCreateTableCalled());
165
166
167
168 ZooKeeperWatcher zkw = new ZooKeeperWatcher(UTIL.getConfiguration(),
169 "unittest", new Abortable() {
170 @Override
171 public void abort(String why, Throwable e) {
172 throw new RuntimeException("Fatal ZK error: " + why, e);
173 }
174 @Override
175 public boolean isAborted() {
176 return false;
177 }
178 });
179
180 MasterTracker masterTracker = new MasterTracker(zkw,"/hbase/master",
181 new Abortable() {
182 @Override
183 public void abort(String why, Throwable e) {
184 throw new RuntimeException("Fatal ZK master tracker error, why=", e);
185 }
186 @Override
187 public boolean isAborted() {
188 return false;
189 }
190 });
191
192 masterTracker.start();
193 zkw.registerListener(masterTracker);
194
195
196
197
198 assertTrue(master.getLoadedCoprocessors().
199 contains(TestMasterCoprocessorExceptionWithAbort.BuggyMasterObserver.class.getName()));
200
201 CreateTableThread createTableThread = new CreateTableThread(UTIL);
202
203
204
205 createTableThread.start();
206
207
208 for (int i = 0; i < 30; i++) {
209 if (masterTracker.masterZKNodeWasDeleted == true) {
210 break;
211 }
212 try {
213 Thread.sleep(1000);
214 } catch (InterruptedException e) {
215 fail("InterruptedException while waiting for master zk node to "
216 + "be deleted.");
217 }
218 }
219
220 assertTrue("Master aborted on coprocessor exception, as expected.",
221 masterTracker.masterZKNodeWasDeleted);
222
223 createTableThread.interrupt();
224 try {
225 createTableThread.join(1000);
226 } catch (InterruptedException e) {
227 assertTrue("Ignoring InterruptedException while waiting for " +
228 " createTableThread.join().", true);
229 }
230 }
231
232
233 }
234