Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

java.util.concurrent.TimeoutException on all tests #121

Closed
aalmiray opened this issue Jul 18, 2014 · 8 comments · Fixed by #126
Closed

java.util.concurrent.TimeoutException on all tests #121

aalmiray opened this issue Jul 18, 2014 · 8 comments · Fixed by #126

Comments

@aalmiray
Copy link
Contributor

I consistently get java.util.concurrent.TimeoutException when running any tests on my environment :-(

Fork is at 308a2fe

Environment is

------------------------------------------------------------
Gradle 2.0
------------------------------------------------------------

Build time:   2014-07-01 07:45:34 UTC
Build number: none
Revision:     b6ead6fa452dfdadec484059191eb641d817226c

Groovy:       2.3.3
Ant:          Apache Ant(TM) version 1.9.3 compiled on December 23 2013
JVM:          1.7.0_65 (Oracle Corporation 24.65-b04)
OS:           Mac OS X 10.9.3 x86_64

Full stack trace is

java.util.concurrent.TimeoutException: Timeout waiting for task.
    at com.google.common.util.concurrent.AbstractFuture$Sync.get(AbstractFuture.java:276)
    at com.google.common.util.concurrent.AbstractFuture.get(AbstractFuture.java:96)
    at org.loadui.testfx.framework.app.impl.AppSetupImpl.waitForPrimaryStage(AppSetupImpl.java:178)
    at org.loadui.testfx.framework.app.impl.AppSetupImpl.getPrimaryStage(AppSetupImpl.java:142)
    at org.loadui.testfx.framework.junit.AppRobotTestBase.setupApplication(AppRobotTestBase.java:55)
    at org.loadui.testfx.GuiTest.setupGuiTest(GuiTest.java:175)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.runTestClass(JUnitTestClassExecuter.java:86)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.execute(JUnitTestClassExecuter.java:49)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassProcessor.processTestClass(JUnitTestClassProcessor.java:69)
    at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:48)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    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:105)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    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:355)
    at org.gradle.internal.concurrent.DefaultExecutorFactory$StoppableExecutorImpl$1.run(DefaultExecutorFactory.java:64)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:745)
@hastebrot
Copy link
Member

Hi Andres!

This issue is related to #64. I also heard Automaton has or had the same issue.

We need to initialize the JavaFX Toolkit and retrieve the primary Stage. To do this we launch a custom Application. In its setup(Stage) we use the Stage parameter and put it into a SettableFuture from Google Guava.

Somehow this does not work under Mac OS X. Unfortunately I have no Apple machine and cannot debug this.

@hastebrot
Copy link
Member

Here is a SSCCE for this bug. Works fine on Windows 7 with Java 7 and Guava 14 for me. Maybe Thread.start() and Application.launch() don not work together on OS X. Parameters we could change are ThreadGroup and AccessControlContext in new Thread().

package org.testfx;

import java.util.concurrent.TimeUnit;
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.stage.StageStyle;

import com.google.common.util.concurrent.SettableFuture;

public class PrimaryStageRetriever {

    public static SettableFuture<Stage> primaryStageFuture = SettableFuture.create();

    public static class ToolkitApplication extends Application {
        @Override
        public void start(Stage primaryStage) throws Exception {
            primaryStage.initStyle(StageStyle.UNDECORATED);
            primaryStageFuture.set(primaryStage);
        }
    }

    public static void main(String[] args) throws Exception {
        System.out.println("Launching Application in new Thread...");
        new Thread(new Runnable() {
            @Override
            public void run() {
                Application.launch(ToolkitApplication.class);
            }
        }).start();
        System.out.println("Waiting for primary Stage...");
        Stage stage = primaryStageFuture.get(10, TimeUnit.SECONDS);
        System.out.println(stage);

        // OUTPUT:
        // Launching Application in new Thread...
        // Waiting for primary Stage...
        // javafx.stage.Stage@5a07e868
    }

}

@hastebrot
Copy link
Member

I finally got my hands on a OSX machine and could reproduce the exception under JDK 1.7. It worked fine under JDK 1.8.

Interestingly the SSCCE worked fine under JDK 1.7 and 1.8.

/Library/Java/JavaVirtualMachines/jdk1.7.0_60.jdk/Contents/Home/bin/java -Dprism.order=j2d ...
Launching Application in new Thread...
Waiting for primary Stage...
javafx.stage.Stage@3c8e683a

@aalmiray
Copy link
Contributor Author

I've found out that JDK 7u60, 7u65, 8u05, 8u11 behave differently when JavaFX is involved. Apprently 7u60 and 8u05 are more stable than the newer versions.

@hastebrot
Copy link
Member

I've identified the cause. Just comment or uncomment the line createAwtRobot(); and run PrimaryStageRetriever#main() to toggle the error.

In GuiTest the java.awt.Robot is instantiated before Application.launch() is called. This instantiation causes the issue.

package org.testfx;

import java.awt.Robot;
import java.util.concurrent.TimeUnit;
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.stage.StageStyle;

import com.google.common.util.concurrent.SettableFuture;

public class PrimaryStageRetriever {

    public static void main(String[] args) throws Exception {
        createAwtRobot();
        System.out.println("Launching Application in new Thread...");
        launchApplicationInThread();
        System.out.println("Waiting for primary Stage...");
        Stage stage = retrievePrimaryStage();
        System.out.println(stage);
    }

    public static Robot createAwtRobot() {
        try {
            return new Robot();
        }
        catch (Exception exception) {
            exception.printStackTrace();
            return null;
        }
    }

    public static void launchApplicationInThread() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                Application.launch(ToolkitApplication.class);
            }
        }).start();
    }

    public static Stage retrievePrimaryStage() throws Exception {
        return primaryStageFuture.get(10, TimeUnit.SECONDS);
    }

    public static SettableFuture<Stage> primaryStageFuture = SettableFuture.create();

    public static class ToolkitApplication extends Application {
        @Override
        public void start(Stage primaryStage) throws Exception {
            primaryStage.initStyle(StageStyle.UNDECORATED);
            primaryStageFuture.set(primaryStage);
        }
    }

}

@hastebrot
Copy link
Member

Weird.

If I instanciate java.awt.Robot before Application.launch() then the launch will fail. In the opposite order it will throw java.awt.AWTException: headless environment. However we can get rid of the AWTException by setting the system property java.awt.headless to false [1] [2].

If I instanciate com.sun.glass.ui.Robot before Application.launch() it will throw an exception. In the opposite order it will return the Robot.

System.setProperty("java.awt.headless", "false");
java.awt.Robot robot = createAwtRobot();
System.out.println(robot);
com.sun.glass.ui.Robot robot = com.sun.glass.ui.Application.GetApplication().createRobot();
System.out.println(robot);

Also MouseInfo, GraphicsEnvironment and Robot#createScreenCapture work fine, which seemed to be an issue (renatoathaydes/Automaton#19).

MouseInfo.getPointerInfo().getLocation();
GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices();
robot.createScreenCapture(new Rectangle(0, 0, 100, 100));

[1] http://stackoverflow.com/questions/13487025/headless-environment-error-in-java-awt-robot-class-with-mac-os
[2] http://stackoverflow.com/questions/15320915/javafx-screencapture-headless-exception-on-osx

@hastebrot
Copy link
Member

There was a lenghty discussion on https://javafx-jira.kenai.com/browse/RT-20784. It seems that the only valid option is to move to Java 1.8.

"We don't have plans to back port these specific changes to 7uX releases because they are somewhat risky, and we don't want to destabilize the 7uX branch."

@hastebrot
Copy link
Member

I had some issues with MouseInfo and Platform.runLater() when I created the java.awt.Robot lazily, i.e. after the Application.launch(). Setting the system property "javafx.macosx.embedded" to "true" seems to fix this issue on OSX (tested with JDK 1.7.0_60 and 1.8.0_05 on OSX 10.8 with -Dprism.order=j2d), although some errors with QuantumRenderer might occur in a different thread.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants