Netflix / go-expect

an expect-like golang library to automate control of terminal or console based programs.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

ExpectString panics

psparago opened this issue · comments

I'm just getting started with go-expect and I'm having difficulty getting a simple test to work. I'm not sure where else to post this because it's not really an issue, it's more of a request for help.

In my test app, I am spawning the Linux SSH client and sending commands. I need to capture the full output that was generated as I will parse through that later.

The issue I'm having is with the ExpectString calls. I get a panic when Expect() calls c.runeReader.ReadRune() (line 89) in bufio.go ReadRune() that the index of an input buffer that is used is out of range. (If I replace the Expects with sleeps, the whole thing works has expected).

Here's my code (sensitive info removed) and I don't know why the markdown is messed up:
`
func expectations() {
f, _ := os.Create("/tmp/log.log")
defer f.Close()

l := log.New(f, "logger: ", log.Lshortfile)

buf := new(bytes.Buffer)

c, err := expect.NewConsole(expect.WithStdout(os.Stdout), expect.WithStdout(buf), expect.WithLogger(l))
if err != nil {
	logit(err.Error())
	os.Exit(1)
}
defer c.Close()

cmd := exec.Command("bash", "-c", "sshpass -p 'topsecret' ssh -p 22 -o 'StrictHostKeyChecking no'  admin@10.0.0.0")
cmd.Stdin = c.Tty()
cmd.Stdout = c.Tty()
cmd.Stderr = c.Tty()

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

err = cmd.Start()
if err != nil {
	logit(err.Error())
	os.Exit(1)
}

count := 0
var e error
var s string
count, e = c.SendLine("")
logit(fmt.Sprintf("send: %d - %+v", count, e))
s, e = c.ExpectString("prompt#")
logit(fmt.Sprintf("expect: %s - %+v", s, e))
count, e = c.SendLine("some command")
logit(fmt.Sprintf("send: %d - %+v", count, e))
s, e = c.ExpectString("prompt#")
logit(fmt.Sprintf("expect: %s - %+v", s, e))
count, e = c.SendLine("another command")
logit(fmt.Sprintf("send: %d - %+v", count, e))
s, e = c.ExpectString("prompt#")
logit(fmt.Sprintf("expect: %s - %+v", s, e))
count, e = c.SendLine("logout")
logit(fmt.Sprintf("send: %d - %+v", count, e))
s, e = c.ExpectString("Logoff")
logit(fmt.Sprintf("expect: %s - %+v", s, e))

err = cmd.Wait()
if err != nil {
	logit(err.Error())
	//os.Exit(1)
}

logit(fmt.Sprintf("\n\n----------------------------------\n%s\n", buf.String()))

}
`

And the output (cleaned up). Note that the string of hashtags is a banner from the server:

send: 1 - /n

###############################panic: runtime error: index out of range

goroutine 20 [running]:
bufio.(*Reader).ReadRune(0xc000116240, 0x2, 0x2, 0x0, 0x6a75a0)
/usr/lib/golang/src/bufio/bufio.go:279 +0x257
github.com/Netflix/go-expect.(*Console).Expect(0xc0001140c0, 0xc000037780, 0x2, 0x2, 0x0, 0x0, 0x0, 0x0)
/home/device42/gocode/src/github.com/Netflix/go-expect/expect.go:89 +0x257
github.com/Netflix/go-expect.(*Console).ExpectEOF(0xc0001140c0, 0x0, 0x0, 0x0, 0x0)
/home/device42/gocode/src/github.com/Netflix/go-expect/expect.go:41 +0x6b
main.expectations.func1(0xc0001140c0)
/home/device42/gocode/go-gadgets/src/test/test.go:97 +0x2b
created by main.expectations
/home/device42/gocode/go-gadgets/src/test/test.go:96 +0x33d

I don't understand why the deferred c.ExpectEOF() is executing at this point.

Any ideas?

Thanks.

Hi @psparago, so the problem here is that you're calling c.ExpectEOF in a goroutine at the same time as calling other c.ExpectString, etc. I think what you want is to remove that goroutine and move that c.ExpectEOF after c.ExpectString("Logoff").

On our side, we'll need to fix that panic.

Hi @hinshun, Thank you sooo much for the immediate response. Moving the ExpectEOF worked! (That's what I get for copying an example I really didn't understand).

By we'll need to fix that panic, I assume you mean that if a dunderhead like me does what I did again, the package won't panic? In other words, I do not need to wait for a release of the package, is that correct?

It's not your fault, I think we're lacking documentation for this package. And yes, you don't need to wait for a new release, we should just have a better error message for this scenario.