The Processes handler provides step definitions which allow you to start and stop local processes, and check their standard output and error.
You can also provide input to a running process.
Uses: Processes
The top of your feature file (e.g. myProcess.feature) may look like this:
Uses: Processes
Feature: Start a Process Feature
Scenario: Check we can start a process
Given I start a myProcess process
The process will automatically get stopped at the end of the scenario Initially this will fail, since you have not yet provided any config to tell Chorus how to start ‘myProcess’
To configure the process, add a myProcess.properties file in the same directory as your processTest.feature.
In the properties file you can configure processes. For a Java process, you must set a property for the main class of your process as below:
processes.myProcess.mainclass=com.mycom.MyProcess
The new process will use the same JVM and classpath as the chorus interpreter, but you can override these by setting other properties.
For a full list of processes properties scroll down to the bottom of this page For full details on chorus properties files see Handler Configuration
In the example above, the configuration is called ‘myProcess’ but the process is named ‘pub’ This distinction allows you to start multiple instances of the myProcess process under different logical names:
I start a myProcess process named pub1
I start a myProcess process named pub2
You generally don’t need to stop processes explicitly using ‘I stop the process’ steps.
By default any processes started during a scenario will be terminated by Chorus when that scenario is completed.
Processes started within a scenario are usually stopped automatically at the end of a scenario. The process is then ‘scenario scoped’
If you wish to run a process throughout a feature, and reuse it between scenarios, you can configure it to be scoped at feature level, by setting the scope
property:
e.g. processes.myProcess.scope=feature
Then the process will not be stopped until feature end.
If you start a process during the special Feature-Start: scenario then it will automatically be scoped to ‘feature scope’ unless you configure it otherwise.
If you need to wait for a process to terminate there are steps for this..
I wait for the process pub to terminate
or
I wait for up to 10 seconds for the process pub to terminate
If you set a process stdOutMode or stdErrMode to ‘FILE’ then you can match regular expressions against its output
#file: myfeature.properties
processes.myProcess.stdOutMode=captured
I read the line 'my .* pattern' from the pub process
or
I read the line 'my .* pattern' from the pub process std error
or if you are not expecting a line terminator:
I read 'my .* pattern' from the pub process
These steps will block for a period waiting to read the output from the process. If the output is not detected, eventually the step will timeout and fail The timeout length can be configured as a property.
You can also write input to a process which processes handler has started:
I write the line 'my text here' to the pub process
or
I write 'my text no line terminator to be appended' to the pub process
The processes you are starting may write to their standard output and standard error streams.
By default any output will written to a log file placed into a log directory under the feature file directory
Alternatively you can write the process output to console (inline) with the interpreter output but this can make the test output hard to read
Logging is configured independently for the process std out and error streams, using an output mode. Output mode is one of
The config below will write the std out of the myProcess process process to a log file, and show error output inline n.b. the log file name will be calculated automatically from the feature and process name
processes.myProcess.stdOutMode=file
processes.myProcess.stdErrMode=inline
processes.myProcess.logDirectory=${user.dir}/test/chorus/logs
processes.myProcess.appendToLogs=false
If the ProcessesHandler finds a file called log4j.xml in the same directory as your feature file, then it will set the appropriate log4j system property when starting your processes.
-Dlog4j.configuration=${path to your log4j.xml
It will also set the following system properties which can be useful in your log4j configuration:
-Dfeature.dir=${path to your feature directory}
-Dfeature.process.name=${name of current feature}
If you want all your processes to log to the same directory, you could set a default for this. The easiest way is to add a chorus.properties file at the top level on your test classpath. Use the special ‘default’ configuration group to specify the default property values:
processes.default.logging=true
processes.default.logDirectory=${user.dir}/test/chorus/logs
Now all processes will log into the above directory, unless you override them with a configuration specific property.
For full details on chorus properties files see Handler Configuration
Processes started by the process handler are often Chorus-enabled JVM processes. These can publish their own step definitions using Chorus’ Remoting featurs and the ChorusHandlerJmxExporter utility. It’s a very common requirement to start a process using the Processes Handler and then call exported test steps on it
To do this you need to turn the jmx management service on for any processes you start (and have your processes export handler classes). You can then connect to the process by setting the remotingPort property below to the correct port for the JMX service started by the process under test.
processes.myProcess.remotingPort=1234
For more details on remoting see Remoting Handler Quick Start
Instead of setting main class, you can set the property pathToExecutable
to point to a script or native process.
This may be either an absolute path or a path which is relative to the feature file directory
Step | Example | Deprecated | Description | Retry Duration (wait for step to pass) |
---|---|---|---|---|
.*start a (.*) process | Given I start a myProcess process | No | Start a process which is configured in handler properties | |
.*start an? (.+) process named ([a-zA-Z0-9-_]+).*? | Given I start a myProcess process named myProcess_A | No | Start a process which is configured in handler properties, given it a name/alias. This allows the same configuration to be used for several named process instances | |
.*stop (?:the )?process (?:named )?([a-zA-Z0-9-_]+).*? | Then I stop the process myProcess | No | Stop the process with the given name | |
.*?(?:the process )?(?:named )?([a-zA-Z0-9-_]+) (?:is |has )(?:stopped|terminated).*? | And the process myProcess has stopped | No | Check the process with the given name which was running is now stopped | 5 SECONDS |
.*?(?:the process )?(?:named )?([a-zA-Z0-9-_]+) is running | And the process myProcess is running | No | Check the process with the given name is running | |
.*?(?:the process )?(?:named )?([a-zA-Z0-9-_]+) is not running | Then the process myProcess is not running | No | Check the process with the given name is not running | 5 SECONDS |
.*wait for (?:up to )?(\d+) seconds for (?:the process )?(?:named )?([a-zA-Z0-9-_]+) to (?:stop|terminate).*? | When I wait for up to 10 seconds for the process named myProcess to stop | No | Wait for a running process to terminate for up to the specified number of seconds | |
.*wait for (?:the process )?(?:named )?([a-zA-Z0-9-_]+) to (?:stop|terminate).*? | When I wait for myProcess to stop | No | Wait for a running process to terminate for up to the terminate wait time specified in the process config | |
.*read the line '(.*)' from (?:the )?([a-zA-Z0-9-_]+) process | Then I read the line 'user \w+ logged in' from the myProcess process | No | Read a line of standard output from the named process which matches the pattern specified, this will be stored into the Chorus Context variable 'ProcessesHandler.match', waiting for the read timeout specified in the process config | |
.*read the line '(.*)' from (?:the )?([a-zA-Z0-9-_]+) process std error | Then I read the line 'user \w+ logged in' from the myProcess process std error | No | Read a line of standard error from the named process which matches the pattern specified, this will be stored into the Chorus Context variable 'ProcessesHandler.match', waiting for the read timeout specified in the process config | |
.*read the line '(.*)' from (?:the )?([a-zA-Z0-9-_]+) process within (\d+) second(?:s)? | Then I read the line 'user \w+ logged in' from the myProcess process within 5 seconds | No | Read a line of standard output from the named process which matches the pattern specified, this will be stored into the Chorus Context variable 'ProcessesHandler.match', waiting for the number of seconds specified | |
.*read the line '(.*)' from (?:the )?([a-zA-Z0-9-_]+) process std error within (\d+) second(?:s)? | Then I read the line 'user \w+ logged in' from the myProcess process within 5 seconds | No | Read a line of standard error from the named process which matches the pattern specified, this will be stored into the Chorus Context variable 'ProcessesHandler.match', waiting for the number of seconds specified | |
.*read '(.*)' from (?:the )?([a-zA-Z0-9-_]+) process | Then I read 'user \w+ logged in' from the myProcess process | No | Read standard output from the named process which matches the pattern specified, matching within lines. This will be stored into the Chorus Context variable 'ProcessesHandler.match'. Wait for up to the read timeout specified in the process config | |
.*read '(.*)' from (?:the )?([a-zA-Z0-9-_]+) process std error | Then I read 'user \w+ logged in' from the myProcess process std errorjj | No | Read standard error from the named process which matches the pattern specified, matching within lines. This will be stored into the Chorus Context variable 'ProcessesHandler.match'. Wait for up to the read timeout specified in the process config | |
.*read '(.*)' from (?:the )?([a-zA-Z0-9-_]+) process within (\d+) second(?:s)? | Then I read 'user \w+ logged in' from the myProcess process | No | Read standard output from the named process which matches the pattern specified, matching within lines. This will be stored into the Chorus Context variable 'ProcessesHandler.match'. Wait for the specified number of seconds | |
.*read '(.*)' from (?:the )?([a-zA-Z0-9-_]+) process std error within (\d+) second(?:s)? | Then I read 'user \w+ logged in' from the myProcess process | No | Read standard error from the named process which matches the pattern specified, matching within lines. This will be stored into the Chorus Context variable 'ProcessesHandler.match'. Wait for the specified number of seconds | |
.*write the line '(.*)' to (?:the )?([a-zA-Z0-9-_]+) process | When I write the line 'hello hello' to the myProcess process | No | Write the supplied text followed by a line terminator to the named process standard input | |
.*write '(.*)' to (?:the )?([a-zA-Z0-9-_]+) process | When I write the line 'hello hello' to the myProcess process | No | Write the supplied text to the named process standard input, no line terminator will be appended | |
Processes start ([a-zA-Z0-9-_, ]+) | #! Processes start myProcess) mySecondProcess, myThirdProcess | No | Start the list of processes (as a directive) | |
Processes connect ([a-zA-Z0-9-_, ]+) | #! Processes connect myProcess) mySecondProcess, myThirdProcess | No | Connect to the list of processes using Chorus' remoting features, a remoting port must have been specified in the process config and the processes must be exporting step definitions |
Property | Is Mandatory | Description | Default | Validation |
---|---|---|---|---|
mainclass | no | The class containing the main method which starts up your component (java processes only) | ||
classpath | no | The classpath to use when executing a Java process. If not set, the Chorus interpreter's classpath will be used | ||
jre | no | Path to the JRE to be used when executing a Java process. If not set, the Chorus interpreter's JVM will be used | ||
jvmargs | no | System properties (-D switches) to use when executing a Java process | ||
args | no | Arguments to pass to the process | ||
pathToExecutable | no | Path to a native executable process or script, the path may be absolute or relative to the feature directory. This property and the mainclass property are mutually exclusive - you should either one but not both | ||
stdOutMode | no | What do to with standard output stream from started process, one of INLINE (combine with interpreter stdout), FILE (write output to file). Other values are deprecated | One of: FILE, INLINE, CAPTURED, CAPTUREDWITHLOG | |
stdErrMode | no | What do to with standard error stream from started process, one of INLINE (combine with interpreter stderr) or FILE (write output to file). Other values are deprecated | One of: FILE, INLINE, CAPTURED, CAPTUREDWITHLOG | |
logging | no | If this property is set true, it will switch stdOutMode and stdErrorMode to FILE. If false then both will be INLINE. Leave it unset if you wish to set the stdOutMode and stdErrorMode individually | One of: true, false | |
remotingPort | yes | Port on which to start the JMX remoting service. This is required when you want to use Chorus' Remoting features to connect to the process being started using JMX. Setting this property will add java system properties to turn on the JMX platform service. (java processes only), -1 to disable | -1 | (-?)\d+ |
debugPort | yes | Enable the debugger when starting the jvm and set it up to listen for connections on the port specified (java processes only), -1 to disable | -1 | (-?)\d+ |
terminateWaitTime | yes | Maximum time to wait for a process to terminate in seconds | 30 | \d+ |
logDirectory | no | If you turn logging on, use this property to set the log directory. If not specified a logs directory will be created in the same directory as the feature file. May be an absolute path or a path relative to the working directory | ||
appendToLogs | yes | Whether to append to or overwrite log files | false | One of: true, false |
createLogDir | yes | Whether to auto-create the log directory if it does not exist | true | One of: true, false |
processCheckDelay | yes | Milliseconds after which to check started process is still running or fail the start process step. Longer values add better detection of immediate process start failures but incur an increased delay before subsequent steps run | 500 | (-?)\d+ |
readTimeoutSeconds | yes | When matching a pattern against process output set the max time to wait for a match | 10 | \d+ |
scope | no | Whether the process should be shut down at the end of the scenario or the end of the feature. this will be set automatically to FEATURE for processes started during 'Feature-Start:' if not provided, otherwise Scenario | SCENARIO | One of: SCENARIO, FEATURE |
enabled | yes | This property can be set to true to disable process start up when running in certain profiles | true | One of: true, false |