docs: Fix empty parallelism argument
[linux-2.6-microblaze.git] / tools / testing / kunit / kunit_kernel.py
1 # SPDX-License-Identifier: GPL-2.0
2 #
3 # Runs UML kernel, collects output, and handles errors.
4 #
5 # Copyright (C) 2019, Google LLC.
6 # Author: Felix Guo <felixguoxiuping@gmail.com>
7 # Author: Brendan Higgins <brendanhiggins@google.com>
8
9
10 import logging
11 import subprocess
12 import os
13
14 import kunit_config
15
16 KCONFIG_PATH = '.config'
17 kunitconfig_path = '.kunitconfig'
18
19 class ConfigError(Exception):
20         """Represents an error trying to configure the Linux kernel."""
21
22
23 class BuildError(Exception):
24         """Represents an error trying to build the Linux kernel."""
25
26
27 class LinuxSourceTreeOperations(object):
28         """An abstraction over command line operations performed on a source tree."""
29
30         def make_mrproper(self):
31                 try:
32                         subprocess.check_output(['make', 'mrproper'])
33                 except OSError as e:
34                         raise ConfigError('Could not call make command: ' + e)
35                 except subprocess.CalledProcessError as e:
36                         raise ConfigError(e.output)
37
38         def make_olddefconfig(self, build_dir):
39                 command = ['make', 'ARCH=um', 'olddefconfig']
40                 if build_dir:
41                         command += ['O=' + build_dir]
42                 try:
43                         subprocess.check_output(command)
44                 except OSError as e:
45                         raise ConfigError('Could not call make command: ' + e)
46                 except subprocess.CalledProcessError as e:
47                         raise ConfigError(e.output)
48
49         def make(self, jobs, build_dir):
50                 command = ['make', 'ARCH=um', '--jobs=' + str(jobs)]
51                 if build_dir:
52                         command += ['O=' + build_dir]
53                 try:
54                         subprocess.check_output(command)
55                 except OSError as e:
56                         raise BuildError('Could not call execute make: ' + e)
57                 except subprocess.CalledProcessError as e:
58                         raise BuildError(e.output)
59
60         def linux_bin(self, params, timeout, build_dir):
61                 """Runs the Linux UML binary. Must be named 'linux'."""
62                 linux_bin = './linux'
63                 if build_dir:
64                         linux_bin = os.path.join(build_dir, 'linux')
65                 process = subprocess.Popen(
66                         [linux_bin] + params,
67                         stdin=subprocess.PIPE,
68                         stdout=subprocess.PIPE,
69                         stderr=subprocess.PIPE)
70                 process.wait(timeout=timeout)
71                 return process
72
73
74 def get_kconfig_path(build_dir):
75         kconfig_path = KCONFIG_PATH
76         if build_dir:
77                 kconfig_path = os.path.join(build_dir, KCONFIG_PATH)
78         return kconfig_path
79
80 class LinuxSourceTree(object):
81         """Represents a Linux kernel source tree with KUnit tests."""
82
83         def __init__(self):
84                 self._kconfig = kunit_config.Kconfig()
85                 self._kconfig.read_from_file(kunitconfig_path)
86                 self._ops = LinuxSourceTreeOperations()
87
88         def clean(self):
89                 try:
90                         self._ops.make_mrproper()
91                 except ConfigError as e:
92                         logging.error(e)
93                         return False
94                 return True
95
96         def build_config(self, build_dir):
97                 kconfig_path = get_kconfig_path(build_dir)
98                 if build_dir and not os.path.exists(build_dir):
99                         os.mkdir(build_dir)
100                 self._kconfig.write_to_file(kconfig_path)
101                 try:
102                         self._ops.make_olddefconfig(build_dir)
103                 except ConfigError as e:
104                         logging.error(e)
105                         return False
106                 validated_kconfig = kunit_config.Kconfig()
107                 validated_kconfig.read_from_file(kconfig_path)
108                 if not self._kconfig.is_subset_of(validated_kconfig):
109                         logging.error('Provided Kconfig is not contained in validated .config!')
110                         return False
111                 return True
112
113         def build_reconfig(self, build_dir):
114                 """Creates a new .config if it is not a subset of the .kunitconfig."""
115                 kconfig_path = get_kconfig_path(build_dir)
116                 if os.path.exists(kconfig_path):
117                         existing_kconfig = kunit_config.Kconfig()
118                         existing_kconfig.read_from_file(kconfig_path)
119                         if not self._kconfig.is_subset_of(existing_kconfig):
120                                 print('Regenerating .config ...')
121                                 os.remove(kconfig_path)
122                                 return self.build_config(build_dir)
123                         else:
124                                 return True
125                 else:
126                         print('Generating .config ...')
127                         return self.build_config(build_dir)
128
129         def build_um_kernel(self, jobs, build_dir):
130                 try:
131                         self._ops.make_olddefconfig(build_dir)
132                         self._ops.make(jobs, build_dir)
133                 except (ConfigError, BuildError) as e:
134                         logging.error(e)
135                         return False
136                 used_kconfig = kunit_config.Kconfig()
137                 used_kconfig.read_from_file(get_kconfig_path(build_dir))
138                 if not self._kconfig.is_subset_of(used_kconfig):
139                         logging.error('Provided Kconfig is not contained in final config!')
140                         return False
141                 return True
142
143         def run_kernel(self, args=[], timeout=None, build_dir=''):
144                 args.extend(['mem=256M'])
145                 process = self._ops.linux_bin(args, timeout, build_dir)
146                 with open(os.path.join(build_dir, 'test.log'), 'w') as f:
147                         for line in process.stdout:
148                                 f.write(line.rstrip().decode('ascii') + '\n')
149                                 yield line.rstrip().decode('ascii')