[Tests] Shutdown test daemon cleanly using rpc. (needed for Windows)

Escape backslashes in config path for test daemon startup.
This commit is contained in:
Chase Sterling 2022-01-25 23:56:40 -05:00 committed by Calum Lind
parent 3dca30343f
commit 209716f7cd
No known key found for this signature in database
GPG Key ID: 90597A687B836BA3
1 changed files with 38 additions and 8 deletions

View File

@ -19,7 +19,9 @@ from twisted.trial import unittest
import deluge.configmanager import deluge.configmanager
import deluge.core.preferencesmanager import deluge.core.preferencesmanager
import deluge.log import deluge.log
from deluge.common import get_localhost_auth
from deluge.error import DelugeError from deluge.error import DelugeError
from deluge.ui.client import client
# This sets log level to critical, so use log.critical() to debug while running unit tests # This sets log level to critical, so use log.critical() to debug while running unit tests
deluge.log.setup_logger('none') deluge.log.setup_logger('none')
@ -94,12 +96,19 @@ class ReactorOverride:
class ProcessOutputHandler(protocol.ProcessProtocol): class ProcessOutputHandler(protocol.ProcessProtocol):
def __init__( def __init__(
self, script, callbacks, logfile=None, print_stdout=True, print_stderr=True self,
script,
shutdown_func,
callbacks,
logfile=None,
print_stdout=True,
print_stderr=True,
): ):
"""Executes a script and handle the process' output to stdout and stderr. """Executes a script and handle the process' output to stdout and stderr.
Args: Args:
script (str): The script to execute. script (str): The script to execute.
shutdown_func (func): A function which will gracefully stop the called script.
callbacks (list): Callbacks to trigger if the expected output if found. callbacks (list): Callbacks to trigger if the expected output if found.
logfile (str, optional): Filename to wrote the process' output. logfile (str, optional): Filename to wrote the process' output.
print_stderr (bool): Print the process' stderr output to stdout. print_stderr (bool): Print the process' stderr output to stdout.
@ -108,6 +117,7 @@ class ProcessOutputHandler(protocol.ProcessProtocol):
""" """
self.callbacks = callbacks self.callbacks = callbacks
self.script = script self.script = script
self.shutdown_func = shutdown_func
self.log_output = '' self.log_output = ''
self.stderr_out = '' self.stderr_out = ''
self.logfile = logfile self.logfile = logfile
@ -127,6 +137,7 @@ class ProcessOutputHandler(protocol.ProcessProtocol):
with open(self.logfile, 'w') as f: with open(self.logfile, 'w') as f:
f.write(self.log_output) f.write(self.log_output)
@defer.inlineCallbacks
def kill(self): def kill(self):
"""Kill the running process. """Kill the running process.
@ -139,8 +150,13 @@ class ProcessOutputHandler(protocol.ProcessProtocol):
self.killed = True self.killed = True
self._kill_watchdogs() self._kill_watchdogs()
self.quit_d = Deferred() self.quit_d = Deferred()
self.transport.signalProcess('INT') shutdown = self.shutdown_func()
return self.quit_d shutdown.addTimeout(5, reactor)
try:
yield shutdown
except Exception:
self.transport.signalProcess('TERM')
yield self.quit_d
def _kill_watchdogs(self): def _kill_watchdogs(self):
""""Cancel all watchdogs""" """"Cancel all watchdogs"""
@ -216,7 +232,7 @@ def start_core(
Args: Args:
listen_port (int, optional): The port the daemon listens for client connections. listen_port (int, optional): The port the daemon listens for client connections.
logfile (str, optional): Logfile name to write the output from the process. logfile (str, optional): Logfile name to write the output from the process.
timeout (int): If none of the callbacks have been triggered before the imeout, the process is killed. timeout (int): If none of the callbacks have been triggered before the timeout, the process is killed.
timeout_msg (str): The message to print when the timeout expires. timeout_msg (str): The message to print when the timeout expires.
custom_script (str): Extra python code to insert into the daemon process script. custom_script (str): Extra python code to insert into the daemon process script.
print_stderr (bool): If the output from the process' stderr should be printed to stdout. print_stderr (bool): If the output from the process' stderr should be printed to stdout.
@ -251,7 +267,7 @@ except Exception:
import traceback import traceback
sys.stderr.write('Exception raised:\\n %%s' %% traceback.format_exc()) sys.stderr.write('Exception raised:\\n %%s' %% traceback.format_exc())
""" % { """ % {
'dir': config_directory, 'dir': config_directory.replace('\\', '\\\\'),
'port': listen_port, 'port': listen_port,
'script': custom_script, 'script': custom_script,
} }
@ -286,20 +302,29 @@ except Exception:
if extra_callbacks: if extra_callbacks:
callbacks.extend(extra_callbacks) callbacks.extend(extra_callbacks)
@defer.inlineCallbacks
def shutdown_daemon():
username, password = get_localhost_auth()
yield client.connect(
'localhost', listen_port, username=username, password=password
)
yield client.daemon.shutdown()
process_protocol = start_process( process_protocol = start_process(
daemon_script, callbacks, logfile, print_stdout, print_stderr daemon_script, shutdown_daemon, callbacks, logfile, print_stdout, print_stderr
) )
return default_core_cb['deferred'], process_protocol return default_core_cb['deferred'], process_protocol
def start_process( def start_process(
script, callbacks, logfile=None, print_stdout=True, print_stderr=True script, shutdown_func, callbacks, logfile=None, print_stdout=True, print_stderr=True
): ):
""" """
Starts an external python process which executes the given script. Starts an external python process which executes the given script.
Args: Args:
script (str): The content of the script to execute. script (str): The content of the script to execute.
shutdown_func (func): A function which will gracefully end the called script.
callbacks (list): list of dictionaries specifying callbacks. callbacks (list): list of dictionaries specifying callbacks.
logfile (str, optional): Logfile name to write the output from the process. logfile (str, optional): Logfile name to write the output from the process.
print_stderr (bool): If the output from the process' stderr should be printed to stdout. print_stderr (bool): If the output from the process' stderr should be printed to stdout.
@ -321,7 +346,12 @@ def start_process(
""" """
cwd = os.path.dirname(os.path.dirname(os.path.dirname(__file__))) cwd = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
process_protocol = ProcessOutputHandler( process_protocol = ProcessOutputHandler(
script.encode('utf8'), callbacks, logfile, print_stdout, print_stderr script.encode('utf8'),
shutdown_func,
callbacks,
logfile,
print_stdout,
print_stderr,
) )
# Add timeouts to deferreds # Add timeouts to deferreds