assertj / assertj/assertj-swing

Orphaned event (EventQueue.dummyRunnable) in an eventQueue will break waitForIdle.

Open
#243 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
Java
Stars
121
Forks
52
PR merge metrics
No merged PRs in 30d

Description

I've seen a sporadic failure where waitForIdle gets into a state where it times out after 10 seconds. The application is actually idle when this happens. This causes a lot of grief for us because it makes all the test run at a snails pace (20 minutes instead of 20 seconds).

2 important conditions for this failure:

1) install a custom eventQueue via Toolkit.getDefaultToolkit().getSystemEventQueue().push()
2) create and hide a Window first. (this is a splash screen in our real app).

After a lot of debugging by adding logs to BasicRobot waitForIdle, I manage to catch it where the custom event queue was empty, but it was waiting for a java.awt.EventQueue to drain. It contained an InvocationEvent with this runnable. "runnable=java.awt.EventQueue$1@2d1630f3". Looking into that lead me to the first anonymous class in EventQueue, which is the member variable "dummyRunnable". That dummyRunnable is used in push/pop to wake up the EDT.

I theorized that if the EDT was already awake when the new Queue was pushed, then that event could be left.

That didn't fail initially when I only had 1 window and tried the push from within an InvokeAndWait. I then expanded the test to create a window, hide it, push a new queue and then wait.

That reproduces the failure. Simple test case below. I think that the first queue (for the hidden window?) is really dead? maybe it should be removed from the "windowMonitor.allEventQueues()" in BasicRobot? I got this far, and now I'm at a loss as to how to proceed.

```
package ajs.eq.fail;

import java.awt.EventQueue;
import java.awt.Toolkit;
import java.lang.reflect.InvocationTargetException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import org.assertj.swing.core.BasicRobot;

public class AjsEqFail {

private final static EventQueue myQueue = new EventQueue() {

};
public static void main(String[] args) {
BasicRobot r = (BasicRobot) BasicRobot.robotWithCurrentAwtHierarchy();
r.settings().simpleWaitForIdle(false);
final JFrame f = new JFrame();
f.setBounds(10,10,300,300);
f.setVisible(true);
r.waitForIdle();
System.out.println("waited");
try {
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
System.out.println("Hi3");
}
});
System.out.println("Hi1");
f.setVisible(false);
Toolkit.getDefaultToolkit().getSystemEventQueue().push(myQueue);
JFrame f2 = new JFrame();
f2.setVisible(true);
f2.setBounds(10,10,300,300);
System.out.println("Hi2");
}
});
} catch (InterruptedException ex) {
Logger.getLogger(AjsEqFail.class.getName()).log(Level.SEVERE, null, ex);
} catch (InvocationTargetException ex) {
Logger.getLogger(AjsEqFail.class.getName()).log(Level.SEVERE, null, ex);
}
r.waitForIdle(); //<-------------this times eventually (30 seconds?) but should be immediate.
System.out.println("waited2");
}

}

```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.