expect

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

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

Go to latest
Published: Mar 31, 2020 License: Apache-2.0 Imports: 15 Imported by: 0

README

go-expect

Build Status GoDoc NetflixOSS Lifecycle

Package expect provides an expect-like interface to automate control of applications. It is unlike expect in that it does not spawn or manage process lifecycle. This package only focuses on expecting output and sending input through it's pseudoterminal.

Usage

os.Exec example
package main

import (
	"log"
	"os"
	"os/exec"
	"time"

	expect "github.com/Netflix/go-expect"
)

func main() {
	c, err := expect.NewConsole(expect.WithStdout(os.Stdout))
	if err != nil {
		log.Fatal(err)
	}
	defer c.Close()

	cmd := exec.Command("vi")
	cmd.Stdin = c.Tty()
	cmd.Stdout = c.Tty()
	cmd.Stderr = c.Tty()

	go func() {
		c.ExpectEOF()
	}()

	err = cmd.Start()
	if err != nil {
		log.Fatal(err)
	}

	time.Sleep(time.Second)
	c.Send("iHello world\x1b")
	time.Sleep(time.Second)
	c.Send("dd")
	time.Sleep(time.Second)
	c.SendLine(":q!")

	err = cmd.Wait()
	if err != nil {
		log.Fatal(err)
	}
}
golang.org/x/crypto/ssh/terminal example
package main

import (
	"fmt"

	"golang.org/x/crypto/ssh/terminal"

	expect "github.com/Netflix/go-expect"
)

func getPassword(fd int) string {
	bytePassword, _ := terminal.ReadPassword(fd)

	return string(bytePassword)
}

func main() {
	c, _ := expect.NewConsole()

	defer c.Close()

	donec := make(chan struct{})
	go func() {
		defer close(donec)
		c.SendLine("hunter2")
	}()

	echoText := getPassword(int(c.Tty().Fd()))

	<-donec

	fmt.Printf("\nPassword from stdin: %s", echoText)
}

Documentation

Overview

Package expect provides an expect-like interface to automate control of applications. It is unlike expect in that it does not spawn or manage process lifecycle. This package only focuses on expecting output and sending input through it's psuedoterminal.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func EOF

func EOF(opts *ExpectOpts) error

EOF adds an Expect condition to exit if io.EOF is returned from reading Console's tty.

func NewChanReader

func NewChanReader(ctx context.Context, bytec <-chan byte) io.Reader

NewChanReader returns a io.Reader over a byte chan. If context is cancelled, future Reads will return io.EOF.

func NewTestWriter

func NewTestWriter(t *testing.T) (io.Writer, error)

NewTestWriter returns an io.Writer where bytes written to the file are logged by go's testing logger. Bytes are flushed to the logger on line end.

func PTSClosed

func PTSClosed(opts *ExpectOpts) error

PTSClosed adds an Expect condition to exit if we get an "read /dev/ptmx: input/output error" error which can occur on Linux while reading from the ptm after the pts is closed. Further Reading: https://github.com/kr/pty/issues/21#issuecomment-129381749

func StripTrailingEmptyLines

func StripTrailingEmptyLines(out string) string

StripTrailingEmptyLines returns a copy of s stripped of trailing lines that consist of only space characters.

Types

type CallbackMatcher

type CallbackMatcher interface {
	// Callback executes the matcher's callback with the content buffer at the
	// time of match.
	Callback(buf *bytes.Buffer) error
}

CallbackMatcher is a matcher that provides a Callback function.

type Console

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

Console is an interface to automate input and output for interactive applications. Console can block until a specified output is received and send input back on it's tty. Console can also multiplex other sources of input and multiplex its output to other writers.

Example (Echo)
c, err := NewConsole(WithStdout(os.Stdout))
if err != nil {
	log.Fatal(err)
}
defer c.Close()

cmd := exec.Command("echo")
cmd.Stdin = c.Tty()
cmd.Stdout = c.Tty()
cmd.Stderr = c.Tty()

err = cmd.Start()
if err != nil {
	log.Fatal(err)
}

c.Send("Hello world")
c.ExpectString("Hello world")
c.Tty().Close()
c.ExpectEOF()

err = cmd.Wait()
if err != nil {
	log.Fatal(err)
}
Output:

Hello world

func NewConsole

func NewConsole(opts ...ConsoleOpt) (*Console, error)

NewConsole returns a new Console with the given options.

func NewTestConsole

func NewTestConsole(t *testing.T, opts ...ConsoleOpt) (*Console, error)

NewTestConsole returns a new Console that multiplexes the application's stdout to go's testing logger. Primarily so that outputs from parallel tests using t.Parallel() is not interleaved.

func (*Console) Close

func (c *Console) Close() error

Close closes Console's tty. Calling Close will unblock Expect and ExpectEOF.

func (*Console) Expect

func (c *Console) Expect(opts ...ExpectOpt) (string, error)

Expect reads from Console's tty until a condition specified from opts is encountered or an error occurs, and returns the buffer read by console. No extra bytes are read once a condition is met, so if a program isn't expecting input yet, it will be blocked. Sends are queued up in tty's internal buffer so that the next Expect will read the remaining bytes (i.e. rest of prompt) as well as its conditions.

func (*Console) ExpectEOF

func (c *Console) ExpectEOF() (string, error)

ExpectEOF reads from Console's tty until EOF or an error occurs, and returns the buffer read by Console. We also treat the PTSClosed error as an EOF.

func (*Console) ExpectString

func (c *Console) ExpectString(s string) (string, error)

ExpectString reads from Console's tty until the provided string is read or an error occurs, and returns the buffer read by Console.

func (*Console) Expectf

func (c *Console) Expectf(format string, args ...interface{}) (string, error)

Expectf reads from the Console's tty until the provided formatted string is read or an error occurs, and returns the buffer read by Console.

func (*Console) Fd

func (c *Console) Fd() uintptr

Fd returns Console's file descripting referencing the master part of its pty.

func (*Console) Log

func (c *Console) Log(v ...interface{})

Log prints to Console's logger. Arguments are handled in the manner of fmt.Print.

func (*Console) Logf

func (c *Console) Logf(format string, v ...interface{})

Logf prints to Console's logger. Arguments are handled in the manner of fmt.Printf.

func (*Console) Read

func (c *Console) Read(b []byte) (int, error)

Read reads bytes b from Console's tty.

func (*Console) Send

func (c *Console) Send(s string) (int, error)

Send writes string s to Console's tty.

func (*Console) SendLine

func (c *Console) SendLine(s string) (int, error)

SendLine writes string s to Console's tty with a trailing newline.

func (*Console) Tty

func (c *Console) Tty() *os.File

Tty returns Console's pts (slave part of a pty). A pseudoterminal, or pty is a pair of psuedo-devices, one of which, the slave, emulates a real text terminal device.

func (*Console) Write

func (c *Console) Write(b []byte) (int, error)

Write writes bytes b to Console's tty.

type ConsoleCallback

type ConsoleCallback func(buf *bytes.Buffer) error

ConsoleCallback is a callback function to execute if a match is found for the chained matcher.

type ConsoleOpt

type ConsoleOpt func(*ConsoleOpts) error

ConsoleOpt allows setting Console options.

func WithCloser

func WithCloser(closer ...io.Closer) ConsoleOpt

WithCloser adds closers that are closed in order when Console is closed.

func WithDefaultTimeout

func WithDefaultTimeout(timeout time.Duration) ConsoleOpt

WithDefaultTimeout sets a default read timeout during Expect statements.

func WithExpectObserver

func WithExpectObserver(observers ...ExpectObserver) ConsoleOpt

WithExpectObserver adds an ExpectObserver to allow monitoring Expect operations.

func WithLogger

func WithLogger(logger *log.Logger) ConsoleOpt

WithLogger adds a logger for Console to log debugging information to. By default Console will discard logs.

func WithSendObserver

func WithSendObserver(observers ...SendObserver) ConsoleOpt

WithSendObserver adds a SendObserver to allow monitoring Send operations.

func WithStdin

func WithStdin(readers ...io.Reader) ConsoleOpt

WithStdin adds readers that bytes read are written to Console's tty. If a listed reader returns an error, that reader will not be continued to read.

func WithStdout

func WithStdout(writers ...io.Writer) ConsoleOpt

WithStdout adds writers that Console duplicates writes to, similar to the Unix tee(1) command.

Each write is written to each listed writer, one at a time. Console is the last writer, writing to it's internal buffer for matching expects. If a listed writer returns an error, that overall write operation stops and returns the error; it does not continue down the list.

type ConsoleOpts

type ConsoleOpts struct {
	Logger          *log.Logger
	Stdins          []io.Reader
	Stdouts         []io.Writer
	Closers         []io.Closer
	ExpectObservers []ExpectObserver
	SendObservers   []SendObserver
	ReadTimeout     *time.Duration
}

ConsoleOpts provides additional options on creating a Console.

type ExpectObserver

type ExpectObserver func(matchers []Matcher, buf string, err error)

ExpectObserver provides an interface for a function callback that will be called after each Expect operation. matchers will be the list of active matchers when an error occurred,

or a list of matchers that matched `buf` when err is nil.

buf is the captured output that was matched against. err is error that might have occurred. May be nil.

type ExpectOpt

type ExpectOpt func(*ExpectOpts) error

ExpectOpt allows settings Expect options.

func All

func All(expectOpts ...ExpectOpt) ExpectOpt

All adds an Expect condition to exit if the content read from Console's tty matches all of the provided ExpectOpt, in any order.

func Error

func Error(errs ...error) ExpectOpt

Error adds an Expect condition to exit if reading from Console's tty returns one of the provided errors.

func Regexp

func Regexp(res ...*regexp.Regexp) ExpectOpt

Regexp adds an Expect condition to exit if the content read from Console's tty matches the given Regexp.

func RegexpPattern

func RegexpPattern(ps ...string) ExpectOpt

RegexpPattern adds an Expect condition to exit if the content read from Console's tty matches the given Regexp patterns. Expect returns an error if the patterns were unsuccessful in compiling the Regexp.

func String

func String(strs ...string) ExpectOpt

String adds an Expect condition to exit if the content read from Console's tty contains any of the given strings.

func WithTimeout

func WithTimeout(timeout time.Duration) ExpectOpt

WithTimeout sets a read timeout for an Expect statement.

func (ExpectOpt) Then

func (eo ExpectOpt) Then(f ConsoleCallback) ExpectOpt

Then returns an Expect condition to execute a callback if a match is found for the chained matcher.

type ExpectOpts

type ExpectOpts struct {
	Matchers    []Matcher
	ReadTimeout *time.Duration
}

ExpectOpts provides additional options on Expect.

func (ExpectOpts) Match

func (eo ExpectOpts) Match(v interface{}) Matcher

Match sequentially calls Match on all matchers in ExpectOpts and returns the first matcher if a match exists, otherwise nil.

type Matcher

type Matcher interface {
	// Match returns true iff a match is found.
	Match(v interface{}) bool
	Criteria() interface{}
}

Matcher provides an interface for finding a match in content read from Console's tty.

type PassthroughPipe

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

PassthroughPipe is pipes data from a io.Reader and allows setting a read deadline. If a timeout is reached the error is returned, otherwise the error from the provided io.Reader is returned is passed through instead.

func NewPassthroughPipe

func NewPassthroughPipe(reader io.Reader) (*PassthroughPipe, error)

NewPassthroughPipe returns a new pipe for a io.Reader that passes through non-timeout errors.

func (*PassthroughPipe) Close

func (pp *PassthroughPipe) Close() error

func (*PassthroughPipe) Read

func (pp *PassthroughPipe) Read(p []byte) (n int, err error)

func (*PassthroughPipe) SetReadDeadline

func (pp *PassthroughPipe) SetReadDeadline(t time.Time) error

type ReaderLease

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

ReaderLease provides cancellable io.Readers from an underlying io.Reader.

func NewReaderLease

func NewReaderLease(reader io.Reader) *ReaderLease

NewReaderLease returns a new ReaderLease that begins reading the given io.Reader.

func (*ReaderLease) NewReader

func (rm *ReaderLease) NewReader(ctx context.Context) io.Reader

NewReader returns a cancellable io.Reader for the underlying io.Reader. Readers can be cancelled without interrupting other Readers, and once a reader is a cancelled it will not read anymore bytes from ReaderLease's underlying io.Reader.

type SendObserver

type SendObserver func(msg string, num int, err error)

SendObserver provides an interface for a function callback that will be called after each Send operation. msg is the string that was sent. num is the number of bytes actually sent. err is the error that might have occured. May be nil.

Jump to

Keyboard shortcuts

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