-
Notifications
You must be signed in to change notification settings - Fork 37.7k
test: test_bitcoin: allow -testdatadir=<datadir> #26564
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
Conversation
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. Code CoverageFor detailed information about the code coverage, see the test coverage report. ReviewsSee the guideline for information on the review process.
If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update. ConflictsNo conflicts as of last run. |
src/test/util/setup_common.cpp
Outdated
@@ -98,7 +98,9 @@ std::ostream& operator<<(std::ostream& os, const uint256& num) | |||
} | |||
|
|||
BasicTestingSetup::BasicTestingSetup(const std::string& chainName, const std::vector<const char*>& extra_args) | |||
: m_path_root{fs::temp_directory_path() / "test_common_" PACKAGE_NAME / g_insecure_rand_ctx_temp_path.rand256().ToString()}, | |||
: m_path_root{std::getenv("TEST_BITCOIN_PATH") ? | |||
std::getenv("TEST_BITCOIN_PATH") : |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pretty sure this will break when running in parallel.
What about a --nocleanup option, like the one in the functional test framework, if the goal is to not delete the dir?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if this would work, but what about checking the datadir lock before removing it, e.g. with util/system.cpp::LockDirectory
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To explain, tests running in parallel can not share a data directory. With rand256, each test gets a unique one. However, with TEST_BITCOIN_PATH
all tests get the same one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know, my suggestion was rather: since this is an advanced setting, we could let the user handle making sure that there are no tests running in parallel, but just add a simple check in case they aren't aware/mistaken (by checking the datadir lock)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about a --nocleanup option ... if the goal is to not delete the dir?
Yes, but also to have a fixed data directory path, so I can open its debug.log
in an editor, and re-read the file as the test runs and after the test completes. (Or better yet, set the editor to automatically re-read if possible, which I do with vim
.) Then if I run the test again, I can re-read the file again, without having to open a different file.
But I think specifying this environment variable can also indicate not to delete the directory when the test completes; you wouldn't want to do this normally because the disk usage would continuously increase as you run the test repeatedly. If instead you specify a fixed directory, then disk usage doesn't grow as you repeatedly run tests, so it's okay for the test not to delete it at the end.
tests running in parallel can not share a data directory
Yes, you definitely wouldn't specify this to multiple tests running in parallel. I would only use this when I'm running a single test that I'm trying to understand or debug. That is, I definitely would not set this environment variable in my .bashrc
! (I could improve the doc changes to make that clear.) The default is to use separate directories (as today).
... checking the datadir lock ...
The unit tests don't create a lock file; only bitcoind
does that. The unit tests don't actually create a full datadir, only some parts of it, and can also create extra files that aren't normally in a datadir. (That's why I called it a working dir in the title and description, instead of a datadir, although the test README
does call it a datadir.)
I don't think it's worth adding a lock file; I think users of this will be advanced enough to understand that multiple tests can't simultaneously share the same work directory.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, sgtm
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Concept ACK - seems helpful to improve productivity in certain workflows.
src/test/util/setup_common.cpp
Outdated
@@ -98,7 +98,9 @@ std::ostream& operator<<(std::ostream& os, const uint256& num) | |||
} | |||
|
|||
BasicTestingSetup::BasicTestingSetup(const std::string& chainName, const std::vector<const char*>& extra_args) | |||
: m_path_root{fs::temp_directory_path() / "test_common_" PACKAGE_NAME / g_insecure_rand_ctx_temp_path.rand256().ToString()}, | |||
: m_path_root{std::getenv("TEST_BITCOIN_PATH") ? | |||
std::getenv("TEST_BITCOIN_PATH") : |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if this would work, but what about checking the datadir lock before removing it, e.g. with util/system.cpp::LockDirectory
?
bc32016
to
68b1a67
Compare
Force-pushed to incorporate two review suggestions (thanks!):
|
This combination seems dangerous... :/ |
68b1a67
to
be0b1e5
Compare
If the concern is that someone may specify a real data directory by mistake, that's a good point! A real datadir has a I just force-pushed code to exit without removing the work directory if contains
Does this address your concern? Is there a better way to report the error? |
Not quite, I'm more concerned about a situation where |
be0b1e5
to
c48a1b4
Compare
Another great point! Force-pushed a change (c48a1b4) so that the environment variable only replaces the random path component within $ BITCOIN_TEST_PATH=mydatadir src/test/test_bitcoin --run_test=getarg_tests/doubledash
Running 1 test case...
*** No errors detected
$ ls -l /tmp/test_common_Bitcoin\ Core/mydatadir/
total 8
drwxrwxr-x 2 larry larry 4096 Nov 27 22:45 blocks
-rw-rw-r-- 1 larry larry 1003 Nov 27 22:45 debug.log
$ |
src/test/util/setup_common.cpp
Outdated
test_path = g_insecure_rand_ctx_temp_path.rand256().ToString(); | ||
} else { | ||
test_path = test_path_env; | ||
if (fs::PathFromString(test_path).is_absolute()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe just use a hardcoded path item like "fixed"
and turn the env into a flag? This should be fine, because anyone can still modify the root temp dir.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know this sounds a little far-fetched, but I have actually done the following: I have two test binaries, one from a PR branch and the other from master, and the test fails on the PR branch but passes on master. I've single-stepped through the tests simultaneously (in sync) comparing them to see what happens leading up to the failure. In this case, it would be convenient to have two different fixed data directories (if I needed to restart the test many times) because I also want to watch the two debug.log
files.
Also, as long as we're going to the trouble of implementing and documenting an environment variable, it's no extra work to make it a value instead of a flag.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that is still possible. You can set TMPDIR=/tmp/1
, see https://en.cppreference.com/w/cpp/filesystem/temp_directory_path
Not sure if relevant, but BITCOIN_TEST_PATH=../../home/user
will still delete your home dir.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch! I just force-pushed an update to require that BITCOIN_TEST_PATH
doesn't contain the separator character. That should take care of both problems. I would say that if the user has set TMPDIR
, it should be safe to delete the given directory, even if it's within the user's home directory, since paths containing ../
are no longer allowed.
$ BITCOIN_TEST_PATH=../mydatadir src/test/test_bitcoin --run_test=getarg_tests/doubledash
Running 1 test case...
unknown location(0): fatal error: in "getarg_tests/doubledash": std::runtime_error: BITCOIN_TEST_PATH cannot contain path separators
test/getarg_tests.cpp(380): last checkpoint: "doubledash" fixture ctor
*** 1 failure is detected in the test module "Bitcoin Core Test Suite"
$
c48a1b4
to
8aee8b4
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Concept ACK
I think this is useful; I recently wanted to read some logs from a benchmark and I wasn't sure how to do it.
This functionality is already possible with the functional tests using the --tmpdir= and --nocleanup arguments.
But this (fixed data directory path by overriding) is something that is not currently possible in the functional tests framework. Which initially made me a bit skeptical, but the explanation of your flow makes sense, plus the fact that now the possible paths directories are confined inside /tmp/test_common_Bitcoin\ Core/
.
And since the BITCOIN_TEST_PATH
environmental variable does not define a path anymore but a directory, maybe BITCOIN_TEST_DIR
could be a better name?
Are you still working on this? |
8aee8b4
to
5df0ed5
Compare
Yes, still hoping to get this merged. Force-pushed 5df0ed5 to rebase onto the latest master (since it's been a long time) |
5df0ed5
to
538e9a9
Compare
Another force push to improve the doc slightly and to address review comments, thanks @kouloumos! Ready for review, also ping @theStack. |
538e9a9
to
4916434
Compare
Rebased for merge conflict. |
Specifying this argument overrides the path location for test_bitcoin; it becomes <datadir>/test_common_Bitcoin Core/<testname>/datadir. Also, this directory isn't removed after the test completes. This can make it easier for developers to study the results of a test (see the state of the data directory after the test runs), and also (for example) have an editor open on debug.log to monitor it across multiple test runs instead of having to re-open a different pathname each time. Example usage (note the "--" is needed): test_bitcoin --run_test=getarg_tests/boolarg -- \ -testdatadir=/somewhere/mydatadir This will create (if necessary) and use the data directory: /somewhere/mydatadir/test_common_Bitcoin Core/getarg_tests/boolarg/datadir Co-authored-by: furszy <mfurszy@protonmail.com>
2209a7f
to
d27e2d8
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK d27e2d8! (Already did some testing with fs::remove()
to make sure it was compatible with the util::Lock/UnlockDirectory
implementation).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK d27e2d8. I ran all the tests with my previous open file limit and no errors were detected. Also ran some individual tests with no, relative, and absolute paths and everything looks good.
I used watch -n 3 lsof -p PID
while running the tests in both this commit and the previous one to compare the outputs and observe the leak. I noticed the presence of only one .lock file as compared to a buildup of .lock files when running the old code.
Thanks for the guidance here @LarryRuane! Everything lgtm
Diffed and re-tested running with -testdatadir with an absolute path and with a relative path. ACK d27e2d8 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK d27e2d8
re-ACK for d27e2d8 Re-executed the test actions in #26564 (review). All unit tests passed. |
ACK d27e2d8 |
This backward-compatible change would help with code review, testing, and debugging. When
test_bitcoin
runs, it creates a working or data directory within/tmp/test_common_Bitcoin\ Core/
, named as a long random (hex) string.This small patch does three things:
-testdatadir=<datadir>
is given, use<datadir>/test_temp/<test-name>/datadir
as the working directory<datadir>/test_temp/<test-name>/datadir
if it exists from an earlier run (currently, it's presumed not to exist due to the long random string)Example usage, which will remove, create, use
/somewhere/test_temp/getarg_tests/boolarg
, and leave it afterward:(A relative pathname also works.)
This change affects only
test_bitcoin
; it could also be applied totest_bitcoin-qt
but that's slightly more involved so I'm skipping that for now.The rationale for this change is that, when running the test using the debugger, it's often useful to watch
debug.log
as the test runs and inspect some of the other files (I've looked at the generatedblknnnn.dat
files for example). Currently, that requires figuring out where the test's working directory is since it changes on every test run. Tests can be run with-printtoconsole=1
to show debug logging to the terminal, but it's nice to keepdebug.log
continuously open in an editor, for example.Even if not using a debugger, it's sometimes helpful to see
debug.log
and other artifacts after the test completes.Similar functionality is already possible with the functional tests using the
--tmpdir=
and--nocleanup
arguments.