1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// Copyright (c) 2026 Mike Grier
//! Shared test helpers.
//!
//! Not a test target: `cargo` compiles only the top-level `.rs` files in
//! `tests/` as integration tests, so a module in a subdirectory is included by
//! the files that declare `mod common;` rather than run on its own.
use ;
/// A path under the system temp directory that removes itself when dropped.
///
/// Exists because the explicit `remove_file` at the end of a test body does
/// **not** run when the test panics, and a panicking test is exactly the case
/// that was leaking: the `M26.13` stall investigation ran a reproducer whose
/// failing arm panics, and filled the temp directory doing it. Even an
/// all-passing run of this crate's suite left files behind, because several
/// paths had no removal at all.
///
/// The counts live in the committed capture rather than here -- see
/// [the measurement record](../../measurements/2026-10-01-the-tests-stop-leaking-temp-files/README.md)
/// and the `arms.csv` beside it. A measured figure transcribed into a doc
/// comment is a second copy that drifts from the capture with nothing to
/// notice, which is the whole reason the capture is committed.
///
/// # Deleting a file whose handle is still open depends on how it was opened
///
/// Two kinds of open are in use here, and they behave oppositely.
///
/// - **`std::fs::OpenOptions`** shares delete by default on Windows -- its
/// default share mode includes `FILE_SHARE_DELETE` -- so removing the file
/// while such a handle is open succeeds. Fixtures such as
/// `completion_event::fixture` and `handover::fixture` rely on exactly that:
/// their guard drops before they return the still-open `File`. Drop order is
/// not what makes their cleanup work.
/// - **Direct `CreateFileW` calls** on a temp file -- the unbuffered,
/// overlapped handles in `flush_barrier`, `flush_barrier_stress` and
/// `handover` -- pass `FILE_SHARE_READ | FILE_SHARE_WRITE` and no
/// `FILE_SHARE_DELETE`, so a removal attempted while one is open fails.
/// (`bounded_pop` calls `CreateFileW` too, but on a named pipe, with no temp
/// file to remove.) For these, ordering matters:
/// struct fields and locals drop *after* the enclosing `Drop` body, and locals
/// drop in reverse declaration order, so a guard declared **before** the
/// handle it shadows is removed after that handle closes.
///
/// A change to how a fixture opens its file can therefore move it from one
/// group to the other, and with it the mechanism its cleanup depends on.
///
/// That ordering is why an explicit `remove_file` placed after the test closes
/// its own handle is kept where it already exists rather than deleted as
/// redundant: it runs at a point the test controls, and this guard is the net
/// underneath it for the panicking path. A removal that finds nothing is not an
/// error here, so the two compose.
///
/// The hazard is not hypothetical -- see the `Fixture` in
/// [flush_barrier_stress.rs](../flush_barrier_stress.rs), where holding the
/// handle directly meant every trial silently leaked a 32 MiB extent.