From d6224035d88a85f5f16f6072aa0f54b9936e73d8 Mon Sep 17 00:00:00 2001 From: Diego Fronza Date: Mon, 19 Apr 2021 14:23:31 -0300 Subject: [PATCH] Add system test for the deadlock fix The test spawns 4 parallel workers that keep adding, modifying and deleting zones, the main thread repeatedly checks wheter rndc status responds within a reasonable period. While environment and timing issues may affect the test, in most test cases the deadlock that was taking place before the fix used to trigger in less than 7 seconds in a machine with at least 2 cores. --- bin/tests/system/addzone/ns3/example.db | 2 + .../system/addzone/tests_rndc_deadlock.py | 90 +++++++++++++++++++ util/copyrights | 1 + 3 files changed, 93 insertions(+) create mode 100644 bin/tests/system/addzone/ns3/example.db create mode 100755 bin/tests/system/addzone/tests_rndc_deadlock.py diff --git a/bin/tests/system/addzone/ns3/example.db b/bin/tests/system/addzone/ns3/example.db new file mode 100644 index 0000000000..4f150a030a --- /dev/null +++ b/bin/tests/system/addzone/ns3/example.db @@ -0,0 +1,2 @@ +@ IN SOA localhost. localhost.localhost. 1 10800 3600 605800 86400 +@ IN NS localhost. diff --git a/bin/tests/system/addzone/tests_rndc_deadlock.py b/bin/tests/system/addzone/tests_rndc_deadlock.py new file mode 100755 index 0000000000..852c551a0d --- /dev/null +++ b/bin/tests/system/addzone/tests_rndc_deadlock.py @@ -0,0 +1,90 @@ +############################################################################ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. +############################################################################ + +import concurrent.futures +import os +import subprocess +import time + + +def run_rndc(server, rndc_command): + ''' + Send the specified 'rndc_command' to 'server' with a timeout of 2 seconds + ''' + rndc = os.getenv('RNDC') + port = os.getenv('CONTROLPORT') + + cmdline = [rndc, '-c', '../common/rndc.conf', '-p', port, '-s', server] + cmdline.extend(rndc_command) + + subprocess.check_output(cmdline, stderr=subprocess.STDOUT, timeout=2) + + +def rndc_loop(test_state, domain): + ''' + Run "rndc addzone", "rndc modzone", and "rndc delzone" in a tight loop + until the test is considered finished, ignoring errors + ''' + rndc_commands = [ + ['addzone', domain, + '{ type master; file "example.db"; };'], + ['modzone', domain, + '{ type master; file "example.db"; allow-transfer { any; }; };'], + ['delzone', domain], + ] + + while not test_state['finished']: + for command in rndc_commands: + try: + run_rndc('10.53.0.3', command) + except subprocess.SubprocessError: + pass + + +def check_if_server_is_responsive(): + ''' + Check if server status can be successfully retrieved using "rndc status" + ''' + try: + run_rndc('10.53.0.3', ['status']) + return True + except subprocess.SubprocessError: + return False + + +def test_rndc_deadlock(): + ''' + Test whether running "rndc addzone", "rndc modzone", and "rndc delzone" + commands concurrently does not trigger a 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) + + # 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() + + # Check whether all "rndc status" commands succeeded. + assert server_is_responsive diff --git a/util/copyrights b/util/copyrights index 92de9fbad9..13f643718c 100644 --- a/util/copyrights +++ b/util/copyrights @@ -221,6 +221,7 @@ ./bin/tests/system/addzone/ns2/default.nzf.in X 2010,2018,2019,2020 ./bin/tests/system/addzone/setup.sh SH 2010,2012,2013,2014,2016,2017,2018,2019,2020,2021 ./bin/tests/system/addzone/tests.sh SH 2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020,2021 +./bin/tests/system/addzone/tests_rndc_deadlock.py PYTHON 2021 ./bin/tests/system/allow-query/clean.sh SH 2010,2012,2014,2015,2016,2018,2019,2020,2021 ./bin/tests/system/allow-query/ns3/named.args X 2018,2019,2020,2021 ./bin/tests/system/allow-query/setup.sh SH 2010,2012,2016,2018,2019,2020,2021