blob: ef738a33598a9c3b3107cb13b1aaad5ddeee7087 [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 = ''
50
51 default_target_type = 'simpleremote'
52 default_manifest = 'data/manifest'
53 default_server_ip = '192.168.7.1'
54 default_target_ip = '192.168.7.2'
Brad Bishop6e60e8b2018-02-01 10:27:11 -050055 default_extract_dir = 'packages/extracted'
56
57 def register_commands(self, logger, subparsers):
58 super(OERuntimeTestContextExecutor, self).register_commands(logger, subparsers)
59
60 runtime_group = self.parser.add_argument_group('runtime options')
61
62 runtime_group.add_argument('--target-type', action='store',
63 default=self.default_target_type, choices=['simpleremote', 'qemu'],
64 help="Target type of device under test, default: %s" \
65 % self.default_target_type)
66 runtime_group.add_argument('--target-ip', action='store',
67 default=self.default_target_ip,
68 help="IP address of device under test, default: %s" \
69 % self.default_target_ip)
70 runtime_group.add_argument('--server-ip', action='store',
71 default=self.default_target_ip,
72 help="IP address of device under test, default: %s" \
73 % self.default_server_ip)
74
75 runtime_group.add_argument('--host-dumper-dir', action='store',
Brad Bishop977dc1a2019-02-06 16:01:43 -050076 help="Directory where host status is dumped, if tests fails")
Brad Bishop6e60e8b2018-02-01 10:27:11 -050077
78 runtime_group.add_argument('--packages-manifest', action='store',
79 default=self.default_manifest,
80 help="Package manifest of the image under testi, default: %s" \
81 % self.default_manifest)
82
83 runtime_group.add_argument('--extract-dir', action='store',
84 default=self.default_extract_dir,
85 help='Directory where extracted packages reside, default: %s' \
86 % self.default_extract_dir)
87
88 runtime_group.add_argument('--qemu-boot', action='store',
89 help="Qemu boot configuration, only needed when target_type is QEMU.")
90
91 @staticmethod
92 def getTarget(target_type, logger, target_ip, server_ip, **kwargs):
93 target = None
94
Brad Bishopd7bf8c12018-02-25 22:55:05 -050095 if target_ip:
96 target_ip_port = target_ip.split(':')
97 if len(target_ip_port) == 2:
98 target_ip = target_ip_port[0]
99 kwargs['port'] = target_ip_port[1]
100
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500101 if target_type == 'simpleremote':
102 target = OESSHTarget(logger, target_ip, server_ip, **kwargs)
103 elif target_type == 'qemu':
Brad Bishop977dc1a2019-02-06 16:01:43 -0500104 target = OEQemuTarget(logger, server_ip, **kwargs)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500105 else:
106 # XXX: This code uses the old naming convention for controllers and
107 # targets, the idea it is to leave just targets as the controller
108 # most of the time was just a wrapper.
109 # XXX: This code tries to import modules from lib/oeqa/controllers
110 # directory and treat them as controllers, it will less error prone
111 # to use introspection to load such modules.
112 # XXX: Don't base your targets on this code it will be refactored
113 # in the near future.
114 # Custom target module loading
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800115 target_modules_path = kwargs.get('target_modules_path', '')
116 controller = OERuntimeTestContextExecutor.getControllerModule(target_type, target_modules_path)
117 target = controller(logger, target_ip, server_ip, **kwargs)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500118
119 return target
120
121 # Search oeqa.controllers module directory for and return a controller
122 # corresponding to the given target name.
123 # AttributeError raised if not found.
124 # ImportError raised if a provided module can not be imported.
125 @staticmethod
126 def getControllerModule(target, target_modules_path):
127 controllerslist = OERuntimeTestContextExecutor._getControllerModulenames(target_modules_path)
128 controller = OERuntimeTestContextExecutor._loadControllerFromName(target, controllerslist)
129 return controller
130
131 # Return a list of all python modules in lib/oeqa/controllers for each
132 # layer in bbpath
133 @staticmethod
134 def _getControllerModulenames(target_modules_path):
135
136 controllerslist = []
137
138 def add_controller_list(path):
139 if not os.path.exists(os.path.join(path, '__init__.py')):
140 raise OSError('Controllers directory %s exists but is missing __init__.py' % path)
Brad Bishop64c979e2019-11-04 13:55:29 -0500141 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 -0500142 for f in files:
143 module = 'oeqa.controllers.' + f[:-3]
144 if module not in controllerslist:
145 controllerslist.append(module)
146 else:
147 raise RuntimeError("Duplicate controller module found for %s. Layers should create unique controller module names" % module)
148
149 extpath = target_modules_path.split(':')
150 for p in extpath:
151 controllerpath = os.path.join(p, 'lib', 'oeqa', 'controllers')
152 if os.path.exists(controllerpath):
153 add_controller_list(controllerpath)
154 return controllerslist
155
156 # Search for and return a controller from given target name and
157 # set of module names.
158 # Raise AttributeError if not found.
159 # Raise ImportError if a provided module can not be imported
160 @staticmethod
161 def _loadControllerFromName(target, modulenames):
162 for name in modulenames:
163 obj = OERuntimeTestContextExecutor._loadControllerFromModule(target, name)
164 if obj:
165 return obj
166 raise AttributeError("Unable to load {0} from available modules: {1}".format(target, str(modulenames)))
167
168 # Search for and return a controller or None from given module name
169 @staticmethod
170 def _loadControllerFromModule(target, modulename):
171 obj = None
172 # import module, allowing it to raise import exception
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800173 module = __import__(modulename, globals(), locals(), [target])
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500174 # look for target class in the module, catching any exceptions as it
175 # is valid that a module may not have the target class.
176 try:
177 obj = getattr(module, target)
178 except:
179 obj = None
180 return obj
181
182 @staticmethod
183 def readPackagesManifest(manifest):
184 if not manifest or not os.path.exists(manifest):
185 raise OSError("Manifest file not exists: %s" % manifest)
186
187 image_packages = set()
188 with open(manifest, 'r') as f:
189 for line in f.readlines():
190 line = line.strip()
191 if line and not line.startswith("#"):
192 image_packages.add(line.split()[0])
193
194 return image_packages
195
196 @staticmethod
197 def getHostDumper(cmds, directory):
198 return HostDumper(cmds, directory)
199
200 def _process_args(self, logger, args):
201 if not args.packages_manifest:
202 raise TypeError('Manifest file not provided')
203
204 super(OERuntimeTestContextExecutor, self)._process_args(logger, args)
205
206 target_kwargs = {}
207 target_kwargs['qemuboot'] = args.qemu_boot
208
209 self.tc_kwargs['init']['target'] = \
210 OERuntimeTestContextExecutor.getTarget(args.target_type,
211 None, args.target_ip, args.server_ip, **target_kwargs)
212 self.tc_kwargs['init']['host_dumper'] = \
213 OERuntimeTestContextExecutor.getHostDumper(None,
214 args.host_dumper_dir)
215 self.tc_kwargs['init']['image_packages'] = \
216 OERuntimeTestContextExecutor.readPackagesManifest(
217 args.packages_manifest)
218 self.tc_kwargs['init']['extract_dir'] = args.extract_dir
219
220_executor_class = OERuntimeTestContextExecutor