Showing posts with label abbot. Show all posts
Showing posts with label abbot. Show all posts

Thursday, June 6, 2013

Problems running lots of X11 sessions concurrently when testing under Hudson/Jenkins

So we are running a quite a bit of automated UI testing and we have found over a large number of concurrent test nodes that even when the Xvnc plugin has correctly started that the environment is not always ready or reliable. This blog post looks at two changes we made that have improved our test stability in recent times.

The first and most important thing to settle when using the Xvnc plugin is to make sure that the user that is running the tests has a normal window manager. By default the default VNC server will start using "twm" as defined in the .vnc/xstartup file. This has significant behavioural differences from the more standard Gnome / KDE and indeed the window managers on Windows and a Mac. Rather than deal with this we have standardised on running with Gnome.

The problem is though is that in our experience if you have multiple gnome sessions starting at the same time that sometimes they will fail with odd error messages. My esteemed colleague Mark Warner came up with the following xstartup script which just puts a simple lock around the startup code.

#!/bin/bash
# It uses a lockfile in the user's .vnc directory to ensure that
# only one instance of gnome will start up for the given user
# at once. This should work around problems associated with
# multiple gnome instances starting and failing to lock certain
# files. It will start gnome after 5 mins of failing to lock as
# a fail safe so a gnome startup will always be attempted.
#

LOCK_FILE=${HOME}/.vnc/xstartup.lock
SESSION_VNC_NAME=VNC-`hostname -f`
LOCKED=0

function clean_up {
  # don't delete the lock file if we didn't create it
  if [ $LOCKED -eq 1 ]; then
    echo "$(date) All finished, deleting lock file."
    rm -f $LOCK_FILE
  fi
}

# make sure that we delete the lock file if we get killed
trap clean_up SIGHUP SIGINT SIGTERM

# retry for 5 mins then assume something died and delete
# the existing lockfile taking control of it for ourselves.
echo "$(date) Attempting to obtain startup lock."
if lockfile -l 300 $LOCK_FILE; then
  echo "$(date) Startup lock aquired."
  LOCKED=1
else
  echo "$(date) Lock failed... starting anyway."
fi

# give X a little breather before we start gnome
sleep 10 

# Start Gnome
gnome-session &

# just let gnome settle before we relinquish the lock
sleep 20
clean_up

Now this resolved spurious test failures that were due to a missing window manager, but as recently the number of nodes increased we found that we were still seeing troubling intermittent failures that took the form of failures to connect to the window server for no obvious reason.

This would happen even if previously in the job we had displayed a window successfully.

[exec] java.lang.InternalError: Can't connect to X11 window server using ':58' as the value of the DISPLAY variable.
     [exec]  at sun.awt.X11GraphicsEnvironment.initDisplay(Native Method)
     [exec]  at sun.awt.X11GraphicsEnvironment.access$200(X11GraphicsEnvironment.java:65)
     [exec]  at sun.awt.X11GraphicsEnvironment$1.run(X11GraphicsEnvironment.java:110)
     [exec]  at java.security.AccessController.doPrivileged(Native Method)
     [exec]  at sun.awt.X11GraphicsEnvironment.(X11GraphicsEnvironment.java:74)
     [exec]  at java.lang.Class.forName0(Native Method)
     [exec]  at java.lang.Class.forName(Class.java:186)
     [exec]  at java.awt.GraphicsEnvironment.createGE(GraphicsEnvironment.java:102)
     [exec]  at java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment(GraphicsEnvironment.java:81)
     [exec]  at org.netbeans.core.startup.Main.start(Main.java:253)
     [exec]  at org.netbeans.core.startup.TopThreadGroup.run(TopThreadGroup.java:123)
     [exec]  at java.lang.Thread.run(Thread.java:722)
     [exec] Result: 2

This would also happen right at the start when gnome was being set up, as shown here by looking at the content of the logs under .vnc .

_XSERVTransmkdir: Owner of /tmp/.X11-unix should be set to root

Xvnc Free Edition 4.1.2
Copyright (C) 2002-2005 RealVNC Ltd.
See http://www.realvnc.com for information on VNC.
Underlying X server release 70101000, The X.Org Foundation


Thu May 30 03:51:34 2013
 vncext:      VNC extension running!
 vncext:      Listening for VNC connections on port 5974
 vncext:      Listening for HTTP connections on port 5874
 vncext:      created VNC server for screen 0
Thu May 30 03:51:37 BST 2013 Attempting to obtain startup lock.
Thu May 30 03:53:45 BST 2013 Startup lock aquired.
Start gnome for OL4 or OL5
AUDIT: Thu May 30 03:53:56 2013: 10280 Xvnc: client 1 rejected from local host
Xlib: connection to ":74.0" refused by server
Xlib: No protocol specified


(gnome-session:10543): Gtk-WARNING **: cannot open display:  
Thu May 30 03:54:15 BST 2013 All finished, deleting lock file.
AUDIT: Thu May 30 04:14:03 2013: 10280 Xvnc: client 1 rejected from local host
AUDIT: Thu May 30 04:14:22 2013: 10280 Xvnc: client 1 rejected from local host
FreeFontPath: FPE "unix/:7100" refcount is 2, should be 1; fixing.

After a little bit of playing around suspicion fell to the .Xauthority file we we knew could cause error messages like this and could become corrupted. Removing /zeroing the file didn't help so like the Gnome problems some kind of concurrency / contention issues was suspected.

After a bit of playing about we decided that for our test user it was going to be best to just have a copy of this file per host. This works for us as we only have the single executor per machine in order to get consistent testing results. In our case we just added the following line in our .bashrc for the NIS user we run our tests as and restarted all our of slave nodes.

# make sure we don't share the Xauthority file between hosts

export XAUTHORITY=~/.Xauthority.`hostname -f`

Since we have made this change we have seen no failures of the above type after nearly week, that of course doesn't rule out that we have just reduced the occurrence of the issue to a reasonably small level; but we are happy that we can run tests again. Of course the moment I post this blog I am going to loose that lovely run of blue balls. :-)



Friday, February 22, 2013

A little temporal feedback when running tests

I have been working a lot recently with a bunch of test jobs that are intermittently getting stuck. Now it is possible to work out the point where the problem is occurring by looking at the date labels on the LOG output; but it is hard visually to pick these discontinuities out.

In order improve the output in a way that my brain can really quickly parse and identify I thought I would try my hand a bit of simple ASCII animation. I wrote a simple fixture that writes out a line every 1 minute while the test is running, here is a very simple implementation - I am sure there are better ways to do the animation!

import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;

public class TickTockFixture
{
   private Timer timer;
   

   @Before
   public void setUp()
   {
      // Clean out any old timers
      tearDown();
      
      // Start a new timer
      
      timer = new Timer();
      timer.scheduleAtFixedRate(new TimerTask()
      {
         int counter = 0;
         
         @Override
         public void run()
         {
            StringBuilder sb = new StringBuilder(". TickTock : ");
            int animation = counter++ % 10;
            boolean direction = animation < 5;
            int count = direction ?  animation : 9 - animation;
            sb.append("     ", 0, count);
            sb.append(direction ? "/" : "\\");
            sb.append("     ",0, 5-count);
            sb.append(counter);
            sb.append(" min(s)");
            System.err.println(sb);
         }
      }, 0, TimeUnit.MINUTES.toMillis(1));
      
   }

   @After
   public void tearDown()
   {
      if (timer!=null)
      {
         timer.cancel();
         timer = null;
      }
   }
}

So does this help, well take a look at the - made up example - output below and try to spot the section of the log output where everything slows down. It is a lot easier with the ticking output which I think sticks out better because of the animation.
22-Feb-2013 11:54:30 Items in drs, going to tidy up
22-Feb-2013 11:54:40 Removing file:/scratch/gdavison/view_storage/gdavison_lt/oracle/jdeveloper/system12.1.2.0.40.65.92/o.j2ee/drs/Application1/Project1WebApp.war/WEB-INF/weblogic.xml
22-Feb-2013 11:54:40 Removing file:/scratch/gdavison/view_storage/gdavison_lt/oracle/jdeveloper/system12.1.2.0.40.65.92/o.j2ee/drs/Application1/Project1WebApp.war/WEB-INF/web.xml
22-Feb-2013 11:54:40 Removing file:/scratch/gdavison/view_storage/gdavison_lt/oracle/jdeveloper/system12.1.2.0.40.65.92/o.j2ee/drs/Application1/Project1WebApp.war/WEB-INF/classes/project1/Hello.class
22-Feb-2013 11:54:40 Removing file:/scratch/gdavison/view_storage/gdavison_lt/oracle/jdeveloper/system12.1.2.0.40.65.92/o.j2ee/drs/Application1/Project1WebApp.war/WEB-INF/classes/project1/
22-Feb-2013 11:54:40 Removing file:/scratch/gdavison/view_storage/gdavison_lt/oracle/jdeveloper/system12.1.2.0.40.65.92/o.j2ee/drs/Application1/Project1WebApp.war/WEB-INF/classes/
22-Feb-2013 11:54:40 Removing file:/scratch/gdavison/view_storage/gdavison_lt/oracle/jdeveloper/system12.1.2.0.40.65.92/o.j2ee/drs/Application1/Project1WebApp.war/WEB-INF/
22-Feb-2013 11:54:40 Removing file:/scratch/gdavison/view_storage/gdavison_lt/oracle/jdeveloper/system12.1.2.0.40.65.92/o.j2ee/drs/Application1/Project1WebApp.war/
22-Feb-2013 11:54:40 Removing file:/scratch/gdavison/view_storage/gdavison_lt/oracle/jdeveloper/system12.1.2.0.40.65.92/o.j2ee/drs/Application1/.module_marker
22-Feb-2013 11:54:40 Removing file:/scratch/gdavison/view_storage/gdavison_lt/oracle/jdeveloper/system12.1.2.0.40.65.92/o.j2ee/drs/Application1/META-INF/weblogic-application.xml
22-Feb-2013 11:54:40 Removing file:/scratch/gdavison/view_storage/gdavison_lt/oracle/jdeveloper/system12.1.2.0.40.65.92/o.j2ee/drs/Application1/META-INF/application.xml
22-Feb-2013 11:54:40 Removing file:/scratch/gdavison/view_storage/gdavison_lt/oracle/jdeveloper/system12.1.2.0.40.65.92/o.j2ee/drs/Application1/META-INF/
22-Feb-2013 11:54:40 Removing file:/scratch/gdavison/view_storage/gdavison_lt/oracle/jdeveloper/system12.1.2.0.40.65.92/o.j2ee/drs/Application1/.adrs-module.properties
22-Feb-2013 11:54:40 Removing file:/scratch/gdavison/view_storage/gdavison_lt/oracle/jdeveloper/system12.1.2.0.40.65.92/o.j2ee/drs/Application1/
22-Feb-2013 11:54:53 oracle.jdevimpl.webservices.tcpmonitor.config.AnalyzerInstance stop
WARNING: AnalyzerInstance aborting a stop as already appears to be stopped
22-Feb-2013 11:54:53 weblogic.logging.ServerLoggingHandler publish
WARNING: Container weblogic.wsee.jaxws.WLSContainer$BasicContainer@1232e17 doesn't support class com.sun.xml.ws.api.server.Module
22-Feb-2013 11:54:53 weblogic.logging.ServerLoggingHandler publish
WARNING: Container weblogic.wsee.jaxws.WLSContainer$BasicContainer@1232e17 doesn't support class com.sun.xml.ws.api.server.Module
trigger seeding of SecureRandom
. TickTock :  \    9 min(s)
. TickTock : \     10 min(s)
. TickTock : /     11 min(s)
. TickTock :  /    12 min(s)
. TickTock :   /   13 min(s)
22-Feb-2013 11:59:50 done seeding SecureRandom
22-Feb-2013 11:59:53 weblogic.logging.ServerLoggingHandler publish
WARNING: Container weblogic.wsee.jaxws.WLSContainer$BasicContainer@1232e17 doesn't support class com.sun.xml.ws.api.server.Module
22-Feb-2013 12:00:01 Removing file:/scratch/gdavison/view_storage/gdavison_lt/oracle/jdeveloper/system12.1.2.0.40.65.92/o.j2ee/drs/Application1/Project1WebApp.war/WEB-INF/classes/project1/Hello.class
22-Feb-2013 12:00:01 Removing file:/scratch/gdavison/view_storage/gdavison_lt/oracle/jdeveloper/system12.1.2.0.40.65.92/o.j2ee/drs/Application1/Project1WebApp.war/WEB-INF/classes/project1/
22-Feb-2013 12:00:01 Removing file:/scratch/gdavison/view_storage/gdavison_lt/oracle/jdeveloper/system12.1.2.0.40.65.92/o.j2ee/drs/Application1/Project1WebApp.war/WEB-INF/classes/
22-Feb-2013 12:00:01 Removing file:/scratch/gdavison/view_storage/gdavison_lt/oracle/jdeveloper/system12.1.2.0.40.65.92/o.j2ee/drs/Application1/Project1WebApp.war/WEB-INF/
22-Feb-2013 12:00:01 Removing file:/scratch/gdavison/view_storage/gdavison_lt/oracle/jdeveloper/system12.1.2.0.40.65.92/o.j2ee/drs/Application1/Project1WebApp.war/

Monday, July 4, 2011

Off-loading your test execution using Hudson

One of the annoyances if you have a load of tests for a particular project is that running them can tie up your machine for a while. There are also sometimes consistency issues when running on different machines with different window managers and operating system versions. One thing we do is for every main hudson job we create a copy just to run the tests for a particular developer. It solves the "it runs on my machine" dilemma and frees up the developer to get on with other work. In our part of the organization running the tests on another machine is a mandatory step before merging to main.

This example uses subversion; but it most likely work equally well with any other source control system with a similar interface. It also assumes that all the developers are working on branches, you are doing this right?.

First of all you take a copy of you original job, in my case I am running test for the abbot project so I am starting with "abbot_SF", and create a copy of this job with a suitable postfix. In our case the job is called "abbot_SF_TestTrans". You need to first disable any normal build triggers so this job only gets used when there is a manual action. We keep the results separate as it makes the normal build results much easier to interpret.

So to this new job add a new Parameter "BRANCH" of type string and update the repository URL to contain this parameter, so in my case https://abbot.svn.sourceforge.net/svnroot/abbot/abbot/branches/$BRANCH. You will also notice that I have the used the description setting plugin to capture the branch name automatically. (You could also just put the $BRANCH parameter in the description field and leave the RegEx blank). After you have finished you have something like this, ignore the red ink as that appears to be a local configuration issue.

Now if you click build on the job you get a nice interface where you can ask Hudson to build a particular branch, leaving the developer to get on with the next job while the build machine does it's business.

Speaking of that, it looks like I have some bugs to fix...

P.S. You might also want to tick the "Execute Concurrent Builds if necessary" flag so that if you have more than one developer you can make proper use of your farm.

Monday, October 12, 2009

How to have more than one instance of AWT

I have been pondering a problem with the Costello, the test recording tool in Abbot. The one main draw back to this tool is that you can't access the recording window then the application you are testing has a modal dialog showing. This is a sever limitation that we can work around to some extent by modifying the window exclusion type for the Costello window after it is shown.


import abbot.editor.Costello;
import abbot.editor.ScriptEditorFrame;


{
  ...

  Costello.showCostello(ec);


  for (Frame next : Frame.getFrames() )
  {
    if (next instanceof ScriptEditorFrame)
    {
      next.setModalExclusionType(
        Dialog.ModalExclusionType.APPLICATION_EXCLUDE);
    }
  }

  ...
}

This is fine if you can accept that dialogs that used to be modal on Costello are no longer; but this is likely to cause bugs as the developer of Costello wasn't expecting this. (What does it mean to have two file open dialog up at the same time?)

(Anybody who believes in the sanctity of the Event Dispatch Thread please look away now, this means you Alex)

Underneath the covers swing makes use of the AppContext class to maintain the settings of a particular "instance" of AWT. For most cases you only have the one instance; but you need more in the case of applets in order to isolate them from each other. Each AppContext also has its own event thread so a deadlock in one applet cannot affect another. (Useful for helping a user when say JDeveloper deadlocks)

The actual AppContext is contained within a kinda inheritable-ThreadGroup-local variable. By default all thread groups will default to default "main" AppContext; but if you create a new ThreadGroup and an AppContext every thread and group under this will make use of the new context. Consider the following code that puts up a frame with a modal child window both on the "default" AppContext and a new AppContext created for just this occasion:


import sun.awt.AppContext;
import sun.awt.SunToolkit;

...

public static void main(String[] args) throws Exception {
    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
    new Example("Main Event Thread");

    ThreadGroup group = new ThreadGroup("SomeOtherGroup");
    new Thread(group, "Start Another Frame") {
            public void run() {
                // Create a new appContext
                AppContext appContext = SunToolkit.createNewAppContext();
                // Create a second frame, independent from the first
                new Example("Other Event Thread");
            }
        }.start();
}

You end up with two windows each able to show a modal dialog at the same time. You can just about make out the different look and feels:

A quick look at the debugger shows that indeed we do have two independent event dispatch threads:

The only thing that is shared between the different AppContext is java.awt.Component.LOCK which is a bit of a pain. I am thinking about logged a bug saying that the tree lock should be on the AppContext to prevent one from blocking another. You can see this would be quite a trivial DOS applet attack. The most obvious work around is to re-load the classes in a separate class loader; but that presents some interaction issues so I will leave that as an exercise to the reader.

Thursday, April 9, 2009

Playing with Hudson for running UI tests

I have a whole bunch of UI automation tests that for one reason of another I never gotten around to running them automatically. I had planned to include them in our short regression tests sequence; but they are just not stable enough at the moment. The problem with testing UI in a complicated environment such as JDeveloper as it only take a minor change by someone else to derail your tests. So I wanted an environment I could run them locally in.

I decided to use Hudson to drive the tests after being impressed by it at a presentation at JavaOne last year. I don't have to worry about building the product, only testing the results of the build system. It is very easy to set up, just download the war and either deploy it to a container or just run it from the command line and its starts its own server.

Now while Hudson has lots of nice support for various source control systems it of course doesn't support Oracle's in-house ADE source control system. Also I was kinda worried that since as control our build with make that it would be hard to integrate. I shouldn't have worried as Hudson has some really nice scripting support which makes integration to any SCM system really quite easy. Perhaps I will write a proper integration one day; but not really necessary for what I need to do day to day.

Anyhow a job can be made up of multiple steps, be they script, ant or maven. Here is a fragment of a job I set up to work out what the latest labels are of each of our current development branches. This might seem like an odd thing to do; but you can trigger hudson jobs off changes in a given URL if you install the right plugin - strangely there isn't one that will trigger of a script.

There are loads of plugins and they are easily installed using the hudson plugin manager ("/pluginManager"), just make sure that you pass in the proxy options at the command line if they are not set up in your environment so it can contact the home server. The Xvnc, Emma and URL Change Trigger plugins are the most important as far I am concerned.

Hudson can run multiple jobs concurrently; but for the purposes of running tests in JDeveloper I only want one running at a time as it means I can rely on default ports on all of my tests. So I reduced the number of executors to 1 on the configuration page ("/configure"). It did have to restart the server to get this to take effect though.

As mentioned before I am using the URL trigger to cause new jobs to run, you can configure this on your job configuration page ("/job/%job_name%/configure").

At the bottom of this page you can also configure how the results of the build steps are processed. In this case capturing junit and emma results. I also want to archive the results of the automation tests, we take a screen grab at the end of each test failure and capture a log of all http traffic. This all gets collected up for each test.

For each job you get a nice overview of test results and coverage, not particular proud of the test coverage values here but it is something I am working on...

Obviously with UI tests you need a display per test run, now with only run executor this isn't so much of a problem; but if you wanted to run multiple tests on the same machine then you should make use of the Xvnc plugin and turn it on for the relevant tests. This create a new vncserver for each job and configure the DISPLAY environment variable correctly. One important thing to consider is to make sure you are running the tests in the same environment as your users. VNC default to running tvm; but for a higher level test tool such as Abbot to work properly you need to run a proper window manager. So I edit my ~/.vnc/xstartup as follows to run gnome, note the "--sm-disable" mean you can run multiple instances concurrently:

#!/bin/sh
[ -x /etc/vnc/xstartup ] && exec /etc/vnc/xstartup
[ -r $HOME/.Xresources ] && xrdb $HOME/.Xresources
xsetroot -solid grey
vncconfig -iconic &

gnome-session --choose-session=VNC  --sm-disable &

The other thing to consider is that the default display dimensions for xvnc is too small to run big complex Swing application. You can control the command line options on the hudson top level configuration page. It would be nice to be able to configure this for each job.

I guess the reason why I like this system so much is that it was easy to set up and you got a lot for the time you have invested. This are load more features, particularly in the area of notification with everything from email to rss to teddy bear lamps. The ability of Hudson to bring a machine in to the build pool by just running a WebStart application is also intriguing and something I am going to look at as I pull a windows machine into the build pool when my desktop become avaliable.

Wednesday, December 10, 2008

Slides from UKOUG'08

I have uploaded the slide set from UKOUG'08 for a service called SlideShare which is useful as blogspot wont let you just upload those files yourself. Not so much detail in the testing presentation, that was mostly demos, but there are some code snippets in the promotion presentation that could be useful.

Monday, August 13, 2007

A viewlet showing Abbot being used to test relatively complex UI

As I have mentioned previously we have been playing with Abbot and Costello internally in order to automate testing of some of our UI. When you start working Abbot/Costello there is a steep learning curve with people not sure that they will ever get there tests run more than once. (Some of the reasons I have talked about before.) Once you get the hang of things though setting up tests becomes much easier with recording tests becoming a normal part of the working day.

I figured it would be usefully to publish a viewlet showing abbot testing some relatively meaty UI. So here is a recording of current smoke tests for JDeveloper web services tooling which were created in Costello and run using Abbot.

There are a few glitches in that some context menu are not recorded and the playback speed is slower than the tests actually run on my machine. In general though this gives a fair representation of a test run on my machine. Also if you look carefully you will notice some bugs that the tests are not picking up; but I will leave that as an exercise for the reader to figure out what is wrong.

Friday, July 27, 2007

"Wait, Don't Delay" or how to test complex async Java GUIs

I have been working with abbot and costello for some time now and people tend to have one of two problems getting there scripts to run reliably: the first is not being able to find a component again; and the second is the real time nature of most complex swing UIs.

The first issue can usually be solved by ensuring the that program is accessible and that use of the "name" property where required. Things do get more complicated with nested component; but they can generally be solved with a little bit of common sense.

The second issue is the real topic of this post and it sometimes takes quite a while to change around the mindset required to create tests that will run reliably on a range of platforms and systems.

Take for example an wizard that needs to query a database between pages. This means that the required components might not be enabled instantly after the user action. Now a naive user might try to include a "delay" step because they know how long the action might take; but they will find that eventually the test will fail on one platform or another. They might also try to use the waitForIdle action which is a better guess; but unfortunately not reliable and it might never return in the case of a dialog with an ongoing animation.

In all cases where delays and waits have been used in our tests we have seen then resulting in unstable test suites. The only thing I can think that delay should be used for in day to day tests is using it to ensure a piece of functionality doesn't take too long to run. Even then it will be hard to pick a value that will work on all platforms being tested upon.

Lets look at a few ideas on how you can detect whether the task has completed.

The first and most important thing you can look at is obvious UI changes that signal that the asynchronous task as finished. This might be as simple as waiting for a component to be showing using "Insert"->"Wait For"->"Component Showing". Or in the case where the UI component is always displayed you can use an assert step to ensure that a given component is enabled. In Costello this is done by selecting the "References" tab, then go to the "Properties" tab and find the "enabled" property, hold down Control and use the button that appears to insert a "Wait For" step.

The one exception to this are progress dialogs which are generally not a reliably way of tracking a task. If a progress dialog is implemented properly they might never show if the task is really quite quick.

You can also monitor lists and trees for the addition of new nodes. In costello you only need to add a selectRow step for a tree and code being the scenes will wait until that node path becomes available. (I did some of the work for this). You do find that when you have some experience with costello that you instinctively select elements in list and tree because they provide you will a cheap way to test the current state of the model.

If you are working in a product such as an IDE then you will find that many asynchronous tasks write to a log window of some kind. The example of this in JDeveloper is when we try to start and embedded oc4j instance and we have to monitor the log window to know when it has finished starting. To deal with this we use the "Call" step to invoke a static java method that does the work for us. We might also have achieved the same results with an "Expression" step; but they can be harder debug.

If the worst comes to the worst then you do end up having to provide some kind of behind the scenes API. In the work I have been doing on JDeveloper it proved to be easier to invoke the build system programatically using an Expression step rather than the UI directly. You can also use "Call" or "Expression" steps to query the state of UI components that you don't have tester for, although in the long term you are much better or writing the testers in the first place. An example I currently have on my queue waiting is a custom tester for the "gutter" in the code editor in JDeveloper. Without that it is very hard to work out when "Audit" has finished applying its rules in order to invoke a "Quick Fix". Currently a test is this area is using a very long delay which I am less than pleased with; but I hope to remove this soon.

Finally we have implemented a kind of "internal" log window using Logger for those cases where we can't think of something more creative. This provide a way for actions to say "I am finished" and for abbot to be able to pick this up. In general this is only for use as a sticking plaster until we can put the right tester in place.