Skip to content

Commit e74fab1

Browse files
andyclaude
andcommitted
tests: stop leaking temporary directories into /tmp
Reported as the machine filling its RAM. It was these: on that machine /tmp is a tmpfs, so every directory left behind is memory that never comes back, and free's "shared" column moved by the same 2.3 GB that deleting them recovered. Three scripts created a workspace per run, or per case, and removed none of it: tests/verify/run_tests.py one for the dialog build, one for the testrt oracle, and ONE PER FIXTURE for the code oracle -- each holding a real Gaussian scratch directory tests/parsers/run_tests.py one per case, 1542 of them tools/modiagram/frommopac.py one per invocation, 749 of them Together, 252 directories holding 2.0 GB, plus eight and a half thousand smaller ones. A suite that eats the machine it runs on gets turned off, which costs more than the leak. Each now registers its own cleanup at exit, so an early return or a failed assertion cannot skip it. tests/symmetry, tests/e2e, tests/dialogs and tests/parsers/expt.py already removed theirs. Verified by running every suite back to back: nine temp entries before, nine after. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EFMUNbw2UpRPmgsqviAowb
1 parent 85d2ab4 commit e74fab1

4 files changed

Lines changed: 32 additions & 3 deletions

File tree

‎tests/parsers/eccejobmonitor_sim.py‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@
4040
finished output file in one pass.
4141
"""
4242

43+
import shutil
44+
import atexit
4345
import os
4446
import re
4547
import subprocess
@@ -497,7 +499,11 @@ def run_parser(script_dir, entry, block, parse_args=DEFAULT_PARSE_ARGS,
497499
# Run in a scratch directory, never in scripts/parsers: the real client
498500
# runs these in the job's own temp dir, and some scripts write side files
499501
# there (nwchem.symlab writes "$key/parseSym", with $key = argv[1] = '.').
500-
cwd = workdir or tempfile.mkdtemp(prefix='ecce-parsertest-')
502+
cwd = workdir
503+
if not cwd:
504+
# Ours to clean up; a caller's own workdir is not.
505+
cwd = tempfile.mkdtemp(prefix='ecce-parsertest-')
506+
atexit.register(shutil.rmtree, cwd, True)
501507
proc = subprocess.run(argv, input=block.text, capture_output=True,
502508
text=True, timeout=timeout, cwd=cwd, env=env)
503509
return proc.stdout, proc.stderr, proc.returncode

‎tests/parsers/run_tests.py‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
Exit status is 0 only if every check passed.
2020
"""
2121

22+
import shutil
23+
import atexit
2224
import argparse
2325
import re
2426
import difflib
@@ -224,7 +226,11 @@ def run_case(case, res, verbose=False):
224226
% (case['name'], ' and '.join('[%s]' % p for p in pair)))
225227

226228
# run the real parser scripts, in a scratch dir (some write side files)
229+
# Removed at exit: on a machine where /tmp is a tmpfs every
230+
# directory left behind is RAM that never comes back, and a
231+
# suite that runs often leaves thousands.
227232
workdir = tempfile.mkdtemp(prefix='ecce-parsertest-%s-' % case['name'])
233+
atexit.register(shutil.rmtree, workdir, True)
228234
report = []
229235
emitted = {} # parse type -> list of (block, records)
230236
for entry in desc.live_entries():

‎tests/verify/run_tests.py‎

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
"""
3838

3939
import argparse
40+
import atexit
4041
import os
4142
import re
4243
import subprocess
@@ -183,8 +184,15 @@ def dialog_smoke(verbose):
183184
if not which(tool):
184185
return (False, True, "no %s" % tool)
185186

187+
# CLEANED UP, ALWAYS. On the reporting machine /tmp is a tmpfs, so
188+
# every directory left here is RAM that never comes back: 252 of
189+
# them across a day of runs held 2 GB and pushed the machine into
190+
# swap. A test that leaks its workspace is a test that gets
191+
# turned off.
192+
import shutil
186193
import tempfile
187194
work = tempfile.mkdtemp(prefix="ecce-verify-smoke")
195+
atexit.register(shutil.rmtree, work, True)
188196
binary = os.path.join(work, "dialog_smoke")
189197
calced = os.path.join(ROOT, os.pardir, "src", "apps", "calced")
190198

@@ -297,9 +305,11 @@ def testrt_agreement(verbose):
297305
if not testrt:
298306
return (False, 0, 0)
299307

308+
import shutil
300309
import tempfile
301310
failures, checked = 0, 0
302311
work = tempfile.mkdtemp(prefix="ecce-testrt")
312+
atexit.register(shutil.rmtree, work, True)
303313

304314
for fixture, code, _atoms, expected in CASES:
305315
if not code.startswith("Gaussian"):
@@ -497,6 +507,7 @@ def code_rejects(code, path, work):
497507

498508
def codes_agreement(verbose):
499509
"""Returns (ran, failures, checked)."""
510+
import shutil
500511
import tempfile
501512
failures, checked = 0, 0
502513

@@ -508,7 +519,12 @@ def codes_agreement(verbose):
508519
continue
509520

510521
work = tempfile.mkdtemp(prefix="ecce-oracle")
511-
refused = code_rejects(code, path, work)
522+
try:
523+
refused = code_rejects(code, path, work)
524+
finally:
525+
# A Gaussian run leaves its scratch here, so this is the
526+
# worst of the leaks: one directory per fixture per run.
527+
shutil.rmtree(work, True)
512528
if refused is None:
513529
continue
514530
checked += 1

‎tools/modiagram/frommopac.py‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@
77
This is the fastest way to get a real spectrum for a molecule that has
88
no ECCE calculation on disk.
99
"""
10-
import os, re, subprocess, sys, tempfile
10+
import atexit, os, re, shutil, subprocess, sys, tempfile
1111

1212
def run(name, atoms, charge=0, keywords="PM7 1SCF VECTORS ALLVEC"):
1313
work = tempfile.mkdtemp(prefix="modiag-")
14+
atexit.register(shutil.rmtree, work, True)
1415
mop = os.path.join(work, name + ".mop")
1516
head = keywords + (" CHARGE=%d" % charge if charge else "")
1617
lines = [head, name, ""]

0 commit comments

Comments
 (0)