blob: 5ef8fcd4781b25fd91c0b0fc467221b135cabb90 [file] [log] [blame]
# SPDX-License-Identifier: GPL-2.0
import logging
import subprocess
import os
import kunit_config
KCONFIG_PATH = '.config'
class ConfigError(Exception):
"""Represents an error trying to configure the Linux kernel."""
class BuildError(Exception):
"""Represents an error trying to build the Linux kernel."""
class LinuxSourceTreeOperations(object):
"""An abstraction over command line operations performed on a source tree."""
def make_mrproper(self):
try:
subprocess.check_output(['make', 'mrproper'])
except OSError as e:
raise ConfigError('Could not call make command: ' + e)
except subprocess.CalledProcessError as e:
raise ConfigError(e.output)
def make_olddefconfig(self):
try:
subprocess.check_output(['make', 'ARCH=um', 'olddefconfig'])
except OSError as e:
raise ConfigError('Could not call make command: ' + e)
except subprocess.CalledProcessError as e:
raise ConfigError(e.output)
def make(self):
try:
subprocess.check_output(['make', 'ARCH=um'])
except OSError as e:
raise BuildError('Could not call execute make: ' + e)
except subprocess.CalledProcessError as e:
raise BuildError(e.output)
def linux_bin(self, params, timeout):
"""Runs the Linux UML binary. Must be named 'linux'."""
process = subprocess.Popen(
['./linux'] + params,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
timed_out = False
try:
process.wait(timeout=timeout)
except subprocess.TimeoutExpired:
process.terminate()
timed_out = True
return process, timed_out
class LinuxSourceTree(object):
"""Represents a Linux kernel source tree with KUnit tests."""
def __init__(self):
self._kconfig = kunit_config.Kconfig()
self._kconfig.read_from_file('kunitconfig')
self._ops = LinuxSourceTreeOperations()
def clean(self):
try:
self._ops.make_mrproper()
except ConfigError as e:
logging.error(e)
return False
return True
def build_config(self):
self._kconfig.write_to_file(KCONFIG_PATH)
try:
self._ops.make_olddefconfig()
except ConfigError as e:
logging.error(e)
return False
validated_kconfig = kunit_config.Kconfig()
validated_kconfig.read_from_file(KCONFIG_PATH)
if not self._kconfig.is_subset_of(validated_kconfig):
logging.error('Provided Kconfig is not contained in validated .config!')
return False
return True
def build_reconfig(self):
"""Creates a new .config if it is not a subset of the kunitconfig."""
if os.path.exists(KCONFIG_PATH):
existing_kconfig = kunit_config.Kconfig()
existing_kconfig.read_from_file(KCONFIG_PATH)
if not self._kconfig.is_subset_of(existing_kconfig):
print('Regenerating .config ...')
os.remove(KCONFIG_PATH)
return self.build_config()
else:
return True
else:
print('Generating .config ...')
return self.build_config()
def build_um_kernel(self):
try:
self._ops.make_olddefconfig()
self._ops.make()
except (ConfigError, BuildError) as e:
logging.error(e)
return False
used_kconfig = kunit_config.Kconfig()
used_kconfig.read_from_file(KCONFIG_PATH)
if not self._kconfig.is_subset_of(used_kconfig):
logging.error('Provided Kconfig is not contained in final config!')
return False
return True
def run_kernel(self, args=[], timeout=None):
args.extend(['mem=256M'])
process, timed_out = self._ops.linux_bin(args, timeout)
with open('test.log', 'w') as f:
for line in process.stdout:
f.write(line.rstrip().decode('ascii') + '\n')
yield line.rstrip().decode('ascii')
if timed_out:
f.write('Timeout Reached - Process Terminated\n')
yield 'Timeout Reached - Process Terminated\n'