Salome HOME
fix sat test for python2-3 compatibility
[tools/sat.git] / commands / test.py
1 #!/usr/bin/env python
2 #-*- coding:utf-8 -*-
3 #  Copyright (C) 2010-2012  CEA/DEN
4 #
5 #  This library is free software; you can redistribute it and/or
6 #  modify it under the terms of the GNU Lesser General Public
7 #  License as published by the Free Software Foundation; either
8 #  version 2.1 of the License.
9 #
10 #  This library is distributed in the hope that it will be useful,
11 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 #  Lesser General Public License for more details.
14 #
15 #  You should have received a copy of the GNU Lesser General Public
16 #  License along with this library; if not, write to the Free Software
17 #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
18
19 import os
20 import sys
21 import shutil
22 import subprocess
23 import datetime
24 import gzip
25
26 verbose = False
27
28 try:
29     from hashlib import sha1
30 except ImportError:
31     from sha import sha as sha1
32
33 import src
34 import src.ElementTree as etree
35 from src.xmlManager import add_simple_node
36
37 # Define all possible option for the test command :  sat test <options>
38 parser = src.options.Options()
39 parser.add_option('b', 'base', 'string', 'base',
40     _("Optional: Indicate the name of the test base to use.\n\tThis name has to"
41       " be registered in your application and in a project.\n\tA path to a "
42       "test base can also be used."))
43 parser.add_option('l', 'launcher', 'string', 'launcher',
44     _("Optional: Use this option to specify the path to a SALOME launcher to "
45       "use to launch the test scripts of the test base."))
46 parser.add_option('g', 'grid', 'list', 'grids',
47     _('Optional: Indicate which grid(s) to test (subdirectory of the test '
48       'base).'))
49 parser.add_option('s', 'session', 'list2', 'sessions',
50     _('Optional: indicate which session(s) to test (subdirectory of the '
51       'grid).'))
52 parser.add_option('', 'display', 'string', 'display',
53     _("Optional: set the display where to launch SALOME.\n"
54 "\tIf value is NO then option --show-desktop=0 will be used to launch SALOME."))
55
56 def description():
57     '''method that is called when salomeTools is called with --help option.
58     
59     :return: The text to display for the test command description.
60     :rtype: str
61     '''
62     return _("The test command runs a test base on a SALOME installation.\n\n"
63              "example:\nsat test SALOME-master --grid GEOM --session light")     
64
65 def parse_option(args, config):
66     """ Parse the options and do some verifications about it
67     
68     :param args List: The list of arguments of the command
69     :param config Config: The global configuration
70     :return: the options of the current command launch and the full arguments
71     :rtype: Tuple (options, args)
72     """
73     (options, args) = parser.parse_args(args)
74
75     if not options.launcher:
76         options.launcher = ""
77     elif not os.path.isabs(options.launcher):
78         if not src.config_has_application(config):
79             raise src.SatException(_("An application is required to use a "
80                                      "relative path with option --appli"))
81         options.launcher = os.path.join(config.APPLICATION.workdir,
82                                         options.launcher)
83
84         if not os.path.exists(options.launcher):
85             raise src.SatException(_("Launcher not found: %s") % 
86                                    options.launcher)
87
88     return (options, args)
89
90 def ask_a_path():
91     """ 
92     """
93     path = raw_input("enter a path where to save the result: ")
94     if path == "":
95         result = raw_input("the result will be not save. Are you sure to "
96                            "continue ? [y/n] ")
97         if result == "y":
98             return path
99         else:
100             return ask_a_path()
101
102     elif os.path.exists(path):
103         result = raw_input("Warning, the content of %s will be deleted. Are you"
104                            " sure to continue ? [y/n] " % path)
105         if result == "y":
106             return path
107         else:
108             return ask_a_path()
109     else:
110         return path
111
112 def save_file(filename, base):
113     f = open(filename, 'r')
114     content = f.read()
115     f.close()
116
117     objectname = sha1(content).hexdigest()
118
119     f = gzip.open(os.path.join(base, '.objects', objectname), 'w')
120     f.write(content)
121     f.close()
122     return objectname
123
124 def move_test_results(in_dir, what, out_dir, logger):
125     if out_dir == in_dir:
126         return
127
128     finalPath = out_dir
129     pathIsOk = False
130     while not pathIsOk:
131         try:
132             # create test results directory if necessary
133             #logger.write("FINAL = %s\n" % finalPath, 5)
134             if not os.access(finalPath, os.F_OK):
135                 #shutil.rmtree(finalPath)
136                 os.makedirs(finalPath)
137             pathIsOk = True
138         except:
139             logger.error(_("%s cannot be created.") % finalPath)
140             finalPath = ask_a_path()
141
142     if finalPath != "":
143         os.makedirs(os.path.join(finalPath, what, 'BASES'))
144
145         # check if .objects directory exists
146         if not os.access(os.path.join(finalPath, '.objects'), os.F_OK):
147             os.makedirs(os.path.join(finalPath, '.objects'))
148
149         logger.write(_('copy tests results to %s ... ') % finalPath, 3)
150         logger.flush()
151         #logger.write("\n", 5)
152
153         # copy env_info.py
154         shutil.copy2(os.path.join(in_dir, what, 'env_info.py'),
155                      os.path.join(finalPath, what, 'env_info.py'))
156
157         # for all sub directory (ie testbase) in the BASES directory
158         for testbase in os.listdir(os.path.join(in_dir, what, 'BASES')):
159             outtestbase = os.path.join(finalPath, what, 'BASES', testbase)
160             intestbase = os.path.join(in_dir, what, 'BASES', testbase)
161
162             # ignore files in root dir
163             if not os.path.isdir(intestbase):
164                 continue
165
166             os.makedirs(outtestbase)
167             #logger.write("  copy testbase %s\n" % testbase, 5)
168
169             for grid_ in [m for m in os.listdir(intestbase) if os.path.isdir(
170                                                 os.path.join(intestbase, m))]:
171                 # ignore source configuration directories
172                 if grid_[:4] == '.git' or grid_ == 'CVS':
173                     continue
174
175                 outgrid = os.path.join(outtestbase, grid_)
176                 ingrid = os.path.join(intestbase, grid_)
177                 os.makedirs(outgrid)
178                 #logger.write("    copy grid %s\n" % grid_, 5)
179
180                 if grid_ == 'RESSOURCES':
181                     for file_name in os.listdir(ingrid):
182                         if not os.path.isfile(os.path.join(ingrid,
183                                                            file_name)):
184                             continue
185                         f = open(os.path.join(outgrid, file_name), "w")
186                         f.write(save_file(os.path.join(ingrid, file_name),
187                                           finalPath))
188                         f.close()
189                 else:
190                     for session_name in [t for t in os.listdir(ingrid) if 
191                                       os.path.isdir(os.path.join(ingrid, t))]:
192                         outsession = os.path.join(outgrid, session_name)
193                         insession = os.path.join(ingrid, session_name)
194                         os.makedirs(outsession)
195                         
196                         for file_name in os.listdir(insession):
197                             if not os.path.isfile(os.path.join(insession,
198                                                                file_name)):
199                                 continue
200                             if file_name.endswith('result.py'):
201                                 shutil.copy2(os.path.join(insession, file_name),
202                                              os.path.join(outsession, file_name))
203                             else:
204                                 f = open(os.path.join(outsession, file_name), "w")
205                                 f.write(save_file(os.path.join(insession,
206                                                                file_name),
207                                                   finalPath))
208                                 f.close()
209
210     logger.write(src.printcolors.printc("OK"), 3, False)
211     logger.write("\n", 3, False)
212
213 def check_remote_machine(machine_name, logger):
214     logger.write(_("\ncheck the display on %s\n" % machine_name), 4)
215     ssh_cmd = 'ssh -o "StrictHostKeyChecking no" %s "ls"' % machine_name
216     logger.write(_("Executing the command : %s " % ssh_cmd), 4)
217     p = subprocess.Popen(ssh_cmd, 
218                          shell=True,
219                          stdin =subprocess.PIPE,
220                          stdout=subprocess.PIPE,
221                          stderr=subprocess.PIPE)
222     p.wait()
223     if p.returncode != 0:
224         logger.write(src.printcolors.printc(src.KO_STATUS) + "\n", 1)
225         logger.write("    " + src.printcolors.printcError(p.stderr.read()), 2)
226         logger.write(src.printcolors.printcWarning((
227                                     "No ssh access to the display machine.")),1)
228     else:
229         logger.write(src.printcolors.printcSuccess(src.OK_STATUS) + "\n\n", 4)
230
231 ##
232 # Creates the XML report for a product.
233 def create_test_report(config,
234                        xml_history_path,
235                        dest_path,
236                        retcode,
237                        xmlname=""):
238     # get the date and hour of the launching of the command, in order to keep
239     # history
240     date_hour = config.VARS.datehour
241     
242     # Get some information to put in the xml file
243     application_name = config.VARS.application
244     withappli = src.config_has_application(config)
245     
246     first_time = False
247     if not os.path.exists(xml_history_path):
248         if verbose: print("first_time as NOT existing '%s'" % xml_history_path) # cvw TODO
249         first_time = True
250         root = etree.Element("salome")
251         prod_node = etree.Element("product", name=application_name, build=xmlname)
252         root.append(prod_node)
253     else:
254         if verbose: print("NOT first_time as existing '%s'" % xml_history_path) # cvw TODO
255         root = etree.parse(xml_history_path).getroot()
256         prod_node = root.find("product")
257     
258     prod_node.attrib["history_file"] = os.path.basename(xml_history_path)
259     prod_node.attrib["global_res"] = retcode
260
261     # OP 14/11/2017 Ajout de traces pour essayer de decouvrir le pb
262     #               de remontee de log des tests
263     #print "TRACES OP - test.py/create_test_report() : xml_history_path = '#%s#'" %xml_history_path
264     
265     if withappli:
266         if not first_time:
267             for node in (prod_node.findall("version_to_download") + 
268                          prod_node.findall("out_dir")):
269                 prod_node.remove(node)
270                 
271         add_simple_node(prod_node, "version_to_download",
272                         config.APPLICATION.name)
273         
274         add_simple_node(prod_node, "out_dir", config.APPLICATION.workdir)
275
276     # add environment
277     if not first_time:
278         for node in prod_node.findall("exec"):
279                 prod_node.remove(node)
280         
281     exec_node = add_simple_node(prod_node, "exec")
282     exec_node.append(etree.Element("env", name="Host", value=config.VARS.node))
283     exec_node.append(etree.Element("env", name="Architecture",
284                                    value=config.VARS.dist))
285     exec_node.append(etree.Element("env", name="Number of processors",
286                                    value=str(config.VARS.nb_proc)))    
287     exec_node.append(etree.Element("env", name="Begin date",
288                                    value=src.parse_date(date_hour)))
289     exec_node.append(etree.Element("env", name="Command",
290                                    value=config.VARS.command))
291     exec_node.append(etree.Element("env", name="sat version",
292                                    value=config.INTERNAL.sat_version))
293
294     if 'TESTS' in config:
295         if first_time:
296             tests = add_simple_node(prod_node, "tests")
297             known_errors = add_simple_node(prod_node, "known_errors")
298             new_errors = add_simple_node(prod_node, "new_errors")
299             amend = add_simple_node(prod_node, "amend")
300         else:
301             tests = prod_node.find("tests")
302             known_errors = prod_node.find("known_errors")
303             new_errors = prod_node.find("new_errors")
304             amend = prod_node.find("amend")
305         
306         tt = {}
307         for test in config.TESTS:
308             if not tt.has_key(test.testbase):
309                 tt[test.testbase] = [test]
310             else:
311                 tt[test.testbase].append(test)
312         
313         for testbase in tt.keys():
314             if verbose: print("---- create_test_report %s %s" % (testbase, first_time))
315             if first_time:
316                 gn = add_simple_node(tests, "testbase")
317             else:
318                 gn = tests.find("testbase")
319                 # initialize all grids and session to "not executed"
320                 for mn in gn.findall("grid"):
321                     mn.attrib["executed_last_time"] = "no"
322                     for tyn in mn.findall("session"):
323                         tyn.attrib["executed_last_time"] = "no"
324                         for test_node in tyn.findall('test'):
325                             for node in test_node.getchildren():
326                                 if node.tag != "history":
327                                     test_node.remove(node)
328                             
329                             attribs_to_pop = []    
330                             for attribute in test_node.attrib:
331                                 if (attribute != "script" and 
332                                                         attribute != "res"):
333                                     attribs_to_pop.append(attribute)
334                             for attribute in attribs_to_pop:
335                                 test_node.attrib.pop(attribute)
336             
337             gn.attrib['name'] = testbase
338             nb, nb_pass, nb_failed, nb_timeout, nb_not_run = 0, 0, 0, 0, 0
339             grids = {}
340             sessions = {}
341             for test in tt[testbase]:
342                 if not grids.has_key(test.grid):
343                     if first_time:
344                         mn = add_simple_node(gn, "grid")
345                         mn.attrib['name'] = test.grid
346                     else:
347                         l_mn = gn.findall("grid")
348                         mn = None
349                         for grid_node in l_mn:
350                             if grid_node.attrib['name'] == test.grid:
351                                 mn = grid_node
352                                 break
353                         if mn == None:
354                             mn = add_simple_node(gn, "grid")
355                             mn.attrib['name'] = test.grid
356                     
357                     grids[test.grid] = mn
358                 
359                 mn.attrib["executed_last_time"] = "yes"
360                 
361                 if not sessions.has_key("%s/%s" % (test.grid, test.session)):
362                     if first_time:
363                         tyn = add_simple_node(mn, "session")
364                         tyn.attrib['name'] = test.session
365                     else:
366                         l_tyn = mn.findall("session")
367                         tyn = None
368                         for session_node in l_tyn:
369                             if session_node.attrib['name'] == test.session:
370                                 tyn = session_node
371                                 break
372                         if tyn == None:
373                             tyn = add_simple_node(mn, "session")
374                             tyn.attrib['name'] = test.session
375                         
376                     sessions["%s/%s" % (test.grid, test.session)] = tyn
377
378                 tyn.attrib["executed_last_time"] = "yes"
379
380                 for script in test.script:
381                     if first_time:
382                         tn = add_simple_node(sessions[
383                                            "%s/%s" % (test.grid, test.session)],
384                                              "test")
385                         tn.attrib['session'] = test.session
386                         tn.attrib['script'] = script.name
387                         hn = add_simple_node(tn, "history")
388                     else:
389                         l_tn = sessions["%s/%s" % (test.grid, test.session)].findall(
390                                                                          "test")
391                         tn = None
392                         for test_node in l_tn:
393                             if test_node.attrib['script'] == script['name']:
394                                 tn = test_node
395                                 break
396                         
397                         if tn == None:
398                             tn = add_simple_node(sessions[
399                                            "%s/%s" % (test.grid, test.session)],
400                                              "test")
401                             tn.attrib['session'] = test.session
402                             tn.attrib['script'] = script.name
403                             hn = add_simple_node(tn, "history")
404                         else:
405                             # Get or create the history node for the current test
406                             if len(tn.findall("history")) == 0:
407                                 hn = add_simple_node(tn, "history")
408                             else:
409                                 hn = tn.find("history")
410                             # Put the last test data into the history
411                             if 'res' in tn.attrib:
412                                 attributes = {"date_hour" : date_hour,
413                                               "res" : tn.attrib['res'] }
414                                 add_simple_node(hn,
415                                                 "previous_test",
416                                                 attrib=attributes)
417                             for node in tn:
418                                 if node.tag != "history":
419                                     tn.remove(node)
420                     
421                     if 'callback' in script:
422                         try:
423                             cnode = add_simple_node(tn, "callback")
424                             if src.architecture.is_windows():
425                                 import string
426                                 cnode.text = filter(
427                                                 lambda x: x in string.printable,
428                                                 script.callback)
429                             else:
430                                 cnode.text = script.callback.decode(
431                                                                 'string_escape')
432                         except UnicodeDecodeError as exc:
433                             zz = (script.callback[:exc.start] +
434                                   '?' +
435                                   script.callback[exc.end-2:])
436                             cnode = add_simple_node(tn, "callback")
437                             cnode.text = zz.decode("UTF-8")
438                     
439                     # Add the script content
440                     cnode = add_simple_node(tn, "content")
441                     cnode.text = script.content
442                     
443                     # Add the script execution log
444                     cnode = add_simple_node(tn, "out")
445                     cnode.text = script.out
446                     
447                     if 'amend' in script:
448                         cnode = add_simple_node(tn, "amend")
449                         cnode.text = script.amend.decode("UTF-8")
450
451                     if script.time < 0:
452                         tn.attrib['exec_time'] = "?"
453                     else:
454                         tn.attrib['exec_time'] = "%.3f" % script.time
455                     tn.attrib['res'] = script.res
456
457                     if "amend" in script:
458                         amend_test = add_simple_node(amend, "atest")
459                         amend_test.attrib['name'] = os.path.join(test.grid,
460                                                                  test.session,
461                                                                  script.name)
462                         amend_test.attrib['reason'] = script.amend.decode(
463                                                                         "UTF-8")
464
465                     # calculate status
466                     nb += 1
467                     if script.res == src.OK_STATUS: nb_pass += 1
468                     elif script.res == src.TIMEOUT_STATUS: nb_timeout += 1
469                     elif script.res == src.KO_STATUS: nb_failed += 1
470                     else: nb_not_run += 1
471
472                     if "known_error" in script:
473                         kf_script = add_simple_node(known_errors, "error")
474                         kf_script.attrib['name'] = os.path.join(test.grid,
475                                                                 test.session,
476                                                                 script.name)
477                         kf_script.attrib['date'] = script.known_error.date
478                         kf_script.attrib[
479                                     'expected'] = script.known_error.expected
480                         kf_script.attrib[
481                          'comment'] = script.known_error.comment.decode("UTF-8")
482                         kf_script.attrib['fixed'] = str(
483                                                        script.known_error.fixed)
484                         overdue = datetime.datetime.today().strftime("%Y-%m-"
485                                             "%d") > script.known_error.expected
486                         if overdue:
487                             kf_script.attrib['overdue'] = str(overdue)
488                         
489                     elif script.res == src.KO_STATUS:
490                         new_err = add_simple_node(new_errors, "new_error")
491                         script_path = os.path.join(test.grid,
492                                                    test.session, script.name)
493                         new_err.attrib['name'] = script_path
494                         new_err.attrib['cmd'] = ("sat testerror %s -s %s -c 'my"
495                                                  " comment' -p %s" % \
496                             (application_name, script_path, config.VARS.dist))
497
498
499             gn.attrib['total'] = str(nb)
500             gn.attrib['pass'] = str(nb_pass)
501             gn.attrib['failed'] = str(nb_failed)
502             gn.attrib['timeout'] = str(nb_timeout)
503             gn.attrib['not_run'] = str(nb_not_run)
504             
505             # Remove the res attribute of all tests that were not launched 
506             # this time
507             for mn in gn.findall("grid"):
508                 if mn.attrib["executed_last_time"] == "no":
509                     for tyn in mn.findall("session"):
510                         if tyn.attrib["executed_last_time"] == "no":
511                             for test_node in tyn.findall('test'):
512                                 if "res" in test_node.attrib:
513                                     test_node.attrib.pop("res")          
514     
515     if len(xmlname) == 0:
516         xmlname = application_name
517     if not xmlname.endswith(".xml"):
518         xmlname += ".xml"
519
520     src.xmlManager.write_report(os.path.join(dest_path, xmlname),
521                                 root,
522                                 "test.xsl")
523     src.xmlManager.write_report(xml_history_path,
524                                 root,
525                                 "test_history.xsl")
526     return src.OK_STATUS
527
528 def generate_history_xml_path(config, test_base):
529     """Generate the name of the xml file that contain the history of the tests
530        on the machine with the current APPLICATION and the current test base.
531     
532     :param config Config: The global configuration
533     :param test_base Str: The test base name (or path)
534     :return: the full path of the history xml file
535     :rtype: Str
536     """
537     history_xml_name = ""
538     if "APPLICATION" in config:
539         history_xml_name += config.APPLICATION.name
540         history_xml_name += "-" 
541     history_xml_name += config.VARS.dist
542     history_xml_name += "-"
543     test_base_name = test_base
544     if os.path.exists(test_base):
545         test_base_name = os.path.basename(test_base)
546     history_xml_name += test_base_name
547     history_xml_name += ".xml"
548     log_dir = src.get_log_path(config)
549     return os.path.join(log_dir, "TEST", history_xml_name)
550
551 def run(args, runner, logger):
552     '''method that is called when salomeTools is called with test parameter.
553     '''
554     (options, args) = parse_option(args, runner.cfg)
555
556     # the test base is specified either by the application, or by the --base option
557     with_application = False
558     if runner.cfg.VARS.application != 'None':
559         logger.write(_('Running tests on application %s\n') % 
560                             src.printcolors.printcLabel(
561                                                 runner.cfg.VARS.application), 1)
562         with_application = True
563     elif not options.base:
564         raise src.SatException(_('A test base is required. Use the --base '
565                                  'option'))
566
567     # the launcher is specified either by the application, or by the --launcher option
568     if with_application:
569         # check if environment is loaded
570         if 'KERNEL_ROOT_DIR' in os.environ:
571             logger.write(src.printcolors.printcWarning(_("WARNING: "
572                             "SALOME environment already sourced")) + "\n", 1)
573             
574         
575     elif options.launcher:
576         logger.write(src.printcolors.printcWarning(_("Running SALOME "
577                                                 "application.")) + "\n\n", 1)
578     else:
579         msg = _("Impossible to find any launcher.\nPlease specify an "
580                 "application or a launcher")
581         logger.write(src.printcolors.printcError(msg))
582         logger.write("\n")
583         return 1
584
585     # set the display
586     show_desktop = (options.display and options.display.upper() == "NO")
587     if options.display and options.display != "NO":
588         remote_name = options.display.split(':')[0]
589         if remote_name != "":
590             check_remote_machine(remote_name, logger)
591         # if explicitly set use user choice
592         os.environ['DISPLAY'] = options.display
593     elif 'DISPLAY' not in os.environ:
594         # if no display set
595         if ('test' in runner.cfg.LOCAL and
596                 'display' in runner.cfg.LOCAL.test and 
597                 len(runner.cfg.LOCAL.test.display) > 0):
598             # use default value for test tool
599             os.environ['DISPLAY'] = runner.cfg.LOCAL.test.display
600         else:
601             os.environ['DISPLAY'] = "localhost:0.0"
602
603     # initialization
604     #################
605     if with_application:
606         tmp_dir = os.path.join(runner.cfg.VARS.tmp_root,
607                                runner.cfg.APPLICATION.name,
608                                "test")
609     else:
610         tmp_dir = os.path.join(runner.cfg.VARS.tmp_root,
611                                "test")
612
613     # remove previous tmp dir
614     if os.access(tmp_dir, os.F_OK):
615         try:
616             shutil.rmtree(tmp_dir)
617         except:
618             logger.error(_("error removing TT_TMP_RESULT %s\n") 
619                                 % tmp_dir)
620
621     lines = []
622     lines.append("date = '%s'" % runner.cfg.VARS.date)
623     lines.append("hour = '%s'" % runner.cfg.VARS.hour)
624     lines.append("node = '%s'" % runner.cfg.VARS.node)
625     lines.append("arch = '%s'" % runner.cfg.VARS.dist)
626
627     if 'APPLICATION' in runner.cfg:
628         lines.append("application_info = {}")
629         lines.append("application_info['name'] = '%s'" % 
630                      runner.cfg.APPLICATION.name)
631         lines.append("application_info['tag'] = '%s'" % 
632                      runner.cfg.APPLICATION.tag)
633         lines.append("application_info['products'] = %s" % 
634                      str(runner.cfg.APPLICATION.products))
635
636     content = "\n".join(lines)
637
638     # create hash from context information
639     dirname = datetime.datetime.now().strftime("%y%m%d_%H%M%S_") + sha1(content.encode()).hexdigest()[0:6]
640     base_dir = os.path.join(tmp_dir, dirname)
641     os.makedirs(base_dir)
642     os.environ['TT_TMP_RESULT'] = base_dir
643
644     # create env_info file
645     f = open(os.path.join(base_dir, 'env_info.py'), "w")
646     f.write(content)
647     f.close()
648
649     # create working dir and bases dir
650     working_dir = os.path.join(base_dir, 'WORK')
651     os.makedirs(working_dir)
652     os.makedirs(os.path.join(base_dir, 'BASES'))
653     os.chdir(working_dir)
654
655     if 'PYTHONPATH' not in os.environ:
656         os.environ['PYTHONPATH'] = ''
657     else:
658         for var in os.environ['PYTHONPATH'].split(':'):
659             if var not in sys.path:
660                 sys.path.append(var)
661
662     # launch of the tests
663     #####################
664     test_base = ""
665     if options.base:
666         test_base = options.base
667     elif with_application and "test_base" in runner.cfg.APPLICATION:
668         test_base = runner.cfg.APPLICATION.test_base.name
669
670     src.printcolors.print_value(logger, _('Display'), os.environ['DISPLAY'], 2)
671     src.printcolors.print_value(logger, _('Timeout'),
672                                 src.test_module.DEFAULT_TIMEOUT, 2)
673     src.printcolors.print_value(logger, _("Working dir"), base_dir, 3)
674
675     # create the test object
676     test_runner = src.test_module.Test(runner.cfg,
677                                   logger,
678                                   base_dir,
679                                   testbase=test_base,
680                                   grids=options.grids,
681                                   sessions=options.sessions,
682                                   launcher=options.launcher,
683                                   show_desktop=show_desktop)
684     
685     if not test_runner.test_base_found:
686         # Fail 
687         return 1
688         
689     # run the test
690     logger.allowPrintLevel = False
691     retcode = test_runner.run_all_tests()
692     logger.allowPrintLevel = True
693
694     logger.write(_("Tests finished"), 1)
695     logger.write("\n", 2, False)
696     
697     logger.write(_("\nGenerate the specific test log\n"), 5)
698     log_dir = src.get_log_path(runner.cfg)
699     out_dir = os.path.join(log_dir, "TEST")
700     src.ensure_path_exists(out_dir)
701     name_xml_board = logger.logFileName.split(".")[0] + "board" + ".xml"
702     historic_xml_path = generate_history_xml_path(runner.cfg, test_base)
703     
704     create_test_report(runner.cfg,
705                        historic_xml_path,
706                        out_dir,
707                        retcode,
708                        xmlname = name_xml_board)
709     xml_board_path = os.path.join(out_dir, name_xml_board)
710
711     # OP 14/11/2017 Ajout de traces pour essayer de decouvrir le pb
712     #               de remontee de log des tests
713     #print "TRACES OP - test.py/run() : historic_xml_path = '#%s#'" %historic_xml_path
714     #print "TRACES OP - test.py/run() : log_dir           = '#%s#'" %log_dir
715     #print "TRACES OP - test.py/run() : name_xml_board    = '#%s#'" %name_xml_board
716
717     logger.l_logFiles.append(xml_board_path)
718     logger.add_link(os.path.join("TEST", name_xml_board),
719                     "board",
720                     retcode,
721                     "Click on the link to get the detailed test results")
722     logger.write("\nTests board is file %s\n" % xml_board_path, 1)
723
724     # Add the historic files into the log files list of the command
725     logger.l_logFiles.append(historic_xml_path)
726     
727     logger.write(_("Removing the temporary directory: "
728                    "rm -rf %s\n" % test_runner.tmp_working_dir), 5)
729     if os.path.exists(test_runner.tmp_working_dir):
730         shutil.rmtree(test_runner.tmp_working_dir)
731
732     return retcode
733