Gradle-2.3: stdout/stderr redirection in test-code causes NPE in Gradle's TestOutputRedirector

One of our projects’ unit tests is failing with Gradle-2.3 on Jenkins. The stacktrace looks like a Gradle Bug:

org.gradle.api.internal.tasks.testing.TestSuiteExecutionException: Could not execute test class 'com.myproject.MyTest'.
 at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:52)
 at sun.reflect.GeneratedMethodAccessor7.invoke(Unknown Source)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
 at java.lang.reflect.Method.invoke(Method.java:597)
 at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
 at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
 at org.gradle.messaging.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
 at org.gradle.messaging.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
 at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
 at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:106)
 at sun.reflect.GeneratedMethodAccessor6.invoke(Unknown Source)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
 at java.lang.reflect.Method.invoke(Method.java:597)
 at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
 at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
 at org.gradle.messaging.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:360)
 at org.gradle.internal.concurrent.DefaultExecutorFactory$StoppableExecutorImpl$1.run(DefaultExecutorFactory.java:64)
 at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
 at java.lang.Thread.run(Thread.java:662)
Caused by: java.lang.NullPointerException
 at org.gradle.api.internal.tasks.testing.processors.TestOutputRedirector.setOutputOwner(TestOutputRedirector.java:51)
 at org.gradle.api.internal.tasks.testing.processors.CaptureTestOutputTestResultProcessor.started(CaptureTestOutputTestResultProcessor.java:51)
 at org.gradle.api.internal.tasks.testing.results.AttachParentTestResultProcessor.started(AttachParentTestResultProcessor.java:37)
 at org.gradle.api.internal.tasks.testing.results.AttachParentTestResultProcessor.started(AttachParentTestResultProcessor.java:37)
 at org.gradle.api.internal.tasks.testing.junit.TestClassExecutionEventGenerator.testClassFinished(TestClassExecutionEventGenerator.java:53)
 at sun.reflect.GeneratedMethodAccessor9.invoke(Unknown Source)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
 at java.lang.reflect.Method.invoke(Method.java:597)
 at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
 at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
 at org.gradle.messaging.actor.internal.DefaultActorFactory$BlockingActor.dispatch(DefaultActorFactory.java:126)
 at org.gradle.messaging.actor.internal.DefaultActorFactory$BlockingActor.dispatch(DefaultActorFactory.java:101)
 at org.gradle.messaging.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
 at com.sun.proxy.$Proxy4.testClassFinished(Unknown Source)
 at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.execute(JUnitTestClassExecuter.java:54)
 at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassProcessor.processTestClass(JUnitTestClassProcessor.java:64)
 at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:50)
 ... 19 more

As a hint, here’s what our (granted, pretty evil) test does:

outContent = new ByteArrayOutputStream();
        errContent = new ByteArrayOutputStream();
          System.setOut(new PrintStream(outContent));
        System.setErr(new PrintStream(errContent));

Are you setting the streams back after the test?

PrintStream sysOut = System.out;
PrintStream sysErr = System.err;
OutputStream outContent = new ByteArrayOutputStream();
OutputStream errContent = new ByteArrayOutputStream();
System.setOut(new PrintStream(outContent));
System.setErr(new PrintStream(errContent));
try {
   doStuff();
finally {
   System.out = sysOut;
   System.err = sysErr;
}

Looking through the test: nope:

System.setOut(null);
        System.setErr(null);

Did I mention the test is evil? :wink:

Still, it might be worth adding a check to avoid the NPE in Gradle as before…

I’m guessing System.out.println(…) would also throw NPE after the nulls are set. I don’t feel it’s gradle’s job to null test System.out/System.err and I feel it’s perfectly valid to assume these are non null. You should really fix the evil test.

I agree, and we will, it’s just that since this worked before Gradle-2.3 one might consider this a regression.

I’ve patched this for 2.4.