Multi-user, Multi-process Test Automation

There is a saying about how to make software: First you make it work; then you make it good; then you make it fast. If you have working test automation, and if your test automation is finding bugs, then the next step is to make your tests run fast. This article talks about handling two things you will need to address to make that happen: users and processes.

If you have automated GUI tests, it's likely that you run them serially, which takes a long time. Imagine how fast they would be if you could run UI tests concurrently.

Concurrent Is Faster than Serial
I recently finished writing a test launcher that concurrently runs four sets of automated tests for four different users in four
different test environments. Doing this means that my tests run in about one third of the time as they do when run serially.

(While this idea isn't new, I hadn't considered trying it until a presentation at the 2007 Google Test Automation Conference inspired me to make this work.)

Who Am I?
When a user logs in to a computer in my test environment, he has to give a user name and a password. Each user on a machine launches processes with a unique identifier, has a defined set of places from which he may run programs, and has space allocated on the machine solely for his use. In the course of getting my test-launcher to work, I had to learn how to manage all of this information for all of my test users.

My four users are named qa9, qa10, qa11, and qa12.

There is even a command "whoami":

$ whoami


Being Someone Else: Sudo and Root

Normally it is impossible to operate as a user other than yourself on these computers, but running tests in multiple user environments from a single controller demands this. On Unix-like systems, the "sudo" command makes this happen.

Because of how my test environments are engineered, I need to be able to use sudo to get root privileges on my test machine. Your automated tests may not require root privileges. Whatever your test environment requires, it is good practice to use only the minimum privileges required.

Effective User ID, aka "euid"

Whenever a user launches a process, that process is associated with the user running it by a "uid" (user id) value and an "euid" (effective user id) value. Both uid and euid values are used by the system to allow or forbid the processes from accessing appropriate resources on the machine. These IDs are interchangeable, but for my purposes I need to be able to manipulate euid, not uid.

I'm testing a Web application with Selenium-RC (Remote Control), but my automated tests also run a command-line utility used for setting up and tearing down test data. This "st-admin" utility is intended for use by administrators of the application, but it comes in very handy for testers, since it allows us to do some powerful things that the regular UI interface does not. Some of the things it can do are "st-admin create-user" and "st-admin delete-page," and much more.

The tricky part is that when st-admin runs, it examines its own euid to discover where it is supposed to run. If user cmcmahon launches st-admin, st-admin will run from cmcmahon's environment and in cmcmahon's environment. If the test launcher (cmcmahon) wants to run st-admin for user qa11, cmcmahon has to launch st-admin from qa11's environment with the euid for user qa11.

Programming languages represent euid in different ways. My st-admin tool is written in Perl, and euid in Perl is represented as "$>". My test launcher is written in Ruby, and euid in Ruby is "Process.euid". The shell command id() shows all the id information for the user.

Launching Simultaneous Processes with fork()
Unix-like systems are designed to run multiple processes for multiple users. The ability to manipulate euid covers the part about multiple users; now we need to cover the part about multiple processes.

AgileConnection is a TechWell community.

Through conferences, training, consulting, and online resources, TechWell helps you develop and deliver great software every day.