Use x52ctl to test daemon communication

This allows us to test x52ctl as well as the daemon communication
infrastructure.
update-lkm
nirenjan 2022-09-23 10:02:17 -07:00
parent ccabb5c953
commit b810c457f9
1 changed files with 31 additions and 21 deletions

View File

@ -1,5 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
"""Test communication with x52d and verify that the behavior is as expected""" """Test communication with x52d and verify that the behavior is as expected"""
# pylint: disable=consider-using-f-string
import glob import glob
import os import os
@ -7,7 +8,6 @@ import os.path
import platform import platform
import shlex import shlex
import signal import signal
import socket
import subprocess import subprocess
import tempfile import tempfile
import time import time
@ -29,10 +29,10 @@ class TestCase:
space separated expected response, possibly quoted space separated expected response, possibly quoted
""" """
self.desc, in_cmd, exp_resp = data.splitlines() self.desc, in_cmd, exp_resp = data.splitlines()
self.in_cmd = '\0'.join(shlex.split(in_cmd)).encode() + b'\0' self.in_cmd = shlex.split(in_cmd)
self.exp_resp = '\0'.join(shlex.split(exp_resp)).encode() + b'\0' self.exp_resp = '\0'.join(shlex.split(exp_resp)).encode() + b'\0'
def execute(self, index, cmdsock): def execute(self, index, suite):
"""Execute the test case and return the result in TAP format""" """Execute the test case and return the result in TAP format"""
def dump_failed(name, value): def dump_failed(name, value):
"""Dump the failed test case""" """Dump the failed test case"""
@ -48,13 +48,20 @@ class TestCase:
out = "not " + out out = "not " + out
print(out) print(out)
cmdsock.send(self.in_cmd) cmd = [suite.find_control_program(),
got_resp = cmdsock.recv(1024) '-s', suite.command, '--',
*self.in_cmd]
if got_resp != self.exp_resp: testcase = subprocess.run(cmd, stdout=subprocess.PIPE, check=False)
if testcase.returncode != 0:
print_result(False)
print("# x52ctl returned code: {}".format(testcase.returncode))
dump_failed("Expected", self.exp_resp)
dump_failed("Got", testcase.stdout)
elif testcase.stdout != self.exp_resp:
print_result(False) print_result(False)
dump_failed("Expected", self.exp_resp) dump_failed("Expected", self.exp_resp)
dump_failed("Got", got_resp) dump_failed("Got", testcase.stdout)
else: else:
print_result(True) print_result(True)
@ -65,10 +72,9 @@ class Test:
def __init__(self): def __init__(self):
"""Create a new instance of the Test class""" """Create a new instance of the Test class"""
self.program = self.find_daemon_program() self.program = self.find_daemon_program()
self.tmpdir = tempfile.TemporaryDirectory() self.tmpdir = tempfile.TemporaryDirectory() # pylint: disable=consider-using-with
self.command = os.path.join(self.tmpdir.name, "x52d.cmd") self.command = os.path.join(self.tmpdir.name, "x52d.cmd")
self.notify = os.path.join(self.tmpdir.name, "x52d.notify") self.notify = os.path.join(self.tmpdir.name, "x52d.notify")
self.cmdsock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
self.daemon = None self.daemon = None
self.testcases = [] self.testcases = []
@ -93,6 +99,17 @@ class Test:
return os.path.realpath(daemon_candidates[0]) return os.path.realpath(daemon_candidates[0])
@staticmethod
def find_control_program():
"""Find the control program. This script should be run from the
root of the build directory"""
ctl_candidates = glob.glob('**/x52ctl', recursive=True)
if not ctl_candidates:
print("Bail out! Unable to find x52ctl.")
sys.exit(1)
return os.path.realpath(ctl_candidates[0])
def launch_daemon(self): def launch_daemon(self):
"""Launch an instance of the running daemon""" """Launch an instance of the running daemon"""
if self.daemon is not None: if self.daemon is not None:
@ -105,7 +122,7 @@ class Test:
daemon_cmdline = [ daemon_cmdline = [
self.program, self.program,
"-f", # Run in foreground "-f", # Run in foreground
"-v", # Verbose logging "-q", # Quiet logging
"-c", os.path.join(self.tmpdir.name, "x52d.cfg"), # Default config file "-c", os.path.join(self.tmpdir.name, "x52d.cfg"), # Default config file
"-l", os.path.join(self.tmpdir.name, "x52d.log"), # Output logs to log file "-l", os.path.join(self.tmpdir.name, "x52d.log"), # Output logs to log file
"-p", os.path.join(self.tmpdir.name, "x52d.pid"), # PID file "-p", os.path.join(self.tmpdir.name, "x52d.pid"), # PID file
@ -114,26 +131,19 @@ class Test:
] ]
# Create empty config file # Create empty config file
with open(daemon_cmdline[4], 'w'): with open(daemon_cmdline[4], 'w', encoding='utf-8'):
pass pass
self.daemon = subprocess.Popen(daemon_cmdline) self.daemon = subprocess.Popen(daemon_cmdline) # pylint: disable=consider-using-with
print("# Sleeping 2 seconds for daemon to start") print("# Sleeping 2 seconds for daemon to start")
time.sleep(2) time.sleep(2)
self.cmdsock.connect(self.command)
def terminate_daemon(self): def terminate_daemon(self):
"""Terminate a running daemon""" """Terminate a running daemon"""
if self.daemon is None: if self.daemon is None:
return return
# Close the command socket and wait 2 seconds for the daemon
# to deregister the client
self.cmdsock.close()
time.sleep(2)
# Send a SIGTERM to the daemon # Send a SIGTERM to the daemon
os.kill(self.daemon.pid, signal.SIGTERM) os.kill(self.daemon.pid, signal.SIGTERM)
try: try:
@ -164,7 +174,7 @@ class Test:
"""Run test cases""" """Run test cases"""
print("1..{}".format(len(self.testcases))) print("1..{}".format(len(self.testcases)))
for index, testcase in enumerate(self.testcases): for index, testcase in enumerate(self.testcases):
testcase.execute(index, self.cmdsock) testcase.execute(index, self)
def find_and_parse_testcase_files(self): def find_and_parse_testcase_files(self):
"""Find and parse *.tc files""" """Find and parse *.tc files"""
@ -173,7 +183,7 @@ class Test:
tc_files = sorted(glob.glob(pattern, recursive=True)) tc_files = sorted(glob.glob(pattern, recursive=True))
for tc_file in tc_files: for tc_file in tc_files:
with open(tc_file) as tc_fd: with open(tc_file, encoding='utf-8') as tc_fd:
# Test cases are separated by blank lines # Test cases are separated by blank lines
testcases = tc_fd.read().split('\n\n') testcases = tc_fd.read().split('\n\n')
self.extend(TestCase(tc_data) for tc_data in testcases) self.extend(TestCase(tc_data) for tc_data in testcases)