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

Capturing stdout from test code is inconsistent #12309

Closed
MicahChalmer opened this issue Feb 16, 2014 · 22 comments
Closed

Capturing stdout from test code is inconsistent #12309

MicahChalmer opened this issue Feb 16, 2014 · 22 comments
Labels
A-libtest Area: #[test] related C-enhancement Category: An issue proposing an enhancement or a PR with one. P-low Low priority T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.

Comments

@MicahChalmer
Copy link
Contributor

The feature that captures "stdout" for tests doesn't capture all the ways that a test could print to stdout.

#[test]
fn output_capture_tests() {
    println!("This gets captured...");
    let _ = std::io::stdout().write_line("but this does not...");
    let _ = std::task::try(proc() { println!("..and neither does this...") });
    let _ = std::run::process_status("/bin/echo", [~"...nor this..."]);
    fail!();
}

Only the first println! call gets captured--the rest appear intermingled with the test output:

running 1 test
but this does not...
..and neither does this...
...nor this...
test output_capture_tests ... FAILED

failures:

---- output_capture_tests stdout ----
    This gets captured...
    task 'output_capture_tests' failed at 'explicit failure', subproc-test-stdout.rs:7


failures:
    output_capture_tests

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured

It would be nice if all of these got captured.

@alexcrichton
Copy link
Member

In my opinion, the only real bug here is that the child task's println isn't captured. Capturing stdout/stderr is not supposed to be comprehensive, it's supposed to clean up the output.

You'll almost always be able to subvert whatever capturing is going on, it's not supposed to be exhaustive.

@MicahChalmer
Copy link
Contributor Author

Ok, so std::io::stdout() will always hit the process-wide FD 1 (not task-local), whereas the functions in std::io::stdio will write to a task-local "stdout" which could be redirected at spawn time. Perhaps the task-local "stdout" should have a different name? Otherwise this could get rather confusing. I think people will expect the term "stdout" to always refer to the process global version. "Task default output" maybe?

If the task-local one is still going to be named "stdout", then I think the documentation will need to be updated in a lot of places to make it explicit which "stdout" is being used. For instance, the documentation of std::io::stdio::println refers to "the stdout of the current process"--but that's no longer the case, now it's "the stdout of the current task" (and probably an explanation of how that is not the same thing as the stdout of the current process.)

Once that distinction is clear, it's natural to assume that child processes will inherit the process global FD, so I see why that's not a bug. It's easy enough to capture the output and print it to the task's "stdout".

@steveklabnik
Copy link
Member

This is still true today with Thread::scoped.

@aturon
Copy link
Member

aturon commented Feb 16, 2015

Nominating for 1.0-beta P-backcompat-libs. We need to finalize our capture story.

@pnkfelix
Copy link
Member

1.0 beta, P-backcompat-libs, I-needsdecision

@pnkfelix pnkfelix added this to the 1.0 beta milestone Feb 19, 2015
@pnkfelix pnkfelix added I-needs-decision Issue: In need of a decision. P-backcompat-libs and removed I-nominated labels Feb 19, 2015
@aturon
Copy link
Member

aturon commented Mar 24, 2015

triage: (1.0)

@aturon
Copy link
Member

aturon commented Mar 24, 2015

triage: P-high (1.0)

@rust-highfive rust-highfive added P-medium Medium priority and removed P-backcompat-libs labels Mar 24, 2015
@rust-highfive rust-highfive modified the milestones: 1.0, 1.0 beta Mar 24, 2015
@alexcrichton alexcrichton self-assigned this Apr 2, 2015
@steveklabnik steveklabnik removed this from the 1.0 milestone May 21, 2015
sgrif added a commit to diesel-rs/diesel that referenced this issue Jan 31, 2016
Rust *should* be swallowing all stdout output during test runs, but for
some reason it isn't. This appears to be due to
rust-lang/rust#12309. However, we can't have
out test suite spam to the point of unreadability until that's fixed, so
let's just not output from migrations during tests.

This was paired, so it has been committed without PR.

Fixes #156.
sgrif added a commit to diesel-rs/diesel that referenced this issue Feb 3, 2016
Rust *should* be swallowing all stdout output during test runs, but for
some reason it isn't. This appears to be due to
rust-lang/rust#12309. However, we can't have
out test suite spam to the point of unreadability until that's fixed, so
let's just not output from migrations during tests.

This was paired, so it has been committed without PR.

Fixes #156.
sgrif added a commit to diesel-rs/diesel that referenced this issue Feb 3, 2016
Rust *should* be swallowing all stdout output during test runs, but for
some reason it isn't. This appears to be due to
rust-lang/rust#12309. However, we can't have
out test suite spam to the point of unreadability until that's fixed, so
let's just not output from migrations during tests.

This was paired, so it has been committed without PR.

Fixes #156.
@dbrgn
Copy link
Contributor

dbrgn commented Mar 16, 2016

I also stumbled over this issue when starting a test server as a child process. The stdout logged by the server does not get captured.

While I could redirect the output to /dev/null, that makes it hard to debug problems. On the other hand, allowing the stdout to be printed causes pages of unnecessary output, making it hard to see the actual test results.

@brson brson added P-low Low priority T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. and removed P-medium Medium priority labels Oct 20, 2016
@nagisa
Copy link
Member

nagisa commented Oct 20, 2016

@alexcrichton just an idea, but how about we use something like freopen (and dup to keep stdout around as a different fd) to replace the stdout file descriptor for the duration of the testing? It should be cheap enough to be able to do that for tests, it would also capture all sorts of outputs and would let us to avoid having that weird thread-local stdout overwrite code we have now.

@retep998
Copy link
Member

@nagisa Can't use freopen to deal with Rust's stdout on Windows.

@alexcrichton
Copy link
Member

@nagisa sounds plausible to me, I think there may also be ways to muck around with this on Windows as well. We'd likely still need to fiddle with private APIs in the standard library, however, as on Windows at least we cache the handles returned by the system so if they're reset we'd have to bust that cache.

@nagisa
Copy link
Member

nagisa commented Oct 20, 2016

@retep998 SetStdHandle?

@retep998
Copy link
Member

@nagisa If Rust didn't cache the result of GetStdHandle, then yes that would work.

@alexcrichton alexcrichton removed their assignment Feb 16, 2017
@Mark-Simulacrum Mark-Simulacrum added the A-libtest Area: #[test] related label Jun 20, 2017
@Mark-Simulacrum Mark-Simulacrum added C-enhancement Category: An issue proposing an enhancement or a PR with one. and removed I-needs-decision Issue: In need of a decision. labels Jul 20, 2017
@sanmai-NL
Copy link

sanmai-NL commented Feb 17, 2018

@alexcrichton: these many reports and suggestions for improvement can be circumvented by removing the whole output capturing code and instead optionally report test outcomes as JSON messages on stdout, and assume tests themselves do not pollute stdout. Then we’d be done with these annoyances without putting in effort to unbreak output capturing. Are you open to a PR?

Also, this issue should be moved to the Cargo issue tracker.

@alexcrichton
Copy link
Member

@sanmai-NL I think that such a PR would unfortunately be a breaking change and as a result needs to be considered a little more carefully (e.g. with the dev-tools team). This is still a rustc issue as-is so I don't think it should move.

@Mark-Simulacrum
Copy link
Member

Going to go ahead and close this as a duplicate of #42474.

@glts
Copy link

glts commented Nov 29, 2022

I suggest that this issue be reopened. It has not been fixed, and there is no explanation for why it should not be considered further, either above or in the linked issue.

I believe it is a current best practice to use writeln!(std::io::stdout())? in place of println! in programs that should not panic on I/O error. However, this idiom results in stdout not being captured.

@mathstuf
Copy link
Contributor

I think this is the issue to keep open; #42474 is "fixed" in that output is now captured. It is just "inconsistent".

FWIW, there will always be a way "around" it (talking to /dev/tty, using fd 1, etc.). Unless there's some mangling going on under cfg(test), what kinds of effects would std::io::stdout() checking some TLS structure add to non-test code?

For child processes, there would need to be some file descriptor/handle juggling in std::process to detect cfg(test) and relocate the file descriptors if not otherwise set. This also leaves things like tokio::process in the dark unless the test crate grows some APIs to use (and stabilizes them).

@mathstuf
Copy link
Contributor

The docs for std::oi::stdout state:

Constructs a new handle to the standard output of the current process.

I don't think that can get an asterisk for "unless running from a #[test] function in which case it is a handle to the capture output (if any)". Note that this also gives a way to guarantee bypassing any such capturing (assuming fd 1 isn't closed…which makes me think "what is the behavior on a closed fd 1 here? how about read-only?"). Similarly for std::process, bypassing may or may not be wanted in different contexts. That sounds like API design and, again, dependent upon the test crate being stabilized anyways.

@Finomnis
Copy link
Contributor

@Mark-Simulacrum Please re-open, this is not actually a duplicate, and the problem still persists.

@Houtamelo
Copy link

@Mark-Simulacrum Please re-open, this is not actually a duplicate, and the problem still persists.

If not fixed, this should at least be on the documentation.

@Mark-Simulacrum
Copy link
Member

#90785 appears to be the current issue tracking this.

flip1995 pushed a commit to flip1995/rust that referenced this issue Feb 26, 2024
fix: make `#[allow]` work on field for `pub_underscore_fields`

Closes rust-lang#12286

changelog: `#[allow(clippy::pub_underscore_fields)]` now works on linted field
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-libtest Area: #[test] related C-enhancement Category: An issue proposing an enhancement or a PR with one. P-low Low priority T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests