/expect

Go expect tool

Primary LanguageGo

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