|
1 # -*- encoding: latin-1 -*- |
|
2 |
|
3 #============================================================================ |
|
4 #Name : __init__.py |
|
5 #Part of : Helium |
|
6 |
|
7 #Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
8 #All rights reserved. |
|
9 #This component and the accompanying materials are made available |
|
10 #under the terms of the License "Eclipse Public License v1.0" |
|
11 #which accompanies this distribution, and is available |
|
12 #at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
13 # |
|
14 #Initial Contributors: |
|
15 #Nokia Corporation - initial contribution. |
|
16 # |
|
17 #Contributors: |
|
18 # |
|
19 #Description: |
|
20 #=============================================================================== |
|
21 |
|
22 """ATS3 test drop generation.""" |
|
23 |
|
24 #W0142 => * and ** were used |
|
25 #R* => will be fixed while refactoring |
|
26 #F0401 => pylint didn't find "path" module |
|
27 #C0302 => Too many lines |
|
28 |
|
29 from optparse import OptionParser |
|
30 import ats3.testconfigurator as acp |
|
31 import ats3.dropgenerator as adg |
|
32 import logging |
|
33 import os |
|
34 import re |
|
35 |
|
36 import ats3.parsers as parser |
|
37 |
|
38 from path import path # pylint: disable-msg=F0401 |
|
39 |
|
40 _logger = logging.getLogger('ats') |
|
41 |
|
42 class Configuration(object): |
|
43 """ |
|
44 ATS3 drop generation configuration. |
|
45 """ |
|
46 def __init__(self, opts, tsrc_paths): |
|
47 """ |
|
48 Initialize from optparse configuration options. |
|
49 """ |
|
50 self._opts = opts |
|
51 c_parser = parser.CppParser() |
|
52 temp_dict = {} |
|
53 pkg_parser = parser.PkgFileParser() |
|
54 |
|
55 # Customize some attributes from how optparse leaves them. |
|
56 self.build_drive = path(self._opts.build_drive) |
|
57 self.file_store = path(self._opts.file_store) |
|
58 self.flash_images = split_paths(self._opts.flash_images) |
|
59 self.sis_files = split_paths(self._opts.sis_files) |
|
60 self.config_file = self._opts.config |
|
61 self.obey_pkgfiles = to_bool(self._opts.obey_pkgfiles) |
|
62 self.hti = to_bool(self._opts.hti) |
|
63 self.specific_pkg = self._opts.specific_pkg |
|
64 if self.specific_pkg == '': |
|
65 self.specific_pkg = None |
|
66 self.tsrc_paths_dict = {} |
|
67 |
|
68 ats_nd = self._opts.ctc_run_process_params.strip() |
|
69 if ats_nd != "": |
|
70 ats_nd = ats_nd.split("#")[0].strip() |
|
71 if ats_nd == "": |
|
72 self._opts.ctc_run_process_params = "" |
|
73 _logger.warning("Property \'ats.ctc.host\' is not set. Code coverage measurement report(s) will not be created.") |
|
74 |
|
75 main_comps = [] |
|
76 |
|
77 for tsrc in tsrc_paths: |
|
78 hrh = os.path.join(self.build_drive + os.sep, 'epoc32', 'include', 'feature_settings.hrh') |
|
79 if os.path.exists(hrh): |
|
80 temp_dict = c_parser.get_cpp_output(path(tsrc), "d", hrh) |
|
81 else: |
|
82 temp_dict = c_parser.get_cpp_output(path(tsrc), "d") |
|
83 for t_key, t_value in temp_dict.items(): |
|
84 self.tsrc_paths_dict[t_key] = t_value |
|
85 |
|
86 #preparing a list of main components |
|
87 for main_component in self.tsrc_paths_dict.keys(): |
|
88 if self.obey_pkgfiles == "True": |
|
89 if pkg_parser.get_pkg_files(main_component) != []: |
|
90 main_comps.append(main_component) |
|
91 else: |
|
92 main_comps.append(main_component) |
|
93 |
|
94 |
|
95 self.tsrc_paths = main_comps |
|
96 |
|
97 def __getattr__(self, attr): |
|
98 return getattr(self._opts, attr) |
|
99 |
|
100 def __str__(self): |
|
101 dump = "Configuration:\n" |
|
102 seen = set() |
|
103 for key, value in vars(self).items(): |
|
104 if not key.startswith("_"): |
|
105 dump += "\t%s = %s\n" % (key, value) |
|
106 seen.add(key) |
|
107 for key, value in vars(self._opts).items(): |
|
108 if key not in seen: |
|
109 dump += "\t%s = %s\n" % (key, value) |
|
110 seen.add(key) |
|
111 return dump |
|
112 |
|
113 |
|
114 class Ats3TestPlan(object): |
|
115 """ |
|
116 Tells ATS3 server what to test and how. |
|
117 |
|
118 The ATS3 test plan from which the test.xml file can be written. The test |
|
119 plan captures all the data related to a test run: flashing, installation |
|
120 of data files and configuration files, test cases, and the notifications. |
|
121 |
|
122 """ |
|
123 EMAIL_SUBJECT = (u"ATS3 report for §RUN_NAME§ §RUN_START_DATE§ " |
|
124 u"§RUN_START_TIME§") |
|
125 REPORT_PATH = u"§RUN_NAME§" + os.sep + u"§RUN_START_DATE§_§RUN_START_TIME§" |
|
126 |
|
127 def __init__(self, config): |
|
128 self.diamonds_build_url = config.diamonds_build_url |
|
129 self.ctc_run_process_params = config.ctc_run_process_params |
|
130 self.testrun_name = config.testrun_name |
|
131 self.harness = config.harness |
|
132 self.device_type = config.device_type |
|
133 self.device_hwid = config.device_hwid |
|
134 self.plan_name = config.plan_name |
|
135 self.report_email = config.report_email |
|
136 self.file_store = config.file_store |
|
137 self.test_timeout = config.test_timeout |
|
138 self.eunitexerunner_flags = config.eunitexerunner_flags |
|
139 self.sets = [] |
|
140 self.src_dst = [] |
|
141 self.pmd_files = [] |
|
142 self.trace_activation_files = [] |
|
143 self.trace_enabled = to_bool(config.trace_enabled) |
|
144 self.ctc_enabled = to_bool(config.ctc_enabled) |
|
145 self.multiset_enabled = to_bool(config.multiset_enabled) |
|
146 self.monsym_files = config.monsym_files |
|
147 self.hti = config.hti |
|
148 self.component_path = "" |
|
149 self.custom_dir = None |
|
150 |
|
151 def insert_set(self, data_files=None, config_files=None, |
|
152 engine_ini_file=None, image_files=None, sis_files=None, |
|
153 testmodule_files=None, test_timeout=None,eunitexerunner_flags=None , test_harness=None, |
|
154 src_dst=None, pmd_files=None, trace_activation_files=None, custom_dir=None, component_path=None): |
|
155 """ |
|
156 Insert a test set into the test plan. |
|
157 """ |
|
158 |
|
159 if not custom_dir is None: |
|
160 self.custom_dir = custom_dir |
|
161 if data_files is None: |
|
162 data_files = [] |
|
163 if config_files is None: |
|
164 config_files = [] |
|
165 if image_files is None: |
|
166 image_files = [] |
|
167 if sis_files is None: |
|
168 sis_files = [] |
|
169 if testmodule_files is None: |
|
170 testmodule_files = [] |
|
171 if test_timeout is None: |
|
172 test_timeout = [] |
|
173 if test_harness is None: |
|
174 test_harness = self.harness |
|
175 if src_dst is None: |
|
176 src_dst = [] |
|
177 if pmd_files is None: |
|
178 pmd_files = [] |
|
179 if trace_activation_files is None: |
|
180 trace_activation_files = [] |
|
181 if component_path is None: |
|
182 component_path = self.component_path |
|
183 |
|
184 setd = dict(name="set%d" % len(self.sets), |
|
185 image_files=image_files, engine_ini_file=engine_ini_file, ctc_enabled=self.ctc_enabled, component_path=component_path) |
|
186 |
|
187 setd = dict(setd, custom_dir=custom_dir) |
|
188 if sis_files: |
|
189 setd = dict(setd, sis_files=sis_files, test_timeout=test_timeout, eunitexerunner_flags=eunitexerunner_flags, test_harness=test_harness, ) |
|
190 else: |
|
191 setd = dict(setd, data_files=data_files, config_files=config_files, |
|
192 testmodule_files=testmodule_files, test_timeout=test_timeout, eunitexerunner_flags=eunitexerunner_flags, test_harness=test_harness, |
|
193 src_dst=src_dst) |
|
194 if self.trace_enabled != "": |
|
195 if self.trace_enabled.lower() == "true": |
|
196 setd = dict(setd, pmd_files=pmd_files, |
|
197 trace_path=self.file_store.joinpath(self.REPORT_PATH, "traces", setd["name"], "tracelog.blx"), |
|
198 trace_activation_files=trace_activation_files) |
|
199 else: |
|
200 setd = dict(setd, pmd_files=[], |
|
201 trace_path="",trace_activation_files=[]) |
|
202 self.sets.append(setd) |
|
203 |
|
204 def set_plan_harness(self): |
|
205 """setting up test harness for a plan""" |
|
206 eunit = False |
|
207 stif = False |
|
208 stifunit = False |
|
209 for setd in self.sets: |
|
210 if setd["test_harness"] == "STIF": |
|
211 stif = True |
|
212 elif setd["test_harness"] == "EUNIT": |
|
213 eunit = True |
|
214 elif setd["test_harness"] == "STIFUNIT": |
|
215 stifunit = True |
|
216 |
|
217 if eunit and stif: |
|
218 self.harness = "MULTI_HARNESS" |
|
219 elif eunit: |
|
220 self.harness = "EUNIT" |
|
221 elif stif: |
|
222 self.harness = "STIF" |
|
223 elif stifunit: |
|
224 self.harness = "STIFUNIT" |
|
225 else: |
|
226 self.harness = "GENERIC" |
|
227 |
|
228 @property |
|
229 def post_actions(self): |
|
230 """ATS3 post actions.""" |
|
231 actions = [] |
|
232 temp_var = "" |
|
233 include_ctc_runprocess = False |
|
234 report_path = self.file_store.joinpath(self.REPORT_PATH) |
|
235 |
|
236 if self.ctc_enabled and adg.CTC_PATHS_LIST != [] and self.monsym_files != "" and not "${" in self.monsym_files: |
|
237 include_ctc_runprocess = True |
|
238 ctc_params = "--ctcdata_files=" |
|
239 for cdl in adg.CTC_PATHS_LIST: |
|
240 ctc_params += cdl + '\\ctcdata.txt' + ";" |
|
241 temp_var = cdl |
|
242 |
|
243 drop_count = self.ctc_run_process_params.rsplit("#", 1)[1] |
|
244 temp_var = temp_var.split("ctc_helium"+os.sep)[1] |
|
245 diamonds_id = temp_var.split(os.sep)[0] |
|
246 drop_id = temp_var.split(os.sep)[1].split(os.sep)[0] |
|
247 drop_id = re.findall(".*drop(\d*)", drop_id.lower())[0] #extracting int part of drop name |
|
248 |
|
249 ctc_params += r" --monsym_files=" + self.monsym_files |
|
250 ctc_params += r" --diamonds_build_id=" + diamonds_id |
|
251 ctc_params += r" --drop_id=" + drop_id |
|
252 ctc_params += r" --total_amount_of_drops=" + drop_count |
|
253 |
|
254 runprocess_action = ("RunProcessAction", |
|
255 (("file", r"catsctc2html/catsctc2html.exe"), #this line will be executing on Windows machine. |
|
256 ("parameters", ctc_params))) |
|
257 |
|
258 email_url = " CTC report can be found from: " + self.diamonds_build_url |
|
259 |
|
260 email_action = ("SendEmailAction", |
|
261 (("subject", self.EMAIL_SUBJECT), |
|
262 ("type", "ATS3_REPORT"), |
|
263 ("send-files", "true"), |
|
264 ("additional-description", email_url), |
|
265 ("to", self.report_email))) |
|
266 else: |
|
267 email_action = ("SendEmailAction", |
|
268 (("subject", self.EMAIL_SUBJECT), |
|
269 ("type", "ATS3_REPORT"), |
|
270 ("send-files", "true"), |
|
271 ("to", self.report_email))) |
|
272 ats3_report = ("FileStoreAction", |
|
273 (("to-folder", report_path.joinpath("ATS3_REPORT")), |
|
274 ("report-type", "ATS3_REPORT"), |
|
275 ("date-format", "yyyyMMdd"), |
|
276 ("time-format", "HHmmss"))) |
|
277 stif_report = ("FileStoreAction", |
|
278 (("to-folder", report_path.joinpath("STIF_REPORT")), |
|
279 ("report-type", "STIF_COMPONENT_REPORT_ALL_CASES"), |
|
280 ("run-log", "true"), |
|
281 ("date-format", "yyyyMMdd"), |
|
282 ("time-format", "HHmmss"))) |
|
283 eunit_report = ("FileStoreAction", |
|
284 (("to-folder", report_path.joinpath("EUNIT_REPORT")), |
|
285 ("report-type", "EUNIT_COMPONENT_REPORT_ALL_CASES"), |
|
286 ("run-log", "true"), |
|
287 ("date-format", "yyyyMMdd"), |
|
288 ("time-format", "HHmmss"))) |
|
289 diamonds_action = ("DiamondsAction", ()) |
|
290 |
|
291 |
|
292 if include_ctc_runprocess: |
|
293 actions.append(runprocess_action) |
|
294 |
|
295 if self.diamonds_build_url: |
|
296 actions.append(diamonds_action) |
|
297 if self.file_store: |
|
298 actions.append(ats3_report) |
|
299 if self.harness == "STIF": |
|
300 actions.append(stif_report) |
|
301 elif self.harness == "EUNIT": |
|
302 actions.append(eunit_report) |
|
303 if self.report_email: |
|
304 actions.append(email_action) |
|
305 return actions |
|
306 |
|
307 def __getitem__(self, key): |
|
308 return self.__dict__[key] |
|
309 |
|
310 def encode_for_xml(unicode_data, encoding='ascii'): |
|
311 """ |
|
312 Encode unicode_data for use as XML or HTML, with characters outside |
|
313 of the encoding converted to XML numeric character references. |
|
314 """ |
|
315 try: |
|
316 return unicode_data.encode(encoding, 'xmlcharrefreplace') |
|
317 except ValueError: |
|
318 # ValueError is raised if there are unencodable chars in the |
|
319 # data and the 'xmlcharrefreplace' error handler is not found. |
|
320 # Pre-2.3 Python doesn't support the 'xmlcharrefreplace' error |
|
321 # handler, so we'll emulate it. |
|
322 return _xmlcharref_encode(unicode_data, encoding) |
|
323 |
|
324 def _xmlcharref_encode(unicode_data, encoding): |
|
325 """Emulate Python 2.3's 'xmlcharrefreplace' encoding error handler.""" |
|
326 chars = [] |
|
327 # Step through the unicode_data string one character at a time in |
|
328 # order to catch unencodable characters: |
|
329 for char in unicode_data: |
|
330 try: |
|
331 chars.append(char.encode(encoding, 'strict')) |
|
332 except UnicodeError: |
|
333 chars.append('&#%i;' % ord(char)) |
|
334 return ''.join(chars) |
|
335 |
|
336 |
|
337 def create_drop(config): |
|
338 """Create a test drop.""" |
|
339 _logger.debug("initialize test plan") |
|
340 |
|
341 test_plan = Ats3TestPlan(config) |
|
342 component_parser = acp.Ats3ComponentParser(config) |
|
343 |
|
344 for tsrc in config.tsrc_paths: |
|
345 lst_check_harness = [] |
|
346 _logger.info("inspecting tsrc path: %s" % tsrc) |
|
347 #checking if there are components without harness |
|
348 for sub_component in config.tsrc_paths_dict[tsrc]['content'].keys(): |
|
349 _harness_ = config.tsrc_paths_dict[tsrc]['content'][sub_component]['harness'] |
|
350 if _harness_ != "": |
|
351 lst_check_harness.append(_harness_) |
|
352 |
|
353 #if component has harness then insert to test set |
|
354 if len(lst_check_harness) > 0: |
|
355 component_parser.insert_test_set(test_plan, path(tsrc), config.tsrc_paths_dict) |
|
356 |
|
357 test_plan.set_plan_harness() |
|
358 |
|
359 |
|
360 #Checking if any non executable set exists |
|
361 #if yes, delete the set |
|
362 tesplan_counter = 0 |
|
363 for plan_sets in test_plan.sets: |
|
364 tesplan_counter += 1 |
|
365 exe_flag = False |
|
366 for srcanddst in plan_sets['src_dst']: |
|
367 _ext = srcanddst[0].rsplit(".")[1] |
|
368 #the list below are the files which are executable |
|
369 #if none exists, set is not executable |
|
370 for mat in ["dll", "ini", "cfg", "exe", "script"]: |
|
371 if mat == _ext.lower(): |
|
372 exe_flag = True |
|
373 break |
|
374 if exe_flag: |
|
375 break |
|
376 |
|
377 if not exe_flag: #the set does not have executable, deleting the set |
|
378 _logger.info(plan_sets['component_path'] + ' has no executables so not including in xml') |
|
379 del test_plan.sets[tesplan_counter - 1] |
|
380 |
|
381 if config.ats4_enabled.lower() == 'true': |
|
382 generator = adg.Ats3TemplateTestDropGenerator() |
|
383 else: |
|
384 generator = adg.Ats3TestDropGenerator() |
|
385 _logger.info("generating drop file: %s" % config.drop_file) |
|
386 generator.generate(test_plan, output_file=config.drop_file, config_file=config.config_file) |
|
387 |
|
388 def split_paths(arg, delim=","): |
|
389 """ |
|
390 Split the string by delim, removing extra whitespace. |
|
391 """ |
|
392 return [path(part.strip()) |
|
393 for part in arg.split(delim) if part.strip()] |
|
394 |
|
395 def to_bool(param): |
|
396 """setting a true or false based on a param value""" |
|
397 param = str(param).lower() |
|
398 if "true" == param or "t" == param or "1" == param: |
|
399 return "True" |
|
400 else: |
|
401 return "False" |
|
402 |
|
403 def main(): |
|
404 """Main entry point.""" |
|
405 cli = OptionParser(usage="%prog [options] TSRC1 [TSRC2 [TSRC3 ...]]") |
|
406 cli.add_option("--build-drive", help="Build area root drive") |
|
407 cli.add_option("--data-dir", help="Data directory name", action="append", |
|
408 default=[]) |
|
409 cli.add_option("--device-type", help="Device type (e.g. 'PRODUCT')", |
|
410 default="unknown") |
|
411 cli.add_option("--device-hwid", help="Device hwid", |
|
412 default="") |
|
413 cli.add_option("--trace-enabled", help="Tracing enabled", default="False") |
|
414 cli.add_option("--ctc-enabled", help="CTC enabled", default="False") |
|
415 cli.add_option("--multiset-enabled", help="Multiset enabled", default="False") |
|
416 cli.add_option("--diamonds-build-url", help="Diamonds build url") |
|
417 cli.add_option("--ctc-run-process-params", help="ctc parameters include ctc host, drop id and total number of drops, separated by '#'") |
|
418 cli.add_option("--drop-file", help="Name for the final drop zip file", |
|
419 default="ATS3Drop.zip") |
|
420 cli.add_option("--file-store", help="Destination path for reports.", |
|
421 default="") |
|
422 cli.add_option("--flash-images", help="Paths to the flash image files", |
|
423 default="") |
|
424 cli.add_option("--minimum-flash-images", help="Minimum amount of flash images", |
|
425 default=2) |
|
426 cli.add_option("--harness", help="Test harness (default: %default)", |
|
427 default="") |
|
428 cli.add_option("--report-email", help="Email notification receivers", |
|
429 default="") |
|
430 cli.add_option("--plan-name", help="Name of the test plan", |
|
431 default="plan") |
|
432 cli.add_option("--sis-files", help="Paths to the sis files", |
|
433 default="") |
|
434 cli.add_option("--monsym-files", help="Paths to MON.sym files, for ctc useage", |
|
435 default="") |
|
436 cli.add_option("--target-platform", help="Target platform (default: %default)", |
|
437 default="armv5 urel") |
|
438 cli.add_option("--test-timeout", help="Test execution timeout value (default: %default)", |
|
439 default="60") |
|
440 cli.add_option("--eunitexerunner-flags", help="Eunitexerunner flags", |
|
441 default="") |
|
442 cli.add_option("--testrun-name", help="Name of the test run", |
|
443 default="run") |
|
444 cli.add_option("--config", help="Path to the config file", |
|
445 default="") |
|
446 cli.add_option("--specific-pkg", help="Text in name of pkg files to use", default='') |
|
447 cli.add_option("--ats4-enabled", help="ATS4 enabled", default="False") |
|
448 cli.add_option("--obey-pkgfiles", help="If this option is True, then only test components having PKG file are executable and if the compnents don't have PKG files they will be ignored.", default="False") |
|
449 cli.add_option("--verbose", help="Increase output verbosity", action="store_true", default=False) |
|
450 cli.add_option("--hti", help="HTI enabled", default="True") |
|
451 |
|
452 opts, tsrc_paths = cli.parse_args() |
|
453 |
|
454 if not tsrc_paths: |
|
455 cli.error("no tsrc directories given") |
|
456 if not opts.build_drive: |
|
457 cli.error("no build drive given") |
|
458 if len(opts.flash_images.split(",")) < int(opts.minimum_flash_images): |
|
459 cli.error("Not enough flash files: %i defined, %i needed" % (len(opts.flash_images.split(",")), int(opts.minimum_flash_images) )) |
|
460 |
|
461 if opts.verbose: |
|
462 _logger.setLevel(logging.DEBUG) |
|
463 logging.basicConfig(level=logging.DEBUG) |
|
464 |
|
465 config = Configuration(opts, tsrc_paths) |
|
466 create_drop(config) |
|
467 |
|
468 |
|
469 if __name__ == "__main__": |
|
470 main() |