1 /** 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 package org.apache.hadoop.test; 19 20 import java.io.PrintWriter; 21 import java.io.StringWriter; 22 import java.util.concurrent.BrokenBarrierException; 23 import java.util.concurrent.CyclicBarrier; 24 import java.util.concurrent.locks.Lock; 25 import java.util.concurrent.locks.ReentrantLock; 26 27 import org.junit.Assert; 28 import org.junit.Test; 29 import org.junit.runner.notification.Failure; 30 31 public class TestTimedOutTestsListener { 32 33 public static class Deadlock { 34 private CyclicBarrier barrier = new CyclicBarrier(6); 35 Deadlock()36 public Deadlock() { 37 DeadlockThread[] dThreads = new DeadlockThread[6]; 38 39 Monitor a = new Monitor("a"); 40 Monitor b = new Monitor("b"); 41 Monitor c = new Monitor("c"); 42 dThreads[0] = new DeadlockThread("MThread-1", a, b); 43 dThreads[1] = new DeadlockThread("MThread-2", b, c); 44 dThreads[2] = new DeadlockThread("MThread-3", c, a); 45 46 Lock d = new ReentrantLock(); 47 Lock e = new ReentrantLock(); 48 Lock f = new ReentrantLock(); 49 50 dThreads[3] = new DeadlockThread("SThread-4", d, e); 51 dThreads[4] = new DeadlockThread("SThread-5", e, f); 52 dThreads[5] = new DeadlockThread("SThread-6", f, d); 53 54 // make them daemon threads so that the test will exit 55 for (int i = 0; i < 6; i++) { 56 dThreads[i].setDaemon(true); 57 dThreads[i].start(); 58 } 59 } 60 61 class DeadlockThread extends Thread { 62 private Lock lock1 = null; 63 64 private Lock lock2 = null; 65 66 private Monitor mon1 = null; 67 68 private Monitor mon2 = null; 69 70 private boolean useSync; 71 DeadlockThread(String name, Lock lock1, Lock lock2)72 DeadlockThread(String name, Lock lock1, Lock lock2) { 73 super(name); 74 this.lock1 = lock1; 75 this.lock2 = lock2; 76 this.useSync = true; 77 } 78 DeadlockThread(String name, Monitor mon1, Monitor mon2)79 DeadlockThread(String name, Monitor mon1, Monitor mon2) { 80 super(name); 81 this.mon1 = mon1; 82 this.mon2 = mon2; 83 this.useSync = false; 84 } 85 run()86 public void run() { 87 if (useSync) { 88 syncLock(); 89 } else { 90 monitorLock(); 91 } 92 } 93 syncLock()94 private void syncLock() { 95 lock1.lock(); 96 try { 97 try { 98 barrier.await(); 99 } catch (Exception e) { 100 } 101 goSyncDeadlock(); 102 } finally { 103 lock1.unlock(); 104 } 105 } 106 goSyncDeadlock()107 private void goSyncDeadlock() { 108 try { 109 barrier.await(); 110 } catch (Exception e) { 111 } 112 lock2.lock(); 113 throw new RuntimeException("should not reach here."); 114 } 115 monitorLock()116 private void monitorLock() { 117 synchronized (mon1) { 118 try { 119 barrier.await(); 120 } catch (Exception e) { 121 } 122 goMonitorDeadlock(); 123 } 124 } 125 goMonitorDeadlock()126 private void goMonitorDeadlock() { 127 try { 128 barrier.await(); 129 } catch (Exception e) { 130 } 131 synchronized (mon2) { 132 throw new RuntimeException(getName() + " should not reach here."); 133 } 134 } 135 } 136 137 class Monitor { 138 String name; 139 Monitor(String name)140 Monitor(String name) { 141 this.name = name; 142 } 143 } 144 145 } 146 147 @Test(timeout=500) testThreadDumpAndDeadlocks()148 public void testThreadDumpAndDeadlocks() throws Exception { 149 new Deadlock(); 150 String s = null; 151 while (true) { 152 s = TimedOutTestsListener.buildDeadlockInfo(); 153 if (s != null) 154 break; 155 Thread.sleep(100); 156 } 157 158 Assert.assertEquals(3, countStringOccurrences(s, "BLOCKED")); 159 160 Failure failure = new Failure( 161 null, new Exception(TimedOutTestsListener.TEST_TIMED_OUT_PREFIX)); 162 StringWriter writer = new StringWriter(); 163 new TimedOutTestsListener(new PrintWriter(writer)).testFailure(failure); 164 String out = writer.toString(); 165 166 Assert.assertTrue(out.contains("THREAD DUMP")); 167 Assert.assertTrue(out.contains("DEADLOCKS DETECTED")); 168 169 System.out.println(out); 170 } 171 countStringOccurrences(String s, String substr)172 private int countStringOccurrences(String s, String substr) { 173 int n = 0; 174 int index = 0; 175 while ((index = s.indexOf(substr, index) + 1) != 0) { 176 n++; 177 } 178 return n; 179 } 180 181 } 182