ExpectString panics
psparago opened this issue · 3 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.