diff --git a/bin/tests/system/addzone/tests_rndc_deadlock.py b/bin/tests/system/addzone/tests_rndc_deadlock.py index 852c551a0d..4e1e1090ba 100755 --- a/bin/tests/system/addzone/tests_rndc_deadlock.py +++ b/bin/tests/system/addzone/tests_rndc_deadlock.py @@ -68,23 +68,22 @@ def test_rndc_deadlock(): 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) + 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) + # 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() + # Signal worker threads that the test is finished. + test_state['finished'] = True # Check whether all "rndc status" commands succeeded. assert server_is_responsive diff --git a/bin/tests/system/shutdown/tests-shutdown.py b/bin/tests/system/shutdown/tests-shutdown.py index e1ed83f242..1556f9f5fb 100755 --- a/bin/tests/system/shutdown/tests-shutdown.py +++ b/bin/tests/system/shutdown/tests-shutdown.py @@ -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. # 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 - # to process results later. - futures = {} + # 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' - # 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)) + # We attempt to send couple rndc commands while named is + # being shutdown + futures[executor.submit(launch_rndc, ['status'])] = 'status' - 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' + 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 - - except (dns.resolver.NXDOMAIN, dns.exception.Timeout): - pass - - if kill_method == "rndc": - assert ret_code == 0 - - executor.shutdown() + if kill_method == "rndc": + assert ret_code == 0 @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), "-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'] @@ -167,38 +157,41 @@ def test_named_shutdown(named_port, control_port): # 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) + 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) - do_work(named_proc, resolver, rndc_cmd, - kill_method, n_workers=12, n_queries=16) + do_work(named_proc, resolver, rndc_cmd, + kill_method, n_workers=12, n_queries=16) - # 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.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