Expect.jl
allows to spawn interactive applications and control them by
communicating through their standard input/output streams.
Expect.jl
is similar to D. Libes's Expect and many other Expect-like
modules. It can be used to automate interactive applications such as shells,
perform software testing or drive test harnesses easily.
Warning
This is a work-in-progress, the API is subject to change without notice. Suggestions about API design are highly appreciated.
The idea behind Expect is simple: commands are spawned with their I/O descriptors attached to the current process. You write to the command's standard input, then you wait for a set of known replies from it's output.
If the program you're communicating with was already meant to be controlled through a serial protocol, then using readandwrite directly is recommended as it avoids some overhead when spawning the process.
Expect differs from readandwrite
in three major ways:
- Commands are spawned under a pseudo-TTY interface, forcing libc-based programs to flush their output buffer at each line.
- Reading is performed for you until a set of possible conditions is met.
- Reading raises an ExpectTimeout exception when it blocks for longer than the requested threshold.
Using ftp
to retrieve a remote file list:
julia> # Start a new process
julia> using Expect;
julia> proc = ExpectProc(`ftp ftp.scene.org`, 16);
julia> # Wait for the prompt
julia> expect!(proc, "> ");
julia> # Send "ls" and wait for prompt
julia> println(proc, "ls");
julia> expect!(proc, "> ");
julia> # Collect all the output since the last prompt
julia> list = proc.before;
julia> println(list);
drwxrwsr-x 11 redhound ftpadm 4096 Mar 2 20:57 incoming
drwx------ 2 redhound ftpadm 16384 Feb 24 12:58 lost+found
-rw-r--r-- 1 redhound ftpadm 16060223 Mar 22 01:15 ls-lR
-rw-r--r-- 1 redhound ftpadm 2723919 Mar 22 01:15 ls-lR.gz
drwxrwsr-x 12 redhound ftpadm 4096 Nov 26 2013 mirrors
drwxrwsr-x 8 redhound ftpadm 4096 Mar 4 18:25 pub
-rw-r--r-- 1 redhound ftpadm 547 Nov 9 2013 welcome.msg
Some highlights about the example:
- The first argument to ExpectProc is just a regular Cmd object.
- You don't have to worry about buffering.
- An
ExpectProc
handle can be read or written to using the standard I/O functions such asreadbytes!
orprintln
. proc.before
contains all the command's output since the last expect! match (excluding the match itself).
The last point can be clarified with the following example:
julia> using Expect;
julia> proc = ExpectProc(`echo "a b c "`, 16);
julia> expect!(proc, " ")
"a"
julia> expect!(proc, " ")
"b"
julia> expect!(proc, " ")
"c"
For convenience, expect!
already returns the contents of proc.before
when given a single pattern to match.
expect!
however is normally used with a list of possible matches to
perform. In this scenario, the index that matched first will be returned.
The matched string itself is also available in proc.match
. This is useful
to perform conditional processing depending on the command's output:
using Expect
proc = ExpectProc(`interpreter`, 16)
println(proc, "perform")
idx = expect!(proc, ["> ", "ERROR: "])
if idx == 2
# error occurred ...
end
The matches themselves can be regular strings or Regex objects. When a Regex
is used, the content of proc.match
contains a match object for the element
that matched.
See tests/runtests.jl
for more usage examples.
ExpectProc(cmd, timeout; env, encoding="utf8", pty=true)
:
Constructs a new
ExpectProc
object.
cmd: the Cmd command to be spawned. timeout: default communication timeout. env: environment for the command (defaults as a copy of the current) encoding: I/O encoding (currently limited to utf8) pty: request allocation of pty
expect!(proc, vector; timeout)
:
Read the standard output of the program until one of the strings/regular expressions specified in
vector
matches. The index of the element that matched first is returned. Matches are searched in sequential order.When
timeout
is specified, it overrides the default timeout specified in the constructor. A value ofInf
waits indefinitely.
proc.before
is reset at each call to contain all the standard output before the match.
proc.match
contains either a string or a match object for the element that matched.
expect!(proc, element; timeout)
:
Read the standard output of the program until the string/regular expressions specified inelement
matches. The content ofproc.before
is returned.
with_timeout!(func, proc, timeout)
:
Modify the default read timeout within the context of
func
. Normally used with thedo
syntax:proc = ExpectProc(`command`, 1) with_timeout!(proc, Inf) do # no read timeout within this context end
ExpectTimeout
:
Reading from the command stalled for the specified number of seconds without matching any pattern. Reading can continue.
ExpectEOF
:
The output ended without matching any of the specified patterns.
LICENSE.rst
).