1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase;
19
20 import java.io.File;
21 import java.io.IOException;
22 import java.io.StringWriter;
23 import java.lang.management.ManagementFactory;
24 import java.lang.management.ThreadInfo;
25 import java.lang.management.ThreadMXBean;
26 import java.lang.reflect.InvocationTargetException;
27 import java.util.Arrays;
28 import java.util.Random;
29 import java.util.Set;
30 import java.util.concurrent.CountDownLatch;
31 import java.util.concurrent.TimeoutException;
32 import java.util.concurrent.atomic.AtomicInteger;
33 import java.util.regex.Pattern;
34
35 import org.apache.commons.logging.Log;
36 import org.apache.commons.logging.impl.Log4JLogger;
37 import org.apache.hadoop.fs.FileUtil;
38 import org.apache.hadoop.util.StringUtils;
39 import org.apache.hadoop.util.Time;
40 import org.apache.log4j.Layout;
41 import org.apache.log4j.Logger;
42 import org.apache.log4j.WriterAppender;
43 import org.junit.Assert;
44 import org.mockito.invocation.InvocationOnMock;
45 import org.mockito.stubbing.Answer;
46
47 import com.google.common.base.Joiner;
48 import com.google.common.base.Supplier;
49 import com.google.common.collect.Sets;
50
51
52
53
54 public abstract class GenericTestUtils {
55
56 private static final AtomicInteger sequence = new AtomicInteger();
57
58
59
60
61
62 public static String getMethodName() {
63 return Thread.currentThread().getStackTrace()[2].getMethodName();
64 }
65
66
67
68
69
70 public static int uniqueSequenceId() {
71 return sequence.incrementAndGet();
72 }
73
74
75
76
77 public static void assertExists(File f) {
78 Assert.assertTrue("File " + f + " should exist", f.exists());
79 }
80
81
82
83
84
85
86 public static void assertGlobEquals(File dir, String pattern,
87 String ... expectedMatches) throws IOException {
88
89 Set<String> found = Sets.newTreeSet();
90 for (File f : FileUtil.listFiles(dir)) {
91 if (f.getName().matches(pattern)) {
92 found.add(f.getName());
93 }
94 }
95 Set<String> expectedSet = Sets.newTreeSet(
96 Arrays.asList(expectedMatches));
97 Assert.assertEquals("Bad files matching " + pattern + " in " + dir,
98 Joiner.on(",").join(expectedSet),
99 Joiner.on(",").join(found));
100 }
101
102 public static void assertExceptionContains(String string, Throwable t) {
103 String msg = t.getMessage();
104 Assert.assertTrue(
105 "Expected to find '" + string + "' but got unexpected exception:"
106 + StringUtils.stringifyException(t), msg.contains(string));
107 }
108
109 public static void waitFor(Supplier<Boolean> check,
110 int checkEveryMillis, int waitForMillis)
111 throws TimeoutException, InterruptedException
112 {
113 long st = Time.now();
114 do {
115 boolean result = check.get();
116 if (result) {
117 return;
118 }
119
120 Thread.sleep(checkEveryMillis);
121 } while (Time.now() - st < waitForMillis);
122
123 throw new TimeoutException("Timed out waiting for condition. " +
124 "Thread diagnostics:\n" +
125 TimedOutTestsListener.buildThreadDiagnosticString());
126 }
127
128 public static class LogCapturer {
129 private StringWriter sw = new StringWriter();
130 private WriterAppender appender;
131 private Logger logger;
132
133 public static LogCapturer captureLogs(Log l) {
134 Logger logger = ((Log4JLogger)l).getLogger();
135 LogCapturer c = new LogCapturer(logger);
136 return c;
137 }
138
139
140 private LogCapturer(Logger logger) {
141 this.logger = logger;
142 Layout layout = Logger.getRootLogger().getAppender("stdout").getLayout();
143 WriterAppender wa = new WriterAppender(layout, sw);
144 logger.addAppender(wa);
145 }
146
147 public String getOutput() {
148 return sw.toString();
149 }
150
151 public void stopCapturing() {
152 logger.removeAppender(appender);
153
154 }
155 }
156
157
158
159
160
161
162 public static class DelayAnswer implements Answer<Object> {
163 private final Log LOG;
164
165 private final CountDownLatch fireLatch = new CountDownLatch(1);
166 private final CountDownLatch waitLatch = new CountDownLatch(1);
167 private final CountDownLatch resultLatch = new CountDownLatch(1);
168
169 private final AtomicInteger fireCounter = new AtomicInteger(0);
170 private final AtomicInteger resultCounter = new AtomicInteger(0);
171
172
173 private volatile Throwable thrown;
174 private volatile Object returnValue;
175
176 public DelayAnswer(Log log) {
177 this.LOG = log;
178 }
179
180
181
182
183 public void waitForCall() throws InterruptedException {
184 fireLatch.await();
185 }
186
187
188
189
190
191 public void proceed() {
192 waitLatch.countDown();
193 }
194
195 @Override
196 public Object answer(InvocationOnMock invocation) throws Throwable {
197 LOG.info("DelayAnswer firing fireLatch");
198 fireCounter.getAndIncrement();
199 fireLatch.countDown();
200 try {
201 LOG.info("DelayAnswer waiting on waitLatch");
202 waitLatch.await();
203 LOG.info("DelayAnswer delay complete");
204 } catch (InterruptedException ie) {
205 throw new IOException("Interrupted waiting on latch", ie);
206 }
207 return passThrough(invocation);
208 }
209
210 protected Object passThrough(InvocationOnMock invocation) throws Throwable {
211 try {
212 Object ret = invocation.callRealMethod();
213 returnValue = ret;
214 return ret;
215 } catch (Throwable t) {
216 thrown = t;
217 throw t;
218 } finally {
219 resultCounter.incrementAndGet();
220 resultLatch.countDown();
221 }
222 }
223
224
225
226
227
228 public void waitForResult() throws InterruptedException {
229 resultLatch.await();
230 }
231
232
233
234
235
236 public Throwable getThrown() {
237 return thrown;
238 }
239
240
241
242
243
244 public Object getReturnValue() {
245 return returnValue;
246 }
247
248 public int getFireCount() {
249 return fireCounter.get();
250 }
251
252 public int getResultCount() {
253 return resultCounter.get();
254 }
255 }
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271 public static class DelegateAnswer implements Answer<Object> {
272 private final Object delegate;
273 private final Log log;
274
275 public DelegateAnswer(Object delegate) {
276 this(null, delegate);
277 }
278
279 public DelegateAnswer(Log log, Object delegate) {
280 this.log = log;
281 this.delegate = delegate;
282 }
283
284 @Override
285 public Object answer(InvocationOnMock invocation) throws Throwable {
286 try {
287 if (log != null) {
288 log.info("Call to " + invocation + " on " + delegate,
289 new Exception("TRACE"));
290 }
291 return invocation.getMethod().invoke(
292 delegate, invocation.getArguments());
293 } catch (InvocationTargetException ite) {
294 throw ite.getCause();
295 }
296 }
297 }
298
299
300
301
302
303
304
305 public static class SleepAnswer implements Answer<Object> {
306 private final int maxSleepTime;
307 private static Random r = new Random();
308
309 public SleepAnswer(int maxSleepTime) {
310 this.maxSleepTime = maxSleepTime;
311 }
312
313 @Override
314 public Object answer(InvocationOnMock invocation) throws Throwable {
315 boolean interrupted = false;
316 try {
317 Thread.sleep(r.nextInt(maxSleepTime));
318 } catch (InterruptedException ie) {
319 interrupted = true;
320 }
321 try {
322 return invocation.callRealMethod();
323 } finally {
324 if (interrupted) {
325 Thread.currentThread().interrupt();
326 }
327 }
328 }
329 }
330
331 public static void assertMatches(String output, String pattern) {
332 Assert.assertTrue("Expected output to match /" + pattern + "/" +
333 " but got:\n" + output,
334 Pattern.compile(pattern).matcher(output).find());
335 }
336
337 public static void assertValueNear(long expected, long actual, long allowedError) {
338 assertValueWithinRange(expected - allowedError, expected + allowedError, actual);
339 }
340
341 public static void assertValueWithinRange(long expectedMin, long expectedMax,
342 long actual) {
343 Assert.assertTrue("Expected " + actual + " to be in range (" + expectedMin + ","
344 + expectedMax + ")", expectedMin <= actual && actual <= expectedMax);
345 }
346
347
348
349
350
351
352 public static void assertNoThreadsMatching(String regex) {
353 Pattern pattern = Pattern.compile(regex);
354 ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
355
356 ThreadInfo[] infos = threadBean.getThreadInfo(threadBean.getAllThreadIds(), 20);
357 for (ThreadInfo info : infos) {
358 if (info == null) continue;
359 if (pattern.matcher(info.getThreadName()).matches()) {
360 Assert.fail("Leaked thread: " + info + "\n" +
361 Joiner.on("\n").join(info.getStackTrace()));
362 }
363 }
364 }
365 }