OSDN Git Service

Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
[tomoyo/tomoyo-test1.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 validate_config(self, build_dir):
97                 kconfig_path = get_kconfig_path(build_dir)
98                 validated_kconfig = kunit_config.Kconfig()
99                 validated_kconfig.read_from_file(kconfig_path)
100                 if not self._kconfig.is_subset_of(validated_kconfig):
101                         invalid = self._kconfig.entries() - validated_kconfig.entries()
102                         message = 'Provided Kconfig is not contained in validated .config. Following fields found in kunitconfig, ' \
103                                           'but not in .config: %s' % (
104                                         ', '.join([str(e) for e in invalid])
105                         )
106                         logging.error(message)
107                         return False
108                 return True
109
110         def build_config(self, build_dir):
111                 kconfig_path = get_kconfig_path(build_dir)
112                 if build_dir and not os.path.exists(build_dir):
113                         os.mkdir(build_dir)
114                 self._kconfig.write_to_file(kconfig_path)
115                 try:
116                         self._ops.make_olddefconfig(build_dir)
117                 except ConfigError as e:
118                         logging.error(e)
119                         return False
120                 return self.validate_config(build_dir)
121
122         def build_reconfig(self, build_dir):
123                 """Creates a new .config if it is not a subset of the .kunitconfig."""
124                 kconfig_path = get_kconfig_path(build_dir)
125                 if os.path.exists(kconfig_path):
126                         existing_kconfig = kunit_config.Kconfig()
127                         existing_kconfig.read_from_file(kconfig_path)
128                         if not self._kconfig.is_subset_of(existing_kconfig):
129                                 print('Regenerating .config ...')
130                                 os.remove(kconfig_path)
131                                 return self.build_config(build_dir)
132                         else:
133                                 return True
134                 else:
135                         print('Generating .config ...')
136                         return self.build_config(build_dir)
137
138         def build_um_kernel(self, jobs, build_dir):
139                 try:
140                         self._ops.make_olddefconfig(build_dir)
141                         self._ops.make(jobs, build_dir)
142                 except (ConfigError, BuildError) as e:
143                         logging.error(e)
144                         return False
145                 return self.validate_config(build_dir)
146
147         def run_kernel(self, args=[], timeout=None, build_dir=''):
148                 args.extend(['mem=256M'])
149                 process = self._ops.linux_bin(args, timeout, build_dir)
150                 with open(os.path.join(build_dir, 'test.log'), 'w') as f:
151                         for line in process.stdout:
152                                 f.write(line.rstrip().decode('ascii') + '\n')
153                                 yield line.rstrip().decode('ascii')