expect

package module
v0.0.0-...-a21cfa3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 14, 2020 License: Apache-2.0 Imports: 11 Imported by: 4

README

STATUS

This project has not been maintained for a while. If you're interested in helping maintain it, please write me.

It's likely there are better and mroe direct options out there for doing SSH/Expect code in Go and that are more of the go idioms.

Expect for Go

build status

A simple expect library for Go.

Highlights

  • Simple API. Multi-pattern expect() statements are not supported, however this limitation is generally not an issue. See the examples for details.
  • Efficient - At the expense of guaranteeing non-greedy matches, the matching algorithm should be efficient and handle large amounts of output well.
  • Observation API - Sniff the conversation for debugging / logging purposes.
  • Bundled command logging and mocking tool.

Quick Example

For real examples, see examples.

This example ignores some important things, like error checking.


// Spawn an expect process
ssh, err := expect.Spawn("ssh", "remote_host")
ssh.SetTimeout(10 * time.Second)
const PROMPT = `(?m)[^$]*$`

// Login
ssh.Expect(`[Pp]assword:`)
ssh.SendMasked("bad password") // SendMasked hides from logging
ssh.Send("\n")
ssh.Expect(PROMPT) // Wait for prompt

// Run a command
ssh.SendLn("ls -lh")
match, err := ssh.Expect(PROMPT) // Wait for prompt
fmt.Println("ls -lh output:", match.Before)

// Hit a timeout
ssh.SendLn("sleep 60") // This will cause a timeout
match, err := ssh.Expect(PROMPT) // This will timeout
if err == expect.ErrTimeout {
    fmt.Println("Session timed out. Like we were expecting.\n")
}

// Wait for EOF
ssh.SendLn("exit")
ssh.ExpectEOF()

Observing the session and logging

Expect has the ability to let the user observe I/O and API calls. This is mostly useful for logging the session.

ssh.AddObserver(expect.LoggingObserver("ssh.log"))

Mocking tests

Tools that make use of Expect libraries are notoriously hard to test. We provide tools to record sessions and subsequently mock that device/session with a TCL-Expect script that's generated by this recorder.

Optimally, it'll eventually implement the replay functionality purely in Go, but I made my head spin too much doing that one night. So, for now we're hacking together TCL-Expect to emulate how an ssh host would respond.

mocker := expect.CreateMocker()
ssh.AddObserver(mocker.ObservationChannel())

// Do stuff with SSH
ssh.SendLn("blah")
ssh.Expect(`blah`)
...

// Store
expectScript := mocker.TCLExpectScript()
ioutil.WriteFile("ssh_mock", expectScript, 0700)

Now you can use that mocked data for further unit tests. It's not perfect by any means, but we'll see how it works in practice.

API Documentation

API Documentation

Documentation

Index

Constants

View Source
const READ_SIZE = 4094

READ_SIZE is the largest amount of data expect attempts to read in a single I/O operation. This likely needs some research and tuning.

Variables

View Source
var ErrTimeout = errors.New("Expect Timeout")

ErrTimeout is returned from exp.Expect*() when a timeout is reached.

Functions

This section is empty.

Types

type Expect

type Expect struct {
	// contains filtered or unexported fields
}

Expect is a program interaction session.

func Create

func Create(pty io.ReadWriteCloser, killer func()) (exp *Expect)

Create an Expect instance from something that we can do read/writes off of.

Note: Close() must be called to cleanup this process.

func Spawn

func Spawn(name string, args ...string) (*Expect, error)

Create an Expect instance from a command. Effectively the same as Create(pty.Start(exec.Command(name, args...)))

func (*Expect) Buffer

func (exp *Expect) Buffer() []byte

Return the current buffer.

Note: This is not all data received off the network, but data that has been received for processing.

func (*Expect) Close

func (exp *Expect) Close() error

Kill & close off process.

Note: This *must* be run to cleanup the process

func (*Expect) Expect

func (exp *Expect) Expect(expr string) (m Match, err error)

Expect(s string) is equivalent to exp.ExpectRegexp(regexp.MustCompile(s))

func (*Expect) ExpectEOF

func (exp *Expect) ExpectEOF() error

Wait for EOF

func (*Expect) ExpectRegexp

func (exp *Expect) ExpectRegexp(pat *regexp.Regexp) (Match, error)

ExpectRegexp searches the I/O read stream for a pattern within .Timeout()

func (*Expect) Send

func (exp *Expect) Send(s string) error

Send data to program

func (*Expect) SendLn

func (exp *Expect) SendLn(lines ...string) error

Send several lines data (separated by \n) to the process

func (*Expect) SendMasked

func (exp *Expect) SendMasked(s string) error

Send data, but mark it as masked to observers. Use this for passwords

func (*Expect) SetLogger

func (exp *Expect) SetLogger(logger Logger)

Set up an I/O logger

func (*Expect) SetTimeout

func (exp *Expect) SetTimeout(d time.Duration)

SetTimeout(Duration) sets the amount of time an Expect() call will wait for the output to appear.

func (*Expect) Timeout

func (exp *Expect) Timeout() time.Duration

Timeout() returns amount of time an Expect() call will wait for the output to appear.

type Logger

type Logger interface {

	// API user sent an item
	Send(time.Time, []byte)

	// API user sent a masked item. The masked data is included, but the API user is advised to
	// not log this data in production.
	SendMasked(time.Time, []byte)

	// Data is received by the same goroutine as the API user.
	Recv(time.Time, []byte)

	// Data is received off the network
	RecvNet(time.Time, []byte)

	// EOF has been reached. Time is when the EOF was received off the network
	RecvEOF(time.Time)

	// API user ran some form of Expect* call
	ExpectCall(time.Time, *regexp.Regexp)

	// API user got a return back from an Expect* call
	ExpectReturn(time.Time, Match, error)

	// Close the log file / this is the last item
	Close(time.Time)
}

func FileLogger

func FileLogger(filename string) Logger

Create an appending file logger.

func StderrLogger

func StderrLogger() Logger

func TestLogger

func TestLogger(t *testing.T) Logger

Logging adapter for `testing.T` test cases

type Match

type Match struct {
	Before string
	Groups []string
}

Match is returned from exp.Expect*() when a match is found.

type NilLogger

type NilLogger struct{}

func (*NilLogger) Close

func (*NilLogger) Close(time.Time)

func (*NilLogger) EOF

func (*NilLogger) EOF(time.Time)

func (*NilLogger) ExpectCall

func (*NilLogger) ExpectCall(time.Time, *regexp.Regexp)

func (*NilLogger) ExpectReturn

func (*NilLogger) ExpectReturn(time.Time, Match, error)

func (*NilLogger) Recv

func (*NilLogger) Recv(time.Time, []byte)

func (*NilLogger) Send

func (*NilLogger) Send(time.Time, []byte)

func (*NilLogger) SendMasked

func (*NilLogger) SendMasked(time.Time, []byte)

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL