test_state = {'finished': False}
# Create 4 worker threads running "rndc" commands in a loop.
- executor = concurrent.futures.ThreadPoolExecutor()
- for i in range(1, 5):
- domain = 'example%d' % i
- executor.submit(rndc_loop, test_state, domain)
-
- # Run "rndc status" in 1-second intervals for a maximum of 10 seconds. If
- # any "rndc status" command fails, the loop will be interrupted.
- server_is_responsive = True
- attempts = 10
- while server_is_responsive and attempts > 0:
- server_is_responsive = check_if_server_is_responsive()
- attempts -= 1
- time.sleep(1)
-
- # Signal worker threads that the test is finished.
- test_state['finished'] = True
- executor.shutdown()
+ with concurrent.futures.ThreadPoolExecutor() as executor:
+ for i in range(1, 5):
+ domain = 'example%d' % i
+ executor.submit(rndc_loop, test_state, domain)
+
+ # Run "rndc status" in 1-second intervals for a maximum of 10 seconds.
+ # If any "rndc status" command fails, the loop will be interrupted.
+ server_is_responsive = True
+ attempts = 10
+ while server_is_responsive and attempts > 0:
+ server_is_responsive = check_if_server_is_responsive()
+ attempts -= 1
+ time.sleep(1)
+
+ # Signal worker threads that the test is finished.
+ test_state['finished'] = True
# Check whether all "rndc status" commands succeeded.
assert server_is_responsive
# We're going to execute queries in parallel by means of a thread pool.
# dnspython functions block, so we need to circunvent that.
- executor = ThreadPoolExecutor(n_workers + 1)
-
- # Helper dict, where keys=Future objects and values are tags used
- # to process results later.
- 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'
+ with ThreadPoolExecutor(n_workers + 1) as executor:
+
+ # Helper dict, where keys=Future objects and values are tags used
+ # to process results later.
+ 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'
- else:
- # We attempt to send couple rndc commands while named is
- # being shutdown
- futures[executor.submit(launch_rndc, ['status'])] = 'status'
-
- ret_code = -1
- for future in as_completed(futures):
- 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
+ else:
+ # We attempt to send couple rndc commands while named is
+ # being shutdown
+ futures[executor.submit(launch_rndc, ['status'])] = 'status'
- except (dns.resolver.NXDOMAIN, dns.exception.Timeout):
- pass
+ ret_code = -1
+ for future in as_completed(futures):
+ 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
- if kill_method == "rndc":
- assert ret_code == 0
+ except (dns.resolver.NXDOMAIN, dns.exception.Timeout):
+ pass
- executor.shutdown()
+ if kill_method == "rndc":
+ assert ret_code == 0
@pytest.mark.dnspython
rndc_cmd = [rndc, "-c", rndc_cfg, "-p", str(control_port),
"-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.
resolver = dns.resolver.Resolver()
resolver.nameservers = ['10.53.0.3']
# Method 2: killing with SIGTERM
# In both methods named should exit gracefully.
for kill_method in ("rndc", "sigterm"):
- named_proc = launch_named()
- # wait for named to finish loading
- for _ in range(10):
- try:
- resolver.query('version.bind', 'TXT', 'CH')
- break
- except (dns.resolver.NoNameservers, dns.exception.Timeout):
- time.sleep(1)
-
- do_work(named_proc, resolver, rndc_cmd,
- kill_method, n_workers=12, n_queries=16)
+ named_cmdline = [named, "-c", cfg_file, "-f"]
+ with subprocess.Popen(named_cmdline, cwd=cfg_dir) as named_proc:
+ # Ensure named is running
+ assert named_proc.poll() is None
+ # wait for named to finish loading
+ for _ in range(10):
+ try:
+ resolver.query('version.bind', 'TXT', 'CH')
+ break
+ except (dns.resolver.NoNameservers, dns.exception.Timeout):
+ time.sleep(1)
- # Wait named to exit for a maximum of MAX_TIMEOUT seconds.
- MAX_TIMEOUT = 10
- is_dead = False
- for _ in range(MAX_TIMEOUT):
- if named_proc.poll() is not None:
- is_dead = True
- break
- time.sleep(1)
+ do_work(named_proc, resolver, rndc_cmd,
+ kill_method, n_workers=12, n_queries=16)
- if not is_dead:
- named_proc.send_signal(signal.SIGABRT)
+ # Wait named to exit for a maximum of MAX_TIMEOUT seconds.
+ MAX_TIMEOUT = 10
+ 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.kill()
- assert is_dead
- # Ensures that named exited gracefully.
- # If it crashed (abort()) exitcode will be non zero.
- assert named_proc.returncode == 0
+ if not is_dead:
+ named_proc.send_signal(signal.SIGABRT)
+ 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.kill()
+
+ assert is_dead
+ # Ensures that named exited gracefully.
+ # If it crashed (abort()) exitcode will be non zero.
+ assert named_proc.returncode == 0