Closed flub closed 11 months ago
Just leaving a 👍 for this. Really enjoying using testdir
, but nexttest definitely causes some issues with paths disappearing unexpectedly!
I ended up copying a bunch of the logic out of testdir
into my work, to fast track a nextest compatible version of testdir
.
This is mainly to serve as an example, and would require a different approach for integrating the changes into testdir
proper.
At its core, there is a second reusefn
needed to support nextest
, and a test against the NEXTEST
env var to decide when to use it:
pub(crate) mod nextestdir {
use std::path::Path;
const NEXTEST_RUN_ID_FILE_NAME: &str = "nextest-run-id";
pub(crate) fn reuse_nextest(dir: &Path) -> bool {
let file_name = dir.join(NEXTEST_RUN_ID_FILE_NAME);
if let Ok(content) = std::fs::read_to_string(file_name) {
if let Ok(read_nextest_run_id) = content.parse::<String>() {
if let Ok(nextest_run_id) = std::env::var("NEXTEST_RUN_ID") {
return read_nextest_run_id == nextest_run_id;
}
}
}
false
}
pub(crate) fn create_nextest_run_id_file(dir: &Path) {
if let Ok(nextest_run_id) = std::env::var("NEXTEST_RUN_ID") {
let file_name = dir.join(NEXTEST_RUN_ID_FILE_NAME);
if !file_name.exists() {
std::fs::write(&file_name, nextest_run_id.to_string())
.expect("Failed to write nextest run ID");
}
}
}
pub(crate) fn with_nextesdir<F, R>(func: F) -> R
where
F: FnOnce(&testdir::NumberedDir) -> R,
{
let test_dir = testdir::TESTDIR.get_or_init(|| {
let mut builder =
testdir::NumberedDirBuilder::new(String::from("init_testdir-not-called"));
builder.reusefn(reuse_nextest);
let testdir = builder.create().expect("Failed to create testdir");
create_nextest_run_id_file(testdir.path());
testdir
});
func(test_dir)
}
}
/// Specialized version of testdir::init_testdir!() that will work with nextest
macro_rules! init_nextestdir {
() => {{
testdir::TESTDIR.get_or_init(move || {
let parent = match testdir::private::cargo_metadata::MetadataCommand::new().exec() {
Ok(metadata) => metadata.target_directory.into(),
Err(_) => {
// In some environments cargo-metadata is not available,
// e.g. cargo-dinghy. Use the directory of test executable.
let current_exe = ::std::env::current_exe().expect("no current exe");
current_exe
.parent()
.expect("no parent dir for current exe")
.into()
}
};
let pkg_name = "testdir";
let mut builder = testdir::NumberedDirBuilder::new(pkg_name.to_string());
builder.set_parent(parent);
builder.reusefn(crate::nextestdir::reuse_nextest);
let testdir = builder.create().expect("Failed to create testdir");
crate::nextestdir::create_nextest_run_id_file(testdir.path());
testdir
})
}};
}
/// Specialized version of testdir::testdir!() that will work with nextest
macro_rules! nextestdir {
() => {{
init_nextestdir!();
let module_path = ::std::module_path!();
let test_name = testdir::private::extract_test_name(&module_path);
let subdir_path = ::std::path::Path::new(&module_path.replace("::", "/")).join(&test_name);
crate::nextestdir::with_nextesdir(move |tdir| {
tdir.create_subdir(subdir_path)
.expect("Failed to create test-scope sub-directory")
})
}};
}
/// Compatible layer to give us either testdir!() or nextestdir!()
macro_rules! testdir_compat {
() => {{
let is_nextest = if let Ok(nextest) = std::env::var("NEXTEST") {
if let Ok(read_nextest) = nextest.parse::<i32>() {
read_nextest == 1
} else {
false
}
} else {
false
};
if is_nextest {
nextestdir!()
} else {
testdir::testdir!()
}
}};
}
awesome! thanks for these pointers, I still haven't managed to find time to work on this but this certainly will speed things up!
(if you feel like making a PR out of this that'd also be cool ;) but no worries if not)
I had originally planned implement this in a fork of testdir
, before I realized everything I needed was public and could be re-implemented.
If you'd be OK with the approach that tries to detect if its running under nextest
and falls back to the default test runner approach if not, I'd be OK to work this into a PR.
@hellertime
Apologies for taking so long to come back to this. I've found some time to wrap my head around testdir again and look at this issue.
To my surprise I ended up making just a tiny change: https://github.com/flub/testdir/pull/7
I haven't tested it that widely yet, so maybe I missed something. I would be grateful if you could check out that approach and see if it works for your situation.
When using cargo-nextest the detection for being in the same testrun is probably broken.