Skip to content

testscript: add waitmatch command - #311

Merged
mvdan merged 2 commits into
rogpeppe:masterfrom
mvdan:waitmatch
Oct 2, 2026
Merged

mvdan merged 2 commits into
rogpeppe:masterfrom
mvdan:waitmatch

Conversation

@mvdan

@mvdan mvdan commented Sep 30, 2026

Copy link
Copy Markdown
Collaborator

(see commit messages - please do not squash)

@rogpeppe rogpeppe left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

LGTM modulo a few suggestions and comments.

Comment thread testscript/doc.go Outdated
Comment on lines +253 to +254
'&command&' to print a line to standard output, or to standard error with
-stderr, which matches the regular expression pattern. This is useful to

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

The distance between "print a line" and "which matches" reads awkwardly to me.

Suggested change
'&command&' to print a line to standard output, or to standard error with
-stderr, which matches the regular expression pattern. This is useful to
'&command&' to print a line matching the regular expression pattern.
It matches against the command's standard output unless -stderr is specified.
This is useful to

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Also, I wonder if it should be possible to specify the timeout explicitly: some commands might legitimately take a long time to run.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Applied, thanks.

As for a timeout: waitmatch does not impose one of its own. It waits until the command exits or the test deadline is reached, so commands which take a long time already work. An explicit timeout would only let a script fail sooner than the test deadline, which we could add later without breaking anything if someone needs it.

Comment thread testscript/testscript.go Outdated

// next returns the output written so far,
// along with a channel which is closed when more output is written.
func (o *backgroundOutput) next() (string, <-chan struct{}) {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

It seems a bit odd to me that this returns the entire output (allocating the entire buffer each time) when the command this is intended for only wants to see newly added bytes.

I wonder whether it might work out more nicely to have something like:

// reader returns a reader that produces the text written to o.
// If the context is cancelled, the final read will return ctx.Err().
func (o *backgroundOutput) reader(ctx context.Context) io.Reader
//

then we can just use `bufio.Scanner` to implement the `waitmatch` command,
and that'll work with \r\n terminated lines too, and probably be a decent amount simpler (although perhaps we'll trade off too much complexity here...)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Good idea, done: waitmatch is now a bufio.Scanner over a reader of the buffer, which is quite a bit simpler. For what it is worth, next did not allocate, as strings.Builder.String does not copy the buffer.

Comment thread testscript/cmd.go Outdated
break
}
scanned += len(line) + 1
if m := re.FindStringSubmatch(line); m != nil {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

ISTM that we should be catering for \r\n line termination here, and that as written, if a command produces \r\n as a line endinng, we probably won't match it against $.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Good catch, confirmed. Fixed by the switch to bufio.Scanner, which drops a trailing \r, and I added a CRLF test case.

mvdan added 2 commits October 2, 2026 17:17
It waits for a background command to print a line matching a regular
expression, optionally setting variables to its subexpressions.
This lets a script wait for a server to be ready, for example one which
listens on a port chosen by the kernel and prints its address.

To read the output of a running command, background commands now write
to a buffer which is safe for concurrent use and signals new writes.
waitmatch fails if the command exits without printing a matching line,
or if the test times out first.
signalcatcher now prints a line once it is ready to catch a signal,
rather than creating a file which the test had to poll for,
so the waitfile test command is no longer needed.
@mvdan
mvdan merged commit ce71b23 into rogpeppe:master Oct 2, 2026
6 checks passed
@mvdan
mvdan deleted the waitmatch branch October 2, 2026 20:22
cueckoo pushed a commit to cue-lang/cue that referenced this pull request Oct 4, 2026
See rogpeppe/go-internal#311.

Signed-off-by: Daniel Martí <mvdan@mvdan.cc>
Change-Id: I76ecaa62e52a3cb06d910e628437274704edcaea
GitOrigin-RevId: 890c324e1754ed1567d58771d1f79ece910f5dda
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.

2 participants