Getting started
The Grinder processes
The Grinder is a framework for running test scripts across a number of machines. The framework is comprised of three types of process (or program). Worker processes, agent processes, and the console. The responsibilities of each of the process types are:
-
Worker processes
- Interpret Jython test scripts and perform tests using a number of worker threads
-
Agent processes
- Manage worker processes
-
The console
- Coordinate the other processes
- Collate and display statistics
- Script editing and distribution
As The Grinder is written in Java, each of these processes is a Java Virtual Machine (JVM).

For heavy duty testing, you start an agent process on each of several load injector machines. The worker processes they launch can be controlled and monitored using the console. There is little reason to run more than one agent on each load injector, but you can if you wish.
Tests and test scripts
A test is a unit of work against which statistics are recorded. Tests are uniquely defined by a test number and also have a description. Users specify which tests to run using a Jython test script. If you wish your scripts can report many different actions (e.g. different web page requests) against the same test, The Grinder will aggregate the results.
The script is executed many times in a typical testing scenario. Each worker process has a number of worker threads, and each worker thread calls the script a number of times. A single execution of a test script is called a run.
You can write scripts for use with the Grinder by hand. There are a number of examples of how to do this in the Script Gallery. See the Scripts section for more details on how to create scripts.
If you are creating a script to test a web site or web application, you can use the TCPProxy to record a browser session as a script.
Network communication
Each worker process sets up a network connection to the console to report statistics. Each agent process sets up a connection to the console to receive commands, which it passes on to its worker processes. The console listens for both types of connection on a particular address and port. By default, the console listens on port 6372 on all local network interfaces of the machine running the console.
If an agent process fails to connect to the console, or the grinder.useConsole property is false, the agent will continue independently without the console and automatically will start its worker processes. The worker processes will run to completion and not report to the console. This can be useful when you want to quickly try out a test script without bothering to start the console.
Output
Each worker process writes logging information to a file called out-host-n.log, where host is the machine host name and n is the worker process number. Errors are written to error-host-n.log. If no errors occur, an error file will not be created.
Data about individual test invocations is written into a file called data-host-n.log that can be imported into a spreadsheet tool such as Microsoft ExcelTM for further analysis. The data file is the only place where information about individual tests is recorded; the console displays only aggregate information.
The final statistics summary (in the out-* files of each process) looks something like this:
Final statistics for this process:
Successful
Tests Errors Mean Test Test Time
Time (ms) Standard
Deviation
(ms)
Test 0 25 0 255.52 22.52
Test 1 25 0 213.40 25.15
Test 2 25 0 156.80 20.81 "Image"
Test 3 25 0 90.48 14.41
Test 4 25 0 228.68 23.97 "Login page"
Test 5 25 0 86.12 12.53 "Security check"
Test 6 25 0 216.20 8.89
Test 7 25 0 73.20 12.83
Test 8 25 0 141.92 18.36
Test 9 25 0 104.68 19.86 "Logout page"
Totals 250 0 156.70 23.32
The console has a dynamic display of similar information collected from all the worker processes. Plug-ins and advanced test scripts can provide additional statistics; for example, the HTTP plug-in adds a statistic for the content length of the response body.
Each test has one of two possible outcomes:
- Success. The number of Successful Tests for that test is incremented The time taken to perform the test is added to the Total.
- Error. The execution of a test raised an exception. The number of Errors for the test is incremented. The time taken is discarded.
The Total, Mean, and Standard Deviation figures are calculated based only on successful tests.
How do I start The Grinder?
Its easy:
- Create a grinder.properties file. This file specifies general control information (how the worker processes should contact the console, how many worker processes to use, ..), as well as the name of the Jython script that will be used to run the tests.
- Set your CLASSPATH to include the grinder.jar file which can be found in the lib directory.
- Start the console on one of the test machines:
java net.grinder.Console
- For each test machine, do steps 1. and 2. and start an agent
process:
java net.grinder.Grinder
You can also specify an explicit properties file as the first argument. For example:
java net.grinder.Grinder myproperties
The console does not read the grinder.properties file. It has its own options dialog (choose the File/Options menu option) which you should use to set the communication addresses and ports to match those in the grinder.properties files. The console controls can be used to trigger The Grinder test scenario. Each agent process then creates child worker processes to do the work.
As the worker processes execute, they dynamically inform the console of the tests in the test script. If you start the console after the agent process, you should press the Reset processes button. This will cause the existing worker processes to exit and the agent process to start fresh worker processes which will update the console with the new test information.
Included below are some sample shell scripts, for both unix/linux and windows, for starting grinder agents, its console, and the HTTPProxy.
Windows:
- setGrinderEnv.cmd:
set GRINDERPATH=(full path to grinder install directory) set GRINDERPROPERTIES=(full path to grinder.properties)\grinder.properties set CLASSPATH=%GRINDERPATH%\lib\grinder.jar;%CLASSPATH% set JAVA_HOME=(full path to java install directory) PATH=%JAVA_HOME%\bin;%PATH%
- startAgent.cmd:
call (path to setGrinderEnv.cmd)\setGrinderEnv.cmd echo %CLASSPATH% java -cp %CLASSPATH% net.grinder.Grinder %GRINDERPROPERTIES%
- startConsole.cmd:
call (path to setGrinderEnv.cmd)\setGrinderEnv.cmd java -cp %CLASSPATH% net.grinder.Console
- startProxy.cmd:
call (path to setGrinderEnv.cmd)\setGrinderEnv.cmd java -cp %CLASSPATH% net.grinder.TCPProxy -console -http > grinder.py
Unix:
- setGrinderEnv.sh:
#!/usr/bin/ksh GRINDERPATH=(full path to grinder install directory) GRINDERPROPERTIES=(full path to grinder.properties)/grinder.properties CLASSPATH=$GRINDERPATH/lib/grinder.jar:$CLASSPATH JAVA_HOME=(full path to java install directory) PATH=$JAVA_HOME/bin:$PATH export CLASSPATH PATH GRINDERPROPERTIES
- startAgent.sh:
#!/usr/bin/ksh . (path to setGrinderEnv.sh)/setGrinderEnv.sh java -cp $CLASSPATH net.grinder.Grinder $GRINDERPROPERTIES
- startConsole.sh:
#!/usr/bin/ksh . (path to setGrinderEnv.sh)/setGrinderEnv.sh java -cp $CLASSPATH net.grinder.Console
- startProxy.sh:
#!/usr/bin/ksh . (path to setGrinderEnv.sh)/setGrinderEnv.sh java -cp $CLASSPATH net.grinder.TCPProxy -console -http > grinder.py
How should I set up a project structure for The Grinder?
Well the short answer is however works best for you. Many people will already know how they want to set up their directory structure and will have no issue implementing The Grinder as one of their many tools. For those looking for a little guidance it is worth asking yourself questions like:
- How many projects will I be working on?
- Will I need to revisit projects from time to time?
- Do I need repeatability?
- Is this a shared implementation?
- ...etc.
Below is given an example of a directory structure for setting up The Grinder.
.
`- Grinder
|
|-- bin
| |-- setGrinderEnv.sh/cmd
| |-- startAgent.sh/cmd
| |-- startConsole.sh/cmd
| `-- startProxy.sh/cmd
|
|-- engine
| |-- grinder-3.0-beta32
| |-- grinder-3.0
| `-- ...
|
|-- etc
| |-- grinder.properties
| `-- ...
|
|-- jvm
| |-- jdk1.3
| |-- jdk1.4.02
| `-- ...
|
|-- lib
| |-- jython2.1
| |-- jdom-1.0
| |-- xerces_2_6_0
| |-- xerces-2_6_2
| |-- oracle
| `-- ...
|
|-- logs
| `-- ...
|
`-- projects
|-- website_project
| |-- httpscript.py
| |-- httpscript_tests.py
| `-- ...
|
|-- db_project
| |-- jdbc.py
| `-- ...
|
`-- ...
First off the bin directory has been created for storing executable files for the implementation. The sample start scripts from "How do I start The Grinder?" have been included in this directory. The engine directory has been created for storing the versions of The Grinder that may be used. Strictly speaking the versions of The Grinder could be stored under the lib directory but for this example The Grinder has been given its own directory. The etc directory has been created to store the configuration files for the implementation such as the grinder.properties file. The jvm directory has been created to store the various jdks and their versions that could be used in testing. The lib directory has been created to store the various third party libraries and their respective versions that projects may require. For example if you wanted to use the full set of libraries which come with jython then this is the directory into which you would install. Remember to update your CLASSPATH with the libraries you require. The logs has been created to store the various logs that the grinder generates during its runs.The projects directory has been created to store the scripts to be run by The Grinder and organise them by project/body of work.
The above example would be useful as a simple implementation for one person who works on one project at a time. As the number of projects grows, more people share the implementation, or projects need to be revisited with repeatability ensured, then it makes sense, in this example, to modularize the implementation around the projects. To do this simply create the bin, etc and logs directories under the respective projects like so:
|
`-- projects
|-- website_project
| |-- bin
| | |-- setGrinderEnv.sh/cmd
| | |-- startAgent.sh/cmd
| | |-- startConsole.sh/cmd
| | `-- startProxy.sh/cmd
| |-- etc
| | |-- grinder.properties
| | `-- ...
| |-- httpscript.py
| |-- httpscript_tests.py
| |-- logs
| | `-- ...
| `-- ...
|
|-- db_project
Once this has been done the environment can be set to use the engine, jvm and libraries required by a particular project, rather than setting the environment for all the projects (as would happen in the simple implementation). This allows you, for example, to retain projects which were run using legacy versions of libraries and/or engine and re-run them at a later date with the same setup. Also different projects may require different versions of the same library which would have caused issues when using an implementation-wide CLASSPATH. The grinder.properties file can also be customised on a per project basis.
Modularizing the implementation like this gives greater flexibility and repeatability and opens up the prospect of multiple people using the implementation concurrently.

