kumquat-buildroot/support/testing/infra/emulator.py
Luca Ceresoli d332f2c521 support/testing: simplify logging by keeping the log file open
We currently call infra.smart_open() to open log files each time we
need to write to them.

Opening the file once in the constructor of Builder and Emulator and
writing to it whenever needed is simpler and slightly more efficient.

Remove smart_open and instead create a new open_log_file() function
which just opens the logfile. Also let it compute the filename, in
order to simplify even further the Builder and Emulator code.

Signed-off-by: Luca Ceresoli <luca@lucaceresoli.net>
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
2017-05-17 21:59:58 +02:00

131 lines
4.3 KiB
Python

import socket
import subprocess
import telnetlib
import infra
import infra.basetest
# TODO: Most of the telnet stuff need to be replaced by stdio/pexpect to discuss
# with the qemu machine.
class Emulator(object):
def __init__(self, builddir, downloaddir, logtofile):
self.qemu = None
self.__tn = None
self.downloaddir = downloaddir
self.log = ""
self.logfile = infra.open_log_file(builddir, "run", logtofile)
# Start Qemu to boot the system
#
# arch: Qemu architecture to use
#
# kernel: path to the kernel image, or the special string
# 'builtin'. 'builtin' means a pre-built kernel image will be
# downloaded from ARTEFACTS_URL and suitable options are
# automatically passed to qemu and added to the kernel cmdline. So
# far only armv5, armv7 and i386 builtin kernels are available.
# If None, then no kernel is used, and we assume a bootable device
# will be specified.
#
# kernel_cmdline: array of kernel arguments to pass to Qemu -append option
#
# options: array of command line options to pass to Qemu
#
def boot(self, arch, kernel=None, kernel_cmdline=None, options=None):
if arch in ["armv7", "armv5"]:
qemu_arch = "arm"
else:
qemu_arch = arch
qemu_cmd = ["qemu-system-{}".format(qemu_arch),
"-serial", "telnet::1234,server",
"-display", "none"]
if options:
qemu_cmd += options
if kernel_cmdline is None:
kernel_cmdline = []
if kernel:
if kernel == "builtin":
if arch in ["armv7", "armv5"]:
kernel_cmdline.append("console=ttyAMA0")
if arch == "armv7":
kernel = infra.download(self.downloaddir,
"kernel-vexpress")
dtb = infra.download(self.downloaddir,
"vexpress-v2p-ca9.dtb")
qemu_cmd += ["-dtb", dtb]
qemu_cmd += ["-M", "vexpress-a9"]
elif arch == "armv5":
kernel = infra.download(self.downloaddir,
"kernel-versatile")
qemu_cmd += ["-M", "versatilepb"]
qemu_cmd += ["-kernel", kernel]
if kernel_cmdline:
qemu_cmd += ["-append", " ".join(kernel_cmdline)]
self.logfile.write("> starting qemu with '%s'\n" % " ".join(qemu_cmd))
self.qemu = subprocess.Popen(qemu_cmd, stdout=self.logfile, stderr=self.logfile)
# Wait for the telnet port to appear and connect to it.
while True:
try:
self.__tn = telnetlib.Telnet("localhost", 1234)
if self.__tn:
break
except socket.error:
continue
def __read_until(self, waitstr, timeout=5):
data = self.__tn.read_until(waitstr, timeout)
self.log += data
self.logfile.write(data)
return data
def __write(self, wstr):
self.__tn.write(wstr)
# Wait for the login prompt to appear, and then login as root with
# the provided password, or no password if not specified.
def login(self, password=None):
self.__read_until("buildroot login:", 10)
if "buildroot login:" not in self.log:
self.logfile.write("==> System does not boot")
raise SystemError("System does not boot")
self.__write("root\n")
if password:
self.__read_until("Password:")
self.__write(password + "\n")
self.__read_until("# ")
if "# " not in self.log:
raise SystemError("Cannot login")
self.run("dmesg -n 1")
# Run the given 'cmd' on the target
# return a tuple (output, exit_code)
def run(self, cmd):
self.__write(cmd + "\n")
output = self.__read_until("# ")
output = output.strip().splitlines()
output = output[1:len(output)-1]
self.__write("echo $?\n")
exit_code = self.__read_until("# ")
exit_code = exit_code.strip().splitlines()[1]
exit_code = int(exit_code)
return output, exit_code
def stop(self):
if self.qemu is None:
return
self.qemu.terminate()
self.qemu.kill()