Skip to content

qa: Drop recursive deletes from test code, add lint checks.#34439

Open
davidgumberg wants to merge 3 commits intobitcoin:masterfrom
davidgumberg:2026-01-28-remove-all
Open

qa: Drop recursive deletes from test code, add lint checks.#34439
davidgumberg wants to merge 3 commits intobitcoin:masterfrom
davidgumberg:2026-01-28-remove-all

Conversation

@davidgumberg
Copy link
Contributor

@davidgumberg davidgumberg commented Jan 29, 2026

Both fs::remove_all and shutil::rmtree() are a bit dangerous, and most of their uses are not necessary, this PR removes most instances of both.

remove_all() is still used in in src/test/util/setup_common.cpp as part of BasicTestingSetup::BasicTestingSetup's constructor and destructor, and it is used in the kernel test code's TestDirectory:

struct TestDirectory {
std::filesystem::path m_directory;
TestDirectory(std::string directory_name)
: m_directory{std::filesystem::temp_directory_path() / (directory_name + random_string(16))}
{
std::filesystem::create_directories(m_directory);
}
~TestDirectory()
{
std::filesystem::remove_all(m_directory);
}
};

In both cases, remove_all is likely necessary, but the kernel's test code is RAII, ideally BasicTestingSetup could be made similar in a follow-up or in this PR if reviewers think it is important.

Similarly in the python code, most usage was unnecessary, but there are a few places where rmtree() was necessary, I have added sanity checks to make sure these are inside of the tmpdir before doing recursive delete there.

@DrahtBot DrahtBot added the Tests label Jan 29, 2026
@DrahtBot
Copy link
Contributor

DrahtBot commented Jan 29, 2026

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Reviews

See the guideline for information on the review process.

Type Reviewers
Concept ACK l0rinc
Approach ACK w0xlt

If your review is incorrectly listed, please copy-paste <!--meta-tag:bot-skip--> into the comment that the bot should ignore.

Conflicts

Reviewers, this pull request conflicts with the following ones:

  • #34603 (wallet: Fix detection of symlinks on Windows by achow101)
  • #34418 (qa: Make wallet_multiwallet.py Windows crossbuild-compatible by hodlinator)
  • #34372 (QA: wallet_migration: Test several more weird scenarios by luke-jr)

If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

@DrahtBot
Copy link
Contributor

🚧 At least one of the CI tasks failed.
Task lint: https://github.com/bitcoin/bitcoin/actions/runs/21465095038/job/61825339241
LLM reason (✨ experimental): Lint check failed due to Ruff error: unused import shutil in test/functional/test_framework/test_node.py.

Hints

Try to run the tests locally, according to the documentation. However, a CI failure may still
happen due to a number of reasons, for example:

  • Possibly due to a silent merge conflict (the changes in this pull request being
    incompatible with the current code in the target branch). If so, make sure to rebase on the latest
    commit of the target branch.

  • A sanitizer issue, which can only be found by compiling with the sanitizer and running the
    affected test.

  • An intermittent issue.

Leave a comment here, if you need help tracking down a confusing failure.

@l0rinc
Copy link
Contributor

l0rinc commented Jan 29, 2026

Sounds reasonable, light concept ACK

Copy link
Contributor

@w0xlt w0xlt left a comment

Choose a reason for hiding this comment

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

Approach ACK

Copy link
Contributor

@sedited sedited left a comment

Choose a reason for hiding this comment

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

lgtm

The changes to the cache directory logic in the last two commits were not that straight forward to understand for me. Can you elaborate on them a bit in the commit messages?

@davidgumberg
Copy link
Contributor Author

The changes to the cache directory logic in the last two commits were not that straight forward to understand for me. Can you elaborate on them a bit in the commit messages?

Thanks for the feedback, I've (hopefully) improved the commit message for the one where I drop the --keepcache argument, and I've moved changes that I accidentally included in the last commit in the series back to their true home in that commit.

Adds a lint check for `remove_all()`

`fs::remove_all()`/`std::filesystem::remove_all()` is extremely
dangerous, all user-facing instances of it have been removed, and it
also deserves to be removed from the places in our test code where it is
being used unnecessarily.
At the time this was added in  bitcoin#10197, building the test cache took 21
seconds, as described in that PR, but this is no longer true, as
demonstrated by running the functional test framework with and without
the --keepcache arguments on master prior to this commit:

```
hyperfine   --warmup 1  --export-markdown results.md --runs 3 \
    -n 'without --keepcache'    './build/test/functional/test_runner.py -j $(nproc)' \
    -n 'with --keepcache'       './build/test/functional/test_runner.py -j $(nproc) --keepcache'
```

| Command               | Mean [s]       | Min [s] | Max [s] | Relative |
|:----------------------|---------------:|--------:|---:|---:|
| `without --keepcache` | 76.373 ± 3.058 | 74.083  | 79.846  | 1.00 |
| `with --keepcache`    | 77.384 ± 1.836 | 75.952  | 79.454  | 1.01 ± 0.05 |

As a consequence, this argument can be removed from the test runner and
this also has the benefit of being able to use an RAII-like
`tempfile.TemporaryDirectory` instead of having to clean up the cache
manually at the end of test runs.

bitcoin#10197: bitcoin#10197
`shutil.rmtree` is dangerous because it recursively deletes. There are
not likely to be any issues with it's current uses, but it is possible
that some of the assumptions being made now won't always be true, e.g.
about what some of the variables being passed to `rmtree` represent.

For some remaining uses of rmtree that can't be avoided for now, use
`cleanup_dir` which asserts that the recursively deleted folder is a
child of the the `tmpdir` of the test run. Otherwise,
`tempfile.TemporaryDirectory` should be used which does it's own
deleting on being garbage collected, or old fashioned unlinking and
rmdir in the case of directories with known contents.
@DrahtBot
Copy link
Contributor

🐙 This pull request conflicts with the target branch and needs rebase.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants