Class: ShellTest::ShellMethods::Agent
- Inherits:
-
Object
- Object
- ShellTest::ShellMethods::Agent
- Defined in:
- lib/shell_test/shell_methods/agent.rb
Overview
Agent wraps a PTY master-slave pair and provides methods for doing reads and writes. The expect method is inspired by the IO.expect method in the stdlib, but tailored to allow for better timeout control.
Defined Under Namespace
Classes: ReadError, WriteError
Instance Attribute Summary collapse
-
#master ⇒ Object
readonly
The pty master.
-
#slave ⇒ Object
readonly
The pty slave.
-
#timer ⇒ Object
readonly
The timer managing read timeouts.
Instance Method Summary collapse
-
#close ⇒ Object
Closes the master and slave.
-
#expect(regexp, timeout = nil) ⇒ Object
Reads from the slave until the regexp is matched and returns the resulting string.
-
#initialize(master, slave, timer) ⇒ Agent
constructor
A new instance of Agent.
- #on(regexp, input, timeout = nil) ⇒ Object
-
#read(timeout = nil) ⇒ Object
Read to the end of the slave.
-
#write(input, timeout = nil) ⇒ Object
Writes to the master.
Constructor Details
#initialize(master, slave, timer) ⇒ Agent
23 24 25 26 27 |
# File 'lib/shell_test/shell_methods/agent.rb', line 23 def initialize(master, slave, timer) @master = master @slave = slave @timer = timer end |
Instance Attribute Details
#master ⇒ Object (readonly)
The pty master
11 12 13 |
# File 'lib/shell_test/shell_methods/agent.rb', line 11 def master @master end |
#slave ⇒ Object (readonly)
The pty slave
14 15 16 |
# File 'lib/shell_test/shell_methods/agent.rb', line 14 def slave @slave end |
#timer ⇒ Object (readonly)
The timer managing read timeouts. The timer ensures that the timeouts used by expect are never negative, or nil to indicate no timeout.
If implementing a custom timer, note that timeouts are set on the timer using timer.timeout= and retrieved via timer.timeout.
21 22 23 |
# File 'lib/shell_test/shell_methods/agent.rb', line 21 def timer @timer end |
Instance Method Details
#close ⇒ Object
Closes the master and slave.
108 109 110 111 112 113 114 115 |
# File 'lib/shell_test/shell_methods/agent.rb', line 108 def close unless master.closed? master.close end unless slave.closed? slave.close end end |
#expect(regexp, timeout = nil) ⇒ Object
Reads from the slave until the regexp is matched and returns the resulting string. If regexp is a String, then it is converted into a regexp assuming it’s a literal prompt (ie /^regexp\z/ - where the regexp string is Regexp escaped). If regexp is nil then expect reads until the slave eof.
A timeout may be given. If the slave doesn’t produce the expected string within the timeout then expect raises a ReadError. A ReadError will be also be raised if the slave eof is reached before the regexp matches.
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/shell_test/shell_methods/agent.rb', line 45 def expect(regexp, timeout=nil) if regexp.kind_of?(String) regexp = /#{Regexp.escape(regexp)}\z/ end timer.timeout = timeout buffer = '' while true timeout = timer.timeout # Use read+select instead of read_nonblock to avoid polling in a # tight loop. Don't bother with readpartial and partial lengths. It # would be an optimization, especially because the regexp matches # each loop, but adds complexity because expect could read past the # end of the regexp and it is unlikely to be necessary in test # scenarios (ie this is not meant to be a general solution). unless IO.select([slave],nil,nil,timeout) msg = "timeout waiting for %s after %.2fs" % [regexp ? regexp.inspect : 'EOF', timeout] raise ReadError.new(msg, buffer) end begin c = slave.read(1) rescue Errno::EIO # see notes in Utils#spawn c = nil end if c.nil? if regexp.nil? break else raise ReadError.new("end of file reached", buffer) end end buffer << c if regexp && buffer =~ regexp break end end buffer end |
#on(regexp, input, timeout = nil) ⇒ Object
29 30 31 32 33 |
# File 'lib/shell_test/shell_methods/agent.rb', line 29 def on(regexp, input, timeout=nil) output = expect(regexp, timeout) write(input) output end |
#read(timeout = nil) ⇒ Object
Read to the end of the slave. Raises a ReadError if the slave eof is not reached within the timeout.
93 94 95 |
# File 'lib/shell_test/shell_methods/agent.rb', line 93 def read(timeout=nil) expect nil, timeout end |
#write(input, timeout = nil) ⇒ Object
Writes to the master. A timeout may be given. If the master doesn’t become available for writing within the timeout then write raises an WriteError.
100 101 102 103 104 105 |
# File 'lib/shell_test/shell_methods/agent.rb', line 100 def write(input, timeout=nil) unless IO.select(nil,[master],nil,timeout) raise WriteError.new("timeout waiting for master") end master.print input end |