blob: 3826f2764216bd4bcca302cb8be2d53b22feef96 [file] [log] [blame]
Brad Bishopc342db32019-05-15 21:57:59 -04001#
Brad Bishop6e60e8b2018-02-01 10:27:11 -05002# Copyright (C) 2016 Intel Corporation
Brad Bishopc342db32019-05-15 21:57:59 -04003#
4# SPDX-License-Identifier: MIT
5#
Brad Bishop6e60e8b2018-02-01 10:27:11 -05006
7import os
8
9from oeqa.core.context import OETestContext, OETestContextExecutor
10from oeqa.core.target.ssh import OESSHTarget
11from oeqa.core.target.qemu import OEQemuTarget
12from oeqa.utils.dump import HostDumper
13
14from oeqa.runtime.loader import OERuntimeTestLoader
15
16class OERuntimeTestContext(OETestContext):
17 loaderClass = OERuntimeTestLoader
18 runtime_files_dir = os.path.join(
19 os.path.dirname(os.path.abspath(__file__)), "files")
20
21 def __init__(self, td, logger, target,
22 host_dumper, image_packages, extract_dir):
23 super(OERuntimeTestContext, self).__init__(td, logger)
24
25 self.target = target
26 self.image_packages = image_packages
27 self.host_dumper = host_dumper
28 self.extract_dir = extract_dir
29 self._set_target_cmds()
30
31 def _set_target_cmds(self):
32 self.target_cmds = {}
33
34 self.target_cmds['ps'] = 'ps'
35 if 'procps' in self.image_packages:
36 self.target_cmds['ps'] = self.target_cmds['ps'] + ' -ef'
37
38class OERuntimeTestContextExecutor(OETestContextExecutor):
39 _context_class = OERuntimeTestContext
40
41 name = 'runtime'
42 help = 'runtime test component'
43 description = 'executes runtime tests over targets'
44
45 default_cases = os.path.join(os.path.abspath(os.path.dirname(__file__)),
46 'cases')
47 default_data = None
48 default_test_data = 'data/testdata.json'
49 default_tests = ''
Andrew Geissler82c905d2020-04-13 13:39:40 -050050 default_json_result_dir = '%s-results' % name
Brad Bishop6e60e8b2018-02-01 10:27:11 -050051
52 default_target_type = 'simpleremote'
53 default_manifest = 'data/manifest'
54 default_server_ip = '192.168.7.1'
55 default_target_ip = '192.168.7.2'
Brad Bishop6e60e8b2018-02-01 10:27:11 -050056 default_extract_dir = 'packages/extracted'
57
58 def register_commands(self, logger, subparsers):
59 super(OERuntimeTestContextExecutor, self).register_commands(logger, subparsers)
60
61 runtime_group = self.parser.add_argument_group('runtime options')
62
63 runtime_group.add_argument('--target-type', action='store',
64 default=self.default_target_type, choices=['simpleremote', 'qemu'],
65 help="Target type of device under test, default: %s" \
66 % self.default_target_type)
67 runtime_group.add_argument('--target-ip', action='store',
68 default=self.default_target_ip,
69 help="IP address of device under test, default: %s" \
70 % self.default_target_ip)
71 runtime_group.add_argument('--server-ip', action='store',
72 default=self.default_target_ip,
73 help="IP address of device under test, default: %s" \
74 % self.default_server_ip)
75
76 runtime_group.add_argument('--host-dumper-dir', action='store',
Brad Bishop977dc1a2019-02-06 16:01:43 -050077 help="Directory where host status is dumped, if tests fails")
Brad Bishop6e60e8b2018-02-01 10:27:11 -050078
79 runtime_group.add_argument('--packages-manifest', action='store',
80 default=self.default_manifest,
Andrew Geissler82c905d2020-04-13 13:39:40 -050081 help="Package manifest of the image under test, default: %s" \
Brad Bishop6e60e8b2018-02-01 10:27:11 -050082 % self.default_manifest)
83
84 runtime_group.add_argument('--extract-dir', action='store',
85 default=self.default_extract_dir,
86 help='Directory where extracted packages reside, default: %s' \
87 % self.default_extract_dir)
88
89 runtime_group.add_argument('--qemu-boot', action='store',
90 help="Qemu boot configuration, only needed when target_type is QEMU.")
91
92 @staticmethod
93 def getTarget(target_type, logger, target_ip, server_ip, **kwargs):
94 target = None
95
Brad Bishopd7bf8c12018-02-25 22:55:05 -050096 if target_ip:
97 target_ip_port = target_ip.split(':')
98 if len(target_ip_port) == 2:
99 target_ip = target_ip_port[0]
100 kwargs['port'] = target_ip_port[1]
101
Andrew Geissler82c905d2020-04-13 13:39:40 -0500102 if server_ip:
103 server_ip_port = server_ip.split(':')
104 if len(server_ip_port) == 2:
105 server_ip = server_ip_port[0]
106 kwargs['server_port'] = int(server_ip_port[1])
107
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500108 if target_type == 'simpleremote':
109 target = OESSHTarget(logger, target_ip, server_ip, **kwargs)
110 elif target_type == 'qemu':
Brad Bishop977dc1a2019-02-06 16:01:43 -0500111 target = OEQemuTarget(logger, server_ip, **kwargs)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500112 else:
113 # XXX: This code uses the old naming convention for controllers and
114 # targets, the idea it is to leave just targets as the controller
115 # most of the time was just a wrapper.
116 # XXX: This code tries to import modules from lib/oeqa/controllers
117 # directory and treat them as controllers, it will less error prone
118 # to use introspection to load such modules.
119 # XXX: Don't base your targets on this code it will be refactored
120 # in the near future.
121 # Custom target module loading
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800122 target_modules_path = kwargs.get('target_modules_path', '')
123 controller = OERuntimeTestContextExecutor.getControllerModule(target_type, target_modules_path)
124 target = controller(logger, target_ip, server_ip, **kwargs)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500125
126 return target
127
128 # Search oeqa.controllers module directory for and return a controller
129 # corresponding to the given target name.
130 # AttributeError raised if not found.
131 # ImportError raised if a provided module can not be imported.
132 @staticmethod
133 def getControllerModule(target, target_modules_path):
134 controllerslist = OERuntimeTestContextExecutor._getControllerModulenames(target_modules_path)
135 controller = OERuntimeTestContextExecutor._loadControllerFromName(target, controllerslist)
136 return controller
137
138 # Return a list of all python modules in lib/oeqa/controllers for each
139 # layer in bbpath
140 @staticmethod
141 def _getControllerModulenames(target_modules_path):
142
143 controllerslist = []
144
145 def add_controller_list(path):
146 if not os.path.exists(os.path.join(path, '__init__.py')):
147 raise OSError('Controllers directory %s exists but is missing __init__.py' % path)
Brad Bishop64c979e2019-11-04 13:55:29 -0500148 files = sorted([f for f in os.listdir(path) if f.endswith('.py') and not f.startswith('_') and not f.startswith('.#')])
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500149 for f in files:
150 module = 'oeqa.controllers.' + f[:-3]
151 if module not in controllerslist:
152 controllerslist.append(module)
153 else:
154 raise RuntimeError("Duplicate controller module found for %s. Layers should create unique controller module names" % module)
155
156 extpath = target_modules_path.split(':')
157 for p in extpath:
158 controllerpath = os.path.join(p, 'lib', 'oeqa', 'controllers')
159 if os.path.exists(controllerpath):
160 add_controller_list(controllerpath)
161 return controllerslist
162
163 # Search for and return a controller from given target name and
164 # set of module names.
165 # Raise AttributeError if not found.
166 # Raise ImportError if a provided module can not be imported
167 @staticmethod
168 def _loadControllerFromName(target, modulenames):
169 for name in modulenames:
170 obj = OERuntimeTestContextExecutor._loadControllerFromModule(target, name)
171 if obj:
172 return obj
173 raise AttributeError("Unable to load {0} from available modules: {1}".format(target, str(modulenames)))
174
175 # Search for and return a controller or None from given module name
176 @staticmethod
177 def _loadControllerFromModule(target, modulename):
178 obj = None
179 # import module, allowing it to raise import exception
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800180 module = __import__(modulename, globals(), locals(), [target])
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500181 # look for target class in the module, catching any exceptions as it
182 # is valid that a module may not have the target class.
183 try:
184 obj = getattr(module, target)
185 except:
186 obj = None
187 return obj
Andrew Geissler82c905d2020-04-13 13:39:40 -0500188
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500189 @staticmethod
190 def readPackagesManifest(manifest):
191 if not manifest or not os.path.exists(manifest):
192 raise OSError("Manifest file not exists: %s" % manifest)
193
194 image_packages = set()
195 with open(manifest, 'r') as f:
196 for line in f.readlines():
197 line = line.strip()
198 if line and not line.startswith("#"):
199 image_packages.add(line.split()[0])
200
201 return image_packages
202
203 @staticmethod
204 def getHostDumper(cmds, directory):
205 return HostDumper(cmds, directory)
206
207 def _process_args(self, logger, args):
208 if not args.packages_manifest:
209 raise TypeError('Manifest file not provided')
210
211 super(OERuntimeTestContextExecutor, self)._process_args(logger, args)
212
213 target_kwargs = {}
214 target_kwargs['qemuboot'] = args.qemu_boot
215
216 self.tc_kwargs['init']['target'] = \
217 OERuntimeTestContextExecutor.getTarget(args.target_type,
218 None, args.target_ip, args.server_ip, **target_kwargs)
219 self.tc_kwargs['init']['host_dumper'] = \
220 OERuntimeTestContextExecutor.getHostDumper(None,
221 args.host_dumper_dir)
222 self.tc_kwargs['init']['image_packages'] = \
223 OERuntimeTestContextExecutor.readPackagesManifest(
224 args.packages_manifest)
225 self.tc_kwargs['init']['extract_dir'] = args.extract_dir
226
227_executor_class = OERuntimeTestContextExecutor