001: package org.junit.internal.runners;
002:
003: import java.lang.reflect.InvocationTargetException;
004: import java.lang.reflect.Method;
005: import java.util.List;
006: import java.util.concurrent.Callable;
007: import java.util.concurrent.ExecutorService;
008: import java.util.concurrent.Executors;
009: import java.util.concurrent.Future;
010: import java.util.concurrent.TimeUnit;
011: import java.util.concurrent.TimeoutException;
012:
013: import org.junit.Assume.AssumptionViolatedException;
014: import org.junit.runner.Description;
015: import org.junit.runner.notification.Failure;
016: import org.junit.runner.notification.RunNotifier;
017:
018: public class MethodRoadie {
019: private final Object fTest;
020: private final RunNotifier fNotifier;
021: private final Description fDescription;
022: private TestMethod fTestMethod;
023:
024: public MethodRoadie(Object test, TestMethod method,
025: RunNotifier notifier, Description description) {
026: fTest = test;
027: fNotifier = notifier;
028: fDescription = description;
029: fTestMethod = method;
030: }
031:
032: public void run() {
033: if (fTestMethod.isIgnored()) {
034: fNotifier.fireTestIgnored(fDescription);
035: return;
036: }
037: fNotifier.fireTestStarted(fDescription);
038: try {
039: long timeout = fTestMethod.getTimeout();
040: if (timeout > 0)
041: runWithTimeout(timeout);
042: else
043: runTest();
044: } finally {
045: fNotifier.fireTestFinished(fDescription);
046: }
047: }
048:
049: private void runWithTimeout(final long timeout) {
050: runBeforesThenTestThenAfters(new Runnable() {
051:
052: public void run() {
053: ExecutorService service = Executors
054: .newSingleThreadExecutor();
055: Callable<Object> callable = new Callable<Object>() {
056: public Object call() throws Exception {
057: runTestMethod();
058: return null;
059: }
060: };
061: Future<Object> result = service.submit(callable);
062: service.shutdown();
063: try {
064: boolean terminated = service.awaitTermination(
065: timeout, TimeUnit.MILLISECONDS);
066: if (!terminated)
067: service.shutdownNow();
068: result.get(0, TimeUnit.MILLISECONDS); // throws the exception if one occurred during the invocation
069: } catch (TimeoutException e) {
070: addFailure(new Exception(String.format(
071: "test timed out after %d milliseconds",
072: timeout)));
073: } catch (Exception e) {
074: addFailure(e);
075: }
076: }
077: });
078: }
079:
080: public void runTest() {
081: runBeforesThenTestThenAfters(new Runnable() {
082: public void run() {
083: runTestMethod();
084: }
085: });
086: }
087:
088: public void runBeforesThenTestThenAfters(Runnable test) {
089: try {
090: runBefores();
091: test.run();
092: } catch (FailedBefore e) {
093: } catch (Exception e) {
094: throw new RuntimeException(
095: "test should never throw an exception to this level");
096: } finally {
097: runAfters();
098: }
099: }
100:
101: protected void runTestMethod() {
102: try {
103: fTestMethod.invoke(fTest);
104: if (fTestMethod.expectsException())
105: addFailure(new AssertionError("Expected exception: "
106: + fTestMethod.getExpectedException().getName()));
107: } catch (InvocationTargetException e) {
108: Throwable actual = e.getTargetException();
109: if (actual instanceof AssumptionViolatedException)
110: return;
111: else if (!fTestMethod.expectsException())
112: addFailure(actual);
113: else if (fTestMethod.isUnexpected(actual)) {
114: String message = "Unexpected exception, expected<"
115: + fTestMethod.getExpectedException().getName()
116: + "> but was<" + actual.getClass().getName()
117: + ">";
118: addFailure(new Exception(message, actual));
119: }
120: } catch (Throwable e) {
121: addFailure(e);
122: }
123: }
124:
125: private void runBefores() throws FailedBefore {
126: try {
127: try {
128: List<Method> befores = fTestMethod.getBefores();
129: for (Method before : befores)
130: before.invoke(fTest);
131: } catch (InvocationTargetException e) {
132: throw e.getTargetException();
133: }
134: } catch (AssumptionViolatedException e) {
135: throw new FailedBefore();
136: } catch (Throwable e) {
137: addFailure(e);
138: throw new FailedBefore();
139: }
140: }
141:
142: private void runAfters() {
143: List<Method> afters = fTestMethod.getAfters();
144: for (Method after : afters)
145: try {
146: after.invoke(fTest);
147: } catch (InvocationTargetException e) {
148: addFailure(e.getTargetException());
149: } catch (Throwable e) {
150: addFailure(e); // Untested, but seems impossible
151: }
152: }
153:
154: protected void addFailure(Throwable e) {
155: fNotifier.fireTestFailure(new Failure(fDescription, e));
156: }
157: }
|