Open colin-kiegel opened 7 years ago
Do you think this might be a bug in cargo check
or in rust-skeptic
?
PS: I can't locate the file /tmp/rust-skeptic.ocUVTbTQ1DCk/test.rs:1:1
from the error message above. All I can find is this
./target/debug/build/cargo_check_bug-899f203356c46842/out/skeptic-tests.rs
extern crate skeptic;
#[test] fn readme_0() {
let ref s = format!("{}", r####"extern crate cargo_check_bug;
fn main() {
}
"####);
skeptic::rt::run_test(r#"/home/colin/projects/rust/cargo_check_bug/target/debug/build/cargo_check_bug-899f203356c46842/out"#, s);
}
ok, looks like something has changed between rust-skeptic
v0.6.x and v0.7.1.
https://github.com/brson/rust-skeptic/compare/master@%7B2016-08-12%7D...master@%7B2017-02-26%7D
It looks like this commit https://github.com/brson/rust-skeptic/commit/205f426928408dcd6bebc719b376e11acbee0906 from @oli-obk fixed it for ordinary libs. But I can still reproduce this error if the library is a proc-macro!
Since an update of skeptic changed the error, I believe the remaining error is also related to skeptic (and not cargo check).
PS: I can confirm, that removing test/skeptic.rs
eliminates the error - both in this toy crate and in derive_builder
.
Any news on this?
It's a bit problematic that I get nonsense failing tests, if I activate skeptic tests (+cargo cache) on travis https://travis-ci.org/colin-kiegel/rust-derive-builder/jobs/219789090#L644
I'm already using skeptic 0.8.1.
The only workaround I know is to always run cargo clean
before cargo test
, but I would prefer to benefit from faster travis builds using its cargo cache feature.
@colin-kiegel Thanks for the great report and investigation, and again sorry I haven't responded earlier.
This kind of sporadic crate resolution failure is because skeptic's tests aren't passing the --extern
flags to rustc needed to disambiguate between multiple crate candidates, like
--extern skeptic_readme=/mnt2/dev/rust-skeptic/target/debug/deps/libskeptic_readme-77286c6085960cab.rlib
This happens when versions change and cargo leaves old deps around. Normally this doesn't matter because cargo properly passes --extern
flags to everything it builds. Skeptic though runs rustc
itself as part of cargo test
, and doesn't actually know the correct values (cargo does not communicate these values to build scripts).
This is a pretty big limitation of skeptic presently, and the workaround is to cargo clean
beforehand.
I'm surprised this looks like a regression to you, since I consider it a long-standing bug, put probably something about skeptic and/or cargo changed to exacerbate the problem, and there may be especially weird stuff going on with proc macros.
The best solution would be for cargo could to pass the names of various libraries to the build script, assuming it knows them that far ahead of time.
In the meantime, I think it would be possible for skeptic to maintain a cache of knowledge about the deps folder and use heuristics to make a pretty good guess about which libs are the most fresh.
PS: I can't locate the file /tmp/rust-skeptic.ocUVTbTQ1DCk/test.rs:1:1 from the error message above. All I can find is this
This is a tempfile that is deleted during test execution. It would be nice if there were some way to tell skeptic not to delete them for debugging purposes.
Ok, it's already good to know that this is a known limitation and cargo clean is the only known workaround.
Hm, this would probably benefit a lot if cargo introduced some testing plugin slot, or some other query mechanism (maybe on nightly only). Compiletests seem to have similar problems. There it already starts with finding the right target directory, which can be a problem in workspaces.
I'm not familiar with cargo plugins. But could it help to introduce a cargo skeptic
or cargo query
subcommand? I could imagine that cargo plugins might already have some access to these kinds of information, no?
PS: I'm not sure how involved that is (or if it is even comparable), but cargo clippy
seems to be doing a good job here. I never experienced these problems with clippy.
Cargo clippy forwards to cargo rustc and injects a custom compiler through the RUSTC env var. This way we avert these issues entirety. But it has the downside of overwriting the RUSTC env var and thus breaking builds that set it. This is an open issue in clippy
that sounds like this might work for skeptic, too. And I think skeptic wouldn't need to inject a custom compiler, right?
I'm not familiar with cargo plugins. But could it help to introduce a cargo skeptic or cargo query subcommand? I could imagine that cargo plugins might already have some access to these kinds of information, no?
Unfortunately cargo plugins have no special information. They are just executables that cargo runs - there's no info passed between them.
Cargo clippy forwards to cargo rustc and injects a custom compiler through the RUSTC env var. This way we avert these issues entirety. But it has the downside of overwriting the RUSTC env var and thus breaking builds that set it. This is an open issue in clippy
I can't quite imagine a way to fix this issue for skeptic by intercepting rustc itself, but if there is such a solution it may be worth pursuing.
One plausible way to fix this would be to have skeptic synthesize an entire cargo project from the original cargo project, for every test it generates, sharing target directories. Then run cargo instead of rustc, and have cargo figure out the deps.
I'm marking this help wanted, to try to implement the 'synthesize-a-cargo-project' solution I suggested previously. It doesn't seem all that complex to do.
@brson I have a very dirty POC implemented (cargo project synthesized and cargo build / run for each example) and it works in solving this particular issue but there are two problems:
Blocking waiting for file lock on the registry index
Blocking waiting for file lock on the registry index
Blocking waiting for file lock on the registry index
Blocking waiting for file lock on build directory
I guess that another approach would be needed. I was wondering if there would be a way to generate separate test files for the project that would just share the original Cargo.toml and could be run concurrently with single cargo test
, but I don't know if it would be ok to overwrite users tests
dir or if it's possible to add another dir to cargo.toml that would be treated with the same semantics as the tests
dir.
Edit: Writing separate test files (with contents of each playpen) to tests
dir might work but the usage would be severely limited:
#[test]
annotationOn the other hand:
I'm thinking about alternative approach. Parsing projects Cargo.lock to find all dependencies and their versions from "dependencies" section. Then match these with metadata from ./target/debug/.fingerprint/
like "local" -> "precalculated" section for lib-bitflags-40c9799a6d297c75.json
"local": {
"Precalculated": "0.9.1"
},
And link tests only to the direct dependencies from Cargo.lock. In case there are duplicated rlibs for given semver (which happens in some cases when we do not do cargo clean) we would just chose the rlib with latest mtime.
Unfortunately I don't know how stable are the .fingerprint
contents between cargo versions (I suspect there might be no guarantees). I'll try make a POC sometime this week.
@budziq if that route is viable then it sounds awesome. I did not know it was possible to correlate specified dependencies with the resulting crate names.
While it is more rare for me to it this, I still do from time to time.
For example, right now with assert_cli:
running 4 tests
error[E0464]: multiple matching crates for `assert_cli`
--> /tmp/rust-skeptic.FmBU3mlPuvYC/test.rs:2:14
|
2 | #[macro_use] extern crate assert_cli;
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: candidates:
= note: crate name: assert_cli
= note: path: /home/epage/git/assert_cli/target/debug/deps/libassert_cli-d4ab2d90a07c5712.rlib
= note: crate name: assert_cli
I confirmed in my Cargo.lock that I am using 0.13.2
Thanks @epage, I'll try to look into it later this weekend. Do you have some reliable way to reproduce it? I did not encounter this problem for quite a while.
Looks like I'm reproducing it consistently with assert_cli.
If anyone familiar with skeptic is at RustBelt, they can catch me and we can look at it together.
If anyone is having trouble with this issue and does not need compile-fail tests I create a fork with https://crates.io/crates/little-skeptic . (See #78 for a full explanation)
Oops, forgot to past back here about docmatic, my lite version based on people's hacks here https://github.com/assert-rs/docmatic
Yeah I've seen both of your crates today. I'm sorry that you had to seek an alternative solution due to me being unable to commit more time to skeptic :/ Hope to free some bandwidth in the upcoming months ...
I've started hacking on a fix for this that emits every test case as an individual cargo project, sharing the target directory with the "master" project.
Another way to tackle this problem is to use cargo's unstable --build-plan
flag, which looks like it contains enough metadata to find the correct libraries. I'm not pursuing that right now, because I think the every-test-case-a-cargo-project will be more reliable, not depending on skeptic to invoke rustc correctly.
Hi @brson nice to see you!
I've started hacking on a fix for this that emits every test case as an individual cargo project, sharing the target directory with the "master" project.
I've tried this approach way back, the problem was that it much slower and concurrent cargo instances working on the same target directory tended to congest due to internal file locking and the execution became sequential (with addition of the much longer cargo calls). It was especially painful on largeish testsets like cookbook. But the situation might have improved recently.
The --build-plan
approach was what Alex Crichton suggested some time ago once it is stable.
Anyhow I'm game for any changes that improve the situation.
Thanks for the feedback @budziq! I'm pretty far down this rabbit hole now, so I'll see for myself the problems you encountered.
I do have an idea I mentioned in #8 for combining every test case into a single binary such that cargo build
only needs to be executed once for the entire test set. That would hopefully be much faster than running cargo build
for every test.
Ok, it's not in a mergable state yet, but here's a branch that overhauls how tests are run, using cargo to deal with resolution: https://github.com/budziq/rust-skeptic/compare/master...brson:next
I think this approach is much cleaner than the current, and will behave in more cases like would be expected.
It fixes this issue, but it slows down testing of rust-cookbook by about 11% (on WSL - results might be better on linux) re https://github.com/budziq/rust-skeptic/issues/8.
The performance of this approach can be improved still. I'll keep hacking at it.
I get a weird error when I use the combination of:
rust-skeptic
cargo check
cargo test
proc_macro
crateThis looks like a skeptic (or cargo check) bug and it is dependent on the order of
cargo check
andcargo test
.Steps to reprodroduce
git clone https://github.com/colin-kiegel/cargo_check_bug.git
cd cargo_check_bug
rustup override set nightly-2017-03-03
cargo clean && cargo test && cargo check
cargo clean && cargo check && cargo test
Result of Step 4
Everything OK!
Result of Step 5
error[E0464]: multiple matching crates for `cargo_check_bug`
Cargo.toml
build.rs
README.md
tests/skeptic.rs
src/lib.rs