3 # Copyright (C) 2010-2013 CEA/DEN
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.
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.
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
19 # Python 2/3 compatibility for execfile function
23 def execfile(somefile, global_vars, local_vars):
24 with open(somefile) as f:
25 code = compile(f.read(), somefile, 'exec')
26 exec(code, global_vars, local_vars)
40 # directories not considered as test grids
41 C_IGNORE_GRIDS = ['.git', '.svn', 'RESSOURCES']
43 # Get directory to be used for the temporary files.
45 def getTmpDirDEFAULT():
46 if src.architecture.is_windows():
47 directory = os.getenv("TEMP")
49 # for Linux: use /tmp/logs/{user} folder
50 directory = os.path.join( '/tmp', 'logs', os.getenv("USER", "unknown"))
66 self.tmp_working_dir = tmp_working_dir
67 self.sessions = sessions
68 self.launcher = launcher
69 self.show_desktop = show_desktop
71 res = self.prepare_testbase(testbase)
72 self.test_base_found = True
75 self.test_base_found = False
78 self.known_errors = None
80 # create section for results
81 self.config.TESTS = src.pyconf.Sequence(self.config)
87 self.nb_acknoledge = 0
89 def _copy_dir(self, source, target):
90 if self.config.VARS.python >= "2.6":
91 shutil.copytree(source, target,
93 ignore=shutil.ignore_patterns('.git*','.svn*'))
95 shutil.copytree(source, target,
98 def prepare_testbase_from_dir(self, testbase_name, testbase_dir):
99 self.logger.write(_("get test base from dir: %s\n") % \
100 src.printcolors.printcLabel(testbase_dir), 3)
101 if not os.access(testbase_dir, os.X_OK):
102 raise src.SatException(_("testbase %(name)s (%(dir)s) does not "
103 "exist ...\n") % { 'name': testbase_name,
104 'dir': testbase_dir })
106 self._copy_dir(testbase_dir,
107 os.path.join(self.tmp_working_dir, 'BASES', testbase_name))
109 def prepare_testbase_from_git(self,
114 _("get test base '%(testbase)s' with '%(tag)s' tag from git\n") % {
115 "testbase" : src.printcolors.printcLabel(testbase_name),
116 "tag" : src.printcolors.printcLabel(testbase_tag)},
119 def set_signal(): # pragma: no cover
120 """see http://bugs.python.org/issue1652"""
122 signal.signal(signal.SIGPIPE, signal.SIG_DFL)
124 cmd = "git clone --depth 1 %(base)s %(dir)s"
125 cmd += " && cd %(dir)s"
126 if testbase_tag=='master':
127 cmd += " && git fetch origin %(branch)s"
129 cmd += " && git fetch origin %(branch)s:%(branch)s"
130 cmd += " && git checkout %(branch)s"
131 cmd = cmd % { 'branch': testbase_tag,
132 'base': testbase_base,
133 'dir': testbase_name }
135 self.logger.write("> %s\n" % cmd, 5)
136 if src.architecture.is_windows():
137 # preexec_fn not supported on windows platform
138 res = subprocess.call(cmd,
139 cwd=os.path.join(self.tmp_working_dir, 'BASES'),
141 stdout=self.logger.logTxtFile,
142 stderr=subprocess.PIPE)
144 res = subprocess.call(cmd,
145 cwd=os.path.join(self.tmp_working_dir, 'BASES'),
147 preexec_fn=set_signal,
148 stdout=self.logger.logTxtFile,
149 stderr=subprocess.PIPE)
151 raise src.SatException(_("Error: unable to get test base "
152 "'%(name)s' from git '%(repo)s'.") % \
153 { 'name': testbase_name,
154 'repo': testbase_base })
157 self.logger.error(_("git is not installed. exiting...\n"))
160 def prepare_testbase_from_svn(self, user, testbase_name, testbase_base):
161 self.logger.write(_("get test base '%s' from svn\n") % \
162 src.printcolors.printcLabel(testbase_name), 3)
164 def set_signal(): # pragma: no cover
165 """see http://bugs.python.org/issue1652"""
167 signal.signal(signal.SIGPIPE, signal.SIG_DFL)
169 cmd = "svn checkout --username %(user)s %(base)s %(dir)s"
170 cmd = cmd % { 'user': user,
171 'base': testbase_base,
172 'dir': testbase_name }
174 # Get the application environment
175 self.logger.write(_("Set the application environment\n"), 5)
176 env_appli = src.environment.SalomeEnviron(self.config,
177 src.environment.Environ(dict(os.environ)))
178 env_appli.set_application_env(self.logger)
180 self.logger.write("> %s\n" % cmd, 5)
181 if src.architecture.is_windows():
182 # preexec_fn not supported on windows platform
183 res = subprocess.call(cmd,
184 cwd=os.path.join(self.tmp_working_dir, 'BASES'),
186 stdout=self.logger.logTxtFile,
187 stderr=subprocess.PIPE)
189 res = subprocess.call(cmd,
190 cwd=os.path.join(self.tmp_working_dir, 'BASES'),
192 preexec_fn=set_signal,
193 stdout=self.logger.logTxtFile,
194 stderr=subprocess.PIPE,
195 env=env_appli.environ.environ,)
198 raise src.SatException(_("Error: unable to get test base '%(nam"
199 "e)s' from svn '%(repo)s'.") % \
200 { 'name': testbase_name,
201 'repo': testbase_base })
204 self.logger.error(_("svn is not installed. exiting...\n"))
208 # Configure tests base.
209 def prepare_testbase(self, test_base_name):
210 src.printcolors.print_value(self.logger,
214 self.logger.write("\n", 3, False)
216 # search for the test base
217 test_base_info = None
218 for project_name in self.config.PROJECTS.projects:
219 project_info = self.config.PROJECTS.projects[project_name]
220 if "test_bases" not in project_info:
222 for t_b_info in project_info.test_bases:
223 if t_b_info.name == test_base_name:
224 test_base_info = t_b_info
226 if not test_base_info:
227 if os.path.exists(test_base_name):
228 self.prepare_testbase_from_dir("DIR", test_base_name)
229 self.currentTestBase = "DIR"
232 if not test_base_info:
233 message = (_("########## ERROR: test base '%s' not found\n") %
235 self.logger.write("%s\n" % src.printcolors.printcError(message))
238 if test_base_info.get_sources == "dir":
239 self.prepare_testbase_from_dir(test_base_name,
240 test_base_info.info.dir)
241 elif test_base_info.get_sources == "git":
242 self.prepare_testbase_from_git(test_base_name,
243 test_base_info.info.base,
244 self.config.APPLICATION.test_base.tag)
245 elif test_base_info.get_sources == "svn":
246 svn_user = src.get_cfg_param(test_base_info.info,
248 self.config.USER.svn_user)
249 self.prepare_testbase_from_svn(svn_user,
251 test_base_info.info.base)
253 raise src.SatException(_("unknown source type '%(type)s' for test b"
254 "ase '%(base)s' ...\n") % {
255 'type': test_base_info.get_sources,
256 'base': test_base_name })
258 self.currentTestBase = test_base_name
261 # Searches if the script is declared in known errors pyconf.
262 # Update the status if needed.
263 def search_known_errors(self, status, test_grid, test_session, test):
264 test_path = os.path.join(test_grid, test_session, test)
265 if not src.config_has_application(self.config):
268 if self.known_errors is None:
271 platform = self.config.VARS.arch
272 application = self.config.VARS.application
273 error = self.known_errors.get_error(test_path, application, platform)
277 if status == src.OK_STATUS:
280 self.known_errors.fix_error(error)
282 #testerror.write_test_failures(
283 # self.config.TOOLS.testerror.file_path,
284 # self.known_errors.errors)
285 return status, [ error.date,
291 self.known_errors.unfix_error(error)
293 #testerror.write_test_failures(self.config.TOOLS.testerror.file_path,
294 # self.known_errors.errors)
296 delta = self.known_errors.get_expecting_days(error)
297 kfres = [ error.date, error.expected, error.comment, error.fixed ]
299 return src.KO_STATUS, kfres
300 return src.KNOWNFAILURE_STATUS, kfres
303 # Read the *.result.py files.
304 def read_results(self, listTest, has_timed_out):
306 for test in listTest:
307 resfile = os.path.join(self.currentDir,
310 test[:-3] + ".result.py")
312 # check if <test>.result.py file exists
313 if not os.path.exists(resfile):
314 results[test] = ["?", -1, "", []]
317 execfile(resfile, gdic, ldic)
319 status = src.TIMEOUT_STATUS
320 if not has_timed_out:
321 status = src.KO_STATUS
323 if ldic.has_key('status'):
324 status = ldic['status']
327 if status == src.KO_STATUS or status == src.OK_STATUS:
328 status, expected = self.search_known_errors(status,
334 if ldic.has_key('callback'):
335 callback = ldic['callback']
336 elif status == src.KO_STATUS:
340 if ldic.has_key('time'):
342 exec_time = float(ldic['time'])
346 results[test] = [status, exec_time, callback, expected]
348 # check if <test>.py file exists
349 testfile = os.path.join(self.currentDir,
354 if not os.path.exists(testfile):
355 results[test].append('')
357 text = open(testfile, "r").read()
358 results[test].append(text)
360 # check if <test>.out.py file exists
361 outfile = os.path.join(self.currentDir,
364 test[:-3] + ".out.py")
366 if not os.path.exists(outfile):
367 results[test].append('')
369 text = open(outfile, "r").read()
370 results[test].append(text)
375 # Generates the script to be run by Salome.
376 # This python script includes init and close statements and a loop
377 # calling all the scripts of a single directory.
378 def generate_script(self, listTest, script_path, ignoreList):
380 template_file = open(os.path.join(self.config.VARS.srcDir,
382 "scriptTemplate.py"), 'r')
383 template = string.Template(template_file.read())
385 # create substitution dictionary
387 d['resourcesWay'] = os.path.join(self.currentDir, 'RESSOURCES')
388 d['tmpDir'] = os.path.join(self.tmp_working_dir, 'WORK')
389 d['toolsWay'] = os.path.join(self.config.VARS.srcDir, "test")
390 d['sessionDir'] = os.path.join(self.currentDir,
393 d['resultFile'] = os.path.join(self.tmp_working_dir,
396 d['listTest'] = listTest
397 d['sessionName'] = self.currentsession
398 d['ignore'] = ignoreList
400 # create script with template
401 script = open(script_path, 'w')
402 script.write(template.safe_substitute(d))
405 # Find the getTmpDir function that gives access to *pidict file directory.
406 # (the *pidict file exists when SALOME is launched)
407 def get_tmp_dir(self):
408 # Rare case where there is no KERNEL in grid list
409 # (for example MED_STANDALONE)
410 if ('APPLICATION' in self.config
411 and 'KERNEL' not in self.config.APPLICATION.products
412 and 'KERNEL_ROOT_DIR' not in os.environ):
413 return getTmpDirDEFAULT
415 # Case where "sat test" is launched in an existing SALOME environment
416 if 'KERNEL_ROOT_DIR' in os.environ:
417 root_dir = os.environ['KERNEL_ROOT_DIR']
419 if ('APPLICATION' in self.config
420 and 'KERNEL' in self.config.APPLICATION.products):
421 root_dir = src.product.get_product_config(self.config,
422 "KERNEL").install_dir
424 # Case where there the appli option is called (with path to launcher)
425 if len(self.launcher) > 0:
426 # There are two cases : The old application (runAppli)
428 launcherName = os.path.basename(self.launcher)
429 launcherDir = os.path.dirname(self.launcher)
430 if launcherName == 'runAppli':
432 cmd = "for i in " + launcherDir + "/env.d/*.sh; do source ${i};"
433 " done ; echo $KERNEL_ROOT_DIR"
436 cmd = ("echo -e 'import os\nprint os.environ[\"KERNEL_" +
437 "ROOT_DIR\"]' > tmpscript.py; %s shell" +
438 " tmpscript.py") % self.launcher
439 root_dir = subprocess.Popen(cmd,
440 stdout=subprocess.PIPE,
442 executable='/bin/bash').communicate()[0].split()[-1]
444 # import grid salome_utils from KERNEL that gives
445 # the right getTmpDir function
447 (file_, pathname, description) = imp.find_module("salome_utils",
448 [os.path.join(root_dir,
452 grid = imp.load_module("salome_utils",
456 return grid.getLogDir
458 grid = imp.load_module("salome_utils",
462 return grid.getTmpDir
468 def get_test_timeout(self, test_name, default_value):
469 if ("timeout" in self.settings and
470 test_name in self.settings["timeout"]):
471 return self.settings["timeout"][test_name]
475 def generate_launching_commands(self):
476 # Case where "sat test" is launched in an existing SALOME environment
477 if 'KERNEL_ROOT_DIR' in os.environ:
478 binSalome = "runSalome"
480 killSalome = "killSalome.py"
482 # Rare case where there is no KERNEL in grid list
483 # (for example MED_STANDALONE)
484 if ('APPLICATION' in self.config and
485 'KERNEL' not in self.config.APPLICATION.products):
486 binSalome = "runSalome"
488 killSalome = "killSalome.py"
489 src.environment.load_environment(self.config, False, self.logger)
490 return binSalome, binPython, killSalome
492 # Case where there the appli option is called (with path to launcher)
493 if len(self.launcher) > 0:
494 # There are two cases : The old application (runAppli)
496 launcherName = os.path.basename(self.launcher)
497 launcherDir = os.path.dirname(self.launcher)
498 if launcherName == 'runAppli':
500 binSalome = self.launcher
501 binPython = ("for i in " +
503 "/env.d/*.sh; do source ${i}; done ; python")
504 killSalome = ("for i in " +
506 "/env.d/*.sh; do source ${i}; done ; killSalome.py'")
507 return binSalome, binPython, killSalome
510 binSalome = self.launcher
511 binPython = self.launcher + ' shell'
512 killSalome = self.launcher + ' killall'
513 return binSalome, binPython, killSalome
515 # SALOME version detection and APPLI repository detection
516 VersionSalome = src.get_salome_version(self.config)
518 if "APPLI" in self.config and "application_name" in self.config.APPLI:
519 appdir = self.config.APPLI.application_name
521 # Case where SALOME has NOT the launcher that uses the SalomeContext API
522 if VersionSalome < 730:
523 binSalome = os.path.join(self.config.APPLICATION.workdir,
527 killSalome = "killSalome.py"
528 src.environment.load_environment(self.config, False, self.logger)
529 return binSalome, binPython, killSalome
531 # Case where SALOME has the launcher that uses the SalomeContext API
532 if VersionSalome >= 730:
533 if 'profile' not in self.config.APPLICATION:
534 # Before revision of application concept
535 launcher_name = self.config.APPLI.launch_alias_name
536 binSalome = os.path.join(self.config.APPLICATION.workdir,
540 # After revision of application concept
541 launcher_name = self.config.APPLICATION.profile.launcher_name
542 binSalome = os.path.join(self.config.APPLICATION.workdir,
545 if src.architecture.is_windows():
548 binPython = binSalome + ' shell'
549 killSalome = binSalome + ' killall'
550 return binSalome, binPython, killSalome
552 return binSalome, binPython, killSalome
556 # Runs tests of a session (using a single instance of Salome).
557 def run_tests(self, listTest, ignoreList):
558 out_path = os.path.join(self.currentDir,
561 sessionname = "%s/%s" % (self.currentgrid, self.currentsession)
562 time_out = self.get_test_timeout(sessionname,
563 self.config.SITE.test.timeout)
565 time_out_salome = src.get_cfg_param(self.config.SITE.test,
567 self.config.SITE.test.timeout)
569 # generate wrapper script
570 script_path = os.path.join(out_path, 'wrapperScript.py')
571 self.generate_script(listTest, script_path, ignoreList)
573 tmpDir = self.get_tmp_dir()
575 binSalome, binPython, killSalome = self.generate_launching_commands()
576 if self.settings.has_key("run_with_grids") \
577 and self.settings["run_with_grids"].has_key(sessionname):
578 binSalome = (binSalome +
579 " -m %s" % self.settings["run_with_grids"][sessionname])
581 logWay = os.path.join(self.tmp_working_dir, "WORK", "log_cxx")
585 if self.currentsession.startswith("NOGUI_"):
586 # runSalome -t (bash)
587 status, elapsed = fork.batch(binSalome, self.logger,
588 os.path.join(self.tmp_working_dir,
591 "--shutdown-server=1",
596 elif self.currentsession.startswith("PY_"):
598 status, elapsed = fork.batch(binPython, self.logger,
599 os.path.join(self.tmp_working_dir,
602 delai=time_out, log=logWay)
606 if self.show_desktop: opt = "--show-desktop=0"
607 status, elapsed = fork.batch_salome(binSalome,
610 self.tmp_working_dir,
613 "--shutdown-server=1",
619 delaiapp=time_out_salome)
621 self.logger.write("status = %s, elapsed = %s\n" % (status, elapsed),
624 # create the test result to add in the config object
625 test_info = src.pyconf.Mapping(self.config)
626 test_info.testbase = self.currentTestBase
627 test_info.grid = self.currentgrid
628 test_info.session = self.currentsession
629 test_info.script = src.pyconf.Sequence(self.config)
631 script_results = self.read_results(listTest, elapsed == time_out)
632 for sr in sorted(script_results.keys()):
635 # create script result
636 script_info = src.pyconf.Mapping(self.config)
637 script_info.name = sr
638 script_info.res = script_results[sr][0]
639 script_info.time = script_results[sr][1]
640 if script_info.res == src.TIMEOUT_STATUS:
641 script_info.time = time_out
642 if script_info.time < 1e-3: script_info.time = 0
644 callback = script_results[sr][2]
645 if script_info.res != src.OK_STATUS and len(callback) > 0:
646 script_info.callback = callback
648 kfres = script_results[sr][3]
650 script_info.known_error = src.pyconf.Mapping(self.config)
651 script_info.known_error.date = kfres[0]
652 script_info.known_error.expected = kfres[1]
653 script_info.known_error.comment = kfres[2]
654 script_info.known_error.fixed = kfres[3]
656 script_info.content = script_results[sr][4]
657 script_info.out = script_results[sr][5]
659 # add it to the list of results
660 test_info.script.append(script_info, '')
662 # display the results
663 if script_info.time > 0:
664 exectime = "(%7.3f s)" % script_info.time
668 sp = "." * (35 - len(script_info.name))
669 self.logger.write(self.write_test_margin(3), 3)
670 self.logger.write("script %s %s %s %s\n" % (
671 src.printcolors.printcLabel(script_info.name),
673 src.printcolors.printc(script_info.res),
675 if script_info and len(callback) > 0:
676 self.logger.write("Exception in %s\n%s\n" % \
678 src.printcolors.printcWarning(callback)), 2, False)
680 if script_info.res == src.OK_STATUS:
682 elif script_info.res == src.KNOWNFAILURE_STATUS:
683 self.nb_acknoledge += 1
684 elif script_info.res == src.TIMEOUT_STATUS:
686 elif script_info.res == src.NA_STATUS:
688 elif script_info.res == "?":
691 self.config.TESTS.append(test_info, '')
694 # Runs all tests of a session.
695 def run_session_tests(self):
697 self.logger.write(self.write_test_margin(2), 3)
698 self.logger.write("Session = %s\n" % src.printcolors.printcLabel(
699 self.currentsession), 3, False)
701 # prepare list of tests to run
702 tests = os.listdir(os.path.join(self.currentDir,
704 self.currentsession))
705 tests = filter(lambda l: l.endswith(".py"), tests)
706 tests = sorted(tests, key=str.lower)
708 # build list of known failures
709 cat = "%s/%s/" % (self.currentgrid, self.currentsession)
711 for k in self.ignore_tests.keys():
712 if k.startswith(cat):
713 ignoreDict[k[len(cat):]] = self.ignore_tests[k]
715 self.run_tests(tests, ignoreDict)
718 # Runs all tests of a grid.
719 def run_grid_tests(self):
720 self.logger.write(self.write_test_margin(1), 3)
721 self.logger.write("grid = %s\n" % src.printcolors.printcLabel(
722 self.currentgrid), 3, False)
724 grid_path = os.path.join(self.currentDir, self.currentgrid)
727 if self.sessions is not None:
728 sessions = self.sessions # user choice
730 # use all scripts in grid
731 sessions = filter(lambda l: l not in C_IGNORE_GRIDS,
732 os.listdir(grid_path))
733 sessions = filter(lambda l: os.path.isdir(os.path.join(grid_path,
736 sessions = sorted(sessions, key=str.lower)
737 for session_ in sessions:
738 if not os.path.exists(os.path.join(grid_path, session_)):
739 self.logger.write(self.write_test_margin(2), 3)
740 self.logger.write(src.printcolors.printcWarning("Session %s not"
741 " found" % session_) + "\n", 3, False)
743 self.currentsession = session_
744 self.run_session_tests()
747 # Runs test testbase.
748 def run_testbase_tests(self):
749 res_dir = os.path.join(self.currentDir, "RESSOURCES")
750 os.environ['PYTHONPATH'] = (res_dir +
752 os.environ['PYTHONPATH'])
753 os.environ['TT_BASE_RESSOURCES'] = res_dir
754 src.printcolors.print_value(self.logger,
755 "TT_BASE_RESSOURCES",
758 self.logger.write("\n", 4, False)
760 self.logger.write(self.write_test_margin(0), 3)
761 testbase_label = "Test base = %s\n" % src.printcolors.printcLabel(
762 self.currentTestBase)
763 self.logger.write(testbase_label, 3, False)
764 self.logger.write("-" * len(src.printcolors.cleancolor(testbase_label)),
766 self.logger.write("\n", 3, False)
769 settings_file = os.path.join(res_dir, "test_settings.py")
770 if os.path.exists(settings_file):
772 execfile(settings_file, gdic, ldic)
773 self.logger.write(_("Load test settings\n"), 3)
774 self.settings = ldic['settings_dic']
775 self.ignore_tests = ldic['known_failures_list']
776 if isinstance(self.ignore_tests, list):
777 self.ignore_tests = {}
778 self.logger.write(src.printcolors.printcWarning("known_failur"
779 "es_list must be a dictionary (not a list)") + "\n", 1, False)
781 self.ignore_tests = {}
782 self.settings.clear()
784 # read known failures pyconf
785 if "testerror" in self.config.SITE:
787 #self.known_errors = testerror.read_test_failures(
788 # self.config.TOOLS.testerror.file_path,
792 self.known_errors = None
794 if self.grids is not None:
795 grids = self.grids # given by user
797 # select all the grids (i.e. directories) in the directory
798 grids = filter(lambda l: l not in C_IGNORE_GRIDS,
799 os.listdir(self.currentDir))
800 grids = filter(lambda l: os.path.isdir(
801 os.path.join(self.currentDir, l)),
804 grids = sorted(grids, key=str.lower)
806 if not os.path.exists(os.path.join(self.currentDir, grid)):
807 self.logger.write(self.write_test_margin(1), 3)
808 self.logger.write(src.printcolors.printcWarning(
809 "grid %s does not exist\n" % grid), 3, False)
811 self.currentgrid = grid
812 self.run_grid_tests()
814 def run_script(self, script_name):
815 if ('APPLICATION' in self.config and
816 script_name in self.config.APPLICATION):
817 script = self.config.APPLICATION[script_name]
821 self.logger.write("\n", 2, False)
822 if not os.path.exists(script):
823 self.logger.write(src.printcolors.printcWarning("WARNING: scrip"
824 "t not found: %s" % script) + "\n", 2)
826 self.logger.write(src.printcolors.printcHeader("----------- sta"
827 "rt %s" % script_name) + "\n", 2)
828 self.logger.write("Run script: %s\n" % script, 2)
829 subprocess.Popen(script, shell=True).wait()
830 self.logger.write(src.printcolors.printcHeader("----------- end"
831 " %s" % script_name) + "\n", 2)
833 def run_all_tests(self):
834 initTime = datetime.datetime.now()
836 self.run_script('test_setup')
837 self.logger.write("\n", 2, False)
839 self.logger.write(src.printcolors.printcHeader(
840 _("=== STARTING TESTS")) + "\n", 2)
841 self.logger.write("\n", 2, False)
842 self.currentDir = os.path.join(self.tmp_working_dir,
844 self.currentTestBase)
845 self.run_testbase_tests()
847 # calculate total execution time
848 totalTime = datetime.datetime.now() - initTime
849 totalTime -= datetime.timedelta(microseconds=totalTime.microseconds)
850 self.logger.write("\n", 2, False)
851 self.logger.write(src.printcolors.printcHeader(_("=== END TESTS")), 2)
852 self.logger.write(" %s\n" % src.printcolors.printcInfo(str(totalTime)),
859 self.run_script('test_cleanup')
860 self.logger.write("\n", 2, False)
863 res_count = "%d / %d" % (self.nb_succeed,
864 self.nb_run - self.nb_acknoledge)
866 res_out = _("Tests Results: %(succeed)d / %(total)d\n") % \
867 { 'succeed': self.nb_succeed, 'total': self.nb_run }
868 if self.nb_succeed == self.nb_run:
869 res_out = src.printcolors.printcSuccess(res_out)
871 res_out = src.printcolors.printcError(res_out)
872 self.logger.write(res_out, 1)
874 if self.nb_timeout > 0:
875 self.logger.write(_("%d tests TIMEOUT\n") % self.nb_timeout, 1)
876 res_count += " TO: %d" % self.nb_timeout
877 if self.nb_not_run > 0:
878 self.logger.write(_("%d tests not executed\n") % self.nb_not_run, 1)
879 res_count += " NR: %d" % self.nb_not_run
881 status = src.OK_STATUS
882 if self.nb_run - self.nb_succeed - self.nb_acknoledge > 0:
883 status = src.KO_STATUS
884 elif self.nb_acknoledge:
885 status = src.KNOWNFAILURE_STATUS
887 self.logger.write(_("Status: %s\n" % status), 3)
889 return self.nb_run - self.nb_succeed - self.nb_acknoledge
892 # Write margin to show test results.
893 def write_test_margin(self, tab):
896 return "| " * (tab - 1) + "+ "