aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/java_tools/junitrunner/java/com/google/testing/junit/runner/internal
diff options
context:
space:
mode:
Diffstat (limited to 'src/java_tools/junitrunner/java/com/google/testing/junit/runner/internal')
-rw-r--r--src/java_tools/junitrunner/java/com/google/testing/junit/runner/internal/BUILD18
-rw-r--r--src/java_tools/junitrunner/java/com/google/testing/junit/runner/internal/Xml.java31
-rw-r--r--src/java_tools/junitrunner/java/com/google/testing/junit/runner/internal/junit4/CancellableRequestFactory.java130
-rw-r--r--src/java_tools/junitrunner/java/com/google/testing/junit/runner/internal/junit4/JUnit4TestNameListener.java55
-rw-r--r--src/java_tools/junitrunner/java/com/google/testing/junit/runner/internal/junit4/JUnit4TestStackTraceListener.java55
-rw-r--r--src/java_tools/junitrunner/java/com/google/testing/junit/runner/internal/junit4/JUnit4TestXmlListener.java120
-rw-r--r--src/java_tools/junitrunner/java/com/google/testing/junit/runner/internal/junit4/SettableCurrentRunningTest.java25
7 files changed, 434 insertions, 0 deletions
diff --git a/src/java_tools/junitrunner/java/com/google/testing/junit/runner/internal/BUILD b/src/java_tools/junitrunner/java/com/google/testing/junit/runner/internal/BUILD
index 7047b3bc08..7e3fa4d644 100644
--- a/src/java_tools/junitrunner/java/com/google/testing/junit/runner/internal/BUILD
+++ b/src/java_tools/junitrunner/java/com/google/testing/junit/runner/internal/BUILD
@@ -1,11 +1,29 @@
package(default_visibility = ["//src:__subpackages__"])
+# Internal code for the JUnit runner that does not depend on JUnit 4.
+# Code used by the JUnit runner that does depend on JUnit 4
+# lives in the ":junit4" rule.
java_library(
name = "internal",
srcs = glob(["*.java"]),
deps = [
"//src/java_tools/junitrunner/java/com/google/testing/junit/runner/util",
"//third_party:jsr330_inject",
+ ],
+)
+
+# Internal code for the JUnit runner that depends on JUnit 4.
+# Code used by the JUnit runner that doesn't depend on JUnit 4
+# lives in the "internal" rule.
+java_library(
+ name = "junit4",
+ srcs = glob(["junit4/*.java"]),
+ deps = [
+ ":internal",
+ "//src/java_tools/junitrunner/java/com/google/testing/junit/junit4:runner",
+ "//src/java_tools/junitrunner/java/com/google/testing/junit/runner/model",
+ "//src/java_tools/junitrunner/java/com/google/testing/junit/runner/util",
+ "//third_party:jsr330_inject",
"//third_party:junit4",
],
)
diff --git a/src/java_tools/junitrunner/java/com/google/testing/junit/runner/internal/Xml.java b/src/java_tools/junitrunner/java/com/google/testing/junit/runner/internal/Xml.java
new file mode 100644
index 0000000000..2734eb1405
--- /dev/null
+++ b/src/java_tools/junitrunner/java/com/google/testing/junit/runner/internal/Xml.java
@@ -0,0 +1,31 @@
+// Copyright 2012 The Bazel Authors. All Rights Reserved.
+//
+// Licensed 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 com.google.testing.junit.runner.internal;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import javax.inject.Qualifier;
+
+/**
+ * Binding annotation that indicates that the given {@code String} or stream
+ * represents XML.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.PARAMETER, ElementType.METHOD})
+@Qualifier
+public @interface Xml {
+}
diff --git a/src/java_tools/junitrunner/java/com/google/testing/junit/runner/internal/junit4/CancellableRequestFactory.java b/src/java_tools/junitrunner/java/com/google/testing/junit/runner/internal/junit4/CancellableRequestFactory.java
new file mode 100644
index 0000000000..74ee5de8df
--- /dev/null
+++ b/src/java_tools/junitrunner/java/com/google/testing/junit/runner/internal/junit4/CancellableRequestFactory.java
@@ -0,0 +1,130 @@
+// Copyright 2012 The Bazel Authors. All Rights Reserved.
+//
+// Licensed 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 com.google.testing.junit.runner.internal.junit4;
+
+import com.google.testing.junit.junit4.runner.MemoizingRequest;
+import com.google.testing.junit.junit4.runner.RunNotifierWrapper;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import org.junit.runner.Description;
+import org.junit.runner.Request;
+import org.junit.runner.Runner;
+import org.junit.runner.notification.RunNotifier;
+import org.junit.runner.notification.StoppedByUserException;
+
+/**
+ * Creates requests that can be cancelled.
+ */
+@Singleton
+public class CancellableRequestFactory {
+ private boolean requestCreated;
+ private volatile ThreadSafeRunNotifier currentNotifier;
+ private volatile boolean cancelRequested = false;
+
+ @Inject
+ public CancellableRequestFactory() {}
+
+ /**
+ * Creates a request that can be cancelled. Can only be called once.
+ *
+ * @param delegate request to wrap
+ */
+ public Request createRequest(Request delegate) {
+ if (requestCreated) {
+ throw new IllegalStateException("a request was already created");
+ }
+ return new MemoizingRequest(delegate) {
+ @Override
+ protected Runner createRunner(Request delegate) {
+ return new CancellableRunner(delegate.getRunner());
+ }
+ };
+ }
+
+ /**
+ * Cancels the request created by this request factory.
+ */
+ public void cancelRun() {
+ cancelRequested = true;
+ RunNotifier notifier = currentNotifier;
+ if (notifier != null) {
+ notifier.pleaseStop();
+ }
+ }
+
+
+ private class CancellableRunner extends Runner {
+ private final Runner delegate;
+
+ public CancellableRunner(Runner delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public Description getDescription() {
+ return delegate.getDescription();
+ }
+
+ @Override
+ public void run(RunNotifier notifier) {
+ currentNotifier = new ThreadSafeRunNotifier(notifier);
+ if (cancelRequested) {
+ currentNotifier.pleaseStop();
+ }
+
+ try {
+ delegate.run(currentNotifier);
+ } catch (StoppedByUserException e) {
+ if (cancelRequested) {
+ throw new RuntimeException("Test run interrupted", e);
+ }
+ throw e;
+ }
+ }
+ }
+
+
+ private static class ThreadSafeRunNotifier extends RunNotifierWrapper {
+ private volatile boolean stopRequested;
+
+ public ThreadSafeRunNotifier(RunNotifier delegate) {
+ super(delegate);
+ }
+
+ /**
+ * {@inheritDoc}<p>
+ *
+ * The implementation is almost an exact copy of the version in
+ * {@code RunNotifier} but is thread-safe.
+ */
+ @Override
+ public void fireTestStarted(Description description) throws StoppedByUserException {
+ if (stopRequested) {
+ throw new StoppedByUserException();
+ }
+ getDelegate().fireTestStarted(description);
+ }
+
+ /**
+ * {@inheritDoc}<p>
+ *
+ * This method is thread-safe.
+ */
+ @Override
+ public void pleaseStop() {
+ stopRequested = true;
+ }
+ }
+}
diff --git a/src/java_tools/junitrunner/java/com/google/testing/junit/runner/internal/junit4/JUnit4TestNameListener.java b/src/java_tools/junitrunner/java/com/google/testing/junit/runner/internal/junit4/JUnit4TestNameListener.java
new file mode 100644
index 0000000000..b2a2e57d58
--- /dev/null
+++ b/src/java_tools/junitrunner/java/com/google/testing/junit/runner/internal/junit4/JUnit4TestNameListener.java
@@ -0,0 +1,55 @@
+// Copyright 2011 The Bazel Authors. All Rights Reserved.
+//
+// Licensed 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 com.google.testing.junit.runner.internal.junit4;
+
+import com.google.testing.junit.runner.util.TestNameProvider;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import org.junit.runner.Description;
+import org.junit.runner.notification.RunListener;
+
+/**
+ * A listener to get the name of a JUnit4 test.
+ */
+@Singleton
+public class JUnit4TestNameListener extends RunListener {
+ private final ThreadLocal<Description> runningTest = new ThreadLocal<>();
+ private final SettableCurrentRunningTest currentRunningTest;
+
+ @Inject
+ public JUnit4TestNameListener(SettableCurrentRunningTest currentRunningTest) {
+ this.currentRunningTest = currentRunningTest;
+ }
+
+ @Override
+ public void testRunStarted(Description description) throws Exception {
+ currentRunningTest.setGlobalTestNameProvider(new TestNameProvider() {
+ @Override
+ public Description get() {
+ return runningTest.get();
+ }
+ });
+ }
+
+ @Override
+ public void testStarted(Description description) throws Exception {
+ runningTest.set(description);
+ }
+
+ @Override
+ public void testFinished(Description description) throws Exception {
+ runningTest.set(null);
+ }
+}
diff --git a/src/java_tools/junitrunner/java/com/google/testing/junit/runner/internal/junit4/JUnit4TestStackTraceListener.java b/src/java_tools/junitrunner/java/com/google/testing/junit/runner/internal/junit4/JUnit4TestStackTraceListener.java
new file mode 100644
index 0000000000..d1ef844b11
--- /dev/null
+++ b/src/java_tools/junitrunner/java/com/google/testing/junit/runner/internal/junit4/JUnit4TestStackTraceListener.java
@@ -0,0 +1,55 @@
+// Copyright 2015 The Bazel Authors. All Rights Reserved.
+//
+// Licensed 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 com.google.testing.junit.runner.internal.junit4;
+
+import com.google.testing.junit.runner.internal.SignalHandlers;
+import com.google.testing.junit.runner.internal.StackTraces;
+import com.google.testing.junit.runner.internal.Stderr;
+import java.io.PrintStream;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import org.junit.runner.Description;
+import org.junit.runner.notification.RunListener;
+import sun.misc.Signal;
+import sun.misc.SignalHandler;
+
+/**
+ * A listener than dumps all stack traces when the test receives a SIGTERM.
+ */
+@Singleton
+public class JUnit4TestStackTraceListener extends RunListener {
+ private final SignalHandlers signalHandlers;
+ private final PrintStream errPrintStream;
+
+ @Inject
+ public JUnit4TestStackTraceListener(
+ SignalHandlers signalHandlers, @Stderr PrintStream errPrintStream) {
+ this.signalHandlers = signalHandlers;
+ this.errPrintStream = errPrintStream;
+ }
+
+ @Override
+ public void testRunStarted(Description description) throws Exception {
+ signalHandlers.installHandler(new Signal("TERM"), new WriteStackTraceSignalHandler());
+ }
+
+ private class WriteStackTraceSignalHandler implements SignalHandler {
+ @Override
+ public void handle(Signal signal) {
+ errPrintStream.println("Dumping stack traces for all threads\n");
+ StackTraces.printAll(errPrintStream);
+ }
+ }
+}
diff --git a/src/java_tools/junitrunner/java/com/google/testing/junit/runner/internal/junit4/JUnit4TestXmlListener.java b/src/java_tools/junitrunner/java/com/google/testing/junit/runner/internal/junit4/JUnit4TestXmlListener.java
new file mode 100644
index 0000000000..6d607256c9
--- /dev/null
+++ b/src/java_tools/junitrunner/java/com/google/testing/junit/runner/internal/junit4/JUnit4TestXmlListener.java
@@ -0,0 +1,120 @@
+// Copyright 2012 The Bazel Authors. All Rights Reserved.
+//
+// Licensed 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 com.google.testing.junit.runner.internal.junit4;
+
+import com.google.testing.junit.runner.internal.SignalHandlers;
+import com.google.testing.junit.runner.internal.Stderr;
+import com.google.testing.junit.runner.internal.Xml;
+import com.google.testing.junit.runner.model.TestSuiteModel;
+import com.google.testing.junit.runner.util.Supplier;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import org.junit.Ignore;
+import org.junit.runner.Description;
+import org.junit.runner.Result;
+import org.junit.runner.notification.Failure;
+import org.junit.runner.notification.RunListener;
+import sun.misc.Signal;
+import sun.misc.SignalHandler;
+
+/**
+ * A listener that writes the test output as XML.
+ */
+@Singleton
+public class JUnit4TestXmlListener extends RunListener {
+ private final Supplier<TestSuiteModel> modelSupplier;
+ private final CancellableRequestFactory requestFactory;
+ private final SignalHandlers signalHandlers;
+ private final OutputStream xmlStream;
+ private final PrintStream errPrintStream;
+ private volatile TestSuiteModel model;
+
+ @Inject
+ public JUnit4TestXmlListener(Supplier<TestSuiteModel> modelSupplier,
+ CancellableRequestFactory requestFactory, SignalHandlers signalHandlers,
+ @Xml OutputStream xmlStream, @Stderr PrintStream errPrintStream) {
+ this.modelSupplier = modelSupplier;
+ this.requestFactory = requestFactory;
+ this.signalHandlers = signalHandlers;
+ this.xmlStream = xmlStream;
+ this.errPrintStream = errPrintStream;
+ }
+
+ @Override
+ public void testRunStarted(Description description) throws Exception {
+ model = modelSupplier.get();
+ signalHandlers.installHandler(new Signal("TERM"), new WriteXmlSignalHandler());
+ }
+
+ @Override
+ public void testStarted(Description description) throws Exception {
+ model.testStarted(description);
+ }
+
+ @Override
+ public void testAssumptionFailure(Failure failure) {
+ model.testSkipped(failure.getDescription());
+ }
+
+ @Override
+ public void testFailure(Failure failure) throws Exception {
+ model.testFailure(failure.getDescription(), failure.getException());
+ }
+
+ @Override
+ public void testIgnored(Description description) throws Exception {
+ // TODO(bazel-team) There's a known issue in the JUnit4 ParentRunner that
+ // fires testIgnored on test suites that are being skipped due to an
+ // assumption failure.
+ if (isSuiteAssumptionFailure(description)) {
+ model.testSkipped(description);
+ } else {
+ model.testSuppressed(description);
+ }
+ }
+
+ private boolean isSuiteAssumptionFailure(Description description) {
+ return description.isSuite() && description.getAnnotation(Ignore.class) == null;
+ }
+
+ @Override
+ public void testFinished(Description description) throws Exception {
+ model.testFinished(description);
+ }
+
+ @Override
+ public void testRunFinished(Result result) throws Exception {
+ model.writeAsXml(xmlStream);
+ }
+
+ private class WriteXmlSignalHandler implements SignalHandler {
+
+ @Override
+ public void handle(Signal signal) {
+ try {
+ errPrintStream.printf("%nReceived %s; writing test XML%n", signal.toString());
+ requestFactory.cancelRun();
+ model.testRunInterrupted();
+ model.writeAsXml(xmlStream);
+ errPrintStream.println("Done writing test XML");
+ } catch (Exception e) {
+ errPrintStream.println("Could not write test XML");
+ e.printStackTrace(errPrintStream);
+ }
+ }
+ }
+}
diff --git a/src/java_tools/junitrunner/java/com/google/testing/junit/runner/internal/junit4/SettableCurrentRunningTest.java b/src/java_tools/junitrunner/java/com/google/testing/junit/runner/internal/junit4/SettableCurrentRunningTest.java
new file mode 100644
index 0000000000..28894ba2e6
--- /dev/null
+++ b/src/java_tools/junitrunner/java/com/google/testing/junit/runner/internal/junit4/SettableCurrentRunningTest.java
@@ -0,0 +1,25 @@
+// Copyright 2015 The Bazel Authors. All Rights Reserved.
+//
+// Licensed 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 com.google.testing.junit.runner.internal.junit4;
+
+import com.google.testing.junit.runner.util.CurrentRunningTest;
+import com.google.testing.junit.runner.util.TestNameProvider;
+
+/**
+ * A {@link CurrentRunningTest} variant that allows to set the testNameProvider via a method call.
+ */
+public abstract class SettableCurrentRunningTest extends CurrentRunningTest {
+ protected abstract void setGlobalTestNameProvider(TestNameProvider provider);
+}