On Thu, Apr 29, 2021 at 1:51 PM Brendan Higgins <brendanhiggins@xxxxxxxxxx> wrote: > > Add basic support to run QEMU via kunit_tool. Add support for i386, > x86_64, arm, arm64, and a bunch more. Hmmm, I'm wondering if I'm seeing unrelated breakages. Applied these patches on top of 55ba0fe059a5 ("Merge tag 'for-5.13-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux") $ make mrproper $ rm -rf .kunit/* # just in case $ ./tools/testing/kunit/kunit.py run --arch=arm64 ... ERROR:root:arch/arm64/Makefile:25: ld does not support --fix-cortex-a53-843419; kernel may be susceptible to erratum arch/arm64/Makefile:44: Detected assembler with broken .inst; disassembly will be unreliable gcc: error: unrecognized command-line option ‘-mlittle-endian’ So it seems like my version of ld might be out of date, but my gcc is 10.2.1 Is there a minimum version of the toolchain this would expect that we can call out in the commit message (and in the Documentation)? --arch=x86_64 worked just fine for me, however, which is mainly what I was interested in. I've mainly just left some nits and comments regarding typechecking. > > Signed-off-by: Brendan Higgins <brendanhiggins@xxxxxxxxxx> > --- > tools/testing/kunit/kunit.py | 33 +++- > tools/testing/kunit/kunit_config.py | 2 +- > tools/testing/kunit/kunit_kernel.py | 207 +++++++++++++++++++++---- > tools/testing/kunit/kunit_tool_test.py | 15 +- > 4 files changed, 217 insertions(+), 40 deletions(-) > > diff --git a/tools/testing/kunit/kunit.py b/tools/testing/kunit/kunit.py > index d5144fcb03acd..07ef80062873b 100755 > --- a/tools/testing/kunit/kunit.py > +++ b/tools/testing/kunit/kunit.py > @@ -70,10 +70,10 @@ def build_tests(linux: kunit_kernel.LinuxSourceTree, > kunit_parser.print_with_timestamp('Building KUnit Kernel ...') > > build_start = time.time() > - success = linux.build_um_kernel(request.alltests, > - request.jobs, > - request.build_dir, > - request.make_options) > + success = linux.build_kernel(request.alltests, > + request.jobs, > + request.build_dir, > + request.make_options) > build_end = time.time() > if not success: > return KunitResult(KunitStatus.BUILD_FAILURE, > @@ -187,6 +187,14 @@ def add_common_opts(parser) -> None: > help='Path to Kconfig fragment that enables KUnit tests', > metavar='kunitconfig') > > + parser.add_argument('--arch', > + help='Specifies the architecture to run tests under.', optional: perhaps add "(e.g. x86_64, um)" Most people using this would be able to infer that, but I prefer strings that are basically enums to document examples of useful values. (And x86 is probably the one most people want to use this flag for). > + type=str, default='um', metavar='arch') > + > + parser.add_argument('--cross_compile', > + help='Sets make\'s CROSS_COMPILE variable.', > + metavar='cross_compile') > + > def add_build_opts(parser) -> None: > parser.add_argument('--jobs', > help='As in the make command, "Specifies the number of ' > @@ -268,7 +276,10 @@ def main(argv, linux=None): > os.mkdir(cli_args.build_dir) > > if not linux: > - linux = kunit_kernel.LinuxSourceTree(cli_args.build_dir, kunitconfig_path=cli_args.kunitconfig) > + linux = kunit_kernel.LinuxSourceTree(cli_args.build_dir, > + kunitconfig_path=cli_args.kunitconfig, > + arch=cli_args.arch, > + cross_compile=cli_args.cross_compile) > > request = KunitRequest(cli_args.raw_output, > cli_args.timeout, > @@ -287,7 +298,9 @@ def main(argv, linux=None): > os.mkdir(cli_args.build_dir) > > if not linux: > - linux = kunit_kernel.LinuxSourceTree(cli_args.build_dir, kunitconfig_path=cli_args.kunitconfig) > + linux = kunit_kernel.LinuxSourceTree(cli_args.build_dir, > + kunitconfig_path=cli_args.kunitconfig, > + arch=cli_args.arch) > > request = KunitConfigRequest(cli_args.build_dir, > cli_args.make_options) > @@ -299,7 +312,9 @@ def main(argv, linux=None): > sys.exit(1) > elif cli_args.subcommand == 'build': > if not linux: > - linux = kunit_kernel.LinuxSourceTree(cli_args.build_dir, kunitconfig_path=cli_args.kunitconfig) > + linux = kunit_kernel.LinuxSourceTree(cli_args.build_dir, > + kunitconfig_path=cli_args.kunitconfig, > + arch=cli_args.arch) > > request = KunitBuildRequest(cli_args.jobs, > cli_args.build_dir, > @@ -313,7 +328,9 @@ def main(argv, linux=None): > sys.exit(1) > elif cli_args.subcommand == 'exec': > if not linux: > - linux = kunit_kernel.LinuxSourceTree(cli_args.build_dir) > + linux = kunit_kernel.LinuxSourceTree(cli_args.build_dir, > + kunitconfig_path=cli_args.kunitconfig, > + arch=cli_args.arch) > > exec_request = KunitExecRequest(cli_args.timeout, > cli_args.build_dir, > diff --git a/tools/testing/kunit/kunit_config.py b/tools/testing/kunit/kunit_config.py > index 1e2683dcc0e7a..07d76be392544 100644 > --- a/tools/testing/kunit/kunit_config.py > +++ b/tools/testing/kunit/kunit_config.py > @@ -53,7 +53,7 @@ class Kconfig(object): > return True > > def write_to_file(self, path: str) -> None: > - with open(path, 'w') as f: > + with open(path, 'a+') as f: I might be missing something, but do we need this? w => a means we wouldn't truncate the file if it exists. I can imagine I'm missing something that makes it necessary. + => opens for read/write: we don't do any reads with f afaict. > for entry in self.entries(): > f.write(str(entry) + '\n') > > diff --git a/tools/testing/kunit/kunit_kernel.py b/tools/testing/kunit/kunit_kernel.py > index 7d5b77967d48f..b8b3b76aaa17e 100644 > --- a/tools/testing/kunit/kunit_kernel.py > +++ b/tools/testing/kunit/kunit_kernel.py > @@ -15,6 +15,8 @@ from typing import Iterator > > from contextlib import ExitStack > > +from collections import namedtuple > + > import kunit_config > import kunit_parser > > @@ -40,6 +42,10 @@ class BuildError(Exception): > class LinuxSourceTreeOperations(object): > """An abstraction over command line operations performed on a source tree.""" > > + def __init__(self, linux_arch, cross_compile): nit: let's annotate these as `linux_arch: str, cross_compile: str` (or is it Optional[str] here?) I can see a reader thinking arch might be an enum and that cross_compile might be a bool. > + self._linux_arch = linux_arch > + self._cross_compile = cross_compile > + > def make_mrproper(self) -> None: > try: > subprocess.check_output(['make', 'mrproper'], stderr=subprocess.STDOUT) > @@ -48,12 +54,18 @@ class LinuxSourceTreeOperations(object): > except subprocess.CalledProcessError as e: > raise ConfigError(e.output.decode()) > > + def make_arch_qemuconfig(self, build_dir): > + pass > + > def make_olddefconfig(self, build_dir, make_options) -> None: > - command = ['make', 'ARCH=um', 'olddefconfig'] > + command = ['make', 'ARCH=' + self._linux_arch, 'olddefconfig'] > + if self._cross_compile: > + command += ['CROSS_COMPILE=' + self._cross_compile] > if make_options: > command.extend(make_options) > if build_dir: > command += ['O=' + build_dir] > + print(' '.join(command)) > try: > subprocess.check_output(command, stderr=subprocess.STDOUT) > except OSError as e: > @@ -61,6 +73,154 @@ class LinuxSourceTreeOperations(object): > except subprocess.CalledProcessError as e: > raise ConfigError(e.output.decode()) > > + def make(self, jobs, build_dir, make_options) -> None: > + command = ['make', 'ARCH=' + self._linux_arch, '--jobs=' + str(jobs)] > + if make_options: > + command.extend(make_options) > + if self._cross_compile: > + command += ['CROSS_COMPILE=' + self._cross_compile] > + if build_dir: > + command += ['O=' + build_dir] > + print(' '.join(command)) > + try: > + proc = subprocess.Popen(command, > + stderr=subprocess.PIPE, > + stdout=subprocess.DEVNULL) > + except OSError as e: > + raise BuildError('Could not call execute make: ' + e) pytype complains about this. You'd want `+ str(e)` > + except subprocess.CalledProcessError as e: > + raise BuildError(e.output) > + _, stderr = proc.communicate() > + if proc.returncode != 0: > + raise BuildError(stderr.decode()) > + if stderr: # likely only due to build warnings > + print(stderr.decode()) > + > + def run(self, params, timeout, build_dir, outfile) -> None: > + pass > + > + > +QemuArchParams = namedtuple('QemuArchParams', ['linux_arch', > + 'qemuconfig', > + 'qemu_arch', > + 'kernel_path', > + 'kernel_command_line', > + 'extra_qemu_params']) > + > + > +QEMU_ARCHS = { > + 'i386' : QemuArchParams(linux_arch='i386', > + qemuconfig='CONFIG_SERIAL_8250=y\nCONFIG_SERIAL_8250_CONSOLE=y', > + qemu_arch='x86_64', > + kernel_path='arch/x86/boot/bzImage', > + kernel_command_line='console=ttyS0', > + extra_qemu_params=['']), > + 'x86_64' : QemuArchParams(linux_arch='x86_64', > + qemuconfig='CONFIG_SERIAL_8250=y\nCONFIG_SERIAL_8250_CONSOLE=y', > + qemu_arch='x86_64', > + kernel_path='arch/x86/boot/bzImage', > + kernel_command_line='console=ttyS0', > + extra_qemu_params=['']), > + 'arm' : QemuArchParams(linux_arch='arm', > + qemuconfig='''CONFIG_ARCH_VIRT=y > +CONFIG_SERIAL_AMBA_PL010=y > +CONFIG_SERIAL_AMBA_PL010_CONSOLE=y > +CONFIG_SERIAL_AMBA_PL011=y > +CONFIG_SERIAL_AMBA_PL011_CONSOLE=y''', > + qemu_arch='arm', > + kernel_path='arch/arm/boot/zImage', > + kernel_command_line='console=ttyAMA0', > + extra_qemu_params=['-machine virt']), > + 'arm64' : QemuArchParams(linux_arch='arm64', > + qemuconfig='''CONFIG_SERIAL_AMBA_PL010=y > +CONFIG_SERIAL_AMBA_PL010_CONSOLE=y > +CONFIG_SERIAL_AMBA_PL011=y > +CONFIG_SERIAL_AMBA_PL011_CONSOLE=y''', > + qemu_arch='aarch64', > + kernel_path='arch/arm64/boot/Image.gz', > + kernel_command_line='console=ttyAMA0', > + extra_qemu_params=['-machine virt', '-cpu cortex-a57']), > + 'alpha' : QemuArchParams(linux_arch='alpha', > + qemuconfig='CONFIG_SERIAL_8250=y\nCONFIG_SERIAL_8250_CONSOLE=y', > + qemu_arch='alpha', > + kernel_path='arch/alpha/boot/vmlinux', > + kernel_command_line='console=ttyS0', > + extra_qemu_params=['']), > + 'powerpc' : QemuArchParams(linux_arch='powerpc', > + qemuconfig='CONFIG_PPC64=y\nCONFIG_SERIAL_8250=y\nCONFIG_SERIAL_8250_CONSOLE=y\nCONFIG_HVC_CONSOLE=y', > + qemu_arch='ppc64', > + kernel_path='vmlinux', > + kernel_command_line='console=ttyS0', > + extra_qemu_params=['-M pseries', '-cpu power8']), > + 'riscv' : QemuArchParams(linux_arch='riscv', > + qemuconfig='CONFIG_SOC_VIRT=y\nCONFIG_SERIAL_8250=y\nCONFIG_SERIAL_8250_CONSOLE=y\nCONFIG_SERIAL_OF_PLATFORM=y\nCONFIG_SERIAL_EARLYCON_RISCV_SBI=y', > + qemu_arch='riscv64', > + kernel_path='arch/riscv/boot/Image', > + kernel_command_line='console=ttyS0', > + extra_qemu_params=['-machine virt', '-cpu rv64', '-bios opensbi-riscv64-generic-fw_dynamic.bin']), > + 's390' : QemuArchParams(linux_arch='s390', > + qemuconfig='CONFIG_EXPERT=y\nCONFIG_TUNE_ZEC12=y\nCONFIG_NUMA=y\nCONFIG_MODULES=y', > + qemu_arch='s390x', > + kernel_path='arch/s390/boot/bzImage', > + kernel_command_line='console=ttyS0', > + extra_qemu_params=[ > + '-machine s390-ccw-virtio', > + '-cpu qemu',]), > + 'sparc' : QemuArchParams(linux_arch='sparc', > + qemuconfig='CONFIG_SERIAL_8250=y\nCONFIG_SERIAL_8250_CONSOLE=y', > + qemu_arch='sparc', > + kernel_path='arch/sparc/boot/zImage', > + kernel_command_line='console=ttyS0 mem=256M', > + extra_qemu_params=['-m 256']), > +} Oh my. I don't know enough to say if there's a better way of doing this. But I think we should probably split this out into a separate python file, if this mapping remains necessary. E.g. in a qemu_configs.py file or the like. > + > +class LinuxSourceTreeOperationsQemu(LinuxSourceTreeOperations): I've called out the two errors pytype gives already, but mypy is even worse about this new class :( $ mypy tools/testing/kunit/*.py tools/testing/kunit/kunit_kernel.py:90: error: Unsupported operand types for + ("str" and "OSError") tools/testing/kunit/kunit_kernel.py:278: error: Incompatible types in assignment (expression has type "LinuxSourceTreeOperationsQemu", variable has type "Optional[LinuxSourceTreeOperationsUml]") tools/testing/kunit/kunit_kernel.py:298: error: Item "None" of "Optional[LinuxSourceTreeOperationsUml]" has no attribute "make_mrproper" tools/testing/kunit/kunit_kernel.py:324: error: Item "None" of "Optional[LinuxSourceTreeOperationsUml]" has no attribute "make_arch_qemuconfig" tools/testing/kunit/kunit_kernel.py:325: error: Item "None" of "Optional[LinuxSourceTreeOperationsUml]" has no attribute "make_olddefconfig" tools/testing/kunit/kunit_kernel.py:352: error: Item "None" of "Optional[LinuxSourceTreeOperationsUml]" has no attribute "make_allyesconfig" tools/testing/kunit/kunit_kernel.py:353: error: Item "None" of "Optional[LinuxSourceTreeOperationsUml]" has no attribute "make_arch_qemuconfig" tools/testing/kunit/kunit_kernel.py:354: error: Item "None" of "Optional[LinuxSourceTreeOperationsUml]" has no attribute "make_olddefconfig" tools/testing/kunit/kunit_kernel.py:355: error: Item "None" of "Optional[LinuxSourceTreeOperationsUml]" has no attribute "make" tools/testing/kunit/kunit_kernel.py:368: error: Item "None" of "Optional[LinuxSourceTreeOperationsUml]" has no attribute "run" So to make up for mypy being less smart, we can do this and get it down 2 errors diff --git a/tools/testing/kunit/kunit_kernel.py b/tools/testing/kunit/kunit_kernel.py index b8b3b76aaa17..a0aaa28db4c1 100644 --- a/tools/testing/kunit/kunit_kernel.py +++ b/tools/testing/kunit/kunit_kernel.py @@ -11,7 +11,7 @@ import subprocess import os import shutil import signal -from typing import Iterator +from typing import Iterator, Union from contextlib import ExitStack @@ -269,15 +269,16 @@ class LinuxSourceTree(object): def __init__(self, build_dir: str, load_config=True, kunitconfig_path='', arch=None, cross_compile=None) -> None: signal.signal(signal.SIGINT, self.signal_handler) - self._ops = None + ops = None # type: Union[None, LinuxSourceTreeOperationsUml, LinuxSourceTreeOperationsQemu] if arch is None or arch == 'um': self._arch = 'um' - self._ops = LinuxSourceTreeOperationsUml() + ops = LinuxSourceTreeOperationsUml() elif arch in QEMU_ARCHS: self._arch = arch - self._ops = LinuxSourceTreeOperationsQemu(QEMU_ARCHS[arch], cross_compile=cross_compile) + ops = LinuxSourceTreeOperationsQemu(QEMU_ARCHS[arch], cross_compile=cross_compile) else: raise ConfigError(arch + ' is not a valid arch') + self._ops = ops if not load_config: return > + > + def __init__(self, qemu_arch_params, cross_compile): > + super().__init__(linux_arch=qemu_arch_params.linux_arch, > + cross_compile=cross_compile) > + self._qemuconfig = qemu_arch_params.qemuconfig > + self._qemu_arch = qemu_arch_params.qemu_arch > + self._kernel_path = qemu_arch_params.kernel_path > + print(self._kernel_path) looks like a leftover debugging print statement? > + self._kernel_command_line = qemu_arch_params.kernel_command_line + ' kunit_shutdown=reboot' > + self._extra_qemu_params = qemu_arch_params.extra_qemu_params > + > + def make_arch_qemuconfig(self, build_dir): > + qemuconfig = kunit_config.Kconfig() > + qemuconfig.parse_from_string(self._qemuconfig) > + qemuconfig.write_to_file(get_kconfig_path(build_dir)) > + > + def run(self, params, timeout, build_dir, outfile): > + kernel_path = os.path.join(build_dir, self._kernel_path) > + qemu_command = ['qemu-system-' + self._qemu_arch, > + '-nodefaults', > + '-m', '1024', > + '-kernel', kernel_path, > + '-append', '\'' + ' '.join(params + [self._kernel_command_line]) + '\'', > + '-no-reboot', > + '-nographic', > + '-serial stdio'] + self._extra_qemu_params > + print(' '.join(qemu_command)) ditto, a debug statement? Though this one could be useful to actually print out for the user if we include some more context in the message. > + with open(outfile, 'w') as output: > + process = subprocess.Popen(' '.join(qemu_command), > + stdin=subprocess.PIPE, > + stdout=output, > + stderr=subprocess.STDOUT, > + text=True, shell=True) > + try: > + process.wait(timeout=timeout) > + except Exception as e: > + print(e) > + process.terminate() > + return process > + > +class LinuxSourceTreeOperationsUml(LinuxSourceTreeOperations): > + """An abstraction over command line operations performed on a source tree.""" > + > + def __init__(self): > + super().__init__(linux_arch='um', cross_compile=None) > + > def make_allyesconfig(self, build_dir, make_options) -> None: > kunit_parser.print_with_timestamp( > 'Enabling all CONFIGs for UML...') > @@ -83,32 +243,16 @@ class LinuxSourceTreeOperations(object): > kunit_parser.print_with_timestamp( > 'Starting Kernel with all configs takes a few minutes...') > > - def make(self, jobs, build_dir, make_options) -> None: > - command = ['make', 'ARCH=um', '--jobs=' + str(jobs)] > - if make_options: > - command.extend(make_options) > - if build_dir: > - command += ['O=' + build_dir] > - try: > - proc = subprocess.Popen(command, > - stderr=subprocess.PIPE, > - stdout=subprocess.DEVNULL) > - except OSError as e: > - raise BuildError('Could not call make command: ' + str(e)) > - _, stderr = proc.communicate() > - if proc.returncode != 0: > - raise BuildError(stderr.decode()) > - if stderr: # likely only due to build warnings > - print(stderr.decode()) > - > - def linux_bin(self, params, timeout, build_dir) -> None: > + def run(self, params, timeout, build_dir, outfile): > """Runs the Linux UML binary. Must be named 'linux'.""" > linux_bin = get_file_path(build_dir, 'linux') > outfile = get_outfile_path(build_dir) > with open(outfile, 'w') as output: > process = subprocess.Popen([linux_bin] + params, > + stdin=subprocess.PIPE, > stdout=output, > - stderr=subprocess.STDOUT) > + stderr=subprocess.STDOUT, > + text=True) > process.wait(timeout) > > def get_kconfig_path(build_dir) -> str: > @@ -123,10 +267,17 @@ def get_outfile_path(build_dir) -> str: > class LinuxSourceTree(object): > """Represents a Linux kernel source tree with KUnit tests.""" > > - def __init__(self, build_dir: str, load_config=True, kunitconfig_path='') -> None: > + def __init__(self, build_dir: str, load_config=True, kunitconfig_path='', arch=None, cross_compile=None) -> None: > signal.signal(signal.SIGINT, self.signal_handler) > - > - self._ops = LinuxSourceTreeOperations() > + self._ops = None > + if arch is None or arch == 'um': > + self._arch = 'um' > + self._ops = LinuxSourceTreeOperationsUml() > + elif arch in QEMU_ARCHS: > + self._arch = arch > + self._ops = LinuxSourceTreeOperationsQemu(QEMU_ARCHS[arch], cross_compile=cross_compile) > + else: > + raise ConfigError(arch + ' is not a valid arch') > > if not load_config: > return > @@ -170,6 +321,7 @@ class LinuxSourceTree(object): > os.mkdir(build_dir) > self._kconfig.write_to_file(kconfig_path) > try: > + self._ops.make_arch_qemuconfig(build_dir) > self._ops.make_olddefconfig(build_dir, make_options) > except ConfigError as e: > logging.error(e) > @@ -192,10 +344,13 @@ class LinuxSourceTree(object): > print('Generating .config ...') > return self.build_config(build_dir, make_options) > > - def build_um_kernel(self, alltests, jobs, build_dir, make_options) -> bool: > + def build_kernel(self, alltests, jobs, build_dir, make_options) -> bool: > try: > if alltests: > + if self._arch != 'um': > + raise ConfigError('Only the "um" arch is supported for alltests') > self._ops.make_allyesconfig(build_dir, make_options) Minor note: pytype doesn't like this. The code is correct, but pytype can't figure out that ops can't be the QEMU variant. Pytype recognizes comments like " # pytype: disable=attribute-error" but mypy doesn't. So I don't know that there's a way we can make both of them happy :/ > + self._ops.make_arch_qemuconfig(build_dir) > self._ops.make_olddefconfig(build_dir, make_options) > self._ops.make(jobs, build_dir, make_options) > except (ConfigError, BuildError) as e: > @@ -209,8 +364,8 @@ class LinuxSourceTree(object): > args.extend(['mem=1G', 'console=tty','kunit_shutdown=halt']) > if filter_glob: > args.append('kunit.filter_glob='+filter_glob) > - self._ops.linux_bin(args, timeout, build_dir) > outfile = get_outfile_path(build_dir) > + self._ops.run(args, timeout, build_dir, outfile) > subprocess.call(['stty', 'sane']) > with open(outfile, 'r') as file: > for line in file: > diff --git a/tools/testing/kunit/kunit_tool_test.py b/tools/testing/kunit/kunit_tool_test.py > index 1ad3049e90698..25e8be95a575d 100755 > --- a/tools/testing/kunit/kunit_tool_test.py > +++ b/tools/testing/kunit/kunit_tool_test.py > @@ -297,7 +297,7 @@ class KUnitMainTest(unittest.TestCase): > > self.linux_source_mock = mock.Mock() > self.linux_source_mock.build_reconfig = mock.Mock(return_value=True) > - self.linux_source_mock.build_um_kernel = mock.Mock(return_value=True) > + self.linux_source_mock.build_kernel = mock.Mock(return_value=True) > self.linux_source_mock.run_kernel = mock.Mock(return_value=all_passed_log) > > def test_config_passes_args_pass(self): > @@ -308,7 +308,7 @@ class KUnitMainTest(unittest.TestCase): > def test_build_passes_args_pass(self): > kunit.main(['build'], self.linux_source_mock) > self.assertEqual(self.linux_source_mock.build_reconfig.call_count, 0) > - self.linux_source_mock.build_um_kernel.assert_called_once_with(False, 8, '.kunit', None) > + self.linux_source_mock.build_kernel.assert_called_once_with(False, 8, '.kunit', None) > self.assertEqual(self.linux_source_mock.run_kernel.call_count, 0) > > def test_exec_passes_args_pass(self): > @@ -390,7 +390,7 @@ class KUnitMainTest(unittest.TestCase): > def test_build_builddir(self): > build_dir = '.kunit' > kunit.main(['build', '--build_dir', build_dir], self.linux_source_mock) > - self.linux_source_mock.build_um_kernel.assert_called_once_with(False, 8, build_dir, None) > + self.linux_source_mock.build_kernel.assert_called_once_with(False, 8, build_dir, None) > > def test_exec_builddir(self): > build_dir = '.kunit' > @@ -404,14 +404,19 @@ class KUnitMainTest(unittest.TestCase): > mock_linux_init.return_value = self.linux_source_mock > kunit.main(['run', '--kunitconfig=mykunitconfig']) > # Just verify that we parsed and initialized it correctly here. > - mock_linux_init.assert_called_once_with('.kunit', kunitconfig_path='mykunitconfig') > + mock_linux_init.assert_called_once_with('.kunit', > + kunitconfig_path='mykunitconfig', > + arch='um', > + cross_compile=None) > > @mock.patch.object(kunit_kernel, 'LinuxSourceTree') > def test_config_kunitconfig(self, mock_linux_init): > mock_linux_init.return_value = self.linux_source_mock > kunit.main(['config', '--kunitconfig=mykunitconfig']) > # Just verify that we parsed and initialized it correctly here. > - mock_linux_init.assert_called_once_with('.kunit', kunitconfig_path='mykunitconfig') > + mock_linux_init.assert_called_once_with('.kunit', > + kunitconfig_path='mykunitconfig', > + arch='um') > > if __name__ == '__main__': > unittest.main() > -- > 2.31.1.498.g6c1eba8ee3d-goog >