New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
interp: test tty detection properly #512
Conversation
cf43d74
to
0c40cf6
Compare
@theclapp requesting a review, if you have a few minutes :) |
LGTM. As a bonus, I got the darwin test to pass (... though I haven't retested under Linux or Windows). As near as I can tell, on a Mac, once you close the tty, reading from the pty returns no data. Which kind of makes sense to me, but apparently isn't true under Linux. And I think I fixed the weird non-EOF error you occasionally(?) get out of creack/pty; see creack/pty#21, with a little help from @mattn in antonmedv/watch/pull/1, here. (Although, since I'm not closing the pty any more, maybe you wouldn't get that error any more? I dunno.) Here's the diff: diff --git a/interp/terminal_test.go b/interp/terminal_test.go
index fac138c..dd6379d 100644
--- a/interp/terminal_test.go
+++ b/interp/terminal_test.go
@@ -9,11 +9,10 @@ import (
"bytes"
"context"
"io"
- "io/ioutil"
"os"
"os/exec"
"runtime"
- "strings"
+ "syscall"
"testing"
"github.com/creack/pty"
@@ -37,9 +36,6 @@ func TestRunnerTerminalStdIO(t *testing.T) {
return b, b
}, "0\n1\n2\n"},
{"Pseudo", func(t *testing.T) (io.ReadWriter, io.Reader) {
- if runtime.GOOS == "darwin" {
- t.Skip("TODO: figure out why this case won't work on Mac")
- }
pty, tty, err := pty.Open()
if err != nil {
t.Fatal(err)
@@ -59,10 +55,6 @@ func TestRunnerTerminalStdIO(t *testing.T) {
if err := r.Run(context.Background(), file); err != nil {
t.Fatal(err)
}
- if closer, ok := stdio.(io.Closer); ok {
- // Otherwise the ReadAll below might get stuck.
- closer.Close()
- }
if got := testReadAll(t, out); got != test.want {
t.Fatalf("\nwant: %q\ngot: %q", test.want, got)
}
@@ -80,11 +72,15 @@ func testReadAll(t *testing.T, r io.Reader) string {
if r == nil {
return ""
}
- // the pty package can give a weird error instead of EOF
- bs, err := ioutil.ReadAll(r)
- if err != nil && !strings.Contains(err.Error(), "input/output error") {
+ buf := make([]byte, 1024)
+ n, err := r.Read(buf)
+ bs := buf[:n]
+ // See https://github.com/creack/pty/issues/21
+ if err != nil && err != io.EOF {
+ if pathErr, ok := err.(*os.PathError); !ok || pathErr.Err != syscall.EIO {
t.Fatal(err)
}
+ }
return string(bs)
}
|
Did you by any chance generate that patch via In any case - thanks so much for the help! I do give up on Mac affairs pretty quickly, simply because it's a nightmare to test on it. I think I was able to simplify your version a bit, and it still passes on Linux. I'll push and see if it still passes on Mac. |
0c40cf6
to
3daacfa
Compare
Ah, the Exec one still fails on Darwin, but you weren't reenabling that one. Hm. |
3daacfa
to
75cbf87
Compare
I think I'm wrapping my mind around the problem. I have a potential solution I'm trying out, which should be portable and non-racy. |
This includes two table-driven tests to detect whether FDs 0-3 are terminals. One uses the Go API with StdIO, without spawning a separate process, and another uses os/exec to run the interpreter in a separate process via TestMain. The cases are very similar, except that with pure Go we can fake a buffer to be a terminal via the IsTerm method. The exec method also has real FDs 0/1/2, versus the native version's, whose global FDs 0/1/2 belong go 'go test'. We remove the IsTerm interface too, as it was initially added mainly for testing, and it's no longer strictly needed. We can re-add it in the future as part of the API, if we think it's useful. We also add github.com/creack/pty, so that we can test a pseudoterminal in both cases. This isn't supported on Windows, so don't run the tests there. While at it, switch from x/crypto to x/term for IsTerminal. It's the new home for this API, and the module is far smaller. Finally, a few changes to the 'test -t' logic needed to be made to properly support all of the combinations above. The mistakes in the old code were correctly spotted by Larry Clapp. Thanks to Larry once again for helping get the pty tests working on Mac. Fixes #508, again.
75cbf87
to
411baf2
Compare
Yes.
:( Sorry
🎉
Yeah, will do. |
OK, so here are the major takeaways:
Then, I resorted to having the master/writer close the connection. This worked most of the time, but it was racy - if the reader hadn't had time to read all of the bytes we want, it could end up with EOF, or an even worse error like "pipe already closed". The root of the problem here is that neither side knows when we're "done". Each test case writes a different number of bytes, so we don't know either. I fixed this by forcing every test case to expect exactly one line of output. This way, the reader can stop as soon as it's read one line, and the writer can then close. Phew :) @theclapp if you're happy with the latest patch, I'll merge. It seems all green, and there are no skips. |
LGTM. Can't test it right now, myself. I'd say, ship it. Thanks for working on this! |
See the commit message.