Support multiple ways of driving hftests, add UART
Move logic that gets the boot arguments of hftest to a separate build
target and implement the same interface for communicating over UART.
Add SerialDriver to hftest.py that drives the communication with a
device over serial port.
The UART backend for hftest depends on an implementation of
'hftest_device' interface to reboot the board when the test has
finished.
Change-Id: Idfcb2c6e9af9cd283e360993fa2580d4fea49594
diff --git a/test/hftest/hftest.py b/test/hftest/hftest.py
index cd60585..91c2782 100755
--- a/test/hftest/hftest.py
+++ b/test/hftest/hftest.py
@@ -28,6 +28,7 @@
import json
import os
import re
+import serial
import subprocess
import sys
@@ -35,6 +36,9 @@
HFTEST_LOG_FAILURE_PREFIX = "Failure:"
HFTEST_LOG_FINISHED = "FINISHED"
+HFTEST_CTRL_GET_COMMAND_LINE = "[hftest_ctrl:get_command_line]"
+HFTEST_CTRL_FINISHED = "[hftest_ctrl:finished]"
+
HF_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(
os.path.abspath(__file__))))
DTC_SCRIPT = os.path.join(HF_ROOT, "build", "image", "dtc.py")
@@ -116,7 +120,9 @@
"kernel",
"initrd",
"vm_args",
- "cpu"
+ "cpu",
+ "serial_dev",
+ "serial_baudrate",
])
@@ -337,6 +343,42 @@
return self.finish_run(run_state)
+class SerialDriver(Driver):
+ """Driver which communicates with a device over the serial port."""
+
+ def __init__(self, args):
+ Driver.__init__(self, args)
+ self.tty_file = self.args.serial_dev
+ self.baudrate = self.args.serial_baudrate
+ input("Press ENTER and then reset the device...")
+
+ def run(self, run_name, test_args, is_long_running):
+ """Communicate `test_args` to the device over the serial port."""
+ run_state = self.start_run(run_name)
+
+ with serial.Serial(self.tty_file, self.baudrate, timeout=10) as ser:
+ with open(run_state.log_path, "a") as f:
+ while True:
+ # Read one line from the serial port.
+ line = ser.readline().decode('utf-8')
+ if len(line) == 0:
+ # Timeout
+ run_state.set_ret_code(124)
+ input("Timeout. " +
+ "Press ENTER and then reset the device...")
+ break
+ # Write the line to the log file.
+ f.write(line)
+ if HFTEST_CTRL_GET_COMMAND_LINE in line:
+ # Device is waiting for `test_args`.
+ ser.write(test_args.encode('ascii'))
+ ser.write(b'\r')
+ elif HFTEST_CTRL_FINISHED in line:
+ # Device has finished running this test and will reboot.
+ break
+ return self.finish_run(run_state)
+
+
# Tuple used to return information about the results of running a set of tests.
TestRunnerResult = collections.namedtuple("TestRunnerResult", [
"tests_run",
@@ -503,7 +545,9 @@
parser.add_argument("--suite")
parser.add_argument("--test")
parser.add_argument("--vm_args")
- parser.add_argument("--fvp", action="store_true")
+ parser.add_argument("--driver", default="qemu")
+ parser.add_argument("--serial-dev", default="/dev/ttyUSB0")
+ parser.add_argument("--serial-baudrate", type=int, default=115200)
parser.add_argument("--skip-long-running-tests", action="store_true")
parser.add_argument("--cpu",
help="Selects the CPU configuration for the run environment.")
@@ -523,12 +567,17 @@
artifacts = ArtifactsManager(os.path.join(args.log, image_name))
# Create a driver for the platform we want to test on.
- driver_args = DriverArgs(artifacts, image, initrd, vm_args,
- args.cpu)
- if args.fvp:
- driver = FvpDriver(driver_args)
- else:
+ driver_args = DriverArgs(artifacts, image, initrd, vm_args, args.cpu,
+ args.serial_dev, args.serial_baudrate)
+
+ if args.driver == "qemu":
driver = QemuDriver(driver_args)
+ elif args.driver == "fvp":
+ driver = FvpDriver(driver_args)
+ elif args.driver == "serial":
+ driver = SerialDriver(driver_args)
+ else:
+ raise Exception("Unknown driver name: {}".format(args.driver))
# Create class which will drive test execution.
runner = TestRunner(artifacts, driver, image_name, args.suite, args.test,