Skip to content

Fix #[after] not running when tests are ignored or filtered - #2

Merged
brianp merged 1 commit into
mainfrom
fix/after-runs-when-tests-ignored-or-filtered
Jul 21, 2026
Merged

Fix #[after] not running when tests are ignored or filtered#2
brianp merged 1 commit into
mainfrom
fix/after-runs-when-tests-ignored-or-filtered

Conversation

@brianp

@brianp brianp commented Jul 20, 2026

Copy link
Copy Markdown
Owner

Fixes #1.

#[after] used an atomic countdown to spot the last test in a group. The counter started at the number of tests and each test decremented it on the way out. Trouble is, a test that's #[ignore]d or #[cfg]'d out never runs, so it never decrements, the counter stays above zero, and after never fires. Your teardown gets skipped and containers leak.

It's actually broader than ignored tests. Any time the harness runs a subset, a name filter like cargo test some_name or --skip, the count is wrong and after goes missing. Counting can't win, because which tests run is a runtime decision libtest makes, not something the macro can see when it expands.

So this drops the countdown. The first test in a group to run registers the group's after as a teardown, and it runs once at process exit through a C atexit handler. It fires exactly once as long as at least one test in the group ran, no matter how the run got filtered. Covers both #[test_suite] and spec!.

The regression test re-execs the test binary with a single-test filter and checks the teardown still ran.

A few things worth knowing:

  • Teardown runs at process exit now, not the instant the last test finishes.
  • Under nextest (a process per test) after runs once per test instead of once per group. The old countdown was broken there anyway, so this is still a step up.
  • If a test process is killed or hangs, exit never happens and after won't run. No in-process hook can help with that.

The `after` hook fired via an atomic countdown seeded with the number of
tests in the group. Any test the harness didn't run (#[ignore], #[cfg],
a name filter, or --skip) never decremented the counter, so it never hit
zero and `after` never ran. Teardown was silently skipped and resources
leaked (issue #1).

Counting can't fix this: which tests run is decided at runtime by libtest,
not at expansion time. Instead, register the group's `after` as a teardown
that runs once at process exit, guarded by a Once so it registers on the
first test that runs. It fires exactly once as long as any test in the
group ran, regardless of filtering.

Applies to both #[test_suite] and spec!.
@brianp
brianp merged commit 9748e44 into main Jul 21, 2026
5 checks passed
@brianp
brianp deleted the fix/after-runs-when-tests-ignored-or-filtered branch July 21, 2026 15:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

#after will not fire if a test is ignored

1 participant