Skip to content

Commit

Permalink
Merge pull request #206 from mattrjacobs/infinite-loop-exception
Browse files Browse the repository at this point in the history
Demonstrates and fixes Issue #205
  • Loading branch information
benjchristensen committed Feb 7, 2014
2 parents 6435c7c + 9dba8c7 commit 55a70d3
Showing 1 changed file with 59 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,13 @@
*/
package com.netflix.hystrix.util;

import org.junit.Test;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

import static org.junit.Assert.assertEquals;

/**
* Used to capture a stacktrace from one thread and append it to the stacktrace of another
Expand All @@ -27,6 +33,8 @@ public class ExceptionThreadingUtility {
private final static String messageForCause = "Calling Thread included as the last 'caused by' on the chain.";

private static void attachCallingThreadStack(Throwable e, StackTraceElement[] stack) {
Set<Throwable> seenCauses = new HashSet<Throwable>();

Throwable callingThrowable = new Throwable(messageForCause);
if (stack[0].toString().startsWith("java.lang.Thread.getStackTrace")) {
// get rid of the first item on the stack that says "java.lang.Thread.getStackTrace"
Expand All @@ -37,6 +45,11 @@ private static void attachCallingThreadStack(Throwable e, StackTraceElement[] st

while (e.getCause() != null) {
e = e.getCause();
if (seenCauses.contains(e)) {
break;
} else {
seenCauses.add(e);
}
}
// check that we're not recursively wrapping an exception that already had the cause set, and if not then add our artificial 'cause'
if (!messageForCause.equals(e.getMessage())) {
Expand Down Expand Up @@ -107,4 +120,50 @@ public static void attachCallingThreadStack(Throwable e) {
public static void assignCallingThread(Thread callingThread) {
callingThreadCache.set(callingThread);
}

public static class UnitTest {
private final Throwable ex1 = new Throwable("Ex1");
private final Throwable ex2 = new Throwable("Ex2", ex1);

public UnitTest() {
ex1.initCause(ex2);
}

@Test
public void testAttachCallingThreadStackParentThenChild() {
ExceptionThreadingUtility.attachCallingThreadStack(ex1, ex2.getStackTrace());
assertEquals("Ex1", ex1.getMessage());
assertEquals("Ex2", ex1.getCause().getMessage());
assertEquals("Ex2", ex2.getMessage());
assertEquals("Ex1", ex2.getCause().getMessage());
}

@Test
public void testAttachCallingThreadStackChildThenParent() {
ExceptionThreadingUtility.attachCallingThreadStack(ex2, ex1.getStackTrace());
assertEquals("Ex1", ex1.getMessage());
assertEquals("Ex2", ex1.getCause().getMessage());
assertEquals("Ex2", ex2.getMessage());
assertEquals("Ex1", ex2.getCause().getMessage());
}

@Test
public void testAttachCallingThreadStackAddExceptionsToEachOther() {
ExceptionThreadingUtility.attachCallingThreadStack(ex1, ex2.getStackTrace());
ExceptionThreadingUtility.attachCallingThreadStack(ex2, ex1.getStackTrace());
assertEquals("Ex1", ex1.getMessage());
assertEquals("Ex2", ex2.getMessage());
assertEquals("Ex2", ex1.getCause().getMessage());
assertEquals("Ex1", ex2.getCause().getMessage());
}

@Test
public void testAttachCallingThreadStackAddExceptionToItself() {
ExceptionThreadingUtility.attachCallingThreadStack(ex2, ex2.getStackTrace());
assertEquals("Ex1", ex1.getMessage());
assertEquals("Ex2", ex1.getCause().getMessage());
assertEquals("Ex2", ex2.getMessage());
assertEquals("Ex1", ex2.getCause().getMessage());
}
}
}

0 comments on commit 55a70d3

Please sign in to comment.