Skip to content
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

testscript: add pty/ptyout commands #172

Merged
merged 2 commits into from Aug 7, 2023
Merged

Conversation

FiloSottile
Copy link
Contributor

This allows testing commands that open /dev/tty to interact with the user separately from stdin/stdout, like age.

See https://github.com/FiloSottile/age/blob/084c974f5393e5d2776fb1bb3a35eeed271a32fa/cmd/age/testdata/terminal.txt and https://github.com/FiloSottile/age/blob/084c974f5393e5d2776fb1bb3a35eeed271a32fa/cmd/age/testdata/scrypt.txt for example scripts.

@mvdan
Copy link
Collaborator

mvdan commented Jul 28, 2022

I'm slightly worried about adding a hard dependency on creack/pty, which is not a small library. I understand that testscript is for testing CLIs and this is an important feature to support, but I imagine it would be nicer to allow plugging in any PTY library. That would be more flexible long-term, and would keep the amount of dependencies small for the majority of users who don't need this feature.

@FiloSottile
Copy link
Contributor Author

Pluggable PTY libraries sounds complex to me, and they have a relatively simple job: opening a pair of file descriptors that work as a virtual terminal. If that's the only blocker, I can probably reimplement the ~40% of creack/pty we need, especially if you're only targeting macOS and Linux.

@mvdan
Copy link
Collaborator

mvdan commented Jul 28, 2022

I have historically only used creack/pty on unix-y systems, but I'm not sure if trying to use it on Windows makes sense :)

To be clear, what I mean by pluggable is to keep your patch as-is, but abstract away the Open, Write, and Close calls to an interface that's satisfied by the library. That doesn't sound particularly complex to me, and gives the downstream the ability to choose which libraries to incorporate. As you can see we've been very careful about adding dependencies, and we're even trying to get rid of pkg/diff soon. The only dependency I think we'll want to add in the near term is x/tools, for the sake of forwarding now-redundant packages like txtar.

@mvdan
Copy link
Collaborator

mvdan commented Jul 28, 2022

Also: perhaps @rogpeppe or @myitcv disagree with me

@FiloSottile
Copy link
Contributor Author

Rebased and removed the creack/pty dependency. Opening a PTY pair is really just a OpenFile and a couple IOCTLs.

Copy link
Collaborator

@mvdan mvdan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks reasonable to me - it just needs a test, which would perhaps double as an example of how it can be used.

cc @rogpeppe for thoughts. My main objection was the added dependency, but 200 lines of code isn't particularly worrisome given that this feature is likely to be useful to some testscript users.

testscript/doc.go Outdated Show resolved Hide resolved
@FiloSottile
Copy link
Contributor Author

Test added! Testing -stdin would require a dependency on x/term or more IOCTLs and it didn't feel worth it.

Copy link
Owner

@rogpeppe rogpeppe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have quite mixed feelings about this PR (I started reviewing it ages ago and didn't complete the review because of that). On the one hand, it seems like it's definitely useful in some circumstances. On the other, it introduces a bunch of very system-dependent code that feels a bit out of place here. It also feels like a bit of a slippery slope: once we've got the ability to talk to a terminal, why not testing of arbitrary interactions? It does seem like the primitives provided here aren't quite enough to make this that useful without some more customisation (for example, tty output will commonly have control characters such as cr-lf sequences, but txtar files aren't well set up for making that clear so that cmp will work OK, for example).

On balance, I just about fall across the line of "OK", but it's a close-run thing!

I wonder about moving the pty-specific stuff into an internal/pty package so that the system-specific stuff is more cleanly delineated.

Also, this definitely needs a test.

testscript/cmd.go Outdated Show resolved Hide resolved
testscript/pty_darwin.go Outdated Show resolved Hide resolved
testscript/pty_darwin.go Outdated Show resolved Hide resolved
testscript/pty_unix.go Outdated Show resolved Hide resolved
testscript/pty_windows.go Outdated Show resolved Hide resolved
<-doneR
<-doneW
ts.ptyin = ""
ts.ptyout = ptyBuf.String()
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand how this isn't racy - it doesn't synchronize with anything after setting this field, so I don't see how a happens-before relationship can be formed between this write and the read that happens to check its value.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I'm missing some feature, but I think there's simply no concurrency between the exec command and the ttyout/cmp/... commands?

testscript/pty_unix.go Outdated Show resolved Hide resolved
testscript/testscript_test.go Show resolved Hide resolved
testscript/cmd.go Outdated Show resolved Hide resolved
testscript/pty_unix.go Outdated Show resolved Hide resolved
Copy link
Contributor Author

@FiloSottile FiloSottile left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the review and sorry for the lag, I had somehow missed it and only saw it as I was checking in yesterday.

It does seem like the primitives provided here aren't quite enough to make this that useful without some more customisation (for example, tty output will commonly have control characters such as cr-lf sequences, but txtar files aren't well set up for making that clear so that cmp will work OK, for example).

FWIW I am using this as-is in age. I mostly need to check that the logic for using the terminal is correct, so ttyout patterns work for that.

testscript/cmd.go Outdated Show resolved Hide resolved
testscript/cmd.go Outdated Show resolved Hide resolved
testscript/pty_darwin.go Outdated Show resolved Hide resolved
testscript/pty_unix.go Outdated Show resolved Hide resolved
testscript/pty_unix.go Outdated Show resolved Hide resolved
testscript/pty_unix.go Outdated Show resolved Hide resolved
testscript/pty_windows.go Outdated Show resolved Hide resolved
testscript/testscript_test.go Show resolved Hide resolved
<-doneR
<-doneW
ts.ptyin = ""
ts.ptyout = ptyBuf.String()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I'm missing some feature, but I think there's simply no concurrency between the exec command and the ttyout/cmp/... commands?

testscript/pty_darwin.go Outdated Show resolved Hide resolved
@FiloSottile FiloSottile force-pushed the filippo/pty branch 3 times, most recently from 8b3284c to d6f5598 Compare February 9, 2023 16:54
Copy link
Owner

@rogpeppe rogpeppe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM; thanks for bearing with me all this time. I still don't like all the crap this adds, and the general poor usability (why can we do cp stdout foo but not cp ttyout foo for example?), but I don't see much alternative, and we can hopefully improve things in the future without breaking compatibility.

Copy link
Owner

@rogpeppe rogpeppe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM; thanks for bearing with me all this time. I still don't like all the crap this adds, and the general poor usability (why can we do cp stdout foo but not cp ttyout foo for example?), but I don't see much alternative, and we can hopefully improve things in the future without breaking compatibility.

@FiloSottile
Copy link
Contributor Author

Sweet, thank you for the reviews! Resolved the conflict, should be ready to merge.

@mvdan
Copy link
Collaborator

mvdan commented May 17, 2023

@FiloSottile you got a 10m pty testscript timeout on macos on 1.20 there, any idea what might have happened? it succeeded on macos on 1.19, so perhaps it's a race or flakiness of some sort.

@FiloSottile
Copy link
Contributor Author

@FiloSottile you got a 10m pty testscript timeout on macos on 1.20 there, any idea what might have happened? it succeeded on macos on 1.19, so perhaps it's a race or flakiness of some sort.

Turns out it's a os Go 1.20 regression. golang/go#61779

@FiloSottile
Copy link
Contributor Author

Rebased and added a skip for golang/go#61779.

@mvdan
Copy link
Collaborator

mvdan commented Aug 7, 2023

Thanks!

@mvdan mvdan merged commit 3fbe0b6 into rogpeppe:master Aug 7, 2023
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants