mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-28 21:17:54 +00:00
Use context managers as suggested by PyLint 2.8.2
PyLint 2.8.2 reports the following suggestions for two Python scripts used in the system test suite: ************* Module tests_rndc_deadlock bin/tests/system/addzone/tests_rndc_deadlock.py:71:4: R1732: Consider using 'with' for resource-allocating operations (consider-using-with) ************* Module tests-shutdown bin/tests/system/shutdown/tests-shutdown.py:68:4: R1732: Consider using 'with' for resource-allocating operations (consider-using-with) bin/tests/system/shutdown/tests-shutdown.py:154:8: R1732: Consider using 'with' for resource-allocating operations (consider-using-with) Implement the above suggestions by using concurrent.futures.ThreadPoolExecutor() and subprocess.Popen() as context managers.
This commit is contained in:
parent
71284cb496
commit
a8163551ed
@ -68,23 +68,22 @@ def test_rndc_deadlock():
|
|||||||
test_state = {'finished': False}
|
test_state = {'finished': False}
|
||||||
|
|
||||||
# Create 4 worker threads running "rndc" commands in a loop.
|
# Create 4 worker threads running "rndc" commands in a loop.
|
||||||
executor = concurrent.futures.ThreadPoolExecutor()
|
with concurrent.futures.ThreadPoolExecutor() as executor:
|
||||||
for i in range(1, 5):
|
for i in range(1, 5):
|
||||||
domain = 'example%d' % i
|
domain = 'example%d' % i
|
||||||
executor.submit(rndc_loop, test_state, domain)
|
executor.submit(rndc_loop, test_state, domain)
|
||||||
|
|
||||||
# Run "rndc status" in 1-second intervals for a maximum of 10 seconds. If
|
# Run "rndc status" in 1-second intervals for a maximum of 10 seconds.
|
||||||
# any "rndc status" command fails, the loop will be interrupted.
|
# If any "rndc status" command fails, the loop will be interrupted.
|
||||||
server_is_responsive = True
|
server_is_responsive = True
|
||||||
attempts = 10
|
attempts = 10
|
||||||
while server_is_responsive and attempts > 0:
|
while server_is_responsive and attempts > 0:
|
||||||
server_is_responsive = check_if_server_is_responsive()
|
server_is_responsive = check_if_server_is_responsive()
|
||||||
attempts -= 1
|
attempts -= 1
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
||||||
# Signal worker threads that the test is finished.
|
# Signal worker threads that the test is finished.
|
||||||
test_state['finished'] = True
|
test_state['finished'] = True
|
||||||
executor.shutdown()
|
|
||||||
|
|
||||||
# Check whether all "rndc status" commands succeeded.
|
# Check whether all "rndc status" commands succeeded.
|
||||||
assert server_is_responsive
|
assert server_is_responsive
|
||||||
|
@ -65,65 +65,63 @@ def do_work(named_proc, resolver, rndc_cmd, kill_method, n_workers, n_queries):
|
|||||||
|
|
||||||
# We're going to execute queries in parallel by means of a thread pool.
|
# We're going to execute queries in parallel by means of a thread pool.
|
||||||
# dnspython functions block, so we need to circunvent that.
|
# dnspython functions block, so we need to circunvent that.
|
||||||
executor = ThreadPoolExecutor(n_workers + 1)
|
with ThreadPoolExecutor(n_workers + 1) as executor:
|
||||||
|
|
||||||
# Helper dict, where keys=Future objects and values are tags used
|
# Helper dict, where keys=Future objects and values are tags used
|
||||||
# to process results later.
|
# to process results later.
|
||||||
futures = {}
|
futures = {}
|
||||||
|
|
||||||
|
# 50% of work will be A queries.
|
||||||
|
# 1 work will be rndc stop.
|
||||||
|
# Remaining work will be rndc status (so we test parallel control
|
||||||
|
# connections that were crashing named).
|
||||||
|
shutdown = True
|
||||||
|
for i in range(n_queries):
|
||||||
|
if i < (n_queries // 2):
|
||||||
|
# Half work will be standard A queries.
|
||||||
|
# Among those we split 50% queries relname='www',
|
||||||
|
# 50% queries relname=random characters
|
||||||
|
if random.randrange(2) == 1:
|
||||||
|
tag = "good"
|
||||||
|
relname = "www"
|
||||||
|
else:
|
||||||
|
tag = "bad"
|
||||||
|
length = random.randint(4, 10)
|
||||||
|
relname = "".join(letters[
|
||||||
|
random.randrange(len(letters))] for i in range(length))
|
||||||
|
|
||||||
|
qname = relname + ".test"
|
||||||
|
futures[executor.submit(resolver.query, qname, 'A')] = tag
|
||||||
|
elif shutdown: # We attempt to stop named in the middle
|
||||||
|
shutdown = False
|
||||||
|
if kill_method == "rndc":
|
||||||
|
futures[executor.submit(launch_rndc, ['stop'])] = 'stop'
|
||||||
|
else:
|
||||||
|
futures[executor.submit(named_proc.terminate)] = 'kill'
|
||||||
|
|
||||||
# 50% of work will be A queries.
|
|
||||||
# 1 work will be rndc stop.
|
|
||||||
# Remaining work will be rndc status (so we test parallel control
|
|
||||||
# connections that were crashing named).
|
|
||||||
shutdown = True
|
|
||||||
for i in range(n_queries):
|
|
||||||
if i < (n_queries // 2):
|
|
||||||
# Half work will be standard A queries.
|
|
||||||
# Among those we split 50% queries relname='www',
|
|
||||||
# 50% queries relname=random characters
|
|
||||||
if random.randrange(2) == 1:
|
|
||||||
tag = "good"
|
|
||||||
relname = "www"
|
|
||||||
else:
|
else:
|
||||||
tag = "bad"
|
# We attempt to send couple rndc commands while named is
|
||||||
length = random.randint(4, 10)
|
# being shutdown
|
||||||
relname = "".join(letters[
|
futures[executor.submit(launch_rndc, ['status'])] = 'status'
|
||||||
random.randrange(len(letters))] for i in range(length))
|
|
||||||
|
|
||||||
qname = relname + ".test"
|
ret_code = -1
|
||||||
futures[executor.submit(resolver.query, qname, 'A')] = tag
|
for future in as_completed(futures):
|
||||||
elif shutdown: # We attempt to stop named in the middle
|
try:
|
||||||
shutdown = False
|
result = future.result()
|
||||||
if kill_method == "rndc":
|
# If tag is "stop", result is an instance of
|
||||||
futures[executor.submit(launch_rndc, ['stop'])] = 'stop'
|
# subprocess.CompletedProcess, then we check returncode
|
||||||
else:
|
# attribute to know if rncd stop command finished successfully.
|
||||||
futures[executor.submit(named_proc.terminate)] = 'kill'
|
#
|
||||||
|
# if tag is "kill" then the main function will check if
|
||||||
|
# named process exited gracefully after SIGTERM signal.
|
||||||
|
if futures[future] == "stop":
|
||||||
|
ret_code = result
|
||||||
|
|
||||||
else:
|
except (dns.resolver.NXDOMAIN, dns.exception.Timeout):
|
||||||
# We attempt to send couple rndc commands while named is
|
pass
|
||||||
# being shutdown
|
|
||||||
futures[executor.submit(launch_rndc, ['status'])] = 'status'
|
|
||||||
|
|
||||||
ret_code = -1
|
if kill_method == "rndc":
|
||||||
for future in as_completed(futures):
|
assert ret_code == 0
|
||||||
try:
|
|
||||||
result = future.result()
|
|
||||||
# If tag is "stop", result is an instance of
|
|
||||||
# subprocess.CompletedProcess, then we check returncode
|
|
||||||
# attribute to know if rncd stop command finished successfully.
|
|
||||||
#
|
|
||||||
# if tag is "kill" then the main function will check if
|
|
||||||
# named process exited gracefully after SIGTERM signal.
|
|
||||||
if futures[future] == "stop":
|
|
||||||
ret_code = result
|
|
||||||
|
|
||||||
except (dns.resolver.NXDOMAIN, dns.exception.Timeout):
|
|
||||||
pass
|
|
||||||
|
|
||||||
if kill_method == "rndc":
|
|
||||||
assert ret_code == 0
|
|
||||||
|
|
||||||
executor.shutdown()
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.dnspython
|
@pytest.mark.dnspython
|
||||||
@ -149,14 +147,6 @@ def test_named_shutdown(named_port, control_port):
|
|||||||
rndc_cmd = [rndc, "-c", rndc_cfg, "-p", str(control_port),
|
rndc_cmd = [rndc, "-c", rndc_cfg, "-p", str(control_port),
|
||||||
"-s", "10.53.0.3"]
|
"-s", "10.53.0.3"]
|
||||||
|
|
||||||
# Helper function, launch named without blocking.
|
|
||||||
def launch_named():
|
|
||||||
proc = subprocess.Popen([named, "-c", cfg_file, "-f"], cwd=cfg_dir)
|
|
||||||
# Ensure named is running
|
|
||||||
assert proc.poll() is None
|
|
||||||
|
|
||||||
return proc
|
|
||||||
|
|
||||||
# We create a resolver instance that will be used to send queries.
|
# We create a resolver instance that will be used to send queries.
|
||||||
resolver = dns.resolver.Resolver()
|
resolver = dns.resolver.Resolver()
|
||||||
resolver.nameservers = ['10.53.0.3']
|
resolver.nameservers = ['10.53.0.3']
|
||||||
@ -167,38 +157,41 @@ def test_named_shutdown(named_port, control_port):
|
|||||||
# Method 2: killing with SIGTERM
|
# Method 2: killing with SIGTERM
|
||||||
# In both methods named should exit gracefully.
|
# In both methods named should exit gracefully.
|
||||||
for kill_method in ("rndc", "sigterm"):
|
for kill_method in ("rndc", "sigterm"):
|
||||||
named_proc = launch_named()
|
named_cmdline = [named, "-c", cfg_file, "-f"]
|
||||||
# wait for named to finish loading
|
with subprocess.Popen(named_cmdline, cwd=cfg_dir) as named_proc:
|
||||||
for _ in range(10):
|
# Ensure named is running
|
||||||
try:
|
assert named_proc.poll() is None
|
||||||
resolver.query('version.bind', 'TXT', 'CH')
|
# wait for named to finish loading
|
||||||
break
|
for _ in range(10):
|
||||||
except (dns.resolver.NoNameservers, dns.exception.Timeout):
|
try:
|
||||||
time.sleep(1)
|
resolver.query('version.bind', 'TXT', 'CH')
|
||||||
|
break
|
||||||
|
except (dns.resolver.NoNameservers, dns.exception.Timeout):
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
do_work(named_proc, resolver, rndc_cmd,
|
do_work(named_proc, resolver, rndc_cmd,
|
||||||
kill_method, n_workers=12, n_queries=16)
|
kill_method, n_workers=12, n_queries=16)
|
||||||
|
|
||||||
# Wait named to exit for a maximum of MAX_TIMEOUT seconds.
|
# Wait named to exit for a maximum of MAX_TIMEOUT seconds.
|
||||||
MAX_TIMEOUT = 10
|
MAX_TIMEOUT = 10
|
||||||
is_dead = False
|
is_dead = False
|
||||||
for _ in range(MAX_TIMEOUT):
|
|
||||||
if named_proc.poll() is not None:
|
|
||||||
is_dead = True
|
|
||||||
break
|
|
||||||
time.sleep(1)
|
|
||||||
|
|
||||||
if not is_dead:
|
|
||||||
named_proc.send_signal(signal.SIGABRT)
|
|
||||||
for _ in range(MAX_TIMEOUT):
|
for _ in range(MAX_TIMEOUT):
|
||||||
if named_proc.poll() is not None:
|
if named_proc.poll() is not None:
|
||||||
is_dead = True
|
is_dead = True
|
||||||
break
|
break
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
if not is_dead:
|
|
||||||
named_proc.kill()
|
|
||||||
|
|
||||||
assert is_dead
|
if not is_dead:
|
||||||
# Ensures that named exited gracefully.
|
named_proc.send_signal(signal.SIGABRT)
|
||||||
# If it crashed (abort()) exitcode will be non zero.
|
for _ in range(MAX_TIMEOUT):
|
||||||
assert named_proc.returncode == 0
|
if named_proc.poll() is not None:
|
||||||
|
is_dead = True
|
||||||
|
break
|
||||||
|
time.sleep(1)
|
||||||
|
if not is_dead:
|
||||||
|
named_proc.kill()
|
||||||
|
|
||||||
|
assert is_dead
|
||||||
|
# Ensures that named exited gracefully.
|
||||||
|
# If it crashed (abort()) exitcode will be non zero.
|
||||||
|
assert named_proc.returncode == 0
|
||||||
|
Loading…
x
Reference in New Issue
Block a user