| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.distributedlog; |
| |
| import java.io.PrintWriter; |
| import java.io.StringWriter; |
| import java.util.concurrent.CyclicBarrier; |
| import java.util.concurrent.locks.Lock; |
| import java.util.concurrent.locks.ReentrantLock; |
| |
| import org.junit.Assert; |
| import org.junit.Test; |
| import org.junit.runner.notification.Failure; |
| |
| /** |
| * Test Case for {@link TimedOutTestsListener}. |
| */ |
| public class TestTimedOutTestsListener { |
| |
| private static class Deadlock { |
| private CyclicBarrier barrier = new CyclicBarrier(6); |
| |
| public Deadlock() { |
| DeadlockThread[] dThreads = new DeadlockThread[6]; |
| |
| Monitor a = new Monitor("a"); |
| Monitor b = new Monitor("b"); |
| Monitor c = new Monitor("c"); |
| dThreads[0] = new DeadlockThread("MThread-1", a, b); |
| dThreads[1] = new DeadlockThread("MThread-2", b, c); |
| dThreads[2] = new DeadlockThread("MThread-3", c, a); |
| |
| Lock d = new ReentrantLock(); |
| Lock e = new ReentrantLock(); |
| Lock f = new ReentrantLock(); |
| |
| dThreads[3] = new DeadlockThread("SThread-4", d, e); |
| dThreads[4] = new DeadlockThread("SThread-5", e, f); |
| dThreads[5] = new DeadlockThread("SThread-6", f, d); |
| |
| // make them daemon threads so that the test will exit |
| for (int i = 0; i < 6; i++) { |
| dThreads[i].setDaemon(true); |
| dThreads[i].start(); |
| } |
| } |
| |
| class DeadlockThread extends Thread { |
| private Lock lock1 = null; |
| |
| private Lock lock2 = null; |
| |
| private Monitor mon1 = null; |
| |
| private Monitor mon2 = null; |
| |
| private boolean useSync; |
| |
| DeadlockThread(String name, Lock lock1, Lock lock2) { |
| super(name); |
| this.lock1 = lock1; |
| this.lock2 = lock2; |
| this.useSync = true; |
| } |
| |
| DeadlockThread(String name, Monitor mon1, Monitor mon2) { |
| super(name); |
| this.mon1 = mon1; |
| this.mon2 = mon2; |
| this.useSync = false; |
| } |
| |
| public void run() { |
| if (useSync) { |
| syncLock(); |
| } else { |
| monitorLock(); |
| } |
| } |
| |
| private void syncLock() { |
| lock1.lock(); |
| try { |
| try { |
| barrier.await(); |
| } catch (Exception e) { |
| } |
| goSyncDeadlock(); |
| } finally { |
| lock1.unlock(); |
| } |
| } |
| |
| private void goSyncDeadlock() { |
| try { |
| barrier.await(); |
| } catch (Exception e) { |
| } |
| lock2.lock(); |
| throw new RuntimeException("should not reach here."); |
| } |
| |
| private void monitorLock() { |
| synchronized (mon1) { |
| try { |
| barrier.await(); |
| } catch (Exception e) { |
| } |
| goMonitorDeadlock(); |
| } |
| } |
| |
| private void goMonitorDeadlock() { |
| try { |
| barrier.await(); |
| } catch (Exception e) { |
| } |
| synchronized (mon2) { |
| throw new RuntimeException(getName() + " should not reach here."); |
| } |
| } |
| } |
| |
| class Monitor { |
| String name; |
| |
| Monitor(String name) { |
| this.name = name; |
| } |
| } |
| |
| } |
| |
| @Test(timeout = 500) |
| public void testThreadDumpAndDeadlocks() throws Exception { |
| new Deadlock(); |
| String s = null; |
| while (true) { |
| s = TimedOutTestsListener.buildDeadlockInfo(); |
| if (s != null) { |
| break; |
| } |
| Thread.sleep(100); |
| } |
| |
| Assert.assertEquals(3, countStringOccurrences(s, "BLOCKED")); |
| |
| Failure failure = new Failure(null, new Exception(TimedOutTestsListener.TEST_TIMED_OUT_PREFIX)); |
| StringWriter writer = new StringWriter(); |
| new TimedOutTestsListener(new PrintWriter(writer)).testFailure(failure); |
| String out = writer.toString(); |
| |
| Assert.assertTrue(out.contains("THREAD DUMP")); |
| Assert.assertTrue(out.contains("DEADLOCKS DETECTED")); |
| |
| System.out.println(out); |
| } |
| |
| private int countStringOccurrences(String s, String substr) { |
| int n = 0; |
| int index = 0; |
| while ((index = s.indexOf(substr, index) + 1) != 0) { |
| n++; |
| } |
| return n; |
| } |
| |
| } |