pytest: close file handles after use (cont.), and tidy-ups

- dante.py, dnsd.py, sshd.py: drop redundant conditions.
  Spotted in sshd by GitHub Code Quality.
- curl.py: comment out `if` to silence CodeQL warning.

Reported by GitHub CodeQL

Follow-up to 8145476d5d #21916

Closes #21917
This commit is contained in:
Viktor Szakats 2026-06-09 02:08:30 +02:00
parent 7b9d74abf6
commit cb4465bfe6
No known key found for this signature in database
9 changed files with 91 additions and 35 deletions

View file

@ -55,6 +55,7 @@ class Caddy:
self._conf_file = os.path.join(self._caddy_dir, 'Caddyfile')
self._error_log = os.path.join(self._caddy_dir, 'caddy.log')
self._tmp_dir = os.path.join(self._caddy_dir, 'tmp')
self._error_fd = None
self._process = None
self._http_port = 0
self._https_port = 0
@ -68,6 +69,11 @@ class Caddy:
def port(self) -> int:
return self._https_port
def close_log(self):
if self._error_fd:
self._error_fd.close()
self._error_fd = None
def clear_logs(self):
self._rmf(self._error_log)
@ -107,8 +113,8 @@ class Caddy:
args = [
self._caddy, 'run'
]
caddyerr = open(self._error_log, 'a')
self._process = subprocess.Popen(args=args, cwd=self._caddy_dir, stderr=caddyerr)
self._error_fd = open(self._error_log, 'a')
self._process = subprocess.Popen(args=args, cwd=self._caddy_dir, stderr=self._error_fd)
if self._process.returncode is not None:
return False
return not wait_live or self.wait_live(timeout=timedelta(seconds=Env.SERVER_TIMEOUT))
@ -122,7 +128,9 @@ class Caddy:
except Exception:
self._process.kill()
self._process = None
self.close_log()
return not wait_dead or self.wait_dead(timeout=timedelta(seconds=5))
self.close_log()
return True
def restart(self):

View file

@ -114,10 +114,10 @@ class LocalClient:
def dump_logs(self):
lines = []
lines.append('>>--stdout ----------------------------------------------\n')
with open(self._stdoutfile) as cstdout:
lines.extend(cstdout.readlines())
with open(self._stdoutfile) as fd:
lines.extend(fd.readlines())
lines.append('>>--stderr ----------------------------------------------\n')
with open(self._stderrfile) as cstderr:
lines.extend(cstderr.readlines())
with open(self._stderrfile) as fd:
lines.extend(fd.readlines())
lines.append('<<-------------------------------------------------------\n')
return ''.join(lines)

View file

@ -191,13 +191,14 @@ class RunTcpDump:
if self._proc:
raise Exception('tcpdump still running')
lines = []
for line in open(self._stdoutfile):
m = re.match(r'.* IP 127\.0\.0\.1\.(\d+) [<>] 127\.0\.0\.1\.(\d+):.*', line)
if m:
sport = int(m.group(1))
dport = int(m.group(2))
if ports is None or sport in ports or dport in ports:
lines.append(line)
with open(self._stdoutfile) as fd:
for line in fd:
m = re.match(r'.* IP 127\.0\.0\.1\.(\d+) [<>] 127\.0\.0\.1\.(\d+):.*', line)
if m:
sport = int(m.group(1))
dport = int(m.group(2))
if ports is None or sport in ports or dport in ports:
lines.append(line)
return lines
@property
@ -208,7 +209,8 @@ class RunTcpDump:
def stderr(self) -> List[str]:
if self._proc:
raise Exception('tcpdump still running')
return open(self._stderrfile).readlines()
with open(self._stderrfile) as fd:
return fd.readlines()
def sample(self):
# not sure how to make that detection reliable for all platforms
@ -1027,8 +1029,8 @@ class CurlClient:
cwd=self._run_dir, shell=False,
env=self._run_env)
profile = RunProfile(p.pid, started_at, self._run_dir)
if intext is not None and False:
p.communicate(input=intext.encode(), timeout=1)
#if intext is not None and False:
# p.communicate(input=intext.encode(), timeout=1)
if self._with_perf:
perf = PerfProfile(p.pid, self._run_dir)
perf.start()

View file

@ -57,6 +57,7 @@ class Dante:
self._dante_log = os.path.join(self._dante_dir, 'dante.log')
self._error_log = os.path.join(self._dante_dir, 'error.log')
self._pid_file = os.path.join(self._dante_dir, 'dante.pid')
self._error_fd = None
self._process = None
self.clear_logs()
@ -65,6 +66,11 @@ class Dante:
def port(self) -> int:
return self._port
def close_log(self):
if self._error_fd:
self._error_fd.close()
self._error_fd = None
def clear_logs(self):
self._rmf(self._error_log)
self._rmf(self._dante_log)
@ -89,7 +95,7 @@ class Dante:
self._process.terminate()
self._process.wait(timeout=2)
self._process = None
return not wait_dead or True
self.close_log()
return True
def restart(self):
@ -122,8 +128,8 @@ class Dante:
'-p', f'{self._pid_file}',
'-d', '0',
]
procerr = open(self._error_log, 'a')
self._process = subprocess.Popen(args=args, stderr=procerr)
self._error_fd = open(self._error_log, 'a')
self._process = subprocess.Popen(args=args, stderr=self._error_fd)
if self._process.returncode is not None:
return False
return self.wait_live(timeout=timedelta(seconds=Env.SERVER_TIMEOUT))

View file

@ -56,6 +56,7 @@ class Dnsd:
self._conf_file = os.path.join(self._log_dir, 'dnsd.cmd')
self._pid_file = os.path.join(self._log_dir, 'dnsd.pid')
self._error_log = os.path.join(self._log_dir, 'dnsd.err.log')
self._error_fd = None
self._process = None
self.clear_logs()
@ -64,6 +65,11 @@ class Dnsd:
def port(self) -> int:
return self._port
def close_log(self):
if self._error_fd:
self._error_fd.close()
self._error_fd = None
def clear_logs(self):
self._rmf(self._log_file)
self._rmf(self._error_log)
@ -87,7 +93,7 @@ class Dnsd:
self._process.terminate()
self._process.wait(timeout=2)
self._process = None
return not wait_dead or True
self.close_log()
return True
def restart(self):
@ -122,8 +128,8 @@ class Dnsd:
'--logfile', f'{self._log_file}',
'--pidfile', f'{self._pid_file}',
]
procerr = open(self._error_log, 'a')
self._process = subprocess.Popen(args=args, stderr=procerr)
self._error_fd = open(self._error_log, 'a')
self._process = subprocess.Popen(args=args, stderr=self._error_fd)
if self._process.returncode is not None:
return False
return self.wait_live(timeout=timedelta(seconds=Env.SERVER_TIMEOUT))

View file

@ -48,6 +48,7 @@ class H2o:
self._port = 0 # defaults to h3_port
self._cred_name = cred_name
self._loaded_cred_name = None
self._error_fd = None
self._process = None
self._tmp_dir = os.path.join(self.env.gen_dir, self._name)
self._run_dir = os.path.join(self._tmp_dir, "run")
@ -72,6 +73,11 @@ class H2o:
def h2_port(self) -> Optional[int]:
return getattr(self, "_h2_port", None)
def close_log(self):
if self._error_fd:
self._error_fd.close()
self._error_fd = None
def clear_logs(self):
self._rmf(self._error_log)
self._rmf(self._stderr)
@ -127,8 +133,8 @@ class H2o:
self._loaded_cred_name = self._cred_name
self.write_config()
args = [self._cmd, "-c", self._conf_file]
ngerr = open(self._stderr, "a")
self._process = subprocess.Popen(args=args, stderr=ngerr)
self._error_fd = open(self._stderr, "a")
self._process = subprocess.Popen(args=args, stderr=self._error_fd)
if self._process.returncode is not None:
return False
if wait_live:
@ -155,15 +161,19 @@ class H2o:
self._process.kill()
self._process.wait(timeout=2)
self._process = None
self.close_log()
return not wait_dead or self.wait_for_state(
live=False, timeout=timedelta(seconds=5)
)
self.close_log()
return True
def kill(self, wait_dead=True):
if self._process:
self._process.kill()
self.close_log()
return True
self.close_log()
return False
def restart(self):

View file

@ -55,6 +55,7 @@ class Nghttpx:
self._error_log = os.path.join(self._run_dir, 'nghttpx.log')
self._stderr = os.path.join(self._run_dir, 'nghttpx.stderr')
self._tmp_dir = os.path.join(self._run_dir, 'tmp')
self._error_fd = None
self._process: Optional[subprocess.Popen] = None
self._cred_name = self._def_cred_name = cred_name
self._loaded_cred_name = ''
@ -86,6 +87,11 @@ class Nghttpx:
def exists(self):
return self._cmd and os.path.exists(self._cmd)
def close_log(self):
if self._error_fd:
self._error_fd.close()
self._error_fd = None
def clear_logs(self):
self._rmf(self._error_log)
self._rmf(self._stderr)
@ -116,7 +122,9 @@ class Nghttpx:
self._process.terminate()
self._process.wait(timeout=2)
self._process = None
self.close_log()
return not wait_dead or self.wait_dead(timeout=timedelta(seconds=5))
self.close_log()
return True
def restart(self):
@ -262,8 +270,8 @@ class NghttpxQuic(Nghttpx):
'--frontend-http3-max-connection-window-size=100M',
# f'--frontend-quic-debug-log',
])
ngerr = open(self._stderr, 'a')
self._process = subprocess.Popen(args=args, stderr=ngerr)
self._error_fd = open(self._stderr, 'a')
self._process = subprocess.Popen(args=args, stderr=self._error_fd)
if self._process.returncode is not None:
return False
return not wait_live or self.wait_live(timeout=timedelta(seconds=Env.SERVER_TIMEOUT))
@ -312,8 +320,8 @@ class NghttpxFwd(Nghttpx):
creds.pkey_file,
creds.cert_file,
]
ngerr = open(self._stderr, 'a')
self._process = subprocess.Popen(args=args, stderr=ngerr)
self._error_fd = open(self._stderr, 'a')
self._process = subprocess.Popen(args=args, stderr=self._error_fd)
if self._process.returncode is not None:
return False
return not wait_live or self.wait_live(timeout=timedelta(seconds=Env.SERVER_TIMEOUT))

View file

@ -74,6 +74,7 @@ class Sshd:
]
self._user_key_files = []
self._user_pub_files = []
self._error_fd = None
self._process = None
self.clear_logs()
@ -164,14 +165,21 @@ class Sshd:
pubkey = fp.read()
fd.write(pubkey)
def close_log(self):
if self._error_fd:
self._error_fd.close()
self._error_fd = None
def clear_logs(self):
self._rmf(self._sshd_log)
def dump_log(self):
lines = ['>>--sshd log ----------------------------------------------\n']
lines.extend(open(self._sshd_log))
with open(self._sshd_log) as fd:
lines.extend(fd.readlines())
lines.extend(['>>--curl log ----------------------------------------------\n'])
lines.extend(open(os.path.join(self._tmp_dir, 'curl.stderr')))
with open(os.path.join(self._tmp_dir, 'curl.stderr')) as fd:
lines.extend(fd.readlines())
lines.append('<<-------------------------------------------------------\n')
return ''.join(lines)
@ -195,7 +203,7 @@ class Sshd:
self._process.terminate()
self._process.wait(timeout=2)
self._process = None
return not wait_dead or True
self.close_log()
return True
def restart(self):
@ -233,8 +241,8 @@ class Sshd:
run_env = os.environ.copy()
# does not have any effect, sadly
# run_env['HOME'] = f'{self._home_dir}'
procerr = open(self._sshd_log, 'a')
self._process = subprocess.Popen(args=args, stderr=procerr, env=run_env)
self._error_fd = open(self._sshd_log, 'a')
self._process = subprocess.Popen(args=args, stderr=self._error_fd, env=run_env)
if self._process.returncode is not None:
return False
return self.wait_live(timeout=timedelta(seconds=Env.SERVER_TIMEOUT))

View file

@ -68,6 +68,7 @@ class VsFTPD:
self._conf_file = os.path.join(self._vsftpd_dir, 'test.conf')
self._pid_file = os.path.join(self._vsftpd_dir, 'vsftpd.pid')
self._error_log = os.path.join(self._vsftpd_dir, 'vsftpd.log')
self._error_fd = None
self._process = None
self.clear_logs()
@ -84,6 +85,11 @@ class VsFTPD:
def port(self) -> int:
return self._port
def close_log(self):
if self._error_fd:
self._error_fd.close()
self._error_fd = None
def clear_logs(self):
self._rmf(self._error_log)
@ -107,7 +113,9 @@ class VsFTPD:
self._process.terminate()
self._process.wait(timeout=2)
self._process = None
self.close_log()
return not wait_dead or self.wait_dead(timeout=timedelta(seconds=5))
self.close_log()
return True
def restart(self):
@ -138,8 +146,8 @@ class VsFTPD:
self._cmd,
f'{self._conf_file}',
]
procerr = open(self._error_log, 'a')
self._process = subprocess.Popen(args=args, stderr=procerr)
self._error_fd = open(self._error_log, 'a')
self._process = subprocess.Popen(args=args, stderr=self._error_fd)
if self._process.returncode is not None:
return False
return not wait_live or self.wait_live(timeout=timedelta(seconds=Env.SERVER_TIMEOUT))