You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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:
install a custom eventQueue via Toolkit.getDefaultToolkit().getSystemEventQueue().push()
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");
}
}
The text was updated successfully, but these errors were encountered:
I confirm this is a problem. It seems to be a known problem since CustomEventQueue_Test reproduces it. r.settings().simpleWaitForIdle(true); seems to be the fix. Is it the official fix? What are the drawbacks?
It brings many question. First, in this code:
Collection<EventQueue> queues = windowMonitor.allEventQueues();
if (queues.size() == 1) {
waitForIdle(checkNotNull(toolkit.getSystemEventQueue()));
return;
}
// FIXME this resurrects dead event queuesfor (EventQueuequeue : queues) {
waitForIdle(checkNotNull(queue));
}
Why do we need to look at anything else than the system event queue? Then, assuming this is needed, the problem is indeed, we keep looking at queues that have been pushed down the queue stack. One solution could be to check if the event is EventQueue.dummyRunnable. If this is the case, we are in a dead queue. This is the ugly pseudo-code:
FielddummyRunnableField = EventQueue.class.getDeclaredField("dummyRunnable");
dummyRunnableField.setAccessible(true);
Runnablerunnable = dummyRunnableField.get(null);
do {
// Timed out waiting for idleif (postInvocationEvent(eventQueue, idleTimeout)) {
break;
}
// Timed out waiting for idle event queueif (currentTimeMillis() - start > idleTimeout) {
break;
}
// Force a yieldpause();
// Look if this is a dead queueAWTEventevent = eventQueue.peekEvent();
// Abbot: this does not detect invocation events (i.e. what gets posted with EventQueue.invokeLater), so if// someone is repeatedly posting one, we might get stuck. Not too worried, since if a Runnable keeps calling// invokeLater on itself, *nothing* else gets much chance to run, so it seems to be a bad programming practice.if (event == null) {
break;
}
if (eventinstanceofInvocationEvent && ((InvocationEvent) event).runnable == runnable) {
// remove this queue from the list. It's a dead queue. Or just ignore and get out.
}
} while (true);
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:
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.
The text was updated successfully, but these errors were encountered: