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